feat(source): reuse tileSource

This commit is contained in:
thinkinggis 2019-06-14 10:08:42 +08:00
parent df6b2bdb77
commit 533b7181b2
21 changed files with 286 additions and 123 deletions

View File

@ -43,7 +43,7 @@ scene.on('loaded', () => {
// http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf // http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key= // https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/all_point/{z}/{x}/{y}.pbf',{ .source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point2/{z}/{x}/{y}.pbf',{
parser:{ parser:{
type: 'mvt', type: 'mvt',
sourceLayer:'layer', sourceLayer:'layer',

View File

@ -35,31 +35,31 @@ const scene = new L7.Scene({
}); });
window.scene = scene; window.scene = scene;
var colorHash = new ColorHash(); var colorHash = new ColorHash();
scene.on('loaded', () => {
const layer = scene.VectorTileLayer({
zIndex:0,
layerType:'polygon'
})
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
// http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf scene.on('loaded', () => {
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/village/{z}/{x}/{y}.pbf',{ const provinceSource = new L7.TileSource('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/province/{z}/{x}/{y}.pbf',{
parser:{ parser:{
type: 'mvt', type: 'mvt',
sourceLayer:'layer', sourceLayer:'layer',
idField:'code', idField:'code',
maxZoom: 17, maxZoom: 5,
} }
}) })
console.log(provinceSource);
const layer = scene.VectorTileLayer({
zIndex:0,
layerType:'line'
})
.source(provinceSource)
.scale({ .scale({
total:{ total:{
type:'linear', type:'linear',
min:0, min:0,
max:5000 max:5000000
} }
}) })
.shape('fill') .shape('line')
.size(2) .size(2)
.active(false) .active(false)
.color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506']) .color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
@ -67,15 +67,9 @@ scene.on('loaded', () => {
opacity:1.0 opacity:1.0
}) })
.render(); .render();
layer.on('mousemove',(feature)=>{
console.log(feature);
})
console.log(layer);
}); });
//OBJECTID',(id)=>{
// const index = id % 8;
//return ['#9e0142','#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd','#5e4fa2'][index];
//}
</script> </script>
</body> </body>
</html> </html>

View File

