From e0de889c8c6d11c067ce5f50dc5871a387b21f81 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Thu, 16 May 2019 21:43:23 +0800 Subject: [PATCH] refactor(layer): add register render --- demos/01_point_circle.html | 8 +- demos/06_text.html | 3 +- demos/taxi.html | 2 +- demos/vectorTile.html | 17 +- src/core/engine/index.js | 5 +- src/core/engine/picking/picking.js | 9 +- src/core/layer.js | 31 ++-- src/core/scene.js | 4 +- src/core/source.js | 4 + src/geom/material/pointLineMaterial.js | 2 +- src/geom/shader/point_meshLine_vert.glsl | 4 +- src/interaction/hash.js | 2 +- src/layer/heatmapLayer.js | 45 +----- src/layer/lineLayer.js | 28 +--- src/layer/pointLayer.js | 70 +------- src/layer/polygonLayer.js | 33 +--- src/layer/render/factory.js | 12 ++ src/layer/render/heatmap/gird.js | 10 +- src/layer/render/heatmap/heatmap.js | 10 +- src/layer/render/heatmap/hexagon.js | 11 +- src/layer/render/index.js | 48 ++++++ src/layer/render/line/drawArc.js | 18 ++- src/layer/render/line/drawMeshLine.js | 15 +- src/layer/render/point/drawFill.js | 17 +- src/layer/render/point/drawImage.js | 10 +- src/layer/render/point/drawNormal.js | 10 +- src/layer/render/point/drawStroke.js | 9 +- src/layer/render/point/drawText.js | 16 +- src/layer/render/polygon/drawAnimate.js | 12 +- src/layer/render/polygon/drawFill.js | 22 +-- src/layer/render/polygon/drawLine.js | 15 +- src/layer/render/polygon/index.js | 5 + src/layer/tile/tile.js | 194 +++++++++++++++++++---- src/layer/tile/tileLayer.js | 91 +++++------ src/layer/tile/vectorTile.js | 70 +++----- src/source/index.js | 2 + src/source/parser/geojson.js | 8 +- src/source/parser/mvt.js | 19 +++ src/util/object3d-util.js | 58 +++++++ 39 files changed, 571 insertions(+), 378 deletions(-) create mode 100644 src/layer/render/factory.js create mode 100644 src/layer/render/index.js create mode 100644 src/source/parser/mvt.js create mode 100644 src/util/object3d-util.js diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html index f63a295ae3..88efe97d33 100644 --- a/demos/01_point_circle.html +++ b/demos/01_point_circle.html @@ -66,7 +66,7 @@ scene.on('loaded', () => { .color('point_count',["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"]) .style({ stroke: 'rgb(255,255,255)', - strokeWidth: 1, + strokeWidth: 2, opacity: 1 }) .render(); @@ -76,7 +76,7 @@ scene.on('loaded', () => { }) .source(circleLayer.layerSource) .shape('point_count', 'text') - .active(true) + .active(false) .filter('point_count',(p)=>{ return p > 50 }) @@ -84,10 +84,10 @@ scene.on('loaded', () => { .color('#fff') .style({ stroke: '#999', - strokeWidth: 0, + strokeWidth: 1, opacity: 1.0 }) - .render(); + .render(); console.log(layerText); }); diff --git a/demos/06_text.html b/demos/06_text.html index 79f636e663..3fd2bc4f61 100644 --- a/demos/06_text.html +++ b/demos/06_text.html @@ -29,8 +29,7 @@ const scene = new L7.Scene({ }); window.scene = scene; scene.on('loaded', () => { - $.get('./data/provincePoint.geojson', data => { - // data.features = data.features.slice(0,1); + $.get('./data/provincePoint.json', data => { scene.PointLayer({ zIndex: 2 }) diff --git a/demos/taxi.html b/demos/taxi.html index d8ea264443..dc2edc621e 100644 --- a/demos/taxi.html +++ b/demos/taxi.html @@ -39,7 +39,7 @@ scene.on('loaded', () => { //.color('#F08D41') .color('#ff893a') .animate({enable:true}) - .render(); + //.render(); }); $.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => { buildLayer = scene.PolygonLayer({ diff --git a/demos/vectorTile.html b/demos/vectorTile.html index 40b4957717..f32f7ae714 100644 --- a/demos/vectorTile.html +++ b/demos/vectorTile.html @@ -35,15 +35,26 @@ const scene = new L7.Scene({ window.scene = scene; scene.on('loaded', () => { const layer = scene.VectorTileLayer({ - zIndex:0 + zIndex:0, + layerType:'polygon' }) //.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test') // https://mvt.amap.com/district/CHN2/8/203/105/4096?key= - .source('http://localhost:5000/test.mbtile/{z}/{x}/{y}.pbf') + .source('http://localhost:5000/test.mbtile/{z}/{x}/{y}.pbf',{ + parser:{ + type: 'mvt', + sourceLayer:'county4326', + idField:'OBJECTID', + maxZoom: 10, + } + }) .shape('line') + .active({fill:'red'}) .color('red') .render(); - + layer.on('click',(feature)=>{ + console.log(feature); + }) console.log(layer); }); diff --git a/src/core/engine/index.js b/src/core/engine/index.js index 03ae64af2a..5a379e0778 100644 --- a/src/core/engine/index.js +++ b/src/core/engine/index.js @@ -10,11 +10,11 @@ export default class Engine extends EventEmitter { this._scene = Scene; this._camera = new Camera(container).camera; this._renderer = new Renderer(container).renderer; - this._world = world; + 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._picking = Picking(this._world, this._renderer, this._camera); this.clock = new THREE.Clock(); this.composerLayers = []; } @@ -30,6 +30,7 @@ export default class Engine extends EventEmitter { } destroy() { } + // 渲染第三方Scene对象 renderScene(scene) { this._renderer.render(scene, this._camera); } diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js index 3d61d86427..5a6cf44936 100755 --- a/src/core/engine/picking/picking.js +++ b/src/core/engine/picking/picking.js @@ -3,13 +3,10 @@ import * as THREE from '../../three'; let nextId = 1; class Picking { - constructor(world, renderer, camera, scene) { + constructor(world, renderer, camera) { this._world = world; this._renderer = renderer; this._camera = camera; - this._raycaster = new THREE.Raycaster(); - this.scene = scene; - this._raycaster.linePrecision = 10; this._pickingScene = PickingScene; this.world = new THREE.Group(); this._pickingScene.add(this.world); @@ -49,11 +46,9 @@ class Picking { this._height = size.height; this._pickingTexture.setSize(this._width, this._height); this._pixelBuffer = new Uint8Array(4 * this._width * this._height); - this._needUpdate = true; } _update(point) { - const texture = this._pickingTexture; this._renderer.render(this._pickingScene, this._camera, this._pickingTexture); this.pixelBuffer = new Uint8Array(4); @@ -125,8 +120,6 @@ class Picking { this._world._container.removeEventListener(event[0], event[1], false); }); - this._world.off('move', this._onWorldMove); - if (this._pickingScene.children) { // Remove everything else in the layer let child; diff --git a/src/core/layer.js b/src/core/layer.js index 0cac7b1228..bbc32c8df6 100644 --- a/src/core/layer.js +++ b/src/core/layer.js @@ -11,6 +11,7 @@ import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl'; import { getInteraction } from '../interaction/index'; import Attr from '../attr/index'; import diff from '../util/diff'; +import { updateObjecteUniform } from '../util/object3d-util'; import Util from '../util'; import Global from '../global'; let id = 1; @@ -97,8 +98,10 @@ export default class Layer extends Base { this._visibleWithZoom(); object.onBeforeRender = () => { // 每次渲染前改变状态 const zoom = this.scene.getZoom(); - object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime()); - object.material.setUniformsValue('u_zoom', zoom); + updateObjecteUniform(this._object3D, { + u_time: this.scene._engine.clock.getElapsedTime(), + u_zoom: zoom + }); this.preRender(); }; @@ -374,13 +377,13 @@ export default class Layer extends Base { if (!Array.isArray(color)) { color = ColorUtil.color2RGBA(color); } - this.layerMesh.material.setUniformsValue('u_activeColor', color); + updateObjecteUniform(this._object3D, { u_activeColor: color }); } _addActiveFeature(e) { const { featureId } = e; this._activeIds = featureId; - this.layerMesh.material.setUniformsValue('u_activeId', featureId); + updateObjecteUniform(this._object3D, { u_activeId: featureId }); } @@ -487,8 +490,7 @@ export default class Layer extends Base { for (const key in option) { newOption['u_' + key] = option[key]; } - this.layerMesh.material.updateUninform(newOption); - + updateObjecteUniform(this._object3D, newOption); } _mapping(source) { const self = this; @@ -606,10 +608,9 @@ export default class Layer extends Base { pickmaterial.fragmentShader = pickingFragmentShader; const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial); pickingMesh.name = this.layerId; - pickmaterial.setDefinesvalue(this.type, true); pickingMesh.onBeforeRender = () => { const zoom = this.scene.getZoom(); - pickingMesh.material.setUniformsValue('u_zoom', zoom); + updateObjecteUniform(pickingMesh, { u_zoom: zoom }); }; this._pickingMesh.add(pickingMesh); @@ -621,13 +622,14 @@ export default class Layer extends Base { type = 'mouseleave'; } this._activeIds = featureId; - const feature = this.layerSource.getSelectFeature(featureId); + // TODO 瓦片图层获取选中数据信息 + // const feature = this.layerSource.getSelectFeature(featureId); const lnglat = this.scene.containerToLngLat(point2d); - const style = this.layerData[featureId - 1]; + // const style = this.layerData[featureId - 1]; const target = { featureId, - feature, - style, + // feature, + // style, pixel: point2d, type, lnglat: { lng: lnglat.lng, lat: lnglat.lat } @@ -738,13 +740,16 @@ export default class Layer extends Base { } interactions[type] = interaction; } + styleCfg() { + + } /** * 重置高亮要素 */ _resetStyle() { this._activeIds = null; - this.layerMesh.material.setUniformsValue('u_activeId', 0); + updateObjecteUniform(this._object3D, { u_activeId: 0 }); } /** * 销毁Layer对象 diff --git a/src/core/scene.js b/src/core/scene.js index b83e20fb99..50823980fd 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -25,8 +25,8 @@ export default class Scene extends Base { _initEngine(mapContainer) { this._engine = new Engine(mapContainer, this); - // this.registerMapEvent(); - this._engine.run(); + this.registerMapEvent(); + // this._engine.run(); // this.workerPool = new WorkerPool(); compileBuiltinModules(); } diff --git a/src/core/source.js b/src/core/source.js index 765636ea5d..96dcd12daf 100644 --- a/src/core/source.js +++ b/src/core/source.js @@ -150,4 +150,8 @@ export default class Source extends Base { } return featureIndex; } + destroy() { + this.data = null; + this.originData = null; + } } diff --git a/src/geom/material/pointLineMaterial.js b/src/geom/material/pointLineMaterial.js index ca6242e0f2..c84c5911f5 100644 --- a/src/geom/material/pointLineMaterial.js +++ b/src/geom/material/pointLineMaterial.js @@ -8,7 +8,7 @@ export default class PointLineMaterial extends Material { u_stroke: { value: [ 1.0, 1.0, 1.0, 1.0 ] }, u_strokeWidth: { value: 1.0 }, u_zoom: { value: 10 }, - u_activeId: { value: -1 }, + u_activeId: { value: 0 }, u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] } } diff --git a/src/geom/shader/point_meshLine_vert.glsl b/src/geom/shader/point_meshLine_vert.glsl index d4773d23e6..023a75f17d 100644 --- a/src/geom/shader/point_meshLine_vert.glsl +++ b/src/geom/shader/point_meshLine_vert.glsl @@ -21,10 +21,12 @@ void main() { #endif v_color = u_stroke; v_color.a *= u_strokeOpacity; + + v_pickingId = pickingId; if(v_pickingId == u_activeId) { v_color = u_activeColor; } - v_pickingId = pickingId; + //vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * pow(2.0,20.0-u_zoom) / 2.0 * a_miter); vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * scale / 2.0 * a_miter); gl_Position = matModelViewProjection * vec4(pointPos, 1.0); diff --git a/src/interaction/hash.js b/src/interaction/hash.js index 04b1bcb86d..abe5cc48a9 100644 --- a/src/interaction/hash.js +++ b/src/interaction/hash.js @@ -13,7 +13,7 @@ export default class Hash extends Interaction { this._updateHash(); } reset() { - this.layer._resetStyle(); + // this.layer._resetStyle(); } _getHashString() { const center = this.layer.getCenter(), diff --git a/src/layer/heatmapLayer.js b/src/layer/heatmapLayer.js index e47b5656fd..b75c270c1f 100644 --- a/src/layer/heatmapLayer.js +++ b/src/layer/heatmapLayer.js @@ -1,9 +1,5 @@ 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 { drawHeatmap } from './render/heatmap/heatmap'; -import hexagonBuffer from '../geom/buffer/heatmap/hexagon'; +import { getRender } from './render/'; export default class HeatMapLayer extends Layer { shape(type) { @@ -12,43 +8,6 @@ export default class HeatMapLayer extends Layer { } draw() { this.type = 'heatmap'; - switch (this.shapeType) { - case 'grid' : - this._drawGrid(); - break; - case 'hexagon' : - this._drawHexagon(); - break; - default: - drawHeatmap(this); - } + this.add(getRender('heatmap', this.shapeType || 'heatmap')(this.layerData, this, this.layerSource)); } - _drawHexagon() { - const style = this.get('styleOptions'); - const activeOption = this.get('activedOptions'); - const { radius } = this.layerSource.data; - this._buffer = new hexagonBuffer(this.layerData); - const config = { - ...style, - radius, - activeColor: activeOption.fill - }; - const Mesh = new DrawHexagon(this._buffer, config); - this.add(Mesh); - } - _drawGrid() { - const style = this.get('styleOptions'); - const activeOption = this.get('activedOptions'); - const { xOffset, yOffset } = this.layerSource.data; - this._buffer = new gridBuffer(this.layerData); - const config = { - ...style, - xOffset, - yOffset, - activeColor: activeOption.fill - }; - const girdMesh = new DrawGrid(this._buffer, config); - this.add(girdMesh); - } - } diff --git a/src/layer/lineLayer.js b/src/layer/lineLayer.js index be0bef02c8..489c1ac999 100644 --- a/src/layer/lineLayer.js +++ b/src/layer/lineLayer.js @@ -1,7 +1,5 @@ import Layer from '../core/layer'; -import DrawLine from './render/line/drawMeshLine'; -import DrawArc from './render/line/drawArc'; -import { LineBuffer } from '../geom/buffer/index'; +import { getRender } from './render/'; export default class LineLayer extends Layer { shape(type) { this.shapeType = type; @@ -19,27 +17,7 @@ export default class LineLayer extends Layer { } } draw() { - this.type = 'polyline'; - const layerData = this.layerData; - const style = this.get('styleOptions'); - const animateOptions = this.get('animateOptions'); - const activeOption = this.get('activedOptions'); - const layerCfg = { - zoom: this.scene.getZoom(), - style, - animateOptions, - activeOption - }; - const buffer = (this._buffer = new LineBuffer({ - layerData, - shapeType: this.shapeType, - style - })); - const { attributes } = buffer; - if (this.shapeType === 'arc') { - DrawArc(attributes, layerCfg, this); - } else { - this.add(DrawLine(attributes, layerCfg, this)); - } + this.type = 'line'; + this.add(getRender('line', this.shapeType || 'line')(this.layerData, this, this.layerSource)); } } diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js index 1e6efc7ae3..07d915c127 100644 --- a/src/layer/pointLayer.js +++ b/src/layer/pointLayer.js @@ -1,10 +1,6 @@ import Layer from '../core/layer'; -import * as drawPoint from '../layer/render/point'; -import TextBuffer from '../geom/buffer/point/text'; -import DrawText from './render/point/drawText'; import Global from '../global'; -// import PointBuffer from '../geom/buffer/point'; -import * as PointBuffer from '../geom/buffer/point/index'; +import { getRender } from './render/'; const { pointShape } = Global; /** * point shape 2d circle, traingle text,image @@ -16,67 +12,9 @@ const { pointShape } = Global; export default class PointLayer extends Layer { draw() { this.type = 'point'; - const { stroke, fill } = this.get('styleOptions'); - const style = this.get('styleOptions'); - const activeOption = this.get('activedOptions'); - const config = { - ...style, - activeColor: activeOption.fill - }; - const pointShapeType = this._getShape(); - this.shapeType = pointShapeType; - switch (pointShapeType) { - case 'fill': { // 填充图形 - if (fill !== 'none') { - // 是否填充 - const attributes = PointBuffer.FillBuffer(this.layerData, style); - const meshfill = drawPoint.DrawFill(attributes, config); - this.add(meshfill); - } - if (stroke !== 'none') { - // 是否绘制边界 - const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style); - const meshStroke = drawPoint.DrawStroke(lineAttribute, config); - this.add(meshStroke, 'line'); - } - break; - } - case 'image': { // 绘制图片标注 - 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(this.layerData, style); - const normalPointMesh = drawPoint.DrawNormal(normalAttribute, config); - this.add(normalPointMesh); - break; - } - case 'text': { // 原生点 - const { width, height } = this.scene.getSize(); - const textCfg = { - ...style, - width, - height, - activeColor: activeOption.fill - }; - const buffer = new TextBuffer( - this.layerData, - this.scene.fontAtlasManager - ); - const mesh = new DrawText(buffer, textCfg); - this.add(mesh); - break; - } - default: - return null; - } + this.shapeType = this._getShape(); + const mesh = getRender(this.type, this.shapeType)(this.layerData, this, this.layerSource); + this.add(mesh); } _getShape() { diff --git a/src/layer/polygonLayer.js b/src/layer/polygonLayer.js index e25c052038..32779aa2c2 100644 --- a/src/layer/polygonLayer.js +++ b/src/layer/polygonLayer.js @@ -1,6 +1,5 @@ import Layer from '../core/layer'; -import * as drawPolygon from './render/polygon'; -import PolygonBuffer from '../geom/buffer/polygon'; +import { getRender } from './render/'; export default class PolygonLayer extends Layer { shape(type) { this.shape = type; @@ -9,33 +8,13 @@ export default class PolygonLayer extends Layer { draw() { this.init(); this.type = 'polygon'; - this._buffer = new PolygonBuffer({ - shape: this.shape, - layerData: this.layerData - }); - this.add(this._getLayerRender()); + const animateOptions = this.get('animateOptions'); + if (animateOptions.enable) { + this.shape = 'animate'; + } + this.add(getRender(this.type, this.shape)(this.layerData, this)); } update() { this.updateFilter(this.layerMesh); } - _getLayerRender() { - const animateOptions = this.get('animateOptions'); - const { attributes } = this._buffer; - const style = this.get('styleOptions'); - const activeOption = this.get('activedOptions'); - const config = { - ...style, - activeColor: activeOption.fill - }; - if (this.shape === 'line') { - return drawPolygon.DrawLine(attributes, style); - } else if (animateOptions.enable) { - const { near, far } = this.map.getCameraState(); - this.scene.startAnimate(); - return drawPolygon.DrawAnimate(attributes, { ...style, near, far }); - } - return drawPolygon.DrawFill(attributes, config); - - } - } diff --git a/src/layer/render/factory.js b/src/layer/render/factory.js new file mode 100644 index 0000000000..9f6d53b333 --- /dev/null +++ b/src/layer/render/factory.js @@ -0,0 +1,12 @@ +export const Render_MAP = {}; +export const getRender = (layerType, shapeType) => { + return Render_MAP[layerType.toLowerCase()] && Render_MAP[layerType.toLowerCase()][shapeType.toLowerCase()]; +}; +export const registerRender = (layerType, shapeType, render) => { + if (getRender(layerType, shapeType)) { + throw new Error(`Render shapeType '${shapeType}' existed.`); + } + // 存储到 map 中 + if (!Render_MAP[layerType.toLowerCase()]) Render_MAP[layerType.toLowerCase()] = {}; + Render_MAP[layerType.toLowerCase()][shapeType.toLowerCase()] = render; +}; diff --git a/src/layer/render/heatmap/gird.js b/src/layer/render/heatmap/gird.js index aa83cedc92..04b31b40bf 100644 --- a/src/layer/render/heatmap/gird.js +++ b/src/layer/render/heatmap/gird.js @@ -1,7 +1,11 @@ import * as THREE from '../../../core/three'; +import gridBuffer from '../../../geom/buffer/heatmap/grid'; import GridMaterial from '../../../geom/material/grid'; -export default function DrawGrid(attributes, style) { - const { opacity, xOffset, yOffset, coverage, activeColor } = style; +export default function DrawGrid(layerdata, layer, source) { + const { opacity, coverage } = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const { xOffset, yOffset } = source.data; + const attributes = new gridBuffer(layerdata); const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2)); @@ -12,7 +16,7 @@ export default function DrawGrid(attributes, style) { u_xOffset: xOffset, u_yOffset: yOffset, u_coverage: coverage, - u_activeColor: activeColor + u_activeColor: activeOption.fill }, { SHAPE: false }); diff --git a/src/layer/render/heatmap/heatmap.js b/src/layer/render/heatmap/heatmap.js index 86511d34af..5ce24e1f68 100644 --- a/src/layer/render/heatmap/heatmap.js +++ b/src/layer/render/heatmap/heatmap.js @@ -7,18 +7,17 @@ import ShaderPass from '../../../core/engine/shader-pass'; import EffectComposer from '../../../core/engine/effect-composer'; import * as THREE from '../../../core/three'; -export function drawHeatmap(layer) { +export default function DrawHeatmap(layerdata, layer) { const colors = layer.get('styleOptions').rampColors; layer.rampColors = createColorRamp(colors); - const heatmap = new heatmapPass(layer); + const heatmap = new heatmapPass(layerdata, layer); const copy = new copyPass(layer); copy.renderToScreen = true; const composer = new EffectComposer(layer.scene._engine._renderer, layer.scene._container); composer.addPass(heatmap); composer.addPass(copy); - layer.add(composer); layer.scene._engine.update(); layer._updateStyle = style => { if (style.rampColors) { @@ -31,13 +30,14 @@ export function drawHeatmap(layer) { heatmap.scene.children[0].material.updateUninform(newOption); copy.scene.children[0].material.updateUninform(newOption); }; + return composer; } -function heatmapPass(layer) { +function heatmapPass(layerdata, layer) { const scene = new THREE.Scene(); const style = layer.get('styleOptions'); - const data = layer.layerData; + const data = layerdata; const camera = layer.scene._engine._camera; // get attributes data const buffer = new HeatmapBuffer({ diff --git a/src/layer/render/heatmap/hexagon.js b/src/layer/render/heatmap/hexagon.js index 639deaa645..8c2c42ee14 100644 --- a/src/layer/render/heatmap/hexagon.js +++ b/src/layer/render/heatmap/hexagon.js @@ -1,7 +1,12 @@ import * as THREE from '../../../core/three'; +import hexagonBuffer from '../../../geom/buffer/heatmap/hexagon'; import GridMaterial from '../../../geom/material/hexagon'; -export default function DrawHexagon(attributes, style) { - const { opacity, radius, angle, coverage, activeColor } = style; +export default function DrawHexagon(layerdata, layer, source) { + const style = layer.get('styleOptions'); + const { fill } = layer.get('activedOptions'); + const { radius } = source.data; + const attributes = new hexagonBuffer(layerdata); + const { opacity, 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)); @@ -12,7 +17,7 @@ export default function DrawHexagon(attributes, style) { u_radius: radius, u_angle: angle / 180 * Math.PI, u_coverage: coverage, - u_activeColor: activeColor + u_activeColor: fill }, { SHAPE: false }); diff --git a/src/layer/render/index.js b/src/layer/render/index.js new file mode 100644 index 0000000000..16a2d48273 --- /dev/null +++ b/src/layer/render/index.js @@ -0,0 +1,48 @@ +import { registerRender, getRender } from './factory'; +// polygon +import DrawFill from './polygon/drawFill'; +import DrawLine from './polygon/drawLine'; +import DrawAnimate from './polygon/drawAnimate'; + +registerRender('polygon', 'fill', DrawFill); +registerRender('polygon', 'extrude', DrawFill); +registerRender('polygon', 'line', DrawLine); +registerRender('polygon', 'animate', DrawAnimate); + +// line +import DrawMeshLine from './line/drawMeshLine'; +import DrawArcLine from './line/drawArc'; + +registerRender('line', 'line', DrawMeshLine); +registerRender('line', 'arc', DrawArcLine); + +// point +import DrawPointFill from './point/drawFill'; +import DrawPointImage from './point/drawImage'; +import DrawPointNormal from './point/drawNormal'; +import DrawPointStroke from './point/drawStroke'; +import DrawPointText from './point/drawText'; + +registerRender('point', 'fill', DrawPointFill); +registerRender('point', 'image', DrawPointImage); +registerRender('point', 'normal', DrawPointNormal); +registerRender('point', 'stroke', DrawPointStroke); +registerRender('point', 'text', DrawPointText); + +// heatmap + +import DrawGrid from './heatmap/gird'; +import DrawHeatmap from './heatmap/heatmap'; +import DrawHexagon from './heatmap/hexagon'; + +registerRender('heatmap', 'grid', DrawGrid); +registerRender('heatmap', 'heatmap', DrawHeatmap); +registerRender('heatmap', 'hexagon', DrawHexagon); + +// image + +import DrawImage from './image/drawImage'; + +registerRender('image', 'image', DrawImage); + +export { getRender }; diff --git a/src/layer/render/line/drawArc.js b/src/layer/render/line/drawArc.js index 5324e0c821..a043a0b2a6 100644 --- a/src/layer/render/line/drawArc.js +++ b/src/layer/render/line/drawArc.js @@ -1,8 +1,14 @@ import * as THREE from '../../../core/three'; +import { LineBuffer } from '../../../geom/buffer/index'; import { ArcLineMaterial } from '../../../geom/material/lineMaterial'; -export default function DrawArcLine(attributes, cfg, layer) { - const { style, activeOption } = cfg; - const { opacity, zoom } = style; +export default function DrawArcLine(layerdata, layer) { + const style = this.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const { attributes } = new LineBuffer({ + layerdata, + shapeType: 'arc', + style + }); const geometry = new THREE.BufferGeometry(); geometry.setIndex(attributes.indexArray); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3)); @@ -10,12 +16,12 @@ export default function DrawArcLine(attributes, cfg, layer) { geometry.addAttribute('a_instance', new THREE.Float32BufferAttribute(attributes.instances, 4)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1)); const lineMaterial = new ArcLineMaterial({ - u_opacity: opacity, - u_zoom: zoom, + u_opacity: style.opacity, + u_zoom: layer.scene.getZoom(), activeColor: activeOption.fill }, { SHAPE: false }); const arcMesh = new THREE.Mesh(geometry, lineMaterial); - layer.add(arcMesh); + return arcMesh; } diff --git a/src/layer/render/line/drawMeshLine.js b/src/layer/render/line/drawMeshLine.js index 85da3b91b6..ded7a550f3 100644 --- a/src/layer/render/line/drawMeshLine.js +++ b/src/layer/render/line/drawMeshLine.js @@ -1,7 +1,16 @@ import * as THREE from '../../../core/three'; +import { LineBuffer } from '../../../geom/buffer/index'; import { MeshLineMaterial } from '../../../geom/material/lineMaterial'; -export default function DrawLine(attributes, cfg, layer) { - const { style, animateOptions, activeOption, zoom } = cfg; +export default function DrawLine(layerData, layer) { + + const style = layer.get('styleOptions'); + const animateOptions = layer.get('animateOptions'); + const activeOption = layer.get('activedOptions'); + const { attributes } = new LineBuffer({ + layerData, + shapeType: 'line', + style + }); const geometry = new THREE.BufferGeometry(); geometry.setIndex(attributes.indexArray); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); @@ -14,7 +23,7 @@ export default function DrawLine(attributes, cfg, layer) { const lineMaterial = new MeshLineMaterial({ u_opacity: style.opacity, - u_zoom: zoom, + u_zoom: layer.scene.getZoom(), u_time: 0, activeColor: activeOption.fill }, { diff --git a/src/layer/render/point/drawFill.js b/src/layer/render/point/drawFill.js index 883d762107..57671b491c 100644 --- a/src/layer/render/point/drawFill.js +++ b/src/layer/render/point/drawFill.js @@ -6,9 +6,13 @@ * @desc [description] 绘制点图层的面状填充,圆,三角形,六边形 */ import * as THREE from '../../../core/three'; +import * as PointBuffer from '../../../geom/buffer/point/index'; +import DrawStroke from './drawStroke'; import PolygonMaterial from '../../../geom/material/polygonMaterial'; -export default function DrawFill(attributes, style) { - const { opacity, activeColor } = style; +export default function DrawFill(layerData, layer) { + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const attributes = PointBuffer.FillBuffer(layerData, style); const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); @@ -17,14 +21,19 @@ export default function DrawFill(attributes, style) { geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(attributes.shapePositions, 3)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3)); const material = new PolygonMaterial({ - u_opacity: opacity, - u_activeColor: activeColor + u_opacity: style.opacity, + u_activeColor: activeOption.fill }, { SHAPE: true }); material.setDefinesvalue('SHAPE', true); material.depthTest = false; const fillMesh = new THREE.Mesh(geometry, material); + if (style.stroke !== 'none') { + // 是否绘制边界 + const meshStroke = DrawStroke(layerData, layer); + fillMesh.add(meshStroke); + } return fillMesh; } diff --git a/src/layer/render/point/drawImage.js b/src/layer/render/point/drawImage.js index f6fc926aac..801cb8e854 100644 --- a/src/layer/render/point/drawImage.js +++ b/src/layer/render/point/drawImage.js @@ -1,9 +1,15 @@ import * as THREE from '../../../core/three'; +import * as PointBuffer from '../../../geom/buffer/point/index'; import PointMaterial from '../../../geom/material/pointMaterial'; -export default function DrawImage(attributes, style) { +export default function DrawImage(layerData, layer) { const geometry = new THREE.BufferGeometry(); - const { strokeWidth, stroke, opacity, texture } = style; + const style = layer.get('styleOptions'); + const { strokeWidth, stroke, opacity } = style; + const texture = layer.scene.image.texture; + const attributes = PointBuffer.ImageBuffer(layerData, { + imagePos: this.scene.image.imagePos + }); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); diff --git a/src/layer/render/point/drawNormal.js b/src/layer/render/point/drawNormal.js index 077c80d6f1..c851e85341 100644 --- a/src/layer/render/point/drawNormal.js +++ b/src/layer/render/point/drawNormal.js @@ -2,17 +2,21 @@ * 原生点绘制 */ import * as THREE from '../../../core/three'; +import * as PointBuffer from '../../../geom/buffer/point/index'; import PointMaterial from '../../../geom/material/pointMaterial'; -export default function DrawNormal(attributes, style) { +export default function DrawNormal(layerData, layer) { const geometry = new THREE.BufferGeometry(); - const { opacity, activeColor } = style; + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const { opacity } = style; + const attributes = PointBuffer.NormalBuffer(layerData, style); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1)); const material = new PointMaterial({ u_opacity: opacity, - u_activeColor: activeColor + u_activeColor: activeOption.fill }, { SHAPE: false, TEXCOORD_0: false diff --git a/src/layer/render/point/drawStroke.js b/src/layer/render/point/drawStroke.js index 8b5c780e48..da4ce645aa 100644 --- a/src/layer/render/point/drawStroke.js +++ b/src/layer/render/point/drawStroke.js @@ -7,9 +7,13 @@ */ import PointLineMaterial from '../../../geom/material/pointLineMaterial'; +import * as PointBuffer from '../../../geom/buffer/point/index'; import * as THREE from '../../../core/three'; -export default function DrawStroke(attributes, style) { +export default function DrawStroke(layerData, layer) { + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); const { strokeWidth, stroke, strokeOpacity } = style; + const attributes = PointBuffer.StrokeBuffer(layerData, style); const geometry = new THREE.BufferGeometry(); geometry.setIndex(attributes.indexArray); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3)); @@ -22,7 +26,8 @@ export default function DrawStroke(attributes, style) { const material = new PointLineMaterial({ u_strokeOpacity: strokeOpacity, u_stroke: stroke, - u_strokeWidth: strokeWidth + u_strokeWidth: strokeWidth, + u_activeColor: activeOption.fill }); const strokeMesh = new THREE.Mesh(geometry, material); return strokeMesh; diff --git a/src/layer/render/point/drawText.js b/src/layer/render/point/drawText.js index 32fa9a28d5..95d1f8949d 100644 --- a/src/layer/render/point/drawText.js +++ b/src/layer/render/point/drawText.js @@ -1,7 +1,15 @@ import * as THREE from '../../../core/three'; import TextMaterial from '../../../geom/material/textMaterial'; +import TextBuffer from '../../../geom/buffer/point/text'; -export default function DrawText(attributes, style) { +export default function DrawText(layerData, layer) { + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const { width, height } = layer.scene.getSize(); + const attributes = new TextBuffer( + layerData, + layer.scene.fontAtlasManager + ); const geometry = new THREE.BufferGeometry(); geometry.addAttribute( 'position', @@ -27,9 +35,9 @@ export default function DrawText(attributes, style) { 'pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1) ); - const { strokeWidth, width, stroke, height, opacity, activeColor } = style; + const { strokeWidth, stroke, opacity } = style; const material = new TextMaterial({ - name: this.layerId, + name: layer.layerId, u_texture: attributes.texture, u_strokeWidth: strokeWidth, u_stroke: stroke, @@ -41,7 +49,7 @@ export default function DrawText(attributes, style) { u_buffer: 0.75, u_opacity: opacity, u_glSize: [ width, height ], - u_activeColor: activeColor + u_activeColor: activeOption.fill }); const mesh = new THREE.Mesh(geometry, material); return mesh; diff --git a/src/layer/render/polygon/drawAnimate.js b/src/layer/render/polygon/drawAnimate.js index 1e7bb408fa..b8eed2ab34 100644 --- a/src/layer/render/polygon/drawAnimate.js +++ b/src/layer/render/polygon/drawAnimate.js @@ -1,7 +1,15 @@ import * as THREE from '../../../core/three'; +import PolygonBuffer from '../../../geom/buffer/polygon'; import PolygonMaterial from '../../../geom/material/polygonMaterial'; -export default function DrawAnimate(attributes, style) { - const { opacity, baseColor, brightColor, windowColor, near, far } = style; +export default function DrawAnimate(layerData, layer) { + const style = layer.get('styleOptions'); + const { near, far } = layer.map.getCameraState(); + layer.scene.startAnimate(); + const { attributes } = new PolygonBuffer({ + shape: 'extrude', + layerData + }); + const { opacity, baseColor, brightColor, windowColor } = style; const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); diff --git a/src/layer/render/polygon/drawFill.js b/src/layer/render/polygon/drawFill.js index d9981cbdbb..11ae385a2e 100644 --- a/src/layer/render/polygon/drawFill.js +++ b/src/layer/render/polygon/drawFill.js @@ -1,20 +1,24 @@ import * as THREE from '../../../core/three'; +import PolygonBuffer from '../../../geom/buffer/polygon'; import PolygonMaterial from '../../../geom/material/polygonMaterial'; -// import TileMaterial from '../../../geom/material/tile/polygon'; -export default function DrawPolygonFill(attributes, style) { - const { opacity, activeColor } = style; +export default function DrawPolygonFill(layerData, layer) { + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const config = { + ...style, + activeColor: activeOption.fill + }; + const { opacity, activeColor } = config; + const { attributes } = new PolygonBuffer({ + shape: layer.shape, + layerData + }); const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3)); - // const material = new PolygonMaterial({ - // u_opacity: opacity, - // u_activeColor: activeColor - // }, { - // SHAPE: false - // }); const material = new PolygonMaterial({ u_opacity: opacity, u_activeColor: activeColor diff --git a/src/layer/render/polygon/drawLine.js b/src/layer/render/polygon/drawLine.js index 8755a4f573..d14d8dc3e6 100644 --- a/src/layer/render/polygon/drawLine.js +++ b/src/layer/render/polygon/drawLine.js @@ -1,7 +1,18 @@ import * as THREE from '../../../core/three'; +import PolygonBuffer from '../../../geom/buffer/polygon'; import { LineMaterial } from '../../../geom/material/lineMaterial'; -export default function DrawPolygonLine(attributes, style) { - const { opacity } = style; +export default function DrawPolygonLine(layerData, layer) { + const style = layer.get('styleOptions'); + const activeOption = layer.get('activedOptions'); + const config = { + ...style, + activeColor: activeOption.fill + }; + const { opacity } = config; + const { attributes } = new PolygonBuffer({ + shape: layer.shape, + layerData + }); const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); diff --git a/src/layer/render/polygon/index.js b/src/layer/render/polygon/index.js index afde7904a6..65a4365702 100644 --- a/src/layer/render/polygon/index.js +++ b/src/layer/render/polygon/index.js @@ -1,3 +1,8 @@ + export { default as DrawAnimate } from './drawAnimate'; export { default as DrawFill } from './drawFill'; export { default as DrawLine } from './drawLine'; + +export function polygonMesh() { + +} diff --git a/src/layer/tile/tile.js b/src/layer/tile/tile.js index 87770386f5..d3661c4525 100644 --- a/src/layer/tile/tile.js +++ b/src/layer/tile/tile.js @@ -1,12 +1,28 @@ import * as THREE from '../../core/three'; -import EventEmitter from 'wolfy87-eventemitter'; +import Base from '../../core/base'; +import { destoryObject } from '../../util/object3d-util'; +import Controller from '../../core/controller/index'; +import Util from '../../util'; +import Global from '../../global'; +import Attr from '../../attr/index'; import { toLngLatBounds, toBounds } from '@antv/geo-coord'; const r2d = 180 / Math.PI; const tileURLRegex = /\{([zxy])\}/g; - -export default class Tile extends EventEmitter { +function parseFields(field) { + if (Util.isArray(field)) { + return field; + } + if (Util.isString(field)) { + return field.split('*'); + } + return [ field ]; +} +export default class Tile extends Base { constructor(key, url, layer) { - super(); + super({ + scales: {}, + attrs: {} + }); this.layer = layer; this._tile = key.split('_').map(v => v * 1); this._path = url; @@ -21,9 +37,130 @@ export default class Tile extends EventEmitter { this._object3D.onBeforeRender = () => { }; this._isLoaded = false; - this.requestTileAsync(); + this._initControllers(); + this.requestTileAsync(data => this._init(data)); + } + _init(data) { + this._creatSource(data); + this._initTileAttrs(); + this._mapping(); + this._createMesh(); + } + _initControllers() { + const scales = this.layer.get('scaleOptions'); + const scaleController = new Controller.Scale({ + defs: { + ...scales + } + }); + this.set('scaleController', scaleController); + } + _createScale(field) { + // TODO scale更新 + const scales = this.get('scales'); + let scale = scales[field]; + if (!scale) { + scale = this.createScale(field); + scales[field] = scale; + } + return scale; + } + createScale(field) { + const data = this.source.data.dataArray; + const scales = this.get('scales'); + let scale = scales[field]; + const scaleController = this.get('scaleController'); + if (!scale) { + scale = scaleController.createScale(field, data); + scales[field] = scale; + } + return scale; + } + // 获取属性映射的值 + _getAttrValues(attr, record) { + const scales = attr.scales; + const params = []; + for (let i = 0; i < scales.length; i++) { + const scale = scales[i]; + const field = scale.field; + if (scale.type === 'identity') { + params.push(scale.value); + } else { + params.push(record[field]); + } + } + const indexZoom = params.indexOf('zoom'); + indexZoom !== -1 ? params[indexZoom] = attr.zoom : null; + const values = attr.mapping(...params); + return values; + } + _mapping() { + const attrs = this.get('attrs'); + const mappedData = []; + // const data = this.layerSource.propertiesData; + const data = this.source.data.dataArray; + for (let i = 0; i < data.length; i++) { + const record = data[i]; + const newRecord = {}; + newRecord.id = data[i]._id; + for (const k in attrs) { + if (attrs.hasOwnProperty(k)) { + const attr = attrs[k]; + const names = attr.names; + const values = this._getAttrValues(attr, record); + if (names.length > 1) { // position 之类的生成多个字段的属性 + for (let j = 0; j < values.length; j++) { + const val = values[j]; + const name = names[j]; + newRecord[name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值 + } + } else { + newRecord[names[0]] = values.length === 1 ? values[0] : values; + } + } + } + newRecord.coordinates = record.coordinates; + mappedData.push(newRecord); + } + // 通过透明度过滤数据 + if (attrs.hasOwnProperty('filter')) { + mappedData.forEach(item => { + item.filter === false && (item.color[3] = 0); + }); + } + this.layerData = mappedData; + } + _initTileAttrs() { + const attrOptions = this.layer.get('attrOptions'); + for (const type in attrOptions) { + if (attrOptions.hasOwnProperty(type)) { + this._updateTileAttr(type); + } + } + } + _updateTileAttr(type) { + const self = this; + const attrs = this.get('attrs'); + const attrOptions = this.layer.get('attrOptions'); + const option = attrOptions[type]; + option.neadUpdate = true; + const className = Util.upperFirst(type); + const fields = parseFields(option.field); + const scales = []; + for (let i = 0; i < fields.length; i++) { + const field = fields[i]; + const scale = self._createScale(field); + + if (type === 'color' && Util.isNil(option.values)) { // 设置 color 的默认色值 + option.values = Global.colors; + } + scales.push(scale); + } + option.scales = scales; + const attr = new Attr[className](option); + attrs[type] = attr; } _createMesh() {} _getTileURL(urlParams) { @@ -65,33 +202,30 @@ export default class Tile extends EventEmitter { const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z); return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))); } + _retainParent(x, y, z, minZoom = 5) { + const x2 = Math.floor(x / 2), + y2 = Math.floor(y / 2), + z2 = z - 1, + coords2 = [ +x2, +y2, +z2 ]; + const tile = this._tiles[coords2]; // 计算保留 + if (tile && tile.active) { + tile.retain = true; + return true; + + } else if (tile && tile.loaded) { + tile.retain = true; + } + + if (z2 > minZoom) { + return this._retainParent(x2, y2, z2, minZoom); + } + + return false; + } _preRender() { } destroy() { - if (this._object3D && this._object3D.children) { - let child; - for (let i = 0; i < this._object3D.children.length; i++) { - child = this._object3D.children[i]; - if (!child) { - continue; - } - this.remove(child); - if (child.geometry) { - // child.geometry.dispose(); - child.geometry = null; - } - if (child.material) { - if (child.material.map) { - child.material.map.dispose(); - child.material.map = null; - } - - child.material.dispose(); - child.material = null; - } - child = null; - } - } - this._object3D = null; + super.destroy(); + destoryObject(this._object3D); } } diff --git a/src/layer/tile/tileLayer.js b/src/layer/tile/tileLayer.js index 2182e95ed6..94b38b1fc0 100644 --- a/src/layer/tile/tileLayer.js +++ b/src/layer/tile/tileLayer.js @@ -1,9 +1,9 @@ import Layer from '../../core/layer'; import source from '../../core/source'; import * as THREE from '../../core/three'; -import Util from '../../util'; import TileCache from './tileCache'; -import { throttle } from '@antv/util'; +import pickingFragmentShader from '../../core/engine/picking/picking_frag.glsl'; +import { throttle, deepMix } from '@antv/util'; import { toLngLat } from '@antv/geo-coord'; import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857'; export default class TileLayer extends Layer { @@ -12,28 +12,43 @@ export default class TileLayer extends Layer { this._tileCache = new TileCache(50, this._destroyTile); this._crs = epsg3857; this._tiles = new THREE.Object3D(); + this._pickTiles = new THREE.Object3D(); + this._pickTiles.name = this.layerId; + this.scene._engine._picking.add(this._pickTiles); + this._tiles.frustumCulled = false; this._tileKeys = []; this.tileList = []; } + shape(field, values) { + const layerType = this.get('layerType'); + if (layerType === 'point') { + return super.shape(field, values); + } + this.shape = field; + return this; + } source(url, cfg = {}) { this.url = url; this.sourceCfg = cfg; + this.sourceCfg.mapType = this.scene.mapType; return this; } - tileSource(data) { - super.source(data, this.sourceCfg); + tileSource(data, cfg) { if (data instanceof source) { return data; } - this.sourceCfg.data = data; - this.sourceCfg.mapType = this.scene.mapType; - this.sourceCfg.zoom = this.scene.getZoom(); - return new source(this.sourceCfg); + const tileSourceCfg = { + data, + zoom: this.scene.getZoom() + }; + deepMix(tileSourceCfg, this.sourceCfg, cfg); + return new source(tileSourceCfg); } render() { this._initControllers(); this._initMapEvent(); this._initAttrs(); + this._initInteraction(); this.draw(); return this; } @@ -43,44 +58,6 @@ export default class TileLayer extends Layer { } drawTile() { - } - _mapping(source) { - - const attrs = this.get('attrs'); - const mappedData = []; - // const data = this.layerSource.propertiesData; - const data = source.data.dataArray; - for (let i = 0; i < data.length; i++) { - const record = data[i]; - const newRecord = {}; - newRecord.id = data[i]._id; - for (const k in attrs) { - if (attrs.hasOwnProperty(k)) { - const attr = attrs[k]; - const names = attr.names; - const values = this._getAttrValues(attr, record); - if (names.length > 1) { // position 之类的生成多个字段的属性 - for (let j = 0; j < values.length; j++) { - const val = values[j]; - const name = names[j]; - newRecord[name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值 - } - } else { - newRecord[names[0]] = values.length === 1 ? values[0] : values; - - } - } - } - newRecord.coordinates = record.coordinates; - mappedData.push(newRecord); - } - // 通过透明度过滤数据 - if (attrs.hasOwnProperty('filter')) { - mappedData.forEach(item => { - item.filter === false && (item.color[3] = 0); - }); - } - return mappedData; } zoomchange(ev) { super.zoomchange(ev); @@ -163,14 +140,31 @@ export default class TileLayer extends Layer { mesh.name = key; this._tileCache.setTile(tile, key); this._tileKeys.push(key); - mesh.children.length !== 0 && this._tiles.add(tile.getMesh()); - this.scene._engine.update(); + if (mesh.children.length !== 0) { + this._tiles.add(tile.getMesh()); + this._addPickTile(tile.getMesh()); + } }); } else { this._tiles.add(tile.getMesh()); + this._addPickTile(tile.getMesh()); this._tileKeys.push(key); + this.scene._engine.update(); } } + _addPickTile(meshobj) { + const mesh = meshobj.children[0]; + const pickmaterial = mesh.material.clone(); + pickmaterial.fragmentShader = pickingFragmentShader; + const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial); + pickingMesh.name = this.layerId; + pickingMesh.onBeforeRender = () => { + const zoom = this.scene.getZoom(); + pickingMesh.material.setUniformsValue('u_zoom', zoom); + }; + this._pickTiles.add(pickingMesh); + + } // 移除视野外的tile _removeOutTiles() { for (let i = this._tiles.children.length - 1; i >= 0; i--) { @@ -195,6 +189,7 @@ export default class TileLayer extends Layer { } _destroyTile(tile) { tile.destroy(); + tile = null; } desttroy() { } diff --git a/src/layer/tile/vectorTile.js b/src/layer/tile/vectorTile.js index 30ded2ab04..e4a1081f2b 100644 --- a/src/layer/tile/vectorTile.js +++ b/src/layer/tile/vectorTile.js @@ -1,23 +1,20 @@ import Tile from './tile'; import { getArrayBuffer } from '../../util/ajax'; -import PBF from 'pbf'; -import * as VectorParser from '@mapbox/vector-tile'; +import { destoryObject } from '../../util/object3d-util'; import * as THREE from '../../core/three'; import MaskMaterial from '../../geom/material/tile/maskMaterial'; -import { LineBuffer } from '../../geom/buffer/index'; -import DrawLine from '../../layer/render/line/drawMeshLine'; - +import { getRender } from '../render/index'; export default class VectorTile extends Tile { - requestTileAsync() { + requestTileAsync(done) { // Making this asynchronous really speeds up the LOD framerate setTimeout(() => { if (!this._mesh) { // this._mesh = this._createMesh(); - this._requestTile(); + this._requestTile(done); } }, 0); } - _requestTile() { + _requestTile(done) { const urlParams = { x: this._tile[0], y: this._tile[1], @@ -31,47 +28,18 @@ export default class VectorTile extends Tile { return; } this._isLoaded = true; - this._parserData(data.data); + done(data.data); }); } _creatSource(data) { - this.source = this.layer.tileSource(data); - } - _parserData(data) { - const tile = new VectorParser.VectorTile(new PBF(data)); - // CHN_Cities_L CHN_Cities CHN_L - const layerName = 'county4326'; - const features = []; - const vectorLayer = tile.layers[layerName]; - for (let i = 0; i < vectorLayer.length; i++) { - const feature = vectorLayer.feature(i); - features.push(feature.toGeoJSON(this._tile[0], this._tile[1], this._tile[2])); - } - const geodata = { - type: 'FeatureCollection', - features - }; - this._creatSource(geodata); - this._createMesh(); + this.source = this.layer.tileSource(data, { + parser: { + tile: this._tile + } + }); } _createMesh() { - this.layerData = this.layer._mapping(this.source); - const style = this.layer.get('styleOptions'); - const buffer = new LineBuffer({ - layerData: this.layerData, - style, - shapeType: 'line' - - }); - const animateOptions = this.layer.get('animateOptions'); - const activeOption = this.layer.get('activedOptions'); - const layerCfg = { - zoom: this.layer.scene.getZoom(), - style, - animateOptions, - activeOption - }; - this.mesh = new DrawLine(buffer.attributes, layerCfg, this.layer); + this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(this.layerData, this.layer); this.mesh.onBeforeRender = renderer => { this._renderMask(renderer); }; @@ -130,12 +98,12 @@ export default class VectorTile extends Tile { this.xhrRequest.abort(); } destroy() { - - this.mesh.destroy(); - // if (this.maskScene) { - // this.maskScene.children[0].geometry = null; - // this.maskScene.children[0].material.dispose(); - // this.maskScene.children[0].material = null; - // } + super.destroy(); + destoryObject(this.maskScene); + this._object3D = null; + this.maskScene = null; + this.layerData = null; + this.source.destroy(); + this.source = null; } } diff --git a/src/source/index.js b/src/source/index.js index 1d7fe62ba4..b1d1819c64 100644 --- a/src/source/index.js +++ b/src/source/index.js @@ -5,6 +5,7 @@ import image from './parser/image'; import csv from './parser/csv'; import json from './parser/json'; import raster from './parser/raster'; +import mvt from './parser/mvt'; import { registerTransform, registerParser } from './factory'; import { aggregatorToGrid } from './transform/grid'; @@ -16,6 +17,7 @@ registerParser('image', image); registerParser('csv', csv); registerParser('json', json); registerParser('raster', raster); +registerParser('mvt', mvt); // 注册transform registerTransform('grid', aggregatorToGrid); diff --git a/src/source/parser/geojson.js b/src/source/parser/geojson.js index 0e7d4de3f1..6bbaf533f4 100644 --- a/src/source/parser/geojson.js +++ b/src/source/parser/geojson.js @@ -1,7 +1,7 @@ import * as turfMeta from '@turf/meta'; import { getCoords } from '@turf/invariant'; -export default function geoJSON(data) { +export default function geoJSON(data, cfg) { const resultData = []; data.features = data.features.filter(item => { return item != null && item.geometry && item.geometry.type && item.geometry.coordinates && item.geometry.coordinates.length > 0; @@ -10,10 +10,14 @@ export default function geoJSON(data) { // 数据为空时处理 turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个 const coord = getCoords(currentFeature); + let id = featureIndex + 1; + if (cfg.idField) { + id = currentFeature.properties[cfg.idField]; + } const dataItem = { ...currentFeature.properties, coordinates: coord, - _id: featureIndex + 1 + _id: id }; resultData.push(dataItem); }); diff --git a/src/source/parser/mvt.js b/src/source/parser/mvt.js new file mode 100644 index 0000000000..7e5165488b --- /dev/null +++ b/src/source/parser/mvt.js @@ -0,0 +1,19 @@ +import PBF from 'pbf'; +import * as VectorParser from '@mapbox/vector-tile'; +import geojson from './geojson'; +export default function mvt(data, cfg) { + const tile = new VectorParser.VectorTile(new PBF(data)); + // CHN_Cities_L CHN_Cities CHN_L + const layerName = cfg.sourceLayer; + const features = []; + const vectorLayer = tile.layers[layerName]; + for (let i = 0; i < vectorLayer.length; i++) { + const feature = vectorLayer.feature(i); + features.push(feature.toGeoJSON(cfg.tile[0], cfg.tile[1], cfg.tile[2])); + } + const geodata = { + type: 'FeatureCollection', + features + }; + return geojson(geodata, cfg); +} diff --git a/src/util/object3d-util.js b/src/util/object3d-util.js new file mode 100644 index 0000000000..17100fccb3 --- /dev/null +++ b/src/util/object3d-util.js @@ -0,0 +1,58 @@ +import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl'; +import * as THREE from '../core/three'; +export function destoryObject(obj) { + if (!obj) { + return; + } + if (obj.children) { + for (let i = 0; i < obj.children.length; i++) { + const child = obj.children[i]; + destoryObject(child); + } + } + if (obj.geometry) { + obj.geometry.dispose(); + obj.geometry = null; + } + if (obj.material) { + if (obj.material.map) { + obj.material.map.dispose(); + obj.material.map = null; + } + + obj.material.dispose(); + obj.material = null; + } +} +export function updateObjecteUniform(obj, newOption) { + if (!obj) { + return; + } + if (obj.children) { + for (let i = 0; i < obj.children.length; i++) { + const child = obj.children[i]; + updateObjecteUniform(child, newOption); + } + } + if (obj.material) { + obj.material.updateUninform(newOption); + } +} +export function getPickObject(obj, newbj) { + if (!obj) { + return; + } + if (obj.isMesh) { + const pickmaterial = obj.material.clone(); + pickmaterial.fragmentShader = pickingFragmentShader; + const pickMesh = new THREE[obj.type](obj.geometry, pickmaterial); + newbj.add(pickMesh); + } + if (obj.children) { + const newObj = new THREE.Object3D(); + for (let i = 0; i < obj.children.length; i++) { + const child = obj.children[i]; + newObj.add(getPickObject(child, newbj)); + } + } +}