mirror of https://gitee.com/antv-l7/antv-l7
feat(source): reuse tileSource
This commit is contained in:
parent
6a4af99c29
commit
4ce9d60256
|
@ -43,7 +43,7 @@ scene.on('loaded', () => {
|
|||
|
||||
// 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=
|
||||
.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:{
|
||||
type: 'mvt',
|
||||
sourceLayer:'layer',
|
||||
|
|
|
@ -35,47 +35,41 @@ const scene = new L7.Scene({
|
|||
});
|
||||
window.scene = scene;
|
||||
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
|
||||
// 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:{
|
||||
type: 'mvt',
|
||||
sourceLayer:'layer',
|
||||
idField:'code',
|
||||
maxZoom: 17,
|
||||
maxZoom: 5,
|
||||
}
|
||||
})
|
||||
console.log(provinceSource);
|
||||
const layer = scene.VectorTileLayer({
|
||||
zIndex:0,
|
||||
layerType:'line'
|
||||
})
|
||||
.source(provinceSource)
|
||||
.scale({
|
||||
total:{
|
||||
type:'linear',
|
||||
min:0,
|
||||
max:5000
|
||||
max:5000000
|
||||
}
|
||||
})
|
||||
.shape('fill')
|
||||
.shape('line')
|
||||
.size(2)
|
||||
.active(false)
|
||||
.color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
|
||||
.style({
|
||||
opacity:1.0
|
||||
})
|
||||
.render();
|
||||
layer.on('mousemove',(feature)=>{
|
||||
console.log(feature);
|
||||
})
|
||||
console.log(layer);
|
||||
.render();
|
||||
|
||||
});
|
||||
//OBJECTID',(id)=>{
|
||||
// const index = id % 8;
|
||||
//return ['#9e0142','#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd','#5e4fa2'][index];
|
||||
//}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -18,10 +18,18 @@ export default class BufferController {
|
|||
const colorAttr = this.mesh.mesh.geometry.attributes.a_color;
|
||||
const pickAttr = this.mesh.mesh.geometry.attributes.pickingId;
|
||||
pickAttr.array.forEach((id, index) => {
|
||||
id = Math.abs(id);
|
||||
const color = colorKey[id];
|
||||
id = Math.abs(id);
|
||||
const item = filterData[id - 1];
|
||||
let newId = Math.abs(id);
|
||||
let item = null;
|
||||
let color = null;
|
||||
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) {
|
||||
colorAttr.array[index * 4 + 0] = 0;
|
||||
colorAttr.array[index * 4 + 1] = 0;
|
||||
|
|
|
@ -34,8 +34,8 @@ export default class Mapping {
|
|||
this.mesh.set('scaleController', scaleController);
|
||||
}
|
||||
_createScale(field) {
|
||||
// TODO scale更新
|
||||
const scales = this.mesh.get('scales');
|
||||
this._initControllers(); // scale更新
|
||||
let scale = scales[field];
|
||||
if (!scale) {
|
||||
scale = this.createScale(field);
|
||||
|
|
|
@ -50,8 +50,7 @@ class Picking {
|
|||
}
|
||||
_update(point) {
|
||||
const texture = this._pickingTexture;
|
||||
// this._pickingTexture
|
||||
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
||||
this._renderer.render(this._pickingScene, this._camera, texture);
|
||||
this.pixelBuffer = new Uint8Array(4);
|
||||
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;
|
||||
});
|
||||
}
|
||||
_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) {
|
||||
this.world.children.forEach((object, index) => {
|
||||
if (!this._layerIsVisable(object)) {
|
||||
return;
|
||||
}
|
||||
this._filterObject(index);
|
||||
const item = this._pick(point, normalisedPoint, object.name);
|
||||
item.type = point.type;
|
||||
|
|
|
@ -460,13 +460,15 @@ export default class Layer extends Base {
|
|||
_initEvents() {
|
||||
this.scene.on('pick-' + this.layerId, e => {
|
||||
let { featureId, point2d, type } = e;
|
||||
if (featureId < 0 && this._activeIds !== null) {
|
||||
type = 'mouseleave';
|
||||
}
|
||||
this._activeIds = featureId;
|
||||
// TODO 瓦片图层获取选中数据信息
|
||||
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 = {
|
||||
featureId,
|
||||
feature,
|
||||
|
@ -475,9 +477,14 @@ export default class Layer extends Base {
|
|||
type,
|
||||
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
||||
};
|
||||
if (featureId >= 0 || this._activeIds >= 0) { // 拾取到元素,或者离开元素
|
||||
if (featureId >= 0) { // 拾取到元素,或者离开元素
|
||||
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;
|
||||
}
|
||||
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;
|
||||
} else if (this.get('visible')) {
|
||||
this._object3D.visible = true;
|
||||
|
|
|
@ -105,7 +105,9 @@ export default class Scene extends Base {
|
|||
this._container.addEventListener(event, e => {
|
||||
// 要素拾取
|
||||
e.pixel || (e.pixel = e.point);
|
||||
this._engine._picking.pickdata(e);
|
||||
requestAnimationFrame(() => {
|
||||
this._engine._picking.pickdata(e);
|
||||
});
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ export default class Source extends Base {
|
|||
this.originData = getParser(type)(data, parser);
|
||||
// this.data = {
|
||||
// dataArray: clone(this.originData.dataArray)
|
||||
// };
|
||||
// }; // TODO 关闭数据备份
|
||||
this.data = this.originData;
|
||||
if (this.data !== null) {
|
||||
this.data.extent = extent(this.data.dataArray);
|
||||
|
|
|
@ -17,8 +17,8 @@ export function LineMaterial(options) {
|
|||
},
|
||||
vertexShader: vs,
|
||||
fragmentShader: fs,
|
||||
transparent: true,
|
||||
blending: THREE.AdditiveBlending
|
||||
transparent: true
|
||||
// blending: THREE.AdditiveBlending
|
||||
});
|
||||
return material;
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ export function MeshLineMaterial(options, defines) {
|
|||
defines,
|
||||
vertexShader: vs,
|
||||
fragmentShader: fs,
|
||||
transparent: true,
|
||||
blending: THREE.AdditiveBlending
|
||||
transparent: true
|
||||
// blending: THREE.AdditiveBlending
|
||||
});
|
||||
return material;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ void main() {
|
|||
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
|
||||
// vTime = 1.0- (28800. + mod(u_time* 10.,28800.)- position.z / 1000.) / 100.;
|
||||
#endif
|
||||
gl_Position = matModelViewProjection * vec4(position.xy, 0., 1.0);
|
||||
gl_Position.z += 2. * gl_Position.w;
|
||||
gl_Position = matModelViewProjection * vec4(position.xy, 10., 1.0);
|
||||
worldId = id_toPickColor(pickingId);
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
import Scene from './core/scene';
|
||||
import Global from './global';
|
||||
import Source from './core/source';
|
||||
import TileSource from './source/tileSource';
|
||||
import { registerParser, registerTransform } from './source';
|
||||
import { registerInteraction, getInteraction } from './interaction';
|
||||
import { registerLayer } from './layer';
|
||||
|
@ -11,6 +12,7 @@ export {
|
|||
version,
|
||||
Scene,
|
||||
Source,
|
||||
TileSource,
|
||||
registerParser,
|
||||
registerTransform,
|
||||
registerLayer,
|
||||
|
|
|
@ -26,6 +26,10 @@ export default function DrawPolygonFill(layerData, layer) {
|
|||
SHAPE: false
|
||||
});
|
||||
const fillPolygonMesh = new THREE.Mesh(geometry, material);
|
||||
delete attributes.vertices;
|
||||
delete attributes.colors;
|
||||
delete attributes.pickingIds;
|
||||
delete attributes.normals;
|
||||
return fillPolygonMesh;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,14 @@ export default class Tile extends Base {
|
|||
this.requestTileAsync(data => this._init(data));
|
||||
}
|
||||
_init(data) {
|
||||
this._creatSource(data);
|
||||
// this._creatSource(data); // 获取Source
|
||||
this.layerSource = data;
|
||||
|
||||
if (this.layerSource.data === null) {
|
||||
this.isValid = false;
|
||||
return;
|
||||
}
|
||||
this.isValid = true;
|
||||
this._initControllers();
|
||||
this._createMesh();
|
||||
}
|
||||
|
@ -41,6 +45,16 @@ export default class Tile extends Base {
|
|||
this._initControllers();
|
||||
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() {
|
||||
const mappingCtr = new Controller.Mapping({
|
||||
layer: this.layer,
|
||||
|
|
|
@ -14,4 +14,10 @@ export default class TileCache {
|
|||
destory() {
|
||||
this._cache.clear();
|
||||
}
|
||||
setNeedUpdate() {
|
||||
this._cache._order.forEach(key => {
|
||||
const tile = this._cache.get(key);
|
||||
tile.needUpdate = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import Layer from '../../core/layer';
|
||||
import Util from '../../util';
|
||||
import diff from '../../util/diff';
|
||||
import source from '../../core/source';
|
||||
import TileSource from '../../source/tileSource';
|
||||
import * as THREE from '../../core/three';
|
||||
import Controller from '../../core/controller/index';
|
||||
import Global from '../../global';
|
||||
const { pointShape } = Global;
|
||||
import TileCache from './tileCache';
|
||||
import { deepMix } from '@antv/util';
|
||||
import { toLngLat, Bounds, Point } from '@antv/geo-coord';
|
||||
import { wrapNum } from '@antv/geo-coord/lib/util/index';
|
||||
import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857';
|
||||
|
@ -35,24 +34,15 @@ export default class TileLayer extends Layer {
|
|||
this.shape = field;
|
||||
return this;
|
||||
}
|
||||
source(url, cfg = {}) {
|
||||
this.url = url;
|
||||
this.sourceCfg = cfg;
|
||||
this.sourceCfg.mapType = this.scene.mapType;
|
||||
this.set('minSourceZoom', this.sourceCfg.parser && this.sourceCfg.parser.minZoom || 0);
|
||||
this.set('maxSourceZoom', this.sourceCfg.parser && this.sourceCfg.parser.maxZoom || 18);
|
||||
return this;
|
||||
}
|
||||
tileSource(data, cfg) {
|
||||
if (data instanceof source) {
|
||||
return data;
|
||||
source(data, cfg = {}) {
|
||||
if (data instanceof TileSource) {
|
||||
data.set('mapType', this.scene.mapType);
|
||||
this.tileSource = data;
|
||||
} else {
|
||||
cfg.mapType = this.scene.mapType;
|
||||
this.tileSource = new TileSource(data, cfg);
|
||||
}
|
||||
const tileSourceCfg = {
|
||||
data,
|
||||
zoom: this.scene.getZoom()
|
||||
};
|
||||
deepMix(tileSourceCfg, this.sourceCfg, cfg);
|
||||
return new source(tileSourceCfg);
|
||||
return this;
|
||||
}
|
||||
_initControllers() {
|
||||
const pickCtr = new Controller.Picking({ layer: this });
|
||||
|
@ -61,10 +51,6 @@ export default class TileLayer extends Layer {
|
|||
this.set('interacionController', interactionCtr);
|
||||
}
|
||||
render() {
|
||||
|
||||
if (this.type !== 'image') {
|
||||
this._initControllers();
|
||||
}
|
||||
this._visibleWithZoom();
|
||||
this._updateDraw();
|
||||
this.scene._engine.update();
|
||||
|
@ -84,7 +70,6 @@ export default class TileLayer extends Layer {
|
|||
requestAnimationFrame(() => {
|
||||
this._calculateLOD();
|
||||
});
|
||||
// throttle(this._calculateLOD, 200);
|
||||
this._calculateLOD();
|
||||
}
|
||||
|
||||
|
@ -93,9 +78,9 @@ export default class TileLayer extends Layer {
|
|||
requestAnimationFrame(() => {
|
||||
this._calculateLOD();
|
||||
});
|
||||
// this._calculateLOD();
|
||||
|
||||
}
|
||||
|
||||
_calculateLOD() {
|
||||
/**
|
||||
* 加载完成 active
|
||||
|
@ -109,16 +94,18 @@ export default class TileLayer extends Layer {
|
|||
const maxSourceZoom = this.get('maxSourceZoom');
|
||||
const currentZoom = this.scene.getZoom();
|
||||
this.tileZoom = zoom > maxSourceZoom ? maxSourceZoom : zoom;
|
||||
if (currentZoom < minZoom || currentZoom > maxZoom || currentZoom < minSourceZoom) {
|
||||
if (currentZoom < minZoom || currentZoom >= maxZoom || currentZoom < minSourceZoom) {
|
||||
this._removeTiles();
|
||||
this.hide();
|
||||
this._object3D.visible = false;
|
||||
return;
|
||||
} else if (this.get('visible')) {
|
||||
this._object3D.visible = true;
|
||||
}
|
||||
this.show();
|
||||
this.updateTileList = [];
|
||||
const center = this.scene.getCenter();
|
||||
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 tileRange = this._pxBoundsToTileRange(pixelBounds);
|
||||
const margin = this.get('keepBuffer');
|
||||
|
@ -228,7 +215,10 @@ export default class TileLayer extends Layer {
|
|||
this._pruneTiles();
|
||||
return;
|
||||
}
|
||||
tile.updateColor();
|
||||
if (tile.needUpdate) {
|
||||
tile.updateColor();
|
||||
tile.needUpdate = false;
|
||||
}
|
||||
this._tiles.add(tile.getMesh());
|
||||
t.active = true;
|
||||
this._addPickTile(tile.getMesh());
|
||||
|
@ -249,8 +239,9 @@ export default class TileLayer extends Layer {
|
|||
// 根据距离优先级查找
|
||||
getSelectFeature(id, lnglat) {
|
||||
const zoom = this.tileZoom;
|
||||
|
||||
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 tile = this._tileCache.getTile(key);
|
||||
const feature = tile ? tile.getSelectFeature(id) : null;
|
||||
|
@ -351,6 +342,7 @@ export default class TileLayer extends Layer {
|
|||
|
||||
|
||||
_removeTiles() {
|
||||
this.hide();
|
||||
if (!this._tiles || !this._tiles.children) {
|
||||
return;
|
||||
}
|
||||
|
@ -415,32 +407,28 @@ export default class TileLayer extends Layer {
|
|||
const preStyle = this.get('preStyleOption');
|
||||
const nextStyle = this.get('styleOptions');
|
||||
if (preAttrs === undefined && preStyle === undefined) { // 首次渲染
|
||||
// this._mapping();
|
||||
this._setPreOption();
|
||||
this._scaleByZoom();
|
||||
// this._initInteraction();
|
||||
this._initControllers();
|
||||
this._initInteraction();
|
||||
this._initMapEvent();
|
||||
this.draw();
|
||||
this._setPreOption();
|
||||
return;
|
||||
}
|
||||
if (!this._tiles.children.length > 0) {
|
||||
this._setPreOption();
|
||||
if (!this._tiles.children.length > 0 || !this._object3D.visible) {
|
||||
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._tileCache.getTile(tile.name).updateColor();
|
||||
const tileObj = this._tileCache.getTile(tile.name);
|
||||
tileObj.updateColor();
|
||||
tileObj.needUpdate = false;
|
||||
this.scene._engine.update();
|
||||
});
|
||||
}
|
||||
// 更新数据过滤 filter
|
||||
if (!Util.isEqual(preAttrs.filter, nextAttrs.filter)) {
|
||||
// 更新color;
|
||||
this._tiles.children(tile => {
|
||||
this._tileCache.get(tile.name).updateColor();
|
||||
});
|
||||
}
|
||||
// 更新Size
|
||||
if (!Util.isEqual(preAttrs.size, nextAttrs.size)) {
|
||||
// this._tiles.children(tile => {
|
||||
|
|
|
@ -5,15 +5,15 @@ import * as THREE from '../../core/three';
|
|||
import MaskMaterial from '../../geom/material/tile/maskMaterial';
|
||||
import { getRender } from '../render/index';
|
||||
export default class VectorTile extends Tile {
|
||||
requestTileAsync(done) {
|
||||
// Making this asynchronous really speeds up the LOD framerate
|
||||
setTimeout(() => {
|
||||
if (!this._mesh) {
|
||||
// this._mesh = this._createMesh();
|
||||
this._requestTile(done);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
// requestTileAsync(done) {
|
||||
// // Making this asynchronous really speeds up the LOD framerate
|
||||
// setTimeout(() => {
|
||||
// if (!this._mesh) {
|
||||
// // this._mesh = this._createMesh();
|
||||
// this._requestTile(done);
|
||||
// }
|
||||
// }, 0);
|
||||
// }
|
||||
_requestTile(done) {
|
||||
const urlParams = {
|
||||
x: this._tile[0],
|
||||
|
@ -58,8 +58,9 @@ export default class VectorTile extends Tile {
|
|||
} else {
|
||||
this._object3D = this.mesh;
|
||||
}
|
||||
|
||||
this.emit('tileLoaded');
|
||||
setTimeout(() => {
|
||||
this.emit('tileLoaded');
|
||||
}, 0);
|
||||
return this._object3D;
|
||||
}
|
||||
_renderMask(renderer) {
|
||||
|
@ -88,7 +89,7 @@ export default class VectorTile extends Tile {
|
|||
// config the stencil buffer to collect data for testing
|
||||
this.layer.scene._engine.renderScene(maskScene);
|
||||
context.colorMask(true, true, true, true);
|
||||
context.depthMask(true);
|
||||
context.depthMask(false);
|
||||
renderer.clearDepth();
|
||||
|
||||
// only render where stencil is set to 1
|
||||
|
@ -117,8 +118,9 @@ export default class VectorTile extends Tile {
|
|||
this.xhrRequest.abort();
|
||||
}
|
||||
getSelectFeature(id) {
|
||||
const featureIndex = this.layerSource.originData.featureKeys[id];
|
||||
if (featureIndex) {
|
||||
const featurekey = this.layerSource.originData.featureKeys[id];
|
||||
if (featurekey && featurekey.index !== undefined) {
|
||||
const featureIndex = featurekey.index;
|
||||
return this.layerSource.originData.dataArray[featureIndex];
|
||||
}
|
||||
return null;
|
||||
|
@ -129,7 +131,5 @@ export default class VectorTile extends Tile {
|
|||
this._object3D = null;
|
||||
this.maskScene = null;
|
||||
this.layerData = null;
|
||||
this.layerSource.destroy();
|
||||
this.layerSource = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as turfMeta from '@turf/meta';
|
||||
import { getCoords } from '@turf/invariant';
|
||||
import { BKDRHash } from '../../util/bkdr-hash';
|
||||
import { djb2hash } from '../../util/bkdr-hash';
|
||||
export default function geoJSON(data, cfg) {
|
||||
const resultData = [];
|
||||
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;
|
||||
});
|
||||
// 数据为空时处理
|
||||
let i = 0;
|
||||
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
||||
const coord = getCoords(currentFeature);
|
||||
let id = featureIndex + 1;
|
||||
if (cfg.idField && currentFeature.properties[cfg.idField]) {
|
||||
const value = currentFeature.properties[cfg.idField];
|
||||
// id = value;
|
||||
id = BKDRHash(value) % 1000019;
|
||||
// if (featureKeys[id] && featureIndex !== featureKeys[id]) {
|
||||
// // TODO 哈希冲突解决方法
|
||||
// console.log('哈希冲突', value);
|
||||
// }
|
||||
id = djb2hash(value) % 1000019;
|
||||
featureKeys[id] = {
|
||||
index: i++,
|
||||
idField: value
|
||||
};
|
||||
}
|
||||
featureKeys[id] = featureIndex;
|
||||
const dataItem = {
|
||||
...currentFeature.properties,
|
||||
coordinates: coord,
|
||||
|
|
|
@ -16,19 +16,20 @@ export default function mvt(data, cfg) {
|
|||
if (geofeature.geometry.type === 'Polygon' && geofeature.geometry.coordinates[0].length < 20) {
|
||||
continue;
|
||||
}
|
||||
const newfc = {
|
||||
geometry: geofeature.geometry,
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
total: geofeature.properties.total,
|
||||
province: geofeature.properties.province,
|
||||
bc_grade: geofeature.properties.bc_grade
|
||||
}
|
||||
|
||||
};
|
||||
features.push(newfc);
|
||||
// const newfc = {
|
||||
// geometry: geofeature.geometry,
|
||||
// type: 'Feature',
|
||||
// properties: {
|
||||
// total: geofeature.properties.total,
|
||||
// province: geofeature.properties.province,
|
||||
// bc_grade: geofeature.properties.bc_grade,
|
||||
// code: geofeature.properties.code || geofeature.properties.adcode
|
||||
// }
|
||||
|
||||
// };
|
||||
features.push(geofeature);
|
||||
}
|
||||
// console.log(features);
|
||||
const geodata = {
|
||||
type: 'FeatureCollection',
|
||||
features
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,3 +14,16 @@ export function BKDRHash(str) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue