mirror of https://gitee.com/antv-l7/antv-l7
commit
75cc96e32a
|
@ -76,7 +76,7 @@ scene.on('loaded', () => {
|
||||||
circleLayer.setData(pointOnCircle(timestamp / 1000));
|
circleLayer.setData(pointOnCircle(timestamp / 1000));
|
||||||
requestAnimationFrame(animateMarker);
|
requestAnimationFrame(animateMarker);
|
||||||
}
|
}
|
||||||
animateMarker(0);
|
//animateMarker(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
const layerText = scene.PointLayer({
|
const layerText = scene.PointLayer({
|
||||||
|
|
|
@ -35,15 +35,15 @@ const scene = new L7.Scene({
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
scene.ImageTileLayer({
|
scene.ImageTileLayer({
|
||||||
zIndex:0
|
zIndex:4
|
||||||
})
|
})
|
||||||
.source('http://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}')
|
.source('http://t1.tianditu.com/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=174705aebfe31b79b3587279e211cb9a')
|
||||||
.render();
|
.render();
|
||||||
|
|
||||||
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/JToMOWvicvJOISZFCkEI.json', city => {
|
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/JToMOWvicvJOISZFCkEI.json', city => {
|
||||||
const citylayer = scene.PolygonLayer(
|
const citylayer = scene.PolygonLayer(
|
||||||
{
|
{
|
||||||
zIndex:4
|
zIndex:0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.source(city)
|
.source(city)
|
||||||
|
|
|
@ -34,6 +34,7 @@ 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:'point'
|
layerType:'point'
|
||||||
|
@ -46,25 +47,28 @@ scene.on('loaded', () => {
|
||||||
parser:{
|
parser:{
|
||||||
type: 'mvt',
|
type: 'mvt',
|
||||||
sourceLayer:'layer',
|
sourceLayer:'layer',
|
||||||
//idField:'OBJECTID',
|
// idField:'adcode',
|
||||||
maxZoom: 17,
|
maxZoom: 14,
|
||||||
|
minZoom: 13,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.scale({
|
.scale({
|
||||||
total:{
|
total:{
|
||||||
min:0,
|
min:0,
|
||||||
max:1000000,
|
max:100000,
|
||||||
type:'log'
|
type:'log'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// cylinder
|
.shape('normal')
|
||||||
.shape('hexagon')
|
.size(1)
|
||||||
.size(2)
|
|
||||||
.active({fill:'red'})
|
.active({fill:'red'})
|
||||||
.color('total', ['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'].reverse())
|
.color('total', ['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'].reverse())
|
||||||
//.color('#0D408C')
|
//.color('#0D408C')
|
||||||
.style({
|
.style({
|
||||||
opacity:1.0
|
stroke: 'rgba(255,255,255,0.8)',
|
||||||
|
strokeWidth: 1,
|
||||||
|
strokeOpacity:0.6,
|
||||||
|
opacity: 1
|
||||||
})
|
})
|
||||||
.render(
|
.render(
|
||||||
);
|
);
|
||||||
|
@ -73,10 +77,6 @@ scene.on('loaded', () => {
|
||||||
})
|
})
|
||||||
console.log(layer);
|
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>
|
||||||
|
|
|
@ -30,51 +30,66 @@ const scene = new L7.Scene({
|
||||||
center: [116.5909,39.9225 ],
|
center: [116.5909,39.9225 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
hash:true,
|
hash:true,
|
||||||
zoom: 14,
|
zoom: 4,
|
||||||
|
|
||||||
});
|
});
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
var colorHash = new ColorHash();
|
var colorHash = new ColorHash();
|
||||||
|
|
||||||
|
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
|
scene.ImageTileLayer({
|
||||||
|
zIndex:4
|
||||||
|
})
|
||||||
|
.source('http://t1.tianditu.com/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=174705aebfe31b79b3587279e211cb9a')
|
||||||
|
.render();
|
||||||
|
|
||||||
|
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: 5,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//
|
||||||
|
|
||||||
|
$.getJSON('https://gw.alipayobjects.com/os/basement_prod/b402ae15-c1ab-499b-834c-708e7c1a13be.json', city => {
|
||||||
|
|
||||||
|
const citylayer = scene.PolygonLayer()
|
||||||
|
.source(city)
|
||||||
|
.color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
|
||||||
|
.shape('line')
|
||||||
|
.size(2)
|
||||||
|
.active(true)
|
||||||
|
.style({
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
});
|
||||||
const layer = scene.VectorTileLayer({
|
const layer = scene.VectorTileLayer({
|
||||||
zIndex:0,
|
zIndex:0,
|
||||||
layerType:'polygon'
|
layerType:'polygon'
|
||||||
})
|
})
|
||||||
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
|
.source(provinceSource)
|
||||||
|
.scale({
|
||||||
// http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf
|
total:{
|
||||||
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
|
type:'linear',
|
||||||
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/{z}/{x}/{y}.pbf',{
|
min:0,
|
||||||
parser:{
|
max:5000000
|
||||||
type: 'mvt',
|
|
||||||
sourceLayer:'layer',
|
|
||||||
idField:'adcode',
|
|
||||||
maxZoom: 17,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//.scale()
|
|
||||||
// cylinder
|
|
||||||
.shape('fill')
|
.shape('fill')
|
||||||
.size(2)
|
.size(2)
|
||||||
.active({fill:'red'})
|
.active(false)
|
||||||
.color('name',name => {
|
.color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
|
||||||
//var colorHash = new ColorHash();
|
|
||||||
return colorHash.hex(name)
|
|
||||||
})
|
|
||||||
.style({
|
.style({
|
||||||
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>
|
||||||
|
|
|
@ -25,55 +25,49 @@
|
||||||
|
|
||||||
const scene = new L7.Scene({
|
const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
mapStyle: 'dark', // 样式URL
|
mapStyle: 'light', // 样式URL
|
||||||
center: [116.5909,39.9225 ],
|
center: [116.5909,39.9225 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
hash:true,
|
hash:true,
|
||||||
zoom: 14,
|
zoom: 16,
|
||||||
|
|
||||||
});
|
});
|
||||||
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:'heatmap'
|
layerType:'point'
|
||||||
})
|
})
|
||||||
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point2/{z}/{x}/{y}.pbf',{
|
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/all_point/{z}/{x}/{y}.pbf',{
|
||||||
parser:{
|
parser:{
|
||||||
type: 'mvt',
|
type: 'mvt',
|
||||||
sourceLayer:'layer',
|
sourceLayer:'layer',
|
||||||
maxZoom: 17,
|
maxZoom:14,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.scale({
|
.scale({
|
||||||
total:{
|
bc_grade:{
|
||||||
min:0,
|
type:'cat',
|
||||||
max:1000000,
|
values:[1, 2 ,3, 4]
|
||||||
type:'log'
|
},
|
||||||
|
open_mode:{
|
||||||
|
type:'cat',
|
||||||
|
values:['线上','线下','自助']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.shape('heatmap')
|
.active(false)
|
||||||
.size('total',[ 0, 1])
|
// 'circle', 'triangle', 'square', 'pentagon', 'hexagon', 'octogon', 'hexagram', 'rhombus', 'vesica'
|
||||||
|
.shape('open_mode', ['circle','hexagon','hexagram'])
|
||||||
|
.size('bc_grade', [2,15])
|
||||||
|
.color('bc_grade', ['#ffffcc','#d9f0a3','#addd8e','#78c679','#31a354','#006837'])
|
||||||
.style({
|
.style({
|
||||||
intensity: 10,
|
stroke: '#fff',
|
||||||
radius: 10,
|
strokeWidth: 1.0,
|
||||||
opacity:1,
|
strokeOpacity:1.,
|
||||||
rampColors: {
|
})
|
||||||
colors: [ '#ffda45ff', '#fde725ff', '#ffc934ff', '#ffb824ff', '#ffb824ff', '#fa8100ff' ],
|
|
||||||
positions: [ 0, 0.2, 0.4, 0.6, 0.9, 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>
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import { updateObjecteUniform } from '../../util/object3d-util';
|
||||||
|
export default class BufferController {
|
||||||
|
constructor(cfg) {
|
||||||
|
// defs 列定义
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
if (!this.mesh) this.mesh = this.layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateColorAttributes() {
|
||||||
|
const filterData = this.mesh.layerData;
|
||||||
|
const colorKey = {};
|
||||||
|
for (let e = 0; e < filterData.length; e++) {
|
||||||
|
const item = filterData[e];
|
||||||
|
colorKey[item.id] = item.color;
|
||||||
|
}
|
||||||
|
this.layer._activeIds = null; // 清空选中元素xwxw
|
||||||
|
const colorAttr = this.mesh.mesh.geometry.attributes.a_color;
|
||||||
|
const pickAttr = this.mesh.mesh.geometry.attributes.pickingId;
|
||||||
|
pickAttr.array.forEach((id, index) => {
|
||||||
|
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;
|
||||||
|
colorAttr.array[index * 4 + 2] = 0;
|
||||||
|
colorAttr.array[index * 4 + 3] = 0;
|
||||||
|
pickAttr.array[index] = -id; // 通过Id数据过滤 id<0 不显示
|
||||||
|
} else {
|
||||||
|
colorAttr.array[index * 4 + 0] = color[0];
|
||||||
|
colorAttr.array[index * 4 + 1] = color[1];
|
||||||
|
colorAttr.array[index * 4 + 2] = color[2];
|
||||||
|
colorAttr.array[index * 4 + 3] = color[3];
|
||||||
|
pickAttr.array[index] = id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
colorAttr.needsUpdate = true;
|
||||||
|
pickAttr.needsUpdate = true;
|
||||||
|
}
|
||||||
|
_updateStyle(option) {
|
||||||
|
const newOption = { };
|
||||||
|
for (const key in option) {
|
||||||
|
newOption['u_' + key] = option[key];
|
||||||
|
}
|
||||||
|
updateObjecteUniform(this.mesh._object3D, newOption);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
export default class EventContoller {
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
}
|
||||||
|
_init() {
|
||||||
|
this.layer.scene.on('pick-' + this.layer.layerId, e => {
|
||||||
|
let { featureId, point2d, type } = e;
|
||||||
|
if (featureId < 0 && this._activeIds !== null) {
|
||||||
|
type = 'mouseleave';
|
||||||
|
}
|
||||||
|
this._activeIds = featureId;
|
||||||
|
// TODO 瓦片图层获取选中数据信息
|
||||||
|
const lnglat = this.layer.scene.containerToLngLat(point2d);
|
||||||
|
const { feature, style } = this.layer.getSelectFeature(featureId, lnglat);
|
||||||
|
// const style = this.layerData[featureId - 1];
|
||||||
|
const target = {
|
||||||
|
featureId,
|
||||||
|
feature,
|
||||||
|
style,
|
||||||
|
pixel: point2d,
|
||||||
|
type,
|
||||||
|
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
||||||
|
};
|
||||||
|
if (featureId >= 0 || this._activeIds >= 0) { // 拾取到元素,或者离开元素
|
||||||
|
this.layer.emit(type, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_initMapEvent() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,14 @@
|
||||||
import Scale from './scale';
|
import Scale from './scale';
|
||||||
|
import Mapping from './mapping';
|
||||||
|
import Picking from './pick';
|
||||||
|
import Interaction from './interaction';
|
||||||
|
import Event from './event';
|
||||||
|
import Buffer from './buffer';
|
||||||
export default {
|
export default {
|
||||||
Scale
|
Scale,
|
||||||
|
Mapping,
|
||||||
|
Picking,
|
||||||
|
Interaction,
|
||||||
|
Event,
|
||||||
|
Buffer
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import { getInteraction } from '../../interaction/index';
|
||||||
|
export default class InteractionController {
|
||||||
|
constructor(cfg) {
|
||||||
|
// defs 列定义
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
}
|
||||||
|
// interaction 方法
|
||||||
|
clearAllInteractions() {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
Util.each(interactions, (interaction, key) => {
|
||||||
|
interaction.destory();
|
||||||
|
delete interactions[key];
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
clearInteraction(type) {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
delete interactions[type];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
addInteraction(type, cfg = {}) {
|
||||||
|
cfg.layer = this.layer;
|
||||||
|
const Ctor = getInteraction(type);
|
||||||
|
const interaction = new Ctor(cfg);
|
||||||
|
this._setInteraction(type, interaction);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
_setInteraction(type, interaction) {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
}
|
||||||
|
interactions[type] = interaction;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import Global from '../../global';
|
||||||
|
import ScaleController from './scale';
|
||||||
|
import Attr from '../../attr/index';
|
||||||
|
export default class Mapping {
|
||||||
|
/** 初始化mapping
|
||||||
|
* 初始化mapping
|
||||||
|
* @param {*} cfg 配置
|
||||||
|
* @param {*} cfg.layer layer对象
|
||||||
|
* @param {*} cfg.mesh mesh对象
|
||||||
|
*/
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
if (!this.mesh) this.mesh = this.layer;
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
_init() {
|
||||||
|
this._initControllers();
|
||||||
|
this._initTileAttrs();
|
||||||
|
this._mapping();
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.mesh.set('scales', {});
|
||||||
|
this._initTileAttrs();
|
||||||
|
this._updateMaping();
|
||||||
|
}
|
||||||
|
_initControllers() {
|
||||||
|
const scalesOption = this.layer.get('scaleOptions');
|
||||||
|
const scaleController = new ScaleController({
|
||||||
|
defs: {
|
||||||
|
...scalesOption
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.mesh.set('scaleController', scaleController);
|
||||||
|
}
|
||||||
|
_createScale(field) {
|
||||||
|
const scales = this.mesh.get('scales');
|
||||||
|
this._initControllers(); // scale更新
|
||||||
|
let scale = scales[field];
|
||||||
|
if (!scale) {
|
||||||
|
scale = this.createScale(field);
|
||||||
|
scales[field] = scale;
|
||||||
|
}
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
createScale(field) {
|
||||||
|
const data = this.mesh.layerSource.data.dataArray;
|
||||||
|
const scales = this.mesh.get('scales');
|
||||||
|
let scale = scales[field];
|
||||||
|
const scaleController = this.mesh.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.mesh.get('attrs');
|
||||||
|
const mappedData = [];
|
||||||
|
const data = this.mesh.layerSource.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 => {
|
||||||
|
if (item.filter === false) {
|
||||||
|
(item.color[3] = 0);
|
||||||
|
item.id = -item.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.mesh.layerData = mappedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据maping
|
||||||
|
* @param {*} layerSource 数据源
|
||||||
|
* @param {*} layer map
|
||||||
|
*/
|
||||||
|
_updateMaping() {
|
||||||
|
const attrs = this.mesh.get('attrs');
|
||||||
|
|
||||||
|
const data = this.mesh.layerSource.data.dataArray;
|
||||||
|
const layerData = this.mesh.layerData;
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const record = data[i];
|
||||||
|
for (const attrName in attrs) {
|
||||||
|
if (attrs.hasOwnProperty(attrName) && attrs[attrName].neadUpdate) {
|
||||||
|
const attr = attrs[attrName];
|
||||||
|
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];
|
||||||
|
layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||||
|
|
||||||
|
}
|
||||||
|
attr.neadUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_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.mesh.get('attrs');
|
||||||
|
const attrOptions = this.layer.get('attrOptions');
|
||||||
|
const option = attrOptions[type];
|
||||||
|
option.neadUpdate = true;
|
||||||
|
const className = Util.upperFirst(type);
|
||||||
|
const fields = this._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;
|
||||||
|
}
|
||||||
|
_parseFields(field) {
|
||||||
|
if (Util.isArray(field)) {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
if (Util.isString(field)) {
|
||||||
|
return field.split('*');
|
||||||
|
}
|
||||||
|
return [ field ];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import * as THREE from '../three';
|
||||||
|
import pickingFragmentShader from '../engine/picking/picking_frag.glsl';
|
||||||
|
import { updateObjecteUniform, destoryObject } from '../../util/object3d-util';
|
||||||
|
export default class PickContoller {
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
this.pickObject3D = new THREE.Object3D();
|
||||||
|
this.addToPicking(this.pickObject3D);
|
||||||
|
}
|
||||||
|
getPickingId() {
|
||||||
|
return this.layer.scene._engine._picking.getNextId();
|
||||||
|
}
|
||||||
|
addToPicking(object) {
|
||||||
|
object.name = this.layer.layerId;
|
||||||
|
this.layer.scene._engine._picking.add(object);
|
||||||
|
}
|
||||||
|
removePickingObject(object) {
|
||||||
|
this.layer.scene._engine._picking.remove(object);
|
||||||
|
}
|
||||||
|
removePickingMesh(mesh) {
|
||||||
|
this.pickObject3D.remove(mesh);
|
||||||
|
destoryObject(mesh);
|
||||||
|
}
|
||||||
|
removePickMeshByName(name) {
|
||||||
|
for (let i = 0; i < this.pickObject3D.children.length; i++) {
|
||||||
|
if (this.pickObject3D.children[i].name === name) {
|
||||||
|
this.removePickingMesh(this.pickObject3D.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeAllMesh() {
|
||||||
|
this.pickObject3D.children.forEach(element => {
|
||||||
|
|
||||||
|
this.pickObject3D.remove(element);
|
||||||
|
destoryObject(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
addPickMesh(mesh) {
|
||||||
|
const pickmaterial = mesh.material.clone();
|
||||||
|
pickmaterial.fragmentShader = pickingFragmentShader;
|
||||||
|
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
||||||
|
pickingMesh.name = mesh.name;
|
||||||
|
pickingMesh.onBeforeRender = () => {
|
||||||
|
const zoom = this.layer.scene.getZoom();
|
||||||
|
updateObjecteUniform(pickingMesh, { u_zoom: zoom });
|
||||||
|
};
|
||||||
|
this.pickObject3D.add(pickingMesh);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -7,9 +7,6 @@ import * as THREE from './three';
|
||||||
import ColorUtil from '../attr/color-util';
|
import ColorUtil from '../attr/color-util';
|
||||||
import Controller from './controller/index';
|
import Controller from './controller/index';
|
||||||
import source from './source';
|
import source from './source';
|
||||||
import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl';
|
|
||||||
import { getInteraction } from '../interaction/index';
|
|
||||||
import Attr from '../attr/index';
|
|
||||||
import diff from '../util/diff';
|
import diff from '../util/diff';
|
||||||
import { updateObjecteUniform } from '../util/object3d-util';
|
import { updateObjecteUniform } from '../util/object3d-util';
|
||||||
import Util from '../util';
|
import Util from '../util';
|
||||||
|
@ -24,7 +21,6 @@ function parseFields(field) {
|
||||||
}
|
}
|
||||||
return [ field ];
|
return [ field ];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Layer extends Base {
|
export default class Layer extends Base {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
return {
|
return {
|
||||||
|
@ -110,7 +106,7 @@ export default class Layer extends Base {
|
||||||
};
|
};
|
||||||
this._object3D.add(object);
|
this._object3D.add(object);
|
||||||
if (type === 'fill') {
|
if (type === 'fill') {
|
||||||
this._addPickMesh(object);// 不对边界线进行拾取
|
this.get('pickingController').addPickMesh(object);
|
||||||
}
|
}
|
||||||
setTimeout(() => this.scene._engine.update(), 500);
|
setTimeout(() => this.scene._engine.update(), 500);
|
||||||
}
|
}
|
||||||
|
@ -302,26 +298,14 @@ export default class Layer extends Base {
|
||||||
this._setAttrOptions(attrName, attrCfg);
|
this._setAttrOptions(attrName, attrCfg);
|
||||||
}
|
}
|
||||||
_initControllers() {
|
_initControllers() {
|
||||||
const scales = this.get('scaleOptions');
|
const mappingCtr = new Controller.Mapping({ layer: this });
|
||||||
const scaleController = new Controller.Scale({
|
const pickCtr = new Controller.Picking({ layer: this });
|
||||||
defs: {
|
const interactionCtr = new Controller.Interaction({ layer: this });
|
||||||
...scales
|
this.set('mappingController', mappingCtr);
|
||||||
}
|
this.set('pickingController', pickCtr);
|
||||||
});
|
this.set('interacionController', interactionCtr);
|
||||||
this.set('scaleController', scaleController);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createScale(field) {
|
|
||||||
const data = this.layerSource ? this.layerSource.data.dataArray : null;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
render() {
|
render() {
|
||||||
this.init();
|
this.init();
|
||||||
this.scene._engine.update();
|
this.scene._engine.update();
|
||||||
|
@ -330,20 +314,21 @@ export default class Layer extends Base {
|
||||||
// 重绘 度量, 映射,顶点构建
|
// 重绘 度量, 映射,顶点构建
|
||||||
repaint() {
|
repaint() {
|
||||||
this.set('scales', {});
|
this.set('scales', {});
|
||||||
this._initControllers();
|
const mappingCtr = new Controller.Mapping({ layer: this });
|
||||||
this._initAttrs();
|
this.set('mappingController', mappingCtr);
|
||||||
this._mapping();
|
// this._initAttrs();
|
||||||
|
// this._mapping();
|
||||||
this.redraw();
|
this.redraw();
|
||||||
}
|
}
|
||||||
// 初始化图层
|
// 初始化图层
|
||||||
init() {
|
init() {
|
||||||
this._initControllers();
|
this._initControllers();
|
||||||
this._initAttrs();
|
// this._initAttrs();
|
||||||
this._updateDraw();
|
this._updateDraw();
|
||||||
}
|
}
|
||||||
_initInteraction() {
|
_initInteraction() {
|
||||||
if (this.get('allowActive')) {
|
if (this.get('allowActive')) {
|
||||||
this.interaction('active');
|
this.get('interacionController').addInteraction('active');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_initMapEvent() {
|
_initMapEvent() {
|
||||||
|
@ -389,16 +374,6 @@ export default class Layer extends Base {
|
||||||
updateObjecteUniform(this._object3D, { u_activeId: featureId });
|
updateObjecteUniform(this._object3D, { u_activeId: featureId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_initAttrs() {
|
|
||||||
// 对比 options变化判断如何更新
|
|
||||||
const attrOptions = this.get('attrOptions');
|
|
||||||
for (const type in attrOptions) {
|
|
||||||
if (attrOptions.hasOwnProperty(type)) {
|
|
||||||
this._updateAttr(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_setPreOption() {
|
_setPreOption() {
|
||||||
const nextAttrs = this.get('attrOptions');
|
const nextAttrs = this.get('attrOptions');
|
||||||
const nextStyle = this.get('styleOptions');
|
const nextStyle = this.get('styleOptions');
|
||||||
|
@ -411,7 +386,7 @@ export default class Layer extends Base {
|
||||||
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._mapping();
|
||||||
this._setPreOption();
|
this._setPreOption();
|
||||||
this._scaleByZoom();
|
this._scaleByZoom();
|
||||||
this._initInteraction();
|
this._initInteraction();
|
||||||
|
@ -449,28 +424,6 @@ export default class Layer extends Base {
|
||||||
this._setPreOption();
|
this._setPreOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateAttr(type) {
|
|
||||||
const self = this;
|
|
||||||
const attrs = this.get('attrs');
|
|
||||||
const attrOptions = this.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;
|
|
||||||
}
|
|
||||||
_updateSize(zoom) {
|
_updateSize(zoom) {
|
||||||
const sizeOption = this.get('attrOptions').size;
|
const sizeOption = this.get('attrOptions').size;
|
||||||
const fields = parseFields(sizeOption.field);
|
const fields = parseFields(sizeOption.field);
|
||||||
|
@ -495,96 +448,6 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
updateObjecteUniform(this._object3D, newOption);
|
updateObjecteUniform(this._object3D, newOption);
|
||||||
}
|
}
|
||||||
_mapping(source) {
|
|
||||||
const self = this;
|
|
||||||
const attrs = self.get('attrs');
|
|
||||||
const mappedData = [];
|
|
||||||
// const data = this.layerSource.propertiesData;
|
|
||||||
let data;
|
|
||||||
source ? data = source.data.dataArray : data = this.layerSource.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 = self._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;
|
|
||||||
return mappedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新地图映射
|
|
||||||
_updateMaping(source, layer) {
|
|
||||||
const self = this;
|
|
||||||
const attrs = self.get('attrs');
|
|
||||||
|
|
||||||
const data = source ? source.data.dataArray : this.layerSource.data.dataArray;
|
|
||||||
const layerData = layer || this.layerData;
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
const record = data[i];
|
|
||||||
for (const attrName in attrs) {
|
|
||||||
if (attrs.hasOwnProperty(attrName) && attrs[attrName].neadUpdate) {
|
|
||||||
const attr = attrs[attrName];
|
|
||||||
const names = attr.names;
|
|
||||||
const values = self._getAttrValues(attr, record);
|
|
||||||
if (names.length > 1) { // position 之类的生成多个字段的属性
|
|
||||||
for (let j = 0; j < values.length; j++) {
|
|
||||||
const val = values[j];
|
|
||||||
const name = names[j];
|
|
||||||
layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
|
||||||
|
|
||||||
}
|
|
||||||
attr.neadUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取属性映射的值
|
|
||||||
_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;
|
|
||||||
}
|
|
||||||
_scaleByZoom() {
|
_scaleByZoom() {
|
||||||
if (this._zoomScale) {
|
if (this._zoomScale) {
|
||||||
this.map.on('zoomend', () => {
|
this.map.on('zoomend', () => {
|
||||||
|
@ -594,41 +457,18 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPickingId() {
|
|
||||||
return this.scene._engine._picking.getNextId();
|
|
||||||
}
|
|
||||||
addToPicking(object) {
|
|
||||||
this.scene._engine._picking.add(object);
|
|
||||||
}
|
|
||||||
removeFromPicking(object) {
|
|
||||||
this.scene._engine._picking.remove(object);
|
|
||||||
}
|
|
||||||
_addPickMesh(mesh) {
|
|
||||||
this._pickingMesh = new THREE.Object3D();
|
|
||||||
this._pickingMesh.name = this.layerId;
|
|
||||||
this.addToPicking(this._pickingMesh);
|
|
||||||
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();
|
|
||||||
updateObjecteUniform(pickingMesh, { u_zoom: zoom });
|
|
||||||
};
|
|
||||||
this._pickingMesh.add(pickingMesh);
|
|
||||||
|
|
||||||
}
|
|
||||||
_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;
|
||||||
// const style = this.layerData[featureId - 1];
|
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,
|
||||||
|
@ -637,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;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -656,7 +501,7 @@ export default class Layer extends Base {
|
||||||
* @param {*} object 更新颜色和数据过滤
|
* @param {*} object 更新颜色和数据过滤
|
||||||
*/
|
*/
|
||||||
_updateAttributes(object) {
|
_updateAttributes(object) {
|
||||||
this._updateMaping();
|
this.get('mappingController').update();
|
||||||
const filterData = this.layerData;
|
const filterData = this.layerData;
|
||||||
this._activeIds = null; // 清空选中元素
|
this._activeIds = null; // 清空选中元素
|
||||||
const colorAttr = object.geometry.attributes.a_color;
|
const colorAttr = object.geometry.attributes.a_color;
|
||||||
|
@ -694,13 +539,13 @@ export default class Layer extends Base {
|
||||||
offset = 5;
|
offset = 5;
|
||||||
this.shapeType = 'text' && (offset = 10);
|
this.shapeType = 'text' && (offset = 10);
|
||||||
|
|
||||||
} else if (this.type === 'polyline') {
|
} else if (this.type === 'polyline' || this.type === 'line') {
|
||||||
offset = 2;
|
offset = 2;
|
||||||
} else if (this.type === 'polygon') {
|
} else if (this.type === 'polygon') {
|
||||||
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;
|
||||||
|
@ -712,7 +557,7 @@ export default class Layer extends Base {
|
||||||
this._object3D.children.forEach(child => {
|
this._object3D.children.forEach(child => {
|
||||||
this._object3D.remove(child);
|
this._object3D.remove(child);
|
||||||
});
|
});
|
||||||
this.removeFromPicking(this._pickingMesh);
|
this.get('pickingController').removeAllMesh();
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
// 更新mesh
|
// 更新mesh
|
||||||
|
@ -720,37 +565,6 @@ export default class Layer extends Base {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// interaction 方法
|
|
||||||
clearAllInteractions() {
|
|
||||||
const interactions = this.get('interactions');
|
|
||||||
Util.each(interactions, (interaction, key) => {
|
|
||||||
interaction.destory();
|
|
||||||
delete interactions[key];
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
clearInteraction(type) {
|
|
||||||
const interactions = this.get('interactions');
|
|
||||||
if (interactions[type]) {
|
|
||||||
interactions[type].destory();
|
|
||||||
delete interactions[type];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
interaction(type, cfg = {}) {
|
|
||||||
cfg.layer = this;
|
|
||||||
const Ctor = getInteraction(type);
|
|
||||||
const interaction = new Ctor(cfg);
|
|
||||||
this._setInteraction(type, interaction);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
_setInteraction(type, interaction) {
|
|
||||||
const interactions = this.get('interactions');
|
|
||||||
if (interactions[type]) {
|
|
||||||
interactions[type].destory();
|
|
||||||
}
|
|
||||||
interactions[type] = interaction;
|
|
||||||
}
|
|
||||||
styleCfg() {
|
styleCfg() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
this._engine._picking.pickdata(e);
|
requestAnimationFrame(() => {
|
||||||
|
this._engine._picking.pickdata(e);
|
||||||
|
});
|
||||||
}, false);
|
}, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default class Source extends Base {
|
||||||
super(cfg);
|
super(cfg);
|
||||||
const transform = this.get('transforms');
|
const transform = this.get('transforms');
|
||||||
this._transforms = transform || [];
|
this._transforms = transform || [];
|
||||||
const mapType = this.get('mapType');
|
const mapType = this.get('mapType') || 'AMap';
|
||||||
this.projectFlat = getMap(mapType).project;
|
this.projectFlat = getMap(mapType).project;
|
||||||
// 数据解析
|
// 数据解析
|
||||||
this._init();
|
this._init();
|
||||||
|
@ -56,10 +56,13 @@ export default class Source extends Base {
|
||||||
const { type = 'geojson' } = parser;
|
const { type = 'geojson' } = parser;
|
||||||
const data = this.get('data');
|
const data = this.get('data');
|
||||||
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.extent = extent(this.data.dataArray);
|
this.data = this.originData;
|
||||||
|
if (this.data !== null) {
|
||||||
|
this.data.extent = extent(this.data.dataArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 数据统计
|
* 数据统计
|
||||||
|
@ -96,6 +99,9 @@ export default class Source extends Base {
|
||||||
this._projectCoords();
|
this._projectCoords();
|
||||||
}
|
}
|
||||||
_projectCoords() {
|
_projectCoords() {
|
||||||
|
if (this.data === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.data.dataArray.forEach(data => {
|
this.data.dataArray.forEach(data => {
|
||||||
// data.coordinates = this._coordProject(data.coordinates);
|
// data.coordinates = this._coordProject(data.coordinates);
|
||||||
data.coordinates = tranfrormCoord(data.coordinates, this._coorConvert.bind(this));
|
data.coordinates = tranfrormCoord(data.coordinates, this._coorConvert.bind(this));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as THREE from '../../core/three';
|
|
||||||
import Material from './material';
|
import Material from './material';
|
||||||
import { getModule } from '../../util/shaderModule';
|
import { getModule } from '../../util/shaderModule';
|
||||||
export default class PointMaterial extends Material {
|
export default class PointMaterial extends Material {
|
||||||
|
@ -26,7 +26,7 @@ export default class PointMaterial extends Material {
|
||||||
this.vertexShader = vs;
|
this.vertexShader = vs;
|
||||||
this.fragmentShader = fs;
|
this.fragmentShader = fs;
|
||||||
this.transparent = true;
|
this.transparent = true;
|
||||||
if (!this.uniforms.shape) { this.blending = THREE.AdditiveBlending; }
|
// if (!this.uniforms.shape) { this.blending = THREE.AdditiveBlending; }
|
||||||
if (this.uniforms.u_texture) {
|
if (this.uniforms.u_texture) {
|
||||||
this.defines.TEXCOORD_0 = true;
|
this.defines.TEXCOORD_0 = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +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);
|
||||||
worldId = id_toPickColor(pickingId);
|
worldId = id_toPickColor(pickingId);
|
||||||
}
|
}
|
|
@ -33,6 +33,7 @@ void main() {
|
||||||
float extrude_scale = pow(2.0, 20.0 - u_zoom);
|
float extrude_scale = pow(2.0, 20.0 - u_zoom);
|
||||||
vec3 offset = vec3(normal * a_size * extrude_scale / 2.0 * a_miter);
|
vec3 offset = vec3(normal * a_size * extrude_scale / 2.0 * a_miter);
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy + offset.xy, 0., 1.0);
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy + offset.xy, 0., 1.0);
|
||||||
|
// gl_Position.z -=0.8 * gl_Position.w;
|
||||||
|
|
||||||
#ifdef ANIMATE
|
#ifdef ANIMATE
|
||||||
float alpha =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
|
float alpha =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -41,11 +41,15 @@ export default class PointLayer extends Layer {
|
||||||
}
|
}
|
||||||
zoomchange(ev) {
|
zoomchange(ev) {
|
||||||
super.zoomchange(ev);
|
super.zoomchange(ev);
|
||||||
this._updateData();
|
requestAnimationFrame(() => {
|
||||||
|
this._updateData();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
dragend(ev) {
|
dragend(ev) {
|
||||||
super.dragend(ev);
|
super.dragend(ev);
|
||||||
this._updateData();
|
requestAnimationFrame(() => {
|
||||||
|
this._updateData();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
_updateData() {
|
_updateData() {
|
||||||
|
|
|
@ -25,5 +25,8 @@ export default function drawCircle(layerData, layer) {
|
||||||
});
|
});
|
||||||
material.depthTest = false;
|
material.depthTest = false;
|
||||||
const fillMesh = new THREE.Mesh(geometry, material);
|
const fillMesh = new THREE.Mesh(geometry, material);
|
||||||
|
aPosition.length = 0;
|
||||||
|
aPackedData.length = 0;
|
||||||
|
index.length = 0;
|
||||||
return fillMesh;
|
return fillMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ export default function DrawPolygonFill(layerData, layer) {
|
||||||
LIGHTING: true
|
LIGHTING: true
|
||||||
});
|
});
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ export default class ImageTile extends Tile {
|
||||||
const image = this._createDebugMesh();
|
const image = this._createDebugMesh();
|
||||||
this._createMesh(image);
|
this._createMesh(image);
|
||||||
this.emit('tileLoaded');
|
this.emit('tileLoaded');
|
||||||
// return;
|
|
||||||
// const urlParams = {
|
// const urlParams = {
|
||||||
// x: this._tile[0],
|
// x: this._tile[0],
|
||||||
// y: this._tile[1],
|
// y: this._tile[1],
|
||||||
|
@ -29,12 +28,10 @@ export default class ImageTile extends Tile {
|
||||||
// image.addEventListener('load', () => {
|
// image.addEventListener('load', () => {
|
||||||
// this._isLoaded = true;
|
// this._isLoaded = true;
|
||||||
// this._createMesh(image);
|
// this._createMesh(image);
|
||||||
|
// this.emit('tileLoaded');
|
||||||
// this._ready = true;
|
// this._ready = true;
|
||||||
// }, false);
|
// }, false);
|
||||||
|
|
||||||
// // image.addEventListener('progress', event => {}, false);
|
|
||||||
// // image.addEventListener('error', event => {}, false);
|
|
||||||
|
|
||||||
// image.crossOrigin = '';
|
// image.crossOrigin = '';
|
||||||
|
|
||||||
// // Load image
|
// // Load image
|
||||||
|
@ -73,6 +70,7 @@ export default class ImageTile extends Tile {
|
||||||
context.font = 'Bold 20px Helvetica Neue, Verdana, Arial';
|
context.font = 'Bold 20px Helvetica Neue, Verdana, Arial';
|
||||||
context.fillStyle = '#ff0000';
|
context.fillStyle = '#ff0000';
|
||||||
context.fillText(this._tile.join('/'), 20, 20);
|
context.fillText(this._tile.join('/'), 20, 20);
|
||||||
|
context.strokeStyle = 'red';
|
||||||
context.rect(0, 0, 256, 256);
|
context.rect(0, 0, 256, 256);
|
||||||
context.stroke();
|
context.stroke();
|
||||||
return canvas;
|
return canvas;
|
||||||
|
@ -83,6 +81,9 @@ export default class ImageTile extends Tile {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._image.src = '';
|
this._image.src = '';
|
||||||
|
}
|
||||||
|
updateColor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
getSelectFeature() {
|
getSelectFeature() {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -2,6 +2,10 @@ import TileLayer from './tileLayer';
|
||||||
import ImageTile from './imageTile';
|
import ImageTile from './imageTile';
|
||||||
|
|
||||||
export default class ImageTileLayer extends TileLayer {
|
export default class ImageTileLayer extends TileLayer {
|
||||||
|
constructor(scene, cfg) {
|
||||||
|
super(scene, cfg);
|
||||||
|
this.type = 'image';
|
||||||
|
}
|
||||||
_createTile(key, layer) {
|
_createTile(key, layer) {
|
||||||
return new ImageTile(key, this.url, layer);
|
return new ImageTile(key, this.url, layer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,9 @@ import * as THREE from '../../core/three';
|
||||||
import Base from '../../core/base';
|
import Base from '../../core/base';
|
||||||
import { destoryObject } from '../../util/object3d-util';
|
import { destoryObject } from '../../util/object3d-util';
|
||||||
import Controller from '../../core/controller/index';
|
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) {
|
|
||||||
if (Util.isArray(field)) {
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
if (Util.isString(field)) {
|
|
||||||
return field.split('*');
|
|
||||||
}
|
|
||||||
return [ field ];
|
|
||||||
}
|
|
||||||
export default class Tile extends Base {
|
export default class Tile extends Base {
|
||||||
constructor(key, url, layer) {
|
constructor(key, url, layer) {
|
||||||
super({
|
super({
|
||||||
|
@ -33,134 +21,52 @@ export default class Tile extends Base {
|
||||||
this._center = this._tileBounds.getCenter();
|
this._center = this._tileBounds.getCenter();
|
||||||
|
|
||||||
this._centerLnglat = this._tileLnglatBounds.getCenter();
|
this._centerLnglat = this._tileLnglatBounds.getCenter();
|
||||||
this._object3D = new THREE.Object3D();
|
this._object3D = new THREE.Object3D({ name: key });
|
||||||
|
this._object3D.frustumCulled = false;
|
||||||
|
// this._object3D.name = key;
|
||||||
this._object3D.onBeforeRender = () => {
|
this._object3D.onBeforeRender = () => {
|
||||||
};
|
};
|
||||||
this._isLoaded = false;
|
this._isLoaded = false;
|
||||||
this.requestTileAsync(data => this._init(data));
|
this.requestTileAsync(data => this._init(data));
|
||||||
}
|
}
|
||||||
_init(data) {
|
_init(data) {
|
||||||
|
// this._creatSource(data); // 获取Source
|
||||||
|
this.layerSource = data;
|
||||||
|
|
||||||
|
if (this.layerSource.data === null) {
|
||||||
|
this.isValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isValid = true;
|
||||||
this._initControllers();
|
this._initControllers();
|
||||||
this._creatSource(data);
|
|
||||||
this._initTileAttrs();
|
|
||||||
this._mapping();
|
|
||||||
this._createMesh();
|
this._createMesh();
|
||||||
}
|
}
|
||||||
_initControllers() {
|
repaint() {
|
||||||
const scales = this.layer.get('scaleOptions');
|
this._initControllers();
|
||||||
const scaleController = new Controller.Scale({
|
this._createMesh();
|
||||||
defs: {
|
|
||||||
...scales
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.set('scaleController', scaleController);
|
|
||||||
}
|
}
|
||||||
_createScale(field) {
|
requestTileAsync(done) {
|
||||||
// TODO scale更新
|
const data = this.layer.tileSource.getTileData(this._tile[0], this._tile[1], this._tile[2]);
|
||||||
const scales = this.get('scales');
|
if (data.loaded) {
|
||||||
let scale = scales[field];
|
done(data.data);
|
||||||
if (!scale) {
|
} else {
|
||||||
scale = this.createScale(field);
|
data.data.then(data => {
|
||||||
scales[field] = scale;
|
done(data);
|
||||||
}
|
|
||||||
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() {
|
_initControllers() {
|
||||||
const attrOptions = this.layer.get('attrOptions');
|
const mappingCtr = new Controller.Mapping({
|
||||||
for (const type in attrOptions) {
|
layer: this.layer,
|
||||||
if (attrOptions.hasOwnProperty(type)) {
|
mesh: this
|
||||||
this._updateTileAttr(type);
|
});
|
||||||
}
|
const bufferCtr = new Controller.Buffer({
|
||||||
}
|
layer: this.layer,
|
||||||
}
|
mesh: this
|
||||||
_updateTileAttr(type) {
|
});
|
||||||
const self = this;
|
this.set('mappingController', mappingCtr);
|
||||||
const attrs = this.get('attrs');
|
this.set('bufferController', bufferCtr);
|
||||||
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) {
|
||||||
|
@ -222,6 +128,15 @@ export default class Tile extends Base {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
updateColor() {
|
||||||
|
const bufferCtr = this.get('bufferController');
|
||||||
|
this.get('mappingController').update();
|
||||||
|
bufferCtr._updateColorAttributes(this.getMesh().children[0]);
|
||||||
|
}
|
||||||
|
updateStyle() {
|
||||||
|
const bufferCtr = this.get('bufferController');
|
||||||
|
bufferCtr._updateStyle(this.getMesh().children[0]);
|
||||||
|
}
|
||||||
_preRender() {
|
_preRender() {
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|
|
@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import Layer from '../../core/layer';
|
import Layer from '../../core/layer';
|
||||||
import source from '../../core/source';
|
import Util from '../../util';
|
||||||
|
import diff from '../../util/diff';
|
||||||
|
import TileSource from '../../source/tileSource';
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
|
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 pickingFragmentShader from '../../core/engine/picking/picking_frag.glsl';
|
|
||||||
import { throttle, 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';
|
||||||
|
@ -13,17 +14,17 @@ export default class TileLayer extends Layer {
|
||||||
constructor(scene, cfg) {
|
constructor(scene, cfg) {
|
||||||
super(scene, {
|
super(scene, {
|
||||||
...cfg,
|
...cfg,
|
||||||
|
minSourceZoom: 0,
|
||||||
|
maxSOurceZoom: 18,
|
||||||
keepBuffer: 2
|
keepBuffer: 2
|
||||||
});
|
});
|
||||||
this._tileCache = new TileCache(100, 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._tiles.frustumCulled = false;
|
||||||
this._tileKeys = [];
|
this._tileKeys = [];
|
||||||
this.tileList = {};
|
this.tileList = {};
|
||||||
|
this.type = this.get('layerType');
|
||||||
}
|
}
|
||||||
shape(field, values) {
|
shape(field, values) {
|
||||||
const layerType = this.get('layerType');
|
const layerType = this.get('layerType');
|
||||||
|
@ -33,62 +34,78 @@ 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;
|
||||||
|
} else {
|
||||||
|
cfg.mapType = this.scene.mapType;
|
||||||
|
this.tileSource = new TileSource(data, cfg);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
tileSource(data, cfg) {
|
_initControllers() {
|
||||||
if (data instanceof source) {
|
const pickCtr = new Controller.Picking({ layer: this });
|
||||||
return data;
|
const interactionCtr = new Controller.Interaction({ layer: this });
|
||||||
}
|
this.set('pickingController', pickCtr);
|
||||||
const tileSourceCfg = {
|
this.set('interacionController', interactionCtr);
|
||||||
data,
|
|
||||||
zoom: this.scene.getZoom()
|
|
||||||
};
|
|
||||||
deepMix(tileSourceCfg, this.sourceCfg, cfg);
|
|
||||||
return new source(tileSourceCfg);
|
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
// this._initControllers();
|
this._visibleWithZoom();
|
||||||
this._initMapEvent();
|
this._updateDraw();
|
||||||
// this._initAttrs();
|
this.scene._engine.update();
|
||||||
this._initInteraction();
|
|
||||||
this.draw();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
draw() {
|
draw() {
|
||||||
this._object3D.add(this._tiles);
|
this._object3D.add(this._tiles);
|
||||||
this._calculateLOD();
|
this._calculateLOD();
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTile() {
|
drawTile() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomchange(ev) {
|
zoomchange(ev) {
|
||||||
super.zoomchange(ev);
|
super.zoomchange(ev);
|
||||||
throttle(this._calculateLOD, 200);
|
this._visibleWithZoom();
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this._calculateLOD();
|
||||||
|
});
|
||||||
this._calculateLOD();
|
this._calculateLOD();
|
||||||
}
|
}
|
||||||
|
|
||||||
dragend(ev) {
|
dragend(ev) {
|
||||||
super.dragend(ev);
|
super.dragend(ev);
|
||||||
this._calculateLOD();
|
requestAnimationFrame(() => {
|
||||||
|
this._calculateLOD();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_calculateLOD() {
|
_calculateLOD() {
|
||||||
/**
|
/**
|
||||||
* 加载完成 active
|
* 加载完成 active
|
||||||
* 需要显示 current
|
* 需要显示 current
|
||||||
* 是否保留 retain
|
* 是否保留 retain
|
||||||
*/
|
*/
|
||||||
|
const zoom = Math.floor(this.scene.getZoom()) - 1;
|
||||||
|
const minZoom = this.get('minZoom');
|
||||||
|
const maxZoom = this.get('maxZoom');
|
||||||
|
const minSourceZoom = this.tileSource.get('minSourceZoom');
|
||||||
|
const maxSourceZoom = this.tileSource.get('maxSourceZoom');
|
||||||
|
const currentZoom = this.scene.getZoom();
|
||||||
|
this.tileZoom = zoom > maxSourceZoom ? maxSourceZoom : zoom;
|
||||||
|
if (currentZoom < minZoom || currentZoom >= maxZoom || currentZoom < minSourceZoom) {
|
||||||
|
this._removeTiles();
|
||||||
|
this._object3D.visible = false;
|
||||||
|
return;
|
||||||
|
} else if (this.get('visible')) {
|
||||||
|
this._object3D.visible = true;
|
||||||
|
}
|
||||||
|
this.show();
|
||||||
this.updateTileList = [];
|
this.updateTileList = [];
|
||||||
const zoom = Math.round(this.scene.getZoom()) - 1;
|
|
||||||
const center = this.scene.getCenter();
|
const center = this.scene.getCenter();
|
||||||
const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), zoom);
|
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');
|
||||||
|
@ -100,7 +117,7 @@ export default class TileLayer extends Layer {
|
||||||
isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
|
isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
|
||||||
for (let j = tileRange.min.y; j <= tileRange.max.y; j++) {
|
for (let j = tileRange.min.y; j <= tileRange.max.y; j++) {
|
||||||
for (let i = tileRange.min.x; i <= tileRange.max.x; i++) {
|
for (let i = tileRange.min.x; i <= tileRange.max.x; i++) {
|
||||||
const coords = [ i, j, zoom ];
|
const coords = [ i, j, this.tileZoom ];
|
||||||
const tile = this.tileList[coords.join('_')];
|
const tile = this.tileList[coords.join('_')];
|
||||||
if (tile) {
|
if (tile) {
|
||||||
tile.current = true;
|
tile.current = true;
|
||||||
|
@ -140,10 +157,9 @@ export default class TileLayer extends Layer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (pointShape['2d'].indexOf(shape) !== -1) {
|
||||||
pointShape['2d'].indexOf(shape) !== -1 ||
|
return 'circle';
|
||||||
pointShape['3d'].indexOf(shape) !== -1
|
} else if (pointShape['3d'].indexOf(shape) !== -1) {
|
||||||
) {
|
|
||||||
return 'fill';
|
return 'fill';
|
||||||
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
|
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
|
||||||
return 'image';
|
return 'image';
|
||||||
|
@ -198,6 +214,10 @@ export default class TileLayer extends Layer {
|
||||||
this._pruneTiles();
|
this._pruneTiles();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (tile.needUpdate) {
|
||||||
|
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());
|
||||||
|
@ -207,23 +227,20 @@ export default class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_addPickTile(meshobj) {
|
_addPickTile(meshobj) {
|
||||||
|
if (this.type === 'image') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pickCtr = this.get('pickingController');
|
||||||
const mesh = meshobj.children[0];
|
const mesh = meshobj.children[0];
|
||||||
const pickmaterial = mesh.material.clone();
|
mesh.name = meshobj.name;
|
||||||
pickmaterial.fragmentShader = pickingFragmentShader;
|
pickCtr.addPickMesh(mesh);
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// 根据距离优先级查找
|
// 根据距离优先级查找
|
||||||
getSelectFeature(id, lnglat) {
|
getSelectFeature(id, lnglat) {
|
||||||
const zoom = Math.round(this.scene.getZoom()) - 1;
|
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;
|
||||||
|
@ -231,7 +248,7 @@ export default class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
_pruneTiles() {
|
_pruneTiles() {
|
||||||
let tile;
|
let tile;
|
||||||
const zoom = Math.round(this.scene.getZoom()) - 1;
|
const zoom = this.tileZoom;
|
||||||
for (const key in this.tileList) {
|
for (const key in this.tileList) {
|
||||||
const c = this.tileList[key].coords;
|
const c = this.tileList[key].coords;
|
||||||
if (c[2] !== zoom || !this.noPruneRange.contains(new Point(c[0], c[1]))) {
|
if (c[2] !== zoom || !this.noPruneRange.contains(new Point(c[0], c[1]))) {
|
||||||
|
@ -298,6 +315,8 @@ export default class TileLayer extends Layer {
|
||||||
const tileObj = this._tileCache.getTile(key);
|
const tileObj = this._tileCache.getTile(key);
|
||||||
if (tileObj) {
|
if (tileObj) {
|
||||||
tileObj._abortRequest();
|
tileObj._abortRequest();
|
||||||
|
const pickCtr = this.get('pickingController');
|
||||||
|
pickCtr && pickCtr.removePickMeshByName(tileObj.getMesh().name);
|
||||||
this._tiles.remove(tileObj.getMesh());
|
this._tiles.remove(tileObj.getMesh());
|
||||||
}
|
}
|
||||||
if (tileObj && tileObj.getMesh().type === 'composer') {
|
if (tileObj && tileObj.getMesh().type === 'composer') {
|
||||||
|
@ -316,11 +335,13 @@ export default class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} // 移除 空的geom
|
} // 移除 空的geom
|
||||||
|
|
||||||
this.scene._engine.update();
|
this.scene._engine.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_removeTiles() {
|
_removeTiles() {
|
||||||
|
this.hide();
|
||||||
if (!this._tiles || !this._tiles.children) {
|
if (!this._tiles || !this._tiles.children) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,12 +349,17 @@ export default class TileLayer extends Layer {
|
||||||
for (let i = this._tiles.children.length - 1; i >= 0; i--) {
|
for (let i = this._tiles.children.length - 1; i >= 0; i--) {
|
||||||
this._tiles.remove(this._tiles.children[i]);
|
this._tiles.remove(this._tiles.children[i]);
|
||||||
}
|
}
|
||||||
|
this.tileList = [];
|
||||||
|
this._tileKeys = [];
|
||||||
|
this._tileCache.destory();
|
||||||
|
const pickCtr = this.get('pickingController');
|
||||||
|
pickCtr.removeAllMesh();
|
||||||
}
|
}
|
||||||
_getPixelBounds() {
|
_getPixelBounds() {
|
||||||
const viewPort = this.scene.getBounds().toBounds();
|
const viewPort = this.scene.getBounds().toBounds();
|
||||||
const NE = viewPort.getNorthEast();
|
const NE = viewPort.getNorthEast();
|
||||||
const SW = viewPort.getSouthWest();
|
const SW = viewPort.getSouthWest();
|
||||||
const zoom = Math.round(this.scene.getZoom()) - 1;
|
const zoom = this.tileZoom;
|
||||||
const center = this.scene.getCenter();
|
const center = this.scene.getCenter();
|
||||||
const NEPoint = this._crs.lngLatToPoint(toLngLat(NE.lng, NE.lat), zoom);
|
const NEPoint = this._crs.lngLatToPoint(toLngLat(NE.lng, NE.lat), zoom);
|
||||||
const SWPoint = this._crs.lngLatToPoint(toLngLat(SW.lng, SW.lat), zoom);
|
const SWPoint = this._crs.lngLatToPoint(toLngLat(SW.lng, SW.lat), zoom);
|
||||||
|
@ -374,6 +400,59 @@ export default class TileLayer extends Layer {
|
||||||
tile.destroy();
|
tile.destroy();
|
||||||
tile = null;
|
tile = null;
|
||||||
}
|
}
|
||||||
|
_updateDraw() {
|
||||||
|
const preAttrs = this.get('preAttrOptions');
|
||||||
|
const nextAttrs = this.get('attrOptions');
|
||||||
|
const preStyle = this.get('preStyleOption');
|
||||||
|
const nextStyle = this.get('styleOptions');
|
||||||
|
if (preAttrs === undefined && preStyle === undefined) { // 首次渲染
|
||||||
|
this._setPreOption();
|
||||||
|
this._scaleByZoom();
|
||||||
|
this._initControllers();
|
||||||
|
this._initInteraction();
|
||||||
|
this._initMapEvent();
|
||||||
|
this.draw();
|
||||||
|
this._setPreOption();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this._tiles.children.length > 0 || !this._object3D.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 更新数据颜色 过滤 filter
|
||||||
|
if (!Util.isEqual(preAttrs.color, nextAttrs.color) || !Util.isEqual(preAttrs.filter, nextAttrs.filter)) {
|
||||||
|
this._tileCache.setNeedUpdate();
|
||||||
|
this._tiles.children.forEach(tile => {
|
||||||
|
const tileObj = this._tileCache.getTile(tile.name);
|
||||||
|
tileObj.updateColor();
|
||||||
|
tileObj.needUpdate = false;
|
||||||
|
this.scene._engine.update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 更新Size
|
||||||
|
if (!Util.isEqual(preAttrs.size, nextAttrs.size)) {
|
||||||
|
// this._tiles.children(tile => {
|
||||||
|
// this._tileCache.get(tile.name).updateSize();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
// 更新形状
|
||||||
|
if (!Util.isEqual(preAttrs.shape, nextAttrs.shape)) {
|
||||||
|
// this._tiles.children(tile => {
|
||||||
|
// this._tileCache.get(tile.name).updateShape();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
if (!Util.isEqual(preStyle, nextStyle)) {
|
||||||
|
// 判断新增,修改,删除
|
||||||
|
const newStyle = {};
|
||||||
|
Util.each(diff(preStyle, nextStyle), ({ type, key, value }) => {
|
||||||
|
(type !== 'remove') && (newStyle[key] = value);
|
||||||
|
// newStyle[key] = type === 'remove' ? null : value;
|
||||||
|
});
|
||||||
|
this._tiles.children(tile => {
|
||||||
|
this._tileCache.get(tile.name).updateStyle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._setPreOption();
|
||||||
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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],
|
||||||
|
@ -32,31 +32,35 @@ export default class VectorTile extends Tile {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_creatSource(data) {
|
_creatSource(data) {
|
||||||
this.source = this.layer.tileSource(data, {
|
if (!data) return null;
|
||||||
|
this.layerSource = this.layer.tileSource(data, {
|
||||||
parser: {
|
parser: {
|
||||||
tile: this._tile
|
tile: this._tile
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_createMesh() {
|
_createMesh() {
|
||||||
|
const layerData = this.layerData;
|
||||||
if (this.layer.get('layerType') === 'point') {
|
if (this.layer.get('layerType') === 'point') {
|
||||||
this.layer.shape = this.layer._getShape(this.layerData);
|
this.layer.shape = this.layer._getShape(layerData);
|
||||||
}
|
}
|
||||||
this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(this.layerData, this.layer);
|
this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(layerData, this.layer);
|
||||||
if (this.mesh.type !== 'composer') { // 热力图的情况
|
if (this.mesh.type !== 'composer') { // 热力图的情况
|
||||||
this.mesh.onBeforeRender = renderer => {
|
this.mesh.onBeforeRender = renderer => {
|
||||||
this._renderMask(renderer);
|
this._renderMask(renderer);
|
||||||
};
|
};
|
||||||
this.mesh.onAfterRender = renderer => {
|
this.mesh.onAfterRender = renderer => {
|
||||||
const context = renderer.context;
|
const context = renderer.context;
|
||||||
|
context.clear(context.STENCIL_BUFFER_BIT);
|
||||||
context.disable(context.STENCIL_TEST);
|
context.disable(context.STENCIL_TEST);
|
||||||
};
|
};
|
||||||
this._object3D.add(this.mesh);
|
this._object3D.add(this.mesh);
|
||||||
} 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) {
|
||||||
|
@ -85,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
|
||||||
|
@ -114,9 +118,10 @@ export default class VectorTile extends Tile {
|
||||||
this.xhrRequest.abort();
|
this.xhrRequest.abort();
|
||||||
}
|
}
|
||||||
getSelectFeature(id) {
|
getSelectFeature(id) {
|
||||||
const featureIndex = this.source.originData.featureKeys[id];
|
const featurekey = this.layerSource.originData.featureKeys[id];
|
||||||
if (featureIndex) {
|
if (featurekey && featurekey.index !== undefined) {
|
||||||
return this.source.originData.dataArray[featureIndex];
|
const featureIndex = featurekey.index;
|
||||||
|
return this.layerSource.originData.dataArray[featureIndex];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -126,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.source.destroy();
|
|
||||||
this.source = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,8 @@ class Linear extends Base {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const percent = (value - min) / (max - min);
|
const percent = Math.min(1, Math.max(0, (value - min) / (max - min))); // 数据控制到 0-1 范围
|
||||||
|
// const percent = (value - min) / (max - min);
|
||||||
const rangeMin = this.rangeMin();
|
const rangeMin = this.rangeMin();
|
||||||
const rangeMax = this.rangeMax();
|
const rangeMax = this.rangeMax();
|
||||||
return rangeMin + percent * (rangeMax - rangeMin);
|
return rangeMin + percent * (rangeMax - rangeMin);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -3,17 +3,24 @@ import * as VectorParser from '@mapbox/vector-tile';
|
||||||
import geojson from './geojson';
|
import geojson from './geojson';
|
||||||
export default function mvt(data, cfg) {
|
export default function mvt(data, cfg) {
|
||||||
const tile = new VectorParser.VectorTile(new PBF(data));
|
const tile = new VectorParser.VectorTile(new PBF(data));
|
||||||
// CHN_Cities_L CHN_Cities CHN_L
|
|
||||||
const layerName = cfg.sourceLayer;
|
const layerName = cfg.sourceLayer;
|
||||||
const features = [];
|
const features = [];
|
||||||
const vectorLayer = tile.layers[layerName];
|
const vectorLayer = tile.layers[layerName];
|
||||||
|
if (vectorLayer === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
for (let i = 0; i < vectorLayer.length; i++) {
|
for (let i = 0; i < vectorLayer.length; i++) {
|
||||||
const feature = vectorLayer.feature(i);
|
const feature = vectorLayer.feature(i);
|
||||||
features.push(feature.toGeoJSON(cfg.tile[0], cfg.tile[1], cfg.tile[2]));
|
const geofeature = feature.toGeoJSON(cfg.tile[0], cfg.tile[1], cfg.tile[2]);
|
||||||
|
if (geofeature.geometry.type === 'Polygon' && geofeature.geometry.coordinates[0].length < 20) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
features.push(geofeature);
|
||||||
}
|
}
|
||||||
|
// console.log(features);
|
||||||
const geodata = {
|
const geodata = {
|
||||||
type: 'FeatureCollection',
|
type: 'FeatureCollection',
|
||||||
features
|
features
|
||||||
};
|
};
|
||||||
return geojson(geodata, cfg);
|
return features.length === 0 ? null : geojson(geodata, cfg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 || !tile.data.data.dataArray) {
|
||||||
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -9,10 +9,14 @@ export default class LRUCache {
|
||||||
constructor(limit = 50, destroy = () => {}) {
|
constructor(limit = 50, destroy = () => {}) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
this.destroy = destroy;
|
this.destroy = destroy;
|
||||||
|
this._order = [];
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
this._order.forEach(key => {
|
||||||
|
this.delete(key);
|
||||||
|
});
|
||||||
this._cache = {};
|
this._cache = {};
|
||||||
// access/update order, first item is oldest, last item is newest
|
// access/update order, first item is oldest, last item is newest
|
||||||
this._order = [];
|
this._order = [];
|
||||||
|
|
|
@ -88,7 +88,28 @@ export default function(points, closed, indexOffset) {
|
||||||
|
|
||||||
// get orientation
|
// get orientation
|
||||||
let flip = (dot(tangent, _normal) < 0) ? -1 : 1;
|
let flip = (dot(tangent, _normal) < 0) ? -1 : 1;
|
||||||
const bevel = miterLen > miterLimit;
|
const bevel = Math.abs(miterLen) > miterLimit;
|
||||||
|
|
||||||
|
// 处理前后两条线段重合的情况,这种情况不需要使用任何接头(miter/bevel)。
|
||||||
|
// 理论上这种情况下 miterLen = Infinity,本应通过 isFinite(miterLen) 判断,
|
||||||
|
// 但是 AMap 投影变换后丢失精度,只能通过一个阈值(1000)判断。
|
||||||
|
if (Math.abs(miterLen) > 1000) {
|
||||||
|
normal(_normal, lineA);
|
||||||
|
extrusions(attrPos, out, cur, _normal, 1);
|
||||||
|
attrDistance.push(d, d);
|
||||||
|
attrIndex.push(
|
||||||
|
_lastFlip === 1 ? [ index + 1, index + 3, index + 2 ]
|
||||||
|
: [ index, index + 2, index + 3 ]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 避免在 Material 中使用 THREE.DoubleSide
|
||||||
|
attrIndex.push([ index + 2, index + 3, index + 4 ]);
|
||||||
|
|
||||||
|
count += 2;
|
||||||
|
_lastFlip = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (bevel) {
|
if (bevel) {
|
||||||
miterLen = miterLimit;
|
miterLen = miterLimit;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue