Merge pull request #179 from antvis/layer_async

Layer async
This commit is contained in:
@thinkinggis 2020-01-29 11:15:29 +08:00 committed by GitHub
commit 602100bf30
18 changed files with 95 additions and 62 deletions

View File

@ -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 计算
### 方法

View File

@ -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<IControlService>(
TYPES.IControlService,
);
this.sceneContainer = sceneContainer;
this.isShow = true;
this.container = this.onAdd();
const container = this.container;

View File

@ -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() {

View File

@ -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() {

View File

@ -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',
};
}

View File

@ -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: '&#x2212;',
zoomOutTitle: 'Zoom out',
name: 'zoom',
};
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -58,4 +58,5 @@ export interface IMultiPassRenderer {
getRenderFlag(): boolean;
setRenderFlag(enabled: boolean): void;
setLayer(layer: ILayer): void;
destroy(): void;
}

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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 初始化完成之后添加

View File

@ -56,7 +56,7 @@ let layerIdCounter = 0;
export default class BaseLayer<ChildLayerStyleOptions = {}> 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<ChildLayerStyleOptions = {}> extends EventEmitter
// 清除sources事件
this.layerSource.off('update', this.sourceEvent);
this.multiPassRenderer.destroy();
// 清除所有属性以及关联的 vao
this.styleAttributeService.clearAllAttributes();
// 销毁所有 model

View File

@ -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,

View File

@ -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);

View File

@ -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],