diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html
index bb80671de8..7121179c29 100644
--- a/demos/01_point_circle.html
+++ b/demos/01_point_circle.html
@@ -10,6 +10,9 @@
point_circle
@@ -55,15 +58,15 @@ scene.on('loaded', () => {
.shape('2d:circle')
.size('value', [ 2, 80]) // default 1
//.size('value', [ 10, 300]) // default 1
- .active(false)
+ .active(true)
.filter('value', field_8 => {
return field_8 * 1 > 500;
})
- .color('type', colorObj.red)
+ .color('type', colorObj.blue)
.style({
stroke: 'rgb(255,255,255)',
strokeWidth: 1,
- opacity: 0.9
+ opacity: 1.
})
.render();
diff --git a/demos/01_point_column.html b/demos/01_point_column.html
index 8e1abda83c..fd7d33ae02 100644
--- a/demos/01_point_column.html
+++ b/demos/01_point_column.html
@@ -34,9 +34,11 @@ scene.on('loaded', () => {
zIndex: 2
})
.source(data.list, {
- type: 'array',
- x: 'j',
- y: 'w',
+ parser:{
+ type: 'json',
+ x: 'j',
+ y: 'w',
+ }
})
.shape('cylinder')
.size('t',(level)=> {
diff --git a/demos/01_point_distribute.html b/demos/01_point_distribute.html
index 18a714ab75..a3d1bd8f73 100644
--- a/demos/01_point_distribute.html
+++ b/demos/01_point_distribute.html
@@ -34,9 +34,11 @@ scene.on('loaded', () => {
zIndex: 2
})
.source(data, {
- type: 'csv',
- y: 'lat',
- x: 'lng'
+ parser:{
+ type: 'csv',
+ y: 'lat',
+ x: 'lng'
+ }
})
.size(1.0)
.color('#0D408C')
diff --git a/demos/02_point_circle.html b/demos/02_point_circle.html
new file mode 100644
index 0000000000..cc95ad57d6
--- /dev/null
+++ b/demos/02_point_circle.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+ point_circle
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/04_image.html b/demos/04_image.html
index 3f0773c96e..5acb717137 100644
--- a/demos/04_image.html
+++ b/demos/04_image.html
@@ -33,8 +33,11 @@ const scene = new L7.Scene({
scene.on('loaded', () => {
const imageLayer = scene.ImageLayer().
source('https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',{
-
- extent: [ 121.1680, 30.2828, 121.3840, 30.4219 ]
+ parser:{
+ type:'image',
+ extent: [ 121.1680, 30.2828, 121.3840, 30.4219 ]
+ }
+
})
.style({
opacity:1.0,
diff --git a/demos/05_raster_dem.html b/demos/05_raster_dem.html
index 0589eed6b4..fb560be45b 100644
--- a/demos/05_raster_dem.html
+++ b/demos/05_raster_dem.html
@@ -48,13 +48,14 @@ scene.on('loaded', () => {
const layer = scene.RasterLayer({ zIndex: 2 }).
source(values, {
- type: 'raster',
- width: n,
- height: m,
- min: 0,
- max: 8000,
- extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
-
+ parser: {
+ type: 'raster',
+ width: n,
+ height: m,
+ min: 0,
+ max: 8000,
+ extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
+ }
})
.style({
rampColors: {
diff --git a/demos/grid.html b/demos/grid.html
new file mode 100644
index 0000000000..94c2000bb9
--- /dev/null
+++ b/demos/grid.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+ point_circle
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index cbaf70578a..3ee6803cde 100755
--- a/package.json
+++ b/package.json
@@ -107,6 +107,7 @@
"lodash": "^4.17.5",
"polyline-normals": "^2.0.2",
"rbush": "^2.0.2",
+ "simple-statistics": "^7.0.1",
"three": "^0.96.0",
"venn.js": "^0.2.20",
"viewport-mercator-project": "^5.2.0",
diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js
index e4fb4c2ee1..e70912ac16 100755
--- a/src/core/engine/picking/picking.js
+++ b/src/core/engine/picking/picking.js
@@ -42,7 +42,7 @@ class Picking {
// this._world._container.addEventListener('mousemove', this._onWorldMove.bind(this), false);
}
pickdata(event) {
- const point = { x: event.clientX, y: event.clientY, type: event.type };
+ const point = { x: event.offsetX, y: event.offsetY, type: event.type };
const normalisedPoint = { x: 0, y: 0 };
normalisedPoint.x = (point.x / this._width) * 2 - 1;
normalisedPoint.y = -(point.y / this._height) * 2 + 1;
@@ -53,7 +53,6 @@ class Picking {
// if (event.button !== 0) {
// return;
// }
-
const point = { x: event.clientX, y: event.clientY, type: event.type };
const normalisedPoint = { x: 0, y: 0 };
normalisedPoint.x = (point.x / this._width) * 2 - 1;
diff --git a/src/core/layer.js b/src/core/layer.js
index 50f2858587..e4d4467ab9 100644
--- a/src/core/layer.js
+++ b/src/core/layer.js
@@ -5,7 +5,7 @@
import Base from './base';
import * as THREE from './three';
import ColorUtil from '../attr/color-util';
-import * as source from '../source/index';
+import source from './source';
import PickingMaterial from '../core/engine/picking/pickingMaterial';
import Attr from '../attr/index';
import Util from '../util';
@@ -106,12 +106,10 @@ export default class Layer extends Base {
this._object3D.visible = this.get('visible');
}
source(data, cfg = {}) {
- const dataType = this._getDataType(data);
- const { type = dataType } = cfg;
cfg.data = data;
cfg.mapType = this.get('mapType');
- this.layerSource = new source[type](cfg);
+ this.layerSource = new source(cfg);
// this.scene.workerPool.runTask({
// command: 'geojson',
// data: cfg
@@ -279,10 +277,10 @@ export default class Layer extends Base {
const { featureId } = e;
if (featureId < 0) return;
const activeStyle = this.get('activedOptions');
- const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
+ // const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
// 如果数据不显示状态则不进行高亮
- if (this.StyleData[selectFeatureIds[0]].hasOwnProperty('filter') && this.StyleData[selectFeatureIds[0]].filter === false) { return; }
- const style = Util.assign({}, this.StyleData[featureId]);
+ if (this.layerData[featureId].hasOwnProperty('filter') && this.layerData[featureId].filter === false) { return; }
+ const style = Util.assign({}, this.layerData[featureId]);
style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
this.updateStyle([ featureId ], style);
}
@@ -321,7 +319,7 @@ export default class Layer extends Base {
_updateSize(zoom) {
const sizeOption = this.get('attrOptions').size;
const fields = parseFields(sizeOption.field);
- const data = this.layerSource.propertiesData;
+ const data = this.layerSource.data.dataArray;
if (!this.zoomSizeCache) this.zoomSizeCache = {};
if (!this.zoomSizeCache[zoom]) {
this.zoomSizeCache[zoom] = [];
@@ -339,7 +337,8 @@ export default class Layer extends Base {
const self = this;
const attrs = self.get('attrs');
const mappedData = [];
- const data = this.layerSource.propertiesData;
+ // const data = this.layerSource.propertiesData;
+ const data = this.layerSource.data.dataArray;
for (let i = 0; i < data.length; i++) {
const record = data[i];
const newRecord = {};
@@ -362,18 +361,17 @@ export default class Layer extends Base {
}
}
}
+ newRecord.coordinates = record.coordinates;
mappedData.push(newRecord);
}
-
- this.StyleData = mappedData;
- return mappedData;
+ this.layerData = mappedData;
}
// 更新地图映射
_updateMaping() {
const self = this;
const attrs = self.get('attrs');
- const data = this.layerSource.propertiesData;
+ const data = this.layerSource.data.dataArray;
for (let i = 0; i < data.length; i++) {
const record = data[i];
for (const attrName in attrs) {
@@ -385,10 +383,10 @@ export default class Layer extends Base {
for (let j = 0; j < values.length; j++) {
const val = values[j];
const name = names[j];
- this.StyleData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
+ this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
}
} else {
- this.StyleData[i][names[0]] = values.length === 1 ? values[0] : values;
+ this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
}
attr.neadUpdate = true;
@@ -468,6 +466,7 @@ export default class Layer extends Base {
pickingMesh.material.setUniformsValue('u_zoom', zoom);
};
this._pickingMesh.add(pickingMesh);
+
}
_setPickingId() {
this._pickingId = this.getPickingId();
@@ -532,13 +531,13 @@ export default class Layer extends Base {
*/
_updateFilter(object) {
this._updateMaping();
- const filterData = this.StyleData;
+ const filterData = this.layerData;
this._activeIds = null; // 清空选中元素
const colorAttr = object.geometry.attributes.a_color;
const pickAttr = object.geometry.attributes.pickingId;
pickAttr.array.forEach((id, index) => {
id = Math.abs(id);
- const color = [ ...this.StyleData[id - 1].color ];
+ const color = [ ...this.layerData[id - 1].color ];
id = Math.abs(id);
const item = filterData[id - 1];
if (item.hasOwnProperty('filter') && item.filter === false) {
@@ -584,7 +583,7 @@ export default class Layer extends Base {
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
const colorAttr = this.layerMesh.geometry.attributes.a_color;
this._activeIds.forEach(index => {
- const color = this.StyleData[index].color;
+ const color = this.layerData[index].color;
const firstId = pickingId.indexOf(index + 1);
for (let i = firstId; i < pickingId.length; i++) {
if (pickingId[i] === index + 1) {
diff --git a/src/core/source.js b/src/core/source.js
index 3a61aead88..fdb37fa2de 100644
--- a/src/core/source.js
+++ b/src/core/source.js
@@ -2,16 +2,19 @@
* @Author: ThinkGIS
* @Date: 2018-06-08 11:19:06
* @Last Modified by: mikey.zhaopeng
- * @Last Modified time: 2018-11-01 11:50:43
+ * @Last Modified time: 2019-02-25 20:58:08
*/
import Base from './base';
const Controller = require('./controller/index');
import { aProjectFlat } from '../geo/project';
+import { getTransform, getParser } from '../source';
export default class Source extends Base {
getDefaultCfg() {
return {
data: null,
defs: {},
+ parser: {},
+ transforms: [],
scales: {
},
options: {}
@@ -19,26 +22,40 @@ export default class Source extends Base {
}
constructor(cfg) {
super(cfg);
-
+ const transform = this.get('transforms');
+ this._transforms = transform || [];
this._initControllers();
- this.prepareData();
+ // 数据解析
+ this._excuteParser();
+ // 数据转换 统计,聚合,分类
+ this._executeTrans();
+ // 坐标转换
+ this._projectCoords();
}
-
- // 标准化数据
- prepareData() {
+ _excuteParser() {
+ const parser = this.get('parser');
+ const { type = 'geojson' } = parser;
const data = this.get('data');
- this.propertiesData = [];// 临时使用
- this.geoData = [];
-
- data.coordinates.forEach(geo => {
- const coord = this._coordProject(geo);
- this.geoData.push(coord);
- this.propertiesData.push([]);
+ this.data = getParser(type)(data, parser);
+ }
+ /**
+ * 数据统计
+ */
+ _executeTrans() {
+ const trans = this._transforms;
+ trans.forEach(tran => {
+ const { type } = tran;
+ this.data = getTransform(type)(this.data, tran);
+ });
+ this._transforms = trans;
+ }
+ _projectCoords() {
+ this.data.dataArray.forEach(data => {
+ data.coordinates = this._coordProject(data.coordinates);
});
}
-
createScale(field) {
- const data = this.propertiesData;
+ const data = this.data.dataArray;
const scales = this.get('scales');
let scale = scales[field];
const scaleController = this.get('scaleController');
@@ -87,5 +104,10 @@ export default class Source extends Base {
return [ ll.x, -ll.y, geo[2] || 0 ];
}
+ getSelectFeature(featureId) {
+ const data = this.get('data');
+ // 如果是GeoJSON 数据返回原数
+ return data.features ? data.features[featureId] : this.data.dataArray[featureId];
+ }
}
diff --git a/src/geom/buffer/heatmap/grid.js b/src/geom/buffer/heatmap/grid.js
new file mode 100644
index 0000000000..af089e408b
--- /dev/null
+++ b/src/geom/buffer/heatmap/grid.js
@@ -0,0 +1,32 @@
+export default function gridBuffer(layerData) {
+ const attribute = {
+ vertices: [],
+ miter: [],
+ colors: [],
+ pickingIds: []
+ };
+ layerData.forEach(element => {
+ const { color, id } = element;
+ const [ x, y, z ] = element.coordinates;
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(-1, -1);
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(1, 1);
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(-1, 1);
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(-1, -1);
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(1, -1);
+ attribute.vertices.push(x, y, z);
+ attribute.miter.push(1, 1);
+ attribute.colors.push(...color);
+ attribute.colors.push(...color);
+ attribute.colors.push(...color);
+ attribute.colors.push(...color);
+ attribute.colors.push(...color);
+ attribute.colors.push(...color);
+ attribute.pickingIds.push(id, id, id, id, id, id);
+ });
+ return attribute;
+}
diff --git a/src/geom/buffer/image.js b/src/geom/buffer/image.js
index 70b52aed51..262151b149 100644
--- a/src/geom/buffer/image.js
+++ b/src/geom/buffer/image.js
@@ -4,8 +4,9 @@ import * as THREE from '../../core/three';
export default class ImageBuffer extends BufferBase {
geometryBuffer() {
- const coordinates = this.get('coordinates');
- const images = this.get('image');
+ const layerData = this.get('layerData');
+ const coordinates = layerData[0].coordinates;
+ const images = layerData[0].images;
const positions = [ ...coordinates[0],
coordinates[1][0], coordinates[0][1], 0,
...coordinates[1],
diff --git a/src/geom/buffer/line.js b/src/geom/buffer/line.js
index a73006f07c..880ac2dc95 100644
--- a/src/geom/buffer/line.js
+++ b/src/geom/buffer/line.js
@@ -3,8 +3,7 @@ import { lineShape } from '../shape';
export default class LineBuffer extends BufferBase {
geometryBuffer() {
- const coordinates = this.get('coordinates');
- const properties = this.get('properties');
+ const layerData = this.get('layerData');
const shapeType = this.shapeType = this.get('shapeType');
const positions = [];
const positionsIndex = [];
@@ -16,16 +15,16 @@ export default class LineBuffer extends BufferBase {
this.attributes = this._getArcLineAttributes();
return;
}
- coordinates.forEach((geo, index) => {
- const props = properties[index];
- const attrData = this._getShape(geo, props, index);
+ layerData.forEach((item, index) => {
+ const props = item;
+ const attrData = this._getShape(item.coordinates, props, index);
positions.push(...attrData.positions);
positionsIndex.push(...attrData.indexes);
if (attrData.hasOwnProperty('instances')) {
instances.push(...attrData.instances);
}
});
- this.bufferStruct.style = properties;
+ this.bufferStruct.style = layerData;
this.bufferStruct.verts = positions;
this.bufferStruct.indexs = positionsIndex;
if (instances.length > 0) {
@@ -50,17 +49,16 @@ export default class LineBuffer extends BufferBase {
}
_getArcLineAttributes() {
- const coordinates = this.get('coordinates');
- const properties = this.get('properties');
+ const layerData = this.get('layerData');
const positions = [];
const colors = [];
const indexArray = [];
const sizes = [];
const instances = [];
- coordinates.forEach((geo, index) => {
- const props = properties[index];
+ layerData.forEach(item => {
+ const props = item;
const positionCount = positions.length / 3;
- const attrData = this._getShape(geo, props, positionCount);
+ const attrData = this._getShape(item.coordinates, props, positionCount);
positions.push(...attrData.positions);
colors.push(...attrData.colors);
indexArray.push(...attrData.indexArray);
@@ -76,8 +74,7 @@ export default class LineBuffer extends BufferBase {
};
}
_getMeshLineAttributes() {
- const coordinates = this.get('coordinates');
- const properties = this.get('properties');
+ const layerData = this.get('layerData');
const { lineType } = this.get('style');
const positions = [];
const pickingIds = [];
@@ -87,10 +84,10 @@ export default class LineBuffer extends BufferBase {
const indexArray = [];
const sizes = [];
const attrDistance = [];
- coordinates.forEach((geo, index) => {
- const props = properties[index];
+ layerData.forEach(item => {
+ const props = item;
const positionCount = positions.length / 3;
- const attr = lineShape.Line(geo, props, positionCount, (lineType !== 'soild'));
+ const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
positions.push(...attr.positions);
normal.push(...attr.normal);
miter.push(...attr.miter);
diff --git a/src/geom/buffer/point/fillBuffer.js b/src/geom/buffer/point/fillBuffer.js
index 84d257c3ee..7179959827 100644
--- a/src/geom/buffer/point/fillBuffer.js
+++ b/src/geom/buffer/point/fillBuffer.js
@@ -3,7 +3,7 @@ import * as THREE from '../../../core/three';
import * as polygonShape from '../../shape/polygon';
import * as polygonPath from '../../shape/path';
import Util from '../../../util';
-export default function fillBuffer(coordinates, properties) {
+export default function fillBuffer(layerData) {
const attribute = {
vertices: [],
normals: [],
@@ -14,8 +14,8 @@ export default function fillBuffer(coordinates, properties) {
faceUv: []
};
- coordinates.forEach((geo, index) => {
- let { size, shape, color, id } = properties[index];
+ layerData.forEach(item => {
+ let { size, shape, color, id, coordinates } = item;
let polygon = null;
const path = polygonPath[shape]();
if (pointShape['2d'].indexOf(shape) !== -1) {
@@ -27,7 +27,7 @@ export default function fillBuffer(coordinates, properties) {
} else {
throw new Error('Invalid shape type: ' + shape);
}
- toPointShapeAttributes(polygon, geo, { size, shape, color, id }, attribute);
+ toPointShapeAttributes(polygon, coordinates, { size, shape, color, id }, attribute);
});
return attribute;
diff --git a/src/geom/buffer/point/imageBuffer.js b/src/geom/buffer/point/imageBuffer.js
index 6bc37b052a..383134b6d9 100644
--- a/src/geom/buffer/point/imageBuffer.js
+++ b/src/geom/buffer/point/imageBuffer.js
@@ -1,4 +1,4 @@
-export default function ImageBuffer(coordinates, properties, opt) {
+export default function ImageBuffer(layerData, opt) {
const attributes = {
vertices: [],
colors: [],
@@ -7,10 +7,10 @@ export default function ImageBuffer(coordinates, properties, opt) {
pickingIds: [],
uv: []
};
- coordinates.forEach((pos, index) => {
- const { color, size, id, shape } = properties[index];
+ layerData.forEach(item => {
+ const { color, size, id, shape, coordinates } = item;
const { x, y } = opt.imagePos[shape];
- attributes.vertices.push(...pos);
+ attributes.vertices.push(...coordinates);
attributes.colors.push(...color);
attributes.pickingIds.push(id);
attributes.sizes.push(size * window.devicePixelRatio); //
diff --git a/src/geom/buffer/point/normalBuffer.js b/src/geom/buffer/point/normalBuffer.js
index d35fd4217b..aaa50ee424 100644
--- a/src/geom/buffer/point/normalBuffer.js
+++ b/src/geom/buffer/point/normalBuffer.js
@@ -1,13 +1,13 @@
-export default function NormalBuffer(coordinates, properties) {
+export default function NormalBuffer(layerData) {
const attributes = {
vertices: [],
colors: [],
sizes: [],
pickingIds: []
};
- coordinates.forEach((pos, index) => {
- const { color, size, id } = properties[index];
- attributes.vertices.push(...pos);
+ layerData.forEach(item => {
+ const { color, size, id, coordinates} = item;
+ attributes.vertices.push(...coordinates);
attributes.colors.push(...color);
attributes.pickingIds.push(id);
attributes.sizes.push(size);
diff --git a/src/geom/buffer/point/strokeBuffer.js b/src/geom/buffer/point/strokeBuffer.js
index c71726cbd6..eff757e3c6 100644
--- a/src/geom/buffer/point/strokeBuffer.js
+++ b/src/geom/buffer/point/strokeBuffer.js
@@ -3,7 +3,7 @@ import * as polygonShape from '../../shape/polygon';
import * as lineShape from '../../shape/line';
import { pointShape } from '../../../global';
import Util from '../../../util';
-export default function StrokeBuffer(coordinates, properties, style) {
+export default function StrokeBuffer(layerData, style) {
const attribute = {
shapes: [],
normal: [],
@@ -15,8 +15,8 @@ export default function StrokeBuffer(coordinates, properties, style) {
colors: []
};
const { stroke, strokeWidth } = style;
- coordinates.forEach((geo, index) => {
- let { size, shape, id } = properties[index];
+ layerData.forEach(item => {
+ let { size, shape, id, coordinates } = item;
const path = polygonPath[shape]();
const positionsIndex = attribute.miter.length;
let polygon = null;
@@ -33,7 +33,7 @@ export default function StrokeBuffer(coordinates, properties, style) {
} else {
throw new Error('Invalid shape type: ' + shape);
}
- polygonLineBuffer(polygon, geo, size, attribute);
+ polygonLineBuffer(polygon, coordinates, size, attribute);
});
return attribute;
diff --git a/src/geom/buffer/point/textBuffer.js b/src/geom/buffer/point/textBuffer.js
index 0bbab7d759..1d68acb3b1 100644
--- a/src/geom/buffer/point/textBuffer.js
+++ b/src/geom/buffer/point/textBuffer.js
@@ -9,7 +9,7 @@ const metrics = {
family: 'ios9',
size: 24
};
-export default function TextBuffer(coordinates, properties, style) {
+export default function TextBuffer(layerData, style) {
EventEmitter.call(this);
const attributes = {
originPoints: [],
@@ -21,7 +21,7 @@ export default function TextBuffer(coordinates, properties, style) {
const { textOffset = [ 0, 0 ] } = style;
const chars = [];
const textChars = {};
- properties.forEach(element => {
+ layerData.forEach(element => {
let text = element.shape || '';
text = text.toString();
for (let j = 0; j < text.length; j++) {
@@ -33,9 +33,9 @@ export default function TextBuffer(coordinates, properties, style) {
}
});
loadTextInfo(chars, (chars, texture) => {
- properties.forEach((element, index) => {
+ layerData.forEach(element => {
const size = element.size;
- const pos = coordinates[index];
+ const pos = layerData.coordinates;
const pen = { x: textOffset[0], y: textOffset[1] };
let text = element.shape || '';
text = text.toString();
diff --git a/src/geom/buffer/polygon.js b/src/geom/buffer/polygon.js
index c90172802a..60c585d872 100644
--- a/src/geom/buffer/polygon.js
+++ b/src/geom/buffer/polygon.js
@@ -3,22 +3,21 @@ import BufferBase from './bufferBase';
export default class PolygonBuffer extends BufferBase {
geometryBuffer() {
- const coordinates = this.get('coordinates');
- const properties = this.get('properties');
+ const layerData = this.get('layerData');
const shape = this.get('shape');
const positions = [];
const faceUv = [];
const sizes = [];
const positionsIndex = [];
let indexCount = 0;
- this.bufferStruct.style = properties;
- const isExtrude = properties[0].hasOwnProperty('size');
+ this.bufferStruct.style = layerData;
+ const isExtrude = layerData[0].hasOwnProperty('size');
// indices, normals, colors, UVs
- coordinates.forEach((geo, index) => {
- const heightValue = properties[index].size;
- let extrudeData = polygonShape[shape](geo);
+ layerData.forEach(item => {
+ const heightValue = item.size;
+ let extrudeData = polygonShape[shape](item.coordinates);
if (isExtrude && shape === 'extrude') {
- extrudeData = polygonShape.extrude(geo);
+ extrudeData = polygonShape.extrude(item.coordinates);
extrudeData.positions = extrudeData.positions.map(pos => {
pos[2] *= heightValue;
return pos;
@@ -48,7 +47,7 @@ export default class PolygonBuffer extends BufferBase {
this.bufferStruct.indices = positionsIndex;
this.bufferStruct.position = positions;
this.bufferStruct.indexCount = indexCount;
- this.bufferStruct.style = properties;
+ this.bufferStruct.style = layerData;
this.bufferStruct.faceUv = faceUv;
this.bufferStruct.sizes = sizes;
if (shape !== 'line') {
diff --git a/src/geom/buffer/raster.js b/src/geom/buffer/raster.js
index 32fa14a3ba..9f62192699 100644
--- a/src/geom/buffer/raster.js
+++ b/src/geom/buffer/raster.js
@@ -3,8 +3,8 @@ import { colorScales } from '../../attr/colorscales';
import * as THREE from '../../core/three';
export class RasterBuffer extends BufferBase {
geometryBuffer() {
- const coordinates = this.get('coordinates');
-
+ const layerData = this.get('layerData');
+ const { coordinates, width, data, height } = layerData.dataArray[0];
const positions = [
...coordinates[0],
coordinates[1][0], coordinates[0][1], 0,
@@ -14,9 +14,8 @@ export class RasterBuffer extends BufferBase {
coordinates[0][0], coordinates[1][1], 0
];
const imgPosUv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
- const raster = this.get('raster');
const size = this.get('size');
- const texture = new THREE.DataTexture(new Float32Array(raster.data), raster.width, raster.height, THREE.LuminanceFormat, THREE.FloatType);
+ const texture = new THREE.DataTexture(new Float32Array(data), width, height, THREE.LuminanceFormat, THREE.FloatType);
texture.generateMipmaps = true;
texture.needsUpdate = true;
const colors = this.get('rampColors');
@@ -28,7 +27,7 @@ export class RasterBuffer extends BufferBase {
this.bufferStruct.u_extent = [ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ];
this.bufferStruct.u_colorTexture = colorTexture; // 颜色表‘=
- const triangles = this._buildTriangles(raster, size, this.bufferStruct.u_extent);
+ const triangles = this._buildTriangles(width, height, size, this.bufferStruct.u_extent);
const attributes = {
vertices: new Float32Array(triangles.vertices),
uvs: new Float32Array(triangles.uvs),
@@ -78,9 +77,8 @@ export class RasterBuffer extends BufferBase {
texture1.needsUpdate = true;
return texture1;
}
- _buildTriangles(raster, size = 1, extent) {
+ _buildTriangles(width, height, size = 1, extent) {
// const extent = [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
- const { width, height } = raster;
const indices = [];
const vertices = [];
const uvs = [];
diff --git a/src/geom/buffer/text.js b/src/geom/buffer/text.js
index 099f6d217f..5f906352b4 100644
--- a/src/geom/buffer/text.js
+++ b/src/geom/buffer/text.js
@@ -13,12 +13,11 @@ export default class TextBuffer extends BufferBase {
family: 'ios9',
size: 24
};
- const coordinates = this.get('coordinates');
- const properties = this.get('properties');
+ const layerData = this.get('layerData');
const { textOffset = [ 0, 0 ] } = this.get('style');
const chars = [];
const textChars = {};
- properties.forEach(element => {
+ layerData.forEach(element => {
let text = element.shape || '';
text = text.toString();
for (let j = 0; j < text.length; j++) {
@@ -39,9 +38,9 @@ export default class TextBuffer extends BufferBase {
const originPoints = [];
const textSizes = [];
const textOffsets = [];
- properties.forEach((element, index) => {
+ layerData.forEach(element => {
const size = element.size;
- const pos = coordinates[index];
+ const pos = element.coordinates;
// const pen = { x: pos[0] - dimensions.advance / 2, y: pos[1] };
const pen = { x: textOffset[0], y: textOffset[1] };
let text = element.shape || '';
@@ -53,7 +52,7 @@ export default class TextBuffer extends BufferBase {
this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
}
});
- this.bufferStruct.style = properties;
+ this.bufferStruct.style = layerData;
this.attributes = {
originPoints,
textSizes,
diff --git a/src/geom/material/grid.js b/src/geom/material/grid.js
new file mode 100644
index 0000000000..65db262fcf
--- /dev/null
+++ b/src/geom/material/grid.js
@@ -0,0 +1,31 @@
+import grid_frag from '../shader/grid_frag.glsl';
+import grid_vert from '../shader/grid_vert.glsl';
+import Material from './material';
+
+
+export default class GridMaterial extends Material {
+ getDefaultParameters() {
+ return {
+ uniforms: {
+ u_opacity: { value: 1.0 },
+ u_time: { value: 0 },
+ u_xOffset: { value: 0.01 },
+ u_yOffset: { value: 0.01 },
+ u_coverage: { value: 0.8 }
+ },
+ defines: {
+
+ }
+ };
+ }
+ constructor(_uniforms, _defines, parameters) {
+ super(parameters);
+ const { uniforms, defines } = this.getDefaultParameters();
+ this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
+ this.type = 'GridMaterial';
+ this.defines = Object.assign(defines, _defines);
+ this.vertexShader = grid_vert;
+ this.fragmentShader = grid_frag;
+ this.transparent = true;
+ }
+}
diff --git a/src/geom/shader/grid_frag.glsl b/src/geom/shader/grid_frag.glsl
new file mode 100644
index 0000000000..042dde511e
--- /dev/null
+++ b/src/geom/shader/grid_frag.glsl
@@ -0,0 +1,8 @@
+ precision highp float;
+ uniform float u_opacity;
+ varying vec4 v_color;
+ void main() {
+ vec4 color = v_color;
+ gl_FragColor = color;
+ gl_FragColor.a =color.a*u_opacity;
+}
\ No newline at end of file
diff --git a/src/geom/shader/grid_vert.glsl b/src/geom/shader/grid_vert.glsl
new file mode 100644
index 0000000000..90c68a3b70
--- /dev/null
+++ b/src/geom/shader/grid_vert.glsl
@@ -0,0 +1,15 @@
+precision highp float;
+attribute vec2 miter;
+attribute vec4 a_color;
+uniform float u_xOffset;
+uniform float u_yOffset;
+uniform float u_coverage;
+varying vec4 v_color;
+
+void main() {
+ mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
+ v_color = a_color;
+ float x = position.x + miter.x * u_xOffset * u_coverage;
+ float y = position.y + miter.y * u_yOffset * u_coverage;
+ gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0);
+}
\ No newline at end of file
diff --git a/src/layer/heatmap.js b/src/layer/heatmap.js
new file mode 100644
index 0000000000..f9971a55da
--- /dev/null
+++ b/src/layer/heatmap.js
@@ -0,0 +1,28 @@
+import Layer from '../core/layer';
+import gridBuffer from '../geom/buffer/heatmap/grid';
+import DrawGrid from './render/heatmap/gird';
+
+export default class HeatMapLayer extends Layer {
+ shape(type) {
+ this.shapeType = type;
+ return this;
+ }
+ render() {
+ this._prepareRender();
+ return this;
+ }
+ _prepareRender() {
+ this.init();
+ this.type = 'heatmap';
+ const style = this.get('styleOptions');
+ const { xOffset, yOffset } = this.layerSource.data;
+ this._buffer = new gridBuffer(this.layerData);
+ const config = {
+ ...style,
+ xOffset,
+ yOffset
+ };
+ const girdMesh = new DrawGrid(this._buffer, config);
+ this.add(girdMesh);
+ }
+}
diff --git a/src/layer/imageLayer.js b/src/layer/imageLayer.js
index f3092da117..92e9a60b59 100644
--- a/src/layer/imageLayer.js
+++ b/src/layer/imageLayer.js
@@ -1,26 +1,19 @@
import Layer from '../core/layer';
import * as THREE from '../core/three';
-import imageSource from '../source/imageSource';
import ImageBuffer from '../geom/buffer/image';
// import ImageGeometry from '../geom/bufferGeometry/image';
import ImageMaterial from '../geom/material/imageMaterial';
export default class imageLayer extends Layer {
- source(data, cfg = {}) {
- cfg.mapType = this.get('mapType');
- cfg.data = data;
- this.layerSource = new imageSource(cfg);
- return this;
- }
render() {
this.init();
this.type = 'image';
const source = this.layerSource;
const { opacity } = this.get('styleOptions');
// 加载 完成事件
- source.on('imageLoaded', () => {
+ source.data.images.then(images => {
+ this.layerData[0].images = images;
const buffer = new ImageBuffer({
- coordinates: source.geoData,
- image: source.image
+ layerData: this.layerData
});
this.initGeometry(buffer.attributes);
const material = new ImageMaterial({
diff --git a/src/layer/index.js b/src/layer/index.js
index 5e8fef27c6..1c2cad2fdf 100644
--- a/src/layer/index.js
+++ b/src/layer/index.js
@@ -4,17 +4,14 @@ import PointLayer from './pointLayer';
import LineLayer from './lineLayer';
import ImageLayer from './imageLayer';
import RasterLayer from './rasterLayer';
+import HeatMapLayer from './heatmap';
registerLayer('PolygonLayer', PolygonLayer);
registerLayer('PointLayer', PointLayer);
registerLayer('LineLayer', LineLayer);
registerLayer('ImageLayer', ImageLayer);
registerLayer('RasterLayer', RasterLayer);
+registerLayer('HeatMapLayer', HeatMapLayer);
export { LAYER_MAP } from './factory';
-export { default as PolygonLayer } from './polygonLayer';
-export { default as PointLayer } from './pointLayer';
-export { default as LineLayer } from './lineLayer';
-export { default as ImageLayer } from './imageLayer';
-export { default as RasterLayer } from './rasterLayer';
diff --git a/src/layer/lineLayer.js b/src/layer/lineLayer.js
index 4d40755100..c83c3f0a88 100644
--- a/src/layer/lineLayer.js
+++ b/src/layer/lineLayer.js
@@ -12,11 +12,10 @@ export default class LineLayer extends Layer {
this.type = 'polyline';
this.init();
const source = this.layerSource;
- const StyleData = this.StyleData;
+ const layerData = this.layerData;
const style = this.get('styleOptions');
const buffer = this._buffer = new LineBuffer({
- coordinates: source.geoData,
- properties: StyleData,
+ layerData,
shapeType: this.shapeType,
style
});
diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js
index a21a80b4a7..02acff004f 100644
--- a/src/layer/pointLayer.js
+++ b/src/layer/pointLayer.js
@@ -46,12 +46,12 @@ export default class PointLayer extends Layer {
case 'fill' :// 填充图形
{
if (fill !== 'none') { // 是否填充
- const attributes = PointBuffer.FillBuffer(source.geoData, this.StyleData, style);
+ const attributes = PointBuffer.FillBuffer(this.layerData, style);
const meshfill = drawPoint.DrawFill(attributes, this.get('styleOptions'));
this.add(meshfill);
}
if (stroke !== 'none') { // 是否绘制边界
- const lineAttribute = PointBuffer.StrokeBuffer(source.geoData, this.StyleData, style);
+ const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style);
const meshStroke = drawPoint.DrawStroke(lineAttribute, this.get('styleOptions'));
this.add(meshStroke, 'line');
}
@@ -59,14 +59,14 @@ export default class PointLayer extends Layer {
}
case 'image':// 绘制图片标注
{
- const imageAttribute = PointBuffer.ImageBuffer(source.geoData, this.StyleData, { imagePos: this.scene.image.imagePos });
+ const imageAttribute = PointBuffer.ImageBuffer(this.layerData, { imagePos: this.scene.image.imagePos });
const imageMesh = drawPoint.DrawImage(imageAttribute, { ...style, texture: this.scene.image.texture });
this.add(imageMesh);
break;
}
case 'normal' : // 原生点
{
- const normalAttribute = PointBuffer.NormalBuffer(source.geoData, this.StyleData, style);
+ const normalAttribute = PointBuffer.NormalBuffer(this.layerData, style);
const normalPointMesh = drawPoint.DrawNormal(normalAttribute, style);
this.add(normalPointMesh);
break;
@@ -78,11 +78,11 @@ export default class PointLayer extends Layer {
_getShape() {
let shape = null;
- if (!this.StyleData[0].hasOwnProperty('shape')) {
+ if (!this.layerData[0].hasOwnProperty('shape')) {
return 'normal';
}
- for (let i = 0; i < this.StyleData.length; i++) {
- shape = this.StyleData[i].shape;
+ for (let i = 0; i < this.layerData.length; i++) {
+ shape = this.layerData[i].shape;
if (shape !== undefined) {
break;
}
@@ -103,8 +103,7 @@ export default class PointLayer extends Layer {
const styleOptions = this.get('styleOptions');
const buffer = new TextBuffer({
type: this.shapeType,
- coordinates: source.geoData,
- properties: this.StyleData,
+ layerData: this.layerData,
style: this.get('styleOptions')
});
diff --git a/src/layer/polygonLayer.js b/src/layer/polygonLayer.js
index 53e7c9903e..ba37ed3b87 100644
--- a/src/layer/polygonLayer.js
+++ b/src/layer/polygonLayer.js
@@ -21,11 +21,9 @@ export default class PolygonLayer extends Layer {
_prepareRender() {
this.init();
this.type = 'polygon';
- const source = this.layerSource;
this._buffer = new PolygonBuffer({
shape: this.shape,
- coordinates: source.geoData,
- properties: this.StyleData
+ layerData: this.layerData
});
this.add(this._getLayerRender());
}
diff --git a/src/layer/rasterLayer.js b/src/layer/rasterLayer.js
index 7a68dc8530..cb5d9f41a9 100644
--- a/src/layer/rasterLayer.js
+++ b/src/layer/rasterLayer.js
@@ -1,16 +1,10 @@
import Layer from '../core/layer';
import * as THREE from '../core/three';
-import RasterSource from '../source/rasterSource';
import RasterMaterial from '../geom/material/rasterMaterial';
import { RasterBuffer } from '../geom/buffer/raster';
export default class RasterLayer extends Layer {
- source(data, cfg = {}) {
- cfg.mapType = this.get('mapType');
- cfg.data = data;
- this.layerSource = new RasterSource(cfg);
- return this;
- }
+
render() {
this.type = 'raster';
this.init();
@@ -18,18 +12,18 @@ export default class RasterLayer extends Layer {
// 加载 完成事件
const styleOptions = this.get('styleOptions');
const buffer = new RasterBuffer({
- coordinates: source.geoData,
- raster: source.rasterData,
+ layerData: source.data,
rampColors: styleOptions.rampColors
});
this.initGeometry(buffer.attributes);
+ const rasterConfig = source.data.dataArray[0];
const material = new RasterMaterial({
u_texture: buffer.bufferStruct.u_raster,
u_colorTexture: buffer.bufferStruct.u_colorTexture,
u_opacity: 1.0,
u_extent: buffer.bufferStruct.u_extent,
- u_min: source.rasterData.min,
- u_max: source.rasterData.max,
+ u_min: rasterConfig.min,
+ u_max: rasterConfig.max,
u_dimension: buffer.attributes.dimension
});
diff --git a/src/layer/render/heatmap/gird.js b/src/layer/render/heatmap/gird.js
new file mode 100644
index 0000000000..5aa4b07796
--- /dev/null
+++ b/src/layer/render/heatmap/gird.js
@@ -0,0 +1,21 @@
+import * as THREE from '../../../core/three';
+import GridMaterial from '../../../geom/material/grid';
+export default function DrawGrid(attributes, style) {
+ const { opacity, xOffset, yOffset, coverage } = style;
+ const geometry = new THREE.BufferGeometry();
+ geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
+ geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
+ geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
+ geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
+ const material = new GridMaterial({
+ u_opacity: opacity,
+ u_xOffset: xOffset,
+ u_yOffset: yOffset,
+ u_coverage: coverage
+ }, {
+ SHAPE: false
+ });
+ const gridMesh = new THREE.Mesh(geometry, material);
+ return gridMesh;
+}
+
diff --git a/src/source/csvSource.js b/src/source/csvSource.js
deleted file mode 100644
index e5ce0b9834..0000000000
--- a/src/source/csvSource.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Source from '../core/source';
-import FeatureIndex from '../geo/featureIndex';
-import { csvParse } from 'd3-dsv';
-export default class CSVSource extends Source {
- prepareData() {
- this.type = 'csv';
- const data = this.get('data');
- const x = this.get('x');
- const y = this.get('y');
- const x1 = this.get('x1');
- const y1 = this.get('y1');
- const coords = this.get('coordinates');
- this.propertiesData = [];// 临时使用
- this.geoData = [];
- let csvdata = data;
- Array.isArray(csvdata) || (csvdata = csvParse(data));
- this.propertiesData = csvdata;
- csvdata.forEach((col, featureIndex) => {
- let coordinates = [];
- if (col.coordinates) {
- coordinates = col.coordinates;
- }
- if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
- if (x1 && y1) { // 弧线 或者线段
- coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
- }
- if (coords && col.coords) { coordinates = col.coords; }
- col._id = featureIndex + 1;
- this._coordProject(coordinates);
- this.geoData.push(this._coordProject(coordinates));
- });
- }
-
- featureIndex() {
- const data = this.get('data');
- this.featureIndex = new FeatureIndex(data);
- }
- getSelectFeatureId(featureId) {
- return [ featureId ];
- }
- getSelectFeature(featureId) {
- return this.propertiesData[featureId];
-
- }
- _getCoord(geo) {
- if (geo.geometry) {
- // GeoJSON feature
- geo = geo.geometry.coordinates;
- } else if (geo.coordinates) {
- // GeoJSON geometry
- geo = geo.coordinates;
- }
- return geo;
- }
- _coordProject(geo) {
- if (Array.isArray(geo[0][0])) {
- return geo.map(coor => {
- return this._coordProject(coor);
- });
- }
- if (!Array.isArray(geo[0])) {
- return this._coorConvert(geo);
- }
- return geo.map(coor => {
- return this._coorConvert(coor);
- });
- }
-
-}
diff --git a/src/source/factory.js b/src/source/factory.js
new file mode 100644
index 0000000000..37629b9e99
--- /dev/null
+++ b/src/source/factory.js
@@ -0,0 +1,11 @@
+
+const TRANSFORMS = {};
+const PARSERS = {};
+export const getParser = type => PARSERS[type];
+export const registerParser = (type, parserFunction) => {
+ PARSERS[type] = parserFunction;
+};
+export const getTransform = type => TRANSFORMS[type];
+export const registerTransform = (type, transFunction) => {
+ TRANSFORMS[type] = transFunction;
+};
diff --git a/src/source/geojsonSource.js b/src/source/geojsonSource.js
deleted file mode 100644
index df38e3fd13..0000000000
--- a/src/source/geojsonSource.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import Source from '../core/source';
-import * as turfMeta from '@turf/meta';
-import { default as cleanCoords } from '@turf/clean-coords';
-import { getCoords } from '@turf/invariant';
-import FeatureIndex from '../geo/featureIndex';
-
-export default class GeojsonSource extends Source {
- prepareData() {
- this.type = 'geojson';
- const data = this.get('data');
- this.propertiesData = [];
- this.geoData = [];
- turfMeta.flattenEach(data, (currentFeature, featureIndex) => {
- const coord = getCoords(cleanCoords(currentFeature));
- this.geoData.push(this._coordProject(coord));
- currentFeature.properties._id = featureIndex + 1;
- this.propertiesData.push(currentFeature.properties);
- });
- }
- featureIndex() {
- const data = this.get('data');
- this.featureIndex = new FeatureIndex(data);
- }
- getSelectFeatureId(featureId) {
- const data = this.get('data');
- const selectFeatureIds = [];
- let featureStyleId = 0;
- /* eslint-disable */
- turfMeta.flattenEach(data, (currentFeature, featureIndex, multiFeatureIndex) => {
- /* eslint-disable */
- if (featureIndex === (featureId)) {
- selectFeatureIds.push(featureStyleId);
- }
- featureStyleId++;
- if (featureIndex > featureId) {
- return;
- }
- });
- return selectFeatureIds;
-
- }
- getSelectFeature(featureId){
- const data = this.get('data');
- return data.features[featureId];
- }
-
-}
diff --git a/src/source/imageSource.js b/src/source/imageSource.js
deleted file mode 100644
index 137f5a0772..0000000000
--- a/src/source/imageSource.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import Source from '../core/source';
-import { getImage } from '../util/ajax';
-export default class ImageSource extends Source {
- prepareData() {
- this.type = 'image';
- const extent = this.get('extent');
- const lb = this._coorConvert(extent.slice(0, 2));
- const tr = this._coorConvert(extent.slice(2, 4));
- this.geoData = [ lb, tr ];
- this.propertiesData = [];
- this._loadData();
- }
- _loadData() {
- const url = this.get('data');
- this.image = [];
- if (typeof (url) === 'string') {
- getImage({ url }, (err, img) => {
- this.image = img;
- this.emit('imageLoaded');
- });
- } else {
- const imageCount = url.length;
- let imageindex = 0;
- url.forEach(item => {
- getImage({ url: item }, (err, img) => {
- imageindex++;
- this.image.push(img);
- if (imageindex === imageCount) {
- this.emit('imageLoaded');
- }
-
- });
- });
-
- }
- }
-}
diff --git a/src/source/index.js b/src/source/index.js
index ea6b260c09..307819cc1f 100644
--- a/src/source/index.js
+++ b/src/source/index.js
@@ -1,5 +1,23 @@
-export { default as geojson } from './geojsonSource';
-export { default as csv } from './csvSource';
-export { default as array } from './csvSource';
-export { default as basic } from '../core/source';
-export { default as imageSource } from './imageSource';
+// source parser
+
+import geojson from './parser/geojson';
+import image from './parser/image';
+import csv from './parser/csv';
+import json from './parser/json';
+import raster from './parser/raster';
+
+import { registerTransform, registerParser } from './factory';
+import { aggregatorToGrid } from './transform/grid-aggregator';
+import { map } from './transform/map';
+
+registerParser('geojson', geojson);
+registerParser('image', image);
+registerParser('csv', csv);
+registerParser('json', json);
+registerParser('raster', raster);
+// 注册transform
+
+registerTransform('grid', aggregatorToGrid);
+registerTransform('map', map);
+
+export { getTransform, registerTransform, getParser, registerParser } from './factory';
diff --git a/src/source/parser/csv.js b/src/source/parser/csv.js
new file mode 100644
index 0000000000..f727d18209
--- /dev/null
+++ b/src/source/parser/csv.js
@@ -0,0 +1,23 @@
+import { csvParse } from 'd3-dsv';
+export default function csv(data, cfg) {
+ const { x, y, x1, y1 } = cfg;
+ const csvdata = csvParse(data);
+ const resultdata = [];
+ csvdata.forEach((col, featureIndex) => {
+ let coordinates = [];
+ if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
+ if (x1 && y1) { // 弧线 或者线段
+ coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
+ }
+ col._id = featureIndex + 1;
+ const dataItem = {
+ ...col,
+ coordinates
+
+ };
+ resultdata.push(dataItem);
+ });
+ return {
+ dataArray: resultdata
+ };
+}
diff --git a/src/source/parser/geojson.js b/src/source/parser/geojson.js
new file mode 100644
index 0000000000..6385fa0d42
--- /dev/null
+++ b/src/source/parser/geojson.js
@@ -0,0 +1,19 @@
+import * as turfMeta from '@turf/meta';
+import { default as cleanCoords } from '@turf/clean-coords';
+import { getCoords } from '@turf/invariant';
+
+export default function geoJSON(data) {
+ const resultData = [];
+ turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
+ const coord = getCoords(cleanCoords(currentFeature));
+ const dataItem = {
+ ...currentFeature.properties,
+ coordinates: coord,
+ _id: featureIndex + 1
+ };
+ resultData.push(dataItem);
+ });
+ return {
+ dataArray: resultData
+ };
+}
diff --git a/src/source/parser/image.js b/src/source/parser/image.js
new file mode 100644
index 0000000000..e4a6f99ddf
--- /dev/null
+++ b/src/source/parser/image.js
@@ -0,0 +1,41 @@
+import { getImage } from '../../util/ajax';
+export default function image(data, cfg) {
+ const { extent } = cfg;
+
+ const images = new Promise(resolve => {
+ loadData(data, res => {
+ resolve(res);
+ });
+ });
+ const resultData = {
+ images,
+ _id: 1,
+ dataArray: [{ coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
+ };
+ return resultData;
+}
+function loadData(data, done) {
+ const url = data;
+ let image = [];
+ if (typeof (url) === 'string') {
+ getImage({ url }, (err, img) => {
+ image = img;
+ done(image);
+ });
+ } else {
+ const imageCount = url.length;
+ let imageindex = 0;
+ url.forEach(item => {
+ getImage({ url: item }, (err, img) => {
+ imageindex++;
+ image.push(img);
+ if (imageindex === imageCount) {
+ done(image);
+ }
+
+ });
+ });
+
+ }
+ return image;
+}
diff --git a/src/source/parser/json.js b/src/source/parser/json.js
new file mode 100644
index 0000000000..37128bebce
--- /dev/null
+++ b/src/source/parser/json.js
@@ -0,0 +1,21 @@
+export default function json(data, cfg) {
+ const { x, y, x1, y1 } = cfg;
+ const resultdata = [];
+ data.forEach((col, featureIndex) => {
+ let coordinates = [];
+ if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
+ if (x1 && y1) { // 弧线 或者线段
+ coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
+ }
+ col._id = featureIndex + 1;
+ const dataItem = {
+ ...col,
+ coordinates
+
+ };
+ resultdata.push(dataItem);
+ });
+ return {
+ dataArray: resultdata
+ };
+}
diff --git a/src/source/parser/raster.js b/src/source/parser/raster.js
new file mode 100644
index 0000000000..7d33903a23
--- /dev/null
+++ b/src/source/parser/raster.js
@@ -0,0 +1,15 @@
+export default function raster(data, cfg) {
+ const { extent, width, height, min, max } = cfg;
+ const resultData = {
+ _id: 1,
+ dataArray: [
+ {
+ data,
+ width,
+ height,
+ min,
+ max,
+ coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
+ };
+ return resultData;
+}
diff --git a/src/source/rainSource.js b/src/source/rainSource.js
deleted file mode 100644
index 6808878742..0000000000
--- a/src/source/rainSource.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import imageSource from './imageSource';
-export class RainSource extends imageSource {
- prepareData() {
- const extent = this.get('extent');
- const lb = this._coorConvert(extent.slice(0, 2));
- const tr = this._coorConvert(extent.slice(2, 4));
- this.extent = [ lb, tr ];
- this.propertiesData = [];
- this._genaratePoints();
- this._loadData();
- }
- _genaratePoints() {
- const numParticles = 512 * 512;
-
- const particleRes = this.particleRes = Math.ceil(Math.sqrt(numParticles));
- const numPoints = particleRes * particleRes;
- const particleState = [];
- const particleState0 = new Uint8ClampedArray(numPoints * 4);
- const particleState1 = new Uint8ClampedArray(numPoints * 4);
- const emptyPixels = new Uint8ClampedArray(numPoints * 4);
- for (let i = 0; i < particleState0.length; i++) {
- particleState0[i] = Math.floor(Math.random() * 256); // randomize the initial particle positions
- }
- this.particleIndices = new Float32Array(numPoints);
- for (let i = 0; i < numPoints; i++) this.particleIndices[i] = i;
- this.particleImage0 = new ImageData(particleState0, particleRes, particleRes);
- this.particleImage1 = new ImageData(particleState1, particleRes, particleRes);
- this.backgroundImage = new ImageData(emptyPixels, particleRes, particleRes);
- this.geoData = particleState;
- }
-}
diff --git a/src/source/rasterSource.js b/src/source/rasterSource.js
deleted file mode 100644
index 2439422dce..0000000000
--- a/src/source/rasterSource.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Source from '../core/source';
-export default class RasterSource extends Source {
- prepareData() {
- this.type = 'raster';
- const extent = this.get('extent');
- const lb = this._coorConvert(extent.slice(0, 2));
- const tr = this._coorConvert(extent.slice(2, 4));
- this.geoData = [ lb, tr ];
- this.propertiesData = [];
- this.rasterData = {
- data: this.get('data'),
- width: this.get('width'),
- height: this.get('height'),
- min: this.get('min'),
- max: this.get('max')
- };
-
- }
-
-}
diff --git a/src/source/transform/grid-aggregator.js b/src/source/transform/grid-aggregator.js
new file mode 100644
index 0000000000..d2ace3476c
--- /dev/null
+++ b/src/source/transform/grid-aggregator.js
@@ -0,0 +1,101 @@
+/**
+ * 生成四边形热力图
+ */
+import * as statistics from './statistics';
+
+const R_EARTH = 6378000;
+
+/**
+ * 计算方格密度图
+ * @param {*} data 经纬度数据 和属性数据
+ * @param {*} size 半径大小 单位 km
+ * @return
+ */
+export function aggregatorToGrid(data, option) {
+ const dataArray = data.dataArray;
+ const { size = 10 } = option;
+ const { gridHash, gridOffset } = _pointsGridHash(dataArray, size);
+ const layerData = _getGridLayerDataFromGridHash(gridHash, gridOffset, option);
+ return {
+ xOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
+ yOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
+ dataArray: layerData
+ };
+}
+
+function _pointsGridHash(dataArray, size) {
+ let latMin = Infinity;
+ let latMax = -Infinity;
+ let pLat;
+ for (let index = 0; index < dataArray.length; index++) {
+ const point = dataArray[index];
+ pLat = point.coordinates[1];
+ if (Number.isFinite(pLat)) {
+ latMin = pLat < latMin ? pLat : latMin;
+ latMax = pLat > latMax ? pLat : latMax;
+ }
+
+ }
+ // const centerLat = (latMin + latMax) / 2;
+ const centerLat = 34.54083;
+ const gridOffset = _calculateGridLatLonOffset(size, centerLat);
+ if (gridOffset.xOffset <= 0 || gridOffset.yOffset <= 0) {
+ return { gridHash: {}, gridOffset };
+ }
+ const gridHash = {};
+ for (let index = 0; index < dataArray.length; index++) {
+ const point = dataArray[index];
+ const lat = point.coordinates[1];
+ const lng = point.coordinates[0];
+
+ if (Number.isFinite(lat) && Number.isFinite(lng)) {
+ const latIdx = Math.floor((lat + 90) / gridOffset.yOffset);
+ const lonIdx = Math.floor((lng + 180) / gridOffset.xOffset);
+ const key = `${latIdx}-${lonIdx}`;
+
+ gridHash[key] = gridHash[key] || { count: 0, points: [] };
+ gridHash[key].count += 1;
+ gridHash[key].points.push(point);
+ }
+ }
+
+ return { gridHash, gridOffset };
+}
+// 计算网格偏移量
+function _calculateGridLatLonOffset(cellSize, latitude) {
+ const yOffset = _calculateLatOffset(cellSize);
+ const xOffset = _calculateLonOffset(latitude, cellSize);
+ return { yOffset, xOffset };
+}
+
+function _calculateLatOffset(dy) {
+ return (dy / R_EARTH) * (180 / Math.PI);
+}
+
+function _calculateLonOffset(lat, dx) {
+ return ((dx / R_EARTH) * (180 / Math.PI)) / Math.cos((lat * Math.PI) / 180);
+}
+function _getGridLayerDataFromGridHash(gridHash, gridOffset, option) {
+ return Object.keys(gridHash).reduce((accu, key, i) => {
+ const idxs = key.split('-');
+ const latIdx = parseInt(idxs[0], 10);
+ const lonIdx = parseInt(idxs[1], 10);
+ const item = {};
+ if (option.field && option.method) {
+ const columns = getColumn(gridHash[key].points, option.field);
+ item[option.method] = statistics[option.method](columns);
+ }
+ Object.assign(item, {
+ _id: i + 1,
+ coordinates: [ -180 + gridOffset.xOffset * lonIdx, -90 + gridOffset.yOffset * latIdx ],
+ count: gridHash[key].count
+ });
+ accu.push(item);
+ return accu;
+ }, []);
+}
+function getColumn(data, columnName) {
+ return data.map(item => {
+ return item[columnName];
+ });
+}
diff --git a/src/source/transform/map.js b/src/source/transform/map.js
new file mode 100644
index 0000000000..47c66e1005
--- /dev/null
+++ b/src/source/transform/map.js
@@ -0,0 +1,7 @@
+export function map(data, options) {
+ const { callback } = options;
+ if (callback) {
+ data.dataArray = data.dataArray.map(callback);
+ }
+ return data;
+}
diff --git a/src/source/transform/statistics.js b/src/source/transform/statistics.js
new file mode 100644
index 0000000000..2a7a317846
--- /dev/null
+++ b/src/source/transform/statistics.js
@@ -0,0 +1,10 @@
+/* 支持 'max', 'mean', 'median', 'min', 'mode', 'product', 'standardDeviation',
+ * 'sum', 'sumSimple', 'variance', 'count', 'distinct'
+ */
+export { default as min } from 'simple-statistics/src/min';
+export { default as max } from 'simple-statistics/src/max';
+export { default as mean } from 'simple-statistics/src/mean';
+export { default as sum } from 'simple-statistics/src/sum';
+export { default as median } from 'simple-statistics/src/median';
+export { default as standardDeviation } from 'simple-statistics/src/standard_deviation';
+