improvement: 拾取新增buffer机制 & 顶点编辑功能

This commit is contained in:
thinkinggis 2020-03-28 11:19:57 +08:00
parent 9270e5da1e
commit 5e72a7d974
30 changed files with 212 additions and 49 deletions

View File

@ -55,6 +55,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
maxZoom: 24,
visible: true,
autoFit: false,
pickingBuffer: 0,
zIndex: 0,
blend: 'normal',
pickedFeatureID: -1,

View File

@ -136,6 +136,10 @@ export default class PickingService implements IPickingService {
) {
const pickedFeatureIdx = decodePickingColor(pickedColors);
const rawFeature = layer.getSource().getFeatureById(pickedFeatureIdx);
if (pickedFeatureIdx !== layer.getCurrentPickId()) {
type = 'mouseenter';
}
const target = {
x,
y,
@ -154,6 +158,7 @@ export default class PickingService implements IPickingService {
this.triggerHoverOnLayer(layer, target);
}
} else {
// 未选中
const target = {
x,
y,

View File

@ -221,6 +221,7 @@ export interface ILayerConfig {
maxZoom: number;
visible: boolean;
zIndex: number;
pickingBuffer: number;
autoFit: boolean;
name: string; //
blend: keyof typeof BlendType;

View File

@ -5,6 +5,7 @@ uniform vec3 u_PickingColor : [0, 0, 0];
uniform vec4 u_HighlightColor : [0, 0, 0, 0];
uniform float u_PickingStage : 0.0;
uniform float u_PickingThreshold : 1.0;
uniform float u_PickingBuffer: 0.0;
#define PICKING_NONE 0.0
#define PICKING_ENCODE 1.0
@ -25,3 +26,7 @@ void setPickingColor(vec3 pickingColor) {
// Stores the picking color so that the fragment shader can render it during picking
v_PickingResult.rgb = pickingColor * COLOR_SCALE;
}
float setPickingSize(float x) {
return u_PickingStage == PICKING_ENCODE ? x + u_PickingBuffer : x;
}

View File

@ -34,6 +34,7 @@
},
"dependencies": {
"@antv/l7": "^2.1.7",
"@turf/midpoint": "^5.1.5",
"@babel/runtime": "^7.7.7",
"@turf/circle": "^6.0.1",
"@turf/distance": "^6.0.1",

View File

@ -86,9 +86,22 @@ export default class DrawCircle extends DrawFeature {
protected editFeature(endPoint: ILngLat): FeatureCollection {
this.endPoint = endPoint;
const newFeature = this.createFeature();
this.drawRender.updateData(newFeature);
const pointfeatures = createPoint([this.endPoint]);
this.pointFeatures = pointfeatures.features;
this.drawVertexLayer.updateData(pointfeatures);
return this.createFeature();
}
protected showOtherLayer() {
this.centerLayer.show();
}
protected hideOtherLayer() {
this.centerLayer.hide();
}
private initCenterLayer() {
const centerStyle = this.getStyle('active').point;
const layer = new PointLayer()

View File

@ -46,6 +46,7 @@ export default class DrawEdit extends DrawFeature {
protected onDragEnd = () => {
this.emit(DrawEvent.UPDATE, null);
this.resetCursor();
this.disable();
};
protected onClick = () => {

View File

@ -87,6 +87,10 @@ export default abstract class DrawFeature extends DrawMode {
protected abstract editFeature(e: any): FeatureCollection;
protected abstract hideOtherLayer(): void;
protected abstract showOtherLayer(): void;
protected ondrawLayerClick = () => {
if (this.currentFeature === null) {
return;
@ -135,7 +139,9 @@ export default abstract class DrawFeature extends DrawMode {
private onModeChange = (mode: DrawModes[any]) => {
switch (mode) {
case DrawModes.DIRECT_SELECT:
// this.editMode.setEditFeature(this.currentFeature as Feature);
this.editMode.setEditFeature(this.currentFeature as Feature);
this.drawVertexLayer.enableEdit();
// this.editMode.enable();
// this.editLayer.updateData(
// featureCollection([this.currentFeature as Feature]),
// );
@ -144,13 +150,18 @@ export default abstract class DrawFeature extends DrawMode {
case DrawModes.SIMPLE_SELECT:
this.selectMode.setSelectedFeature(this.currentFeature as Feature);
this.drawRender.enableDrag();
this.drawVertexLayer.enableDrag();
this.drawVertexLayer.disableEdit();
this.drawVertexLayer.show();
this.drawRender.show();
this.showOtherLayer();
break;
case DrawModes.STATIC:
this.source.setFeatureUnActive(this.currentFeature as Feature);
this.drawVertexLayer.hide();
this.drawVertexLayer.disableEdit();
this.hideOtherLayer();
this.renderLayer.update(this.source.data);
this.renderLayer.enableDrag();
break;
}
};
@ -178,6 +189,5 @@ export default abstract class DrawFeature extends DrawMode {
private onDrawEdit = (endpoint: ILngLat) => {
const feature = this.editFeature(endpoint);
this.currentFeature = feature.features[0];
// this.editLayer.updateData(feature);
};
}

View File

@ -38,6 +38,7 @@ export default class DrawLine extends DrawPolygon {
protected createFeature(points: ILngLat[]): FeatureCollection {
const feature = createLine(points, {
id: this.getUniqId(),
type: 'line',
});
this.setCurrentFeature(feature as Feature);
return {

View File

@ -80,6 +80,14 @@ export default class DrawPoint extends DrawFeature {
return this.createFeature(endPoint);
}
protected showOtherLayer() {
return null;
}
protected hideOtherLayer() {
return null;
}
private addDrawLayer(drawLayers: ILayer[], fc: FeatureCollection) {
if (drawLayers.length !== 0) {
drawLayers.map((layer) => this.scene.removeLayer(layer));

View File

@ -17,6 +17,7 @@ import {
point,
} from '@turf/helpers';
import drawRender from '../render/draw';
import DrawMidVertex from '../render/draw_mid_vertex';
import selectRender from '../render/selected';
import { DrawEvent, DrawModes, unitsType } from '../util/constant';
import { createPoint, createPolygon } from '../util/create_geometry';
@ -32,8 +33,13 @@ export default class DrawPolygon extends DrawFeature {
protected endPoint: ILngLat;
protected points: ILngLat[] = [];
protected pointFeatures: Feature[];
protected drawMidVertexLayer: DrawMidVertex;
constructor(scene: Scene, options: Partial<IDrawRectOption> = {}) {
super(scene, options);
this.drawMidVertexLayer = new DrawMidVertex(this);
this.on(DrawEvent.MODE_CHANGE, this.addMidLayerEvent);
// this.editMode.on(DrawEvent.MODE_CHANGE, this.addMidLayerEvent);
}
public enable() {
super.enable();
@ -113,6 +119,7 @@ export default class DrawPolygon extends DrawFeature {
protected createFeature(points: ILngLat[]): FeatureCollection {
const feature = createPolygon(points, {
id: this.getUniqId(),
type: 'polygon',
active: true,
});
this.setCurrentFeature(feature as Feature);
@ -139,6 +146,25 @@ export default class DrawPolygon extends DrawFeature {
this.drawFinish();
});
};
protected showOtherLayer() {
return null;
}
protected hideOtherLayer() {
return null;
}
protected addMidLayerEvent(mode: DrawModes[any]) {
switch (mode) {
case DrawModes.DIRECT_SELECT:
this.drawMidVertexLayer.update(featureCollection(this.pointFeatures));
break;
case DrawModes.STATIC:
this.drawMidVertexLayer.hide();
break;
}
}
}
/**
* draw

View File

@ -43,9 +43,4 @@ export default class DrawRect extends DrawCircle {
this.setCurrentFeature(feature as Feature);
return featureCollection([feature]);
}
protected editFeature(endPoint: ILngLat): FeatureCollection {
this.endPoint = endPoint;
return this.createFeature();
}
}

View File

@ -18,19 +18,29 @@ export default class DrawLayer extends BaseRender {
public enableDrag() {
this.show();
const layer = this.drawLayers[0];
layer.on('mousemove', this.onMouseMove);
layer.on('mouseenter', this.onMouseMove);
layer.on('mouseout', this.onUnMouseMove);
layer.on('click', this.onClick);
layer.on('unclick', this.onUnClick);
}
public disableDrag() {
const layer = this.drawLayers[0];
layer.off('mousemove', this.onMouseMove);
layer.off('mouseenter', this.onMouseMove);
layer.off('mouseout', this.onUnMouseMove);
layer.off('click', this.onClick);
layer.off('unclick', this.onUnClick);
}
public enableEdit() {
const layer = this.drawLayers[0];
layer.on('unclick', this.onUnClick);
}
public disableEdit() {
const layer = this.drawLayers[0];
layer.off('unclick', this.onUnClick);
}
private onMouseMove = (e: any) => {
this.draw.setCursor('move');
this.draw.selectMode.enable();
@ -43,7 +53,8 @@ export default class DrawLayer extends BaseRender {
this.draw.selectMode.disable();
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.DIRECT_SELECT);
this.disableDrag();
this.hide();
this.draw.resetCursor();
this.enableEdit();
};
private onUnClick = (e: any) => {
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.STATIC);

View File

@ -0,0 +1,64 @@
import {
feature,
Feature,
featureCollection,
FeatureCollection,
Point,
Properties,
} from '@turf/helpers';
import midPoint from '@turf/midpoint';
import { renderFeature } from '../util/renderFeature';
import BaseRender from './base_render';
export default class DrawVertexLayer extends BaseRender {
public update(pointFeatures: FeatureCollection) {
this.removeLayers();
const midFeatures = this.calcMidPointData(pointFeatures);
const style = this.draw.getStyle('mid_point');
this.drawLayers = renderFeature(midFeatures, style);
this.addLayers();
this.enableEdit();
}
public updateData(data: any) {
const midFeatures = this.calcMidPointData(data);
this.drawLayers.forEach((layer) => layer.setData(midFeatures));
}
public enableEdit() {
const layer = this.drawLayers[0];
layer.on('mouseenter', this.onMouseEnter);
layer.on('mouseout', this.onMouseOut);
layer.on('click', this.onClick);
}
public disableEdit() {
const layer = this.drawLayers[0];
layer.off('mouseenter', this.onMouseEnter);
layer.off('mouseout', this.onMouseOut);
layer.off('click', this.onClick);
}
private onMouseEnter = (e: any) => {
this.draw.setCursor('pointer');
// this.draw.editMode.enable();
};
private onMouseOut = (e: any) => {
this.draw.resetCursor();
// this.draw.editMode.disable();
};
private onClick = (e: any) => {
// 添加一个顶点 1.更新顶点 2.更新重点
};
private calcMidPointData(fe: FeatureCollection) {
const midFeatures: Feature[] = [];
fe.features.forEach((item, index) => {
const preFeature = (item as unknown) as Feature<Point, Properties>;
const nextFeature =
index !== fe.features.length - 1
? ((fe.features[index + 1] as unknown) as Feature<Point, Properties>)
: ((fe.features[0] as unknown) as Feature<Point, Properties>);
// @ts-ignore
midFeatures.push(midPoint(preFeature, nextFeature));
});
return featureCollection(midFeatures);
}
}

View File

@ -7,6 +7,7 @@ export default class DrawResultLayer extends BaseRender {
this.removeLayers();
const style = this.draw.getStyle('normal');
this.drawLayers = renderFeature(feature, style);
this.addFilter();
this.addLayers();
}
public enableDrag() {
@ -26,6 +27,8 @@ export default class DrawResultLayer extends BaseRender {
}
private onClick = (e: any) => {
this.draw.setCurrentFeature(e.feature);
this.draw.source.setFeatureActive(e.feature);
this.update(this.draw.source.data);
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.SIMPLE_SELECT);
};
}

View File

@ -10,30 +10,42 @@ export default class DrawVertexLayer extends BaseRender {
this.addLayers();
}
public enableDrag() {
const layer = this.drawLayers[0];
layer.on('mousemove', this.onMouseMove);
layer.on('mouseout', this.onUnMouseMove);
layer.on('click', this.onClick);
// const layer = this.drawLayers[0];
// layer.on('mousemove', this.onMouseEnter);
// layer.on('mouseout', this.onMouseOut);
// layer.on('click', this.onClick);
}
public disableDrag() {
const layer = this.drawLayers[0];
layer.off('mousemove', this.onMouseMove);
layer.off('mouseout', this.onUnMouseMove);
layer.off('click', this.onClick);
// const layer = this.drawLayers[0];
// layer.off('mousemove', this.onMouseEnter);
// layer.off('mouseout', this.onMouseOut);
// layer.off('click', this.onClick);
}
private onMouseMove = (e: any) => {
this.draw.setCursor('pointer');
// this.draw.editMode.enable();
public enableEdit() {
const layer = this.drawLayers[0];
layer.on('mouseenter', this.onMouseEnter);
layer.on('mouseout', this.onMouseOut);
}
public disableEdit() {
const layer = this.drawLayers[0];
layer.off('mouseenter', this.onMouseEnter);
layer.off('mouseout', this.onMouseOut);
}
private onMouseEnter = (e: any) => {
this.draw.setCursor('move');
this.draw.editMode.enable();
};
private onUnMouseMove = (e: any) => {
private onMouseOut = (e: any) => {
this.draw.resetCursor();
// this.draw.editMode.disable();
this.draw.editMode.disable();
};
private onClick = (e: any) => {
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.DIRECT_SELECT);
this.draw.selectMode.disable();
this.disableDrag();
this.draw.editMode.enable();
// this.disableDrag();
// this.draw.editMode.enable();
};
}

View File

@ -25,6 +25,7 @@ export function createCircle(
properties: {
...options,
active: true,
type: 'circle',
radius,
startPoint: center,
endPoint,
@ -48,6 +49,7 @@ export function createRect(
const feature = {
type: 'Feature',
properties: {
type: 'rect',
active: true,
startPoint,
endPoint,

View File

@ -79,11 +79,13 @@ const LayerStyles = {
},
},
mid_point: {
type: 'PointLayer',
shape: 'circle',
color: '#fbb03b',
size: 3,
style: {},
point: {
type: 'PointLayer',
shape: 'circle',
color: '#fbb03b',
size: 3,
style: {},
},
},
};

View File

@ -23,11 +23,7 @@ function drawPoint(fe: FeatureCollection, style: any) {
.shape('circle')
.color(style.color)
.size(style.size)
.style({
opacity: style.style.opacity,
stroke: style.style.stroke,
strokeWidth: style.style.strokeWidth,
});
.style(style.style);
return [layer];
}

View File

@ -49,7 +49,7 @@ vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size) / 2.0;
return offset * vec2(1.0, -1.0);
}
vec2 getNormal(vec2 line_clipspace, float offset_direction) {

View File

@ -51,7 +51,7 @@ vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size) / 2.0;
return offset;
}

View File

@ -49,7 +49,7 @@ vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size)/ 2.0;
return offset;
}
vec2 getNormal(vec2 line_clipspace, float offset_direction) {

View File

@ -48,7 +48,7 @@ vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size) / 2.0;
return offset * vec2(1.0, -1.0);
}
vec2 getNormal(vec2 line_clipspace, float offset_direction) {

View File

@ -29,7 +29,7 @@ void main() {
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
v_color = a_Color;
vec3 size = a_Miter * a_Size * reverse_offset_normal(a_Normal); //v_normal * vec3(1., -1., 1.0);
vec3 size = a_Miter * setPickingSize(a_Size) * reverse_offset_normal(a_Normal); //v_normal * vec3(1., -1., 1.0);
vec2 offset = project_pixel(size.xy);
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0, 1.0));

View File

@ -38,7 +38,7 @@ void main() {
}
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
v_color = a_Color;
vec3 size = a_Miter * a_Size.x * reverse_offset_normal(a_Normal);
vec3 size = a_Miter * setPickingSize(a_Size.x) * reverse_offset_normal(a_Normal);
vec2 offset = project_pixel(size.xy);
v_side = a_Miter * a_Size.x;
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));

View File

@ -55,6 +55,7 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
u_ViewportSize: [width, height],
u_DevicePixelRatio: window.devicePixelRatio,
u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
u_PickingBuffer: layer.getLayerConfig().pickingBuffer || 0,
}),
);

View File

@ -21,17 +21,19 @@ void main() {
float shape_type = a_Shape;
// radius(16-bit)
v_radius = a_Size;
float newSize = setPickingSize(a_Size)
vec2 offset = project_pixel(extrude * (a_Size + u_stroke_width));
// radius(16-bit)
v_radius = newSize;
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width));
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
// TODO: billboard
// anti-alias
float antialiasblur = 1.0 / (a_Size + u_stroke_width);
float antialiasblur = 1.0 / (newSize + u_stroke_width);
// construct point coords
v_data = vec4(extrude, antialiasblur,shape_type);

View File

@ -23,7 +23,9 @@ export default class DashLineDemo extends React.Component {
zoom: 14,
}),
});
const lineLayer = new LineLayer()
const lineLayer = new LineLayer({
pickingBuffer: 5,
})
.source(await response.json())
.size(1)
.shape('line')

View File

@ -22,7 +22,7 @@ export default class HeatMapLayerDemo extends React.Component {
pitch: 58.5,
center: [111.8759, 30.6942],
rotation: 0.519,
zoom: 3.6116,
zoom: 14,
}),
});
scene.on('loaded', () => {

View File

@ -34,12 +34,13 @@ export default class World extends React.Component {
style: 'blank',
center: [110.19382669582967, 30.258134],
pitch: 0,
zoom: 0,
zoom: 5,
}),
});
this.scene = scene;
const layer = new PolygonLayer({
name: '01',
autoFit: true,
});
layer