@ -18,10 +18,18 @@ export default class BufferController {
const colorAttr = this.mesh.mesh.geometry.attributes.a_color; const colorAttr = this.mesh.mesh.geometry.attributes.a_color;
const pickAttr = this.mesh.mesh.geometry.attributes.pickingId; const pickAttr = this.mesh.mesh.geometry.attributes.pickingId;
pickAttr.array.forEach((id, index) => { pickAttr.array.forEach((id, index) => {
id = Math.abs(id); let newId = Math.abs(id);
const color = colorKey[id]; let item = null;
id = Math.abs(id); let color = null;
const item = filterData[id - 1]; if (this.mesh.layerSource.data.featureKeys) { // hash数据映射
newId = this.mesh.layerSource.data.featureKeys[newId].index;
item = filterData[newId];
color = colorKey[item.id];
} else {
item = filterData[newId - 1];
color = colorKey[newId];
}
if (item.hasOwnProperty('filter') && item.filter === false) { if (item.hasOwnProperty('filter') && item.filter === false) {
colorAttr.array[index * 4 + 0] = 0; colorAttr.array[index * 4 + 0] = 0;
colorAttr.array[index * 4 + 1] = 0; colorAttr.array[index * 4 + 1] = 0;

View File

@ -34,8 +34,8 @@ export default class Mapping {
this.mesh.set('scaleController', scaleController); this.mesh.set('scaleController', scaleController);
} }
_createScale(field) { _createScale(field) {
// TODO scale更新
const scales = this.mesh.get('scales'); const scales = this.mesh.get('scales');
this._initControllers(); // scale更新
let scale = scales[field]; let scale = scales[field];
if (!scale) { if (!scale) {
scale = this.createScale(field); scale = this.createScale(field);

View File

@ -50,8 +50,7 @@ class Picking {
} }
_update(point) { _update(point) {
const texture = this._pickingTexture; const texture = this._pickingTexture;
// this._pickingTexture this._renderer.render(this._pickingScene, this._camera, texture);
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
this.pixelBuffer = new Uint8Array(4); this.pixelBuffer = new Uint8Array(4);
this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer); this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer);
@ -62,8 +61,23 @@ class Picking {
index === id ? object.visible = true : object.visible = false; index === id ? object.visible = true : object.visible = false;
}); });
} }
_layerIsVisable(object) {
const layers = this._world.getLayers();
let isVisable = false;
for (let i = 0; i < layers.length; i++) {
const layer = layers[i];
if (object.name === layer.layerId) {
isVisable = layer.get('visible');
break;
}
}
return isVisable;
}
_pickAllObject(point, normalisedPoint) { _pickAllObject(point, normalisedPoint) {
this.world.children.forEach((object, index) => { this.world.children.forEach((object, index) => {
if (!this._layerIsVisable(object)) {
return;
}
this._filterObject(index); this._filterObject(index);
const item = this._pick(point, normalisedPoint, object.name); const item = this._pick(point, normalisedPoint, object.name);
item.type = point.type; item.type = point.type;

View File

@ -460,13 +460,15 @@ export default class Layer extends Base {
_initEvents() { _initEvents() {
this.scene.on('pick-' + this.layerId, e => { this.scene.on('pick-' + this.layerId, e => {
let { featureId, point2d, type } = e; let { featureId, point2d, type } = e;
if (featureId < 0 && this._activeIds !== null) {
type = 'mouseleave';
}
this._activeIds = featureId;
// TODO 瓦片图层获取选中数据信息 // TODO 瓦片图层获取选中数据信息
const lnglat = this.scene.containerToLngLat(point2d); const lnglat = this.scene.containerToLngLat(point2d);
const { feature, style } = this.getSelectFeature(featureId, lnglat); let feature = null;
let style = null;
if (featureId !== -999) {
const res = this.getSelectFeature(featureId, lnglat);
feature = res.feature;
style = res.style;
}
const target = { const target = {
featureId, featureId,
feature, feature,
@ -475,9 +477,14 @@ export default class Layer extends Base {
type, type,
lnglat: { lng: lnglat.lng, lat: lnglat.lat } lnglat: { lng: lnglat.lng, lat: lnglat.lat }
}; };
if (featureId >= 0 || this._activeIds >= 0) { // 拾取到元素,或者离开元素 if (featureId >= 0) { // 拾取到元素,或者离开元素
this.emit(type, target); this.emit(type, target);
} }
if (featureId < 0 && this._activeIds >= 0) {
type = 'mouseleave';
this.emit(type, target);
}
this._activeIds = featureId;
}); });
} }
@ -538,7 +545,7 @@ export default class Layer extends Base {
offset = 1; offset = 1;
} }
this._object3D.position && (this._object3D.position.z = offset * Math.pow(2, 20 - zoom)); this._object3D.position && (this._object3D.position.z = offset * Math.pow(2, 20 - zoom));
if (zoom < minZoom || zoom > maxZoom) { if (zoom < minZoom || zoom >= maxZoom) {
this._object3D.visible = false; this._object3D.visible = false;
} else if (this.get('visible')) { } else if (this.get('visible')) {
this._object3D.visible = true; this._object3D.visible = true;

View File

@ -105,7 +105,9 @@ export default class Scene extends Base {
this._container.addEventListener(event, e => { this._container.addEventListener(event, e => {
// 要素拾取 // 要素拾取
e.pixel || (e.pixel = e.point); e.pixel || (e.pixel = e.point);
requestAnimationFrame(() => {
this._engine._picking.pickdata(e); this._engine._picking.pickdata(e);
});
}, false); }, false);
}); });
} }

View File

@ -58,7 +58,7 @@ export default class Source extends Base {
this.originData = getParser(type)(data, parser); this.originData = getParser(type)(data, parser);
// this.data = { // this.data = {
// dataArray: clone(this.originData.dataArray) // dataArray: clone(this.originData.dataArray)
// }; // }; // TODO 关闭数据备份
this.data = this.originData; this.data = this.originData;
if (this.data !== null) { if (this.data !== null) {
this.data.extent = extent(this.data.dataArray); this.data.extent = extent(this.data.dataArray);

View File

@ -17,8 +17,8 @@ export function LineMaterial(options) {
}, },
vertexShader: vs, vertexShader: vs,
fragmentShader: fs, fragmentShader: fs,
transparent: true, transparent: true
blending: THREE.AdditiveBlending // blending: THREE.AdditiveBlending
}); });
return material; return material;
} }
@ -50,8 +50,8 @@ export function MeshLineMaterial(options, defines) {
defines, defines,
vertexShader: vs, vertexShader: vs,
fragmentShader: fs, fragmentShader: fs,
transparent: true, transparent: true
blending: THREE.AdditiveBlending // blending: THREE.AdditiveBlending
}); });
return material; return material;
} }

