mirror of https://gitee.com/antv-l7/antv-l7
feat: add DebugService (#1590)
* feat: 新增 debugService step1 * chore: layer_init test 测试文件修改 * refactor: 重构日志系统结构 * feat: add remove layer log * feat: add render debug * feat: 增加 debugService 的开关控制 * feat: add simple source log * feat: 调整 souce getLog 方法的输出 * feat: add scene webgl context lost * docs: 补充 scene 的事件监听方法 * feat: 标砖 debugService 枚举类型、修复初始化时间节点错误 * style: lint style * fix: 删除单独的sourcelog,优化了log 流程 (#1599) * chore: remove render model log * docs: add debugService contents * style: lint style * docs: add IDebugLog details * style: lint style --------- Co-authored-by: shihui <yiqianyao.yqy@alibaba-inc.com> Co-authored-by: @thinkinggis <lzx199065@gmail.com>
This commit is contained in:
parent
5a96e01ad5
commit
b0d9862164
|
@ -1,5 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { LineLayer, Scene } from '@antv/l7';
|
||||
import { LineLayer, PointLayer, Scene } from '@antv/l7';
|
||||
// @ts-ignore
|
||||
import { GaodeMapV1 } from '@antv/l7-maps';
|
||||
import React, { useEffect } from 'react';
|
||||
|
@ -14,6 +14,7 @@ export default () => {
|
|||
style:'light'
|
||||
// style: 'amap://styles/wine',
|
||||
}),
|
||||
debug: true,
|
||||
});
|
||||
|
||||
scene.on('loaded', () => {
|
||||
|
@ -34,14 +35,65 @@ export default () => {
|
|||
});
|
||||
scene.addLayer(layer);
|
||||
|
||||
// const point = new PointLayer({})
|
||||
// .source([{ lng: 116.2, lat: 40 }], {
|
||||
// parser: {
|
||||
// type: 'json',
|
||||
// x: 'lng',
|
||||
// y: 'lat',
|
||||
// }
|
||||
// })
|
||||
// .size(10)
|
||||
// .shape('circle')
|
||||
// .color('#5CCEA1');
|
||||
// scene.addLayer(point);
|
||||
|
||||
const debugService = scene.getDebugService();
|
||||
|
||||
layerAllLoad([layer], () => {
|
||||
// console.log('debugService id type', debugService.getLog())
|
||||
// console.log('debugService id type', debugService.getLog(layer.id))
|
||||
// console.log('debugService id type', debugService.getLog('map'))
|
||||
// console.log('debugService id type', debugService.getLog([layer.id, point.id]))
|
||||
console.log('debugService id type', debugService.getLog([layer.id]))
|
||||
})
|
||||
|
||||
function layerAllLoad(layers: any[], callback: () => void) {
|
||||
let count = 0;
|
||||
layers.forEach(l => {
|
||||
l.on('inited', () => {
|
||||
console.log('***');
|
||||
|
||||
count++;
|
||||
if(count === layers.length) {
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
}, 100)
|
||||
// callback();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
// setTimeout(()=>{
|
||||
// console.log('setdata')
|
||||
// layer.setData({
|
||||
// type: 'featureCollection',
|
||||
// features:[],
|
||||
// console.log('lostContext test')
|
||||
// scene.on('webglcontextlost', () => {
|
||||
// console.log('webglcontextlost');
|
||||
// })
|
||||
|
||||
// // scene.lostContext();
|
||||
// },3000)
|
||||
|
||||
// setTimeout(()=>{
|
||||
// },3000)
|
||||
// debugService.renderDebug(true);
|
||||
|
||||
// debugService.on('renderEnd', (renderInfo) => {
|
||||
// console.log('renderEnd', renderInfo);
|
||||
// })
|
||||
|
||||
|
||||
// setTimeout(() => {
|
||||
// debugService.renderDebug(false);
|
||||
// }, 200)
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
|
|
@ -30,6 +30,7 @@ export {
|
|||
|
||||
/** 暴露服务接口供其他 packages 实现 */
|
||||
export * from './services/layer/ILayerService';
|
||||
export * from './services/debug/IDebugService';
|
||||
export * from './services/layer/IStyleAttributeService';
|
||||
export * from './services/source/ISourceService';
|
||||
export * from './services/map/IMapService';
|
||||
|
|
|
@ -19,6 +19,7 @@ import { ICoordinateSystemService } from './services/coordinate/ICoordinateSyste
|
|||
import { IInteractionService } from './services/interaction/IInteractionService';
|
||||
import { IPickingService } from './services/interaction/IPickingService';
|
||||
import { ILayerService } from './services/layer/ILayerService';
|
||||
import { IDebugService } from './services/debug/IDebugService';
|
||||
import { IStyleAttributeService } from './services/layer/IStyleAttributeService';
|
||||
import { ISceneService } from './services/scene/ISceneService';
|
||||
import { IShaderModuleService } from './services/shader/IShaderModuleService';
|
||||
|
@ -35,6 +36,7 @@ import CoordinateSystemService from './services/coordinate/CoordinateSystemServi
|
|||
import InteractionService from './services/interaction/InteractionService';
|
||||
import PickingService from './services/interaction/PickingService';
|
||||
import LayerService from './services/layer/LayerService';
|
||||
import DebugService from './services/debug/DebugService';
|
||||
import StyleAttributeService from './services/layer/StyleAttributeService';
|
||||
import SceneService from './services/scene/SceneService';
|
||||
import ShaderModuleService from './services/shader/ShaderModuleService';
|
||||
|
@ -153,6 +155,10 @@ export function createSceneContainer() {
|
|||
.bind<ILayerService>(TYPES.ILayerService)
|
||||
.to(LayerService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IDebugService>(TYPES.IDebugService)
|
||||
.to(DebugService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<ISceneService>(TYPES.ISceneService)
|
||||
.to(SceneService)
|
||||
|
|
|
@ -17,6 +17,7 @@ export interface ISceneConfig extends IRenderConfig {
|
|||
pickBufferScale?: number;
|
||||
// TODO: 场景是否支持 stencil mask
|
||||
stencil?: boolean;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export interface IGlobalConfigService {
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import { guid } from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { injectable } from 'inversify';
|
||||
import { IDebugService, ILog, IRenderInfo } from './IDebugService';
|
||||
|
||||
@injectable()
|
||||
export default class DebugService
|
||||
extends EventEmitter
|
||||
implements IDebugService
|
||||
{
|
||||
private logMap = new Map<string, ILog>();
|
||||
private renderMap = new Map<string, IRenderInfo>();
|
||||
|
||||
private enable: boolean = false;
|
||||
public renderEnable: boolean = false;
|
||||
|
||||
public setEnable(flag: boolean) {
|
||||
this.enable = !!flag;
|
||||
}
|
||||
|
||||
public log(key: string, values: ILog) {
|
||||
if (!this.enable) {
|
||||
return;
|
||||
}
|
||||
const [k1, k2] = key.split('.');
|
||||
const logType = k2;
|
||||
/**
|
||||
* map: {
|
||||
* mapInitStart: { time, ... }
|
||||
* },
|
||||
* 12: {
|
||||
* layerInitStart: { time, id, ... },
|
||||
* layerInitEnd: { time, id, ... },
|
||||
* }
|
||||
*/
|
||||
const cacheLog = this.logMap.get(k1) || {}; // 一级存储对象
|
||||
const cacheLogValues = cacheLog[logType] || {}; // 二级存储对象
|
||||
const logValues = {
|
||||
time: Date.now(),
|
||||
...cacheLogValues,
|
||||
...values,
|
||||
};
|
||||
this.logMap.set(k1, {
|
||||
...cacheLog,
|
||||
[logType]: logValues,
|
||||
});
|
||||
}
|
||||
|
||||
public getLog(key: string | string[] | undefined) {
|
||||
switch (typeof key) {
|
||||
case 'string':
|
||||
return this.logMap.get(key);
|
||||
case 'object':
|
||||
return (key as string[])
|
||||
.map((k) => this.logMap.get(k))
|
||||
.filter((o) => o !== undefined) as ILog[];
|
||||
case 'undefined':
|
||||
return Array.from(this.logMap.keys()).map((k) => this.logMap.get(k));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除日志
|
||||
* @param key
|
||||
*/
|
||||
public removeLog(key: string) {
|
||||
this.logMap.delete(key);
|
||||
}
|
||||
|
||||
public generateRenderUid() {
|
||||
if (this.renderEnable) {
|
||||
return guid();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public renderDebug(enable: boolean) {
|
||||
this.renderEnable = enable;
|
||||
}
|
||||
|
||||
public renderStart(guid: string) {
|
||||
if (!this.renderEnable || !this.enable) {
|
||||
return;
|
||||
}
|
||||
const cacheRenderInfo = this.renderMap.get(guid) || {};
|
||||
this.renderMap.set(guid, {
|
||||
...cacheRenderInfo,
|
||||
renderUid: guid,
|
||||
renderStart: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
public renderEnd(guid: string) {
|
||||
if (!this.renderEnable || !this.enable) {
|
||||
return;
|
||||
}
|
||||
const cacheRenderInfo = this.renderMap.get(guid);
|
||||
if (cacheRenderInfo) {
|
||||
const renderStart = cacheRenderInfo.renderStart as number;
|
||||
const renderEnd = Date.now();
|
||||
this.emit('renderEnd', {
|
||||
...cacheRenderInfo,
|
||||
renderEnd,
|
||||
renderDuration: renderEnd - renderStart,
|
||||
});
|
||||
this.renderMap.delete(guid);
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.logMap.clear();
|
||||
this.renderMap.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
export type ILayerId = string;
|
||||
export interface ILog {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const enum IDebugLog {
|
||||
MapInitStart = 'mapInitStart',
|
||||
LayerInitStart = 'layerInitStart',
|
||||
LayerInitEnd = 'layerInitEnd',
|
||||
SourceInitStart = 'sourceInitStart',
|
||||
SourceInitEnd = 'sourceInitEnd',
|
||||
ScaleInitStart = 'scaleInitStart',
|
||||
ScaleInitEnd = 'scaleInitEnd',
|
||||
MappingStart = 'mappingStart',
|
||||
MappingEnd = 'mappingEnd',
|
||||
BuildModelStart = 'buildModelStart',
|
||||
BuildModelEnd = 'buildModelEnd',
|
||||
}
|
||||
|
||||
export interface IRenderInfo {
|
||||
renderUid: string;
|
||||
renderStart?: number;
|
||||
renderEnd?: number;
|
||||
renderDuration?: number;
|
||||
}
|
||||
export interface IDebugService {
|
||||
renderEnable: boolean;
|
||||
|
||||
setEnable(flag: boolean | undefined): void;
|
||||
|
||||
log(key: string, values: ILog): void;
|
||||
getLog(key: string | string[] | undefined): ILog[] | ILog | undefined;
|
||||
removeLog(key: string): void;
|
||||
|
||||
generateRenderUid(): string;
|
||||
renderStart(guid: string): void;
|
||||
renderEnd(guid: string): void;
|
||||
}
|
|
@ -443,6 +443,7 @@ export interface ILayer {
|
|||
getMinZoom(): number;
|
||||
getMaxZoom(): number;
|
||||
get(name: string): number;
|
||||
log(type: string, time?: number): void;
|
||||
setBlend(type: keyof typeof BlendType): ILayer;
|
||||
// animate(field: string, option: any): ILayer;
|
||||
|
||||
|
|
|
@ -5,13 +5,16 @@ import { throttle } from 'lodash';
|
|||
import 'reflect-metadata';
|
||||
import { TYPES } from '../../types';
|
||||
import Clock from '../../utils/clock';
|
||||
import { IDebugService } from '../debug/IDebugService';
|
||||
import { IMapService } from '../map/IMapService';
|
||||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { ILayer, ILayerService, LayerServiceEvent } from './ILayerService';
|
||||
|
||||
@injectable()
|
||||
export default class LayerService extends EventEmitter<LayerServiceEvent>
|
||||
implements ILayerService {
|
||||
export default class LayerService
|
||||
extends EventEmitter<LayerServiceEvent>
|
||||
implements ILayerService
|
||||
{
|
||||
// pickedLayerId 参数用于指定当前存在被选中的 layer
|
||||
public pickedLayerId: number = -1;
|
||||
public clock = new Clock();
|
||||
|
@ -39,6 +42,9 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
@inject(TYPES.IMapService)
|
||||
private readonly mapService: IMapService;
|
||||
|
||||
@inject(TYPES.IDebugService)
|
||||
private readonly debugService: IDebugService;
|
||||
|
||||
public reRender = throttle(() => {
|
||||
this.updateLayerRenderList();
|
||||
this.renderLayers();
|
||||
|
@ -48,8 +54,8 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
this.renderLayers();
|
||||
}, 16);
|
||||
|
||||
public needPick(type:string): boolean {
|
||||
return this.layerList.some((layer=>layer.needPick(type)))
|
||||
public needPick(type: string): boolean {
|
||||
return this.layerList.some((layer) => layer.needPick(type));
|
||||
}
|
||||
public add(layer: ILayer) {
|
||||
this.layers.push(layer);
|
||||
|
@ -58,9 +64,7 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
this.updateLayerRenderList();
|
||||
this.renderLayers();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public addMask(mask: ILayer) {
|
||||
|
@ -102,7 +106,7 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
return this.layers.find((layer) => layer.name === name);
|
||||
}
|
||||
|
||||
public async remove(layer: ILayer, parentLayer?: ILayer):Promise<void> {
|
||||
public async remove(layer: ILayer, parentLayer?: ILayer): Promise<void> {
|
||||
// Tip: layer.layerChildren 当 layer 存在子图层的情况
|
||||
if (parentLayer) {
|
||||
const layerIndex = parentLayer.layerChildren.indexOf(layer);
|
||||
|
@ -117,13 +121,13 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
}
|
||||
this.updateLayerRenderList();
|
||||
layer.destroy();
|
||||
this.reRender()
|
||||
this.reRender();
|
||||
this.emit('layerChange', this.layers);
|
||||
}
|
||||
|
||||
public async removeAllLayers():Promise<void> {
|
||||
public async removeAllLayers(): Promise<void> {
|
||||
this.destroy();
|
||||
this.reRender()
|
||||
this.reRender();
|
||||
}
|
||||
|
||||
public setEnableRender(flag: boolean) {
|
||||
|
@ -134,10 +138,12 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
if (this.alreadyInRendering || !this.enableRender) {
|
||||
return;
|
||||
}
|
||||
const renderUid = this.debugService.generateRenderUid();
|
||||
this.debugService.renderStart(renderUid);
|
||||
this.alreadyInRendering = true;
|
||||
this.clear();
|
||||
for (const layer of this.layerList) {
|
||||
if (layer.masks.filter((m)=>m.inited).length > 0) {
|
||||
if (layer.masks.filter((m) => m.inited).length > 0) {
|
||||
// 清除上一次的模版缓存
|
||||
this.renderService.clear({
|
||||
stencil: 0,
|
||||
|
@ -146,7 +152,7 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
});
|
||||
layer.masks.map(async (m: ILayer) => {
|
||||
m.render();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (layer.getLayerConfig().enableMultiPassRenderer) {
|
||||
|
@ -154,39 +160,37 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
await layer.renderMultiPass();
|
||||
} else {
|
||||
await layer.render();
|
||||
|
||||
}
|
||||
}
|
||||
this.debugService.renderEnd(renderUid);
|
||||
this.alreadyInRendering = false;
|
||||
}
|
||||
|
||||
public renderMask(masks:ILayer[]) {
|
||||
masks.filter(m => m.inited)
|
||||
.map(m =>{
|
||||
m.render();
|
||||
})
|
||||
|
||||
public renderMask(masks: ILayer[]) {
|
||||
masks
|
||||
.filter((m) => m.inited)
|
||||
.map((m) => {
|
||||
m.render();
|
||||
});
|
||||
}
|
||||
|
||||
public async beforeRenderData(layer: ILayer) {
|
||||
const flag = await layer.hooks.beforeRenderData.promise();
|
||||
if(flag) {
|
||||
if (flag) {
|
||||
this.renderLayers();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async renderLayer(layer: ILayer){
|
||||
|
||||
if (layer.masks.filter((m)=>m.inited).length > 0) {
|
||||
layer.masks.map(mask =>{
|
||||
this.renderService.clear({
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
framebuffer: null,
|
||||
});
|
||||
mask.render();
|
||||
})
|
||||
|
||||
public async renderLayer(layer: ILayer) {
|
||||
if (layer.masks.filter((m) => m.inited).length > 0) {
|
||||
layer.masks.map((mask) => {
|
||||
this.renderService.clear({
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
framebuffer: null,
|
||||
});
|
||||
mask.render();
|
||||
});
|
||||
}
|
||||
if (layer.getLayerConfig().enableMultiPassRenderer) {
|
||||
// multiPassRender 不是同步渲染完成的
|
||||
|
@ -194,7 +198,6 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
} else {
|
||||
await layer.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public updateLayerRenderList() {
|
||||
|
@ -210,7 +213,6 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
.forEach((layer) => {
|
||||
this.layerList.push(layer);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
@ -252,7 +254,6 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
public getShaderPickStat() {
|
||||
return this.shaderPicking;
|
||||
}
|
||||
|
||||
|
||||
public clear() {
|
||||
const color = rgb2arr(this.mapService.bgColor) as [
|
||||
|
@ -279,6 +280,4 @@ export default class LayerService extends EventEmitter<LayerServiceEvent>
|
|||
private stopRender() {
|
||||
$window.cancelAnimationFrame(this.layerRenderID);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import { IMapService } from '../map/IMapService';
|
|||
import { IRenderConfig, IRendererService } from '../renderer/IRendererService';
|
||||
import { IShaderModuleService } from '../shader/IShaderModuleService';
|
||||
import { ISceneService } from './ISceneService';
|
||||
import { IDebugService } from '../debug/IDebugService';
|
||||
|
||||
/**
|
||||
* will emit `loaded` `resize` `destroy` event panstart panmove panend
|
||||
|
@ -65,6 +66,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
@inject(TYPES.ILayerService)
|
||||
private readonly layerService: ILayerService;
|
||||
|
||||
@inject(TYPES.IDebugService)
|
||||
private readonly debugService: IDebugService;
|
||||
|
||||
@inject(TYPES.ICameraService)
|
||||
private readonly cameraService: ICameraService;
|
||||
|
||||
|
@ -134,6 +138,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
* 初始化底图
|
||||
*/
|
||||
this.hooks.init.tapPromise('initMap', async () => {
|
||||
this.debugService.log('map.mapInitStart', {
|
||||
type: this.map.version
|
||||
})
|
||||
// 等待首次相机同步
|
||||
await new Promise<void>((resolve) => {
|
||||
this.map.onCameraChanged((viewport: IViewport) => {
|
||||
|
@ -188,6 +195,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.configService.getSceneConfig(this.id) as IRenderConfig,
|
||||
sceneConfig.gl,
|
||||
);
|
||||
this.registerContextLost();
|
||||
this.initContainer();
|
||||
|
||||
elementResizeEvent(
|
||||
|
@ -208,6 +216,13 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.render();
|
||||
}
|
||||
|
||||
private registerContextLost() {
|
||||
const canvas = this.rendererService.getCanvas();
|
||||
if(canvas) {
|
||||
canvas.addEventListener('webglcontextlost', () => this.emit('webglcontextlost'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序环境下初始化 Scene
|
||||
* @param sceneConfig
|
||||
|
|
|
@ -5,6 +5,7 @@ const TYPES = {
|
|||
ICameraService: Symbol.for('ICameraService'),
|
||||
ICoordinateSystemService: Symbol.for('ICoordinateSystemService'),
|
||||
ILayerService: Symbol.for('ILayerService'),
|
||||
IDebugService: Symbol.for('IDebugService'),
|
||||
ILayerMappingService: Symbol.for('ILayerMappingService'),
|
||||
ILayerStyleService: Symbol.for('ILayerStyleService'),
|
||||
IMapService: Symbol.for('IMapService'),
|
||||
|
|
|
@ -13,6 +13,8 @@ import {
|
|||
ICameraService,
|
||||
ICoordinateSystemService,
|
||||
IDataState,
|
||||
IDebugLog,
|
||||
IDebugService,
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
IGlobalConfigService,
|
||||
|
@ -182,6 +184,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
|
||||
protected layerService: ILayerService;
|
||||
|
||||
protected debugService: IDebugService;
|
||||
|
||||
protected interactionService: IInteractionService;
|
||||
|
||||
protected mapService: IMapService;
|
||||
|
@ -331,6 +335,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
TYPES.IRendererService,
|
||||
);
|
||||
this.layerService = this.container.get<ILayerService>(TYPES.ILayerService);
|
||||
this.debugService = this.container.get<IDebugService>(TYPES.IDebugService);
|
||||
this.interactionService = this.container.get<IInteractionService>(
|
||||
TYPES.IInteractionService,
|
||||
);
|
||||
|
@ -414,9 +419,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
|
||||
// 颜色纹理服务
|
||||
this.textureService = new TextureService(this);
|
||||
|
||||
this.log(IDebugLog.LayerInitStart);
|
||||
// 触发 init 生命周期插件
|
||||
await this.hooks.init.promise();
|
||||
this.log(IDebugLog.LayerInitEnd);
|
||||
this.inited = true;
|
||||
|
||||
// 触发初始化完成事件;
|
||||
|
@ -431,6 +437,22 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
this.hooks.afterInit.call();
|
||||
}
|
||||
|
||||
public log(logType: string, time?: number) {
|
||||
// @ts-ignore 瓦片、瓦片图层目前不参与日志
|
||||
if (this.tileLayer || this.isTileLayer) {
|
||||
return;
|
||||
}
|
||||
const key = `${this.id}.${logType}`;
|
||||
const values: { [key: string]: any } = {
|
||||
id: this.id,
|
||||
type: this.type,
|
||||
};
|
||||
if (time) {
|
||||
values.time = time;
|
||||
}
|
||||
this.debugService.log(key, values);
|
||||
}
|
||||
|
||||
public updateModelData(data: IAttributeAndElements) {
|
||||
if (data.attributes && data.elements) {
|
||||
this.models.map((m) => {
|
||||
|
@ -1013,6 +1035,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
this.tileLayer?.destroy();
|
||||
|
||||
this.models = [];
|
||||
// 清除图层日志(如果有的话:非瓦片相关)
|
||||
this.debugService.removeLog(this.id);
|
||||
|
||||
this.emit('remove', {
|
||||
target: this,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
IDebugLog,
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
ILayer,
|
||||
|
@ -32,8 +33,10 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
layer.hooks.init.tapPromise('DataMappingPlugin', async () => {
|
||||
layer.log(IDebugLog.MappingStart);
|
||||
// 初始化重新生成 map
|
||||
this.generateMaping(layer, { styleAttributeService });
|
||||
layer.log(IDebugLog.MappingEnd);
|
||||
});
|
||||
|
||||
layer.hooks.beforeRenderData.tapPromise(
|
||||
|
@ -42,6 +45,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
if (!flag) {
|
||||
return flag;
|
||||
}
|
||||
|
||||
layer.dataState.dataMappingNeedUpdate = false;
|
||||
return this.generateMaping(layer, { styleAttributeService });
|
||||
},
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
|
||||
import {
|
||||
IDebugLog,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
IMapService,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import Source from '@antv/l7-source';
|
||||
import { injectable } from 'inversify';
|
||||
import 'reflect-metadata';
|
||||
|
@ -9,6 +15,7 @@ export default class DataSourcePlugin implements ILayerPlugin {
|
|||
public apply(layer: ILayer) {
|
||||
this.mapService = layer.getContainer().get<IMapService>(TYPES.IMapService);
|
||||
layer.hooks.init.tapPromise('DataSourcePlugin', async () => {
|
||||
layer.log(IDebugLog.SourceInitStart);
|
||||
let source = layer.getSource();
|
||||
if (!source) {
|
||||
// Tip: 用户没有传入 source 的时候使用图层的默认数据
|
||||
|
@ -19,11 +26,13 @@ export default class DataSourcePlugin implements ILayerPlugin {
|
|||
}
|
||||
if (source.inited) {
|
||||
this.updateClusterData(layer);
|
||||
layer.log(IDebugLog.SourceInitEnd);
|
||||
} else {
|
||||
await new Promise((resolve) => {
|
||||
source.on('update', (e) => {
|
||||
if (e.type === 'inited') {
|
||||
this.updateClusterData(layer);
|
||||
layer.log(IDebugLog.SourceInitEnd);
|
||||
}
|
||||
resolve(null);
|
||||
});
|
||||
|
@ -37,7 +46,9 @@ export default class DataSourcePlugin implements ILayerPlugin {
|
|||
|
||||
const dataSourceNeedUpdate = layer.dataState.dataSourceNeedUpdate;
|
||||
layer.dataState.dataSourceNeedUpdate = false;
|
||||
return neeUpdateCluster || dataSourceNeedUpdate;
|
||||
|
||||
const needScale = neeUpdateCluster || dataSourceNeedUpdate;
|
||||
return needScale;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
IDebugLog,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
IScale,
|
||||
|
@ -49,6 +50,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
layer.hooks.init.tapPromise('FeatureScalePlugin', async () => {
|
||||
layer.log(IDebugLog.ScaleInitStart);
|
||||
this.scaleOptions = layer.getScaleOptions();
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes();
|
||||
const dataArray = layer.getSource()?.data.dataArray;
|
||||
|
@ -57,6 +59,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
} else {
|
||||
this.caculateScalesForAttributes(attributes || [], dataArray);
|
||||
}
|
||||
layer.log(IDebugLog.ScaleInitEnd);
|
||||
});
|
||||
|
||||
// 检测数据是否需要更新
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ILayer, ILayerPlugin } from '@antv/l7-core';
|
||||
import { IDebugLog, ILayer, ILayerPlugin } from '@antv/l7-core';
|
||||
import { injectable } from 'inversify';
|
||||
import 'reflect-metadata';
|
||||
import TileLayer from '../tile/tileLayer/BaseLayer';
|
||||
|
@ -7,21 +7,21 @@ import TileLayer from '../tile/tileLayer/BaseLayer';
|
|||
*/
|
||||
@injectable()
|
||||
export default class LayerModelPlugin implements ILayerPlugin {
|
||||
public async initLayerModel(layer: ILayer) {
|
||||
private async build(layer: ILayer) {
|
||||
// 更新Model 配置项
|
||||
layer.prepareBuildModel();
|
||||
// 初始化 Model
|
||||
await layer.buildModels();
|
||||
}
|
||||
|
||||
public async initLayerModel(layer: ILayer) {
|
||||
await this.build(layer);
|
||||
|
||||
layer.styleNeedUpdate = false;
|
||||
}
|
||||
|
||||
public async prepareLayerModel(layer: ILayer) {
|
||||
// 更新Model 配置项
|
||||
layer.prepareBuildModel();
|
||||
// clear layerModel resource
|
||||
// 初始化 Model
|
||||
await layer.buildModels();
|
||||
await this.build(layer);
|
||||
// layer.layerModelNeedUpdate = false;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,9 @@ export default class LayerModelPlugin implements ILayerPlugin {
|
|||
layer.tileLayer = new TileLayer(layer);
|
||||
return;
|
||||
}
|
||||
layer.log(IDebugLog.BuildModelStart);
|
||||
await this.initLayerModel(layer);
|
||||
layer.log(IDebugLog.BuildModelEnd);
|
||||
});
|
||||
|
||||
layer.hooks.beforeRenderData.tapPromise(
|
||||
|
|
|
@ -3,7 +3,6 @@ import { TestScene } from '@antv/l7-test-utils';
|
|||
import PointLayer from '../';
|
||||
|
||||
describe('template', () => {
|
||||
|
||||
const el = document.createElement('div');
|
||||
el.id = 'test-div-id';
|
||||
const body = document.querySelector('body') as HTMLBodyElement;
|
||||
|
@ -40,8 +39,8 @@ describe('template', () => {
|
|||
scene.on('loaded', () =>{
|
||||
scene.addLayer(layer)
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
it('scene layer text', async () => {
|
||||
const layer = new PointLayer({name:'text'}).source(
|
||||
testData,
|
||||
|
@ -60,10 +59,6 @@ describe('template', () => {
|
|||
scene.addLayer(layer)
|
||||
expect(layer.name).toEqual('text')
|
||||
})
|
||||
|
||||
scene.addLayer(layer)
|
||||
|
||||
|
||||
});
|
||||
|
||||
it('scene layer extrude', async () => {
|
||||
|
@ -79,10 +74,9 @@ describe('template', () => {
|
|||
).shape('cloumn')
|
||||
.color('red')
|
||||
.size([5,5,10])
|
||||
scene.addLayer(layer)
|
||||
|
||||
|
||||
|
||||
scene.on('loaded', () =>{
|
||||
scene.addLayer(layer)
|
||||
})
|
||||
});
|
||||
|
||||
it('scene layer simplePoint', async () => {
|
||||
|
@ -101,9 +95,5 @@ describe('template', () => {
|
|||
scene.on('loaded', () =>{
|
||||
scene.addLayer(layer)
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -81,6 +81,7 @@ export default class ReglRendererService implements IRendererService {
|
|||
'EXT_texture_filter_anisotropic',
|
||||
'EXT_blend_minmax',
|
||||
'WEBGL_depth_texture',
|
||||
'WEBGL_lose_context',
|
||||
],
|
||||
profile: true,
|
||||
onDone: (err: Error | null, r?: regl.Regl | undefined): void => {
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
IInteractionService,
|
||||
ILayer,
|
||||
ILayerService,
|
||||
IDebugService,
|
||||
ILngLat,
|
||||
IMapService,
|
||||
IMarker,
|
||||
|
@ -57,6 +58,7 @@ class Scene
|
|||
private mapService: IMapService<unknown>;
|
||||
private controlService: IControlService;
|
||||
private layerService: ILayerService;
|
||||
private debugService: IDebugService;
|
||||
private iconService: IIconService;
|
||||
private markerService: IMarkerService;
|
||||
private popupService: IPopupService;
|
||||
|
@ -90,6 +92,8 @@ class Scene
|
|||
TYPES.IControlService,
|
||||
);
|
||||
this.layerService = sceneContainer.get<ILayerService>(TYPES.ILayerService);
|
||||
this.debugService = sceneContainer.get<IDebugService>(TYPES.IDebugService);
|
||||
this.debugService.setEnable(config.debug);
|
||||
|
||||
this.markerService = sceneContainer.get<IMarkerService>(
|
||||
TYPES.IMarkerService,
|
||||
|
@ -147,6 +151,15 @@ class Scene
|
|||
public getMapService(): IMapService<unknown> {
|
||||
return this.mapService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外暴露 debugService
|
||||
* @returns
|
||||
*/
|
||||
public getDebugService(): IDebugService{
|
||||
return this.debugService;
|
||||
}
|
||||
|
||||
public async exportPng(type?: 'png' | 'jpg'): Promise<string> {
|
||||
return await this.sceneService.exportPng(type);
|
||||
}
|
||||
|
|
|
@ -308,6 +308,14 @@ export default defineConfig({
|
|||
},
|
||||
order: 11,
|
||||
},
|
||||
{
|
||||
slug: 'tutorial/debug',
|
||||
title: {
|
||||
zh: '调试 debug',
|
||||
en: 'debug',
|
||||
},
|
||||
order: 12,
|
||||
},
|
||||
{
|
||||
slug: 'api/map',
|
||||
title: {
|
||||
|
@ -412,6 +420,14 @@ export default defineConfig({
|
|||
},
|
||||
order: 11,
|
||||
},
|
||||
{
|
||||
slug: 'api/debug',
|
||||
title: {
|
||||
zh: '调试 debug',
|
||||
en: 'debug',
|
||||
},
|
||||
order: 12,
|
||||
},
|
||||
{
|
||||
slug: 'api/component/control',
|
||||
title: {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: DebugService
|
||||
order: 0
|
||||
---
|
||||
|
||||
<embed src="@/docs/api/debug/debugservice.zh.md"></embed>
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
title: DebugService
|
||||
order: 0
|
||||
---
|
||||
|
||||
<embed src="@/docs/common/style.md"></embed>
|
||||
|
||||
## 简介
|
||||
|
||||
L7 在通过 debugService 的形式对外提供调试服务,通过 debugService 用户可以获得一些有助于性能监控的信息。
|
||||
|
||||
### serEnable(enable: boolean)
|
||||
|
||||
用户可以通过 scene 初始化的时候和 debugService 提供的方法来开启监控。
|
||||
|
||||
```js
|
||||
// 可以在 scene 初始化的时候打开监控
|
||||
const scene = new Scene({
|
||||
debug: true, // 默认为 false
|
||||
});
|
||||
|
||||
// 可以通过 debugService 单独控制监控
|
||||
const debugService = scene.getDebugService();
|
||||
debugService.serEnable(true); // 开启监控
|
||||
```
|
||||
|
||||
### getLog(field: undefined | string | string[]): ILog[] | ILog | undefined
|
||||
|
||||
用户通过 getLog 方法获取日志,通过传入不通的参数,用户可以准确获得自己需要的日志内容。
|
||||
|
||||
```js
|
||||
// 获取地图初始化日志
|
||||
debugService.getLog('map'); // map 为固定值
|
||||
|
||||
// 在获取图层的创建日志时,为了获取到全部的数据,需要在 layer 创建完成之后获取
|
||||
layer.on('inited', () => {
|
||||
debugService.getLog(layer.id); // 获取单个图层创建日志
|
||||
});
|
||||
|
||||
layerAllLoad([pointLayer1, pointLayer2], () => {
|
||||
// layerAllLoad 自己实现监听
|
||||
debugService.getLog([pointLayer1.id, pointLayer2.id]); // 获取多个图层创建日志
|
||||
});
|
||||
|
||||
// 获取所有日志
|
||||
debugService.getLog();
|
||||
```
|
||||
|
||||
- 通过 getLog 方法可以获得如下的日志信息
|
||||
|
||||
```js
|
||||
const enum IDebugLog {
|
||||
MapInitStart = 'mapInitStart', // 地图初始化时间
|
||||
|
||||
LayerInitStart = 'layerInitStart', // 图层初始化开始时间
|
||||
LayerInitEnd = 'layerInitEnd', // 图层初始化结束时间
|
||||
|
||||
SourceInitStart = 'sourceInitStart',// souce 初始化开始时间
|
||||
SourceInitEnd = 'sourceInitEnd', // souce 初始化结束时间
|
||||
|
||||
// scale:将数据进行 scale 映射处理 => 将数据从定义域转化到值域
|
||||
// 如: layer.size('v', [1, 10]);
|
||||
// 根据字段 v 表示的定义域将 size 的结果映射到 1 ~ 10 之间
|
||||
ScaleInitStart = 'scaleInitStart', // scale 初始化开始时间
|
||||
ScaleInitEnd = 'scaleInitEnd', // scale 初始化结束时间
|
||||
|
||||
// mapping:构建渲染数据
|
||||
MappingStart = 'mappingStart', // mapping 初始化开始时间
|
||||
MappingEnd = 'mappingEnd', // mapping 初始化结束时间
|
||||
|
||||
// build model:构建渲染使用的程序对象、构建网格、纹理等
|
||||
BuildModelStart = 'buildModelStart',// souce 初始化开始时间
|
||||
BuildModelEnd = 'buildModelEnd', // souce 初始化结束时间
|
||||
}
|
||||
```
|
||||
|
||||
### renderDebug(enable: boolean)
|
||||
|
||||
debugService 提供了监听图层渲染时间的便捷方法, 通过 renderDebug 开启。
|
||||
|
||||
### on(name: string, options: any)
|
||||
|
||||
debugService 支持事件监听,常用与监听渲染。
|
||||
|
||||
```js
|
||||
debugService.on('renderEnd', renderInfo => {
|
||||
const {
|
||||
renderUid, // 当前帧渲染唯一编号
|
||||
renderStart, // 当前帧渲染开始时间
|
||||
renderEnd, // 当前帧渲染结束时间
|
||||
renderDuration // 当前帧渲染时间
|
||||
} = renderInfo;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### off(name: string, func: Function)
|
||||
|
||||
debugService 事件取消监听。
|
|
@ -725,6 +725,8 @@ scene.on('contextmenu', (ev) => {}); // 鼠标右键单击事件
|
|||
scene.on('dragstart', (ev) => {}); //开始拖拽地图时触发
|
||||
scene.on('dragging', (ev) => {}); // 拖拽地图过程中触发
|
||||
scene.on('dragend', (ev) => {}); //停止拖拽地图时触发。如地图有拖拽缓动效果,则在拽停止,缓动开始前触发
|
||||
|
||||
scene.on('webglcontextlost', () => {}); // webgl 上下文丢失
|
||||
```
|
||||
|
||||
## 实验参数
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Layer Init
|
||||
order: 1
|
||||
---
|
||||
<embed src="@/docs/tutorial/debug/layerInit.zh.md"></embed>
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
title: 图层初始化
|
||||
order: 1
|
||||
---
|
||||
<embed src="@/docs/common/style.md"></embed>
|
||||
|
||||
在地图应用中,渲染大数据的地理数据是十分常见的需求,为了保证应用的流畅性,需要追求极致的渲染性能,为此监控引擎渲染内容对于优化性能,建设地图可视化应用性能指标有切实的意义。
|
||||
|
||||
### 实现
|
||||
|
||||
下面介绍如何使用 L7 提供的能力简单获取图层的初始化的信息。
|
||||
|
||||
```javascript
|
||||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 60, 40.7128 ],
|
||||
zoom: 2
|
||||
}),
|
||||
debug: true
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
const debugService = scene.getDebugService();
|
||||
const layer = new PointLayer()
|
||||
.source([{lng: 120, lat: 30}], {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.size(10)
|
||||
.color('#f00');
|
||||
layer.on('inited', () => {
|
||||
console.log(debugService.getLog(layer.id));
|
||||
})
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Map Init
|
||||
order: 2
|
||||
---
|
||||
<embed src="@/docs/tutorial/debug/mapInit.zh.md"></embed>
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: 地图初始化
|
||||
order: 1
|
||||
---
|
||||
<embed src="@/docs/common/style.md"></embed>
|
||||
|
||||
在地图应用中,渲染大数据的地理数据是十分常见的需求,为了保证应用的流畅性,需要追求极致的渲染性能,为此监控引擎渲染内容对于优化性能,建设地图可视化应用性能指标有切实的意义。
|
||||
|
||||
### 实现
|
||||
|
||||
下面介绍如何使用 L7 提供的能力简单获取地图的初始化的信息。
|
||||
|
||||
```javascript
|
||||
import { Scene } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 60, 40.7128 ],
|
||||
zoom: 2
|
||||
}),
|
||||
debug: true
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
const debugService = scene.getDebugService();
|
||||
console.log(debugService.getLog('map');)
|
||||
});
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Render
|
||||
order: 2
|
||||
---
|
||||
<embed src="@/docs/tutorial/debug/render.zh.md"></embed>
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: 渲染监控
|
||||
order: 3
|
||||
---
|
||||
<embed src="@/docs/common/style.md"></embed>
|
||||
|
||||
在地图应用中,渲染大数据的地理数据是十分常见的需求,为了保证应用的流畅性,需要追求极致的渲染性能,为此监控引擎渲染内容对于优化性能,建设地图可视化应用性能指标有切实的意义。
|
||||
|
||||
### 实现
|
||||
|
||||
下面介绍如何使用 L7 提供的能力简单获取应用的渲染性能信息。
|
||||
|
||||
```javascript
|
||||
import { Scene } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 60, 40.7128 ],
|
||||
zoom: 2
|
||||
}),
|
||||
debug: true
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
const debugService = scene.getDebugService();
|
||||
// 开启每帧渲染的监控
|
||||
debugService.renderDebug(true)
|
||||
debugService.on('renderEnd', renderInfo => {
|
||||
const {
|
||||
renderUid, // 当前帧渲染唯一编号
|
||||
renderStart, // 当前帧渲染开始时间
|
||||
renderEnd, // 当前帧渲染结束时间
|
||||
renderDuration // 当前帧渲染时间
|
||||
} = renderInfo;
|
||||
...
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
debugService.renderDebug(false);
|
||||
debugService.off('renderEnd');
|
||||
}, 1000); // 监听 1s 内的渲染情况
|
||||
});
|
||||
```
|
||||
|
|
@ -22,3 +22,10 @@ export function djb2hash(str: string) {
|
|||
}
|
||||
return hash >>> 0;
|
||||
}
|
||||
|
||||
export function guid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
// @ts-ignore
|
||||
export { djb2hash, BKDRHash, guid } from './hash';
|
||||
|
||||
import * as DOM from './dom';
|
||||
import * as Satistics from './statistics';
|
||||
|
||||
export { DOM, Satistics };
|
||||
|
||||
export * from './mini-adapter/index';
|
||||
export * from './ajax';
|
||||
export * from './anchor';
|
||||
export * from './color';
|
||||
export * from './cull';
|
||||
export * as DOM from './dom';
|
||||
|
||||
export * from './env';
|
||||
export * from './event';
|
||||
export * from './geo';
|
||||
export { BKDRHash, djb2hash } from './hash';
|
||||
export * from './lineAtOffset';
|
||||
export * from './lru_cache';
|
||||
export * from './mini-adapter/index';
|
||||
export * as Satistics from './statistics';
|
||||
|
||||
export * from './stencli';
|
||||
export * from './tileset-manager';
|
||||
export * from './worker-helper';
|
||||
|
|
Loading…
Reference in New Issue