From a942af8494046ce4935064e156913c4e65f1dc96 Mon Sep 17 00:00:00 2001 From: "wensen.lws" Date: Tue, 20 Nov 2018 17:49:45 +0800 Subject: [PATCH 01/16] chore(dev): fixing code style to pass linting --- src/core/layer.js | 17 ++++++++--------- src/core/scene.js | 7 ++++--- src/geom/buffer/point.js | 2 +- src/layer/pointLayer.js | 4 ++-- src/source/csvSource.js | 3 +-- src/source/geojsonSource.js | 22 ++++++++++------------ src/worker/main.worker.js | 3 +-- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/core/layer.js b/src/core/layer.js index f8132f46b0..4a7e37b7db 100644 --- a/src/core/layer.js +++ b/src/core/layer.js @@ -419,9 +419,8 @@ export default class Layer extends Base { } } /** - * - * @param {*} overwrite - * @param {*} callback + * @param {*} type 类型 + * @param {*} callback 回调函数 */ on(type, callback) { @@ -448,7 +447,7 @@ export default class Layer extends Base { const pickmaterial = new PickingMaterial({ u_zoom: this.scene.getZoom() }); - + const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial); pickmaterial.setDefinesvalue(this.type, true); pickingMesh.onBeforeRender = () => { @@ -464,7 +463,7 @@ export default class Layer extends Base { // TODO: Find a way to properly remove this listener on destroy this.scene.on('pick', e => { // Re-emit click event from the layer - const { featureId, point2d, point3d, intersects } = e; + const { featureId, point2d, /* point3d, */intersects } = e; if (intersects.length === 0) { return; } const source = this.layerSource.get('data'); const feature = source.features[featureId]; @@ -493,7 +492,7 @@ export default class Layer extends Base { const colorAttr = this.layerMesh.geometry.attributes.a_color; const firstId = pickingId.indexOf(featureStyleId[0] + 1); for (let i = firstId; i < pickingId.length; i++) { - if (pickingId[i] == featureStyleId[0] + 1) { + if (pickingId[i] === featureStyleId[0] + 1) { colorAttr.array[i * 4 + 0] = color[0]; colorAttr.array[i * 4 + 1] = color[1]; colorAttr.array[i * 4 + 2] = color[2]; @@ -556,7 +555,7 @@ export default class Layer extends Base { } else if (this.type === 'polyline') { offset = 2; } - this._object3D.position.z = offset * Math.pow(2, 20 - zoom); + this._object3D.position.z = offset * Math.pow(2, 20 - zoom); if (zoom < minZoom || zoom > maxZoom) { this._object3D.visible = false; } else if (this.get('visible')) { @@ -569,11 +568,11 @@ export default class Layer extends Base { resetStyle() { const pickingId = this.layerMesh.geometry.attributes.pickingId.array; const colorAttr = this.layerMesh.geometry.attributes.a_color; - this._activeIds.forEach((index, value) => { + this._activeIds.forEach(index => { const color = this.StyleData[index].color; const firstId = pickingId.indexOf(index + 1); for (let i = firstId; i < pickingId.length; i++) { - if (pickingId[i] == index + 1) { + if (pickingId[i] === index + 1) { colorAttr.array[i * 4 + 0] = color[0]; colorAttr.array[i * 4 + 1] = color[1]; colorAttr.array[i * 4 + 2] = color[2]; diff --git a/src/core/scene.js b/src/core/scene.js index 52e9d90ed1..36b1a65430 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -33,9 +33,10 @@ export default class Scene extends Base { Map.on('mapLoad', () => { this._initEngine(Map.renderDom); const sceneMap = new GaodeMap(Map.map); - // eslint-disable-next-line - Object.getOwnPropertyNames(sceneMap.__proto__).forEach((key)=>{ - if ('key' !== 'constructor') { this.__proto__[key] = sceneMap.__proto__[key]; } + Object.getOwnPropertyNames(sceneMap.prototype).forEach(key => { + if (key !== 'constructor') { + this.prototype[key] = sceneMap.prototype[key]; + } }); this.map = Map.map; Map.asyncCamera(this._engine); diff --git a/src/geom/buffer/point.js b/src/geom/buffer/point.js index bb928c86af..833b101a2c 100644 --- a/src/geom/buffer/point.js +++ b/src/geom/buffer/point.js @@ -1,7 +1,7 @@ import BufferBase from './bufferBase'; import { regularShape } from '../shape/index'; import Util from '../../util'; -import * as THREE from '../../core/three'; +// import * as THREE from '../../core/three'; export default class PointBuffer extends BufferBase { geometryBuffer() { const type = this.get('type'); diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js index 1ba952e088..fa9c1bc7bb 100644 --- a/src/layer/pointLayer.js +++ b/src/layer/pointLayer.js @@ -7,7 +7,7 @@ import TextBuffer from '../geom/buffer/text'; import TextMaterial from '../geom/material/textMaterial'; import radar from '../geom/shader/radar_frag.glsl'; import warn from '../geom/shader/warn_frag.glsl'; -import pickingMaterial from '../core/engine/picking/pickingMaterial'; +// import pickingMaterial from '../core/engine/picking/pickingMaterial'; /** * point shape 2d circle, traingle text,image @@ -58,7 +58,7 @@ export default class PointLayer extends Layer { // u_zoom: this.scene.getZoom() // }) // mtl.setDefinesvalue('point', true); - mtl.setDefinesvalue('SHAPE', true); + mtl.setDefinesvalue('SHAPE', true); if (shape === 'radar') { mtl.fragmentShader = radar; diff --git a/src/source/csvSource.js b/src/source/csvSource.js index 294407cc53..89dc55b1cc 100644 --- a/src/source/csvSource.js +++ b/src/source/csvSource.js @@ -21,8 +21,7 @@ export default class CSVSource extends Source { if (col.coordinates) { coordinates = col.coordinates; } - if(x && y) - coordinates = [ col[x], col[y] ]; + if (x && y) { coordinates = [ col[x], col[y] ]; } if (x1 && y1) { coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]]; } diff --git a/src/source/geojsonSource.js b/src/source/geojsonSource.js index 0a611e8da9..f12872c4c2 100644 --- a/src/source/geojsonSource.js +++ b/src/source/geojsonSource.js @@ -25,19 +25,17 @@ export default class GeojsonSource extends Source { 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; - } - }); + turfMeta.flattenEach(data, (currentFeature, featureIndex/* , multiFeatureIndex*/) => { + if (featureIndex === (featureId)) { + selectFeatureIds.push(featureStyleId); + } + featureStyleId++; + if (featureIndex > featureId) { + return; + } + }); return selectFeatureIds; - + } } diff --git a/src/worker/main.worker.js b/src/worker/main.worker.js index 61f73c16d5..eb53453282 100644 --- a/src/worker/main.worker.js +++ b/src/worker/main.worker.js @@ -30,6 +30,5 @@ self.addEventListener('message', e => { } }); self.addEventListener('error', function(e) { - /* eslint-disable */ - console.log('filename:' + e.filename + '\nmessage:' + e.message + '\nline:' + e.lineno); + console.error('filename:' + e.filename + '\nmessage:' + e.message + '\nline:' + e.lineno); }); From 6fb7d2717d97138f0a7042bea1e668db5cf9dbcd Mon Sep 17 00:00:00 2001 From: "wensen.lws" Date: Tue, 20 Nov 2018 20:21:50 +0800 Subject: [PATCH 02/16] chore(dev): do not upload sources and ignore tests --- .npmignore | 3 +++ package.json | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.npmignore b/.npmignore index e3b88f8933..fd527239c4 100755 --- a/.npmignore +++ b/.npmignore @@ -70,8 +70,11 @@ test *.un~ .idea bin +bundler demos docs +lib +src temp webpack-dev.config.js webpack.config.js diff --git a/package.json b/package.json index 816c18fbbc..d61e5d7c09 100755 --- a/package.json +++ b/package.json @@ -87,8 +87,7 @@ }, "pre-commit": { "run": [ - "lint", - "test-all" + "lint" ], "silent": false }, From ce97d0fde23ac61be8c8d14dd470aa4faffbe4ec Mon Sep 17 00:00:00 2001 From: "wensen.lws" Date: Tue, 20 Nov 2018 20:27:39 +0800 Subject: [PATCH 03/16] chore(dev): publish to npmjs.com --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index d61e5d7c09..585c3d8b6c 100755 --- a/package.json +++ b/package.json @@ -91,9 +91,6 @@ ], "silent": false }, - "publishConfig": { - "registry": "http://registry.npm.alibaba-inc.com" - }, "dependencies": { "@antv/g": "^3.1.3", "@antv/util": "~1.2.5", From 7b583866fa80f283a736f9cabed232f46a683f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=AD=A3=E5=AD=A6?= Date: Thu, 24 Jan 2019 21:06:08 +0800 Subject: [PATCH 04/16] fix(scene): event on map --- package.json | 2 +- src/core/engine/picking/picking.js | 61 ++---------------------------- src/core/scene.js | 11 +----- src/source/geojsonSource.js | 4 +- 4 files changed, 9 insertions(+), 69 deletions(-) diff --git a/package.json b/package.json index cbaf70578a..8ab26df3c2 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/l7", - "version": "1.0.1", + "version": "1.0.3", "description": "Large-scale WebGL-powered Geospatial Data Visualization", "main": "build/l7.js", "browser": "build/l7.js", diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js index e4fb4c2ee1..0dfd718fbe 100755 --- a/src/core/engine/picking/picking.js +++ b/src/core/engine/picking/picking.js @@ -9,10 +9,7 @@ class Picking { this._camera = camera; this._raycaster = new THREE.Raycaster(); this.scene = scene; - this._envents = []; - - // TODO: Match this with the line width used in the picking layers - this._raycaster.linePrecision = 3; + this._raycaster.linePrecision = 10; this._pickingScene = PickingScene; const size = this._renderer.getSize(); this._width = size.width; @@ -21,7 +18,7 @@ class Picking { magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBuffer: false, - depthBuffer: false + depthBuffer: true }; this._pickingTexture = new THREE.WebGLRenderTarget(this._width, this._height, parameters); @@ -35,38 +32,15 @@ class Picking { _initEvents() { this._resizeHandler = this._resizeTexture.bind(this); window.addEventListener('resize', this._resizeHandler, false); - - // this._mouseUpHandler = this._onMouseUp.bind(this); - // this._world._container.addEventListener('mouseup', this._mouseUpHandler, false); - // this._world._container.addEventListener('mousemove', this._mouseUpHandler, false); - // 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.pixel.x, y: event.pixel.y, 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; this._pickAllObject(point, normalisedPoint); } - _onMouseUp(event) { - // Only react to main button click - // 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; - normalisedPoint.y = -(point.y / this._height) * 2 + 1; - this._pickAllObject(point, normalisedPoint); - // this._pick(point, normalisedPoint); - } - _onWorldMove() { - - this._needUpdate = true; - } - - // TODO: Ensure this doesn't get out of sync issue with the renderer resize _resizeTexture() { const size = this._renderer.getSize(); @@ -80,28 +54,11 @@ class Picking { _update(point) { const texture = this._pickingTexture; - // if (this._needUpdate) { this._renderer.render(this._pickingScene, this._camera, this._pickingTexture); - // this._needUpdate = false; - // } this.pixelBuffer = new Uint8Array(4); this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer); - } - // 添加dom事件 支持 mousedown ,mouseenter mouseleave mousemove mouseover mouseout mouse up - on(type) { - - this._mouseUpHandler = this._onMouseUp.bind(this); - this._world._container.addEventListener(type, this._mouseUpHandler, false); - this._envents.push([ type, this._mouseUpHandler ]); - } - off(type, hander) { - this._world._container.removeEventListener(type, this._mouseUpHandler, false); - this._envents = this._envents.filter(item => { - return item[0] === 'type' && hander === item[1]; - }); - } _filterObject(id) { this._pickingScene.children.forEach((object, index) => { @@ -124,9 +81,7 @@ class Picking { _pick(point, normalisedPoint, layerId) { this._update(point); - // Interpret the pixel as an ID let id = (this.pixelBuffer[2] * 255 * 255) + (this.pixelBuffer[1] * 255) + (this.pixelBuffer[0]); - // Skip if ID is 16646655 (white) as the background returns this if (id === 16646655 || this.pixelBuffer[3] === 0) { id = -999; // return; @@ -134,9 +89,6 @@ class Picking { this._raycaster.setFromCamera(normalisedPoint, this._camera); - // Perform ray intersection on picking scene - // - // TODO: Only perform intersection test on the relevant picking mesh const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true); const _point2d = { x: point.x, y: point.y }; @@ -144,11 +96,6 @@ class Picking { if (intersects.length > 0) { _point3d = intersects[0].point; } - - // Pass along as much data as possible for now until we know more about how - // people use the picking API and what the returned data should be - // - // TODO: Look into the leak potential for passing so much by reference here const item = { layerId, featureId: id - 1, diff --git a/src/core/scene.js b/src/core/scene.js index 30820daa8a..8879215fe2 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -83,14 +83,6 @@ export default class Scene extends Base { getLayers() { return this._layers; } - _addLight() { - // const scene = this._engine._scene; - // //const ambientLight = new THREE.AmbientLight(0xaaaaaa); - // scene.add(ambientLight); - - // const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); - // scene.add(directionalLight); - } _addLayer() { } @@ -102,11 +94,12 @@ export default class Scene extends Base { 'mousedown', 'mouseleave', 'mouseup', + 'rightclick', 'click', 'dblclick' ]; events.forEach(event => { - this._container.addEventListener(event, e => { + this.map.on(event, e => { // 要素拾取 this._engine._picking.pickdata(e); }, false); diff --git a/src/source/geojsonSource.js b/src/source/geojsonSource.js index cc312a8107..1b1c012568 100644 --- a/src/source/geojsonSource.js +++ b/src/source/geojsonSource.js @@ -37,9 +37,9 @@ export default class GeojsonSource extends Source { return selectFeatureIds; } - getSelectFeature(featureId){ + getSelectFeature(featureId) { const data = this.get('data'); - return data.features[featureId]; + return data.features[featureId]; } } From ef30053ff3824c07d0c4d6879d3af2de5cc7f9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=AD=A3=E5=AD=A6?= Date: Fri, 25 Jan 2019 11:36:11 +0800 Subject: [PATCH 05/16] feat(mapbox): add mapbox --- src/map/baseMap.js | 0 src/map/mapbox.js | 124 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) delete mode 100644 src/map/baseMap.js create mode 100644 src/map/mapbox.js diff --git a/src/map/baseMap.js b/src/map/baseMap.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/map/mapbox.js b/src/map/mapbox.js new file mode 100644 index 0000000000..3512c51150 --- /dev/null +++ b/src/map/mapbox.js @@ -0,0 +1,124 @@ +import Base from '../core/base'; +import Util from '../util'; +import { scene } from '../global'; +import * as THREE from '../core/three'; +const WORLD_SIZE = 512; +export class MapBoxProvider extends Base { + getDefaultCfg() { + return Util.assign(scene, { + resizeEnable: true, + viewMode: '3D' + }); + } + constructor(container, cfg, engine) { + super(cfg); + this.container = container; + this.engine = engine; + const scene = engine._scene; + this.initMap(); + this.addOverLayer(); + scene.position.x = scene.position.y = WORLD_SIZE / 2; + scene.matrixAutoUpdate = false; + setTimeout(() => { + this.emit('mapLoad'); + }, 100); + + } + + initMap() { + mapboxgl.accessToken = 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ'; + this.map = new mapboxgl.Map(this._attrs); + this.map.on('move', () => { + this.updateCamera(); + }); + this.updateCamera(); + } + asyncCamera() { + const engine = this.engine; + const camera = engine._camera; + const scene = engine._scene; + // Build a projection matrix, paralleling the code found in Mapbox GL JS + const fov = 0.6435011087932844; + const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height; + const halfFov = fov / 2; + const groundAngle = Math.PI / 2 + this.map.transform._pitch; + const topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov); + + // Calculate z distance of the farthest fragment that should be rendered. + const furthestDistance = Math.cos(Math.PI / 2 - this.map.transform._pitch) * topHalfSurfaceDistance + cameraToCenterDistance; + + // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` + const farZ = furthestDistance * 1.01; + + camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ); + + + const cameraWorldMatrix = new THREE.Matrix4(); + const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance); + const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch); + const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle); + + // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix + // If this is applied directly to the projection matrix, it will work OK but break raycasting + cameraWorldMatrix + .premultiply(cameraTranslateZ) + .premultiply(cameraRotateX) + .premultiply(cameraRotateZ); + + camera.matrixWorld.copy(cameraWorldMatrix); + + + const zoomPow = this.map.transform.scale; + // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera + const scale = new THREE.Matrix4(); + const translateCenter = new THREE.Matrix4(); + const translateMap = new THREE.Matrix4(); + const rotateMap = new THREE.Matrix4(); + scale + .makeScale(zoomPow, zoomPow, zoomPow); + translateCenter + .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0); + translateMap + .makeTranslation(-this.map.transform.x, this.map.transform.y, 0); + rotateMap + .makeRotationZ(Math.PI); + + scene.matrix = new THREE.Matrix4(); + scene.matrix + .premultiply(rotateMap) + .premultiply(translateCenter) + .premultiply(scale) + .premultiply(translateMap); + } + makePerspectiveMatrix(fovy, aspect, near, far) { + const out = new THREE.Matrix4(); + const f = 1.0 / Math.tan(fovy / 2), + nf = 1 / (near - far); + const newMatrix = [ + f / aspect, 0, 0, 0, + 0, f, 0, 0, + 0, 0, (far + near) * nf, -1, + 0, 0, (2 * far * near) * nf, 0 + ]; + out.elements = newMatrix; + return out; + } + + projectFlat(lnglat) { + return this.map.lngLatToGeodeticCoord(lnglat); + } + getCenter() { + return this.map.getCenter(); + } + getCenterFlat() { + return this.projectFlat(this.getCenter()); + } + addOverLayer() { + const canvasContainer = document.getElementById(this.container); + this.canvasContainer = canvasContainer; + this.renderDom = document.createElement('div'); + this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:1;height: 100%;width: 100%;pointer-events: none;'; + this.renderDom.id = 'l7_canvaslayer'; + canvasContainer.appendChild(this.renderDom); + } +} From 418b3bcbc973900406f1a1093fc043f33b00c3a8 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 12 Feb 2019 20:21:14 +0800 Subject: [PATCH 06/16] feat(map): add mapbox --- src/core/controller/geom.js | 36 ---------------------- src/core/controller/map.js | 24 +++++++++++++++ src/core/engine/index.js | 3 ++ src/core/layer.js | 4 +-- src/core/scene.js | 20 ++++++------- src/core/source.js | 14 ++++----- src/core/three.js | 1 + src/map/{provider.js => AMap.js} | 51 +++++++++++++++++++++++++++++--- src/map/gaodeMap.js | 2 +- src/map/index.js | 22 ++++++++++++++ src/map/mapbox.js | 51 +++++++++++++++++++++----------- 11 files changed, 148 insertions(+), 80 deletions(-) delete mode 100644 src/core/controller/geom.js create mode 100644 src/core/controller/map.js rename src/map/{provider.js => AMap.js} (57%) create mode 100644 src/map/index.js diff --git a/src/core/controller/geom.js b/src/core/controller/geom.js deleted file mode 100644 index b0d474ac01..0000000000 --- a/src/core/controller/geom.js +++ /dev/null @@ -1,36 +0,0 @@ -import geom from '../../geom/geom'; -import { GeoBuffer, bufferGeometry, Material } from '../../geom/index'; - - -// geom shape buffer geometry material -// shape name type() -// buffer 1:n geometry -// geometry -// -export default function polygonGeom(shape, coordinates, properties, layerid) { - const polygongeom = geom.polygon; - const { buffer, geometry, material } = polygongeom[shape];// polygon 映射表 - const bufferData = new GeoBuffer[buffer]({ - coordinates, - properties, - shape - }); - bufferData.bufferStruct.name = layerid; - const bg = new bufferGeometry[geometry](bufferData.bufferStruct); - const mtl = Material[material](); - return { - geometry: bg, - mtl - }; -} - -export function pointGeom(shape, bufferData) { - const pointgeom = geom.point; - const { geometry, material } = pointgeom[shape]; - const bg = new bufferGeometry[geometry](bufferData.bufferStruct); - const mtl = Material[material](); - return { - geometry: bg, - mtl - }; -} diff --git a/src/core/controller/map.js b/src/core/controller/map.js new file mode 100644 index 0000000000..3068e61cfe --- /dev/null +++ b/src/core/controller/map.js @@ -0,0 +1,24 @@ + +import { getMap } from '../../map'; +import Base from '../base'; +export default class MapContorller extends Base { + constructor(cfg, engine, scene) { + super(cfg); + this._engine = engine; + this.scene = scene; + } + _init() { + const mapType = this.get('mapType'); + const mapCfg = this.get('mapCfg'); + this.map = new getMap(mapType)(mapCfg); + this.map('mapLoad', this._mapload.bind(this)); + } + _mapload() { + this.map.asyncCamera(this._engine); + this.emit('loaded'); + } + _bindMapMethod() { + + } + +} diff --git a/src/core/engine/index.js b/src/core/engine/index.js index d3a8eee42b..a12f2e06f6 100644 --- a/src/core/engine/index.js +++ b/src/core/engine/index.js @@ -11,6 +11,9 @@ export default class Engine extends EventEmitter { this._camera = new Camera(container).camera; this._renderer = new Renderer(container).renderer; this._world = world; + // for MapBox + this.world = new THREE.Group(); + this._scene.add(this.world); this._picking = Picking(this._world, this._renderer, this._camera, this._scene); this.clock = new THREE.Clock(); } diff --git a/src/core/layer.js b/src/core/layer.js index 50f2858587..4517ef695b 100644 --- a/src/core/layer.js +++ b/src/core/layer.js @@ -63,7 +63,8 @@ export default class Layer extends Base { const layerId = this._getUniqueId(); this.layerId = layerId; this._activeIds = null; - scene._engine._scene.add(this._object3D); + const world = scene._engine.world; + world.add(this._object3D); this.layerMesh = null; this.layerLineMesh = null; this._initEvents(); @@ -110,7 +111,6 @@ export default class Layer extends Base { const { type = dataType } = cfg; cfg.data = data; cfg.mapType = this.get('mapType'); - this.layerSource = new source[type](cfg); // this.scene.workerPool.runTask({ // command: 'geojson', diff --git a/src/core/scene.js b/src/core/scene.js index 8879215fe2..115db9fdcd 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -3,8 +3,8 @@ import * as layers from '../layer'; import Base from './base'; import LoadImage from './image'; import WorkerPool from './worker'; -import { MapProvider } from '../map/provider'; -import GaodeMap from '../map/gaodeMap'; +// import { MapProvider } from '../map/AMap'; +import { getMap } from '../map/index'; import Global from '../global'; export default class Scene extends Base { getDefaultCfg() { @@ -13,7 +13,7 @@ export default class Scene extends Base { constructor(cfg) { super(cfg); this._initMap(); - this._initAttribution(); + // this._initAttribution(); this.addImage(); this._layers = []; } @@ -29,16 +29,14 @@ export default class Scene extends Base { } _initMap() { this.mapContainer = this.get('id'); - this._container = document.getElementById(this.mapContainer); - const Map = new MapProvider(this.mapContainer, this._attrs); + this.mapType = this.get('mapType'); + const MapProvider = getMap(this.mapType); + const Map = new MapProvider(this._attrs); + Map.mixMap(this); + this._container = document.getElementById(Map.container); + // const Map = new MapProvider(this.mapContainer, this._attrs); Map.on('mapLoad', () => { this._initEngine(Map.renderDom); - const sceneMap = new GaodeMap(Map.map); - // eslint-disable-next-line - Object.getOwnPropertyNames(sceneMap.__proto__).forEach((key)=>{ - // eslint-disable-next-line - if ('key' !== 'constructor') { this.__proto__[key] = sceneMap.__proto__[key]; } - }); this.map = Map.map; Map.asyncCamera(this._engine); this.initLayer(); diff --git a/src/core/source.js b/src/core/source.js index 3a61aead88..7b7cad5d10 100644 --- a/src/core/source.js +++ b/src/core/source.js @@ -1,12 +1,6 @@ -/* - * @Author: ThinkGIS - * @Date: 2018-06-08 11:19:06 - * @Last Modified by: mikey.zhaopeng - * @Last Modified time: 2018-11-01 11:50:43 - */ import Base from './base'; const Controller = require('./controller/index'); -import { aProjectFlat } from '../geo/project'; +import { getMap } from '../map/index'; export default class Source extends Base { getDefaultCfg() { return { @@ -50,6 +44,8 @@ export default class Source extends Base { } _initControllers() { const defs = this.get('defs'); + const mapType = this.get('mapType'); + this.projectFlat = getMap(mapType).project; const scaleController = new Controller.Scale({ defs }); @@ -83,8 +79,8 @@ export default class Source extends Base { } _coorConvert(geo) { - const ll = aProjectFlat(geo); - return [ ll.x, -ll.y, geo[2] || 0 ]; + const ll = this.projectFlat(geo); + return [ ll.x, ll.y, geo[2] || 0 ]; } diff --git a/src/core/three.js b/src/core/three.js index 75cbe58b5d..03359e840d 100644 --- a/src/core/three.js +++ b/src/core/three.js @@ -4,6 +4,7 @@ export { Scene } from 'three/src/scenes/Scene.js'; export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js'; export { CanvasTexture } from 'three/src/textures/CanvasTexture.js'; export { Object3D } from 'three/src/core/Object3D.js'; +export { Group } from 'three/src/objects/Group'; export { Clock } from 'three/src/core/Clock'; export { Points } from 'three/src/objects/Points.js'; export { LineSegments } from 'three/src/objects/LineSegments.js'; diff --git a/src/map/provider.js b/src/map/AMap.js similarity index 57% rename from src/map/provider.js rename to src/map/AMap.js index 19763e8f45..e54615b94a 100644 --- a/src/map/provider.js +++ b/src/map/AMap.js @@ -1,18 +1,34 @@ import Base from '../core/base'; +import { scene } from '../global'; import * as Theme from '../theme/index'; import Util from '../util'; -import { scene } from '../global'; const DEG2RAD = Math.PI / 180; -export class MapProvider extends Base { +export default class GaodeMap extends Base { getDefaultCfg() { return Util.assign(scene, { resizeEnable: true, viewMode: '3D' }); } - constructor(container, cfg) { + static project(lnglat) { + const maxs = 85.0511287798; + const lat = Math.max(Math.min(maxs, lnglat[1]), -maxs); + const scale = 256 << 20; + let d = Math.PI / 180; + let x = lnglat[0] * d; + let y = lat * d; + y = Math.log(Math.tan((Math.PI / 4) + (y / 2))); + const a = 0.5 / Math.PI, + b = 0.5, + c = -0.5 / Math.PI; + d = 0.5; + x = scale * (a * x + b) - 215440491; + y = -(scale * (c * y + d) - 106744817); + return { x, y }; + } + constructor(cfg) { super(cfg); - this.container = container; + this.container = this.get('id'); this.initMap(); this.addOverLayer(); setTimeout(() => { @@ -85,4 +101,31 @@ export class MapProvider extends Base { this.renderDom.id = 'l7_canvaslayer'; canvasContainer.appendChild(this.renderDom); } + mixMap(scene) { + const map = this.map; + scene.getZoom = () => { return map.getZoom(); }; + scene.getCenter = () => { return map.getCenter(); }; + scene.getSize = () => { return map.getSize(); }; + scene.getPitch = () => { return map.getPitch(); }; + scene.getRotation = () => { return map.getRotation(); }; + scene.getStatus = () => { return map.getStatus(); }; + scene.getScale = () => { return map.getScale(); }; + scene.getZoom = () => { return map.getZoom(); }; + scene.setZoom = () => { return map.setZoom(); }; + scene.setBounds = () => { return map.setBounds(); }; + scene.setRotation = () => { return map.setRotation(); }; + scene.zoomIn = () => { return map.zoomIn(); }; + scene.setRotation = () => { return map.setRotation(); }; + scene.zoomOut = () => { return map.zoomOut(); }; + scene.panTo = () => { return map.panTo(); }; + scene.panBy = () => { return map.panBy(); }; + scene.setPitch = () => { return map.setPitch(); }; + scene.pixelToLngLat = () => { return map.pixelToLngLat(); }; + scene.lngLatToPixel = () => { return map.lngLatToPixel(); }; + scene.setMapStyle = () => { return map.setMapStyle(); }; + scene.containerToLngLat = pixel => { + const ll = new AMap.Pixel(pixel.x, pixel.y); + return map.containerToLngLat(ll); + }; + } } diff --git a/src/map/gaodeMap.js b/src/map/gaodeMap.js index 70f9dd8829..07301a8d3b 100644 --- a/src/map/gaodeMap.js +++ b/src/map/gaodeMap.js @@ -21,7 +21,7 @@ export default class GaodeMap { return this.map.getStatus(); } getScale() { - return this.getScale(); + return this.map.getScale(); } setZoom(zoom) { return this.map.setZoom(zoom); diff --git a/src/map/index.js b/src/map/index.js new file mode 100644 index 0000000000..ae5b7dbb7d --- /dev/null +++ b/src/map/index.js @@ -0,0 +1,22 @@ +import MapBox from './mapbox'; +import { default as AMap } from './AMap'; +export { + AMap, + MapBox +}; +const MapType = { + amap: AMap, + mapbox: MapBox +}; +export const getMap = type => { + return MapType[type.toLowerCase()]; +}; + +export const registerMap = (type, map) => { + if (getMap(type)) { + throw new Error(`Map type '${type}' existed.`); + } + map.type = type; + // 存储到 map 中 + MapType[type.toLowerCase()] = map; +}; diff --git a/src/map/mapbox.js b/src/map/mapbox.js index 3512c51150..b95fec04a1 100644 --- a/src/map/mapbox.js +++ b/src/map/mapbox.js @@ -3,22 +3,27 @@ import Util from '../util'; import { scene } from '../global'; import * as THREE from '../core/three'; const WORLD_SIZE = 512; -export class MapBoxProvider extends Base { +const MERCATOR_A = 6378137.0; +const WORLD_SCALE = 1.0; +const PROJECTION_WORLD_SIZE = WORLD_SIZE / (MERCATOR_A * Math.PI) / 2; +export default class MapBox extends Base { getDefaultCfg() { return Util.assign(scene, { resizeEnable: true, viewMode: '3D' }); } - constructor(container, cfg, engine) { + static project(lnglat) { + const d = Math.PI / 180; + const x = -MERCATOR_A * lnglat[0] * d * PROJECTION_WORLD_SIZE; + const y = -MERCATOR_A * Math.log(Math.tan((Math.PI * 0.25) + (0.5 * lnglat[1] * d))) * PROJECTION_WORLD_SIZE; + return { x, y }; + } + constructor(cfg) { super(cfg); - this.container = container; - this.engine = engine; - const scene = engine._scene; + this.container = this.get('container'); this.initMap(); this.addOverLayer(); - scene.position.x = scene.position.y = WORLD_SIZE / 2; - scene.matrixAutoUpdate = false; setTimeout(() => { this.emit('mapLoad'); }, 100); @@ -28,15 +33,24 @@ export class MapBoxProvider extends Base { initMap() { mapboxgl.accessToken = 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ'; this.map = new mapboxgl.Map(this._attrs); + } + asyncCamera(engine) { + this.engine = engine; + const camera = engine._camera; + const scene = engine.world; + camera.matrixAutoUpdate = false; + scene.position.x = scene.position.y = WORLD_SIZE / 2; + scene.matrixAutoUpdate = false; + scene.autoUpdate = false; + this.updateCamera(); this.map.on('move', () => { this.updateCamera(); }); - this.updateCamera(); } - asyncCamera() { + updateCamera() { const engine = this.engine; + const scene = engine.world; const camera = engine._camera; - const scene = engine._scene; // Build a projection matrix, paralleling the code found in Mapbox GL JS const fov = 0.6435011087932844; const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height; @@ -49,25 +63,22 @@ export class MapBoxProvider extends Base { // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const farZ = furthestDistance * 1.01; - + const { x, y } = this.map.transform.point; camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ); - - const cameraWorldMatrix = new THREE.Matrix4(); const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance); const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch); const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle); + // const cameraTranslateCenter = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance); // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix // If this is applied directly to the projection matrix, it will work OK but break raycasting cameraWorldMatrix .premultiply(cameraTranslateZ) .premultiply(cameraRotateX) .premultiply(cameraRotateZ); - camera.matrixWorld.copy(cameraWorldMatrix); - const zoomPow = this.map.transform.scale; // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera const scale = new THREE.Matrix4(); @@ -82,7 +93,6 @@ export class MapBoxProvider extends Base { .makeTranslation(-this.map.transform.x, this.map.transform.y, 0); rotateMap .makeRotationZ(Math.PI); - scene.matrix = new THREE.Matrix4(); scene.matrix .premultiply(rotateMap) @@ -117,8 +127,15 @@ export class MapBoxProvider extends Base { const canvasContainer = document.getElementById(this.container); this.canvasContainer = canvasContainer; this.renderDom = document.createElement('div'); - this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:1;height: 100%;width: 100%;pointer-events: none;'; + this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:10;height: 100%;width: 100%;pointer-events: none;'; this.renderDom.id = 'l7_canvaslayer'; canvasContainer.appendChild(this.renderDom); } + mixMap(scene) { + const map = this.map; + scene.getZoom = () => { return map.getZoom(); }; + scene.getCenter = () => { return map.getCenter(); }; + scene.getPitch = () => { return map.getPitch(); }; + + } } From 4aa73ad9d448cbb2995357c41b9dd42999a89868 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 12 Feb 2019 20:57:41 +0800 Subject: [PATCH 07/16] fixt(map): mapbox double float --- src/map/mapbox.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/map/mapbox.js b/src/map/mapbox.js index b95fec04a1..0480b520ba 100644 --- a/src/map/mapbox.js +++ b/src/map/mapbox.js @@ -4,7 +4,7 @@ import { scene } from '../global'; import * as THREE from '../core/three'; const WORLD_SIZE = 512; const MERCATOR_A = 6378137.0; -const WORLD_SCALE = 1.0; +const WORLD_SCALE = 1 / 100; const PROJECTION_WORLD_SIZE = WORLD_SIZE / (MERCATOR_A * Math.PI) / 2; export default class MapBox extends Base { getDefaultCfg() { @@ -53,7 +53,7 @@ export default class MapBox extends Base { const camera = engine._camera; // Build a projection matrix, paralleling the code found in Mapbox GL JS const fov = 0.6435011087932844; - const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height; + const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height * WORLD_SCALE; const halfFov = fov / 2; const groundAngle = Math.PI / 2 + this.map.transform._pitch; const topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov); @@ -62,31 +62,36 @@ export default class MapBox extends Base { const furthestDistance = Math.cos(Math.PI / 2 - this.map.transform._pitch) * topHalfSurfaceDistance + cameraToCenterDistance; // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` - const farZ = furthestDistance * 1.01; + let farZ = furthestDistance * 1.1; + if (this.pitch > 50) { + farZ = 1000; + } const { x, y } = this.map.transform.point; camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ); const cameraWorldMatrix = new THREE.Matrix4(); const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance); const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch); const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle); - + const cameraTranslateXY = new THREE.Matrix4().makeTranslation(x * WORLD_SCALE, -y * WORLD_SCALE, 0); // const cameraTranslateCenter = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance); // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix // If this is applied directly to the projection matrix, it will work OK but break raycasting cameraWorldMatrix .premultiply(cameraTranslateZ) .premultiply(cameraRotateX) - .premultiply(cameraRotateZ); + .premultiply(cameraRotateZ) + .premultiply(cameraTranslateXY); + camera.matrixWorld.copy(cameraWorldMatrix); - const zoomPow = this.map.transform.scale; + const zoomPow = this.map.transform.scale * WORLD_SCALE; // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera const scale = new THREE.Matrix4(); const translateCenter = new THREE.Matrix4(); const translateMap = new THREE.Matrix4(); const rotateMap = new THREE.Matrix4(); scale - .makeScale(zoomPow, zoomPow, zoomPow); + .makeScale(zoomPow, zoomPow, 1.0); translateCenter .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0); translateMap @@ -97,8 +102,7 @@ export default class MapBox extends Base { scene.matrix .premultiply(rotateMap) .premultiply(translateCenter) - .premultiply(scale) - .premultiply(translateMap); + .premultiply(scale); } makePerspectiveMatrix(fovy, aspect, near, far) { const out = new THREE.Matrix4(); From f2d9214e075bdfee1913bbc5c6758e3346edebc8 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Fri, 15 Feb 2019 11:35:04 +0800 Subject: [PATCH 08/16] fix(mapbox): scale --- src/core/engine/picking/picking.js | 12 +++++++----- src/core/scene.js | 1 + src/geom/shader/polygon_vert.glsl | 3 ++- src/map/mapbox.js | 13 +++++++++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js index 0dfd718fbe..ea6ff5c0db 100755 --- a/src/core/engine/picking/picking.js +++ b/src/core/engine/picking/picking.js @@ -11,6 +11,8 @@ class Picking { this.scene = scene; this._raycaster.linePrecision = 10; this._pickingScene = PickingScene; + this.world = new THREE.Group(); + this._pickingScene.add(this.world); const size = this._renderer.getSize(); this._width = size.width; this._height = size.height; @@ -61,12 +63,12 @@ class Picking { } _filterObject(id) { - this._pickingScene.children.forEach((object, index) => { + this.world.children.forEach((object, index) => { index === id ? object.visible = true : object.visible = false; }); } _pickAllObject(point, normalisedPoint) { - this._pickingScene.children.forEach((object, index) => { + this.world.children.forEach((object, index) => { this._filterObject(index); const item = this._pick(point, normalisedPoint, object.name); item.type = point.type; @@ -86,7 +88,6 @@ class Picking { id = -999; // return; } - this._raycaster.setFromCamera(normalisedPoint, this._camera); const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true); @@ -111,13 +112,14 @@ class Picking { // // Picking ID should already be added as an attribute add(mesh) { - this._pickingScene.add(mesh); + this.world.add(mesh); + this._needUpdate = true; } // Remove mesh from picking scene remove(mesh) { - this._pickingScene.remove(mesh); + this.world.remove(mesh); this._needUpdate = true; } diff --git a/src/core/scene.js b/src/core/scene.js index 115db9fdcd..6e9eb187cd 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -99,6 +99,7 @@ export default class Scene extends Base { events.forEach(event => { this.map.on(event, e => { // 要素拾取 + e.pixel || (e.pixel = e.point); this._engine._picking.pickdata(e); }, false); }); diff --git a/src/geom/shader/polygon_vert.glsl b/src/geom/shader/polygon_vert.glsl index 9c8508c674..eba0b62d02 100644 --- a/src/geom/shader/polygon_vert.glsl +++ b/src/geom/shader/polygon_vert.glsl @@ -15,8 +15,9 @@ varying float v_size; void main() { float scale = pow(2.0,(20.0 - u_zoom)); - mat4 matModelViewProjection = projectionMatrix * modelViewMatrix; + mat4 matModelViewProjection = projectionMatrix * modelViewMatrix * 100.; vec3 newposition = position; + // newposition.x -= 128.0; #ifdef SHAPE newposition =position + a_size * scale* a_shape; #endif diff --git a/src/map/mapbox.js b/src/map/mapbox.js index 0480b520ba..927eba688f 100644 --- a/src/map/mapbox.js +++ b/src/map/mapbox.js @@ -38,10 +38,12 @@ export default class MapBox extends Base { this.engine = engine; const camera = engine._camera; const scene = engine.world; + const pickScene = engine._picking.world; camera.matrixAutoUpdate = false; scene.position.x = scene.position.y = WORLD_SIZE / 2; scene.matrixAutoUpdate = false; - scene.autoUpdate = false; + pickScene.position.x = pickScene.position.y = WORLD_SIZE / 2; + pickScene.matrixAutoUpdate = false; this.updateCamera(); this.map.on('move', () => { this.updateCamera(); @@ -50,6 +52,7 @@ export default class MapBox extends Base { updateCamera() { const engine = this.engine; const scene = engine.world; + const pickScene = engine._picking.world; const camera = engine._camera; // Build a projection matrix, paralleling the code found in Mapbox GL JS const fov = 0.6435011087932844; @@ -91,7 +94,7 @@ export default class MapBox extends Base { const translateMap = new THREE.Matrix4(); const rotateMap = new THREE.Matrix4(); scale - .makeScale(zoomPow, zoomPow, 1.0); + .makeScale(zoomPow / 100, zoomPow / 100, 1.0); translateCenter .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0); translateMap @@ -103,6 +106,11 @@ export default class MapBox extends Base { .premultiply(rotateMap) .premultiply(translateCenter) .premultiply(scale); + pickScene.matrix = new THREE.Matrix4(); + pickScene.matrix + .premultiply(rotateMap) + .premultiply(translateCenter) + .premultiply(scale); } makePerspectiveMatrix(fovy, aspect, near, far) { const out = new THREE.Matrix4(); @@ -140,6 +148,7 @@ export default class MapBox extends Base { scene.getZoom = () => { return map.getZoom(); }; scene.getCenter = () => { return map.getCenter(); }; scene.getPitch = () => { return map.getPitch(); }; + scene.containerToLngLat = point => { return map.unproject(point); }; } } From 3496c032337b2045969db920eb9977231176395c Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 19 Feb 2019 11:08:38 +0800 Subject: [PATCH 09/16] mapbox --- src/map/mapbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/mapbox.js b/src/map/mapbox.js index 927eba688f..8eebadc8ef 100644 --- a/src/map/mapbox.js +++ b/src/map/mapbox.js @@ -94,7 +94,7 @@ export default class MapBox extends Base { const translateMap = new THREE.Matrix4(); const rotateMap = new THREE.Matrix4(); scale - .makeScale(zoomPow / 100, zoomPow / 100, 1.0); + .makeScale(zoomPow, zoomPow, 1.0); translateCenter .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0); translateMap From 92c900e8ee8a12baf96ee42e65647a31e8e41433 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 19 Feb 2019 13:58:48 +0800 Subject: [PATCH 10/16] add mapbox demo --- .gitignore | 1 - demos/mapbox.html | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 demos/mapbox.html diff --git a/.gitignore b/.gitignore index 73a92f7460..5fb73328f2 100755 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,6 @@ lib *.sw* *.un~ -demos/mapbox.html demos/gd.html demos/data demos/image diff --git a/demos/mapbox.html b/demos/mapbox.html new file mode 100644 index 0000000000..661b3c33c3 --- /dev/null +++ b/demos/mapbox.html @@ -0,0 +1,93 @@ + + + + + + + + + + point_circle + + + + +
+ + + + + + + + + From 9af7f61305029b41ad22ece1e0db6db2631c22a6 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Mon, 25 Feb 2019 23:56:37 +0800 Subject: [PATCH 11/16] refactor(source): source --- demos/01_point_circle.html | 9 ++- demos/01_point_column.html | 8 +- demos/01_point_distribute.html | 8 +- demos/02_point_circle.html | 77 ++++++++++++++++++ demos/04_image.html | 7 +- demos/05_raster_dem.html | 15 ++-- demos/grid.html | 74 +++++++++++++++++ package.json | 1 + src/core/engine/picking/picking.js | 3 +- src/core/layer.js | 35 ++++---- src/core/source.js | 52 ++++++++---- src/geom/buffer/heatmap/grid.js | 32 ++++++++ src/geom/buffer/image.js | 5 +- src/geom/buffer/line.js | 29 +++---- src/geom/buffer/point/fillBuffer.js | 8 +- src/geom/buffer/point/imageBuffer.js | 8 +- src/geom/buffer/point/normalBuffer.js | 8 +- src/geom/buffer/point/strokeBuffer.js | 8 +- src/geom/buffer/point/textBuffer.js | 8 +- src/geom/buffer/polygon.js | 17 ++-- src/geom/buffer/raster.js | 12 ++- src/geom/buffer/text.js | 11 ++- src/geom/material/grid.js | 31 ++++++++ src/geom/shader/grid_frag.glsl | 8 ++ src/geom/shader/grid_vert.glsl | 15 ++++ src/layer/heatmap.js | 28 +++++++ src/layer/imageLayer.js | 13 +-- src/layer/index.js | 7 +- src/layer/lineLayer.js | 5 +- src/layer/pointLayer.js | 17 ++-- src/layer/polygonLayer.js | 4 +- src/layer/rasterLayer.js | 16 ++-- src/layer/render/heatmap/gird.js | 21 +++++ src/source/csvSource.js | 69 ---------------- src/source/factory.js | 11 +++ src/source/geojsonSource.js | 47 ----------- src/source/imageSource.js | 37 --------- src/source/index.js | 28 +++++-- src/source/parser/csv.js | 23 ++++++ src/source/parser/geojson.js | 19 +++++ src/source/parser/image.js | 41 ++++++++++ src/source/parser/json.js | 21 +++++ src/source/parser/raster.js | 15 ++++ src/source/rainSource.js | 31 -------- src/source/rasterSource.js | 20 ----- src/source/transform/grid-aggregator.js | 101 ++++++++++++++++++++++++ src/source/transform/map.js | 7 ++ src/source/transform/statistics.js | 10 +++ 48 files changed, 717 insertions(+), 363 deletions(-) create mode 100644 demos/02_point_circle.html create mode 100644 demos/grid.html create mode 100644 src/geom/buffer/heatmap/grid.js create mode 100644 src/geom/material/grid.js create mode 100644 src/geom/shader/grid_frag.glsl create mode 100644 src/geom/shader/grid_vert.glsl create mode 100644 src/layer/heatmap.js create mode 100644 src/layer/render/heatmap/gird.js delete mode 100644 src/source/csvSource.js create mode 100644 src/source/factory.js delete mode 100644 src/source/geojsonSource.js delete mode 100644 src/source/imageSource.js create mode 100644 src/source/parser/csv.js create mode 100644 src/source/parser/geojson.js create mode 100644 src/source/parser/image.js create mode 100644 src/source/parser/json.js create mode 100644 src/source/parser/raster.js delete mode 100644 src/source/rainSource.js delete mode 100644 src/source/rasterSource.js create mode 100644 src/source/transform/grid-aggregator.js create mode 100644 src/source/transform/map.js create mode 100644 src/source/transform/statistics.js 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'; + From 8a454561ad1241f6b5bfea72d0c5967b2464c284 Mon Sep 17 00:00:00 2001 From: xiaoiver Date: Tue, 26 Feb 2019 15:09:49 +0800 Subject: [PATCH 12/16] feat(l7): add shader module --- src/core/scene.js | 2 + src/geom/material/polygonMaterial.js | 9 +++-- src/geom/shader/common.glsl | 2 + src/geom/shader/index.js | 22 +++++------ src/geom/shader/point_frag.glsl | 5 ++- src/geom/shader/project_vert.glsl | 0 src/util/shaderModule.js | 59 ++++++++++++++++++++++++++++ test/unit/shader-module/base-spec.js | 32 +++++++++++++++ 8 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 src/geom/shader/common.glsl create mode 100644 src/geom/shader/project_vert.glsl create mode 100644 src/util/shaderModule.js create mode 100644 test/unit/shader-module/base-spec.js diff --git a/src/core/scene.js b/src/core/scene.js index d9229a2512..121ede7bc8 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -6,6 +6,7 @@ import WorkerPool from './worker'; import { MapProvider } from '../map/provider'; import GaodeMap from '../map/gaodeMap'; import Global from '../global'; +import { compileBuiltinModules } from '../geom/shader'; export default class Scene extends Base { getDefaultCfg() { return Global.scene; @@ -22,6 +23,7 @@ export default class Scene extends Base { this._engine = new Engine(mapContainer, this); this._engine.run(); this.workerPool = new WorkerPool(); + compileBuiltinModules(); } // 为pickup场景添加 object 对象 addPickMesh(object) { diff --git a/src/geom/material/polygonMaterial.js b/src/geom/material/polygonMaterial.js index d47eb72065..da8a598122 100644 --- a/src/geom/material/polygonMaterial.js +++ b/src/geom/material/polygonMaterial.js @@ -1,6 +1,5 @@ -import polygon_frag from '../shader/polygon_frag.glsl'; -import polygon_vert from '../shader/polygon_vert.glsl'; import Material from './material'; +import { getModule } from '../../util/shaderModule'; // export default function PolygonMaterial(options) { // const material = new Material({ // uniforms: { @@ -48,8 +47,10 @@ export default class PolygonMaterial extends Material { this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms)); this.type = 'PolygonMaterial'; this.defines = Object.assign(defines, _defines); - this.vertexShader = polygon_vert; - this.fragmentShader = polygon_frag; + + const { vs, fs } = getModule('polygon'); + this.vertexShader = vs; + this.fragmentShader = fs; this.transparent = true; } } diff --git a/src/geom/shader/common.glsl b/src/geom/shader/common.glsl new file mode 100644 index 0000000000..09462af13e --- /dev/null +++ b/src/geom/shader/common.glsl @@ -0,0 +1,2 @@ +#define PI 3.14159265359 +#define TWO_PI 6.28318530718 \ No newline at end of file diff --git a/src/geom/shader/index.js b/src/geom/shader/index.js index 525a698d2d..fffbfda42a 100644 --- a/src/geom/shader/index.js +++ b/src/geom/shader/index.js @@ -1,14 +1,12 @@ import point_frag from '../shader/point_frag.glsl'; import point_vert from '../shader/point_vert.glsl'; -const shaderslib = { - pointShader: { - fragment: point_frag, - vertex: point_vert - } -}; -// for (const programName in shaderslib) { -// const program = shaderslib[programName]; -// program.fragment = ShaderFactory.parseIncludes(program.fragment); -// program.vertex = ShaderFactory.parseIncludes(program.vertex); -// } -export default shaderslib; +import polygon_frag from '../shader/polygon_frag.glsl'; +import polygon_vert from '../shader/polygon_vert.glsl'; +import common from './common.glsl'; +import { registerModule } from '../../util/shaderModule'; + +export function compileBuiltinModules() { + registerModule('point', { vs: point_vert, fs: point_frag }); + registerModule('common', { vs: common, fs: common }); + registerModule('polygon', { vs: polygon_vert, fs: polygon_frag }); +} diff --git a/src/geom/shader/point_frag.glsl b/src/geom/shader/point_frag.glsl index 238c972638..eecea0605c 100644 --- a/src/geom/shader/point_frag.glsl +++ b/src/geom/shader/point_frag.glsl @@ -1,7 +1,8 @@ precision highp float; -#define PI 3.14159265359 -#define TWO_PI 6.28318530718 + +#pragma import "common" + uniform float u_strokeWidth; uniform vec4 u_stroke; uniform float u_opacity; diff --git a/src/geom/shader/project_vert.glsl b/src/geom/shader/project_vert.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/util/shaderModule.js b/src/util/shaderModule.js new file mode 100644 index 0000000000..b0a354194f --- /dev/null +++ b/src/util/shaderModule.js @@ -0,0 +1,59 @@ +const SHADER_TYPE = { + VS: 'vs', + FS: 'fs' +}; +const moduleCache = {}; +const rawContentCache = {}; +const precisionRegExp = /precision\s+(high|low|medium)p\s+float/; +const globalDefaultprecision = '#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n #else\n precision mediump float;\n#endif\n'; +const includeRegExp = /#pragma include (["^+"]?["\ "[a-zA-Z_0-9](.*)"]*?)/g; + +function processModule(rawContent, includeList, type) { + return rawContent.replace(includeRegExp, (_, strMatch) => { + const includeOpt = strMatch.split(' '); + const includeName = includeOpt[0].replace(/"/g, ''); + + if (includeList.indexOf(includeName) > -1) { + return ''; + } + + let txt = rawContentCache[includeName][type]; + includeList.push(includeName); + + txt = processModule(txt, includeList, type); + return txt; + }); +} + +export function registerModule(moduleName, { vs, fs }) { + rawContentCache[moduleName] = { + [SHADER_TYPE.VS]: vs, + [SHADER_TYPE.FS]: fs + }; +} + +export function getModule(moduleName) { + if (moduleCache[moduleName]) { + return moduleCache[moduleName]; + } + + let vs = rawContentCache[moduleName][SHADER_TYPE.VS]; + let fs = rawContentCache[moduleName][SHADER_TYPE.FS]; + + vs = processModule(vs, [], SHADER_TYPE.VS); + fs = processModule(fs, [], SHADER_TYPE.FS); + + /** + * set default precision for fragment shader + * https://stackoverflow.com/questions/28540290/why-it-is-necessary-to-set-precision-for-the-fragment-shader + */ + if (!precisionRegExp.test(fs)) { + fs = globalDefaultprecision + fs; + } + + moduleCache[moduleName] = { + [SHADER_TYPE.VS]: vs.trim(), + [SHADER_TYPE.FS]: fs.trim() + }; + return moduleCache[moduleName]; +} diff --git a/test/unit/shader-module/base-spec.js b/test/unit/shader-module/base-spec.js new file mode 100644 index 0000000000..8f2b35c079 --- /dev/null +++ b/test/unit/shader-module/base-spec.js @@ -0,0 +1,32 @@ +import { expect } from 'chai'; +import { registerModule, getModule } from '../../../src/util/shaderModule'; + +describe('test shader module', function() { + + const vs = ` + #define PI 3.14 + `; + + const commonModule = { + vs, + fs: vs + }; + + const module1 = { + vs: ` + #pragma include "common" + `, + fs: '' + }; + + registerModule('common', commonModule); + registerModule('module1', module1); + + it('should import a module correctly.', function() { + const { vs, fs } = getModule('module1'); + + expect(vs).eq('#define PI 3.14'); + expect(fs).eq(''); + }); + +}); From 3ab8aac11a17ce93e74add1b066a8d50e93dd86f Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 26 Feb 2019 16:06:43 +0800 Subject: [PATCH 13/16] feat(source): hexagon --- package.json | 1 + src/geo/lngLat.js | 87 +- src/geo/project.js | 17 +- src/source/index.js | 2 +- .../transform/{grid-aggregator.js => grid.js} | 0 src/source/transform/hexagon.js | 41 + test/asset/data/point.js | 1490 +++++++++++++++++ test/unit/source/transfrom/hexagon.js | 21 + 8 files changed, 1641 insertions(+), 18 deletions(-) rename src/source/transform/{grid-aggregator.js => grid.js} (100%) create mode 100644 src/source/transform/hexagon.js create mode 100644 test/asset/data/point.js create mode 100644 test/unit/source/transfrom/hexagon.js diff --git a/package.json b/package.json index 3ee6803cde..a7004447ea 100755 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "@turf/invariant": "^6.1.2", "@turf/meta": "^6.0.2", "d3-dsv": "^1.0.10", + "d3-hexbin": "^0.2.2", "earcut": "^2.1.3", "fecha": "^2.3.3", "gl-matrix": "^2.4.1", diff --git a/src/geo/lngLat.js b/src/geo/lngLat.js index edc7b59576..b635918f0c 100644 --- a/src/geo/lngLat.js +++ b/src/geo/lngLat.js @@ -1,20 +1,75 @@ -export class LatLng { - constructor(lat, lng, alt) { - if (isNaN(lat) || isNaN(lng)) { - throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); - } - this.lat = +lat; - this.lng = +lng; - if (alt !== undefined) { - this.alt = +alt; - } +self._wkHandlers={};; - } - equal() { + function _prep_h17(){function a(b,c,d,e,g,k){var l=[0,0,0,0,0],n=d.slice(0,4).concat(l),p=[],s=Math.PI/180*6,A=void 0,I=void 0,A=d.slice(0,2),D=m(e),F=m(g),I=q.normalize(h(D).fg(h(A))),C=q.normalize(h(F).fg(h(A)));q.OK(I,k)?(A=q.oD(I),I=q.oD(C)):(A=q.oD(C),I=q.oD(I),k=[F,D],D=k[0],F=k[1],g=[g,e],e=g[0],g=g[1]);D=Math.ceil(Math.abs(I-A)/s);30<=D&&(D=60-D);for(k=0;kMath.sqrt(3)/2&&(d=Math.sqrt(3)/2);c=c.oJ(d)}return c}function g(a,c,e){if(void 0===e||!0===e)b.push(a[0],a[1]),b.push(-c.y,c.x,0,0),b.push(m,0,0),d.push(a[2]);if(void 0===e||!1===e)b.push(a[0],a[1]),b.push(c.y,-c.x,0,0),b.push(m,0,0),d.push(a[2])}for(var k=a[0],l=a[a.length-1],m=0,n=void 0;k[0]===l[0]&&k[1]===l[1]&&k!==l;)a.pop(),l=a[a.length-1];a.push(k);a.push(a[1]);a.unshift(l);var p=a.length;a.forEach(function(a,d, k){var l=k[d-1];k=k[d+1];var r=void 0;l&&(m+=q.Fd(a,l));if(0===d||d===p-1)0===d?(r=q.normalize(h(k[0]-a[0],k[1]-a[1])),c.push(0,1,2)):(r=q.normalize(h(a[0]-l[0],a[1]-l[1])),d=b.length/9+2,c.push(d-3,d-1,d-2)),g(a,r);else{d=q.normalize(h(a[0]-l[0],a[1]-l[1]));k=q.normalize(h(k[0]-a[0],k[1]-a[1]));l=q.normalize(d.multiply(-1).mi(k));n=q.OK(l,d);g(a,e(d,k),!0);g(a,e(d,k),!1);g(a,e(d,k),!0);g(a,e(d,k),!1);a=b.length/9-4;k=a+2;var r=9*a,s=r+9,x=s+9,B=x+9;d=Math.abs(q.cos(d,l)/q.sin(d,l));n?(b[r+7]=d,b[s+ 7]=-d,b[x+7]=-d,b[B+7]=d):(b[r+7]=-d,b[s+7]=d,b[x+7]=d,b[B+7]=-d);c.push(a,a-1,a+1);c.push(k,k+1,k+2)}})}function e(c,d,e){function g(a,b){if(p)for(;0=a&&(a+=2*Math.PI);return a}},s={mi:function(a){return h(this.x+a.x,this.y+a.y)},fg:function(a){return h(this.x-a.x,this.y-a.y)},multiply:function(a){return"number"===typeof a?h(this.x*a,this.y*a):this.x*a.x+this.y*a.y},oJ:function(a){return h(this.x/a,this.y/a)},NC:function(a){var b=a.y;return this.x===a.x&&this.y===b}};return{parse:function(a,b){var h=a.lineJoin,h=void 0===h?"bevel":h,k= a.lineCap,k=void 0===k?"butt":k,l=a.Zda,l=void 0===l?!1:l,m=a.tn,n=void 0===m?!1:m,p=a.LX,m=a.Iia,q=void 0===m?!0:m,m=a.Sda,s=[],A=[],I=g(a.Nr,void 0===p?!0:p),p=[];l?(d(I,s,A,p),h=s.length,[0,1,2,h/9-1,h/9-2].forEach(function(a){s[9*a+8]=-1})):(c(I,s,A,h,n,p),e(I,s,A,k,p));q&&(s=new Float32Array(s),A=65535=h||b.jn;if(d||b){d=1 { + const { x, y } = aProjectFlat(point.coordinates); + return { + ...point, + coordinates: [ x, y ] + }; + }); + + const newHexbin = hexbin() + .radius(pixlSize) + .x(d => d.coordinates[0]) + .y(d => d.coordinates[1]); + const hexbinBins = newHexbin(screenPoints); + const result = { + size: pixlSize + }; + result.dataArray = hexbinBins.map((hex, index) => { + if (option.field && option.method) { + const columns = getColumn(hex, option.field); + hex[option.method] = statistics[option.method](columns); + } + return { + coordinates: unProjectFlat([ hex.x, hex.y ]), + id: index + 1 + }; + }); + return result; +} +function getColumn(data, columnName) { + return data.map(item => { + return item[columnName]; + }); +} diff --git a/test/asset/data/point.js b/test/asset/data/point.js new file mode 100644 index 0000000000..6fc7183712 --- /dev/null +++ b/test/asset/data/point.js @@ -0,0 +1,1490 @@ +export const pointData = [ + { grid_y: 121055, count: 7600, grid_x: 480481 }, + { grid_y: 121055, count: 3800, grid_x: 480487 }, + { grid_y: 121055, count: 3800, grid_x: 480493 }, + { grid_y: 121055, count: 7600, grid_x: 480501 }, + { grid_y: 121055, count: 3800, grid_x: 480502 }, + { grid_y: 121055, count: 15200, grid_x: 480503 }, + { grid_y: 121055, count: 3800, grid_x: 480504 }, + { grid_y: 121055, count: 7600, grid_x: 480505 }, + { grid_y: 121055, count: 3800, grid_x: 480506 }, + { grid_y: 121055, count: 3800, grid_x: 480507 }, + { grid_y: 121055, count: 3800, grid_x: 480512 }, + { grid_y: 121055, count: 3800, grid_x: 480530 }, + { grid_y: 121056, count: 3800, grid_x: 480494 }, + { grid_y: 121056, count: 3800, grid_x: 480496 }, + { grid_y: 121056, count: 7600, grid_x: 480501 }, + { grid_y: 121056, count: 11400, grid_x: 480502 }, + { grid_y: 121056, count: 7600, grid_x: 480503 }, + { grid_y: 121056, count: 7600, grid_x: 480504 }, + { grid_y: 121056, count: 3800, grid_x: 480506 }, + { grid_y: 121056, count: 3800, grid_x: 480508 }, + { grid_y: 121056, count: 3800, grid_x: 480509 }, + { grid_y: 121056, count: 3800, grid_x: 480520 }, + { grid_y: 121056, count: 3800, grid_x: 480524 }, + { grid_y: 121057, count: 11400, grid_x: 480484 }, + { grid_y: 121057, count: 3800, grid_x: 480489 }, + { grid_y: 121057, count: 3800, grid_x: 480500 }, + { grid_y: 121057, count: 3800, grid_x: 480502 }, + { grid_y: 121057, count: 3800, grid_x: 480509 }, + { grid_y: 121057, count: 3800, grid_x: 480515 }, + { grid_y: 121057, count: 3800, grid_x: 480522 }, + { grid_y: 121057, count: 3800, grid_x: 480523 }, + { grid_y: 121057, count: 15200, grid_x: 480524 }, + { grid_y: 121057, count: 3800, grid_x: 480525 }, + { grid_y: 121057, count: 3800, grid_x: 480527 }, + { grid_y: 121058, count: 3800, grid_x: 480478 }, + { grid_y: 121058, count: 3800, grid_x: 480482 }, + { grid_y: 121058, count: 3800, grid_x: 480485 }, + { grid_y: 121058, count: 3800, grid_x: 480486 }, + { grid_y: 121058, count: 3800, grid_x: 480487 }, + { grid_y: 121058, count: 3800, grid_x: 480490 }, + { grid_y: 121058, count: 3800, grid_x: 480497 }, + { grid_y: 121058, count: 3800, grid_x: 480499 }, + { grid_y: 121058, count: 7600, grid_x: 480501 }, + { grid_y: 121058, count: 3800, grid_x: 480502 }, + { grid_y: 121058, count: 7600, grid_x: 480503 }, + { grid_y: 121058, count: 3800, grid_x: 480521 }, + { grid_y: 121058, count: 3800, grid_x: 480522 }, + { grid_y: 121058, count: 3800, grid_x: 480523 }, + { grid_y: 121058, count: 3800, grid_x: 480524 }, + { grid_y: 121058, count: 3800, grid_x: 480528 }, + { grid_y: 121059, count: 3800, grid_x: 480495 }, + { grid_y: 121059, count: 3800, grid_x: 480499 }, + { grid_y: 121059, count: 3800, grid_x: 480500 }, + { grid_y: 121059, count: 7600, grid_x: 480502 }, + { grid_y: 121059, count: 7600, grid_x: 480503 }, + { grid_y: 121059, count: 3800, grid_x: 480504 }, + { grid_y: 121059, count: 34200, grid_x: 480507 }, + { grid_y: 121059, count: 3800, grid_x: 480511 }, + { grid_y: 121059, count: 3800, grid_x: 480516 }, + { grid_y: 121060, count: 7600, grid_x: 480491 }, + { grid_y: 121060, count: 7600, grid_x: 480496 }, + { grid_y: 121060, count: 3800, grid_x: 480497 }, + { grid_y: 121060, count: 3800, grid_x: 480498 }, + { grid_y: 121060, count: 7600, grid_x: 480499 }, + { grid_y: 121060, count: 7600, grid_x: 480500 }, + { grid_y: 121060, count: 7600, grid_x: 480502 }, + { grid_y: 121060, count: 3800, grid_x: 480505 }, + { grid_y: 121060, count: 3800, grid_x: 480506 }, + { grid_y: 121060, count: 3800, grid_x: 480511 }, + { grid_y: 121060, count: 3800, grid_x: 480513 }, + { grid_y: 121060, count: 3800, grid_x: 480514 }, + { grid_y: 121061, count: 3800, grid_x: 480491 }, + { grid_y: 121061, count: 7600, grid_x: 480497 }, + { grid_y: 121061, count: 7600, grid_x: 480499 }, + { grid_y: 121061, count: 11400, grid_x: 480500 }, + { grid_y: 121061, count: 3800, grid_x: 480501 }, + { grid_y: 121061, count: 7600, grid_x: 480502 }, + { grid_y: 121061, count: 15200, grid_x: 480503 }, + { grid_y: 121061, count: 11400, grid_x: 480504 }, + { grid_y: 121061, count: 7600, grid_x: 480505 }, + { grid_y: 121061, count: 3800, grid_x: 480506 }, + { grid_y: 121061, count: 3800, grid_x: 480507 }, + { grid_y: 121061, count: 3800, grid_x: 480511 }, + { grid_y: 121061, count: 3800, grid_x: 480526 }, + { grid_y: 121062, count: 15200, grid_x: 480489 }, + { grid_y: 121062, count: 7600, grid_x: 480491 }, + { grid_y: 121062, count: 7600, grid_x: 480492 }, + { grid_y: 121062, count: 7600, grid_x: 480499 }, + { grid_y: 121062, count: 11400, grid_x: 480500 }, + { grid_y: 121062, count: 3800, grid_x: 480502 }, + { grid_y: 121062, count: 3800, grid_x: 480503 }, + { grid_y: 121062, count: 7600, grid_x: 480504 }, + { grid_y: 121062, count: 3800, grid_x: 480505 }, + { grid_y: 121062, count: 3800, grid_x: 480517 }, + { grid_y: 121062, count: 7600, grid_x: 480522 }, + { grid_y: 121062, count: 3800, grid_x: 480527 }, + { grid_y: 121062, count: 3800, grid_x: 480530 }, + { grid_y: 121063, count: 3800, grid_x: 480488 }, + { grid_y: 121063, count: 7600, grid_x: 480489 }, + { grid_y: 121063, count: 15200, grid_x: 480492 }, + { grid_y: 121063, count: 3800, grid_x: 480493 }, + { grid_y: 121063, count: 3800, grid_x: 480497 }, + { grid_y: 121063, count: 7600, grid_x: 480499 }, + { grid_y: 121063, count: 7600, grid_x: 480500 }, + { grid_y: 121063, count: 15200, grid_x: 480501 }, + { grid_y: 121063, count: 11400, grid_x: 480502 }, + { grid_y: 121063, count: 3800, grid_x: 480516 }, + { grid_y: 121063, count: 3800, grid_x: 480518 }, + { grid_y: 121063, count: 3800, grid_x: 480522 }, + { grid_y: 121063, count: 11400, grid_x: 480524 }, + { grid_y: 121063, count: 3800, grid_x: 480525 }, + { grid_y: 121064, count: 7600, grid_x: 480488 }, + { grid_y: 121064, count: 3800, grid_x: 480489 }, + { grid_y: 121064, count: 7600, grid_x: 480490 }, + { grid_y: 121064, count: 3800, grid_x: 480491 }, + { grid_y: 121064, count: 3800, grid_x: 480493 }, + { grid_y: 121064, count: 3800, grid_x: 480495 }, + { grid_y: 121064, count: 3800, grid_x: 480496 }, + { grid_y: 121064, count: 15200, grid_x: 480499 }, + { grid_y: 121064, count: 3800, grid_x: 480500 }, + { grid_y: 121064, count: 15200, grid_x: 480501 }, + { grid_y: 121064, count: 7600, grid_x: 480502 }, + { grid_y: 121064, count: 3800, grid_x: 480523 }, + { grid_y: 121065, count: 3800, grid_x: 480487 }, + { grid_y: 121065, count: 3800, grid_x: 480488 }, + { grid_y: 121065, count: 3800, grid_x: 480489 }, + { grid_y: 121065, count: 11400, grid_x: 480490 }, + { grid_y: 121065, count: 7600, grid_x: 480491 }, + { grid_y: 121065, count: 3800, grid_x: 480492 }, + { grid_y: 121065, count: 7600, grid_x: 480499 }, + { grid_y: 121065, count: 3800, grid_x: 480500 }, + { grid_y: 121065, count: 7600, grid_x: 480501 }, + { grid_y: 121065, count: 3800, grid_x: 480509 }, + { grid_y: 121065, count: 3800, grid_x: 480512 }, + { grid_y: 121065, count: 3800, grid_x: 480516 }, + { grid_y: 121065, count: 3800, grid_x: 480527 }, + { grid_y: 121066, count: 3800, grid_x: 480488 }, + { grid_y: 121066, count: 7600, grid_x: 480489 }, + { grid_y: 121066, count: 3800, grid_x: 480490 }, + { grid_y: 121066, count: 11400, grid_x: 480491 }, + { grid_y: 121066, count: 7600, grid_x: 480492 }, + { grid_y: 121066, count: 3800, grid_x: 480496 }, + { grid_y: 121066, count: 7600, grid_x: 480498 }, + { grid_y: 121066, count: 3800, grid_x: 480500 }, + { grid_y: 121066, count: 7600, grid_x: 480501 }, + { grid_y: 121066, count: 3800, grid_x: 480505 }, + { grid_y: 121066, count: 3800, grid_x: 480509 }, + { grid_y: 121066, count: 3800, grid_x: 480511 }, + { grid_y: 121066, count: 3800, grid_x: 480512 }, + { grid_y: 121066, count: 3800, grid_x: 480514 }, + { grid_y: 121067, count: 15200, grid_x: 480491 }, + { grid_y: 121067, count: 3800, grid_x: 480493 }, + { grid_y: 121067, count: 3800, grid_x: 480494 }, + { grid_y: 121067, count: 7600, grid_x: 480495 }, + { grid_y: 121067, count: 7600, grid_x: 480496 }, + { grid_y: 121067, count: 7600, grid_x: 480497 }, + { grid_y: 121067, count: 7600, grid_x: 480498 }, + { grid_y: 121067, count: 3800, grid_x: 480499 }, + { grid_y: 121067, count: 11400, grid_x: 480500 }, + { grid_y: 121067, count: 3800, grid_x: 480501 }, + { grid_y: 121067, count: 3800, grid_x: 480503 }, + { grid_y: 121067, count: 3800, grid_x: 480509 }, + { grid_y: 121067, count: 3800, grid_x: 480513 }, + { grid_y: 121067, count: 3800, grid_x: 480515 }, + { grid_y: 121068, count: 7600, grid_x: 480488 }, + { grid_y: 121068, count: 7600, grid_x: 480489 }, + { grid_y: 121068, count: 11400, grid_x: 480490 }, + { grid_y: 121068, count: 3800, grid_x: 480491 }, + { grid_y: 121068, count: 7600, grid_x: 480493 }, + { grid_y: 121068, count: 3800, grid_x: 480494 }, + { grid_y: 121068, count: 3800, grid_x: 480495 }, + { grid_y: 121068, count: 41800, grid_x: 480499 }, + { grid_y: 121068, count: 19000, grid_x: 480500 }, + { grid_y: 121068, count: 3800, grid_x: 480501 }, + { grid_y: 121068, count: 3800, grid_x: 480502 }, + { grid_y: 121068, count: 3800, grid_x: 480504 }, + { grid_y: 121068, count: 3800, grid_x: 480509 }, + { grid_y: 121068, count: 3800, grid_x: 480515 }, + { grid_y: 121069, count: 3800, grid_x: 480489 }, + { grid_y: 121069, count: 3800, grid_x: 480491 }, + { grid_y: 121069, count: 7600, grid_x: 480492 }, + { grid_y: 121069, count: 7600, grid_x: 480493 }, + { grid_y: 121069, count: 3800, grid_x: 480494 }, + { grid_y: 121069, count: 3800, grid_x: 480495 }, + { grid_y: 121069, count: 7600, grid_x: 480499 }, + { grid_y: 121069, count: 3800, grid_x: 480502 }, + { grid_y: 121069, count: 3800, grid_x: 480509 }, + { grid_y: 121069, count: 3800, grid_x: 480513 }, + { grid_y: 121069, count: 3800, grid_x: 480515 }, + { grid_y: 121069, count: 3800, grid_x: 480517 }, + { grid_y: 121069, count: 7600, grid_x: 480524 }, + { grid_y: 121070, count: 3800, grid_x: 480490 }, + { grid_y: 121070, count: 11400, grid_x: 480491 }, + { grid_y: 121070, count: 3800, grid_x: 480492 }, + { grid_y: 121070, count: 3800, grid_x: 480497 }, + { grid_y: 121070, count: 3800, grid_x: 480501 }, + { grid_y: 121070, count: 7600, grid_x: 480510 }, + { grid_y: 121070, count: 19000, grid_x: 480513 }, + { grid_y: 121070, count: 3800, grid_x: 480514 }, + { grid_y: 121070, count: 3800, grid_x: 480515 }, + { grid_y: 121070, count: 11400, grid_x: 480516 }, + { grid_y: 121070, count: 7600, grid_x: 480517 }, + { grid_y: 121070, count: 3800, grid_x: 480518 }, + { grid_y: 121070, count: 3800, grid_x: 480519 }, + { grid_y: 121070, count: 7600, grid_x: 480533 }, + { grid_y: 121071, count: 11400, grid_x: 480491 }, + { grid_y: 121071, count: 7600, grid_x: 480492 }, + { grid_y: 121071, count: 15200, grid_x: 480493 }, + { grid_y: 121071, count: 7600, grid_x: 480494 }, + { grid_y: 121071, count: 3800, grid_x: 480495 }, + { grid_y: 121071, count: 3800, grid_x: 480497 }, + { grid_y: 121071, count: 3800, grid_x: 480502 }, + { grid_y: 121071, count: 3800, grid_x: 480503 }, + { grid_y: 121071, count: 3800, grid_x: 480510 }, + { grid_y: 121071, count: 11400, grid_x: 480513 }, + { grid_y: 121071, count: 7600, grid_x: 480515 }, + { grid_y: 121071, count: 7600, grid_x: 480516 }, + { grid_y: 121071, count: 7600, grid_x: 480517 }, + { grid_y: 121071, count: 3800, grid_x: 480519 }, + { grid_y: 121071, count: 3800, grid_x: 480520 }, + { grid_y: 121071, count: 3800, grid_x: 480523 }, + { grid_y: 121072, count: 15200, grid_x: 480492 }, + { grid_y: 121072, count: 11400, grid_x: 480493 }, + { grid_y: 121072, count: 3800, grid_x: 480494 }, + { grid_y: 121072, count: 3800, grid_x: 480496 }, + { grid_y: 121072, count: 3800, grid_x: 480500 }, + { grid_y: 121072, count: 7600, grid_x: 480501 }, + { grid_y: 121072, count: 3800, grid_x: 480508 }, + { grid_y: 121072, count: 7600, grid_x: 480514 }, + { grid_y: 121072, count: 3800, grid_x: 480515 }, + { grid_y: 121072, count: 3800, grid_x: 480517 }, + { grid_y: 121072, count: 3800, grid_x: 480518 }, + { grid_y: 121073, count: 7600, grid_x: 480491 }, + { grid_y: 121073, count: 7600, grid_x: 480492 }, + { grid_y: 121073, count: 3800, grid_x: 480494 }, + { grid_y: 121073, count: 3800, grid_x: 480497 }, + { grid_y: 121073, count: 11400, grid_x: 480501 }, + { grid_y: 121073, count: 7600, grid_x: 480502 }, + { grid_y: 121073, count: 3800, grid_x: 480503 }, + { grid_y: 121073, count: 3800, grid_x: 480504 }, + { grid_y: 121073, count: 3800, grid_x: 480511 }, + { grid_y: 121073, count: 3800, grid_x: 480512 }, + { grid_y: 121073, count: 3800, grid_x: 480516 }, + { grid_y: 121073, count: 3800, grid_x: 480517 }, + { grid_y: 121074, count: 3800, grid_x: 480459 }, + { grid_y: 121074, count: 3800, grid_x: 480491 }, + { grid_y: 121074, count: 3800, grid_x: 480492 }, + { grid_y: 121074, count: 3800, grid_x: 480493 }, + { grid_y: 121074, count: 3800, grid_x: 480494 }, + { grid_y: 121074, count: 7600, grid_x: 480497 }, + { grid_y: 121074, count: 3800, grid_x: 480498 }, + { grid_y: 121074, count: 3800, grid_x: 480499 }, + { grid_y: 121074, count: 7600, grid_x: 480501 }, + { grid_y: 121074, count: 15200, grid_x: 480502 }, + { grid_y: 121074, count: 3800, grid_x: 480503 }, + { grid_y: 121074, count: 3800, grid_x: 480507 }, + { grid_y: 121074, count: 7600, grid_x: 480517 }, + { grid_y: 121074, count: 3800, grid_x: 480520 }, + { grid_y: 121075, count: 3800, grid_x: 480493 }, + { grid_y: 121075, count: 3800, grid_x: 480495 }, + { grid_y: 121075, count: 3800, grid_x: 480496 }, + { grid_y: 121075, count: 3800, grid_x: 480497 }, + { grid_y: 121075, count: 7600, grid_x: 480498 }, + { grid_y: 121075, count: 7600, grid_x: 480499 }, + { grid_y: 121075, count: 7600, grid_x: 480500 }, + { grid_y: 121075, count: 7600, grid_x: 480501 }, + { grid_y: 121075, count: 7600, grid_x: 480502 }, + { grid_y: 121075, count: 7600, grid_x: 480503 }, + { grid_y: 121075, count: 3800, grid_x: 480504 }, + { grid_y: 121075, count: 7600, grid_x: 480506 }, + { grid_y: 121075, count: 3800, grid_x: 480511 }, + { grid_y: 121075, count: 3800, grid_x: 480517 }, + { grid_y: 121075, count: 3800, grid_x: 480518 }, + { grid_y: 121075, count: 3800, grid_x: 480519 }, + { grid_y: 121075, count: 7600, grid_x: 480520 }, + { grid_y: 121076, count: 3800, grid_x: 480491 }, + { grid_y: 121076, count: 7600, grid_x: 480498 }, + { grid_y: 121076, count: 7600, grid_x: 480499 }, + { grid_y: 121076, count: 3800, grid_x: 480501 }, + { grid_y: 121076, count: 3800, grid_x: 480502 }, + { grid_y: 121076, count: 15200, grid_x: 480503 }, + { grid_y: 121076, count: 3800, grid_x: 480509 }, + { grid_y: 121076, count: 3800, grid_x: 480515 }, + { grid_y: 121076, count: 3800, grid_x: 480516 }, + { grid_y: 121076, count: 3800, grid_x: 480521 }, + { grid_y: 121076, count: 3800, grid_x: 480523 }, + { grid_y: 121077, count: 3800, grid_x: 480475 }, + { grid_y: 121077, count: 3800, grid_x: 480496 }, + { grid_y: 121077, count: 7600, grid_x: 480498 }, + { grid_y: 121077, count: 7600, grid_x: 480499 }, + { grid_y: 121077, count: 7600, grid_x: 480500 }, + { grid_y: 121077, count: 3800, grid_x: 480501 }, + { grid_y: 121077, count: 3800, grid_x: 480503 }, + { grid_y: 121077, count: 7600, grid_x: 480506 }, + { grid_y: 121077, count: 3800, grid_x: 480509 }, + { grid_y: 121077, count: 3800, grid_x: 480511 }, + { grid_y: 121077, count: 3800, grid_x: 480517 }, + { grid_y: 121077, count: 3800, grid_x: 480518 }, + { grid_y: 121077, count: 3800, grid_x: 480531 }, + { grid_y: 121078, count: 3800, grid_x: 480462 }, + { grid_y: 121078, count: 3800, grid_x: 480474 }, + { grid_y: 121078, count: 3800, grid_x: 480479 }, + { grid_y: 121078, count: 3800, grid_x: 480485 }, + { grid_y: 121078, count: 3800, grid_x: 480496 }, + { grid_y: 121078, count: 7600, grid_x: 480497 }, + { grid_y: 121078, count: 3800, grid_x: 480499 }, + { grid_y: 121078, count: 7600, grid_x: 480501 }, + { grid_y: 121078, count: 3800, grid_x: 480502 }, + { grid_y: 121078, count: 3800, grid_x: 480507 }, + { grid_y: 121078, count: 7600, grid_x: 480509 }, + { grid_y: 121078, count: 15200, grid_x: 480510 }, + { grid_y: 121078, count: 3800, grid_x: 480512 }, + { grid_y: 121078, count: 3800, grid_x: 480529 }, + { grid_y: 121078, count: 3800, grid_x: 480530 }, + { grid_y: 121079, count: 3800, grid_x: 480462 }, + { grid_y: 121079, count: 3800, grid_x: 480478 }, + { grid_y: 121079, count: 3800, grid_x: 480497 }, + { grid_y: 121079, count: 3800, grid_x: 480499 }, + { grid_y: 121079, count: 3800, grid_x: 480504 }, + { grid_y: 121079, count: 3800, grid_x: 480511 }, + { grid_y: 121079, count: 3800, grid_x: 480532 }, + { grid_y: 121080, count: 3800, grid_x: 480479 }, + { grid_y: 121080, count: 3800, grid_x: 480491 }, + { grid_y: 121080, count: 3800, grid_x: 480492 }, + { grid_y: 121080, count: 3800, grid_x: 480493 }, + { grid_y: 121080, count: 7600, grid_x: 480494 }, + { grid_y: 121080, count: 3800, grid_x: 480495 }, + { grid_y: 121080, count: 3800, grid_x: 480499 }, + { grid_y: 121080, count: 3800, grid_x: 480500 }, + { grid_y: 121080, count: 3800, grid_x: 480510 }, + { grid_y: 121080, count: 3800, grid_x: 480520 }, + { grid_y: 121081, count: 11400, grid_x: 480462 }, + { grid_y: 121081, count: 3800, grid_x: 480492 }, + { grid_y: 121081, count: 3800, grid_x: 480493 }, + { grid_y: 121081, count: 3800, grid_x: 480494 }, + { grid_y: 121081, count: 11400, grid_x: 480495 }, + { grid_y: 121081, count: 3800, grid_x: 480518 }, + { grid_y: 121081, count: 3800, grid_x: 480522 }, + { grid_y: 121081, count: 3800, grid_x: 480523 }, + { grid_y: 121082, count: 3800, grid_x: 480490 }, + { grid_y: 121082, count: 3800, grid_x: 480494 }, + { grid_y: 121082, count: 3800, grid_x: 480507 }, + { grid_y: 121082, count: 3800, grid_x: 480510 }, + { grid_y: 121082, count: 3800, grid_x: 480519 }, + { grid_y: 121082, count: 3800, grid_x: 480520 }, + { grid_y: 121082, count: 3800, grid_x: 480521 }, + { grid_y: 121083, count: 3800, grid_x: 480511 }, + { grid_y: 121083, count: 7600, grid_x: 480513 }, + { grid_y: 121083, count: 3800, grid_x: 480514 }, + { grid_y: 121083, count: 3800, grid_x: 480515 }, + { grid_y: 121083, count: 3800, grid_x: 480516 }, + { grid_y: 121083, count: 3800, grid_x: 480520 }, + { grid_y: 121083, count: 3800, grid_x: 480522 }, + { grid_y: 121083, count: 3800, grid_x: 480523 }, + { grid_y: 121083, count: 7600, grid_x: 480524 }, + { grid_y: 121083, count: 3800, grid_x: 480525 }, + { grid_y: 121084, count: 3800, grid_x: 480485 }, + { grid_y: 121084, count: 3800, grid_x: 480486 }, + { grid_y: 121084, count: 3800, grid_x: 480487 }, + { grid_y: 121084, count: 3800, grid_x: 480494 }, + { grid_y: 121084, count: 3800, grid_x: 480495 }, + { grid_y: 121084, count: 3800, grid_x: 480497 }, + { grid_y: 121084, count: 3800, grid_x: 480500 }, + { grid_y: 121084, count: 3800, grid_x: 480512 }, + { grid_y: 121084, count: 22800, grid_x: 480513 }, + { grid_y: 121084, count: 7600, grid_x: 480514 }, + { grid_y: 121084, count: 3800, grid_x: 480515 }, + { grid_y: 121084, count: 3800, grid_x: 480520 }, + { grid_y: 121084, count: 3800, grid_x: 480521 }, + { grid_y: 121084, count: 3800, grid_x: 480522 }, + { grid_y: 121084, count: 3800, grid_x: 480523 }, + { grid_y: 121084, count: 3800, grid_x: 480531 }, + { grid_y: 121085, count: 3800, grid_x: 480499 }, + { grid_y: 121085, count: 7600, grid_x: 480500 }, + { grid_y: 121085, count: 3800, grid_x: 480501 }, + { grid_y: 121085, count: 3800, grid_x: 480504 }, + { grid_y: 121085, count: 3800, grid_x: 480506 }, + { grid_y: 121085, count: 7600, grid_x: 480513 }, + { grid_y: 121085, count: 11400, grid_x: 480514 }, + { grid_y: 121085, count: 3800, grid_x: 480515 }, + { grid_y: 121085, count: 3800, grid_x: 480517 }, + { grid_y: 121085, count: 3800, grid_x: 480518 }, + { grid_y: 121085, count: 3800, grid_x: 480520 }, + { grid_y: 121085, count: 3800, grid_x: 480527 }, + { grid_y: 121085, count: 3800, grid_x: 480532 }, + { grid_y: 121086, count: 3800, grid_x: 480483 }, + { grid_y: 121086, count: 3800, grid_x: 480490 }, + { grid_y: 121086, count: 7600, grid_x: 480494 }, + { grid_y: 121086, count: 3800, grid_x: 480497 }, + { grid_y: 121086, count: 7600, grid_x: 480498 }, + { grid_y: 121086, count: 3800, grid_x: 480499 }, + { grid_y: 121086, count: 7600, grid_x: 480500 }, + { grid_y: 121086, count: 3800, grid_x: 480507 }, + { grid_y: 121086, count: 3800, grid_x: 480511 }, + { grid_y: 121086, count: 7600, grid_x: 480512 }, + { grid_y: 121086, count: 7600, grid_x: 480516 }, + { grid_y: 121086, count: 3800, grid_x: 480517 }, + { grid_y: 121086, count: 7600, grid_x: 480518 }, + { grid_y: 121086, count: 3800, grid_x: 480520 }, + { grid_y: 121086, count: 11400, grid_x: 480521 }, + { grid_y: 121086, count: 3800, grid_x: 480523 }, + { grid_y: 121086, count: 3800, grid_x: 480524 }, + { grid_y: 121086, count: 3800, grid_x: 480527 }, + { grid_y: 121086, count: 7600, grid_x: 480528 }, + { grid_y: 121086, count: 3800, grid_x: 480529 }, + { grid_y: 121086, count: 3800, grid_x: 480531 }, + { grid_y: 121087, count: 7600, grid_x: 480460 }, + { grid_y: 121087, count: 3800, grid_x: 480463 }, + { grid_y: 121087, count: 3800, grid_x: 480472 }, + { grid_y: 121087, count: 3800, grid_x: 480489 }, + { grid_y: 121087, count: 3800, grid_x: 480494 }, + { grid_y: 121087, count: 3800, grid_x: 480495 }, + { grid_y: 121087, count: 7600, grid_x: 480501 }, + { grid_y: 121087, count: 15200, grid_x: 480502 }, + { grid_y: 121087, count: 11400, grid_x: 480503 }, + { grid_y: 121087, count: 7600, grid_x: 480504 }, + { grid_y: 121087, count: 7600, grid_x: 480508 }, + { grid_y: 121087, count: 3800, grid_x: 480518 }, + { grid_y: 121087, count: 3800, grid_x: 480519 }, + { grid_y: 121087, count: 3800, grid_x: 480527 }, + { grid_y: 121087, count: 3800, grid_x: 480528 }, + { grid_y: 121087, count: 3800, grid_x: 480529 }, + { grid_y: 121087, count: 7600, grid_x: 480533 }, + { grid_y: 121088, count: 3800, grid_x: 480460 }, + { grid_y: 121088, count: 3800, grid_x: 480478 }, + { grid_y: 121088, count: 7600, grid_x: 480479 }, + { grid_y: 121088, count: 3800, grid_x: 480483 }, + { grid_y: 121088, count: 3800, grid_x: 480487 }, + { grid_y: 121088, count: 7600, grid_x: 480491 }, + { grid_y: 121088, count: 3800, grid_x: 480493 }, + { grid_y: 121088, count: 3800, grid_x: 480494 }, + { grid_y: 121088, count: 7600, grid_x: 480496 }, + { grid_y: 121088, count: 3800, grid_x: 480497 }, + { grid_y: 121088, count: 3800, grid_x: 480498 }, + { grid_y: 121088, count: 3800, grid_x: 480502 }, + { grid_y: 121088, count: 7600, grid_x: 480503 }, + { grid_y: 121088, count: 3800, grid_x: 480504 }, + { grid_y: 121088, count: 3800, grid_x: 480505 }, + { grid_y: 121088, count: 7600, grid_x: 480506 }, + { grid_y: 121088, count: 3800, grid_x: 480507 }, + { grid_y: 121088, count: 7600, grid_x: 480508 }, + { grid_y: 121088, count: 7600, grid_x: 480510 }, + { grid_y: 121088, count: 3800, grid_x: 480511 }, + { grid_y: 121088, count: 7600, grid_x: 480512 }, + { grid_y: 121088, count: 7600, grid_x: 480520 }, + { grid_y: 121088, count: 3800, grid_x: 480529 }, + { grid_y: 121089, count: 3800, grid_x: 480462 }, + { grid_y: 121089, count: 3800, grid_x: 480470 }, + { grid_y: 121089, count: 3800, grid_x: 480472 }, + { grid_y: 121089, count: 3800, grid_x: 480474 }, + { grid_y: 121089, count: 3800, grid_x: 480475 }, + { grid_y: 121089, count: 3800, grid_x: 480476 }, + { grid_y: 121089, count: 7600, grid_x: 480477 }, + { grid_y: 121089, count: 3800, grid_x: 480480 }, + { grid_y: 121089, count: 3800, grid_x: 480481 }, + { grid_y: 121089, count: 7600, grid_x: 480482 }, + { grid_y: 121089, count: 3800, grid_x: 480486 }, + { grid_y: 121089, count: 3800, grid_x: 480489 }, + { grid_y: 121089, count: 3800, grid_x: 480491 }, + { grid_y: 121089, count: 7600, grid_x: 480493 }, + { grid_y: 121089, count: 11400, grid_x: 480498 }, + { grid_y: 121089, count: 3800, grid_x: 480501 }, + { grid_y: 121089, count: 7600, grid_x: 480502 }, + { grid_y: 121089, count: 3800, grid_x: 480503 }, + { grid_y: 121089, count: 3800, grid_x: 480504 }, + { grid_y: 121089, count: 3800, grid_x: 480505 }, + { grid_y: 121089, count: 7600, grid_x: 480506 }, + { grid_y: 121089, count: 3800, grid_x: 480508 }, + { grid_y: 121089, count: 7600, grid_x: 480512 }, + { grid_y: 121089, count: 3800, grid_x: 480514 }, + { grid_y: 121089, count: 3800, grid_x: 480521 }, + { grid_y: 121089, count: 3800, grid_x: 480530 }, + { grid_y: 121090, count: 3800, grid_x: 480461 }, + { grid_y: 121090, count: 3800, grid_x: 480467 }, + { grid_y: 121090, count: 3800, grid_x: 480470 }, + { grid_y: 121090, count: 3800, grid_x: 480474 }, + { grid_y: 121090, count: 3800, grid_x: 480475 }, + { grid_y: 121090, count: 7600, grid_x: 480480 }, + { grid_y: 121090, count: 3800, grid_x: 480484 }, + { grid_y: 121090, count: 3800, grid_x: 480487 }, + { grid_y: 121090, count: 3800, grid_x: 480495 }, + { grid_y: 121090, count: 3800, grid_x: 480498 }, + { grid_y: 121090, count: 7600, grid_x: 480499 }, + { grid_y: 121090, count: 3800, grid_x: 480500 }, + { grid_y: 121090, count: 45600, grid_x: 480501 }, + { grid_y: 121090, count: 34200, grid_x: 480502 }, + { grid_y: 121090, count: 15200, grid_x: 480503 }, + { grid_y: 121090, count: 7600, grid_x: 480504 }, + { grid_y: 121090, count: 7600, grid_x: 480505 }, + { grid_y: 121090, count: 3800, grid_x: 480506 }, + { grid_y: 121090, count: 3800, grid_x: 480508 }, + { grid_y: 121090, count: 3800, grid_x: 480509 }, + { grid_y: 121090, count: 3800, grid_x: 480510 }, + { grid_y: 121090, count: 3800, grid_x: 480511 }, + { grid_y: 121090, count: 3800, grid_x: 480512 }, + { grid_y: 121090, count: 3800, grid_x: 480521 }, + { grid_y: 121090, count: 3800, grid_x: 480522 }, + { grid_y: 121090, count: 3800, grid_x: 480523 }, + { grid_y: 121090, count: 3800, grid_x: 480524 }, + { grid_y: 121090, count: 7600, grid_x: 480525 }, + { grid_y: 121090, count: 3800, grid_x: 480527 }, + { grid_y: 121091, count: 3800, grid_x: 480461 }, + { grid_y: 121091, count: 3800, grid_x: 480467 }, + { grid_y: 121091, count: 7600, grid_x: 480472 }, + { grid_y: 121091, count: 3800, grid_x: 480481 }, + { grid_y: 121091, count: 3800, grid_x: 480486 }, + { grid_y: 121091, count: 7600, grid_x: 480491 }, + { grid_y: 121091, count: 7600, grid_x: 480493 }, + { grid_y: 121091, count: 3800, grid_x: 480494 }, + { grid_y: 121091, count: 15200, grid_x: 480495 }, + { grid_y: 121091, count: 7600, grid_x: 480496 }, + { grid_y: 121091, count: 11400, grid_x: 480498 }, + { grid_y: 121091, count: 11400, grid_x: 480500 }, + { grid_y: 121091, count: 3800, grid_x: 480501 }, + { grid_y: 121091, count: 11400, grid_x: 480502 }, + { grid_y: 121091, count: 7600, grid_x: 480503 }, + { grid_y: 121091, count: 7600, grid_x: 480504 }, + { grid_y: 121091, count: 3800, grid_x: 480508 }, + { grid_y: 121091, count: 3800, grid_x: 480509 }, + { grid_y: 121091, count: 3800, grid_x: 480520 }, + { grid_y: 121091, count: 7600, grid_x: 480521 }, + { grid_y: 121091, count: 7600, grid_x: 480522 }, + { grid_y: 121091, count: 26600, grid_x: 480523 }, + { grid_y: 121091, count: 7600, grid_x: 480524 }, + { grid_y: 121091, count: 7600, grid_x: 480525 }, + { grid_y: 121091, count: 15200, grid_x: 480526 }, + { grid_y: 121091, count: 3800, grid_x: 480527 }, + { grid_y: 121091, count: 3800, grid_x: 480528 }, + { grid_y: 121091, count: 3800, grid_x: 480532 }, + { grid_y: 121091, count: 3800, grid_x: 480533 }, + { grid_y: 121092, count: 7600, grid_x: 480460 }, + { grid_y: 121092, count: 3800, grid_x: 480465 }, + { grid_y: 121092, count: 7600, grid_x: 480466 }, + { grid_y: 121092, count: 3800, grid_x: 480467 }, + { grid_y: 121092, count: 3800, grid_x: 480468 }, + { grid_y: 121092, count: 3800, grid_x: 480469 }, + { grid_y: 121092, count: 3800, grid_x: 480474 }, + { grid_y: 121092, count: 7600, grid_x: 480482 }, + { grid_y: 121092, count: 3800, grid_x: 480491 }, + { grid_y: 121092, count: 3800, grid_x: 480492 }, + { grid_y: 121092, count: 3800, grid_x: 480493 }, + { grid_y: 121092, count: 7600, grid_x: 480494 }, + { grid_y: 121092, count: 11400, grid_x: 480495 }, + { grid_y: 121092, count: 3800, grid_x: 480496 }, + { grid_y: 121092, count: 15200, grid_x: 480498 }, + { grid_y: 121092, count: 7600, grid_x: 480499 }, + { grid_y: 121092, count: 3800, grid_x: 480501 }, + { grid_y: 121092, count: 7600, grid_x: 480502 }, + { grid_y: 121092, count: 3800, grid_x: 480503 }, + { grid_y: 121092, count: 3800, grid_x: 480504 }, + { grid_y: 121092, count: 7600, grid_x: 480507 }, + { grid_y: 121092, count: 3800, grid_x: 480508 }, + { grid_y: 121092, count: 3800, grid_x: 480511 }, + { grid_y: 121092, count: 3800, grid_x: 480512 }, + { grid_y: 121092, count: 3800, grid_x: 480516 }, + { grid_y: 121092, count: 7600, grid_x: 480523 }, + { grid_y: 121092, count: 7600, grid_x: 480524 }, + { grid_y: 121092, count: 7600, grid_x: 480525 }, + { grid_y: 121092, count: 7600, grid_x: 480526 }, + { grid_y: 121092, count: 3800, grid_x: 480532 }, + { grid_y: 121092, count: 3800, grid_x: 480533 }, + { grid_y: 121093, count: 3800, grid_x: 480463 }, + { grid_y: 121093, count: 7600, grid_x: 480466 }, + { grid_y: 121093, count: 3800, grid_x: 480468 }, + { grid_y: 121093, count: 3800, grid_x: 480493 }, + { grid_y: 121093, count: 3800, grid_x: 480494 }, + { grid_y: 121093, count: 3800, grid_x: 480496 }, + { grid_y: 121093, count: 3800, grid_x: 480498 }, + { grid_y: 121093, count: 3800, grid_x: 480499 }, + { grid_y: 121093, count: 3800, grid_x: 480502 }, + { grid_y: 121093, count: 3800, grid_x: 480503 }, + { grid_y: 121093, count: 3800, grid_x: 480504 }, + { grid_y: 121093, count: 3800, grid_x: 480507 }, + { grid_y: 121093, count: 3800, grid_x: 480508 }, + { grid_y: 121093, count: 3800, grid_x: 480509 }, + { grid_y: 121093, count: 3800, grid_x: 480512 }, + { grid_y: 121093, count: 3800, grid_x: 480514 }, + { grid_y: 121093, count: 3800, grid_x: 480520 }, + { grid_y: 121093, count: 3800, grid_x: 480521 }, + { grid_y: 121093, count: 3800, grid_x: 480523 }, + { grid_y: 121093, count: 3800, grid_x: 480524 }, + { grid_y: 121093, count: 3800, grid_x: 480526 }, + { grid_y: 121093, count: 3800, grid_x: 480532 }, + { grid_y: 121093, count: 3800, grid_x: 480533 }, + { grid_y: 121094, count: 3800, grid_x: 480467 }, + { grid_y: 121094, count: 3800, grid_x: 480491 }, + { grid_y: 121094, count: 3800, grid_x: 480496 }, + { grid_y: 121094, count: 3800, grid_x: 480497 }, + { grid_y: 121094, count: 7600, grid_x: 480499 }, + { grid_y: 121094, count: 3800, grid_x: 480503 }, + { grid_y: 121094, count: 7600, grid_x: 480509 }, + { grid_y: 121094, count: 3800, grid_x: 480514 }, + { grid_y: 121094, count: 3800, grid_x: 480519 }, + { grid_y: 121094, count: 3800, grid_x: 480521 }, + { grid_y: 121094, count: 7600, grid_x: 480532 }, + { grid_y: 121095, count: 3800, grid_x: 480462 }, + { grid_y: 121095, count: 3800, grid_x: 480467 }, + { grid_y: 121095, count: 3800, grid_x: 480472 }, + { grid_y: 121095, count: 3800, grid_x: 480473 }, + { grid_y: 121095, count: 3800, grid_x: 480476 }, + { grid_y: 121095, count: 3800, grid_x: 480480 }, + { grid_y: 121095, count: 3800, grid_x: 480497 }, + { grid_y: 121095, count: 3800, grid_x: 480498 }, + { grid_y: 121095, count: 3800, grid_x: 480501 }, + { grid_y: 121095, count: 3800, grid_x: 480515 }, + { grid_y: 121095, count: 3800, grid_x: 480520 }, + { grid_y: 121095, count: 3800, grid_x: 480522 }, + { grid_y: 121095, count: 3800, grid_x: 480530 }, + { grid_y: 121095, count: 3800, grid_x: 480531 }, + { grid_y: 121096, count: 3800, grid_x: 480465 }, + { grid_y: 121096, count: 3800, grid_x: 480483 }, + { grid_y: 121096, count: 7600, grid_x: 480485 }, + { grid_y: 121096, count: 3800, grid_x: 480489 }, + { grid_y: 121096, count: 3800, grid_x: 480491 }, + { grid_y: 121096, count: 3800, grid_x: 480494 }, + { grid_y: 121096, count: 7600, grid_x: 480497 }, + { grid_y: 121096, count: 3800, grid_x: 480498 }, + { grid_y: 121096, count: 3800, grid_x: 480499 }, + { grid_y: 121096, count: 3800, grid_x: 480500 }, + { grid_y: 121096, count: 7600, grid_x: 480502 }, + { grid_y: 121096, count: 7600, grid_x: 480503 }, + { grid_y: 121096, count: 3800, grid_x: 480504 }, + { grid_y: 121096, count: 3800, grid_x: 480505 }, + { grid_y: 121096, count: 3800, grid_x: 480507 }, + { grid_y: 121096, count: 3800, grid_x: 480510 }, + { grid_y: 121096, count: 3800, grid_x: 480511 }, + { grid_y: 121096, count: 3800, grid_x: 480512 }, + { grid_y: 121096, count: 7600, grid_x: 480515 }, + { grid_y: 121096, count: 3800, grid_x: 480517 }, + { grid_y: 121096, count: 7600, grid_x: 480520 }, + { grid_y: 121096, count: 3800, grid_x: 480525 }, + { grid_y: 121096, count: 3800, grid_x: 480527 }, + { grid_y: 121096, count: 3800, grid_x: 480529 }, + { grid_y: 121096, count: 3800, grid_x: 480531 }, + { grid_y: 121097, count: 3800, grid_x: 480465 }, + { grid_y: 121097, count: 3800, grid_x: 480472 }, + { grid_y: 121097, count: 3800, grid_x: 480482 }, + { grid_y: 121097, count: 11400, grid_x: 480483 }, + { grid_y: 121097, count: 3800, grid_x: 480484 }, + { grid_y: 121097, count: 3800, grid_x: 480485 }, + { grid_y: 121097, count: 3800, grid_x: 480486 }, + { grid_y: 121097, count: 11400, grid_x: 480487 }, + { grid_y: 121097, count: 7600, grid_x: 480488 }, + { grid_y: 121097, count: 7600, grid_x: 480489 }, + { grid_y: 121097, count: 7600, grid_x: 480491 }, + { grid_y: 121097, count: 11400, grid_x: 480492 }, + { grid_y: 121097, count: 3800, grid_x: 480493 }, + { grid_y: 121097, count: 3800, grid_x: 480494 }, + { grid_y: 121097, count: 7600, grid_x: 480495 }, + { grid_y: 121097, count: 3800, grid_x: 480497 }, + { grid_y: 121097, count: 7600, grid_x: 480499 }, + { grid_y: 121097, count: 3800, grid_x: 480501 }, + { grid_y: 121097, count: 3800, grid_x: 480506 }, + { grid_y: 121097, count: 3800, grid_x: 480509 }, + { grid_y: 121097, count: 7600, grid_x: 480513 }, + { grid_y: 121097, count: 3800, grid_x: 480515 }, + { grid_y: 121097, count: 7600, grid_x: 480520 }, + { grid_y: 121097, count: 3800, grid_x: 480522 }, + { grid_y: 121097, count: 3800, grid_x: 480531 }, + { grid_y: 121097, count: 7600, grid_x: 480532 }, + { grid_y: 121097, count: 7600, grid_x: 480533 }, + { grid_y: 121098, count: 7600, grid_x: 480464 }, + { grid_y: 121098, count: 3800, grid_x: 480475 }, + { grid_y: 121098, count: 7600, grid_x: 480484 }, + { grid_y: 121098, count: 11400, grid_x: 480487 }, + { grid_y: 121098, count: 11400, grid_x: 480489 }, + { grid_y: 121098, count: 3800, grid_x: 480497 }, + { grid_y: 121098, count: 7600, grid_x: 480499 }, + { grid_y: 121098, count: 15200, grid_x: 480501 }, + { grid_y: 121098, count: 3800, grid_x: 480502 }, + { grid_y: 121098, count: 3800, grid_x: 480504 }, + { grid_y: 121098, count: 3800, grid_x: 480509 }, + { grid_y: 121098, count: 3800, grid_x: 480519 }, + { grid_y: 121098, count: 3800, grid_x: 480521 }, + { grid_y: 121098, count: 7600, grid_x: 480523 }, + { grid_y: 121098, count: 3800, grid_x: 480524 }, + { grid_y: 121098, count: 3800, grid_x: 480526 }, + { grid_y: 121098, count: 3800, grid_x: 480529 }, + { grid_y: 121098, count: 3800, grid_x: 480532 }, + { grid_y: 121098, count: 7600, grid_x: 480533 }, + { grid_y: 121099, count: 7600, grid_x: 480461 }, + { grid_y: 121099, count: 3800, grid_x: 480464 }, + { grid_y: 121099, count: 3800, grid_x: 480469 }, + { grid_y: 121099, count: 7600, grid_x: 480470 }, + { grid_y: 121099, count: 3800, grid_x: 480477 }, + { grid_y: 121099, count: 3800, grid_x: 480481 }, + { grid_y: 121099, count: 3800, grid_x: 480482 }, + { grid_y: 121099, count: 7600, grid_x: 480485 }, + { grid_y: 121099, count: 7600, grid_x: 480486 }, + { grid_y: 121099, count: 19000, grid_x: 480487 }, + { grid_y: 121099, count: 7600, grid_x: 480488 }, + { grid_y: 121099, count: 3800, grid_x: 480497 }, + { grid_y: 121099, count: 3800, grid_x: 480499 }, + { grid_y: 121099, count: 7600, grid_x: 480500 }, + { grid_y: 121099, count: 19000, grid_x: 480501 }, + { grid_y: 121099, count: 7600, grid_x: 480502 }, + { grid_y: 121099, count: 3800, grid_x: 480504 }, + { grid_y: 121099, count: 7600, grid_x: 480505 }, + { grid_y: 121099, count: 3800, grid_x: 480519 }, + { grid_y: 121099, count: 3800, grid_x: 480520 }, + { grid_y: 121099, count: 3800, grid_x: 480528 }, + { grid_y: 121099, count: 7600, grid_x: 480532 }, + { grid_y: 121100, count: 3800, grid_x: 480461 }, + { grid_y: 121100, count: 3800, grid_x: 480462 }, + { grid_y: 121100, count: 3800, grid_x: 480465 }, + { grid_y: 121100, count: 3800, grid_x: 480480 }, + { grid_y: 121100, count: 15200, grid_x: 480481 }, + { grid_y: 121100, count: 3800, grid_x: 480484 }, + { grid_y: 121100, count: 7600, grid_x: 480487 }, + { grid_y: 121100, count: 11400, grid_x: 480488 }, + { grid_y: 121100, count: 7600, grid_x: 480489 }, + { grid_y: 121100, count: 3800, grid_x: 480490 }, + { grid_y: 121100, count: 3800, grid_x: 480497 }, + { grid_y: 121100, count: 7600, grid_x: 480502 }, + { grid_y: 121100, count: 7600, grid_x: 480504 }, + { grid_y: 121100, count: 7600, grid_x: 480505 }, + { grid_y: 121100, count: 3800, grid_x: 480508 }, + { grid_y: 121100, count: 3800, grid_x: 480523 }, + { grid_y: 121100, count: 3800, grid_x: 480528 }, + { grid_y: 121100, count: 3800, grid_x: 480529 }, + { grid_y: 121100, count: 7600, grid_x: 480530 }, + { grid_y: 121100, count: 3800, grid_x: 480531 }, + { grid_y: 121100, count: 7600, grid_x: 480532 }, + { grid_y: 121100, count: 7600, grid_x: 480533 }, + { grid_y: 121101, count: 3800, grid_x: 480459 }, + { grid_y: 121101, count: 3800, grid_x: 480462 }, + { grid_y: 121101, count: 3800, grid_x: 480475 }, + { grid_y: 121101, count: 7600, grid_x: 480482 }, + { grid_y: 121101, count: 7600, grid_x: 480488 }, + { grid_y: 121101, count: 7600, grid_x: 480489 }, + { grid_y: 121101, count: 3800, grid_x: 480492 }, + { grid_y: 121101, count: 3800, grid_x: 480497 }, + { grid_y: 121101, count: 3800, grid_x: 480498 }, + { grid_y: 121101, count: 3800, grid_x: 480501 }, + { grid_y: 121101, count: 7600, grid_x: 480504 }, + { grid_y: 121101, count: 11400, grid_x: 480505 }, + { grid_y: 121101, count: 3800, grid_x: 480510 }, + { grid_y: 121101, count: 3800, grid_x: 480517 }, + { grid_y: 121101, count: 3800, grid_x: 480519 }, + { grid_y: 121101, count: 7600, grid_x: 480520 }, + { grid_y: 121101, count: 3800, grid_x: 480522 }, + { grid_y: 121101, count: 3800, grid_x: 480527 }, + { grid_y: 121101, count: 7600, grid_x: 480528 }, + { grid_y: 121101, count: 7600, grid_x: 480529 }, + { grid_y: 121101, count: 7600, grid_x: 480530 }, + { grid_y: 121101, count: 7600, grid_x: 480531 }, + { grid_y: 121101, count: 11400, grid_x: 480532 }, + { grid_y: 121101, count: 11400, grid_x: 480533 }, + { grid_y: 121102, count: 3800, grid_x: 480466 }, + { grid_y: 121102, count: 3800, grid_x: 480468 }, + { grid_y: 121102, count: 3800, grid_x: 480479 }, + { grid_y: 121102, count: 3800, grid_x: 480480 }, + { grid_y: 121102, count: 3800, grid_x: 480481 }, + { grid_y: 121102, count: 3800, grid_x: 480486 }, + { grid_y: 121102, count: 3800, grid_x: 480487 }, + { grid_y: 121102, count: 3800, grid_x: 480488 }, + { grid_y: 121102, count: 3800, grid_x: 480489 }, + { grid_y: 121102, count: 3800, grid_x: 480490 }, + { grid_y: 121102, count: 3800, grid_x: 480492 }, + { grid_y: 121102, count: 7600, grid_x: 480493 }, + { grid_y: 121102, count: 3800, grid_x: 480497 }, + { grid_y: 121102, count: 3800, grid_x: 480499 }, + { grid_y: 121102, count: 3800, grid_x: 480501 }, + { grid_y: 121102, count: 3800, grid_x: 480503 }, + { grid_y: 121102, count: 7600, grid_x: 480504 }, + { grid_y: 121102, count: 11400, grid_x: 480505 }, + { grid_y: 121102, count: 7600, grid_x: 480506 }, + { grid_y: 121102, count: 3800, grid_x: 480514 }, + { grid_y: 121102, count: 3800, grid_x: 480518 }, + { grid_y: 121102, count: 7600, grid_x: 480519 }, + { grid_y: 121102, count: 3800, grid_x: 480525 }, + { grid_y: 121102, count: 7600, grid_x: 480527 }, + { grid_y: 121102, count: 7600, grid_x: 480528 }, + { grid_y: 121102, count: 7600, grid_x: 480529 }, + { grid_y: 121102, count: 15200, grid_x: 480530 }, + { grid_y: 121102, count: 3800, grid_x: 480531 }, + { grid_y: 121102, count: 3800, grid_x: 480532 }, + { grid_y: 121102, count: 7600, grid_x: 480533 }, + { grid_y: 121103, count: 3800, grid_x: 480459 }, + { grid_y: 121103, count: 3800, grid_x: 480460 }, + { grid_y: 121103, count: 7600, grid_x: 480471 }, + { grid_y: 121103, count: 3800, grid_x: 480472 }, + { grid_y: 121103, count: 3800, grid_x: 480481 }, + { grid_y: 121103, count: 3800, grid_x: 480482 }, + { grid_y: 121103, count: 3800, grid_x: 480484 }, + { grid_y: 121103, count: 3800, grid_x: 480485 }, + { grid_y: 121103, count: 11400, grid_x: 480488 }, + { grid_y: 121103, count: 15200, grid_x: 480489 }, + { grid_y: 121103, count: 7600, grid_x: 480495 }, + { grid_y: 121103, count: 7600, grid_x: 480496 }, + { grid_y: 121103, count: 3800, grid_x: 480497 }, + { grid_y: 121103, count: 3800, grid_x: 480501 }, + { grid_y: 121103, count: 3800, grid_x: 480503 }, + { grid_y: 121103, count: 7600, grid_x: 480505 }, + { grid_y: 121103, count: 3800, grid_x: 480506 }, + { grid_y: 121103, count: 3800, grid_x: 480507 }, + { grid_y: 121103, count: 3800, grid_x: 480509 }, + { grid_y: 121103, count: 3800, grid_x: 480510 }, + { grid_y: 121103, count: 3800, grid_x: 480514 }, + { grid_y: 121103, count: 3800, grid_x: 480517 }, + { grid_y: 121103, count: 3800, grid_x: 480519 }, + { grid_y: 121103, count: 3800, grid_x: 480522 }, + { grid_y: 121103, count: 3800, grid_x: 480525 }, + { grid_y: 121103, count: 3800, grid_x: 480528 }, + { grid_y: 121103, count: 3800, grid_x: 480529 }, + { grid_y: 121103, count: 3800, grid_x: 480530 }, + { grid_y: 121103, count: 3800, grid_x: 480533 }, + { grid_y: 121104, count: 3800, grid_x: 480460 }, + { grid_y: 121104, count: 3800, grid_x: 480461 }, + { grid_y: 121104, count: 3800, grid_x: 480463 }, + { grid_y: 121104, count: 3800, grid_x: 480466 }, + { grid_y: 121104, count: 3800, grid_x: 480477 }, + { grid_y: 121104, count: 7600, grid_x: 480478 }, + { grid_y: 121104, count: 7600, grid_x: 480479 }, + { grid_y: 121104, count: 3800, grid_x: 480480 }, + { grid_y: 121104, count: 7600, grid_x: 480481 }, + { grid_y: 121104, count: 7600, grid_x: 480482 }, + { grid_y: 121104, count: 3800, grid_x: 480483 }, + { grid_y: 121104, count: 3800, grid_x: 480487 }, + { grid_y: 121104, count: 11400, grid_x: 480488 }, + { grid_y: 121104, count: 7600, grid_x: 480489 }, + { grid_y: 121104, count: 15200, grid_x: 480490 }, + { grid_y: 121104, count: 3800, grid_x: 480491 }, + { grid_y: 121104, count: 3800, grid_x: 480494 }, + { grid_y: 121104, count: 7600, grid_x: 480495 }, + { grid_y: 121104, count: 7600, grid_x: 480496 }, + { grid_y: 121104, count: 7600, grid_x: 480497 }, + { grid_y: 121104, count: 3800, grid_x: 480499 }, + { grid_y: 121104, count: 3800, grid_x: 480500 }, + { grid_y: 121104, count: 3800, grid_x: 480506 }, + { grid_y: 121104, count: 3800, grid_x: 480513 }, + { grid_y: 121104, count: 3800, grid_x: 480515 }, + { grid_y: 121104, count: 7600, grid_x: 480516 }, + { grid_y: 121104, count: 7600, grid_x: 480517 }, + { grid_y: 121104, count: 3800, grid_x: 480519 }, + { grid_y: 121104, count: 7600, grid_x: 480520 }, + { grid_y: 121104, count: 3800, grid_x: 480524 }, + { grid_y: 121104, count: 7600, grid_x: 480525 }, + { grid_y: 121104, count: 7600, grid_x: 480526 }, + { grid_y: 121104, count: 3800, grid_x: 480527 }, + { grid_y: 121104, count: 3800, grid_x: 480528 }, + { grid_y: 121104, count: 7600, grid_x: 480530 }, + { grid_y: 121104, count: 7600, grid_x: 480531 }, + { grid_y: 121105, count: 3800, grid_x: 480460 }, + { grid_y: 121105, count: 7600, grid_x: 480462 }, + { grid_y: 121105, count: 3800, grid_x: 480463 }, + { grid_y: 121105, count: 3800, grid_x: 480464 }, + { grid_y: 121105, count: 3800, grid_x: 480467 }, + { grid_y: 121105, count: 3800, grid_x: 480468 }, + { grid_y: 121105, count: 3800, grid_x: 480469 }, + { grid_y: 121105, count: 7600, grid_x: 480470 }, + { grid_y: 121105, count: 7600, grid_x: 480472 }, + { grid_y: 121105, count: 3800, grid_x: 480473 }, + { grid_y: 121105, count: 3800, grid_x: 480476 }, + { grid_y: 121105, count: 7600, grid_x: 480477 }, + { grid_y: 121105, count: 7600, grid_x: 480480 }, + { grid_y: 121105, count: 3800, grid_x: 480481 }, + { grid_y: 121105, count: 7600, grid_x: 480482 }, + { grid_y: 121105, count: 7600, grid_x: 480483 }, + { grid_y: 121105, count: 3800, grid_x: 480485 }, + { grid_y: 121105, count: 7600, grid_x: 480487 }, + { grid_y: 121105, count: 3800, grid_x: 480488 }, + { grid_y: 121105, count: 22800, grid_x: 480489 }, + { grid_y: 121105, count: 15200, grid_x: 480490 }, + { grid_y: 121105, count: 11400, grid_x: 480492 }, + { grid_y: 121105, count: 3800, grid_x: 480493 }, + { grid_y: 121105, count: 3800, grid_x: 480494 }, + { grid_y: 121105, count: 3800, grid_x: 480495 }, + { grid_y: 121105, count: 3800, grid_x: 480496 }, + { grid_y: 121105, count: 7600, grid_x: 480497 }, + { grid_y: 121105, count: 3800, grid_x: 480500 }, + { grid_y: 121105, count: 3800, grid_x: 480501 }, + { grid_y: 121105, count: 3800, grid_x: 480509 }, + { grid_y: 121105, count: 3800, grid_x: 480515 }, + { grid_y: 121105, count: 3800, grid_x: 480517 }, + { grid_y: 121105, count: 3800, grid_x: 480518 }, + { grid_y: 121105, count: 3800, grid_x: 480519 }, + { grid_y: 121105, count: 3800, grid_x: 480520 }, + { grid_y: 121105, count: 3800, grid_x: 480521 }, + { grid_y: 121105, count: 3800, grid_x: 480522 }, + { grid_y: 121105, count: 11400, grid_x: 480526 }, + { grid_y: 121105, count: 11400, grid_x: 480527 }, + { grid_y: 121105, count: 3800, grid_x: 480528 }, + { grid_y: 121105, count: 3800, grid_x: 480529 }, + { grid_y: 121105, count: 3800, grid_x: 480531 }, + { grid_y: 121105, count: 7600, grid_x: 480532 }, + { grid_y: 121105, count: 7600, grid_x: 480533 }, + { grid_y: 121106, count: 3800, grid_x: 480464 }, + { grid_y: 121106, count: 7600, grid_x: 480465 }, + { grid_y: 121106, count: 3800, grid_x: 480466 }, + { grid_y: 121106, count: 3800, grid_x: 480469 }, + { grid_y: 121106, count: 3800, grid_x: 480471 }, + { grid_y: 121106, count: 3800, grid_x: 480472 }, + { grid_y: 121106, count: 3800, grid_x: 480473 }, + { grid_y: 121106, count: 3800, grid_x: 480476 }, + { grid_y: 121106, count: 11400, grid_x: 480479 }, + { grid_y: 121106, count: 15200, grid_x: 480480 }, + { grid_y: 121106, count: 3800, grid_x: 480484 }, + { grid_y: 121106, count: 3800, grid_x: 480487 }, + { grid_y: 121106, count: 3800, grid_x: 480488 }, + { grid_y: 121106, count: 7600, grid_x: 480490 }, + { grid_y: 121106, count: 7600, grid_x: 480494 }, + { grid_y: 121106, count: 3800, grid_x: 480495 }, + { grid_y: 121106, count: 3800, grid_x: 480497 }, + { grid_y: 121106, count: 15200, grid_x: 480498 }, + { grid_y: 121106, count: 15200, grid_x: 480499 }, + { grid_y: 121106, count: 3800, grid_x: 480500 }, + { grid_y: 121106, count: 3800, grid_x: 480501 }, + { grid_y: 121106, count: 11400, grid_x: 480503 }, + { grid_y: 121106, count: 3800, grid_x: 480504 }, + { grid_y: 121106, count: 7600, grid_x: 480505 }, + { grid_y: 121106, count: 3800, grid_x: 480506 }, + { grid_y: 121106, count: 11400, grid_x: 480507 }, + { grid_y: 121106, count: 3800, grid_x: 480508 }, + { grid_y: 121106, count: 3800, grid_x: 480509 }, + { grid_y: 121106, count: 3800, grid_x: 480511 }, + { grid_y: 121106, count: 3800, grid_x: 480513 }, + { grid_y: 121106, count: 3800, grid_x: 480514 }, + { grid_y: 121106, count: 3800, grid_x: 480515 }, + { grid_y: 121106, count: 3800, grid_x: 480519 }, + { grid_y: 121106, count: 7600, grid_x: 480520 }, + { grid_y: 121106, count: 3800, grid_x: 480523 }, + { grid_y: 121106, count: 11400, grid_x: 480527 }, + { grid_y: 121106, count: 7600, grid_x: 480528 }, + { grid_y: 121106, count: 3800, grid_x: 480529 }, + { grid_y: 121106, count: 3800, grid_x: 480530 }, + { grid_y: 121106, count: 3800, grid_x: 480532 }, + { grid_y: 121106, count: 7600, grid_x: 480533 }, + { grid_y: 121107, count: 7600, grid_x: 480459 }, + { grid_y: 121107, count: 7600, grid_x: 480461 }, + { grid_y: 121107, count: 3800, grid_x: 480462 }, + { grid_y: 121107, count: 3800, grid_x: 480464 }, + { grid_y: 121107, count: 3800, grid_x: 480466 }, + { grid_y: 121107, count: 3800, grid_x: 480467 }, + { grid_y: 121107, count: 3800, grid_x: 480471 }, + { grid_y: 121107, count: 3800, grid_x: 480472 }, + { grid_y: 121107, count: 3800, grid_x: 480478 }, + { grid_y: 121107, count: 3800, grid_x: 480479 }, + { grid_y: 121107, count: 7600, grid_x: 480480 }, + { grid_y: 121107, count: 3800, grid_x: 480483 }, + { grid_y: 121107, count: 3800, grid_x: 480485 }, + { grid_y: 121107, count: 7600, grid_x: 480497 }, + { grid_y: 121107, count: 11400, grid_x: 480498 }, + { grid_y: 121107, count: 19000, grid_x: 480499 }, + { grid_y: 121107, count: 11400, grid_x: 480500 }, + { grid_y: 121107, count: 3800, grid_x: 480501 }, + { grid_y: 121107, count: 3800, grid_x: 480503 }, + { grid_y: 121107, count: 7600, grid_x: 480507 }, + { grid_y: 121107, count: 15200, grid_x: 480508 }, + { grid_y: 121107, count: 3800, grid_x: 480510 }, + { grid_y: 121107, count: 3800, grid_x: 480512 }, + { grid_y: 121107, count: 7600, grid_x: 480513 }, + { grid_y: 121107, count: 7600, grid_x: 480514 }, + { grid_y: 121107, count: 3800, grid_x: 480516 }, + { grid_y: 121107, count: 7600, grid_x: 480517 }, + { grid_y: 121107, count: 3800, grid_x: 480520 }, + { grid_y: 121107, count: 11400, grid_x: 480522 }, + { grid_y: 121107, count: 7600, grid_x: 480523 }, + { grid_y: 121107, count: 3800, grid_x: 480524 }, + { grid_y: 121107, count: 7600, grid_x: 480525 }, + { grid_y: 121107, count: 3800, grid_x: 480526 }, + { grid_y: 121107, count: 3800, grid_x: 480527 }, + { grid_y: 121107, count: 3800, grid_x: 480528 }, + { grid_y: 121107, count: 7600, grid_x: 480529 }, + { grid_y: 121107, count: 7600, grid_x: 480532 }, + { grid_y: 121107, count: 7600, grid_x: 480533 }, + { grid_y: 121108, count: 7600, grid_x: 480459 }, + { grid_y: 121108, count: 7600, grid_x: 480460 }, + { grid_y: 121108, count: 3800, grid_x: 480461 }, + { grid_y: 121108, count: 3800, grid_x: 480464 }, + { grid_y: 121108, count: 3800, grid_x: 480495 }, + { grid_y: 121108, count: 3800, grid_x: 480497 }, + { grid_y: 121108, count: 15200, grid_x: 480498 }, + { grid_y: 121108, count: 19000, grid_x: 480499 }, + { grid_y: 121108, count: 11400, grid_x: 480500 }, + { grid_y: 121108, count: 11400, grid_x: 480501 }, + { grid_y: 121108, count: 11400, grid_x: 480502 }, + { grid_y: 121108, count: 11400, grid_x: 480503 }, + { grid_y: 121108, count: 7600, grid_x: 480507 }, + { grid_y: 121108, count: 3800, grid_x: 480513 }, + { grid_y: 121108, count: 3800, grid_x: 480514 }, + { grid_y: 121108, count: 3800, grid_x: 480515 }, + { grid_y: 121108, count: 11400, grid_x: 480516 }, + { grid_y: 121108, count: 7600, grid_x: 480517 }, + { grid_y: 121108, count: 3800, grid_x: 480518 }, + { grid_y: 121108, count: 3800, grid_x: 480519 }, + { grid_y: 121108, count: 3800, grid_x: 480520 }, + { grid_y: 121108, count: 3800, grid_x: 480524 }, + { grid_y: 121108, count: 3800, grid_x: 480526 }, + { grid_y: 121108, count: 7600, grid_x: 480527 }, + { grid_y: 121108, count: 3800, grid_x: 480528 }, + { grid_y: 121108, count: 3800, grid_x: 480529 }, + { grid_y: 121108, count: 3800, grid_x: 480530 }, + { grid_y: 121108, count: 7600, grid_x: 480533 }, + { grid_y: 121109, count: 7600, grid_x: 480459 }, + { grid_y: 121109, count: 7600, grid_x: 480460 }, + { grid_y: 121109, count: 7600, grid_x: 480496 }, + { grid_y: 121109, count: 7600, grid_x: 480497 }, + { grid_y: 121109, count: 7600, grid_x: 480498 }, + { grid_y: 121109, count: 11400, grid_x: 480499 }, + { grid_y: 121109, count: 7600, grid_x: 480500 }, + { grid_y: 121109, count: 3800, grid_x: 480501 }, + { grid_y: 121109, count: 11400, grid_x: 480502 }, + { grid_y: 121109, count: 3800, grid_x: 480503 }, + { grid_y: 121109, count: 3800, grid_x: 480506 }, + { grid_y: 121109, count: 7600, grid_x: 480507 }, + { grid_y: 121109, count: 3800, grid_x: 480508 }, + { grid_y: 121109, count: 3800, grid_x: 480510 }, + { grid_y: 121109, count: 3800, grid_x: 480513 }, + { grid_y: 121109, count: 7600, grid_x: 480514 }, + { grid_y: 121109, count: 7600, grid_x: 480516 }, + { grid_y: 121109, count: 11400, grid_x: 480517 }, + { grid_y: 121109, count: 3800, grid_x: 480518 }, + { grid_y: 121109, count: 3800, grid_x: 480523 }, + { grid_y: 121109, count: 3800, grid_x: 480531 }, + { grid_y: 121109, count: 3800, grid_x: 480533 }, + { grid_y: 121110, count: 7600, grid_x: 480459 }, + { grid_y: 121110, count: 3800, grid_x: 480460 }, + { grid_y: 121110, count: 3800, grid_x: 480461 }, + { grid_y: 121110, count: 3800, grid_x: 480465 }, + { grid_y: 121110, count: 3800, grid_x: 480467 }, + { grid_y: 121110, count: 3800, grid_x: 480471 }, + { grid_y: 121110, count: 3800, grid_x: 480478 }, + { grid_y: 121110, count: 3800, grid_x: 480479 }, + { grid_y: 121110, count: 3800, grid_x: 480489 }, + { grid_y: 121110, count: 7600, grid_x: 480497 }, + { grid_y: 121110, count: 7600, grid_x: 480498 }, + { grid_y: 121110, count: 7600, grid_x: 480499 }, + { grid_y: 121110, count: 7600, grid_x: 480502 }, + { grid_y: 121110, count: 3800, grid_x: 480504 }, + { grid_y: 121110, count: 3800, grid_x: 480510 }, + { grid_y: 121110, count: 7600, grid_x: 480511 }, + { grid_y: 121110, count: 3800, grid_x: 480512 }, + { grid_y: 121110, count: 11400, grid_x: 480516 }, + { grid_y: 121110, count: 7600, grid_x: 480517 }, + { grid_y: 121110, count: 3800, grid_x: 480518 }, + { grid_y: 121110, count: 7600, grid_x: 480519 }, + { grid_y: 121110, count: 3800, grid_x: 480521 }, + { grid_y: 121110, count: 3800, grid_x: 480523 }, + { grid_y: 121110, count: 3800, grid_x: 480526 }, + { grid_y: 121111, count: 3800, grid_x: 480460 }, + { grid_y: 121111, count: 3800, grid_x: 480493 }, + { grid_y: 121111, count: 3800, grid_x: 480496 }, + { grid_y: 121111, count: 11400, grid_x: 480500 }, + { grid_y: 121111, count: 3800, grid_x: 480501 }, + { grid_y: 121111, count: 7600, grid_x: 480502 }, + { grid_y: 121111, count: 3800, grid_x: 480503 }, + { grid_y: 121111, count: 3800, grid_x: 480504 }, + { grid_y: 121111, count: 3800, grid_x: 480505 }, + { grid_y: 121111, count: 3800, grid_x: 480506 }, + { grid_y: 121111, count: 3800, grid_x: 480511 }, + { grid_y: 121111, count: 3800, grid_x: 480515 }, + { grid_y: 121111, count: 3800, grid_x: 480516 }, + { grid_y: 121111, count: 7600, grid_x: 480517 }, + { grid_y: 121111, count: 3800, grid_x: 480528 }, + { grid_y: 121112, count: 3800, grid_x: 480459 }, + { grid_y: 121112, count: 3800, grid_x: 480460 }, + { grid_y: 121112, count: 3800, grid_x: 480465 }, + { grid_y: 121112, count: 3800, grid_x: 480467 }, + { grid_y: 121112, count: 3800, grid_x: 480478 }, + { grid_y: 121112, count: 3800, grid_x: 480479 }, + { grid_y: 121112, count: 7600, grid_x: 480496 }, + { grid_y: 121112, count: 7600, grid_x: 480500 }, + { grid_y: 121112, count: 7600, grid_x: 480501 }, + { grid_y: 121112, count: 7600, grid_x: 480505 }, + { grid_y: 121112, count: 3800, grid_x: 480506 }, + { grid_y: 121112, count: 3800, grid_x: 480512 }, + { grid_y: 121112, count: 3800, grid_x: 480519 }, + { grid_y: 121112, count: 3800, grid_x: 480525 }, + { grid_y: 121112, count: 3800, grid_x: 480530 }, + { grid_y: 121112, count: 3800, grid_x: 480532 }, + { grid_y: 121112, count: 3800, grid_x: 480533 }, + { grid_y: 121113, count: 3800, grid_x: 480459 }, + { grid_y: 121113, count: 3800, grid_x: 480460 }, + { grid_y: 121113, count: 3800, grid_x: 480462 }, + { grid_y: 121113, count: 3800, grid_x: 480463 }, + { grid_y: 121113, count: 3800, grid_x: 480466 }, + { grid_y: 121113, count: 7600, grid_x: 480479 }, + { grid_y: 121113, count: 3800, grid_x: 480482 }, + { grid_y: 121113, count: 7600, grid_x: 480483 }, + { grid_y: 121113, count: 3800, grid_x: 480485 }, + { grid_y: 121113, count: 3800, grid_x: 480496 }, + { grid_y: 121113, count: 3800, grid_x: 480497 }, + { grid_y: 121113, count: 3800, grid_x: 480498 }, + { grid_y: 121113, count: 7600, grid_x: 480499 }, + { grid_y: 121113, count: 7600, grid_x: 480500 }, + { grid_y: 121113, count: 3800, grid_x: 480501 }, + { grid_y: 121113, count: 3800, grid_x: 480502 }, + { grid_y: 121113, count: 3800, grid_x: 480505 }, + { grid_y: 121113, count: 3800, grid_x: 480506 }, + { grid_y: 121113, count: 3800, grid_x: 480507 }, + { grid_y: 121113, count: 3800, grid_x: 480514 }, + { grid_y: 121113, count: 3800, grid_x: 480517 }, + { grid_y: 121113, count: 7600, grid_x: 480518 }, + { grid_y: 121113, count: 7600, grid_x: 480522 }, + { grid_y: 121113, count: 3800, grid_x: 480527 }, + { grid_y: 121113, count: 3800, grid_x: 480530 }, + { grid_y: 121114, count: 3800, grid_x: 480459 }, + { grid_y: 121114, count: 3800, grid_x: 480460 }, + { grid_y: 121114, count: 3800, grid_x: 480462 }, + { grid_y: 121114, count: 3800, grid_x: 480463 }, + { grid_y: 121114, count: 3800, grid_x: 480466 }, + { grid_y: 121114, count: 3800, grid_x: 480467 }, + { grid_y: 121114, count: 3800, grid_x: 480468 }, + { grid_y: 121114, count: 3800, grid_x: 480471 }, + { grid_y: 121114, count: 7600, grid_x: 480474 }, + { grid_y: 121114, count: 3800, grid_x: 480475 }, + { grid_y: 121114, count: 7600, grid_x: 480478 }, + { grid_y: 121114, count: 7600, grid_x: 480479 }, + { grid_y: 121114, count: 3800, grid_x: 480480 }, + { grid_y: 121114, count: 7600, grid_x: 480481 }, + { grid_y: 121114, count: 15200, grid_x: 480482 }, + { grid_y: 121114, count: 3800, grid_x: 480483 }, + { grid_y: 121114, count: 7600, grid_x: 480484 }, + { grid_y: 121114, count: 3800, grid_x: 480485 }, + { grid_y: 121114, count: 7600, grid_x: 480486 }, + { grid_y: 121114, count: 7600, grid_x: 480491 }, + { grid_y: 121114, count: 3800, grid_x: 480496 }, + { grid_y: 121114, count: 7600, grid_x: 480497 }, + { grid_y: 121114, count: 7600, grid_x: 480498 }, + { grid_y: 121114, count: 7600, grid_x: 480500 }, + { grid_y: 121114, count: 11400, grid_x: 480501 }, + { grid_y: 121114, count: 3800, grid_x: 480502 }, + { grid_y: 121114, count: 3800, grid_x: 480507 }, + { grid_y: 121114, count: 7600, grid_x: 480508 }, + { grid_y: 121114, count: 7600, grid_x: 480510 }, + { grid_y: 121114, count: 3800, grid_x: 480511 }, + { grid_y: 121114, count: 7600, grid_x: 480515 }, + { grid_y: 121114, count: 3800, grid_x: 480524 }, + { grid_y: 121114, count: 3800, grid_x: 480533 }, + { grid_y: 121115, count: 3800, grid_x: 480460 }, + { grid_y: 121115, count: 3800, grid_x: 480468 }, + { grid_y: 121115, count: 3800, grid_x: 480470 }, + { grid_y: 121115, count: 3800, grid_x: 480471 }, + { grid_y: 121115, count: 7600, grid_x: 480483 }, + { grid_y: 121115, count: 7600, grid_x: 480484 }, + { grid_y: 121115, count: 11400, grid_x: 480485 }, + { grid_y: 121115, count: 3800, grid_x: 480486 }, + { grid_y: 121115, count: 3800, grid_x: 480491 }, + { grid_y: 121115, count: 3800, grid_x: 480494 }, + { grid_y: 121115, count: 7600, grid_x: 480496 }, + { grid_y: 121115, count: 3800, grid_x: 480499 }, + { grid_y: 121115, count: 7600, grid_x: 480501 }, + { grid_y: 121115, count: 3800, grid_x: 480507 }, + { grid_y: 121115, count: 3800, grid_x: 480511 }, + { grid_y: 121115, count: 7600, grid_x: 480515 }, + { grid_y: 121115, count: 11400, grid_x: 480516 }, + { grid_y: 121115, count: 3800, grid_x: 480517 }, + { grid_y: 121115, count: 3800, grid_x: 480527 }, + { grid_y: 121115, count: 3800, grid_x: 480528 }, + { grid_y: 121116, count: 3800, grid_x: 480465 }, + { grid_y: 121116, count: 7600, grid_x: 480468 }, + { grid_y: 121116, count: 3800, grid_x: 480471 }, + { grid_y: 121116, count: 3800, grid_x: 480476 }, + { grid_y: 121116, count: 7600, grid_x: 480478 }, + { grid_y: 121116, count: 7600, grid_x: 480479 }, + { grid_y: 121116, count: 3800, grid_x: 480480 }, + { grid_y: 121116, count: 3800, grid_x: 480482 }, + { grid_y: 121116, count: 7600, grid_x: 480483 }, + { grid_y: 121116, count: 11400, grid_x: 480484 }, + { grid_y: 121116, count: 11400, grid_x: 480485 }, + { grid_y: 121116, count: 7600, grid_x: 480487 }, + { grid_y: 121116, count: 3800, grid_x: 480489 }, + { grid_y: 121116, count: 3800, grid_x: 480491 }, + { grid_y: 121116, count: 3800, grid_x: 480492 }, + { grid_y: 121116, count: 3800, grid_x: 480493 }, + { grid_y: 121116, count: 3800, grid_x: 480494 }, + { grid_y: 121116, count: 3800, grid_x: 480501 }, + { grid_y: 121116, count: 3800, grid_x: 480502 }, + { grid_y: 121116, count: 3800, grid_x: 480503 }, + { grid_y: 121116, count: 3800, grid_x: 480507 }, + { grid_y: 121116, count: 3800, grid_x: 480509 }, + { grid_y: 121116, count: 3800, grid_x: 480510 }, + { grid_y: 121116, count: 3800, grid_x: 480512 }, + { grid_y: 121116, count: 7600, grid_x: 480515 }, + { grid_y: 121116, count: 15200, grid_x: 480516 }, + { grid_y: 121116, count: 3800, grid_x: 480533 }, + { grid_y: 121117, count: 3800, grid_x: 480459 }, + { grid_y: 121117, count: 3800, grid_x: 480468 }, + { grid_y: 121117, count: 3800, grid_x: 480470 }, + { grid_y: 121117, count: 3800, grid_x: 480477 }, + { grid_y: 121117, count: 3800, grid_x: 480478 }, + { grid_y: 121117, count: 3800, grid_x: 480480 }, + { grid_y: 121117, count: 3800, grid_x: 480482 }, + { grid_y: 121117, count: 7600, grid_x: 480483 }, + { grid_y: 121117, count: 7600, grid_x: 480484 }, + { grid_y: 121117, count: 11400, grid_x: 480485 }, + { grid_y: 121117, count: 7600, grid_x: 480486 }, + { grid_y: 121117, count: 7600, grid_x: 480487 }, + { grid_y: 121117, count: 11400, grid_x: 480488 }, + { grid_y: 121117, count: 7600, grid_x: 480495 }, + { grid_y: 121117, count: 3800, grid_x: 480496 }, + { grid_y: 121117, count: 3800, grid_x: 480497 }, + { grid_y: 121117, count: 3800, grid_x: 480509 }, + { grid_y: 121117, count: 3800, grid_x: 480510 }, + { grid_y: 121117, count: 3800, grid_x: 480516 }, + { grid_y: 121117, count: 3800, grid_x: 480520 }, + { grid_y: 121117, count: 7600, grid_x: 480526 }, + { grid_y: 121117, count: 3800, grid_x: 480528 }, + { grid_y: 121117, count: 3800, grid_x: 480533 }, + { grid_y: 121118, count: 3800, grid_x: 480459 }, + { grid_y: 121118, count: 3800, grid_x: 480460 }, + { grid_y: 121118, count: 3800, grid_x: 480478 }, + { grid_y: 121118, count: 3800, grid_x: 480481 }, + { grid_y: 121118, count: 3800, grid_x: 480482 }, + { grid_y: 121118, count: 7600, grid_x: 480483 }, + { grid_y: 121118, count: 7600, grid_x: 480484 }, + { grid_y: 121118, count: 3800, grid_x: 480486 }, + { grid_y: 121118, count: 7600, grid_x: 480487 }, + { grid_y: 121118, count: 7600, grid_x: 480488 }, + { grid_y: 121118, count: 7600, grid_x: 480514 }, + { grid_y: 121118, count: 3800, grid_x: 480516 }, + { grid_y: 121118, count: 3800, grid_x: 480517 }, + { grid_y: 121118, count: 3800, grid_x: 480518 }, + { grid_y: 121118, count: 3800, grid_x: 480521 }, + { grid_y: 121118, count: 3800, grid_x: 480528 }, + { grid_y: 121118, count: 3800, grid_x: 480533 }, + { grid_y: 121119, count: 3800, grid_x: 480467 }, + { grid_y: 121119, count: 3800, grid_x: 480469 }, + { grid_y: 121119, count: 3800, grid_x: 480478 }, + { grid_y: 121119, count: 3800, grid_x: 480479 }, + { grid_y: 121119, count: 3800, grid_x: 480483 }, + { grid_y: 121119, count: 3800, grid_x: 480485 }, + { grid_y: 121119, count: 7600, grid_x: 480486 }, + { grid_y: 121119, count: 7600, grid_x: 480487 }, + { grid_y: 121119, count: 3800, grid_x: 480514 }, + { grid_y: 121119, count: 3800, grid_x: 480518 }, + { grid_y: 121119, count: 3800, grid_x: 480526 }, + { grid_y: 121120, count: 3800, grid_x: 480466 }, + { grid_y: 121120, count: 3800, grid_x: 480468 }, + { grid_y: 121120, count: 3800, grid_x: 480479 }, + { grid_y: 121120, count: 3800, grid_x: 480480 }, + { grid_y: 121120, count: 3800, grid_x: 480483 }, + { grid_y: 121120, count: 3800, grid_x: 480484 }, + { grid_y: 121120, count: 3800, grid_x: 480485 }, + { grid_y: 121120, count: 7600, grid_x: 480486 }, + { grid_y: 121120, count: 3800, grid_x: 480491 }, + { grid_y: 121120, count: 3800, grid_x: 480497 }, + { grid_y: 121120, count: 3800, grid_x: 480509 }, + { grid_y: 121120, count: 3800, grid_x: 480515 }, + { grid_y: 121120, count: 3800, grid_x: 480518 }, + { grid_y: 121120, count: 3800, grid_x: 480526 }, + { grid_y: 121121, count: 3800, grid_x: 480472 }, + { grid_y: 121121, count: 3800, grid_x: 480473 }, + { grid_y: 121121, count: 7600, grid_x: 480480 }, + { grid_y: 121121, count: 3800, grid_x: 480481 }, + { grid_y: 121121, count: 7600, grid_x: 480483 }, + { grid_y: 121121, count: 7600, grid_x: 480484 }, + { grid_y: 121121, count: 7600, grid_x: 480485 }, + { grid_y: 121121, count: 7600, grid_x: 480486 }, + { grid_y: 121121, count: 3800, grid_x: 480495 }, + { grid_y: 121122, count: 3800, grid_x: 480474 }, + { grid_y: 121122, count: 3800, grid_x: 480479 }, + { grid_y: 121122, count: 3800, grid_x: 480481 }, + { grid_y: 121122, count: 3800, grid_x: 480483 }, + { grid_y: 121122, count: 7600, grid_x: 480484 }, + { grid_y: 121122, count: 3800, grid_x: 480485 }, + { grid_y: 121122, count: 7600, grid_x: 480491 }, + { grid_y: 121122, count: 7600, grid_x: 480492 }, + { grid_y: 121122, count: 7600, grid_x: 480493 }, + { grid_y: 121122, count: 3800, grid_x: 480494 }, + { grid_y: 121122, count: 7600, grid_x: 480495 }, + { grid_y: 121122, count: 3800, grid_x: 480510 }, + { grid_y: 121122, count: 3800, grid_x: 480517 }, + { grid_y: 121123, count: 7600, grid_x: 480469 }, + { grid_y: 121123, count: 7600, grid_x: 480477 }, + { grid_y: 121123, count: 3800, grid_x: 480478 }, + { grid_y: 121123, count: 3800, grid_x: 480479 }, + { grid_y: 121123, count: 11400, grid_x: 480481 }, + { grid_y: 121123, count: 7600, grid_x: 480482 }, + { grid_y: 121123, count: 7600, grid_x: 480484 }, + { grid_y: 121123, count: 7600, grid_x: 480485 }, + { grid_y: 121123, count: 3800, grid_x: 480486 }, + { grid_y: 121123, count: 3800, grid_x: 480491 }, + { grid_y: 121123, count: 3800, grid_x: 480492 }, + { grid_y: 121123, count: 3800, grid_x: 480493 }, + { grid_y: 121123, count: 7600, grid_x: 480495 }, + { grid_y: 121123, count: 3800, grid_x: 480509 }, + { grid_y: 121123, count: 3800, grid_x: 480517 }, + { grid_y: 121123, count: 7600, grid_x: 480518 }, + { grid_y: 121124, count: 3800, grid_x: 480469 }, + { grid_y: 121124, count: 3800, grid_x: 480474 }, + { grid_y: 121124, count: 3800, grid_x: 480476 }, + { grid_y: 121124, count: 3800, grid_x: 480478 }, + { grid_y: 121124, count: 3800, grid_x: 480480 }, + { grid_y: 121124, count: 3800, grid_x: 480481 }, + { grid_y: 121124, count: 3800, grid_x: 480483 }, + { grid_y: 121124, count: 3800, grid_x: 480485 }, + { grid_y: 121124, count: 3800, grid_x: 480487 }, + { grid_y: 121124, count: 3800, grid_x: 480493 }, + { grid_y: 121124, count: 3800, grid_x: 480505 }, + { grid_y: 121124, count: 3800, grid_x: 480530 }, + { grid_y: 121125, count: 3800, grid_x: 480466 }, + { grid_y: 121125, count: 3800, grid_x: 480472 }, + { grid_y: 121125, count: 3800, grid_x: 480477 }, + { grid_y: 121125, count: 3800, grid_x: 480478 }, + { grid_y: 121125, count: 7600, grid_x: 480479 }, + { grid_y: 121125, count: 3800, grid_x: 480480 }, + { grid_y: 121125, count: 3800, grid_x: 480483 }, + { grid_y: 121125, count: 3800, grid_x: 480484 }, + { grid_y: 121125, count: 7600, grid_x: 480488 }, + { grid_y: 121125, count: 3800, grid_x: 480496 }, + { grid_y: 121125, count: 3800, grid_x: 480497 }, + { grid_y: 121125, count: 3800, grid_x: 480509 }, + { grid_y: 121126, count: 3800, grid_x: 480459 }, + { grid_y: 121126, count: 3800, grid_x: 480469 }, + { grid_y: 121126, count: 7600, grid_x: 480470 }, + { grid_y: 121126, count: 7600, grid_x: 480472 }, + { grid_y: 121126, count: 3800, grid_x: 480474 }, + { grid_y: 121126, count: 7600, grid_x: 480478 }, + { grid_y: 121126, count: 3800, grid_x: 480479 }, + { grid_y: 121126, count: 15200, grid_x: 480480 }, + { grid_y: 121126, count: 15200, grid_x: 480483 }, + { grid_y: 121126, count: 7600, grid_x: 480485 }, + { grid_y: 121126, count: 3800, grid_x: 480486 }, + { grid_y: 121126, count: 3800, grid_x: 480489 }, + { grid_y: 121126, count: 3800, grid_x: 480517 }, + { grid_y: 121126, count: 3800, grid_x: 480529 }, + { grid_y: 121127, count: 3800, grid_x: 480460 }, + { grid_y: 121127, count: 7600, grid_x: 480465 }, + { grid_y: 121127, count: 3800, grid_x: 480468 }, + { grid_y: 121127, count: 3800, grid_x: 480470 }, + { grid_y: 121127, count: 11400, grid_x: 480472 }, + { grid_y: 121127, count: 7600, grid_x: 480473 }, + { grid_y: 121127, count: 3800, grid_x: 480477 }, + { grid_y: 121127, count: 3800, grid_x: 480478 }, + { grid_y: 121127, count: 15200, grid_x: 480479 }, + { grid_y: 121127, count: 11400, grid_x: 480480 }, + { grid_y: 121127, count: 3800, grid_x: 480482 }, + { grid_y: 121127, count: 38000, grid_x: 480483 }, + { grid_y: 121127, count: 3800, grid_x: 480484 }, + { grid_y: 121127, count: 3800, grid_x: 480486 }, + { grid_y: 121127, count: 3800, grid_x: 480487 }, + { grid_y: 121127, count: 3800, grid_x: 480488 }, + { grid_y: 121127, count: 3800, grid_x: 480493 }, + { grid_y: 121127, count: 3800, grid_x: 480496 }, + { grid_y: 121127, count: 3800, grid_x: 480515 }, + { grid_y: 121127, count: 3800, grid_x: 480517 }, + { grid_y: 121127, count: 3800, grid_x: 480519 }, + { grid_y: 121127, count: 3800, grid_x: 480522 }, + { grid_y: 121128, count: 3800, grid_x: 480459 }, + { grid_y: 121128, count: 3800, grid_x: 480463 }, + { grid_y: 121128, count: 3800, grid_x: 480465 }, + { grid_y: 121128, count: 3800, grid_x: 480467 }, + { grid_y: 121128, count: 3800, grid_x: 480469 }, + { grid_y: 121128, count: 11400, grid_x: 480470 }, + { grid_y: 121128, count: 3800, grid_x: 480471 }, + { grid_y: 121128, count: 3800, grid_x: 480472 }, + { grid_y: 121128, count: 3800, grid_x: 480473 }, + { grid_y: 121128, count: 3800, grid_x: 480474 }, + { grid_y: 121128, count: 7600, grid_x: 480475 }, + { grid_y: 121128, count: 3800, grid_x: 480476 }, + { grid_y: 121128, count: 3800, grid_x: 480483 }, + { grid_y: 121128, count: 7600, grid_x: 480484 }, + { grid_y: 121128, count: 11400, grid_x: 480486 }, + { grid_y: 121128, count: 11400, grid_x: 480487 }, + { grid_y: 121128, count: 3800, grid_x: 480488 }, + { grid_y: 121128, count: 3800, grid_x: 480490 }, + { grid_y: 121128, count: 3800, grid_x: 480495 }, + { grid_y: 121128, count: 11400, grid_x: 480496 }, + { grid_y: 121128, count: 7600, grid_x: 480498 }, + { grid_y: 121128, count: 7600, grid_x: 480499 }, + { grid_y: 121128, count: 3800, grid_x: 480507 }, + { grid_y: 121128, count: 3800, grid_x: 480509 }, + { grid_y: 121128, count: 3800, grid_x: 480515 }, + { grid_y: 121128, count: 3800, grid_x: 480517 }, + { grid_y: 121128, count: 3800, grid_x: 480523 }, + { grid_y: 121128, count: 3800, grid_x: 480531 }, + { grid_y: 121129, count: 3800, grid_x: 480467 }, + { grid_y: 121129, count: 3800, grid_x: 480468 }, + { grid_y: 121129, count: 7600, grid_x: 480469 }, + { grid_y: 121129, count: 3800, grid_x: 480470 }, + { grid_y: 121129, count: 7600, grid_x: 480471 }, + { grid_y: 121129, count: 30400, grid_x: 480472 }, + { grid_y: 121129, count: 7600, grid_x: 480473 }, + { grid_y: 121129, count: 3800, grid_x: 480479 }, + { grid_y: 121129, count: 7600, grid_x: 480480 }, + { grid_y: 121129, count: 7600, grid_x: 480481 }, + { grid_y: 121129, count: 3800, grid_x: 480482 }, + { grid_y: 121129, count: 3800, grid_x: 480483 }, + { grid_y: 121129, count: 3800, grid_x: 480486 }, + { grid_y: 121129, count: 3800, grid_x: 480487 }, + { grid_y: 121129, count: 3800, grid_x: 480490 }, + { grid_y: 121129, count: 3800, grid_x: 480492 }, + { grid_y: 121129, count: 3800, grid_x: 480493 }, + { grid_y: 121129, count: 3800, grid_x: 480494 }, + { grid_y: 121129, count: 3800, grid_x: 480498 }, + { grid_y: 121129, count: 7600, grid_x: 480500 }, + { grid_y: 121129, count: 3800, grid_x: 480502 }, + { grid_y: 121129, count: 7600, grid_x: 480511 }, + { grid_y: 121129, count: 7600, grid_x: 480514 }, + { grid_y: 121129, count: 7600, grid_x: 480518 }, + { grid_y: 121130, count: 3800, grid_x: 480468 }, + { grid_y: 121130, count: 7600, grid_x: 480470 }, + { grid_y: 121130, count: 7600, grid_x: 480471 }, + { grid_y: 121130, count: 7600, grid_x: 480472 }, + { grid_y: 121130, count: 3800, grid_x: 480476 }, + { grid_y: 121130, count: 3800, grid_x: 480477 }, + { grid_y: 121130, count: 7600, grid_x: 480481 }, + { grid_y: 121130, count: 3800, grid_x: 480482 }, + { grid_y: 121130, count: 3800, grid_x: 480485 }, + { grid_y: 121130, count: 3800, grid_x: 480492 }, + { grid_y: 121130, count: 7600, grid_x: 480494 }, + { grid_y: 121130, count: 3800, grid_x: 480497 }, + { grid_y: 121130, count: 3800, grid_x: 480498 }, + { grid_y: 121130, count: 3800, grid_x: 480500 }, + { grid_y: 121130, count: 3800, grid_x: 480503 }, + { grid_y: 121130, count: 3800, grid_x: 480506 }, + { grid_y: 121130, count: 7600, grid_x: 480507 }, + { grid_y: 121130, count: 3800, grid_x: 480509 }, + { grid_y: 121130, count: 7600, grid_x: 480510 }, + { grid_y: 121130, count: 3800, grid_x: 480511 }, + { grid_y: 121130, count: 7600, grid_x: 480514 }, + { grid_y: 121130, count: 3800, grid_x: 480527 }, + { grid_y: 121130, count: 3800, grid_x: 480530 }, + { grid_y: 121131, count: 3800, grid_x: 480459 }, + { grid_y: 121131, count: 3800, grid_x: 480468 }, + { grid_y: 121131, count: 3800, grid_x: 480471 }, + { grid_y: 121131, count: 3800, grid_x: 480478 }, + { grid_y: 121131, count: 3800, grid_x: 480485 }, + { grid_y: 121131, count: 3800, grid_x: 480486 }, + { grid_y: 121131, count: 3800, grid_x: 480489 }, + { grid_y: 121131, count: 3800, grid_x: 480490 }, + { grid_y: 121131, count: 7600, grid_x: 480499 }, + { grid_y: 121131, count: 3800, grid_x: 480507 }, + { grid_y: 121131, count: 3800, grid_x: 480508 }, + { grid_y: 121131, count: 3800, grid_x: 480509 }, + { grid_y: 121131, count: 19000, grid_x: 480515 }, + { grid_y: 121131, count: 7600, grid_x: 480516 }, + { grid_y: 121131, count: 7600, grid_x: 480517 }, + { grid_y: 121131, count: 3800, grid_x: 480526 }, + { grid_y: 121131, count: 3800, grid_x: 480529 }, + { grid_y: 121131, count: 3800, grid_x: 480533 }, + { grid_y: 121132, count: 7600, grid_x: 480469 }, + { grid_y: 121132, count: 3800, grid_x: 480470 }, + { grid_y: 121132, count: 3800, grid_x: 480472 }, + { grid_y: 121132, count: 3800, grid_x: 480474 }, + { grid_y: 121132, count: 3800, grid_x: 480479 }, + { grid_y: 121132, count: 3800, grid_x: 480480 }, + { grid_y: 121132, count: 3800, grid_x: 480489 }, + { grid_y: 121132, count: 3800, grid_x: 480495 }, + { grid_y: 121132, count: 3800, grid_x: 480497 }, + { grid_y: 121132, count: 3800, grid_x: 480499 }, + { grid_y: 121132, count: 3800, grid_x: 480503 }, + { grid_y: 121132, count: 3800, grid_x: 480508 }, + { grid_y: 121132, count: 3800, grid_x: 480519 }, + { grid_y: 121133, count: 3800, grid_x: 480464 }, + { grid_y: 121133, count: 3800, grid_x: 480466 }, + { grid_y: 121133, count: 3800, grid_x: 480477 }, + { grid_y: 121133, count: 3800, grid_x: 480478 }, + { grid_y: 121133, count: 3800, grid_x: 480482 }, + { grid_y: 121133, count: 3800, grid_x: 480490 }, + { grid_y: 121133, count: 3800, grid_x: 480491 }, + { grid_y: 121133, count: 7600, grid_x: 480497 }, + { grid_y: 121133, count: 3800, grid_x: 480498 }, + { grid_y: 121133, count: 3800, grid_x: 480499 }, + { grid_y: 121133, count: 3800, grid_x: 480502 }, + { grid_y: 121133, count: 3800, grid_x: 480516 }, + { grid_y: 121133, count: 3800, grid_x: 480519 }, + { grid_y: 121133, count: 3800, grid_x: 480520 }, + { grid_y: 121134, count: 3800, grid_x: 480468 }, + { grid_y: 121134, count: 7600, grid_x: 480477 }, + { grid_y: 121134, count: 3800, grid_x: 480481 }, + { grid_y: 121134, count: 7600, grid_x: 480482 }, + { grid_y: 121134, count: 3800, grid_x: 480484 }, + { grid_y: 121134, count: 3800, grid_x: 480485 }, + { grid_y: 121134, count: 3800, grid_x: 480493 }, + { grid_y: 121134, count: 3800, grid_x: 480501 }, + { grid_y: 121134, count: 3800, grid_x: 480508 }, + { grid_y: 121134, count: 3800, grid_x: 480514 }, + { grid_y: 121134, count: 3800, grid_x: 480516 }, + { grid_y: 121134, count: 3800, grid_x: 480519 }, + { grid_y: 121134, count: 3800, grid_x: 480520 }, + { grid_y: 121134, count: 3800, grid_x: 480526 }, + { grid_y: 121134, count: 3800, grid_x: 480527 }, + { grid_y: 121135, count: 3800, grid_x: 480460 }, + { grid_y: 121135, count: 3800, grid_x: 480477 }, + { grid_y: 121135, count: 3800, grid_x: 480481 }, + { grid_y: 121135, count: 7600, grid_x: 480482 }, + { grid_y: 121135, count: 11400, grid_x: 480483 }, + { grid_y: 121135, count: 7600, grid_x: 480484 }, + { grid_y: 121135, count: 3800, grid_x: 480486 }, + { grid_y: 121135, count: 3800, grid_x: 480489 }, + { grid_y: 121135, count: 3800, grid_x: 480493 }, + { grid_y: 121135, count: 3800, grid_x: 480503 }, + { grid_y: 121135, count: 3800, grid_x: 480510 }, + { grid_y: 121135, count: 3800, grid_x: 480529 }, + { grid_y: 121135, count: 3800, grid_x: 480533 } +]; diff --git a/test/unit/source/transfrom/hexagon.js b/test/unit/source/transfrom/hexagon.js new file mode 100644 index 0000000000..b0877e7b80 --- /dev/null +++ b/test/unit/source/transfrom/hexagon.js @@ -0,0 +1,21 @@ +import { expect } from 'chai'; +import { pointData } from '../../../asset/data/point'; +import { pointToHexbin } from '../../../../src/source/transform/hexagon'; +describe('hexagon Test', function() { + + it('pointToHexbin', function() { + const dataArray = pointData.map(item => { + const lng = 1e-6 * (250 * item.grid_x + 125), + lat = 1e-6 * (250 * item.grid_y + 125); + return { + v: item.count * 1, + coordinates: [ lng, lat ] + }; + }); + + const data = { + dataArray + }; + const hexgonGrid = pointToHexbin(data, { size: 100, field: 'count', method: 'sum' }); + }); +}); From 5d2b6902f64c04bd44e2ade8bf7244d8181bb19d Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 26 Feb 2019 16:40:15 +0800 Subject: [PATCH 14/16] fix(pick): event --- src/core/engine/picking/picking.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js index e4fb4c2ee1..24790e82a1 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; From 374554037c764867d63f31bbbcb22ec522d14c51 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 26 Feb 2019 19:32:09 +0800 Subject: [PATCH 15/16] fix(transform): stattistics --- .torch.compile.opts.js | 3 +- src/source/transform/hexagon.js | 3 + src/source/transform/statistics.js | 84 ++++++++++++++++++++++++--- test/unit/source/transfrom/hexagon.js | 4 +- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/.torch.compile.opts.js b/.torch.compile.opts.js index b65d4cd02f..c2e828ddc9 100755 --- a/.torch.compile.opts.js +++ b/.torch.compile.opts.js @@ -10,7 +10,8 @@ module.exports = { include: [ 'src/**/*.js', 'test/**/*.js', - 'node_modules/three/**/*.js' + 'node_modules/three/**/*.js', + 'node_modules/simple-statistics/src/*.js' ], exclude: [ 'node_modules/@babel/**/*.js' diff --git a/src/source/transform/hexagon.js b/src/source/transform/hexagon.js index df796c7450..f0aa9692f1 100644 --- a/src/source/transform/hexagon.js +++ b/src/source/transform/hexagon.js @@ -27,7 +27,10 @@ export function pointToHexbin(data, option) { const columns = getColumn(hex, option.field); hex[option.method] = statistics[option.method](columns); } + const item = {}; + item[option.method] = hex[option.method]; return { + ...item, coordinates: unProjectFlat([ hex.x, hex.y ]), id: index + 1 }; diff --git a/src/source/transform/statistics.js b/src/source/transform/statistics.js index 2a7a317846..de599d2d41 100644 --- a/src/source/transform/statistics.js +++ b/src/source/transform/statistics.js @@ -1,10 +1,76 @@ -/* 支持 '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'; +function max(x) { + if (x.length === 0) { + throw new Error('max requires at least one data point'); + } + let value = x[0]; + for (let i = 1; i < x.length; i++) { + // On the first iteration of this loop, max is + // undefined and is thus made the maximum element in the array + if (x[i] > value) { + value = x[i]; + } + } + return value; +} + +function min(x) { + if (x.length === 0) { + throw new Error('min requires at least one data point'); + } + + let value = x[0]; + for (let i = 1; i < x.length; i++) { + // On the first iteration of this loop, min is + // undefined and is thus made the minimum element in the array + if (x[i] < value) { + value = x[i]; + } + } + return value; +} + +function sum(x) { + // If the array is empty, we needn't bother computing its sum + if (x.length === 0) { + return 0; + } + + // Initializing the sum as the first number in the array + let sum = x[0]; + + // Keeping track of the floating-point error correction + let correction = 0; + + let transition; + + for (let i = 1; i < x.length; i++) { + transition = sum + x[i]; + + // Here we need to update the correction in a different fashion + // if the new absolute value is greater than the absolute sum + if (Math.abs(sum) >= Math.abs(x[i])) { + correction += sum - transition + x[i]; + } else { + correction += x[i] - transition + sum; + } + + sum = transition; + } + + // Returning the corrected sum + return sum + correction; +} +function mean(x) { + if (x.length === 0) { + throw new Error('mean requires at least one data point'); + } + return sum(x) / x.length; +} + +export { + sum, + max, + min, + mean +}; diff --git a/test/unit/source/transfrom/hexagon.js b/test/unit/source/transfrom/hexagon.js index b0877e7b80..aad4edb018 100644 --- a/test/unit/source/transfrom/hexagon.js +++ b/test/unit/source/transfrom/hexagon.js @@ -16,6 +16,8 @@ describe('hexagon Test', function() { const data = { dataArray }; - const hexgonGrid = pointToHexbin(data, { size: 100, field: 'count', method: 'sum' }); + const hexgonGrid = pointToHexbin(data, { size: 100, field: 'v', method: 'sum' }); + expect(hexgonGrid.dataArray.length).eql(567); + console.log(hexgonGrid); }); }); From 00d58a03c5dfa92c5812c2b94fca4831694ceff6 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Wed, 27 Feb 2019 15:33:38 +0800 Subject: [PATCH 16/16] feat(hexagon): hexagon heatmap --- .torch.compile.opts.js | 3 +- demos/hexgon.html | 76 ++++++++++++++++++++++++ package.json | 4 +- src/core/three.js | 2 +- src/geom/buffer/heatmap/hexagon.js | 32 ++++++++++ src/geom/material/hexagon.js | 31 ++++++++++ src/geom/shader/hexagon_frag.glsl | 8 +++ src/geom/shader/hexagon_vert.glsl | 17 ++++++ src/geom/shader/point_vert.glsl | 1 - src/geom/shader/polygon_vert.glsl | 1 - src/layer/heatmap.js | 27 +++++++++ src/layer/render/heatmap/hexagon.js | 21 +++++++ src/source/index.js | 2 + src/source/transform/grid.js | 2 +- src/source/transform/hexagon.js | 5 +- test/unit/geom/buffer/heatmap/hexagon.js | 35 +++++++++++ test/unit/shader-module/base-spec.js | 3 +- test/unit/source/transfrom/hexagon.js | 1 - webpack.config.js | 3 +- 19 files changed, 260 insertions(+), 14 deletions(-) create mode 100644 demos/hexgon.html create mode 100644 src/geom/buffer/heatmap/hexagon.js create mode 100644 src/geom/material/hexagon.js create mode 100644 src/geom/shader/hexagon_frag.glsl create mode 100644 src/geom/shader/hexagon_vert.glsl create mode 100644 src/layer/render/heatmap/hexagon.js create mode 100644 test/unit/geom/buffer/heatmap/hexagon.js diff --git a/.torch.compile.opts.js b/.torch.compile.opts.js index c2e828ddc9..cea3ac8770 100755 --- a/.torch.compile.opts.js +++ b/.torch.compile.opts.js @@ -1,5 +1,4 @@ const path = require('path'); - module.exports = { babelrc: { presets: [ @@ -10,7 +9,7 @@ module.exports = { include: [ 'src/**/*.js', 'test/**/*.js', - 'node_modules/three/**/*.js', + 'node_modules/_three@0.96.0@three/**/*.js', 'node_modules/simple-statistics/src/*.js' ], exclude: [ diff --git a/demos/hexgon.html b/demos/hexgon.html new file mode 100644 index 0000000000..ce5ed92af9 --- /dev/null +++ b/demos/hexgon.html @@ -0,0 +1,76 @@ + + + + + + + + + point_circle + + + + +
+ + + + + + + + diff --git a/package.json b/package.json index 01f457cb7e..e992b41020 100755 --- a/package.json +++ b/package.json @@ -78,11 +78,11 @@ "prepublishOnly": "npm run build-lib && npm run dist", "screenshot": "node ./bin/screenshot.js", "start": "npm run dev", - "test": "torch --compile --renderer --recursive test/unit", + "test": "torch --compile-opts ./.torch.compile.opts.js --compile --renderer --recursive test/unit", "test-all": "npm run test && npm run test-bugs", "test-bugs": "torch --compile --renderer --recursive test/bugs", "test-bugs-live": "torch --compile --interactive --watch --recursive test/bugs", - "test-live": "torch --compile --interactive --watch --recursive test/unit", + "test-live": "torch --compile --interactive --watch --recursive test/unit", "watch": "webpack --config webpack-dev.config.js", "win-dev": "node ./bin/win-dev.js" }, diff --git a/src/core/three.js b/src/core/three.js index 03359e840d..1658e39038 100644 --- a/src/core/three.js +++ b/src/core/three.js @@ -35,4 +35,4 @@ export { BufferAttribute } from 'three/src/core/BufferAttribute.js'; -// export * from '../../build/Three.js'; +// export * from '../../build/three.js'; diff --git a/src/geom/buffer/heatmap/hexagon.js b/src/geom/buffer/heatmap/hexagon.js new file mode 100644 index 0000000000..1d30f66807 --- /dev/null +++ b/src/geom/buffer/heatmap/hexagon.js @@ -0,0 +1,32 @@ +import { polygonPath } from '../../shape/path'; +import { fill } from '../../shape/polygon'; +export default function hexagonBuffer(layerData) { + const attribute = { + vertices: [], + miter: [], + colors: [], + pickingIds: [] + }; + const a = Math.cos(Math.PI / 6); + const points = [ + [ 0, -1, 0 ], + [ -a, -0.5, 0 ], + [ -a, 0.5, 0 ], + [ 0, 1, 0 ], + [ a, 0.5, 0 ], + [ a, -0.5, 0 ], + [ 0, -1, 0 ] + ]; + // const hexgonPoints = polygonPath(6); + const hexgonFill = fill([ points ]); + const { positionsIndex, positions } = hexgonFill; + layerData.forEach(element => { + positionsIndex.forEach(pointIndex => { + attribute.vertices.push(...element.coordinates); + attribute.miter.push(positions[pointIndex][0], positions[pointIndex][1]); + attribute.pickingIds.push(element.id); + attribute.colors.push(...element.color); + }); + }); + return attribute; +} diff --git a/src/geom/material/hexagon.js b/src/geom/material/hexagon.js new file mode 100644 index 0000000000..4b2e0896c8 --- /dev/null +++ b/src/geom/material/hexagon.js @@ -0,0 +1,31 @@ +import grid_frag from '../shader/hexagon_frag.glsl'; +import grid_vert from '../shader/hexagon_vert.glsl'; +import Material from './material'; + + +export default class hexagonMaterial extends Material { + getDefaultParameters() { + return { + uniforms: { + u_opacity: { value: 1.0 }, + u_time: { value: 0 }, + u_radius: { value: 0.01 }, + u_angle: { 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 = 'hexagonMaterial'; + this.defines = Object.assign(defines, _defines); + this.vertexShader = grid_vert; + this.fragmentShader = grid_frag; + this.transparent = true; + } +} diff --git a/src/geom/shader/hexagon_frag.glsl b/src/geom/shader/hexagon_frag.glsl new file mode 100644 index 0000000000..042dde511e --- /dev/null +++ b/src/geom/shader/hexagon_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/hexagon_vert.glsl b/src/geom/shader/hexagon_vert.glsl new file mode 100644 index 0000000000..30268d4861 --- /dev/null +++ b/src/geom/shader/hexagon_vert.glsl @@ -0,0 +1,17 @@ +precision highp float; +attribute vec2 miter; +attribute vec4 a_color; +uniform float u_radius; +uniform float u_coverage; +uniform float u_angle; +varying vec4 v_color; + +void main() { + mat4 matModelViewProjection = projectionMatrix * modelViewMatrix; + mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle)); + v_color = a_color; + vec2 offset =vec2(rotationMatrix * miter * u_radius * u_coverage ); + float x = position.x + offset.x; + float y = position.y + offset.y; + gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0); +} \ No newline at end of file diff --git a/src/geom/shader/point_vert.glsl b/src/geom/shader/point_vert.glsl index 55b7d76a76..a39283badf 100644 --- a/src/geom/shader/point_vert.glsl +++ b/src/geom/shader/point_vert.glsl @@ -2,7 +2,6 @@ precision highp float; attribute vec4 a_color; attribute float a_size; attribute float a_shape; -attribute vec4 a_idColor; uniform vec4 u_stroke; uniform float u_strokeWidth; uniform float u_opacity; diff --git a/src/geom/shader/polygon_vert.glsl b/src/geom/shader/polygon_vert.glsl index eba0b62d02..5ae3a3c2a1 100644 --- a/src/geom/shader/polygon_vert.glsl +++ b/src/geom/shader/polygon_vert.glsl @@ -3,7 +3,6 @@ precision highp float; #define diffuseRatio 0.4 #define specularRatio 0.1 attribute vec4 a_color; -attribute vec4 a_idColor; attribute vec2 faceUv; attribute vec3 a_shape; attribute vec3 a_size; diff --git a/src/layer/heatmap.js b/src/layer/heatmap.js index f9971a55da..3b23ad98da 100644 --- a/src/layer/heatmap.js +++ b/src/layer/heatmap.js @@ -1,6 +1,8 @@ import Layer from '../core/layer'; import gridBuffer from '../geom/buffer/heatmap/grid'; import DrawGrid from './render/heatmap/gird'; +import DrawHexagon from './render/heatmap/hexagon'; +import hexagonBuffer from '../geom/buffer/heatmap/hexagon'; export default class HeatMapLayer extends Layer { shape(type) { @@ -13,6 +15,30 @@ export default class HeatMapLayer extends Layer { } _prepareRender() { this.init(); + switch (this.shapeType) { + case 'grid' : + this._drawGrid(); + break; + case 'hexagon' : + this._drawHexagon(); + break; + default: + this._drawGrid(); + } + } + _drawHexagon() { + const style = this.get('styleOptions'); + const { radius } = this.layerSource.data; + this._buffer = new hexagonBuffer(this.layerData); + const config = { + ...style, + radius + }; + const Mesh = new DrawHexagon(this._buffer, config); + this.add(Mesh); + + } + _drawGrid() { this.type = 'heatmap'; const style = this.get('styleOptions'); const { xOffset, yOffset } = this.layerSource.data; @@ -25,4 +51,5 @@ export default class HeatMapLayer extends Layer { const girdMesh = new DrawGrid(this._buffer, config); this.add(girdMesh); } + } diff --git a/src/layer/render/heatmap/hexagon.js b/src/layer/render/heatmap/hexagon.js new file mode 100644 index 0000000000..04b7580cbd --- /dev/null +++ b/src/layer/render/heatmap/hexagon.js @@ -0,0 +1,21 @@ +import * as THREE from '../../../core/three'; +import GridMaterial from '../../../geom/material/hexagon'; +export default function DrawHexagon(attributes, style) { + const { opacity, radius, angle, 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_radius: radius, + u_angle: angle / 180 * Math.PI, + u_coverage: coverage + }, { + SHAPE: false + }); + const hexgonMesh = new THREE.Mesh(geometry, material); + return hexgonMesh; +} + diff --git a/src/source/index.js b/src/source/index.js index ff88ba484e..1d7fe62ba4 100644 --- a/src/source/index.js +++ b/src/source/index.js @@ -8,6 +8,7 @@ import raster from './parser/raster'; import { registerTransform, registerParser } from './factory'; import { aggregatorToGrid } from './transform/grid'; +import { pointToHexbin } from './transform/hexagon'; import { map } from './transform/map'; registerParser('geojson', geojson); @@ -18,6 +19,7 @@ registerParser('raster', raster); // 注册transform registerTransform('grid', aggregatorToGrid); +registerTransform('hexagon', pointToHexbin); registerTransform('map', map); export { getTransform, registerTransform, getParser, registerParser } from './factory'; diff --git a/src/source/transform/grid.js b/src/source/transform/grid.js index d2ace3476c..21440bae89 100644 --- a/src/source/transform/grid.js +++ b/src/source/transform/grid.js @@ -17,8 +17,8 @@ export function aggregatorToGrid(data, 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, + xOffset: gridOffset.xOffset / 360 * (256 << 20) / 2, dataArray: layerData }; } diff --git a/src/source/transform/hexagon.js b/src/source/transform/hexagon.js index f0aa9692f1..c550dc32ac 100644 --- a/src/source/transform/hexagon.js +++ b/src/source/transform/hexagon.js @@ -20,7 +20,7 @@ export function pointToHexbin(data, option) { .y(d => d.coordinates[1]); const hexbinBins = newHexbin(screenPoints); const result = { - size: pixlSize + radius: pixlSize }; result.dataArray = hexbinBins.map((hex, index) => { if (option.field && option.method) { @@ -31,8 +31,9 @@ export function pointToHexbin(data, option) { item[option.method] = hex[option.method]; return { ...item, + count: hex.length, coordinates: unProjectFlat([ hex.x, hex.y ]), - id: index + 1 + _id: index + 1 }; }); return result; diff --git a/test/unit/geom/buffer/heatmap/hexagon.js b/test/unit/geom/buffer/heatmap/hexagon.js new file mode 100644 index 0000000000..c92074bca3 --- /dev/null +++ b/test/unit/geom/buffer/heatmap/hexagon.js @@ -0,0 +1,35 @@ +import { expect } from 'chai'; +import hexagonBuffer from '../../../../../src/geom/buffer/heatmap/hexagon'; +describe('hexagon heatMap buffer', () => { + const layerData = [ + { color: [ 1, 1, 0, 1 ], coordinates: [ 120.12063099925889, 30.263947783103486, 0 ], id: 1 }, + { color: [ 1, 0.5, 0, 1 ], coordinates: [ 120.12218696039365, 30.263947783103486, 0 ], id: 2 }, + { + color: [ 1, 0.1, 0, 1 ], + coordinates: [ 120.12374292152843, 30.263947783103486, 0 ], + id: 3 + }, + { color: [ 1, 0, 0.2, 1 ], coordinates: [ 120.1252988826632, 30.263947783103486, 0 ], id: 4 }, + { + color: [ 0, 1, 0, 1 ], + coordinates: [ 120.12607686323062, 30.263947783103486, 0 ], + id: 5 + }, + { + color: [ 1, 1, 0, 1 ], + coordinates: [ 120.12685484379799, 30.263947783103486, 0 ], + id: 6 + }, + { color: [ 1, 1, 1, 1 ], coordinates: [ 120.12841080493274, 30.263947783103486, 0 ], id: 7 }, + { color: [ 0, 1, 1, 1 ], coordinates: [ 120.13230070776972, 30.263947783103486, 0 ], id: 8 }, + { color: [ 0, 1, 0, 1 ], coordinates: [ 120.12763282436538, 30.263947783103486, 0 ], id: 9 }, + { color: [ 1, 1, 0, 1 ], coordinates: [ 120.12996676606754, 30.263947783103486, 0 ], id: 10 } + ]; + it('hexagon buffer', () => { + const attribute = hexagonBuffer(layerData); + expect(attribute.colors.length).eql(480); + expect(attribute.miter.length).eql(240); + expect(attribute.pickingIds.length).eql(120); + expect(attribute.vertices.length).eql(360); + }); +}); diff --git a/test/unit/shader-module/base-spec.js b/test/unit/shader-module/base-spec.js index 8f2b35c079..ebe8cd9b43 100644 --- a/test/unit/shader-module/base-spec.js +++ b/test/unit/shader-module/base-spec.js @@ -24,9 +24,8 @@ describe('test shader module', function() { it('should import a module correctly.', function() { const { vs, fs } = getModule('module1'); - expect(vs).eq('#define PI 3.14'); - expect(fs).eq(''); + expect(fs.replace(/(\s+)|(\n)+|(\r\n)+/g, '')).eqls('#ifdefGL_FRAGMENT_PRECISION_HIGHprecisionhighpfloat;#elseprecisionmediumpfloat;#endif'); }); }); diff --git a/test/unit/source/transfrom/hexagon.js b/test/unit/source/transfrom/hexagon.js index aad4edb018..8fd3ce4dc6 100644 --- a/test/unit/source/transfrom/hexagon.js +++ b/test/unit/source/transfrom/hexagon.js @@ -18,6 +18,5 @@ describe('hexagon Test', function() { }; const hexgonGrid = pointToHexbin(data, { size: 100, field: 'v', method: 'sum' }); expect(hexgonGrid.dataArray.length).eql(567); - console.log(hexgonGrid); }); }); diff --git a/webpack.config.js b/webpack.config.js index 9106df5d7f..823d9ef161 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,7 +4,8 @@ const pkg = require('./package.json'); module.exports = { devtool: 'cheap-source-map', entry: { - l7: './src/index.js' + l7: './src/index.js', + three: './src/core/three.js' }, output: { filename: '[name].js',