2018-10-23 19:32:42 +08:00
|
|
|
/**
|
|
|
|
* @fileOverview Layer基类
|
|
|
|
* @author lzx199065@gmail.com
|
|
|
|
*/
|
|
|
|
import Base from './base';
|
|
|
|
import * as THREE from './three';
|
|
|
|
import ColorUtil from '../attr/color-util';
|
2019-02-25 23:56:37 +08:00
|
|
|
import source from './source';
|
2018-10-23 19:32:42 +08:00
|
|
|
import PickingMaterial from '../core/engine/picking/pickingMaterial';
|
|
|
|
import Attr from '../attr/index';
|
|
|
|
import Util from '../util';
|
2019-03-01 10:43:36 +08:00
|
|
|
import Global from '../global';
|
2018-10-23 19:32:42 +08:00
|
|
|
let id = 1;
|
|
|
|
function parseFields(field) {
|
|
|
|
if (Util.isArray(field)) {
|
|
|
|
return field;
|
|
|
|
}
|
|
|
|
if (Util.isString(field)) {
|
|
|
|
return field.split('*');
|
|
|
|
}
|
|
|
|
return [ field ];
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class Layer extends Base {
|
|
|
|
getDefaultCfg() {
|
|
|
|
return {
|
|
|
|
visible: true,
|
|
|
|
zIndex: 0,
|
|
|
|
type: '',
|
|
|
|
minZoom: 0,
|
|
|
|
maxZoom: 22,
|
|
|
|
rotation: 0,
|
|
|
|
attrOptions: {
|
|
|
|
},
|
|
|
|
scales: {},
|
|
|
|
attrs: {},
|
|
|
|
// 样式配置项
|
|
|
|
styleOptions: {
|
2018-12-24 10:48:03 +08:00
|
|
|
stroke: 'none',
|
2018-10-23 19:32:42 +08:00
|
|
|
strokeWidth: 1.0,
|
2018-11-08 20:56:17 +08:00
|
|
|
opacity: 1.0,
|
2018-12-24 10:48:03 +08:00
|
|
|
strokeOpacity: 1.0,
|
2018-11-16 16:52:25 +08:00
|
|
|
texture: false
|
2018-10-23 19:32:42 +08:00
|
|
|
},
|
2019-01-20 20:44:49 +08:00
|
|
|
destroyed: false,
|
2018-10-23 19:32:42 +08:00
|
|
|
// 选中时的配置项
|
|
|
|
selectedOptions: null,
|
|
|
|
// active 时的配置项
|
|
|
|
activedOptions: null,
|
2018-11-08 20:56:17 +08:00
|
|
|
animateOptions: {
|
2018-11-16 16:52:25 +08:00
|
|
|
enable: false
|
2018-11-08 20:56:17 +08:00
|
|
|
}
|
2018-10-23 19:32:42 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
constructor(scene, cfg) {
|
|
|
|
super(cfg);
|
|
|
|
this.scene = scene;
|
|
|
|
this.map = scene.map;
|
|
|
|
this._object3D = new THREE.Object3D();
|
|
|
|
this._pickObject3D = new THREE.Object3D();
|
|
|
|
this._object3D.visible = this.get('visible');
|
|
|
|
this._object3D.renderOrder = this.get('zIndex') || 0;
|
|
|
|
const layerId = this._getUniqueId();
|
|
|
|
this.layerId = layerId;
|
|
|
|
this._activeIds = null;
|
2019-02-12 20:21:14 +08:00
|
|
|
const world = scene._engine.world;
|
|
|
|
world.add(this._object3D);
|
2018-10-23 19:32:42 +08:00
|
|
|
this.layerMesh = null;
|
2018-12-24 10:48:03 +08:00
|
|
|
this.layerLineMesh = null;
|
2019-01-20 20:44:49 +08:00
|
|
|
this._initEvents();
|
2018-10-23 19:32:42 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
2018-10-30 11:22:18 +08:00
|
|
|
* 将图层添加加到 Object
|
|
|
|
* @param {*} object three 物体
|
2018-12-24 10:48:03 +08:00
|
|
|
* @param {*} type mesh类型是区别是填充还是边线
|
2018-10-23 19:32:42 +08:00
|
|
|
*/
|
2018-12-24 10:48:03 +08:00
|
|
|
add(object, type = 'fill') {
|
|
|
|
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
|
|
|
|
2018-11-16 16:52:25 +08:00
|
|
|
this._visibleWithZoom();
|
2019-01-20 20:44:49 +08:00
|
|
|
this._zoomchangeHander = this._visibleWithZoom.bind(this);
|
|
|
|
this.scene.on('zoomchange', this._zoomchangeHander);
|
2018-11-19 12:06:42 +08:00
|
|
|
|
2018-12-24 10:48:03 +08:00
|
|
|
object.onBeforeRender = () => {
|
2018-11-16 16:52:25 +08:00
|
|
|
const zoom = this.scene.getZoom();
|
2019-03-01 13:09:41 +08:00
|
|
|
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
|
|
|
|
object.material.setUniformsValue('u_zoom', zoom);
|
2018-12-24 10:48:03 +08:00
|
|
|
this._preRender();
|
2018-11-16 16:52:25 +08:00
|
|
|
|
|
|
|
};
|
2018-11-03 16:39:22 +08:00
|
|
|
// 更新
|
2018-11-08 20:56:17 +08:00
|
|
|
if (this._needUpdateFilter) {
|
2018-12-24 10:48:03 +08:00
|
|
|
this._updateFilter(object);
|
2018-11-03 16:39:22 +08:00
|
|
|
}
|
2018-10-23 19:32:42 +08:00
|
|
|
this._object3D.add(object);
|
2018-12-24 10:48:03 +08:00
|
|
|
if (type === 'fill') { this._addPickMesh(object); }
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
remove(object) {
|
|
|
|
this._object3D.remove(object);
|
|
|
|
}
|
|
|
|
_getUniqueId() {
|
|
|
|
return id++;
|
|
|
|
}
|
|
|
|
_visible(visible) {
|
|
|
|
this.set('visible', visible);
|
|
|
|
this._object3D.visible = this.get('visible');
|
|
|
|
}
|
|
|
|
source(data, cfg = {}) {
|
|
|
|
cfg.data = data;
|
2019-02-26 17:22:55 +08:00
|
|
|
cfg.mapType = this.scene.mapType;
|
2019-02-25 23:56:37 +08:00
|
|
|
this.layerSource = new source(cfg);
|
2019-01-20 20:44:49 +08:00
|
|
|
// this.scene.workerPool.runTask({
|
|
|
|
// command: 'geojson',
|
|
|
|
// data: cfg
|
|
|
|
// }).then(data => {
|
|
|
|
// console.log(data);
|
|
|
|
// });
|
2018-10-23 19:32:42 +08:00
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
color(field, values) {
|
2018-11-08 20:56:17 +08:00
|
|
|
this._needUpdateColor = true;// 标识颜色是否需要更新
|
2018-10-23 19:32:42 +08:00
|
|
|
this._createAttrOption('color', field, values, Global.colors);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
size(field, values) {
|
|
|
|
const fields = parseFields(field);
|
|
|
|
if (fields.indexOf('zoom') !== -1) {
|
|
|
|
this._zoomScale = true;
|
|
|
|
}
|
|
|
|
if (Util.isArray(fields) && !values) values = fields;
|
|
|
|
this._createAttrOption('size', field, values, Global.size);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
shape(field, values) {
|
|
|
|
if (field.split(':').length === 2) {
|
|
|
|
this.shapeType = field.split(':')[0];
|
|
|
|
field = field.split(':')[1];
|
|
|
|
}
|
|
|
|
values === 'text' ? this.shapeType = values : null;
|
|
|
|
|
2018-12-24 10:48:03 +08:00
|
|
|
this._createAttrOption('shape', field, values, Global.shape);
|
2018-10-23 19:32:42 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* 是否允许使用默认的图形激活交互
|
|
|
|
* @param {Boolean} enable 是否允许激活开关
|
|
|
|
* @param {Object} cfg 激活的配置项
|
|
|
|
* @return {Geom} 返回 geom 自身
|
|
|
|
*/
|
|
|
|
active(enable, cfg) {
|
|
|
|
if (enable === false) {
|
|
|
|
this.set('allowActive', false);
|
|
|
|
} else if (Util.isObject(enable)) {
|
|
|
|
this.set('allowActive', true);
|
|
|
|
this.set('activedOptions', enable);
|
|
|
|
} else {
|
|
|
|
this.set('allowActive', true);
|
|
|
|
this.set('activedOptions', cfg || { fill: Global.activeColor });
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
style(field, cfg) {
|
2018-11-16 16:52:25 +08:00
|
|
|
const colorItem = [ 'fill', 'stroke', 'color', 'baseColor', 'brightColor', 'windowColor' ];
|
2018-10-23 19:32:42 +08:00
|
|
|
let styleOptions = this.get('styleOptions');
|
|
|
|
if (!styleOptions) {
|
|
|
|
styleOptions = {};
|
|
|
|
this.set('styleOptions', styleOptions);
|
|
|
|
}
|
|
|
|
if (Util.isObject(field)) {
|
|
|
|
cfg = field;
|
|
|
|
field = null;
|
|
|
|
}
|
|
|
|
let fields;
|
|
|
|
if (field) {
|
|
|
|
fields = parseFields(field);
|
|
|
|
}
|
|
|
|
styleOptions.fields = fields;
|
|
|
|
Util.assign(styleOptions, cfg);
|
|
|
|
for (const item in cfg) {
|
2018-12-24 10:48:03 +08:00
|
|
|
if (colorItem.indexOf(item) !== -1 && styleOptions[item] !== 'none') {
|
2018-10-23 19:32:42 +08:00
|
|
|
styleOptions[item] = ColorUtil.color2RGBA(styleOptions[item]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.set('styleOptions', styleOptions);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
filter(field, values) {
|
2018-11-03 16:39:22 +08:00
|
|
|
this._needUpdateFilter = true;
|
2018-10-23 19:32:42 +08:00
|
|
|
this._createAttrOption('filter', field, values, true);
|
|
|
|
return this;
|
|
|
|
}
|
2018-11-16 16:52:25 +08:00
|
|
|
animate(field, cfg) {
|
|
|
|
let animateOptions = this.get('animateOptions');
|
|
|
|
if (!animateOptions) {
|
|
|
|
animateOptions = {};
|
2018-11-08 20:56:17 +08:00
|
|
|
this.set('animateOptions', animateOptions);
|
|
|
|
}
|
|
|
|
if (Util.isObject(field)) {
|
|
|
|
cfg = field;
|
|
|
|
field = null;
|
|
|
|
}
|
|
|
|
let fields;
|
|
|
|
if (field) {
|
|
|
|
fields = parseFields(field);
|
|
|
|
}
|
2018-11-16 16:52:25 +08:00
|
|
|
animateOptions.fields = fields;
|
|
|
|
Util.assign(animateOptions, cfg);
|
|
|
|
this.set('animateOptions', animateOptions);
|
2018-10-23 19:32:42 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
texture() {
|
|
|
|
|
|
|
|
}
|
|
|
|
hide() {
|
|
|
|
this._visible(false);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
show() {
|
|
|
|
this._visible(true);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
_createScale(field) {
|
|
|
|
const scales = this.get('scales');
|
|
|
|
let scale = scales[field];
|
|
|
|
if (!scale) {
|
|
|
|
scale = this.layerSource.createScale(field);
|
|
|
|
scales[field] = scale;
|
|
|
|
}
|
|
|
|
return scale;
|
|
|
|
}
|
|
|
|
_setAttrOptions(attrName, attrCfg) {
|
|
|
|
const options = this.get('attrOptions');
|
|
|
|
|
|
|
|
if (attrName === 'size' && this._zoomScale) {
|
|
|
|
attrCfg.zoom = this.map.getZoom();
|
|
|
|
}
|
|
|
|
options[attrName] = attrCfg;
|
|
|
|
}
|
|
|
|
_createAttrOption(attrName, field, cfg, defaultValues) {
|
|
|
|
const attrCfg = {};
|
|
|
|
attrCfg.field = field;
|
|
|
|
if (cfg) {
|
|
|
|
if (Util.isFunction(cfg)) {
|
|
|
|
attrCfg.callback = cfg;
|
|
|
|
} else {
|
|
|
|
attrCfg.values = cfg;
|
|
|
|
}
|
|
|
|
} else if (attrName !== 'color') {
|
|
|
|
attrCfg.values = defaultValues;
|
|
|
|
}
|
|
|
|
this._setAttrOptions(attrName, attrCfg);
|
|
|
|
}
|
2018-11-03 16:39:22 +08:00
|
|
|
// 初始化图层
|
2018-10-23 19:32:42 +08:00
|
|
|
init() {
|
|
|
|
this._initAttrs();
|
|
|
|
this._scaleByZoom();
|
|
|
|
this._mapping();
|
2018-11-08 20:56:17 +08:00
|
|
|
|
2018-10-23 19:32:42 +08:00
|
|
|
const activeHander = this._addActiveFeature.bind(this);
|
2018-12-24 10:48:03 +08:00
|
|
|
const resetHander = this._resetStyle.bind(this);
|
2018-10-23 19:32:42 +08:00
|
|
|
if (this.get('allowActive')) {
|
|
|
|
|
2018-12-24 16:15:18 +08:00
|
|
|
this.on('mousemove', activeHander);
|
2018-12-24 10:48:03 +08:00
|
|
|
this.on('mouseleave', resetHander);
|
2018-10-23 19:32:42 +08:00
|
|
|
|
|
|
|
} else {
|
2018-12-24 16:15:18 +08:00
|
|
|
this.off('mousemove', activeHander);
|
2018-12-24 10:48:03 +08:00
|
|
|
this.off('mouseleave', resetHander);
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_addActiveFeature(e) {
|
|
|
|
const { featureId } = e;
|
2018-12-24 10:48:03 +08:00
|
|
|
if (featureId < 0) return;
|
2018-10-23 19:32:42 +08:00
|
|
|
const activeStyle = this.get('activedOptions');
|
2019-02-25 23:56:37 +08:00
|
|
|
// const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
|
2018-12-24 10:48:03 +08:00
|
|
|
// 如果数据不显示状态则不进行高亮
|
2019-02-25 23:56:37 +08:00
|
|
|
if (this.layerData[featureId].hasOwnProperty('filter') && this.layerData[featureId].filter === false) { return; }
|
|
|
|
const style = Util.assign({}, this.layerData[featureId]);
|
2018-10-23 19:32:42 +08:00
|
|
|
style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
|
2018-11-19 12:06:42 +08:00
|
|
|
this.updateStyle([ featureId ], style);
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_initAttrs() {
|
|
|
|
const attrOptions = this.get('attrOptions');
|
|
|
|
for (const type in attrOptions) {
|
|
|
|
if (attrOptions.hasOwnProperty(type)) {
|
2018-11-19 12:06:42 +08:00
|
|
|
this._updateAttr(type);
|
2018-11-03 16:39:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
_updateAttr(type) {
|
2018-11-03 16:39:22 +08:00
|
|
|
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);
|
2018-10-23 19:32:42 +08:00
|
|
|
|
2018-11-03 16:39:22 +08:00
|
|
|
if (type === 'color' && Util.isNil(option.values)) { // 设置 color 的默认色值
|
|
|
|
option.values = Global.colors;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-03 16:39:22 +08:00
|
|
|
scales.push(scale);
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-03 16:39:22 +08:00
|
|
|
option.scales = scales;
|
|
|
|
const attr = new Attr[className](option);
|
|
|
|
attrs[type] = attr;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
_updateSize(zoom) {
|
|
|
|
const sizeOption = this.get('attrOptions').size;
|
|
|
|
const fields = parseFields(sizeOption.field);
|
2019-02-25 23:56:37 +08:00
|
|
|
const data = this.layerSource.data.dataArray;
|
2018-10-23 19:32:42 +08:00
|
|
|
if (!this.zoomSizeCache) this.zoomSizeCache = {};
|
|
|
|
if (!this.zoomSizeCache[zoom]) {
|
|
|
|
this.zoomSizeCache[zoom] = [];
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
const params = fields.map(field => data[i][field]);
|
|
|
|
const indexZoom = fields.indexOf('zoom');
|
|
|
|
indexZoom !== -1 ? params[indexZoom] = zoom : null;
|
|
|
|
this.zoomSizeCache[zoom].push(sizeOption.callback(...params));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.emit('sizeUpdated', this.zoomSizeCache[zoom]);
|
|
|
|
}
|
|
|
|
_mapping() {
|
|
|
|
const self = this;
|
|
|
|
const attrs = self.get('attrs');
|
|
|
|
const mappedData = [];
|
2019-02-25 23:56:37 +08:00
|
|
|
// const data = this.layerSource.propertiesData;
|
|
|
|
const data = this.layerSource.data.dataArray;
|
2018-10-23 19:32:42 +08:00
|
|
|
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];
|
2018-11-03 16:39:22 +08:00
|
|
|
attr.needUpdate = false;
|
2018-10-23 19:32:42 +08:00
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-25 23:56:37 +08:00
|
|
|
newRecord.coordinates = record.coordinates;
|
2018-10-23 19:32:42 +08:00
|
|
|
mappedData.push(newRecord);
|
|
|
|
}
|
2019-02-25 23:56:37 +08:00
|
|
|
this.layerData = mappedData;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-06 11:27:16 +08:00
|
|
|
// 更新地图映射
|
2018-11-03 16:39:22 +08:00
|
|
|
_updateMaping() {
|
2018-10-23 19:32:42 +08:00
|
|
|
const self = this;
|
|
|
|
const attrs = self.get('attrs');
|
|
|
|
|
2019-02-25 23:56:37 +08:00
|
|
|
const data = this.layerSource.data.dataArray;
|
2018-10-23 19:32:42 +08:00
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
const record = data[i];
|
2018-11-03 16:39:22 +08:00
|
|
|
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];
|
2019-02-25 23:56:37 +08:00
|
|
|
this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
2018-11-03 16:39:22 +08:00
|
|
|
}
|
|
|
|
} else {
|
2019-02-25 23:56:37 +08:00
|
|
|
this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
2018-10-23 19:32:42 +08:00
|
|
|
|
2018-11-03 16:39:22 +08:00
|
|
|
}
|
|
|
|
attr.neadUpdate = true;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 获取属性映射的值
|
|
|
|
_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// temp
|
|
|
|
_getDataType(data) {
|
|
|
|
if (data.hasOwnProperty('type')) {
|
|
|
|
const type = data.type;
|
|
|
|
if (type === 'FeatureCollection') {
|
|
|
|
return 'geojson';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 'basic';
|
|
|
|
}
|
|
|
|
_scaleByZoom() {
|
|
|
|
if (this._zoomScale) {
|
|
|
|
this.map.on('zoomend', () => {
|
|
|
|
const zoom = this.map.getZoom();
|
|
|
|
this._updateSize(Math.floor(zoom));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2018-12-24 16:15:18 +08:00
|
|
|
// on(type, callback) {
|
2018-10-23 19:32:42 +08:00
|
|
|
|
2018-12-24 16:15:18 +08:00
|
|
|
// this._addPickingEvents();
|
|
|
|
// super.on(type, callback);
|
|
|
|
// }
|
2018-10-23 19:32:42 +08:00
|
|
|
getPickingId() {
|
2018-11-19 12:06:42 +08:00
|
|
|
return this.scene._engine._picking.getNextId();
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
addToPicking(object) {
|
|
|
|
this.scene._engine._picking.add(object);
|
|
|
|
}
|
|
|
|
removeFromPicking(object) {
|
|
|
|
this.scene._engine._picking.remove(object);
|
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
_addPickMesh(mesh) {
|
2018-10-23 19:32:42 +08:00
|
|
|
this._pickingMesh = new THREE.Object3D();
|
2018-12-24 10:48:03 +08:00
|
|
|
this._pickingMesh.name = this.layerId;
|
2019-01-20 20:44:49 +08:00
|
|
|
// this._visibleWithZoom();
|
|
|
|
// this.scene.on('zoomchange', () => {
|
|
|
|
// this._visibleWithZoom();
|
|
|
|
// });
|
2018-11-19 12:06:42 +08:00
|
|
|
|
2018-10-23 19:32:42 +08:00
|
|
|
this.addToPicking(this._pickingMesh);
|
2018-11-19 10:45:40 +08:00
|
|
|
const pickmaterial = new PickingMaterial({
|
2018-11-19 12:06:42 +08:00
|
|
|
u_zoom: this.scene.getZoom()
|
2018-11-19 10:45:40 +08:00
|
|
|
});
|
2018-11-20 20:07:22 +08:00
|
|
|
|
2018-11-20 15:04:21 +08:00
|
|
|
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
2018-12-24 10:48:03 +08:00
|
|
|
pickingMesh.name = this.layerId;
|
2018-11-19 12:06:42 +08:00
|
|
|
pickmaterial.setDefinesvalue(this.type, true);
|
2018-11-20 15:04:21 +08:00
|
|
|
pickingMesh.onBeforeRender = () => {
|
2018-11-19 10:45:40 +08:00
|
|
|
const zoom = this.scene.getZoom();
|
2018-11-20 15:04:21 +08:00
|
|
|
pickingMesh.material.setUniformsValue('u_zoom', zoom);
|
2018-11-19 10:45:40 +08:00
|
|
|
};
|
2018-10-23 19:32:42 +08:00
|
|
|
this._pickingMesh.add(pickingMesh);
|
2019-02-25 23:56:37 +08:00
|
|
|
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
_setPickingId() {
|
|
|
|
this._pickingId = this.getPickingId();
|
|
|
|
}
|
2019-01-20 20:44:49 +08:00
|
|
|
_initEvents() {
|
2018-12-24 10:48:03 +08:00
|
|
|
this.scene.on('pick-' + this.layerId, e => {
|
2018-12-24 16:15:18 +08:00
|
|
|
const { featureId, point2d, type } = e;
|
2018-12-24 10:48:03 +08:00
|
|
|
if (featureId < -100 && this._activeIds !== null) {
|
|
|
|
this.emit('mouseleave');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const feature = this.layerSource.getSelectFeature(featureId);
|
2018-10-31 18:01:56 +08:00
|
|
|
const lnglat = this.scene.containerToLngLat(point2d);
|
|
|
|
const target = {
|
2018-12-24 10:48:03 +08:00
|
|
|
featureId,
|
2018-10-31 18:01:56 +08:00
|
|
|
feature,
|
2018-11-19 12:06:42 +08:00
|
|
|
pixel: point2d,
|
|
|
|
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
|
|
|
};
|
2018-12-24 16:15:18 +08:00
|
|
|
if (featureId >= 0) {
|
|
|
|
this.emit(type, target);
|
2018-12-24 10:48:03 +08:00
|
|
|
}
|
|
|
|
|
2018-10-23 19:32:42 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* 更新active操作
|
|
|
|
* @param {*} featureStyleId 需要更新的要素Id
|
|
|
|
* @param {*} style 更新的要素样式
|
|
|
|
*/
|
|
|
|
updateStyle(featureStyleId, style) {
|
2018-11-19 12:06:42 +08:00
|
|
|
if (this._activeIds) {
|
2018-12-24 10:48:03 +08:00
|
|
|
this._resetStyle();
|
2018-11-19 12:06:42 +08:00
|
|
|
}
|
|
|
|
this._activeIds = featureStyleId;
|
|
|
|
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
|
|
|
|
const color = style.color;
|
|
|
|
const colorAttr = this.layerMesh.geometry.attributes.a_color;
|
|
|
|
const firstId = pickingId.indexOf(featureStyleId[0] + 1);
|
|
|
|
for (let i = firstId; i < pickingId.length; i++) {
|
2018-11-20 20:07:22 +08:00
|
|
|
if (pickingId[i] === featureStyleId[0] + 1) {
|
2018-11-19 12:06:42 +08:00
|
|
|
colorAttr.array[i * 4 + 0] = color[0];
|
|
|
|
colorAttr.array[i * 4 + 1] = color[1];
|
|
|
|
colorAttr.array[i * 4 + 2] = color[2];
|
|
|
|
colorAttr.array[i * 4 + 3] = color[3];
|
|
|
|
} else {
|
|
|
|
break;
|
2018-11-19 10:45:40 +08:00
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
}
|
|
|
|
colorAttr.needsUpdate = true;
|
|
|
|
return;
|
2018-11-03 16:39:22 +08:00
|
|
|
}
|
2018-11-19 10:45:40 +08:00
|
|
|
|
2018-11-19 12:06:42 +08:00
|
|
|
_updateColor() {
|
|
|
|
|
2018-11-03 16:39:22 +08:00
|
|
|
this._updateMaping();
|
2018-11-19 12:06:42 +08:00
|
|
|
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2019-03-01 10:43:36 +08:00
|
|
|
/**
|
2018-12-24 10:48:03 +08:00
|
|
|
* 用于过滤数据
|
|
|
|
* @param {*} object 需要过滤的mesh
|
2018-10-23 19:32:42 +08:00
|
|
|
*/
|
2018-12-24 10:48:03 +08:00
|
|
|
_updateFilter(object) {
|
2018-11-03 16:39:22 +08:00
|
|
|
this._updateMaping();
|
2019-02-25 23:56:37 +08:00
|
|
|
const filterData = this.layerData;
|
2018-10-23 19:32:42 +08:00
|
|
|
this._activeIds = null; // 清空选中元素
|
2018-12-24 10:48:03 +08:00
|
|
|
const colorAttr = object.geometry.attributes.a_color;
|
|
|
|
const pickAttr = object.geometry.attributes.pickingId;
|
2018-11-19 12:06:42 +08:00
|
|
|
pickAttr.array.forEach((id, index) => {
|
|
|
|
id = Math.abs(id);
|
2019-02-25 23:56:37 +08:00
|
|
|
const color = [ ...this.layerData[id - 1].color ];
|
2018-11-19 10:45:40 +08:00
|
|
|
id = Math.abs(id);
|
2018-11-19 12:06:42 +08:00
|
|
|
const item = filterData[id - 1];
|
2018-11-19 10:45:40 +08:00
|
|
|
if (item.hasOwnProperty('filter') && item.filter === false) {
|
2018-11-19 12:06:42 +08:00
|
|
|
colorAttr.array[index * 4 + 0] = 0;
|
|
|
|
colorAttr.array[index * 4 + 1] = 0;
|
|
|
|
colorAttr.array[index * 4 + 2] = 0;
|
|
|
|
colorAttr.array[index * 4 + 3] = 0;
|
2018-12-24 10:48:03 +08:00
|
|
|
pickAttr.array[index] = -id; // 通过Id数据过滤 id<0 不显示
|
2018-11-19 10:45:40 +08:00
|
|
|
} else {
|
2018-11-19 12:06:42 +08:00
|
|
|
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];
|
2018-11-19 10:45:40 +08:00
|
|
|
pickAttr.array[index] = id;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
});
|
|
|
|
colorAttr.needsUpdate = true;
|
|
|
|
pickAttr.needsUpdate = true;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
_visibleWithZoom() {
|
|
|
|
const zoom = this.scene.getZoom();
|
2018-11-16 16:52:25 +08:00
|
|
|
const minZoom = this.get('minZoom');
|
|
|
|
const maxZoom = this.get('maxZoom');
|
|
|
|
// z-fighting
|
2018-11-19 10:45:40 +08:00
|
|
|
let offset = 0;
|
2018-11-19 12:06:42 +08:00
|
|
|
if (this.type === 'point') {
|
2018-11-19 10:45:40 +08:00
|
|
|
offset = 5;
|
2018-11-19 12:06:42 +08:00
|
|
|
} else if (this.type === 'polyline') {
|
2018-11-19 10:45:40 +08:00
|
|
|
offset = 2;
|
|
|
|
}
|
2018-11-20 20:07:22 +08:00
|
|
|
this._object3D.position.z = offset * Math.pow(2, 20 - zoom);
|
2018-11-19 12:06:42 +08:00
|
|
|
if (zoom < minZoom || zoom > maxZoom) {
|
|
|
|
this._object3D.visible = false;
|
|
|
|
} else if (this.get('visible')) {
|
|
|
|
this._object3D.visible = true;
|
2018-11-16 16:52:25 +08:00
|
|
|
}
|
|
|
|
}
|
2018-10-23 19:32:42 +08:00
|
|
|
/**
|
|
|
|
* 重置高亮要素
|
|
|
|
*/
|
2018-12-24 10:48:03 +08:00
|
|
|
_resetStyle() {
|
|
|
|
|
2018-11-19 12:06:42 +08:00
|
|
|
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
|
|
|
|
const colorAttr = this.layerMesh.geometry.attributes.a_color;
|
2018-11-20 20:07:22 +08:00
|
|
|
this._activeIds.forEach(index => {
|
2019-02-25 23:56:37 +08:00
|
|
|
const color = this.layerData[index].color;
|
2018-11-19 12:06:42 +08:00
|
|
|
const firstId = pickingId.indexOf(index + 1);
|
|
|
|
for (let i = firstId; i < pickingId.length; i++) {
|
2018-11-20 20:07:22 +08:00
|
|
|
if (pickingId[i] === index + 1) {
|
2018-11-19 12:06:42 +08:00
|
|
|
colorAttr.array[i * 4 + 0] = color[0];
|
|
|
|
colorAttr.array[i * 4 + 1] = color[1];
|
|
|
|
colorAttr.array[i * 4 + 2] = color[2];
|
|
|
|
colorAttr.array[i * 4 + 3] = color[3];
|
2018-11-19 10:45:40 +08:00
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
colorAttr.needsUpdate = true;
|
2018-12-24 10:48:03 +08:00
|
|
|
this._activeIds = null;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-11-03 16:39:22 +08:00
|
|
|
/**
|
|
|
|
* 销毁Layer对象
|
|
|
|
*/
|
2019-01-20 20:44:49 +08:00
|
|
|
destroy() {
|
|
|
|
this.removeAllListeners();
|
2018-11-19 12:06:42 +08:00
|
|
|
if (this._object3D && this._object3D.children) {
|
2018-10-23 19:32:42 +08:00
|
|
|
let child;
|
2018-11-19 12:06:42 +08:00
|
|
|
for (let i = 0; i < this._object3D.children.length; i++) {
|
|
|
|
child = this._object3D.children[i];
|
|
|
|
if (!child) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
this.remove(child);
|
|
|
|
if (child.geometry) {
|
2019-01-20 20:44:49 +08:00
|
|
|
// child.geometry.dispose();
|
2018-11-19 12:06:42 +08:00
|
|
|
child.geometry = null;
|
|
|
|
}
|
|
|
|
if (child.material) {
|
2018-10-23 19:32:42 +08:00
|
|
|
if (child.material.map) {
|
|
|
|
child.material.map.dispose();
|
|
|
|
child.material.map = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
child.material.dispose();
|
|
|
|
child.material = null;
|
|
|
|
}
|
2019-01-20 20:44:49 +08:00
|
|
|
child = null;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
}
|
2018-11-19 12:06:42 +08:00
|
|
|
this._object3D = null;
|
2019-01-20 20:44:49 +08:00
|
|
|
this.scene._engine._scene.remove(this._object3D);
|
|
|
|
this.scene._engine._picking.remove(this._pickingMesh);
|
|
|
|
this.scene.off('zoomchange', this._zoomchangeHander);
|
|
|
|
this.destroyed = true;
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
2018-12-24 16:15:18 +08:00
|
|
|
_preRender() {
|
2018-12-24 10:48:03 +08:00
|
|
|
|
|
|
|
}
|
2018-10-23 19:32:42 +08:00
|
|
|
}
|
|
|
|
|