From 39fb89cc7f3e4abd2aa97de4d0b7f0b0673da065 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Fri, 25 Oct 2019 17:16:53 +0800 Subject: [PATCH] feat(picking): support advanced picking API: `layer.pick({x, y})` --- packages/core/src/index.ts | 1 + .../interaction/IInteractionService.ts | 1 + .../interaction/InteractionService.ts | 4 +++ .../core/src/services/layer/ILayerService.ts | 4 +++ .../renderer/passes/PixelPickingPass.ts | 16 ++++++++++-- packages/layers/src/core/BaseLayer.ts | 9 +++++++ stories/MapAdaptor/Map.md | 1 - stories/Picking/components/AdvancedAPI.tsx | 25 +++++++++++-------- 8 files changed, 48 insertions(+), 13 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 02a989997b..349a16a5a1 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -55,6 +55,7 @@ export * from './services/component/IControlService'; export * from './services/component/IMarkerService'; export * from './services/component/IPopUpService'; export * from './services/log/ILogService'; +export * from './services/interaction/IInteractionService'; /** 全部渲染服务接口 */ export * from './services/renderer/IAttribute'; diff --git a/packages/core/src/services/interaction/IInteractionService.ts b/packages/core/src/services/interaction/IInteractionService.ts index 627c171f0f..df77a1d265 100644 --- a/packages/core/src/services/interaction/IInteractionService.ts +++ b/packages/core/src/services/interaction/IInteractionService.ts @@ -10,4 +10,5 @@ export interface IInteractionService { eventName: InteractionEvent, callback: (params: { x: number; y: number }) => void, ): void; + triggerHover({ x, y }: { x: number; y: number }): void; } diff --git a/packages/core/src/services/interaction/InteractionService.ts b/packages/core/src/services/interaction/InteractionService.ts index e29ba59ad9..e1860a3297 100644 --- a/packages/core/src/services/interaction/InteractionService.ts +++ b/packages/core/src/services/interaction/InteractionService.ts @@ -34,6 +34,10 @@ export default class InteractionService extends EventEmitter this.off(InteractionEvent.Hover); } + public triggerHover({ x, y }: { x: number; y: number }) { + this.emit(InteractionEvent.Hover, { x, y }); + } + private addEventListenerOnMap() { const $containter = this.mapService.getMapContainer(); if ($containter) { diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 785d6e061e..cca590aa5f 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -73,6 +73,10 @@ export interface ILayer { getEncodedData(): IEncodeFeature[]; getStyleOptions(): Partial; isDirty(): boolean; + /** + * 直接调用拾取方法,在非鼠标交互场景中使用 + */ + pick(query: { x: number; y: number }): void; } /** diff --git a/packages/core/src/services/renderer/passes/PixelPickingPass.ts b/packages/core/src/services/renderer/passes/PixelPickingPass.ts index 9ce74de6f2..ab28428eaf 100644 --- a/packages/core/src/services/renderer/passes/PixelPickingPass.ts +++ b/packages/core/src/services/renderer/passes/PixelPickingPass.ts @@ -126,11 +126,17 @@ export default class PixelPickingPass implements IPass { const { width, height } = getViewportSize(); const { enableHighlight } = this.layer.getStyleOptions(); + const xInDevicePixel = x * window.devicePixelRatio; + const yInDevicePixel = y * window.devicePixelRatio; + if (xInDevicePixel > width || xInDevicePixel < 0 || yInDevicePixel > height || yInDevicePixel < 0) { + return; + } + let pickedColors: Uint8Array | undefined; useFramebuffer(this.pickingFBO, () => { // avoid realloc pickedColors = readPixels({ - x: Math.round(x * window.devicePixelRatio), + x: Math.round(xInDevicePixel), // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 y: Math.round(height - (y + 1) * window.devicePixelRatio), width: 1, @@ -171,7 +177,6 @@ export default class PixelPickingPass implements IPass { y: number; feature: unknown; }) { - // TODO: onClick const { onHover, onClick } = this.layer.getStyleOptions(); if (onHover) { onHover({ @@ -180,6 +185,13 @@ export default class PixelPickingPass implements IPass { feature, }); } + if (onClick) { + onClick({ + x, + y, + feature, + }); + } } /** diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index 938c228c8c..6d45cff0b2 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -3,12 +3,14 @@ import { IFontService, IGlobalConfigService, IIconService, + IInteractionService, ILayer, ILayerInitializationOptions, ILayerPlugin, IMapService, IModel, IMultiPassRenderer, + InteractionEvent, IRendererService, IShaderModuleService, ISourceCFG, @@ -149,6 +151,9 @@ export default class BaseLayer implements ILayer { @lazyInject(TYPES.IMapService) private readonly map: IMapService; + @lazyInject(TYPES.IInteractionService) + private readonly interactionService: IInteractionService; + constructor( styleOptions: Partial, ) { @@ -278,6 +283,10 @@ export default class BaseLayer implements ILayer { return this.encodedData; } + public pick({ x, y }: { x: number; y: number }) { + this.interactionService.triggerHover({ x, y }); + } + protected buildLayerModel(options: ILayerModelInitializationOptions): IModel { const { moduleName, vertexShader, fragmentShader, triangulation } = options; this.shaderModuleService.registerModule(moduleName, { diff --git a/stories/MapAdaptor/Map.md b/stories/MapAdaptor/Map.md index f52740c0ec..e69de29bb2 100644 --- a/stories/MapAdaptor/Map.md +++ b/stories/MapAdaptor/Map.md @@ -1 +0,0 @@ -xxxss \ No newline at end of file diff --git a/stories/Picking/components/AdvancedAPI.tsx b/stories/Picking/components/AdvancedAPI.tsx index 9823928652..b8be10b2f9 100644 --- a/stories/Picking/components/AdvancedAPI.tsx +++ b/stories/Picking/components/AdvancedAPI.tsx @@ -69,17 +69,10 @@ export default class AdvancedAPI extends React.Component { enablePicking: true, enableHighlight: true, highlightColor: [0, 0, 255], + pickingX: window.innerWidth / 2, + pickingY: window.innerHeight / 2, }; - const pointFolder = gui.addFolder('拾取 & 高亮'); - // pointFolder - // .add(styleOptions, 'enablePicking') - // .onChange((enablePicking: boolean) => { - // // FIXME: 该配置项会影响到初始化阶段 PixelPickingPass 的添加,暂不支持在运行时更改 - // layer.style({ - // enablePicking, - // }); - // scene.render(); - // }); + const pointFolder = gui.addFolder('非鼠标 hover 交互'); pointFolder .add(styleOptions, 'enableHighlight') .onChange((enableHighlight: boolean) => { @@ -88,6 +81,18 @@ export default class AdvancedAPI extends React.Component { }); scene.render(); }); + pointFolder + .add(styleOptions, 'pickingX', 0, window.innerWidth) + .onChange((pickingX: number) => { + layer.pick({ x: pickingX, y: styleOptions.pickingY }); + // scene.render(); + }); + pointFolder + .add(styleOptions, 'pickingY', 0, window.innerHeight) + .onChange((pickingY: number) => { + layer.pick({ x: styleOptions.pickingX, y: pickingY }); + // scene.render(); + }); pointFolder .addColor(styleOptions, 'highlightColor') .onChange((highlightColor: number[]) => {