feat(picking): support advanced picking API: `layer.pick({x, y})`

This commit is contained in:
yuqi.pyq 2019-10-25 17:16:53 +08:00
parent 5fc540f8fd
commit 39fb89cc7f
8 changed files with 48 additions and 13 deletions

View File

@ -55,6 +55,7 @@ export * from './services/component/IControlService';
export * from './services/component/IMarkerService'; export * from './services/component/IMarkerService';
export * from './services/component/IPopUpService'; export * from './services/component/IPopUpService';
export * from './services/log/ILogService'; export * from './services/log/ILogService';
export * from './services/interaction/IInteractionService';
/** 全部渲染服务接口 */ /** 全部渲染服务接口 */
export * from './services/renderer/IAttribute'; export * from './services/renderer/IAttribute';

View File

@ -10,4 +10,5 @@ export interface IInteractionService {
eventName: InteractionEvent, eventName: InteractionEvent,
callback: (params: { x: number; y: number }) => void, callback: (params: { x: number; y: number }) => void,
): void; ): void;
triggerHover({ x, y }: { x: number; y: number }): void;
} }

View File

@ -34,6 +34,10 @@ export default class InteractionService extends EventEmitter
this.off(InteractionEvent.Hover); this.off(InteractionEvent.Hover);
} }
public triggerHover({ x, y }: { x: number; y: number }) {
this.emit(InteractionEvent.Hover, { x, y });
}
private addEventListenerOnMap() { private addEventListenerOnMap() {
const $containter = this.mapService.getMapContainer(); const $containter = this.mapService.getMapContainer();
if ($containter) { if ($containter) {

View File

@ -73,6 +73,10 @@ export interface ILayer {
getEncodedData(): IEncodeFeature[]; getEncodedData(): IEncodeFeature[];
getStyleOptions(): Partial<ILayerInitializationOptions>; getStyleOptions(): Partial<ILayerInitializationOptions>;
isDirty(): boolean; isDirty(): boolean;
/**
* 使
*/
pick(query: { x: number; y: number }): void;
} }
/** /**

View File

@ -126,11 +126,17 @@ export default class PixelPickingPass implements IPass {
const { width, height } = getViewportSize(); const { width, height } = getViewportSize();
const { enableHighlight } = this.layer.getStyleOptions(); 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; let pickedColors: Uint8Array | undefined;
useFramebuffer(this.pickingFBO, () => { useFramebuffer(this.pickingFBO, () => {
// avoid realloc // avoid realloc
pickedColors = readPixels({ pickedColors = readPixels({
x: Math.round(x * window.devicePixelRatio), x: Math.round(xInDevicePixel),
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
y: Math.round(height - (y + 1) * window.devicePixelRatio), y: Math.round(height - (y + 1) * window.devicePixelRatio),
width: 1, width: 1,
@ -171,7 +177,6 @@ export default class PixelPickingPass implements IPass {
y: number; y: number;
feature: unknown; feature: unknown;
}) { }) {
// TODO: onClick
const { onHover, onClick } = this.layer.getStyleOptions(); const { onHover, onClick } = this.layer.getStyleOptions();
if (onHover) { if (onHover) {
onHover({ onHover({
@ -180,6 +185,13 @@ export default class PixelPickingPass implements IPass {
feature, feature,
}); });
} }
if (onClick) {
onClick({
x,
y,
feature,
});
}
} }
/** /**

View File

@ -3,12 +3,14 @@ import {
IFontService, IFontService,
IGlobalConfigService, IGlobalConfigService,
IIconService, IIconService,
IInteractionService,
ILayer, ILayer,
ILayerInitializationOptions, ILayerInitializationOptions,
ILayerPlugin, ILayerPlugin,
IMapService, IMapService,
IModel, IModel,
IMultiPassRenderer, IMultiPassRenderer,
InteractionEvent,
IRendererService, IRendererService,
IShaderModuleService, IShaderModuleService,
ISourceCFG, ISourceCFG,
@ -149,6 +151,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
@lazyInject(TYPES.IMapService) @lazyInject(TYPES.IMapService)
private readonly map: IMapService; private readonly map: IMapService;
@lazyInject(TYPES.IInteractionService)
private readonly interactionService: IInteractionService;
constructor( constructor(
styleOptions: Partial<ILayerInitializationOptions & ChildLayerStyleOptions>, styleOptions: Partial<ILayerInitializationOptions & ChildLayerStyleOptions>,
) { ) {
@ -278,6 +283,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
return this.encodedData; return this.encodedData;
} }
public pick({ x, y }: { x: number; y: number }) {
this.interactionService.triggerHover({ x, y });
}
protected buildLayerModel(options: ILayerModelInitializationOptions): IModel { protected buildLayerModel(options: ILayerModelInitializationOptions): IModel {
const { moduleName, vertexShader, fragmentShader, triangulation } = options; const { moduleName, vertexShader, fragmentShader, triangulation } = options;
this.shaderModuleService.registerModule(moduleName, { this.shaderModuleService.registerModule(moduleName, {

View File

@ -1 +0,0 @@
xxxss

View File

@ -69,17 +69,10 @@ export default class AdvancedAPI extends React.Component {
enablePicking: true, enablePicking: true,
enableHighlight: true, enableHighlight: true,
highlightColor: [0, 0, 255], highlightColor: [0, 0, 255],
pickingX: window.innerWidth / 2,
pickingY: window.innerHeight / 2,
}; };
const pointFolder = gui.addFolder('拾取 & 高亮'); const pointFolder = gui.addFolder('非鼠标 hover 交互');
// pointFolder
// .add(styleOptions, 'enablePicking')
// .onChange((enablePicking: boolean) => {
// // FIXME: 该配置项会影响到初始化阶段 PixelPickingPass 的添加,暂不支持在运行时更改
// layer.style({
// enablePicking,
// });
// scene.render();
// });
pointFolder pointFolder
.add(styleOptions, 'enableHighlight') .add(styleOptions, 'enableHighlight')
.onChange((enableHighlight: boolean) => { .onChange((enableHighlight: boolean) => {
@ -88,6 +81,18 @@ export default class AdvancedAPI extends React.Component {
}); });
scene.render(); 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 pointFolder
.addColor(styleOptions, 'highlightColor') .addColor(styleOptions, 'highlightColor')
.onChange((highlightColor: number[]) => { .onChange((highlightColor: number[]) => {