Skip to content

Commit

Permalink
feat(layer): add setSelect setActive 方法 & refactor color util
Browse files Browse the repository at this point in the history
  • Loading branch information
lzxue committed Dec 17, 2019
1 parent fe8b480 commit 5c27d66
Show file tree
Hide file tree
Showing 24 changed files with 234 additions and 88 deletions.
8 changes: 7 additions & 1 deletion packages/component/src/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ export default class Popup extends EventEmitter implements IPopup {
};
}

private onClickClose() {
private onClickClose(e: Event) {
if (e.stopPropagation) {
e.stopPropagation();
}
this.remove();
}

Expand Down Expand Up @@ -193,6 +196,9 @@ export default class Popup extends EventEmitter implements IPopup {
this.container.addEventListener('mousedown', (e) => {
e.stopPropagation();
});
this.container.addEventListener('click', (e) => {
e.stopPropagation();
});
}
if (maxWidth && this.container.style.maxWidth !== maxWidth) {
this.container.style.maxWidth = maxWidth;
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/services/component/PopupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export default class PopupService implements IPopupService {
}

public addPopup(popup: IPopup) {
this.popup.remove();
if (this.popup) {
this.popup.remove();
}
popup.addTo(this.scene);
this.popup = popup;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/services/config/ConfigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
active: false,
activeColor: 'red',
enableHighlight: false,
enableSelect: false,
highlightColor: 'red',
selectColor: 'blue',
enableTAA: false,
jitterScale: 1,
enableLighting: false,
Expand Down
16 changes: 14 additions & 2 deletions packages/core/src/services/interaction/IInteractionService.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import { ILngLat } from '../map/IMapService';
export enum InteractionEvent {
Hover = 'hover',
Click = 'click',
Select = 'select',
Active = 'active',
}
export interface IInteractionTarget {
x: number;
y: number;
lngLat: ILngLat;
type: string;
featureId?: number;
}

export interface IInteractionService {
init(): void;
destroy(): void;
on(
eventName: InteractionEvent,
callback: (params: { x: number; y: number; type: string }) => void,
callback: (params: IInteractionTarget) => void,
): void;
triggerHover({ x, y, type }: { x: number; y: number; type?: string }): void;
triggerHover({ x, y, type }: Partial<IInteractionTarget>): void;
triggerSelect(id: number): void;
triggerActive(id: number): void;
}
10 changes: 9 additions & 1 deletion packages/core/src/services/interaction/InteractionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ export default class InteractionService extends EventEmitter
public triggerHover({ x, y }: { x: number; y: number }) {
this.emit(InteractionEvent.Hover, { x, y });
}
public triggerSelect(id: number): void {
this.emit(InteractionEvent.Select, { featureId: id });
}

public triggerActive(id: number): void {
this.emit(InteractionEvent.Active, { featureId: id });
}

private addEventListenerOnMap() {
const $containter = this.mapService.getMapContainer();
Expand Down Expand Up @@ -81,6 +88,7 @@ export default class InteractionService extends EventEmitter
x -= left;
y -= top;
}
this.emit(InteractionEvent.Hover, { x, y, type });
const lngLat = this.mapService.containerToLngLat([x, y]);
this.emit(InteractionEvent.Hover, { x, y, lngLat, type });
};
}
7 changes: 7 additions & 0 deletions packages/core/src/services/layer/ILayerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export interface ILayer {
beforePickingEncode: SyncHook<void>;
afterPickingEncode: SyncHook<void>;
beforeHighlight: SyncHook<[number[]]>;
beforeSelect: SyncHook<[number[]]>;
afterSelect: SyncHook<void>;
afterHighlight: SyncHook<void>;
beforeDestroy: SyncHook<void>;
afterDestroy: SyncHook<void>;
Expand All @@ -86,6 +88,8 @@ export interface ILayer {
getLayerConfig(): Partial<ILayerConfig & ISceneConfig>;
getContainer(): Container;
setContainer(container: Container): void;
setCurrentPickId(id: number | null): void;
getCurrentPickId(): number | null;
buildLayerModel(
options: ILayerModelInitializationOptions &
Partial<IModelInitializationOptions>,
Expand Down Expand Up @@ -198,10 +202,13 @@ export interface ILayerConfig {
* 开启高亮
*/
enableHighlight: boolean;

enableSelect: boolean;
/**
* 高亮颜色
*/
highlightColor: string | number[];
selectColor: string | number[];
active: boolean;
activeColor: string | number[];
/**
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/services/renderer/passes/BaseNormalPass.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { inject, injectable } from 'inversify';
import { IRendererService, IShaderModuleService } from '../../../index';
import {
IMapService,
IRendererService,
IShaderModuleService,
} from '../../../index';
import { TYPES } from '../../../types';
import { ICameraService } from '../../camera/ICameraService';
import { IInteractionService } from '../../interaction/IInteractionService';
Expand All @@ -17,6 +21,7 @@ export default class BaseNormalPass<InitializationOptions = {}>

protected rendererService: IRendererService;
protected cameraService: ICameraService;
protected mapService: IMapService;
protected interactionService: IInteractionService;
protected layerService: ILayerService;

Expand All @@ -38,6 +43,7 @@ export default class BaseNormalPass<InitializationOptions = {}>
this.cameraService = layer
.getContainer()
.get<ICameraService>(TYPES.ICameraService);
this.mapService = layer.getContainer().get<IMapService>(TYPES.IMapService);
this.interactionService = layer
.getContainer()
.get<IInteractionService>(TYPES.IInteractionService);
Expand Down
135 changes: 87 additions & 48 deletions packages/core/src/services/renderer/passes/PixelPickingPass.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { decodePickingColor, encodePickingColor } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
import { TYPES } from '../../../types';
import { InteractionEvent } from '../../interaction/IInteractionService';
import {
IInteractionTarget,
InteractionEvent,
} from '../../interaction/IInteractionService';
import { ILayer } from '../../layer/ILayerService';
import { ILogService } from '../../log/ILogService';
import { ILngLat } from '../../map/IMapService';
import { gl } from '../gl';
import { IFramebuffer } from '../IFramebuffer';
import { PassType } from '../IMultiPassRenderer';
import BaseNormalPass from './BaseNormalPass';

function decodePickingColor(color: Uint8Array): number {
const [i1, i2, i3] = color;
// 1 was added to seperate from no selection
const index = i1 + i2 * 256 + i3 * 65536 - 1;
return index;
}

/**
* color-based PixelPickingPass
* @see https://github.com/antvis/L7/blob/next/dev-docs/PixelPickingEngine.md
Expand Down Expand Up @@ -66,6 +64,14 @@ export default class PixelPickingPass<

// 监听 hover 事件
this.interactionService.on(InteractionEvent.Hover, this.pickFromPickingFBO);
this.interactionService.on(
InteractionEvent.Select,
this.selectFeatureHander.bind(this),
);
this.interactionService.on(
InteractionEvent.Active,
this.highlightFeatureHander.bind(this),
);
}

public render(layer: ILayer) {
Expand Down Expand Up @@ -112,15 +118,7 @@ export default class PixelPickingPass<
* 拾取视口指定坐标属于的要素
* TODO:支持区域拾取
*/
private pickFromPickingFBO = ({
x,
y,
type,
}: {
x: number;
y: number;
type: string;
}) => {
private pickFromPickingFBO = ({ x, y, lngLat, type }: IInteractionTarget) => {
if (!this.layer.isVisible()) {
return;
}
Expand All @@ -130,7 +128,7 @@ export default class PixelPickingPass<
useFramebuffer,
} = this.rendererService;
const { width, height } = getViewportSize();
const { enableHighlight } = this.layer.getLayerConfig();
const { enableHighlight, enableSelect } = this.layer.getLayerConfig();

const xInDevicePixel = x * window.devicePixelRatio;
const yInDevicePixel = y * window.devicePixelRatio;
Expand All @@ -142,7 +140,6 @@ export default class PixelPickingPass<
) {
return;
}

let pickedColors: Uint8Array | undefined;
useFramebuffer(this.pickingFBO, () => {
// avoid realloc
Expand All @@ -166,54 +163,58 @@ export default class PixelPickingPass<
const rawFeature = this.layer
.getSource()
.getFeatureById(pickedFeatureIdx);

const target = {
x,
y,
type,
lngLat,
featureId: pickedFeatureIdx,
feature: rawFeature,
};
if (!rawFeature) {
// this.logger.error(
// '未找到颜色编码解码后的原始 feature,请检查 fragment shader 中末尾是否添加了 `gl_FragColor = filterColor(gl_FragColor);`',
// );
} else {
// trigger onHover/Click callback on layer
this.triggerHoverOnLayer({ x, y, type, feature: rawFeature });
this.layer.setCurrentPickId(pickedFeatureIdx);
this.triggerHoverOnLayer(target);
}
} else {
const target = {
x,
y,
lngLat,
type: this.layer.getCurrentPickId() === null ? 'unpick' : 'mouseout',
featureId: null,
feature: null,
};
this.triggerHoverOnLayer(target);
this.layer.setCurrentPickId(null);
}
});

if (enableHighlight) {
this.highlightPickedFeature(pickedColors);
}
if (
enableSelect &&
type === 'click' &&
pickedColors?.toString() !== [0, 0, 0, 0].toString()
) {
this.selectFeature(pickedColors);
}
};

private triggerHoverOnLayer({
x,
y,
type,
feature,
}: {
private triggerHoverOnLayer(target: {
x: number;
y: number;
type: string;
lngLat: ILngLat;
feature: unknown;
featureId: number | null;
}) {
const { onHover, onClick } = this.layer.getLayerConfig();
// if (onHover) {
// onHover({
// x,
// y,
// feature,
// });
// }
// if (onClick) {
// onClick({
// x,
// y,
// feature,
// });
// }
this.layer.emit(type, {
x,
y,
feature,
});
this.layer.emit(target.type, target);
}

/**
Expand All @@ -232,7 +233,6 @@ export default class PixelPickingPass<
private highlightPickedFeature(pickedColors: Uint8Array | undefined) {
const [r, g, b] = pickedColors;
const { clear, useFramebuffer } = this.rendererService;

// 先输出到 PostProcessor
const readFBO = this.layer.multiPassRenderer
.getPostProcessor()
Expand All @@ -257,4 +257,43 @@ export default class PixelPickingPass<
});
this.layer.multiPassRenderer.getPostProcessor().render(this.layer);
}

private selectFeature(pickedColors: Uint8Array | undefined) {
const [r, g, b] = pickedColors;
const { clear, useFramebuffer } = this.rendererService;

// 先输出到 PostProcessor
const readFBO = this.layer.multiPassRenderer
.getPostProcessor()
.getReadFBO();
this.layer.hooks.beforeRender.call();
useFramebuffer(readFBO, () => {
clear({
color: [0, 0, 0, 0],
depth: 1,
stencil: 0,
framebuffer: readFBO,
});

// TODO: highlight pass 需要 multipass
const originRenderFlag = this.layer.multiPassRenderer.getRenderFlag();
this.layer.multiPassRenderer.setRenderFlag(false);
this.layer.hooks.beforeSelect.call([r, g, b]);
this.layer.render();
this.layer.hooks.afterSelect.call();
this.layer.hooks.afterRender.call();
this.layer.multiPassRenderer.setRenderFlag(originRenderFlag);
});
this.layer.multiPassRenderer.getPostProcessor().render(this.layer);
}

private selectFeatureHander({ featureId }: Partial<IInteractionTarget>) {
const pickedColors = encodePickingColor(featureId as number);
this.selectFeature(new Uint8Array(pickedColors));
}

private highlightFeatureHander({ featureId }: Partial<IInteractionTarget>) {
const pickedColors = encodePickingColor(featureId as number);
this.highlightPickedFeature(new Uint8Array(pickedColors));
}
}
Loading

0 comments on commit 5c27d66

Please sign in to comment.