refactor(layer): add register render

This commit is contained in:
thinkinggis 2019-05-16 21:43:23 +08:00
parent 2ceb4069e6
commit 44d405ce93
39 changed files with 571 additions and 378 deletions

View File

@ -66,7 +66,7 @@ scene.on('loaded', () => {
.color('point_count',["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"]) .color('point_count',["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
.style({ .style({
stroke: 'rgb(255,255,255)', stroke: 'rgb(255,255,255)',
strokeWidth: 1, strokeWidth: 2,
opacity: 1 opacity: 1
}) })
.render(); .render();
@ -76,7 +76,7 @@ scene.on('loaded', () => {
}) })
.source(circleLayer.layerSource) .source(circleLayer.layerSource)
.shape('point_count', 'text') .shape('point_count', 'text')
.active(true) .active(false)
.filter('point_count',(p)=>{ .filter('point_count',(p)=>{
return p > 50 return p > 50
}) })
@ -84,10 +84,10 @@ scene.on('loaded', () => {
.color('#fff') .color('#fff')
.style({ .style({
stroke: '#999', stroke: '#999',
strokeWidth: 0, strokeWidth: 1,
opacity: 1.0 opacity: 1.0
}) })
.render(); .render();
console.log(layerText); console.log(layerText);
}); });

View File