View File

@ -18,7 +18,6 @@ void main() {
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.; vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
// vTime = 1.0- (28800. + mod(u_time* 10.,28800.)- position.z / 1000.) / 100.; // vTime = 1.0- (28800. + mod(u_time* 10.,28800.)- position.z / 1000.) / 100.;
#endif #endif
gl_Position = matModelViewProjection * vec4(position.xy, 0., 1.0); gl_Position = matModelViewProjection * vec4(position.xy, 10., 1.0);
gl_Position.z += 2. * gl_Position.w;
worldId = id_toPickColor(pickingId); worldId = id_toPickColor(pickingId);
} }

View File

@ -3,6 +3,7 @@
import Scene from './core/scene'; import Scene from './core/scene';
import Global from './global'; import Global from './global';
import Source from './core/source'; import Source from './core/source';
import TileSource from './source/tileSource';
import { registerParser, registerTransform } from './source'; import { registerParser, registerTransform } from './source';
import { registerInteraction, getInteraction } from './interaction'; import { registerInteraction, getInteraction } from './interaction';
import { registerLayer } from './layer'; import { registerLayer } from './layer';
@ -11,6 +12,7 @@ export {
version, version,
Scene, Scene,
Source, Source,
TileSource,
registerParser, registerParser,
registerTransform, registerTransform,
registerLayer, registerLayer,

View File

@ -26,6 +26,10 @@ export default function DrawPolygonFill(layerData, layer) {
SHAPE: false SHAPE: false
}); });
const fillPolygonMesh = new THREE.Mesh(geometry, material); const fillPolygonMesh = new THREE.Mesh(geometry, material);
delete attributes.vertices;
delete attributes.colors;
delete attributes.pickingIds;
delete attributes.normals;
return fillPolygonMesh; return fillPolygonMesh;
} }

View File

