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:
YiQianYao 2023-02-14 17:26:11 +08:00 committed by GitHub
parent 5a96e01ad5
commit b0d9862164
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 620 additions and 72 deletions

View File

@ -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)
});
});
}, []);

View File

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

View File

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

View File

@ -17,6 +17,7 @@ export interface ISceneConfig extends IRenderConfig {
pickBufferScale?: number;
// TODO: 场景是否支持 stencil mask
stencil?: boolean;
debug?: boolean;
}
export interface IGlobalConfigService {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
});
// 检测数据是否需要更新

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
---
title: DebugService
order: 0
---
<embed src="@/docs/api/debug/debugservice.zh.md"></embed>

View File

@ -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 事件取消监听。

View File

@ -725,6 +725,8 @@ scene.on('contextmenu', (ev) => {}); // 鼠标右键单击事件
scene.on('dragstart', (ev) => {}); //开始拖拽地图时触发
scene.on('dragging', (ev) => {}); // 拖拽地图过程中触发
scene.on('dragend', (ev) => {}); //停止拖拽地图时触发。如地图有拖拽缓动效果,则在拽停止,缓动开始前触发
scene.on('webglcontextlost', () => {}); // webgl 上下文丢失
```
## 实验参数

View File

@ -0,0 +1,5 @@
---
title: Layer Init
order: 1
---
<embed src="@/docs/tutorial/debug/layerInit.zh.md"></embed>

View File

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

View File

@ -0,0 +1,5 @@
---
title: Map Init
order: 2
---
<embed src="@/docs/tutorial/debug/mapInit.zh.md"></embed>

View File

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

View File

@ -0,0 +1,5 @@
---
title: Render
order: 2
---
<embed src="@/docs/tutorial/debug/render.zh.md"></embed>

View File

@ -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 内的渲染情况
});
```

View File

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

View File

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