diff --git a/docs/api/component/markerLayer.zh.md b/docs/api/component/markerLayer.zh.md index c62a0fb875..3d480476d2 100644 --- a/docs/api/component/markerLayer.zh.md +++ b/docs/api/component/markerLayer.zh.md @@ -40,17 +40,15 @@ scene.addMarkerLayer(markerLayer); - field `string` 聚合统计字段 - method `sum| max| min| mean` - element `function` 通过回调函数设置聚合 Marker 的样式,返回 dom 元素 - + 参数:feature - - point_count 默认 聚合元素个数 - - clusterData `Array` 聚合节点的原始数据 - - point_sum 聚合求和 根据 field 和 method 计算 - - point_max 聚合最大值 根据 field 和 method 计算 - - point_min 聚合最小值 根据 field 和 method 计算 - - point_mean 聚合平均值 根据 field 和 method 计算 - - + - point_count 默认 聚合元素个数 + - clusterData `Array` 聚合节点的原始数据 + - point_sum 聚合求和 根据 field 和 method 计算 + - point_max 聚合最大值 根据 field 和 method 计算 + - point_min 聚合最小值 根据 field 和 method 计算 + - point_mean 聚合平均值 根据 field 和 method 计算 ### 方法 diff --git a/packages/component/src/control/BaseControl.ts b/packages/component/src/control/BaseControl.ts index 9685baa59c..679183515b 100644 --- a/packages/component/src/control/BaseControl.ts +++ b/packages/component/src/control/BaseControl.ts @@ -1,8 +1,10 @@ import { + IControlOption, IControlService, ILayerService, IMapService, IRendererService, + PositionName, TYPES, } from '@antv/l7-core'; import { DOM } from '@antv/l7-utils'; @@ -15,18 +17,12 @@ export enum PositionType { 'BOTTOMRIGHT' = 'bottomright', 'BOTTOMLEFT' = 'bottomleft', } -export type PositionName = - | 'topright' - | 'topleft' - | 'bottomright' - | 'bottomleft'; -export interface IControlOption { - position: PositionName; - [key: string]: any; -} + +let controlId = 0; export default class Control extends EventEmitter { public controlOption: IControlOption; protected container: HTMLElement; + protected sceneContainer: Container; protected mapsService: IMapService; protected renderService: IRendererService; protected layerService: ILayerService; @@ -45,18 +41,19 @@ export default class Control extends EventEmitter { public getDefault() { return { position: PositionType.TOPRIGHT, + name: `${controlId++}`, }; } public setPosition(position: PositionName) { // 考虑组件的自动布局,需要销毁重建 - // const controlService = this.controlService; - // if (controlService) { - // controlService.removeControl(this); - // } - // this.controlOption.position = position; - // if (controlService) { - // controlService.addControl(this, this.mapsService); - // } + const controlService = this.controlService; + if (controlService) { + controlService.removeControl(this); + } + this.controlOption.position = position; + if (controlService) { + controlService.addControl(this, this.sceneContainer); + } return this; } public addTo(sceneContainer: Container) { @@ -68,7 +65,7 @@ export default class Control extends EventEmitter { this.controlService = sceneContainer.get( TYPES.IControlService, ); - + this.sceneContainer = sceneContainer; this.isShow = true; this.container = this.onAdd(); const container = this.container; diff --git a/packages/component/src/control/layer.ts b/packages/component/src/control/layer.ts index 58c7596768..0f6a53c7d6 100644 --- a/packages/component/src/control/layer.ts +++ b/packages/component/src/control/layer.ts @@ -1,10 +1,6 @@ -import { IMapService } from '@antv/l7-core'; +import { IControlOption, PositionName, PositionType } from '@antv/l7-core'; import { bindAll, DOM, lnglatDistance } from '@antv/l7-utils'; -import Control, { - IControlOption, - PositionName, - PositionType, -} from './BaseControl'; +import Control from './BaseControl'; export interface ILayerControlOption extends IControlOption { collapsed: boolean; autoZIndex: boolean; @@ -55,6 +51,7 @@ export default class Layers extends Control { autoZIndex: true, hideSingleBase: false, sortLayers: false, + name: 'layers', }; } public onAdd() { diff --git a/packages/component/src/control/logo.ts b/packages/component/src/control/logo.ts index da7d543b14..dd027735df 100644 --- a/packages/component/src/control/logo.ts +++ b/packages/component/src/control/logo.ts @@ -1,9 +1,11 @@ +import { IControlOption } from '@antv/l7-core'; import { DOM } from '@antv/l7-utils'; import Control, { PositionType } from './BaseControl'; export default class Logo extends Control { public getDefault() { return { position: PositionType.BOTTOMLEFT, + name: 'logo', }; } public onAdd() { diff --git a/packages/component/src/control/scale.ts b/packages/component/src/control/scale.ts index 1b28e7bcb9..404c618089 100644 --- a/packages/component/src/control/scale.ts +++ b/packages/component/src/control/scale.ts @@ -1,6 +1,7 @@ -import { IMapService } from '@antv/l7-core'; +import { IControlOption } from '@antv/l7-core'; import { bindAll, DOM, lnglatDistance } from '@antv/l7-utils'; -import Control, { IControlOption, PositionType } from './BaseControl'; + +import Control, { PositionType } from './BaseControl'; export interface IScaleControlOption extends IControlOption { maxWidth: number; metric: boolean; @@ -22,6 +23,7 @@ export default class Scale extends Control { metric: true, updateWhenIdle: false, imperial: false, + name: 'scale', }; } diff --git a/packages/component/src/control/zoom.ts b/packages/component/src/control/zoom.ts index 8d0550889b..b96155d618 100644 --- a/packages/component/src/control/zoom.ts +++ b/packages/component/src/control/zoom.ts @@ -1,5 +1,6 @@ +import { IControlOption } from '@antv/l7-core'; import { bindAll, DOM } from '@antv/l7-utils'; -import Control, { IControlOption, PositionType } from './BaseControl'; +import Control, { PositionType } from './BaseControl'; export interface IZoomControlOption extends IControlOption { zoomInText: string; zoomInTitle: string; @@ -22,6 +23,7 @@ export default class Zoom extends Control { zoomInTitle: 'Zoom in', zoomOutText: '−', zoomOutTitle: 'Zoom out', + name: 'zoom', }; } diff --git a/packages/component/src/markerlayer.ts b/packages/component/src/markerlayer.ts index 409c453221..29f60a0d3c 100644 --- a/packages/component/src/markerlayer.ts +++ b/packages/component/src/markerlayer.ts @@ -7,7 +7,7 @@ import Supercluster from 'supercluster'; import Marker from './marker'; type CallBack = (...args: any[]) => any; interface IMarkerStyleOption { - element: CallBack; + element?: CallBack; style: { [key: string]: any } | CallBack; className: string; field?: string; @@ -56,7 +56,6 @@ export default class MarkerLayer extends EventEmitter { zoom: -99, style: {}, className: '', - element: this.generateElement, }, }; } @@ -171,10 +170,10 @@ export default class MarkerLayer extends EventEmitter { feature.properties[fieldName] = stat; } } - const marker = - feature.properties && feature.properties.hasOwnProperty('point_count') - ? this.clusterMarker(feature) - : this.normalMarker(feature); + const marker = this.clusterMarker(feature); + // feature.properties && feature.properties.hasOwnProperty('point_count') + // ? this.clusterMarker(feature) + // : this.normalMarker(feature); this.clusterMarkers.push(marker); marker.addTo(this.scene); @@ -193,7 +192,9 @@ export default class MarkerLayer extends EventEmitter { private clusterMarker(feature: any) { const clusterOption = this.markerLayerOption.clusterOption; - const { element } = clusterOption as IMarkerStyleOption; + const { + element = this.generateElement.bind(this), + } = clusterOption as IMarkerStyleOption; const marker = new Marker({ element: element(feature), }).setLnglat({ @@ -204,12 +205,7 @@ export default class MarkerLayer extends EventEmitter { } private normalMarker(feature: any) { const marker_id = feature.properties.marker_id; - return marker_id - ? new Marker().setLnglat({ - lng: feature.geometry.coordinates[0], - lat: feature.geometry.coordinates[1], - }) - : this.markers[marker_id]; + return this.markers[marker_id]; } private update() { const zoom = this.mapsService.getZoom(); @@ -222,11 +218,14 @@ export default class MarkerLayer extends EventEmitter { const el = DOM.create('div', 'l7-marker-cluster'); const label = DOM.create('div', '', el); const span = DOM.create('span', '', label); - span.textContent = feature.properties.point_count; - // if (className !== '') { - // DOM.addClass(el, className); - // } - // span.textContent = feature.properties.point_count; + const { field, method } = this.markerLayerOption.clusterOption; + feature.properties.point_count = feature.properties.point_count || 1; + + const text = + field && method + ? feature.properties['point_' + method] || feature.properties[field] + : feature.properties.point_count; + span.textContent = text; // const elStyle = isFunction(style) // ? style(feature.properties.point_count) // : style; diff --git a/packages/core/src/services/component/ControlService.ts b/packages/core/src/services/component/ControlService.ts index 0f0c6de019..9516ec8264 100644 --- a/packages/core/src/services/component/ControlService.ts +++ b/packages/core/src/services/component/ControlService.ts @@ -32,6 +32,11 @@ export default class ControlService implements IControlService { this.unAddControls.push(ctr); } } + public getControlByName(name: string | number): IControl | undefined { + return this.controls.find((ctr) => { + return ctr.controlOption.name === name; + }); + } public removeControl(ctr: IControl): this { const index = this.controls.indexOf(ctr); if (index > -1) { diff --git a/packages/core/src/services/component/IControlService.ts b/packages/core/src/services/component/IControlService.ts index e7bd40da13..8d6872b9a6 100644 --- a/packages/core/src/services/component/IControlService.ts +++ b/packages/core/src/services/component/IControlService.ts @@ -5,8 +5,16 @@ export enum PositionType { 'BOTTOMRIGHT' = 'bottomright', 'BOTTOMLEFT' = 'bottomleft', } + +export type PositionName = + | 'topright' + | 'topleft' + | 'bottomright' + | 'bottomleft'; export interface IControlOption { - position: PositionType; + name: string; + position: PositionName; + [key: string]: any; } export interface IControlServiceCfg { container: HTMLElement; @@ -15,6 +23,7 @@ export interface IControlCorners { [key: string]: HTMLElement; } export interface IControl { + controlOption: IControlOption; setPosition(pos: PositionType): void; addTo(sceneContainer: Container): void; onAdd(): HTMLElement; @@ -29,6 +38,7 @@ export interface IControlService { addControls(): void; init(cfg: IControlServiceCfg, sceneContainer: Container): void; addControl(ctr: IControl, sceneContainer: Container): void; + getControlByName(name: string | number): IControl | undefined; removeControl(ctr: IControl): void; destroy(): void; } diff --git a/packages/core/src/services/layer/LayerService.ts b/packages/core/src/services/layer/LayerService.ts index 2f85b75c28..b9c3089504 100644 --- a/packages/core/src/services/layer/LayerService.ts +++ b/packages/core/src/services/layer/LayerService.ts @@ -27,9 +27,9 @@ export default class LayerService implements ILayerService { private readonly configService: IGlobalConfigService; public add(layer: ILayer) { - // if (this.sceneInited) { - // layer.init(); - // } + if (this.sceneInited) { + layer.init(); + } this.layers.push(layer); } @@ -73,6 +73,7 @@ export default class LayerService implements ILayerService { this.alreadyInRendering = true; this.clear(); this.layers + .filter((layer) => layer.inited) .filter((layer) => layer.isVisible()) .forEach((layer) => { // trigger hooks diff --git a/packages/core/src/services/renderer/IMultiPassRenderer.ts b/packages/core/src/services/renderer/IMultiPassRenderer.ts index 619c208818..b4ad1a4494 100644 --- a/packages/core/src/services/renderer/IMultiPassRenderer.ts +++ b/packages/core/src/services/renderer/IMultiPassRenderer.ts @@ -58,4 +58,5 @@ export interface IMultiPassRenderer { getRenderFlag(): boolean; setRenderFlag(enabled: boolean): void; setLayer(layer: ILayer): void; + destroy(): void; } diff --git a/packages/core/src/services/renderer/passes/MultiPassRenderer.ts b/packages/core/src/services/renderer/passes/MultiPassRenderer.ts index 9e8017c948..3a6f1e4bf4 100644 --- a/packages/core/src/services/renderer/passes/MultiPassRenderer.ts +++ b/packages/core/src/services/renderer/passes/MultiPassRenderer.ts @@ -82,4 +82,8 @@ export default class MultiPassRenderer implements IMultiPassRenderer { pass.init(this.layer, config); this.passes.splice(index, 0, pass); } + + public destroy() { + this.passes.length = 0; + } } diff --git a/packages/core/src/services/renderer/passes/PixelPickingPass.ts b/packages/core/src/services/renderer/passes/PixelPickingPass.ts index d1f99684be..699258ed4b 100644 --- a/packages/core/src/services/renderer/passes/PixelPickingPass.ts +++ b/packages/core/src/services/renderer/passes/PixelPickingPass.ts @@ -34,6 +34,10 @@ export default class PixelPickingPass< */ private layer: ILayer; + private width: number = 0; + + private height: number = 0; + /** * 简单的 throttle,防止连续触发 hover 时导致频繁渲染到 picking framebuffer */ @@ -91,8 +95,11 @@ export default class PixelPickingPass< this.alreadyInRendering = true; // resize first, fbo can't be resized in use - this.pickingFBO.resize({ width, height }); - + if (this.width !== width || this.height !== height) { + this.pickingFBO.resize({ width, height }); + this.width = width; + this.height = height; + } useFramebuffer(this.pickingFBO, () => { clear({ framebuffer: this.pickingFBO, diff --git a/packages/core/src/services/scene/SceneService.ts b/packages/core/src/services/scene/SceneService.ts index 94c4426411..45776b2e57 100644 --- a/packages/core/src/services/scene/SceneService.ts +++ b/packages/core/src/services/scene/SceneService.ts @@ -207,13 +207,13 @@ export default class Scene extends EventEmitter implements ISceneService { // FIXME: 初始化 marker 容器,可以放到 map 初始化方法中? this.logger.info(' render inited'); + this.layerService.initLayers(); this.controlService.addControls(); this.emit('loaded'); this.inited = true; } // 尝试初始化未初始化的图层 - this.layerService.initLayers(); this.layerService.renderLayers(); // 组件需要等待layer 初始化完成之后添加 diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index b902419d14..68b2c08588 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -56,7 +56,7 @@ let layerIdCounter = 0; export default class BaseLayer extends EventEmitter implements ILayer { public id: string = `${layerIdCounter++}`; - public name: string = `${layerIdCounter++}`; + public name: string = `${layerIdCounter}`; public type: string; public visible: boolean = true; public zIndex: number = 0; @@ -659,6 +659,8 @@ export default class BaseLayer extends EventEmitter // 清除sources事件 this.layerSource.off('update', this.sourceEvent); + this.multiPassRenderer.destroy(); + // 清除所有属性以及关联的 vao this.styleAttributeService.clearAllAttributes(); // 销毁所有 model diff --git a/packages/layers/src/point/models/text.ts b/packages/layers/src/point/models/text.ts index e9b08eaf9a..a066fceaeb 100644 --- a/packages/layers/src/point/models/text.ts +++ b/packages/layers/src/point/models/text.ts @@ -92,6 +92,7 @@ export default class TextModel extends BaseModel { stroke = '#fff', strokeWidth = 0, } = this.layer.getLayerConfig() as IPointTextLayerStyleOptions; + this.updateTexture(); const { canvas } = this.fontService; return { u_opacity: 1.0, diff --git a/packages/scene/src/index.ts b/packages/scene/src/index.ts index 21a4e54e79..a6f7ec64ac 100644 --- a/packages/scene/src/index.ts +++ b/packages/scene/src/index.ts @@ -158,6 +158,10 @@ class Scene this.controlService.removeControl(ctr); } + public getControlByName(name: string) { + return this.controlService.getControlByName(name); + } + // marker public addMarker(marker: IMarker) { this.markerService.addMarker(marker); diff --git a/stories/Components/components/clusterMarker.tsx b/stories/Components/components/clusterMarker.tsx index 4ee3f9455e..ab6ca05dd8 100644 --- a/stories/Components/components/clusterMarker.tsx +++ b/stories/Components/components/clusterMarker.tsx @@ -52,6 +52,7 @@ export default class ClusterMarkerLayer extends React.Component { for (let i = 0; i < nodes.features.length; i++) { const { coordinates } = nodes.features[i].geometry; const marker = new Marker({ + color: 'red', extData: nodes.features[i].properties, }).setLnglat({ lng: coordinates[0],