@ -30,10 +30,14 @@ export default class Tile extends Base {
this.requestTileAsync(data => this._init(data)); this.requestTileAsync(data => this._init(data));
} }
_init(data) { _init(data) {
this._creatSource(data); // this._creatSource(data); // 获取Source
this.layerSource = data;
if (this.layerSource.data === null) { if (this.layerSource.data === null) {
this.isValid = false;
return; return;
} }
this.isValid = true;
this._initControllers(); this._initControllers();
this._createMesh(); this._createMesh();
} }
@ -41,6 +45,16 @@ export default class Tile extends Base {
this._initControllers(); this._initControllers();
this._createMesh(); this._createMesh();
} }
requestTileAsync(done) {
const data = this.layer.tileSource.getTileData(this._tile[0], this._tile[1], this._tile[2]);
if (data.loaded) {
done(data.data);
} else {
data.data.then(data => {
done(data);
});
}
}
_initControllers() { _initControllers() {
const mappingCtr = new Controller.Mapping({ const mappingCtr = new Controller.Mapping({
layer: this.layer, layer: this.layer,

View File

@ -14,4 +14,10 @@ export default class TileCache {
destory() { destory() {
this._cache.clear(); this._cache.clear();
} }
setNeedUpdate() {
this._cache._order.forEach(key => {
const tile = this._cache.get(key);
tile.needUpdate = true;
});
}
} }

View File

@ -1,13 +1,12 @@
import Layer from '../../core/layer'; import Layer from '../../core/layer';
import Util from '../../util'; import Util from '../../util';
import diff from '../../util/diff'; import diff from '../../util/diff';
import source from '../../core/source'; import TileSource from '../../source/tileSource';
import * as THREE from '../../core/three'; import * as THREE from '../../core/three';
import Controller from '../../core/controller/index'; import Controller from '../../core/controller/index';
import Global from '../../global'; import Global from '../../global';
const { pointShape } = Global; const { pointShape } = Global;
import TileCache from './tileCache'; import TileCache from './tileCache';
import { deepMix } from '@antv/util';
import { toLngLat, Bounds, Point } from '@antv/geo-coord'; import { toLngLat, Bounds, Point } from '@antv/geo-coord';
import { wrapNum } from '@antv/geo-coord/lib/util/index'; import { wrapNum } from '@antv/geo-coord/lib/util/index';
import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857'; import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857';
@ -35,25 +34,16 @@ export default class TileLayer extends Layer {
this.shape = field; this.shape = field;
return this; return this;
} }
source(url, cfg = {}) { source(data, cfg = {}) {
this.url = url; if (data instanceof TileSource) {
this.sourceCfg = cfg; data.set('mapType', this.scene.mapType);
this.sourceCfg.mapType = this.scene.mapType; this.tileSource = data;
this.set('minSourceZoom', this.sourceCfg.parser && this.sourceCfg.parser.minZoom || 0); } else {
this.set('maxSourceZoom', this.sourceCfg.parser && this.sourceCfg.parser.maxZoom || 18); cfg.mapType = this.scene.mapType;
this.tileSource = new TileSource(data, cfg);
}
return this; return this;
} }
tileSource(data, cfg) {
if (data instanceof source) {
return data;
}
const tileSourceCfg = {
data,
zoom: this.scene.getZoom()
};
deepMix(tileSourceCfg, this.sourceCfg, cfg);
return new source(tileSourceCfg);
}
_initControllers() { _initControllers() {
const pickCtr = new Controller.Picking({ layer: this }); const pickCtr = new Controller.Picking({ layer: this });
const interactionCtr = new Controller.Interaction({ layer: this }); const interactionCtr = new Controller.Interaction({ layer: this });
@ -61,10 +51,6 @@ export default class TileLayer extends Layer {
this.set('interacionController', interactionCtr); this.set('interacionController', interactionCtr);
} }
render() { render() {
if (this.type !== 'image') {
this._initControllers();
}
this._visibleWithZoom(); this._visibleWithZoom();
this._updateDraw(); this._updateDraw();
this.scene._engine.update(); this.scene._engine.update();
@ -84,7 +70,6 @@ export default class TileLayer extends Layer {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this._calculateLOD(); this._calculateLOD();
}); });
// throttle(this._calculateLOD, 200);
this._calculateLOD(); this._calculateLOD();
} }
@ -93,9 +78,9 @@ export default class TileLayer extends Layer {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this._calculateLOD(); this._calculateLOD();
}); });
// this._calculateLOD();
} }
_calculateLOD() { _calculateLOD() {
/** /**
* 加载完成 active * 加载完成 active
@ -109,16 +94,18 @@ export default class TileLayer extends Layer {
const maxSourceZoom = this.get('maxSourceZoom'); const maxSourceZoom = this.get('maxSourceZoom');
const currentZoom = this.scene.getZoom(); const currentZoom = this.scene.getZoom();
this.tileZoom = zoom > maxSourceZoom ? maxSourceZoom : zoom; this.tileZoom = zoom > maxSourceZoom ? maxSourceZoom : zoom;
if (currentZoom < minZoom || currentZoom > maxZoom || currentZoom < minSourceZoom) { if (currentZoom < minZoom || currentZoom >= maxZoom || currentZoom < minSourceZoom) {
this._removeTiles(); this._removeTiles();
this.hide(); this._object3D.visible = false;
return; return;
} else if (this.get('visible')) {
this._object3D.visible = true;
} }
this.show(); this.show();
this.updateTileList = []; this.updateTileList = [];
const center = this.scene.getCenter(); const center = this.scene.getCenter();
const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), this.tileZoom); const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), this.tileZoom);
const centerXY = centerPoint.divideBy(256).round(); const centerXY = centerPoint.divideBy(256).floor();
const pixelBounds = this._getPixelBounds(); const pixelBounds = this._getPixelBounds();
const tileRange = this._pxBoundsToTileRange(pixelBounds); const tileRange = this._pxBoundsToTileRange(pixelBounds);
const margin = this.get('keepBuffer'); const margin = this.get('keepBuffer');
@ -228,7 +215,10 @@ export default class TileLayer extends Layer {
this._pruneTiles(); this._pruneTiles();
return; return;
} }
if (tile.needUpdate) {
tile.updateColor(); tile.updateColor();
tile.needUpdate = false;
}
this._tiles.add(tile.getMesh()); this._tiles.add(tile.getMesh());
t.active = true; t.active = true;
this._addPickTile(tile.getMesh()); this._addPickTile(tile.getMesh());
@ -249,8 +239,9 @@ export default class TileLayer extends Layer {
// 根据距离优先级查找 // 根据距离优先级查找
getSelectFeature(id, lnglat) { getSelectFeature(id, lnglat) {
const zoom = this.tileZoom; const zoom = this.tileZoom;
const tilePoint = this._crs.lngLatToPoint(toLngLat(lnglat.lng, lnglat.lat), zoom); const tilePoint = this._crs.lngLatToPoint(toLngLat(lnglat.lng, lnglat.lat), zoom);
const tileXY = tilePoint.divideBy(256).round(); const tileXY = tilePoint.divideBy(256).floor();
const key = [ tileXY.x, tileXY.y, zoom ].join('_'); const key = [ tileXY.x, tileXY.y, zoom ].join('_');
const tile = this._tileCache.getTile(key); const tile = this._tileCache.getTile(key);
const feature = tile ? tile.getSelectFeature(id) : null; const feature = tile ? tile.getSelectFeature(id) : null;
@ -351,6 +342,7 @@ export default class TileLayer extends Layer {
_removeTiles() { _removeTiles() {
this.hide();
if (!this._tiles || !this._tiles.children) { if (!this._tiles || !this._tiles.children) {
return; return;
} }
@ -415,32 +407,28 @@ export default class TileLayer extends Layer {
const preStyle = this.get('preStyleOption'); const preStyle = this.get('preStyleOption');
const nextStyle = this.get('styleOptions'); const nextStyle = this.get('styleOptions');
if (preAttrs === undefined && preStyle === undefined) { // 首次渲染 if (preAttrs === undefined && preStyle === undefined) { // 首次渲染
// this._mapping();
this._setPreOption(); this._setPreOption();
this._scaleByZoom(); this._scaleByZoom();
// this._initInteraction(); this._initControllers();
this._initInteraction();
this._initMapEvent(); this._initMapEvent();
this.draw(); this.draw();
this._setPreOption(); this._setPreOption();
return; return;
} }
if (!this._tiles.children.length > 0) { if (!this._tiles.children.length > 0 || !this._object3D.visible) {
this._setPreOption();
return; return;
} }
if (!Util.isEqual(preAttrs.color, nextAttrs.color)) { // 更新数据颜色 过滤 filter
if (!Util.isEqual(preAttrs.color, nextAttrs.color) || !Util.isEqual(preAttrs.filter, nextAttrs.filter)) {
this._tileCache.setNeedUpdate();
this._tiles.children.forEach(tile => { this._tiles.children.forEach(tile => {
this._tileCache.getTile(tile.name).updateColor(); const tileObj = this._tileCache.getTile(tile.name);
tileObj.updateColor();
tileObj.needUpdate = false;
this.scene._engine.update(); this.scene._engine.update();
}); });
} }
// 更新数据过滤 filter
if (!Util.isEqual(preAttrs.filter, nextAttrs.filter)) {
// 更新color
this._tiles.children(tile => {
this._tileCache.get(tile.name).updateColor();
});
}
// 更新Size // 更新Size
if (!Util.isEqual(preAttrs.size, nextAttrs.size)) { if (!Util.isEqual(preAttrs.size, nextAttrs.size)) {
// this._tiles.children(tile => { // this._tiles.children(tile => {

View File

@ -5,15 +5,15 @@ import * as THREE from '../../core/three';
import MaskMaterial from '../../geom/material/tile/maskMaterial'; import MaskMaterial from '../../geom/material/tile/maskMaterial';
import { getRender } from '../render/index'; import { getRender } from '../render/index';
export default class VectorTile extends Tile { export default class VectorTile extends Tile {
requestTileAsync(done) { // 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(done); // this._requestTile(done);
} // }
}, 0); // }, 0);
} // }
_requestTile(done) { _requestTile(done) {
const urlParams = { const urlParams = {
x: this._tile[0], x: this._tile[0],
@ -58,8 +58,9 @@ export default class VectorTile extends Tile {
} else { } else {
this._object3D = this.mesh; this._object3D = this.mesh;
} }
setTimeout(() => {
this.emit('tileLoaded'); this.emit('tileLoaded');
}, 0);
return this._object3D; return this._object3D;
} }
_renderMask(renderer) { _renderMask(renderer) {
@ -88,7 +89,7 @@ export default class VectorTile extends Tile {
// config the stencil buffer to collect data for testing // config the stencil buffer to collect data for testing
this.layer.scene._engine.renderScene(maskScene); this.layer.scene._engine.renderScene(maskScene);
context.colorMask(true, true, true, true); context.colorMask(true, true, true, true);
context.depthMask(true); context.depthMask(false);
renderer.clearDepth(); renderer.clearDepth();
// only render where stencil is set to 1 // only render where stencil is set to 1
@ -117,8 +118,9 @@ export default class VectorTile extends Tile {
this.xhrRequest.abort(); this.xhrRequest.abort();
} }
getSelectFeature(id) { getSelectFeature(id) {
const featureIndex = this.layerSource.originData.featureKeys[id]; const featurekey = this.layerSource.originData.featureKeys[id];
if (featureIndex) { if (featurekey && featurekey.index !== undefined) {
const featureIndex = featurekey.index;
return this.layerSource.originData.dataArray[featureIndex]; return this.layerSource.originData.dataArray[featureIndex];
} }
return null; return null;
@ -129,7 +131,5 @@ export default class VectorTile extends Tile {
this._object3D = null; this._object3D = null;
this.maskScene = null; this.maskScene = null;
this.layerData = null; this.layerData = null;
this.layerSource.destroy();
this.layerSource = null;
} }
} }

View File

@ -1,6 +1,6 @@
import * as turfMeta from '@turf/meta'; import * as turfMeta from '@turf/meta';
import { getCoords } from '@turf/invariant'; import { getCoords } from '@turf/invariant';
import { BKDRHash } from '../../util/bkdr-hash'; import { djb2hash } from '../../util/bkdr-hash';
export default function geoJSON(data, cfg) { export default function geoJSON(data, cfg) {
const resultData = []; const resultData = [];
const featureKeys = {}; const featureKeys = {};
@ -8,19 +8,18 @@ export default function geoJSON(data, cfg) {
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;
}); });
// 数据为空时处理 // 数据为空时处理
let i = 0;
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个 turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
const coord = getCoords(currentFeature); const coord = getCoords(currentFeature);
let id = featureIndex + 1; let id = featureIndex + 1;
if (cfg.idField && currentFeature.properties[cfg.idField]) { if (cfg.idField && currentFeature.properties[cfg.idField]) {
const value = currentFeature.properties[cfg.idField]; const value = currentFeature.properties[cfg.idField];
// id = value; id = djb2hash(value) % 1000019;
id = BKDRHash(value) % 1000019; featureKeys[id] = {
// if (featureKeys[id] && featureIndex !== featureKeys[id]) { index: i++,
// // TODO 哈希冲突解决方法 idField: value
// console.log('哈希冲突', value); };
// }
} }
featureKeys[id] = featureIndex;
const dataItem = { const dataItem = {
...currentFeature.properties, ...currentFeature.properties,
coordinates: coord, coordinates: coord,

View File

@ -16,19 +16,20 @@ export default function mvt(data, cfg) {
if (geofeature.geometry.type === 'Polygon' && geofeature.geometry.coordinates[0].length < 20) { if (geofeature.geometry.type === 'Polygon' && geofeature.geometry.coordinates[0].length < 20) {
continue; continue;
} }
const newfc = { // const newfc = {
geometry: geofeature.geometry, // geometry: geofeature.geometry,
type: 'Feature', // type: 'Feature',
properties: { // properties: {
total: geofeature.properties.total, // total: geofeature.properties.total,
province: geofeature.properties.province, // province: geofeature.properties.province,
bc_grade: geofeature.properties.bc_grade // bc_grade: geofeature.properties.bc_grade,
} // code: geofeature.properties.code || geofeature.properties.adcode
// }
};
features.push(newfc);
// };
features.push(geofeature);
} }
// console.log(features);
const geodata = { const geodata = {
type: 'FeatureCollection', type: 'FeatureCollection',
features features

View File

@ -0,0 +1,20 @@
import LRUCache from '../util/lru-cache';
export default class TileDataCache {
constructor(limit = 50, tileDestroy) {
this._cache = new LRUCache(limit, tileDestroy);
}
getTile(key) {
return this._cache.get(key);
}
setTile(tile, key) {
this._cache.set(key, tile);
}
removeTile(key) {
return this._cache.delete(key);
}
destory() {
this._cache.clear();
}
}

92
src/source/tileSource.js Normal file
View File

@ -0,0 +1,92 @@
import Source from '../core/source';
import { getArrayBuffer } from '../util/ajax';
import TileDataCache from './tileDataCache';
const tileURLRegex = /\{([zxy])\}/g;
export default class TileSource extends Source {
constructor(url, cfg) {
super(cfg);
this.cfg = cfg;
this.urlTemplate = url;
this._tileDataCache = new TileDataCache(50, this.tileDestroy);
this.type = 'tile';
}
getTileData(x, y, z) {
const key = [ x, y, z ].join('_');
let tileData = this._tileDataCache.getTile(key);
if (!tileData) {
const tiledataPromise = new Promise(resolve => {
if (tileData) {
setTimeout(() => {
resolve(tileData);
}, 0);
} else {
this._requestTileData(x, y, z, resolve);
}
});
tileData = {
loading: true,
data: tiledataPromise
};
this._tileDataCache.setTile(tileData, key);
return tileData;
}
return tileData;
}
_init() {
const parser = this.get('parser');
this.set('minSourceZoom', parser && parser.minZoom || 0);
this.set('maxSourceZoom', parser && parser.maxZoom || 18);
}
_generateSource(x, y, z, data) {
this.cfg.parser.tile = [ x, y, z ];
const tileData = new Source({
...this.cfg,
mapType: this.get('mapType'),
data,
tile: [ x, y, z ]
});
return tileData;
}
_requestTileData(x, y, z, done) {
const urlParams = { x, y, z };
const url = this._getTileURL(urlParams);
const key = [ x, y, z ].join('_');
this.xhrRequest = getArrayBuffer({ url }, (err, data) => {
if (err) {
this._noData = true;
this._tileDataCache.setTile({ loaded: true, data: { data: null } }, key);
return;
}
const tileData = this._generateSource(x, y, z, data.data);
this._tileDataCache.setTile({ loaded: true, data: tileData }, key);
done(tileData);
});
}
_getTileURL(urlParams) {
if (!urlParams.s) {
// Default to a random choice of a, b or c
urlParams.s = String.fromCharCode(97 + Math.floor(Math.random() * 3));
}
tileURLRegex.lastIndex = 0;
return this.urlTemplate.replace(tileURLRegex, function(value, key) {
return urlParams[key];
});
}
tileDestroy(tile) {
if (!tile || !tile.data || tile.loading) {
return;
}
const tileData = tile.data;
tileData.destroy();
tileData.data.dataArray.length = 0;
tileData.data.featureKeys = null;
tileData.originData.dataArray.length = 0;
tileData.originData.featureKeys = null;
}
}

View File

@ -14,3 +14,16 @@ export function BKDRHash(str) {
} }
return hash; return hash;
} }
export function djb2hash(str) {
let hash = 5381,
i = str.length;
while (i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
/* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
* integers. Since we want the results to be always positive, convert the
* signed int to an unsigned by doing an unsigned bitshift. */
return hash >>> 0;
}