@ -29,8 +29,7 @@ const scene = new L7.Scene({
}); });
window.scene = scene; window.scene = scene;
scene.on('loaded', () => { scene.on('loaded', () => {
$.get('./data/provincePoint.geojson', data => { $.get('./data/provincePoint.json', data => {
// data.features = data.features.slice(0,1);
scene.PointLayer({ scene.PointLayer({
zIndex: 2 zIndex: 2
}) })

View File

@ -39,7 +39,7 @@ scene.on('loaded', () => {
//.color('#F08D41') //.color('#F08D41')
.color('#ff893a') .color('#ff893a')
.animate({enable:true}) .animate({enable:true})
.render(); //.render();
}); });
$.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => { $.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => {
buildLayer = scene.PolygonLayer({ buildLayer = scene.PolygonLayer({

View File

@ -35,15 +35,26 @@ const scene = new L7.Scene({
window.scene = scene; window.scene = scene;
scene.on('loaded', () => { scene.on('loaded', () => {
const layer = scene.VectorTileLayer({ 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') //.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= // 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') .shape('line')
.active({fill:'red'})
.color('red') .color('red')
.render(); .render();
layer.on('click',(feature)=>{
console.log(feature);
})
console.log(layer); console.log(layer);
}); });

View File

@ -10,11 +10,11 @@ export default class Engine extends EventEmitter {
this._scene = Scene; this._scene = Scene;
this._camera = new Camera(container).camera; this._camera = new Camera(container).camera;
this._renderer = new Renderer(container).renderer; this._renderer = new Renderer(container).renderer;
this._world = world; this._world = world;// 地图场景实例
// for MapBox // for MapBox
this.world = new THREE.Group(); this.world = new THREE.Group();
this._scene.add(this.world); 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.clock = new THREE.Clock();
this.composerLayers = []; this.composerLayers = [];
} }
@ -30,6 +30,7 @@ export default class Engine extends EventEmitter {
} }
destroy() { destroy() {
} }
// 渲染第三方Scene对象
renderScene(scene) { renderScene(scene) {
this._renderer.render(scene, this._camera); this._renderer.render(scene, this._camera);
} }

View File

@ -3,13 +3,10 @@ import * as THREE from '../../three';
let nextId = 1; let nextId = 1;
class Picking { class Picking {
constructor(world, renderer, camera, scene) { constructor(world, renderer, camera) {
this._world = world; this._world = world;
this._renderer = renderer; this._renderer = renderer;
this._camera = camera; this._camera = camera;
this._raycaster = new THREE.Raycaster();
this.scene = scene;
this._raycaster.linePrecision = 10;
this._pickingScene = PickingScene; this._pickingScene = PickingScene;
this.world = new THREE.Group(); this.world = new THREE.Group();
this._pickingScene.add(this.world); this._pickingScene.add(this.world);
@ -49,11 +46,9 @@ class Picking {
this._height = size.height; this._height = size.height;
this._pickingTexture.setSize(this._width, this._height); this._pickingTexture.setSize(this._width, this._height);
this._pixelBuffer = new Uint8Array(4 * this._width * this._height); this._pixelBuffer = new Uint8Array(4 * this._width * this._height);
this._needUpdate = true; this._needUpdate = true;
} }
_update(point) { _update(point) {
const texture = this._pickingTexture; const texture = this._pickingTexture;
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture); this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
this.pixelBuffer = new Uint8Array(4); this.pixelBuffer = new Uint8Array(4);
@ -125,8 +120,6 @@ class Picking {
this._world._container.removeEventListener(event[0], event[1], false); this._world._container.removeEventListener(event[0], event[1], false);
}); });
this._world.off('move', this._onWorldMove);
if (this._pickingScene.children) { if (this._pickingScene.children) {
// Remove everything else in the layer // Remove everything else in the layer
let child; let child;

View File

@ -11,6 +11,7 @@ import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl';
import { getInteraction } from '../interaction/index'; import { getInteraction } from '../interaction/index';
import Attr from '../attr/index'; import Attr from '../attr/index';
import diff from '../util/diff'; import diff from '../util/diff';
import { updateObjecteUniform } from '../util/object3d-util';
import Util from '../util'; import Util from '../util';
import Global from '../global'; import Global from '../global';
let id = 1; let id = 1;
@ -97,8 +98,10 @@ export default class Layer extends Base {
this._visibleWithZoom(); this._visibleWithZoom();
object.onBeforeRender = () => { // 每次渲染前改变状态 object.onBeforeRender = () => { // 每次渲染前改变状态
const zoom = this.scene.getZoom(); const zoom = this.scene.getZoom();
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime()); updateObjecteUniform(this._object3D, {
object.material.setUniformsValue('u_zoom', zoom); u_time: this.scene._engine.clock.getElapsedTime(),
u_zoom: zoom
});
this.preRender(); this.preRender();
}; };
@ -374,13 +377,13 @@ export default class Layer extends Base {
if (!Array.isArray(color)) { if (!Array.isArray(color)) {
color = ColorUtil.color2RGBA(color); color = ColorUtil.color2RGBA(color);
} }
this.layerMesh.material.setUniformsValue('u_activeColor', color); updateObjecteUniform(this._object3D, { u_activeColor: color });
} }
_addActiveFeature(e) { _addActiveFeature(e) {
const { featureId } = e; const { featureId } = e;
this._activeIds = featureId; 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) { for (const key in option) {
newOption['u_' + key] = option[key]; newOption['u_' + key] = option[key];
} }
this.layerMesh.material.updateUninform(newOption); updateObjecteUniform(this._object3D, newOption);
} }
_mapping(source) { _mapping(source) {
const self = this; const self = this;
@ -606,10 +608,9 @@ export default class Layer extends Base {
pickmaterial.fragmentShader = pickingFragmentShader; pickmaterial.fragmentShader = pickingFragmentShader;
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial); const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
pickingMesh.name = this.layerId; pickingMesh.name = this.layerId;
pickmaterial.setDefinesvalue(this.type, true);
pickingMesh.onBeforeRender = () => { pickingMesh.onBeforeRender = () => {
const zoom = this.scene.getZoom(); const zoom = this.scene.getZoom();
pickingMesh.material.setUniformsValue('u_zoom', zoom); updateObjecteUniform(pickingMesh, { u_zoom: zoom });
}; };
this._pickingMesh.add(pickingMesh); this._pickingMesh.add(pickingMesh);
@ -621,13 +622,14 @@ export default class Layer extends Base {
type = 'mouseleave'; type = 'mouseleave';
} }
this._activeIds = featureId; this._activeIds = featureId;
const feature = this.layerSource.getSelectFeature(featureId); // TODO 瓦片图层获取选中数据信息
// const feature = this.layerSource.getSelectFeature(featureId);
const lnglat = this.scene.containerToLngLat(point2d); const lnglat = this.scene.containerToLngLat(point2d);
const style = this.layerData[featureId - 1]; // const style = this.layerData[featureId - 1];
const target = { const target = {
featureId, featureId,
feature, // feature,
style, // style,
pixel: point2d, pixel: point2d,
type, type,
lnglat: { lng: lnglat.lng, lat: lnglat.lat } lnglat: { lng: lnglat.lng, lat: lnglat.lat }
@ -738,13 +740,16 @@ export default class Layer extends Base {
} }
interactions[type] = interaction; interactions[type] = interaction;
} }
styleCfg() {
}
/** /**
* 重置高亮要素 * 重置高亮要素
*/ */
_resetStyle() { _resetStyle() {
this._activeIds = null; this._activeIds = null;
this.layerMesh.material.setUniformsValue('u_activeId', 0); updateObjecteUniform(this._object3D, { u_activeId: 0 });
} }
/** /**
* 销毁Layer对象 * 销毁Layer对象

View File

@ -25,8 +25,8 @@ export default class Scene extends Base {
_initEngine(mapContainer) { _initEngine(mapContainer) {
this._engine = new Engine(mapContainer, this); this._engine = new Engine(mapContainer, this);
// this.registerMapEvent(); this.registerMapEvent();
this._engine.run(); // this._engine.run();
// this.workerPool = new WorkerPool(); // this.workerPool = new WorkerPool();
compileBuiltinModules(); compileBuiltinModules();
} }

View File

@ -150,4 +150,8 @@ export default class Source extends Base {
} }
return featureIndex; return featureIndex;
} }
destroy() {
this.data = null;
this.originData = null;
}
} }

View File

@ -8,7 +8,7 @@ export default class PointLineMaterial extends Material {
u_stroke: { value: [ 1.0, 1.0, 1.0, 1.0 ] }, u_stroke: { value: [ 1.0, 1.0, 1.0, 1.0 ] },
u_strokeWidth: { value: 1.0 }, u_strokeWidth: { value: 1.0 },
u_zoom: { value: 10 }, u_zoom: { value: 10 },
u_activeId: { value: -1 }, u_activeId: { value: 0 },
u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] } u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] }
} }

View File

@ -21,10 +21,12 @@ void main() {
#endif #endif
v_color = u_stroke; v_color = u_stroke;
v_color.a *= u_strokeOpacity; v_color.a *= u_strokeOpacity;
v_pickingId = pickingId;
if(v_pickingId == u_activeId) { if(v_pickingId == u_activeId) {
v_color = u_activeColor; 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 * pow(2.0,20.0-u_zoom) / 2.0 * a_miter);
vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * scale / 2.0 * a_miter); vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * scale / 2.0 * a_miter);
gl_Position = matModelViewProjection * vec4(pointPos, 1.0); gl_Position = matModelViewProjection * vec4(pointPos, 1.0);

View File

@ -13,7 +13,7 @@ export default class Hash extends Interaction {
this._updateHash(); this._updateHash();
} }
reset() { reset() {
this.layer._resetStyle(); // this.layer._resetStyle();
} }
_getHashString() { _getHashString() {
const center = this.layer.getCenter(), const center = this.layer.getCenter(),

View File

@ -1,9 +1,5 @@
import Layer from '../core/layer'; import Layer from '../core/layer';
import gridBuffer from '../geom/buffer/heatmap/grid'; import { getRender } from './render/';
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';
export default class HeatMapLayer extends Layer { export default class HeatMapLayer extends Layer {
shape(type) { shape(type) {
@ -12,43 +8,6 @@ export default class HeatMapLayer extends Layer {
} }
draw() { draw() {
this.type = 'heatmap'; this.type = 'heatmap';
switch (this.shapeType) { this.add(getRender('heatmap', this.shapeType || 'heatmap')(this.layerData, this, this.layerSource));
case 'grid' :
this._drawGrid();
break;
case 'hexagon' :
this._drawHexagon();
break;
default:
drawHeatmap(this);
}
} }
_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);
}
} }

View File

@ -1,7 +1,5 @@
import Layer from '../core/layer'; import Layer from '../core/layer';
import DrawLine from './render/line/drawMeshLine'; import { getRender } from './render/';
import DrawArc from './render/line/drawArc';
import { LineBuffer } from '../geom/buffer/index';
export default class LineLayer extends Layer { export default class LineLayer extends Layer {
shape(type) { shape(type) {
this.shapeType = type; this.shapeType = type;
@ -19,27 +17,7 @@ export default class LineLayer extends Layer {
} }
} }
draw() { draw() {
this.type = 'polyline'; this.type = 'line';
const layerData = this.layerData; this.add(getRender('line', this.shapeType || 'line')(this.layerData, this, this.layerSource));
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));
}
} }
} }

View File

@ -1,10 +1,6 @@
import Layer from '../core/layer'; 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 Global from '../global';
// import PointBuffer from '../geom/buffer/point'; import { getRender } from './render/';
import * as PointBuffer from '../geom/buffer/point/index';
const { pointShape } = Global; const { pointShape } = Global;
/** /**
* point shape 2d circle, traingle text,image * point shape 2d circle, traingle text,image
@ -16,67 +12,9 @@ const { pointShape } = Global;
export default class PointLayer extends Layer { export default class PointLayer extends Layer {
draw() { draw() {
this.type = 'point'; this.type = 'point';
const { stroke, fill } = this.get('styleOptions'); this.shapeType = this._getShape();
const style = this.get('styleOptions'); const mesh = getRender(this.type, this.shapeType)(this.layerData, this, this.layerSource);
const activeOption = this.get('activedOptions'); this.add(mesh);
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;
}
} }
_getShape() { _getShape() {

View File

@ -1,6 +1,5 @@
import Layer from '../core/layer'; import Layer from '../core/layer';
import * as drawPolygon from './render/polygon'; import { getRender } from './render/';
import PolygonBuffer from '../geom/buffer/polygon';
export default class PolygonLayer extends Layer { export default class PolygonLayer extends Layer {
shape(type) { shape(type) {
this.shape = type; this.shape = type;
@ -9,33 +8,13 @@ export default class PolygonLayer extends Layer {
draw() { draw() {
this.init(); this.init();
this.type = 'polygon'; this.type = 'polygon';
this._buffer = new PolygonBuffer({ const animateOptions = this.get('animateOptions');
shape: this.shape, if (animateOptions.enable) {
layerData: this.layerData this.shape = 'animate';
}); }
this.add(this._getLayerRender()); this.add(getRender(this.type, this.shape)(this.layerData, this));
} }
update() { update() {
this.updateFilter(this.layerMesh); 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);
}
} }

View File

@ -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;
};

View File

@ -1,7 +1,11 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import gridBuffer from '../../../geom/buffer/heatmap/grid';
import GridMaterial from '../../../geom/material/grid'; import GridMaterial from '../../../geom/material/grid';
export default function DrawGrid(attributes, style) { export default function DrawGrid(layerdata, layer, source) {
const { opacity, xOffset, yOffset, coverage, activeColor } = style; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2)); geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
@ -12,7 +16,7 @@ export default function DrawGrid(attributes, style) {
u_xOffset: xOffset, u_xOffset: xOffset,
u_yOffset: yOffset, u_yOffset: yOffset,
u_coverage: coverage, u_coverage: coverage,
u_activeColor: activeColor u_activeColor: activeOption.fill
}, { }, {
SHAPE: false SHAPE: false
}); });

View File

@ -7,18 +7,17 @@ import ShaderPass from '../../../core/engine/shader-pass';
import EffectComposer from '../../../core/engine/effect-composer'; import EffectComposer from '../../../core/engine/effect-composer';
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
export function drawHeatmap(layer) { export default function DrawHeatmap(layerdata, layer) {
const colors = layer.get('styleOptions').rampColors; const colors = layer.get('styleOptions').rampColors;
layer.rampColors = createColorRamp(colors); layer.rampColors = createColorRamp(colors);
const heatmap = new heatmapPass(layer); const heatmap = new heatmapPass(layerdata, layer);
const copy = new copyPass(layer); const copy = new copyPass(layer);
copy.renderToScreen = true; copy.renderToScreen = true;
const composer = new EffectComposer(layer.scene._engine._renderer, layer.scene._container); const composer = new EffectComposer(layer.scene._engine._renderer, layer.scene._container);
composer.addPass(heatmap); composer.addPass(heatmap);
composer.addPass(copy); composer.addPass(copy);
layer.add(composer);
layer.scene._engine.update(); layer.scene._engine.update();
layer._updateStyle = style => { layer._updateStyle = style => {
if (style.rampColors) { if (style.rampColors) {
@ -31,13 +30,14 @@ export function drawHeatmap(layer) {
heatmap.scene.children[0].material.updateUninform(newOption); heatmap.scene.children[0].material.updateUninform(newOption);
copy.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 scene = new THREE.Scene();
const style = layer.get('styleOptions'); const style = layer.get('styleOptions');
const data = layer.layerData; const data = layerdata;
const camera = layer.scene._engine._camera; const camera = layer.scene._engine._camera;
// get attributes data // get attributes data
const buffer = new HeatmapBuffer({ const buffer = new HeatmapBuffer({

View File

@ -1,7 +1,12 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import hexagonBuffer from '../../../geom/buffer/heatmap/hexagon';
import GridMaterial from '../../../geom/material/hexagon'; import GridMaterial from '../../../geom/material/hexagon';
export default function DrawHexagon(attributes, style) { export default function DrawHexagon(layerdata, layer, source) {
const { opacity, radius, angle, coverage, activeColor } = style; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2)); geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
@ -12,7 +17,7 @@ export default function DrawHexagon(attributes, style) {
u_radius: radius, u_radius: radius,
u_angle: angle / 180 * Math.PI, u_angle: angle / 180 * Math.PI,
u_coverage: coverage, u_coverage: coverage,
u_activeColor: activeColor u_activeColor: fill
}, { }, {
SHAPE: false SHAPE: false
}); });

48
src/layer/render/index.js Normal file
View File

@ -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 };

View File

@ -1,8 +1,14 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import { LineBuffer } from '../../../geom/buffer/index';
import { ArcLineMaterial } from '../../../geom/material/lineMaterial'; import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawArcLine(attributes, cfg, layer) { export default function DrawArcLine(layerdata, layer) {
const { style, activeOption } = cfg; const style = this.get('styleOptions');
const { opacity, zoom } = style; const activeOption = layer.get('activedOptions');
const { attributes } = new LineBuffer({
layerdata,
shapeType: 'arc',
style
});
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray); geometry.setIndex(attributes.indexArray);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3)); 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_instance', new THREE.Float32BufferAttribute(attributes.instances, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const lineMaterial = new ArcLineMaterial({ const lineMaterial = new ArcLineMaterial({
u_opacity: opacity, u_opacity: style.opacity,
u_zoom: zoom, u_zoom: layer.scene.getZoom(),
activeColor: activeOption.fill activeColor: activeOption.fill
}, { }, {
SHAPE: false SHAPE: false
}); });
const arcMesh = new THREE.Mesh(geometry, lineMaterial); const arcMesh = new THREE.Mesh(geometry, lineMaterial);
layer.add(arcMesh); return arcMesh;
} }

View File

@ -1,7 +1,16 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import { LineBuffer } from '../../../geom/buffer/index';
import { MeshLineMaterial } from '../../../geom/material/lineMaterial'; import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawLine(attributes, cfg, layer) { export default function DrawLine(layerData, layer) {
const { style, animateOptions, activeOption, zoom } = cfg;
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(); const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray); geometry.setIndex(attributes.indexArray);
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
@ -14,7 +23,7 @@ export default function DrawLine(attributes, cfg, layer) {
const lineMaterial = new MeshLineMaterial({ const lineMaterial = new MeshLineMaterial({
u_opacity: style.opacity, u_opacity: style.opacity,
u_zoom: zoom, u_zoom: layer.scene.getZoom(),
u_time: 0, u_time: 0,
activeColor: activeOption.fill activeColor: activeOption.fill
}, { }, {

View File

@ -6,9 +6,13 @@
* @desc [description] 绘制点图层的面状填充三角形六边形 * @desc [description] 绘制点图层的面状填充三角形六边形
*/ */
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import * as PointBuffer from '../../../geom/buffer/point/index';
import DrawStroke from './drawStroke';
import PolygonMaterial from '../../../geom/material/polygonMaterial'; import PolygonMaterial from '../../../geom/material/polygonMaterial';
export default function DrawFill(attributes, style) { export default function DrawFill(layerData, layer) {
const { opacity, activeColor } = style; const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
const attributes = PointBuffer.FillBuffer(layerData, style);
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); 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_shape', new THREE.Float32BufferAttribute(attributes.shapePositions, 3));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3));
const material = new PolygonMaterial({ const material = new PolygonMaterial({
u_opacity: opacity, u_opacity: style.opacity,
u_activeColor: activeColor u_activeColor: activeOption.fill
}, { }, {
SHAPE: true SHAPE: true
}); });
material.setDefinesvalue('SHAPE', true); material.setDefinesvalue('SHAPE', true);
material.depthTest = false; material.depthTest = false;
const fillMesh = new THREE.Mesh(geometry, material); const fillMesh = new THREE.Mesh(geometry, material);
if (style.stroke !== 'none') {
// 是否绘制边界
const meshStroke = DrawStroke(layerData, layer);
fillMesh.add(meshStroke);
}
return fillMesh; return fillMesh;
} }

View File

@ -1,9 +1,15 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import * as PointBuffer from '../../../geom/buffer/point/index';
import PointMaterial from '../../../geom/material/pointMaterial'; import PointMaterial from '../../../geom/material/pointMaterial';
export default function DrawImage(attributes, style) { export default function DrawImage(layerData, layer) {
const geometry = new THREE.BufferGeometry(); 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('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));

View File

@ -2,17 +2,21 @@
* 原生点绘制 * 原生点绘制
*/ */
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import * as PointBuffer from '../../../geom/buffer/point/index';
import PointMaterial from '../../../geom/material/pointMaterial'; import PointMaterial from '../../../geom/material/pointMaterial';
export default function DrawNormal(attributes, style) { export default function DrawNormal(layerData, layer) {
const geometry = new THREE.BufferGeometry(); 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('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const material = new PointMaterial({ const material = new PointMaterial({
u_opacity: opacity, u_opacity: opacity,
u_activeColor: activeColor u_activeColor: activeOption.fill
}, { }, {
SHAPE: false, SHAPE: false,
TEXCOORD_0: false TEXCOORD_0: false

View File

@ -7,9 +7,13 @@
*/ */
import PointLineMaterial from '../../../geom/material/pointLineMaterial'; import PointLineMaterial from '../../../geom/material/pointLineMaterial';
import * as PointBuffer from '../../../geom/buffer/point/index';
import * as THREE from '../../../core/three'; 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 { strokeWidth, stroke, strokeOpacity } = style;
const attributes = PointBuffer.StrokeBuffer(layerData, style);
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray); geometry.setIndex(attributes.indexArray);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
@ -22,7 +26,8 @@ export default function DrawStroke(attributes, style) {
const material = new PointLineMaterial({ const material = new PointLineMaterial({
u_strokeOpacity: strokeOpacity, u_strokeOpacity: strokeOpacity,
u_stroke: stroke, u_stroke: stroke,
u_strokeWidth: strokeWidth u_strokeWidth: strokeWidth,
u_activeColor: activeOption.fill
}); });
const strokeMesh = new THREE.Mesh(geometry, material); const strokeMesh = new THREE.Mesh(geometry, material);
return strokeMesh; return strokeMesh;

View File

@ -1,7 +1,15 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import TextMaterial from '../../../geom/material/textMaterial'; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute( geometry.addAttribute(
'position', 'position',
@ -27,9 +35,9 @@ export default function DrawText(attributes, style) {
'pickingId', 'pickingId',
new THREE.Float32BufferAttribute(attributes.pickingIds, 1) new THREE.Float32BufferAttribute(attributes.pickingIds, 1)
); );
const { strokeWidth, width, stroke, height, opacity, activeColor } = style; const { strokeWidth, stroke, opacity } = style;
const material = new TextMaterial({ const material = new TextMaterial({
name: this.layerId, name: layer.layerId,
u_texture: attributes.texture, u_texture: attributes.texture,
u_strokeWidth: strokeWidth, u_strokeWidth: strokeWidth,
u_stroke: stroke, u_stroke: stroke,
@ -41,7 +49,7 @@ export default function DrawText(attributes, style) {
u_buffer: 0.75, u_buffer: 0.75,
u_opacity: opacity, u_opacity: opacity,
u_glSize: [ width, height ], u_glSize: [ width, height ],
u_activeColor: activeColor u_activeColor: activeOption.fill
}); });
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
return mesh; return mesh;

View File

@ -1,7 +1,15 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial'; import PolygonMaterial from '../../../geom/material/polygonMaterial';
export default function DrawAnimate(attributes, style) { export default function DrawAnimate(layerData, layer) {
const { opacity, baseColor, brightColor, windowColor, near, far } = style; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));

View File

@ -1,20 +1,24 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial'; import PolygonMaterial from '../../../geom/material/polygonMaterial';
// import TileMaterial from '../../../geom/material/tile/polygon';
export default function DrawPolygonFill(attributes, style) { export default function DrawPolygonFill(layerData, layer) {
const { opacity, activeColor } = style; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1)); geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3)); 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({ const material = new PolygonMaterial({
u_opacity: opacity, u_opacity: opacity,
u_activeColor: activeColor u_activeColor: activeColor

View File

@ -1,7 +1,18 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import { LineMaterial } from '../../../geom/material/lineMaterial'; import { LineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawPolygonLine(attributes, style) { export default function DrawPolygonLine(layerData, layer) {
const { opacity } = style; 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(); const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));

View File

@ -1,3 +1,8 @@
export { default as DrawAnimate } from './drawAnimate'; export { default as DrawAnimate } from './drawAnimate';
export { default as DrawFill } from './drawFill'; export { default as DrawFill } from './drawFill';
export { default as DrawLine } from './drawLine'; export { default as DrawLine } from './drawLine';
export function polygonMesh() {
}

View File

@ -1,12 +1,28 @@
import * as THREE from '../../core/three'; 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'; import { toLngLatBounds, toBounds } from '@antv/geo-coord';
const r2d = 180 / Math.PI; const r2d = 180 / Math.PI;
const tileURLRegex = /\{([zxy])\}/g; const tileURLRegex = /\{([zxy])\}/g;
function parseFields(field) {
export default class Tile extends EventEmitter { 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) { constructor(key, url, layer) {
super(); super({
scales: {},
attrs: {}
});
this.layer = layer; this.layer = layer;
this._tile = key.split('_').map(v => v * 1); this._tile = key.split('_').map(v => v * 1);
this._path = url; this._path = url;
@ -21,9 +37,130 @@ export default class Tile extends EventEmitter {
this._object3D.onBeforeRender = () => { this._object3D.onBeforeRender = () => {
}; };
this._isLoaded = false; 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() {} _createMesh() {}
_getTileURL(urlParams) { _getTileURL(urlParams) {
@ -65,33 +202,30 @@ export default class Tile extends EventEmitter {
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z); const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))); 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() { _preRender() {
} }
destroy() { destroy() {
if (this._object3D && this._object3D.children) { super.destroy();
let child; destoryObject(this._object3D);
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;
} }
} }

View File

@ -1,9 +1,9 @@
import Layer from '../../core/layer'; import Layer from '../../core/layer';
import source from '../../core/source'; import source from '../../core/source';
import * as THREE from '../../core/three'; import * as THREE from '../../core/three';
import Util from '../../util';
import TileCache from './tileCache'; 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 { toLngLat } from '@antv/geo-coord';
import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857'; import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857';
export default class TileLayer extends Layer { export default class TileLayer extends Layer {
@ -12,28 +12,43 @@ export default class TileLayer extends Layer {
this._tileCache = new TileCache(50, this._destroyTile); this._tileCache = new TileCache(50, this._destroyTile);
this._crs = epsg3857; this._crs = epsg3857;
this._tiles = new THREE.Object3D(); 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._tileKeys = [];
this.tileList = []; 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 = {}) { source(url, cfg = {}) {
this.url = url; this.url = url;
this.sourceCfg = cfg; this.sourceCfg = cfg;
this.sourceCfg.mapType = this.scene.mapType;
return this; return this;
} }
tileSource(data) { tileSource(data, cfg) {
super.source(data, this.sourceCfg);
if (data instanceof source) { if (data instanceof source) {
return data; return data;
} }
this.sourceCfg.data = data; const tileSourceCfg = {
this.sourceCfg.mapType = this.scene.mapType; data,
this.sourceCfg.zoom = this.scene.getZoom(); zoom: this.scene.getZoom()
return new source(this.sourceCfg); };
deepMix(tileSourceCfg, this.sourceCfg, cfg);
return new source(tileSourceCfg);
} }
render() { render() {
this._initControllers(); this._initControllers();
this._initMapEvent(); this._initMapEvent();
this._initAttrs(); this._initAttrs();
this._initInteraction();
this.draw(); this.draw();
return this; return this;
} }
@ -43,44 +58,6 @@ export default class TileLayer extends Layer {
} }
drawTile() { 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) { zoomchange(ev) {
super.zoomchange(ev); super.zoomchange(ev);
@ -163,14 +140,31 @@ export default class TileLayer extends Layer {
mesh.name = key; mesh.name = key;
this._tileCache.setTile(tile, key); this._tileCache.setTile(tile, key);
this._tileKeys.push(key); this._tileKeys.push(key);
mesh.children.length !== 0 && this._tiles.add(tile.getMesh()); if (mesh.children.length !== 0) {
this.scene._engine.update(); this._tiles.add(tile.getMesh());
this._addPickTile(tile.getMesh());
}
}); });
} else { } else {
this._tiles.add(tile.getMesh()); this._tiles.add(tile.getMesh());
this._addPickTile(tile.getMesh());
this._tileKeys.push(key); 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 // 移除视野外的tile
_removeOutTiles() { _removeOutTiles() {
for (let i = this._tiles.children.length - 1; i >= 0; i--) { for (let i = this._tiles.children.length - 1; i >= 0; i--) {
@ -195,6 +189,7 @@ export default class TileLayer extends Layer {
} }
_destroyTile(tile) { _destroyTile(tile) {
tile.destroy(); tile.destroy();
tile = null;
} }
desttroy() { desttroy() {
} }

View File

@ -1,23 +1,20 @@
import Tile from './tile'; import Tile from './tile';
import { getArrayBuffer } from '../../util/ajax'; import { getArrayBuffer } from '../../util/ajax';
import PBF from 'pbf'; import { destoryObject } from '../../util/object3d-util';
import * as VectorParser from '@mapbox/vector-tile';
import * as THREE from '../../core/three'; import * as THREE from '../../core/three';
import MaskMaterial from '../../geom/material/tile/maskMaterial'; import MaskMaterial from '../../geom/material/tile/maskMaterial';
import { LineBuffer } from '../../geom/buffer/index'; import { getRender } from '../render/index';
import DrawLine from '../../layer/render/line/drawMeshLine';
export default class VectorTile extends Tile { export default class VectorTile extends Tile {
requestTileAsync() { requestTileAsync(done) {
// Making this asynchronous really speeds up the LOD framerate // Making this asynchronous really speeds up the LOD framerate
setTimeout(() => { setTimeout(() => {
if (!this._mesh) { if (!this._mesh) {
// this._mesh = this._createMesh(); // this._mesh = this._createMesh();
this._requestTile(); this._requestTile(done);
} }
}, 0); }, 0);
} }
_requestTile() { _requestTile(done) {
const urlParams = { const urlParams = {
x: this._tile[0], x: this._tile[0],
y: this._tile[1], y: this._tile[1],
@ -31,47 +28,18 @@ export default class VectorTile extends Tile {
return; return;
} }
this._isLoaded = true; this._isLoaded = true;
this._parserData(data.data); done(data.data);
}); });
} }
_creatSource(data) { _creatSource(data) {
this.source = this.layer.tileSource(data); this.source = this.layer.tileSource(data, {
} parser: {
_parserData(data) { tile: this._tile
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();
} }
_createMesh() { _createMesh() {
this.layerData = this.layer._mapping(this.source); this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(this.layerData, this.layer);
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.onBeforeRender = renderer => { this.mesh.onBeforeRender = renderer => {
this._renderMask(renderer); this._renderMask(renderer);
}; };
@ -130,12 +98,12 @@ export default class VectorTile extends Tile {
this.xhrRequest.abort(); this.xhrRequest.abort();
} }
destroy() { destroy() {
super.destroy();
this.mesh.destroy(); destoryObject(this.maskScene);
// if (this.maskScene) { this._object3D = null;
// this.maskScene.children[0].geometry = null; this.maskScene = null;
// this.maskScene.children[0].material.dispose(); this.layerData = null;
// this.maskScene.children[0].material = null; this.source.destroy();
// } this.source = null;
} }
} }

View File

@ -5,6 +5,7 @@ import image from './parser/image';
import csv from './parser/csv'; import csv from './parser/csv';
import json from './parser/json'; import json from './parser/json';
import raster from './parser/raster'; import raster from './parser/raster';
import mvt from './parser/mvt';
import { registerTransform, registerParser } from './factory'; import { registerTransform, registerParser } from './factory';
import { aggregatorToGrid } from './transform/grid'; import { aggregatorToGrid } from './transform/grid';
@ -16,6 +17,7 @@ registerParser('image', image);
registerParser('csv', csv); registerParser('csv', csv);
registerParser('json', json); registerParser('json', json);
registerParser('raster', raster); registerParser('raster', raster);
registerParser('mvt', mvt);
// 注册transform // 注册transform
registerTransform('grid', aggregatorToGrid); registerTransform('grid', aggregatorToGrid);

View File

@ -1,7 +1,7 @@
import * as turfMeta from '@turf/meta'; import * as turfMeta from '@turf/meta';
import { getCoords } from '@turf/invariant'; import { getCoords } from '@turf/invariant';
export default function geoJSON(data) { export default function geoJSON(data, cfg) {
const resultData = []; const resultData = [];
data.features = data.features.filter(item => { data.features = data.features.filter(item => {
return item != null && item.geometry && item.geometry.type && item.geometry.coordinates && item.geometry.coordinates.length > 0; 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 拆成一个 turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
const coord = getCoords(currentFeature); const coord = getCoords(currentFeature);
let id = featureIndex + 1;
if (cfg.idField) {
id = currentFeature.properties[cfg.idField];
}
const dataItem = { const dataItem = {
...currentFeature.properties, ...currentFeature.properties,
coordinates: coord, coordinates: coord,
_id: featureIndex + 1 _id: id
}; };
resultData.push(dataItem); resultData.push(dataItem);
}); });

19
src/source/parser/mvt.js Normal file
View File

@ -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);
}

58
src/util/object3d-util.js Normal file
View File

@ -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));
}
}
}