feat: 增加根据范围选择

This commit is contained in:
thinkinggis 2021-01-12 19:46:04 +08:00
parent f39f4c62bb
commit a2ec206985
10 changed files with 147 additions and 28306 deletions

View File

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

View File

@ -1,3 +1,10 @@
import { ILayer } from '../layer/ILayerService';
export interface IPickingService {
init(id: string): void;
pickBox(layer: ILayer, box: [number, number, number, number]): any[];
boxPickLayer(
layer: ILayer,
box: [number, number, number, number],
cb: (...args: any[]) => void,
): Promise<any>;
}

View File

@ -72,6 +72,75 @@ export default class PickingService implements IPickingService {
this.pickingAllLayer.bind(this),
);
}
public async boxPickLayer(
layer: ILayer,
box: [number, number, number, number],
cb: (...args: any[]) => void
): Promise<any> {
const { useFramebuffer, clear, getContainer } = this.rendererService;
this.resizePickingFBO();
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();
const features = this.pickBox(layer, box);
cb(features);
});
}
public pickBox(layer: ILayer, box: [number, number, number, number]): any[] {
const [xMin, yMin, xMax, yMax] = box.map((v) => {
const tmpV = v < 0 ? 0 : v;
return Math.floor((tmpV * DOM.DPR) / this.pickBufferScale);
});
const { getViewportSize, readPixels, getContainer } = this.rendererService;
let {
width,
height,
} = (getContainer() as HTMLElement).getBoundingClientRect();
width *= DOM.DPR;
height *= DOM.DPR;
if (
xMin > ((width - 1) * DOM.DPR) / this.pickBufferScale ||
xMax < 0 ||
yMin > ((height - 1) * DOM.DPR) / this.pickBufferScale ||
yMax < 0
) {
return [];
}
let pickedColors: Uint8Array | undefined;
const w = Math.min(width / this.pickBufferScale, xMax) - xMin;
const h = Math.min(height / this.pickBufferScale, yMax) - yMin;
pickedColors = readPixels({
x: xMin,
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
y: Math.floor(height / this.pickBufferScale - (yMax + 1)),
width: w,
height: h,
data: new Uint8Array(w * h * 4),
framebuffer: this.pickingFBO,
});
const features = [];
const featuresIdMap: { [key: string]: boolean } = {};
for (let i = 0; i < pickedColors.length / 4; i = i + 1) {
const color = pickedColors.slice(i * 4, i * 4 + 4);
const pickedFeatureIdx = decodePickingColor(color);
if (pickedFeatureIdx !== -1 && !featuresIdMap[pickedFeatureIdx]) {
const rawFeature = layer.getSource().getFeatureById(pickedFeatureIdx);
features.push(rawFeature);
featuresIdMap[pickedFeatureIdx] = true;
}
}
return features;
}
private async pickingAllLayer(target: IInteractionTarget) {
if (this.alreadyInPicking || this.layerService.alreadyInRendering) {
return;
@ -81,13 +150,9 @@ export default class PickingService implements IPickingService {
this.layerService.renderLayers();
this.alreadyInPicking = false;
}
private async pickingLayers(target: IInteractionTarget) {
const {
getViewportSize,
useFramebuffer,
clear,
getContainer,
} = this.rendererService;
private resizePickingFBO() {
const { getContainer } = this.rendererService;
let {
width,
height,
@ -102,6 +167,16 @@ export default class PickingService implements IPickingService {
this.width = width;
this.height = height;
}
}
private async pickingLayers(target: IInteractionTarget) {
const {
getViewportSize,
useFramebuffer,
clear,
getContainer,
} = this.rendererService;
this.resizePickingFBO();
useFramebuffer(this.pickingFBO, () => {
const layers = this.layerService.getLayers();
@ -123,6 +198,7 @@ export default class PickingService implements IPickingService {
});
});
}
private pickFromPickingFBO = (
layer: ILayer,
{ x, y, lngLat, type, target }: IInteractionTarget,

View File

@ -192,6 +192,10 @@ export interface ILayer {
* 使
*/
pick(query: { x: number; y: number }): void;
boxSelect(
box: [number, number, number, number],
cb: (...args: any[]) => void,
): void;
updateLayerConfig(configToUpdate: Partial<ILayerConfig | unknown>): void;
setAnimateStartTime(): void;

View File

@ -25,6 +25,7 @@ import {
IModelInitializationOptions,
IMultiPassRenderer,
IPass,
IPickingService,
IPostProcessingPass,
IRendererService,
IScale,
@ -129,6 +130,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
protected fontService: IFontService;
protected pickingService: IPickingService;
protected rendererService: IRendererService;
protected layerService: ILayerService;
@ -258,6 +261,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
this.interactionService = this.container.get<IInteractionService>(
TYPES.IInteractionService,
);
this.pickingService = this.container.get<IPickingService>(
TYPES.IPickingService,
);
this.mapService = this.container.get<IMapService>(TYPES.IMapService);
this.cameraService = this.container.get<ICameraService>(
TYPES.ICameraService,
@ -815,6 +822,13 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
this.interactionService.triggerHover({ x, y });
}
public boxSelect(
box: [number, number, number, number],
cb: (...args: any[]) => void,
) {
this.pickingService.boxPickLayer(this, box, cb);
}
public buildLayerModel(
options: ILayerModelInitializationOptions &
Partial<IModelInitializationOptions>,

View File

@ -8,6 +8,7 @@ import {
IRendererService,
TYPES,
} from '@antv/l7-core';
import { DOM } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
/**

View File

@ -20,7 +20,7 @@ import {
Properties,
} from '@turf/helpers';
import { EventEmitter } from 'eventemitter3';
import { cloneDeep, isFunction, isString } from 'lodash';
import { cloneDeep, isFunction, isString, merge } from 'lodash';
// @ts-ignore
// tslint:disable-next-line:no-submodule-imports
import Supercluster from 'supercluster/dist/supercluster';
@ -37,6 +37,7 @@ export default class Source extends EventEmitter {
public hooks = {
init: new SyncHook(),
};
public parser: IParserCfg = { type: 'geojson' };
public transforms: ITransform[] = [];
public cluster: boolean = false;
@ -51,6 +52,7 @@ export default class Source extends EventEmitter {
// 原始数据
private originData: any;
private rawData: any;
private cfg: any = {};
private clusterIndex: Supercluster;
@ -58,6 +60,7 @@ export default class Source extends EventEmitter {
super();
// this.rawData = cloneDeep(data);
this.originData = data;
this.initCfg(cfg);
this.hooks.init.tap('parser', () => {
@ -75,7 +78,7 @@ export default class Source extends EventEmitter {
public setData(data: any, options?: ISourceCFG) {
this.rawData = data;
this.originData = data;
this.initCfg(options);
this.initCfg(this.cfg);
this.init();
this.emit('update');
}
@ -160,7 +163,9 @@ export default class Source extends EventEmitter {
this.data = null;
}
private initCfg(cfg?: ISourceCFG) {
private initCfg(option?: ISourceCFG) {
this.cfg = merge(this.cfg, option);
const cfg = this.cfg;
if (cfg) {
if (cfg.parser) {
this.parser = cfg.parser;

View File

@ -155,8 +155,8 @@ export function printCanvas(canvas: HTMLCanvasElement) {
export function getViewPortScale() {
const meta = document.querySelector('meta[name="viewport"]');
const contentItems = meta.content.split(',');
const scale = contentItems.find((item) => {
const contentItems = (meta as any).content?.split(',');
const scale = contentItems.find((item: string) => {
const [key, value] = item.split('=');
return key === 'initial-scale';
});

View File

@ -14,7 +14,7 @@ export default class Point3D extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
pickBufferScale: 3.0,
pickBufferScale: 1.0,
map: new GaodeMap({
style: 'light',
center: [-121.24357, 37.58264],
@ -59,23 +59,35 @@ export default class Point3D extends React.Component {
stroke: '#fff',
});
scene.addLayer(pointLayer);
this.scene = scene;
setTimeout(() => {
console.log('updatedata');
pointLayer.setData(
{
type: 'FeatureCollection',
features: [],
const textLayer = new PointLayer({})
.source(data, {
parser: {
type: 'csv',
x: 'Longitude',
y: 'Latitude',
},
{
parser: {
type: 'geojson',
},
})
.shape('EventID', 'text')
.size(8)
.color('red')
.style({
opacity: 1,
strokeWidth: 0,
stroke: '#fff',
});
scene.addLayer(pointLayer);
scene.addLayer(textLayer);
pointLayer.on('click', (e) => {
const res = pointLayer.boxSelect(
[e.x - 10, e.y - 10, e.x + 10, e.y + 10],
(fe) => {
console.log(fe);
},
);
console.log(pointLayer);
}, 3000);
});
this.scene = scene;
});
});
}

28279
yarn.lock

File diff suppressed because it is too large Load Diff