mirror of https://gitee.com/antv-l7/antv-l7
refactor(feature picking): feature picking
This commit is contained in:
parent
17f44bb2f7
commit
5936f9aa47
|
@ -104,6 +104,7 @@
|
||||||
"stylelint-config-styled-components": "^0.1.1",
|
"stylelint-config-styled-components": "^0.1.1",
|
||||||
"stylelint-processor-styled-components": "^1.3.2",
|
"stylelint-processor-styled-components": "^1.3.2",
|
||||||
"svg-inline-loader": "^0.8.0",
|
"svg-inline-loader": "^0.8.0",
|
||||||
|
"tapable": "^1.1.3",
|
||||||
"ts-jest": "^24.0.2",
|
"ts-jest": "^24.0.2",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"tslint-config-prettier": "^1.15.0",
|
"tslint-config-prettier": "^1.15.0",
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { IControlService } from './services/component/IControlService';
|
||||||
import { IGlobalConfigService } from './services/config/IConfigService';
|
import { IGlobalConfigService } from './services/config/IConfigService';
|
||||||
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
||||||
import { IInteractionService } from './services/interaction/IInteractionService';
|
import { IInteractionService } from './services/interaction/IInteractionService';
|
||||||
|
import { IPickingService } from './services/interaction/IPickingService';
|
||||||
import { ILayerService } from './services/layer/ILayerService';
|
import { ILayerService } from './services/layer/ILayerService';
|
||||||
import { IStyleAttributeService } from './services/layer/IStyleAttributeService';
|
import { IStyleAttributeService } from './services/layer/IStyleAttributeService';
|
||||||
import { ILogService } from './services/log/ILogService';
|
import { ILogService } from './services/log/ILogService';
|
||||||
|
@ -33,6 +34,7 @@ import PopupService from './services/component/PopupService';
|
||||||
import GlobalConfigService from './services/config/ConfigService';
|
import GlobalConfigService from './services/config/ConfigService';
|
||||||
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
|
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
|
||||||
import InteractionService from './services/interaction/InteractionService';
|
import InteractionService from './services/interaction/InteractionService';
|
||||||
|
import PickingService from './services/interaction/PickingService';
|
||||||
import LayerService from './services/layer/LayerService';
|
import LayerService from './services/layer/LayerService';
|
||||||
import StyleAttributeService from './services/layer/StyleAttributeService';
|
import StyleAttributeService from './services/layer/StyleAttributeService';
|
||||||
import LogService from './services/log/LogService';
|
import LogService from './services/log/LogService';
|
||||||
|
@ -180,6 +182,10 @@ export function createSceneContainer() {
|
||||||
.bind<IInteractionService>(TYPES.IInteractionService)
|
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||||
.to(InteractionService)
|
.to(InteractionService)
|
||||||
.inSingletonScope();
|
.inSingletonScope();
|
||||||
|
sceneContainer
|
||||||
|
.bind<IPickingService>(TYPES.IPickingService)
|
||||||
|
.to(PickingService)
|
||||||
|
.inSingletonScope();
|
||||||
sceneContainer
|
sceneContainer
|
||||||
.bind<IControlService>(TYPES.IControlService)
|
.bind<IControlService>(TYPES.IControlService)
|
||||||
.to(ControlService)
|
.to(ControlService)
|
||||||
|
|
|
@ -55,7 +55,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
||||||
zIndex: 0,
|
zIndex: 0,
|
||||||
blend: 'normal',
|
blend: 'normal',
|
||||||
pickedFeatureID: -1,
|
pickedFeatureID: -1,
|
||||||
enableMultiPassRenderer: true,
|
enableMultiPassRenderer: false,
|
||||||
enablePicking: true,
|
enablePicking: true,
|
||||||
active: false,
|
active: false,
|
||||||
activeColor: '#2f54eb',
|
activeColor: '#2f54eb',
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface IPickingService {
|
||||||
|
init(): void;
|
||||||
|
}
|
|
@ -0,0 +1,247 @@
|
||||||
|
import { decodePickingColor, encodePickingColor } from '@antv/l7-utils';
|
||||||
|
import { inject, injectable } from 'inversify';
|
||||||
|
import {
|
||||||
|
IMapService,
|
||||||
|
IRendererService,
|
||||||
|
IShaderModuleService,
|
||||||
|
} from '../../index';
|
||||||
|
import { TYPES } from '../../types';
|
||||||
|
import { ICameraService } from '../camera/ICameraService';
|
||||||
|
import {
|
||||||
|
IInteractionService,
|
||||||
|
IInteractionTarget,
|
||||||
|
InteractionEvent,
|
||||||
|
} from '../interaction/IInteractionService';
|
||||||
|
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||||
|
import { ILngLat } from '../map/IMapService';
|
||||||
|
import { gl } from '../renderer/gl';
|
||||||
|
import { IFramebuffer } from '../renderer/IFramebuffer';
|
||||||
|
import { IPickingService } from './IPickingService';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export default class PickingService implements IPickingService {
|
||||||
|
@inject(TYPES.IRendererService)
|
||||||
|
private rendererService: IRendererService;
|
||||||
|
|
||||||
|
@inject(TYPES.IInteractionService)
|
||||||
|
private interactionService: IInteractionService;
|
||||||
|
|
||||||
|
@inject(TYPES.ILayerService)
|
||||||
|
private layerService: ILayerService;
|
||||||
|
private pickingFBO: IFramebuffer;
|
||||||
|
|
||||||
|
private width: number = 0;
|
||||||
|
|
||||||
|
private height: number = 0;
|
||||||
|
|
||||||
|
private alreadyInPicking: boolean = false;
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
const {
|
||||||
|
createTexture2D,
|
||||||
|
createFramebuffer,
|
||||||
|
getViewportSize,
|
||||||
|
} = this.rendererService;
|
||||||
|
const { width, height } = getViewportSize();
|
||||||
|
// 创建 picking framebuffer,后续实时 resize
|
||||||
|
this.pickingFBO = createFramebuffer({
|
||||||
|
color: createTexture2D({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
wrapS: gl.CLAMP_TO_EDGE,
|
||||||
|
wrapT: gl.CLAMP_TO_EDGE,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听 hover 事件
|
||||||
|
this.interactionService.on(
|
||||||
|
InteractionEvent.Hover,
|
||||||
|
this.pickingAllLayer.bind(this),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private async pickingAllLayer(target: IInteractionTarget) {
|
||||||
|
if (this.alreadyInPicking || this.layerService.alreadyInRendering) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.alreadyInPicking = true;
|
||||||
|
const layers = this.layerService.getLayers();
|
||||||
|
layers
|
||||||
|
.filter((layer) => layer.needPick())
|
||||||
|
.reverse()
|
||||||
|
.forEach(async (layer) => {
|
||||||
|
await this.pickingLayer(layer, target); // 可以实现是否向下触发
|
||||||
|
});
|
||||||
|
this.layerService.renderLayers();
|
||||||
|
this.alreadyInPicking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pickingLayer(layer: ILayer, target: IInteractionTarget) {
|
||||||
|
const { getViewportSize, useFramebuffer, clear } = this.rendererService;
|
||||||
|
const { width, height } = getViewportSize();
|
||||||
|
|
||||||
|
if (this.width !== width || this.height !== height) {
|
||||||
|
this.pickingFBO.resize({ width, height });
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
useFramebuffer(this.pickingFBO, () => {
|
||||||
|
clear({
|
||||||
|
framebuffer: this.pickingFBO,
|
||||||
|
color: [0, 0, 0, 0],
|
||||||
|
stencil: 0,
|
||||||
|
depth: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.hooks.beforePickingEncode.call();
|
||||||
|
layer.renderModels();
|
||||||
|
layer.hooks.afterPickingEncode.call();
|
||||||
|
this.pickFromPickingFBO(layer, target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private pickFromPickingFBO = (
|
||||||
|
layer: ILayer,
|
||||||
|
{ x, y, lngLat, type }: IInteractionTarget,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
getViewportSize,
|
||||||
|
readPixels,
|
||||||
|
useFramebuffer,
|
||||||
|
} = this.rendererService;
|
||||||
|
const { width, height } = getViewportSize();
|
||||||
|
|
||||||
|
const { enableHighlight, enableSelect } = layer.getLayerConfig();
|
||||||
|
|
||||||
|
const xInDevicePixel = x * window.devicePixelRatio;
|
||||||
|
const yInDevicePixel = y * window.devicePixelRatio;
|
||||||
|
if (
|
||||||
|
xInDevicePixel > width ||
|
||||||
|
xInDevicePixel < 0 ||
|
||||||
|
yInDevicePixel > height ||
|
||||||
|
yInDevicePixel < 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let pickedColors: Uint8Array | undefined;
|
||||||
|
|
||||||
|
pickedColors = readPixels({
|
||||||
|
x: Math.round(xInDevicePixel),
|
||||||
|
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
|
||||||
|
y: Math.round(height - (y + 1) * window.devicePixelRatio),
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
data: new Uint8Array(1 * 1 * 4),
|
||||||
|
framebuffer: this.pickingFBO,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
pickedColors[0] !== 0 ||
|
||||||
|
pickedColors[1] !== 0 ||
|
||||||
|
pickedColors[2] !== 0
|
||||||
|
) {
|
||||||
|
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||||
|
const rawFeature = 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
|
||||||
|
layer.setCurrentPickId(pickedFeatureIdx);
|
||||||
|
this.triggerHoverOnLayer(layer, target);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const target = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
lngLat,
|
||||||
|
type: layer.getCurrentPickId() === null ? 'un' + type : 'mouseout',
|
||||||
|
featureId: null,
|
||||||
|
feature: null,
|
||||||
|
};
|
||||||
|
this.triggerHoverOnLayer(layer, {
|
||||||
|
...target,
|
||||||
|
type: 'unpick',
|
||||||
|
});
|
||||||
|
this.triggerHoverOnLayer(layer, target);
|
||||||
|
layer.setCurrentPickId(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableHighlight) {
|
||||||
|
this.highlightPickedFeature(layer, pickedColors);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
enableSelect &&
|
||||||
|
type === 'click' &&
|
||||||
|
pickedColors?.toString() !== [0, 0, 0, 0].toString()
|
||||||
|
) {
|
||||||
|
this.selectFeature(layer, pickedColors);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private triggerHoverOnLayer(
|
||||||
|
layer: ILayer,
|
||||||
|
target: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
type: string;
|
||||||
|
lngLat: ILngLat;
|
||||||
|
feature: unknown;
|
||||||
|
featureId: number | null;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
layer.emit(target.type, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* highlight 如果直接修改选中 feature 的 buffer,存在两个问题:
|
||||||
|
* 1. 鼠标移走时无法恢复
|
||||||
|
* 2. 无法实现高亮颜色与原始原色的 alpha 混合
|
||||||
|
* 因此高亮还是放在 shader 中做比较好
|
||||||
|
* @example
|
||||||
|
* this.layer.color('name', ['#000000'], {
|
||||||
|
* featureRange: {
|
||||||
|
* startIndex: pickedFeatureIdx,
|
||||||
|
* endIndex: pickedFeatureIdx + 1,
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
private highlightPickedFeature(
|
||||||
|
layer: ILayer,
|
||||||
|
pickedColors: Uint8Array | undefined,
|
||||||
|
) {
|
||||||
|
const [r, g, b] = pickedColors;
|
||||||
|
layer.hooks.beforeHighlight.call([r, g, b]);
|
||||||
|
this.layerService.renderLayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private selectFeature(layer: ILayer, pickedColors: Uint8Array | undefined) {
|
||||||
|
const [r, g, b] = pickedColors;
|
||||||
|
layer.hooks.beforeSelect.call([r, g, b]);
|
||||||
|
this.layerService.renderLayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private selectFeatureHandle(
|
||||||
|
layer: ILayer,
|
||||||
|
{ featureId }: Partial<IInteractionTarget>,
|
||||||
|
) {
|
||||||
|
const pickedColors = encodePickingColor(featureId as number);
|
||||||
|
this.selectFeature(layer, new Uint8Array(pickedColors));
|
||||||
|
}
|
||||||
|
|
||||||
|
private highlightFeatureHandle(
|
||||||
|
layer: ILayer,
|
||||||
|
{ featureId }: Partial<IInteractionTarget>,
|
||||||
|
) {
|
||||||
|
const pickedColors = encodePickingColor(featureId as number);
|
||||||
|
this.highlightPickedFeature(layer, new Uint8Array(pickedColors));
|
||||||
|
}
|
||||||
|
}
|
|
@ -111,6 +111,7 @@ export interface ILayer {
|
||||||
setCurrentPickId(id: number | null): void;
|
setCurrentPickId(id: number | null): void;
|
||||||
getCurrentPickId(): number | null;
|
getCurrentPickId(): number | null;
|
||||||
prepareBuildModel(): void;
|
prepareBuildModel(): void;
|
||||||
|
renderModels(): void;
|
||||||
buildModels(): void;
|
buildModels(): void;
|
||||||
buildLayerModel(
|
buildLayerModel(
|
||||||
options: ILayerModelInitializationOptions &
|
options: ILayerModelInitializationOptions &
|
||||||
|
@ -263,6 +264,7 @@ export interface ILayerConfig {
|
||||||
*/
|
*/
|
||||||
export interface ILayerService {
|
export interface ILayerService {
|
||||||
clock: Clock;
|
clock: Clock;
|
||||||
|
alreadyInRendering: boolean;
|
||||||
add(layer: ILayer): void;
|
add(layer: ILayer): void;
|
||||||
initLayers(): void;
|
initLayers(): void;
|
||||||
startAnimate(): void;
|
startAnimate(): void;
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { ILayerModel, ILayerService } from './ILayerService';
|
||||||
export default class LayerService implements ILayerService {
|
export default class LayerService implements ILayerService {
|
||||||
public clock = new Clock();
|
public clock = new Clock();
|
||||||
|
|
||||||
|
public alreadyInRendering: boolean = false;
|
||||||
|
|
||||||
private layers: ILayer[] = [];
|
private layers: ILayer[] = [];
|
||||||
|
|
||||||
private layerRenderID: number;
|
private layerRenderID: number;
|
||||||
|
@ -18,8 +20,6 @@ export default class LayerService implements ILayerService {
|
||||||
|
|
||||||
private animateInstanceCount: number = 0;
|
private animateInstanceCount: number = 0;
|
||||||
|
|
||||||
private alreadyInRendering: boolean = false;
|
|
||||||
|
|
||||||
@inject(TYPES.IRendererService)
|
@inject(TYPES.IRendererService)
|
||||||
private readonly renderService: IRendererService;
|
private readonly renderService: IRendererService;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Probe, { Log } from 'probe.gl';
|
||||||
import { ILogService } from './ILogService';
|
import { ILogService } from './ILogService';
|
||||||
const Logger = new Log({ id: 'L7' }).enable(true);
|
const Logger = new Log({ id: 'L7' }).enable(true);
|
||||||
// // 只输出 debug 级别以上的日志信息
|
// // 只输出 debug 级别以上的日志信息
|
||||||
Logger.priority = 2;
|
Logger.priority = 5;
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export default class LogService implements ILogService {
|
export default class LogService implements ILogService {
|
||||||
|
|
|
@ -38,6 +38,10 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
||||||
private layer: ILayer;
|
private layer: ILayer;
|
||||||
private renderFlag: boolean;
|
private renderFlag: boolean;
|
||||||
|
|
||||||
|
private width: number = 0;
|
||||||
|
|
||||||
|
private height: number = 0;
|
||||||
|
|
||||||
public setLayer(layer: ILayer) {
|
public setLayer(layer: ILayer) {
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +62,16 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
||||||
for (const pass of this.passes) {
|
for (const pass of this.passes) {
|
||||||
await pass.render(this.layer);
|
await pass.render(this.layer);
|
||||||
}
|
}
|
||||||
await this.postProcessor.render(this.layer);
|
this.layer.renderModels();
|
||||||
|
// await this.postProcessor.render(this.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(width: number, height: number) {
|
public resize(width: number, height: number) {
|
||||||
|
if (this.width !== width || this.height !== height) {
|
||||||
this.postProcessor.resize(width, height);
|
this.postProcessor.resize(width, height);
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public add<T>(pass: IPass<T>, config?: Partial<T>) {
|
public add<T>(pass: IPass<T>, config?: Partial<T>) {
|
||||||
|
|
|
@ -60,7 +60,6 @@ export default class PixelPickingPass<
|
||||||
getViewportSize,
|
getViewportSize,
|
||||||
} = this.rendererService;
|
} = this.rendererService;
|
||||||
const { width, height } = getViewportSize();
|
const { width, height } = getViewportSize();
|
||||||
|
|
||||||
// 创建 picking framebuffer,后续实时 resize
|
// 创建 picking framebuffer,后续实时 resize
|
||||||
this.pickingFBO = createFramebuffer({
|
this.pickingFBO = createFramebuffer({
|
||||||
color: createTexture2D({
|
color: createTexture2D({
|
||||||
|
|
|
@ -14,4 +14,9 @@ export interface ISceneService {
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
// scene 事件
|
// scene 事件
|
||||||
export const SceneEventList = ['loaded', 'maploaded', 'resize', 'destroy'];
|
export const SceneEventList: string[] = [
|
||||||
|
'loaded',
|
||||||
|
'maploaded',
|
||||||
|
'resize',
|
||||||
|
'destroy',
|
||||||
|
];
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { IPopupService } from '../component/IPopupService';
|
||||||
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
||||||
import { ICoordinateSystemService } from '../coordinate/ICoordinateSystemService';
|
import { ICoordinateSystemService } from '../coordinate/ICoordinateSystemService';
|
||||||
import { IInteractionService } from '../interaction/IInteractionService';
|
import { IInteractionService } from '../interaction/IInteractionService';
|
||||||
|
import { IPickingService } from '../interaction/IPickingService';
|
||||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||||
import { ILogService } from '../log/ILogService';
|
import { ILogService } from '../log/ILogService';
|
||||||
import { IMapCamera, IMapService } from '../map/IMapService';
|
import { IMapCamera, IMapService } from '../map/IMapService';
|
||||||
|
@ -64,6 +65,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
@inject(TYPES.IInteractionService)
|
@inject(TYPES.IInteractionService)
|
||||||
private readonly interactionService: IInteractionService;
|
private readonly interactionService: IInteractionService;
|
||||||
|
|
||||||
|
@inject(TYPES.IPickingService)
|
||||||
|
private readonly pickingService: IPickingService;
|
||||||
|
|
||||||
@inject(TYPES.IShaderModuleService)
|
@inject(TYPES.IShaderModuleService)
|
||||||
private readonly shaderModuleService: IShaderModuleService;
|
private readonly shaderModuleService: IShaderModuleService;
|
||||||
|
|
||||||
|
@ -150,6 +154,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
this.popupService.initPopup();
|
this.popupService.initPopup();
|
||||||
// 地图初始化之后 才能初始化 container 上的交互
|
// 地图初始化之后 才能初始化 container 上的交互
|
||||||
this.interactionService.init();
|
this.interactionService.init();
|
||||||
|
|
||||||
this.logger.debug(`map ${this.id} loaded`);
|
this.logger.debug(`map ${this.id} loaded`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -174,6 +179,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
} else {
|
} else {
|
||||||
this.logger.error('容器 id 不存在');
|
this.logger.error('容器 id 不存在');
|
||||||
}
|
}
|
||||||
|
this.pickingService.init();
|
||||||
|
|
||||||
this.logger.debug(`scene ${this.id} renderer loaded`);
|
this.logger.debug(`scene ${this.id} renderer loaded`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@ const TYPES = {
|
||||||
IIconService: Symbol.for('IIconService'),
|
IIconService: Symbol.for('IIconService'),
|
||||||
IFontService: Symbol.for('IFontService'),
|
IFontService: Symbol.for('IFontService'),
|
||||||
IInteractionService: Symbol.for('IInteractionService'),
|
IInteractionService: Symbol.for('IInteractionService'),
|
||||||
|
IPickingService: Symbol.for('IPickingService'),
|
||||||
IControlService: Symbol.for('IControlService'),
|
IControlService: Symbol.for('IControlService'),
|
||||||
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
|
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
|
||||||
ILayer: Symbol.for('ILayer'),
|
ILayer: Symbol.for('ILayer'),
|
||||||
|
|
|
@ -170,6 +170,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
|
|
||||||
private aniamateStatus: boolean = false;
|
private aniamateStatus: boolean = false;
|
||||||
|
|
||||||
|
// private pickingPassRender: IPass<'pixelPicking'>;
|
||||||
|
|
||||||
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
||||||
super();
|
super();
|
||||||
this.name = config.name || this.id;
|
this.name = config.name || this.id;
|
||||||
|
@ -228,7 +230,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
// 设置配置项
|
// 设置配置项
|
||||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||||
// 初始化图层配置项
|
// 初始化图层配置项
|
||||||
this.configService.setLayerConfig(sceneId, this.id, {});
|
const { enableMultiPassRenderer = false } = this.rawConfig;
|
||||||
|
this.configService.setLayerConfig(sceneId, this.id, {
|
||||||
|
enableMultiPassRenderer,
|
||||||
|
});
|
||||||
|
|
||||||
// 全局容器服务
|
// 全局容器服务
|
||||||
|
|
||||||
|
@ -297,6 +302,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
|
|
||||||
// 触发 init 生命周期插件
|
// 触发 init 生命周期插件
|
||||||
this.hooks.init.call();
|
this.hooks.init.call();
|
||||||
|
|
||||||
|
// this.pickingPassRender = this.normalPassFactory('pixelPicking');
|
||||||
|
// this.pickingPassRender.init(this);
|
||||||
this.hooks.afterInit.call();
|
this.hooks.afterInit.call();
|
||||||
|
|
||||||
// 触发初始化完成事件;
|
// 触发初始化完成事件;
|
||||||
|
@ -465,11 +473,21 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public render(): ILayer {
|
public render(): ILayer {
|
||||||
if (this.multiPassRenderer && this.multiPassRenderer.getRenderFlag()) {
|
// if (
|
||||||
this.multiPassRenderer.render();
|
// this.needPick() &&
|
||||||
} else {
|
// this.multiPassRenderer &&
|
||||||
|
// this.multiPassRenderer.getRenderFlag()
|
||||||
|
// ) {
|
||||||
|
// this.multiPassRenderer.render();
|
||||||
|
// } else if (this.needPick() && this.multiPassRenderer) {
|
||||||
|
// this.renderModels();
|
||||||
|
// } else {
|
||||||
|
// this.renderModels();
|
||||||
|
// }
|
||||||
|
|
||||||
this.renderModels();
|
this.renderModels();
|
||||||
}
|
// this.multiPassRenderer.render();
|
||||||
|
// this.renderModels();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,11 +824,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getConfigSchema() {
|
public renderModels() {
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
if (this.layerModelNeedUpdate) {
|
if (this.layerModelNeedUpdate) {
|
||||||
this.models = this.layerModel.buildModels();
|
this.models = this.layerModel.buildModels();
|
||||||
this.hooks.beforeRender.call();
|
this.hooks.beforeRender.call();
|
||||||
|
@ -824,6 +838,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getConfigSchema() {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
protected getModelType(): unknown {
|
protected getModelType(): unknown {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,19 +12,7 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
||||||
this.layerModel = new HeatMapModels[shape](this);
|
this.layerModel = new HeatMapModels[shape](this);
|
||||||
this.models = this.layerModel.buildModels();
|
this.models = this.layerModel.buildModels();
|
||||||
}
|
}
|
||||||
protected getConfigSchema() {
|
public renderModels() {
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
opacity: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
const shape = this.getModelType();
|
const shape = this.getModelType();
|
||||||
if (shape === 'heatmap') {
|
if (shape === 'heatmap') {
|
||||||
// if (this.layerModelNeedUpdate) {
|
// if (this.layerModelNeedUpdate) {
|
||||||
|
@ -49,6 +37,18 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
protected getConfigSchema() {
|
||||||
|
return {
|
||||||
|
properties: {
|
||||||
|
opacity: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected getModelType(): HeatMapModelType {
|
protected getModelType(): HeatMapModelType {
|
||||||
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
|
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
|
||||||
'shape',
|
'shape',
|
||||||
|
|
|
@ -76,11 +76,11 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
||||||
});
|
});
|
||||||
|
|
||||||
layer.hooks.beforeRender.tap('MultiPassRendererPlugin', () => {
|
layer.hooks.beforeRender.tap('MultiPassRendererPlugin', () => {
|
||||||
if (this.enabled) {
|
// if (this.enabled) {
|
||||||
// 渲染前根据 viewport 调整 FBO size
|
// // 渲染前根据 viewport 调整 FBO size
|
||||||
const { width, height } = rendererService.getViewportSize();
|
// const { width, height } = rendererService.getViewportSize();
|
||||||
layer.multiPassRenderer.resize(width, height);
|
// layer.multiPassRenderer.resize(width, height);
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,26 +103,26 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// use TAA pass if enabled instead of render pass
|
// use TAA pass if enabled instead of render pass
|
||||||
if (enableTAA) {
|
// if (enableTAA) {
|
||||||
multiPassRenderer.add(normalPassFactory('taa'));
|
// multiPassRenderer.add(normalPassFactory('taa'));
|
||||||
} else {
|
// } else {
|
||||||
// render all layers in this pass
|
// // render all layers in this pass
|
||||||
multiPassRenderer.add(normalPassFactory('render'));
|
// multiPassRenderer.add(normalPassFactory('render'));
|
||||||
}
|
// }
|
||||||
|
|
||||||
// post processing
|
// post processing
|
||||||
normalizePasses(passes).forEach(
|
// normalizePasses(passes).forEach(
|
||||||
(pass: [string, { [key: string]: unknown }]) => {
|
// (pass: [string, { [key: string]: unknown }]) => {
|
||||||
const [passName, initializationOptions] = pass;
|
// const [passName, initializationOptions] = pass;
|
||||||
multiPassRenderer.add(
|
// multiPassRenderer.add(
|
||||||
postProcessingPassFactory(passName),
|
// postProcessingPassFactory(passName),
|
||||||
initializationOptions,
|
// initializationOptions,
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
|
|
||||||
// 末尾为固定的 CopyPass
|
// 末尾为固定的 CopyPass
|
||||||
multiPassRenderer.add(postProcessingPassFactory('copy'));
|
// multiPassRenderer.add(postProcessingPassFactory('copy'));
|
||||||
|
|
||||||
return multiPassRenderer;
|
return multiPassRenderer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ interface IPointLayerStyleOptions {
|
||||||
opacity: number;
|
opacity: number;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
stroke: string;
|
stroke: string;
|
||||||
|
strokeOpacity: number;
|
||||||
}
|
}
|
||||||
export default class FillModel extends BaseModel {
|
export default class FillModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
|
@ -25,11 +26,13 @@ export default class FillModel extends BaseModel {
|
||||||
opacity = 1,
|
opacity = 1,
|
||||||
stroke = 'rgb(0,0,0,0)',
|
stroke = 'rgb(0,0,0,0)',
|
||||||
strokeWidth = 1,
|
strokeWidth = 1,
|
||||||
|
strokeOpacity = 1,
|
||||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity,
|
u_opacity: opacity,
|
||||||
u_stroke_width: strokeWidth,
|
u_stroke_width: strokeWidth,
|
||||||
u_stroke_color: rgb2arr(stroke),
|
u_stroke_color: rgb2arr(stroke),
|
||||||
|
u_stroke_opacity: strokeOpacity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public getAnimateUniforms(): IModelUniform {
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
|
|
@ -57,19 +57,7 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||||
});
|
});
|
||||||
this.models = [this.buildRasterModel()];
|
this.models = [this.buildRasterModel()];
|
||||||
}
|
}
|
||||||
protected getConfigSchema() {
|
public renderModels() {
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
opacity: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
const { opacity, heightRatio = 10 } = this.getLayerConfig();
|
const { opacity, heightRatio = 10 } = this.getLayerConfig();
|
||||||
const parserDataItem = this.getSource().data.dataArray[0];
|
const parserDataItem = this.getSource().data.dataArray[0];
|
||||||
const { coordinates, width, height, min, max } = parserDataItem;
|
const { coordinates, width, height, min, max } = parserDataItem;
|
||||||
|
@ -91,6 +79,18 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
protected getConfigSchema() {
|
||||||
|
return {
|
||||||
|
properties: {
|
||||||
|
opacity: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private buildRasterModel() {
|
private buildRasterModel() {
|
||||||
const source = this.getSource();
|
const source = this.getSource();
|
||||||
const sourceFeature = source.data.dataArray[0];
|
const sourceFeature = source.data.dataArray[0];
|
||||||
|
|
|
@ -57,20 +57,7 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
public renderModels() {
|
||||||
protected getConfigSchema() {
|
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
opacity: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
const { opacity } = this.getLayerConfig();
|
const { opacity } = this.getLayerConfig();
|
||||||
const parserDataItem = this.getSource().data.dataArray[0];
|
const parserDataItem = this.getSource().data.dataArray[0];
|
||||||
const { min, max } = parserDataItem;
|
const { min, max } = parserDataItem;
|
||||||
|
@ -91,6 +78,18 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getConfigSchema() {
|
||||||
|
return {
|
||||||
|
properties: {
|
||||||
|
opacity: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private registerBuiltinAttributes() {
|
private registerBuiltinAttributes() {
|
||||||
// point layer size;
|
// point layer size;
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
|
|
@ -240,6 +240,7 @@ export default class AMapService
|
||||||
if (mapInstance) {
|
if (mapInstance) {
|
||||||
this.map = mapInstance as AMap.Map & IAMapInstance;
|
this.map = mapInstance as AMap.Map & IAMapInstance;
|
||||||
this.$mapContainer = this.map.getContainer();
|
this.$mapContainer = this.map.getContainer();
|
||||||
|
this.removeLogoControl();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.map.on('camerachange', this.handleCameraChanged);
|
this.map.on('camerachange', this.handleCameraChanged);
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -255,6 +256,7 @@ export default class AMapService
|
||||||
viewMode: '3D',
|
viewMode: '3D',
|
||||||
...rest,
|
...rest,
|
||||||
});
|
});
|
||||||
|
this.removeLogoControl();
|
||||||
// 监听地图相机事件
|
// 监听地图相机事件
|
||||||
map.on('camerachange', this.handleCameraChanged);
|
map.on('camerachange', this.handleCameraChanged);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -390,4 +392,12 @@ export default class AMapService
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private removeLogoControl(): void {
|
||||||
|
// @ts-ignore
|
||||||
|
const logo = document.getElementsByClassName('amap-logo');
|
||||||
|
if (logo) {
|
||||||
|
logo[0].setAttribute('style', 'display: none !important');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { IMapConfig, Scene } from '@antv/l7';
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-submodule-imports
|
||||||
|
import GaodeMap from '@antv/l7-maps/lib/amap';
|
||||||
|
import React, { createElement, createRef, useEffect, useState } from 'react';
|
||||||
|
import SceneContext from './SceneContext';
|
||||||
|
interface IMapSceneConig {
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
className?: string;
|
||||||
|
map: IMapConfig;
|
||||||
|
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||||
|
}
|
||||||
|
const AMapScene = React.memo((props: IMapSceneConig) => {
|
||||||
|
const { style, className, map } = props;
|
||||||
|
const container = createRef();
|
||||||
|
const [scene, setScene] = useState();
|
||||||
|
useEffect(() => {
|
||||||
|
const sceneInstance = new Scene({
|
||||||
|
id: container.current as HTMLDivElement,
|
||||||
|
map: new GaodeMap(map),
|
||||||
|
});
|
||||||
|
sceneInstance.on('loaded', () => {
|
||||||
|
setScene(sceneInstance);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
sceneInstance.destroy();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!scene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scene.setMapStyle(map.style);
|
||||||
|
}, [map.style]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SceneContext.Provider value={scene}>
|
||||||
|
{createElement(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
ref: container,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
},
|
||||||
|
scene && props.children,
|
||||||
|
)}
|
||||||
|
</SceneContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AMapScene;
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { IControl, Logo, PositionType, Scale, Scene, Zoom } from '@antv/l7';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useSceneValue } from './SceneContext';
|
||||||
|
interface IControlProps {
|
||||||
|
type: 'scale' | 'zoom' | 'logo';
|
||||||
|
position: PositionType;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
export default React.memo(function MapControl(props: IControlProps) {
|
||||||
|
const scene = (useSceneValue() as unknown) as Scene;
|
||||||
|
const [, setControl] = useState();
|
||||||
|
const { type, position } = props;
|
||||||
|
useEffect(() => {
|
||||||
|
let ctr: IControl;
|
||||||
|
switch (type) {
|
||||||
|
case 'scale':
|
||||||
|
ctr = new Scale({
|
||||||
|
position,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'zoom':
|
||||||
|
ctr = new Zoom({
|
||||||
|
position,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'logo':
|
||||||
|
ctr = new Logo({
|
||||||
|
position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setControl(ctr);
|
||||||
|
scene.addControl(ctr);
|
||||||
|
return () => {
|
||||||
|
scene.removeControl(ctr);
|
||||||
|
};
|
||||||
|
}, [type, position]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
|
@ -12,8 +12,11 @@ export default React.memo(function Chart(props: ISourceProps) {
|
||||||
const { data, ...sourceOption } = source;
|
const { data, ...sourceOption } = source;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @ts-ignore
|
if (!layer.inited) {
|
||||||
layer.source(data, sourceOption);
|
layer.source(data, sourceOption);
|
||||||
}, []);
|
} else {
|
||||||
|
layer.setData(data, sourceOption);
|
||||||
|
}
|
||||||
|
}, [data, sourceOption]);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { IMapConfig, Scene } from '@antv/l7';
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-submodule-imports
|
||||||
|
import Mapbox from '@antv/l7-maps/lib/mapbox';
|
||||||
|
import React, { createElement, createRef, useEffect, useState } from 'react';
|
||||||
|
import SceneContext from './SceneContext';
|
||||||
|
interface IMapSceneConig {
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
className?: string;
|
||||||
|
map: IMapConfig;
|
||||||
|
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||||
|
}
|
||||||
|
const MapboxScene = React.memo((props: IMapSceneConig) => {
|
||||||
|
const { style, className, map } = props;
|
||||||
|
const container = createRef();
|
||||||
|
const [scene, setScene] = useState();
|
||||||
|
useEffect(() => {
|
||||||
|
const sceneInstance = new Scene({
|
||||||
|
id: container.current as HTMLDivElement,
|
||||||
|
map: new Mapbox(map),
|
||||||
|
});
|
||||||
|
sceneInstance.on('loaded', () => {
|
||||||
|
setScene(sceneInstance);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
sceneInstance.destroy();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!scene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scene.setMapStyle(map.style);
|
||||||
|
}, [map.style]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SceneContext.Provider value={scene}>
|
||||||
|
{createElement(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
ref: container,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
},
|
||||||
|
scene && props.children,
|
||||||
|
)}
|
||||||
|
</SceneContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default MapboxScene;
|
|
@ -23,6 +23,12 @@ const MapScene = React.memo((props: IMapSceneConig) => {
|
||||||
sceneInstance.destroy();
|
sceneInstance.destroy();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!scene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scene.setMapStyle(style);
|
||||||
|
}, [style]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SceneContext.Provider value={scene}>
|
<SceneContext.Provider value={scene}>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
export * from './component/SceneContext';
|
export * from './component/SceneContext';
|
||||||
export { default as Scene } from './component/Scene';
|
export { default as Scene } from './component/Scene';
|
||||||
|
export { default as AMapScene } from './component/AMapScene';
|
||||||
|
export { default as MapboxScene } from './component/MapboxScene';
|
||||||
export * from './component/Layer';
|
export * from './component/Layer';
|
||||||
|
export { default as Control } from './component/Control';
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class ScaleComponent extends React.Component {
|
||||||
})
|
})
|
||||||
.size('point_count', [5, 10, 15, 20, 25])
|
.size('point_count', [5, 10, 15, 20, 25])
|
||||||
.animate(false)
|
.animate(false)
|
||||||
.select(true)
|
.active(true)
|
||||||
.color('yellow')
|
.color('yellow')
|
||||||
.style({
|
.style({
|
||||||
opacity: 0.5,
|
opacity: 0.5,
|
||||||
|
|
|
@ -35,22 +35,24 @@ export default class PointImage extends React.Component {
|
||||||
'02',
|
'02',
|
||||||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*o16fSIvcKdUAAAAAAAAAAABkARQnAQ',
|
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*o16fSIvcKdUAAAAAAAAAAABkARQnAQ',
|
||||||
);
|
);
|
||||||
|
let i = 0;
|
||||||
const imageLayer = new PointLayer({})
|
const data = await response.json();
|
||||||
.source(await response.json(), {
|
while (i < 50) {
|
||||||
|
const imageLayer = new PointLayer()
|
||||||
|
.source(data, {
|
||||||
parser: {
|
parser: {
|
||||||
type: 'json',
|
type: 'json',
|
||||||
x: 'longitude',
|
x: 'longitude',
|
||||||
y: 'latitude',
|
y: 'latitude',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.shape('name', ['00', '01', '02'])
|
.shape('circle')
|
||||||
.active(true)
|
.color('red')
|
||||||
.size(30);
|
.active(false)
|
||||||
|
.size(20);
|
||||||
scene.addLayer(imageLayer);
|
scene.addLayer(imageLayer);
|
||||||
imageLayer.on('click', (e) => {
|
i++;
|
||||||
console.log(e);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -22411,8 +22411,8 @@ table@^5.0.0, table@^5.2.3:
|
||||||
|
|
||||||
tapable@^1.0.0, tapable@^1.1.3:
|
tapable@^1.0.0, tapable@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||||
integrity sha1-ofzMBrWNth/XpF2i2kT186Pme6I=
|
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||||
|
|
||||||
tapable@^2.0.0-beta.8:
|
tapable@^2.0.0-beta.8:
|
||||||
version "2.0.0-beta.9"
|
version "2.0.0-beta.9"
|
||||||
|
|
Loading…
Reference in New Issue