mirror of https://gitee.com/antv-l7/antv-l7
commit
6ef8e87ef0
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
title: Buble Map
|
title: Bubble Map
|
||||||
order: 1
|
order: 1
|
||||||
---
|
---
|
||||||
气泡图地理区域上方会显示不同大小的圆点,圆形面积与其在数据集中的数值会成正比。
|
气泡图地理区域上方会显示不同大小的圆点,圆形面积与其在数据集中的数值会成正比。
|
||||||
|
|
|
@ -94,8 +94,11 @@
|
||||||
"rollup": "^1.27.14",
|
"rollup": "^1.27.14",
|
||||||
"rollup-plugin-analyzer": "^3.2.2",
|
"rollup-plugin-analyzer": "^3.2.2",
|
||||||
"rollup-plugin-babel": "^4.3.3",
|
"rollup-plugin-babel": "^4.3.3",
|
||||||
|
"rollup-plugin-buble": "^0.19.8",
|
||||||
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
"rollup-plugin-postcss": "^2.0.3",
|
"rollup-plugin-postcss": "^2.0.3",
|
||||||
"rollup-plugin-terser": "^5.1.2",
|
"rollup-plugin-terser": "^5.1.2",
|
||||||
|
"rollup-plugin-typescript": "^1.0.1",
|
||||||
"rollup-pluginutils": "^2.8.2",
|
"rollup-pluginutils": "^2.8.2",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^1.0.0",
|
"style-loader": "^1.0.0",
|
||||||
|
@ -180,5 +183,8 @@
|
||||||
"tnpm": {
|
"tnpm": {
|
||||||
"mode": "yarn"
|
"mode": "yarn"
|
||||||
},
|
},
|
||||||
"version": "0.0.0"
|
"version": "0.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/turf": "^5.1.6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export interface IPopupOption {
|
||||||
closeButton: boolean;
|
closeButton: boolean;
|
||||||
closeOnClick: boolean;
|
closeOnClick: boolean;
|
||||||
maxWidth: string;
|
maxWidth: string;
|
||||||
anchor: anchorType;
|
anchor: anchorType[any];
|
||||||
className: string;
|
className: string;
|
||||||
offsets: number[];
|
offsets: number[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
const draw = require('draw');
|
const draw = require('l7-draw');
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import { Feature, Geometry, Properties } from '@turf/helpers';
|
||||||
|
import moveFeature from '../../src/util/move_featrues';
|
||||||
|
describe('moveFeature', () => {
|
||||||
|
const delta = {
|
||||||
|
lng: 1,
|
||||||
|
lat: 1,
|
||||||
|
};
|
||||||
|
const pointFeature: Feature<Geometry, Properties> = {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [130, 47],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const polyon: Feature<Geometry, Properties> = {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [
|
||||||
|
[
|
||||||
|
[49.5703125, 45.583289756006316],
|
||||||
|
[71.3671875, 45.583289756006316],
|
||||||
|
[71.3671875, 57.136239319177434],
|
||||||
|
[49.5703125, 57.136239319177434],
|
||||||
|
[49.5703125, 45.583289756006316],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const line: Feature<Geometry, Properties> = {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: [
|
||||||
|
[54.31640625, 62.91523303947614],
|
||||||
|
[71.015625, 62.59334083012024],
|
||||||
|
[70.48828125, 58.07787626787517],
|
||||||
|
[77.16796875, 54.36775852406841],
|
||||||
|
[83.3203125, 58.26328705248601],
|
||||||
|
[83.3203125, 66.37275500247455],
|
||||||
|
[94.74609375, 66.65297740055279],
|
||||||
|
[94.74609375, 62.512317938386914],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
it('move Point', () => {
|
||||||
|
const res = moveFeature([pointFeature], delta) as Array<
|
||||||
|
Feature<Geometry, Properties>
|
||||||
|
>;
|
||||||
|
expect(res[0].geometry.coordinates).toEqual([131, 48]);
|
||||||
|
});
|
||||||
|
it('move BBox', () => {
|
||||||
|
const res = moveFeature([polyon], delta) as Array<
|
||||||
|
Feature<Geometry, Properties>
|
||||||
|
>;
|
||||||
|
expect(res[0].geometry.coordinates).toEqual([
|
||||||
|
[
|
||||||
|
[50.5703125, 46.583289756006316],
|
||||||
|
[72.3671875, 46.583289756006316],
|
||||||
|
[72.3671875, 58.136239319177434],
|
||||||
|
[50.5703125, 58.136239319177434],
|
||||||
|
[50.5703125, 46.583289756006316],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('move line', () => {
|
||||||
|
const res = moveFeature([line], delta) as Array<
|
||||||
|
Feature<Geometry, Properties>
|
||||||
|
>;
|
||||||
|
expect(res[0].geometry.coordinates).toEqual([
|
||||||
|
[55.31640625, 63.91523303947614],
|
||||||
|
[72.015625, 63.59334083012024],
|
||||||
|
[71.48828125, 59.07787626787517],
|
||||||
|
[78.16796875, 55.36775852406841],
|
||||||
|
[84.3203125, 59.26328705248601],
|
||||||
|
[84.3203125, 67.37275500247455],
|
||||||
|
[95.74609375, 67.65297740055279],
|
||||||
|
[95.74609375, 63.512317938386914],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "@antv/l7-draw",
|
"name": "@antv/l7-draw",
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"description": "Now I’m the model of a modern major general / The venerated Virginian veteran whose men are all / Lining up, to put me up on a pedestal / Writin’ letters to relatives / Embellishin’ my elegance and eloquence / But the elephant is in the room / The truth is in ya face when ya hear the British cannons go / BOOM",
|
"description": "L7 Draw moudules",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "thinkinggis <lzx199065@gmail.com>",
|
"author": "thinkinggis <lzx199065@gmail.com>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
|
"unpkg": "dist/l7-draw.js",
|
||||||
"types": "es/index.d.ts",
|
"types": "es/index.d.ts",
|
||||||
"sideEffects": true,
|
"sideEffects": true,
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -33,7 +34,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@antv/l7": "^2.1.5",
|
"@antv/l7": "^2.1.5",
|
||||||
"@babel/runtime": "^7.7.7"
|
"@babel/runtime": "^7.7.7",
|
||||||
|
"@turf/circle": "^6.0.1",
|
||||||
|
"@turf/distance": "^6.0.1",
|
||||||
|
"@turf/helpers": "^6.1.4",
|
||||||
|
"lodash": "^4.6.2"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/antvis/L7/issues"
|
"url": "https://github.com/antvis/L7/issues"
|
||||||
|
|
|
@ -19,13 +19,9 @@ export default {
|
||||||
],
|
],
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
format: 'cjs',
|
format: 'umd',
|
||||||
file: pkg.main,
|
name: 'L7-Draw',
|
||||||
sourcemap: true
|
file: pkg.unpkg,
|
||||||
},
|
|
||||||
{
|
|
||||||
format: 'es',
|
|
||||||
file: pkg.module,
|
|
||||||
sourcemap: true
|
sourcemap: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export { default as DrawSource } from './source';
|
export * from './modes/index';
|
||||||
|
|
|
@ -1,22 +1,109 @@
|
||||||
import { ILayer } from '@antv/l7';
|
import {
|
||||||
import DrawFeature from './draw_feature';
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
import { Feature, FeatureCollection, point } from '@turf/helpers';
|
||||||
|
import selectRender from '../render/selected';
|
||||||
|
import { DrawEvent, DrawModes, unitsType } from '../util/constant';
|
||||||
|
import { createCircle } from '../util/create_geometry';
|
||||||
|
import moveFeatures, { movePoint, moveRing } from '../util/move_featrues';
|
||||||
|
import DrawFeature, { IDrawFeatureOption } from './draw_feature';
|
||||||
|
export interface IDrawRectOption extends IDrawFeatureOption {
|
||||||
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
|
}
|
||||||
|
let CircleFeatureId = 0;
|
||||||
export default class DrawCircle extends DrawFeature {
|
export default class DrawCircle extends DrawFeature {
|
||||||
private center: [number, number];
|
private startPoint: ILngLat;
|
||||||
private drawCircleLayer: ILayer;
|
private endPoint: ILngLat;
|
||||||
protected onDragStart() {
|
constructor(scene: Scene, options: Partial<IDrawRectOption> = {}) {
|
||||||
// @ts-ignore
|
super(scene, options);
|
||||||
this.scene.map.dragdrag.disable();
|
this.selectLayer = new selectRender(this);
|
||||||
}
|
}
|
||||||
protected onDragging() {
|
protected onDragStart = (e: IInteractionTarget) => {
|
||||||
return;
|
this.startPoint = e.lngLat;
|
||||||
|
this.setCursor('grabbing');
|
||||||
|
this.initCenterLayer();
|
||||||
|
this.initDrawFillLayer();
|
||||||
|
this.centerLayer.setData([this.startPoint]);
|
||||||
|
};
|
||||||
|
protected onDragging = (e: IInteractionTarget) => {
|
||||||
|
this.endPoint = e.lngLat;
|
||||||
|
const feature = this.createFeature();
|
||||||
|
this.updateDrawFillLayer(feature);
|
||||||
|
};
|
||||||
|
|
||||||
|
protected onDragEnd = () => {
|
||||||
|
this.emit(DrawEvent.CREATE, this.currentFeature);
|
||||||
|
this.emit(DrawEvent.MODE_CHANGE, DrawModes.SIMPLE_SELECT);
|
||||||
|
this.disable();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected moveFeature(delta: ILngLat): Feature {
|
||||||
|
const newFeature = moveFeatures([this.currentFeature as Feature], delta)[0];
|
||||||
|
const properties = newFeature.properties as {
|
||||||
|
startPoint: [number, number];
|
||||||
|
endPoint: [number, number];
|
||||||
|
};
|
||||||
|
const { startPoint, endPoint } = properties;
|
||||||
|
properties.startPoint = movePoint(startPoint, delta);
|
||||||
|
properties.endPoint = movePoint(endPoint, delta);
|
||||||
|
newFeature.properties = properties;
|
||||||
|
this.startPoint = {
|
||||||
|
lat: startPoint[1],
|
||||||
|
lng: startPoint[0],
|
||||||
|
};
|
||||||
|
this.endPoint = {
|
||||||
|
lat: endPoint[1],
|
||||||
|
lng: endPoint[0],
|
||||||
|
};
|
||||||
|
return newFeature;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onDragEnd() {
|
protected createFeature(): FeatureCollection {
|
||||||
return;
|
const feature = createCircle(
|
||||||
|
[this.startPoint.lng, this.startPoint.lat],
|
||||||
|
[this.endPoint.lng, this.endPoint.lat],
|
||||||
|
{
|
||||||
|
units: this.getOption('units'),
|
||||||
|
steps: this.getOption('steps'),
|
||||||
|
id: `${CircleFeatureId++}`,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.setCurrentFeature(feature as Feature);
|
||||||
|
return {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [feature],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onClick() {
|
protected editFeature(endPoint: ILngLat): FeatureCollection {
|
||||||
return;
|
this.endPoint = endPoint;
|
||||||
|
return this.createFeature();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initCenterLayer() {
|
||||||
|
const centerStyle = this.getStyle('active_point');
|
||||||
|
const layer = new PointLayer()
|
||||||
|
.source([this.startPoint], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
this.scene.addLayer(layer);
|
||||||
|
this.centerLayer = layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { IInteractionTarget, ILayer, ILngLat, Popup, Scene } from '@antv/l7';
|
||||||
|
import turfCircle from '@turf/circle';
|
||||||
|
import turfDistance from '@turf/distance';
|
||||||
|
import { Feature, featureCollection, point } from '@turf/helpers';
|
||||||
|
import EditRender from '../render/edit';
|
||||||
|
import { DrawEvent } from '../util/constant';
|
||||||
|
import DrawFeature, { IDrawOption } from './draw_mode';
|
||||||
|
export type unitsType = 'degrees' | 'radians' | 'miles' | 'kilometers';
|
||||||
|
export interface IDrawCircleOption extends IDrawOption {
|
||||||
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
|
}
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
export default class DrawEdit extends DrawFeature {
|
||||||
|
private center: ILngLat;
|
||||||
|
private endPoint: ILngLat;
|
||||||
|
// 绘制完成之后显示
|
||||||
|
private editLayer: EditRender;
|
||||||
|
constructor(scene: Scene, options: Partial<IDrawCircleOption> = {}) {
|
||||||
|
super(scene, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setEditFeature(feature: Feature) {
|
||||||
|
this.currentFeature = feature;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDragStart = (e: IInteractionTarget) => {
|
||||||
|
// @ts-ignore
|
||||||
|
};
|
||||||
|
protected getDefaultOptions() {
|
||||||
|
return {
|
||||||
|
steps: 64,
|
||||||
|
units: 'kilometres',
|
||||||
|
cursor: 'move',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDragging = (e: IInteractionTarget) => {
|
||||||
|
this.endPoint = e.lngLat;
|
||||||
|
this.emit(DrawEvent.Edit, this.endPoint);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected onDragEnd = () => {
|
||||||
|
this.emit(DrawEvent.UPDATE, null);
|
||||||
|
this.disable();
|
||||||
|
};
|
||||||
|
protected onClick = () => {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,40 +1,204 @@
|
||||||
import { Scene } from '@antv/l7';
|
import {
|
||||||
import { Feature, FeatureCollection } from '@turf/helpers';
|
IInteractionTarget,
|
||||||
import DrawSource from '../source';
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
import turfCircle from '@turf/circle';
|
||||||
|
import turfDistance from '@turf/distance';
|
||||||
|
import {
|
||||||
|
Feature,
|
||||||
|
FeatureCollection,
|
||||||
|
featureCollection,
|
||||||
|
point,
|
||||||
|
} from '@turf/helpers';
|
||||||
|
import EditLayer from '../render/edit';
|
||||||
|
import RenderLayer from '../render/render';
|
||||||
|
import SelectLayer from '../render/selected';
|
||||||
|
import { DrawEvent, DrawModes, unitsType } from '../util/constant';
|
||||||
|
import DrawEdit from './draw_edit';
|
||||||
|
import DrawMode, { IDrawOption } from './draw_mode';
|
||||||
|
import DrawSelected from './draw_selected';
|
||||||
|
let CircleFeatureId = 0;
|
||||||
|
|
||||||
export interface IDrawOption {
|
export interface IDrawFeatureOption extends IDrawOption {
|
||||||
data: FeatureCollection;
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
}
|
}
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
export default abstract class DrawFeature extends DrawMode {
|
||||||
|
// 绘制完成之后显示
|
||||||
|
public selectMode: DrawSelected;
|
||||||
|
public editMode: DrawEdit;
|
||||||
|
protected renderLayer: RenderLayer;
|
||||||
|
protected selectLayer: SelectLayer;
|
||||||
|
protected editLayer: EditLayer;
|
||||||
|
protected centerLayer: ILayer;
|
||||||
|
|
||||||
export type DrawStatus = 'Drawing' | 'Selected' | 'Edit' | 'Finish';
|
// 编辑过程中显示
|
||||||
|
protected drawLayer: ILayer;
|
||||||
export default abstract class DrawFeature {
|
protected drawLineLayer: ILayer;
|
||||||
private source: DrawSource;
|
constructor(scene: Scene, options: Partial<IDrawFeatureOption> = {}) {
|
||||||
private scene: Scene;
|
super(scene, options);
|
||||||
constructor(scene: Scene, options: IDrawOption) {
|
this.renderLayer = new RenderLayer(this);
|
||||||
const { data } = options;
|
this.selectLayer = new SelectLayer(this);
|
||||||
this.scene = scene;
|
this.editLayer = new EditLayer(this);
|
||||||
this.source = new DrawSource(data);
|
this.selectMode = new DrawSelected(this.scene, {});
|
||||||
|
this.editMode = new DrawEdit(this.scene, {});
|
||||||
|
this.selectMode.on(DrawEvent.UPDATE, this.onDrawUpdate);
|
||||||
|
this.selectMode.on(DrawEvent.Move, this.onDrawMove);
|
||||||
|
this.editMode.on(DrawEvent.MODE_CHANGE, this.onModeChange);
|
||||||
|
this.editMode.on(DrawEvent.UPDATE, this.onDrawUpdate);
|
||||||
|
this.editMode.on(DrawEvent.Edit, this.onDrawEdit);
|
||||||
|
this.selectMode.on(DrawEvent.MODE_CHANGE, this.onModeChange);
|
||||||
|
this.on(DrawEvent.CREATE, this.onDrawCreate);
|
||||||
|
this.on(DrawEvent.MODE_CHANGE, this.onModeChange);
|
||||||
}
|
}
|
||||||
public enable() {
|
protected getDefaultOptions() {
|
||||||
this.scene.on('dragstart', this.onDragStart);
|
return {
|
||||||
this.scene.on('drag', this.onDragging);
|
steps: 64,
|
||||||
this.scene.on('dragend', this.onDragEnd);
|
units: 'kilometres',
|
||||||
this.scene.on('click', this.onClick);
|
cursor: 'crosshair',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
protected abstract onDragStart(e: IInteractionTarget): void;
|
||||||
|
|
||||||
|
protected abstract onDragging(e: IInteractionTarget): void;
|
||||||
|
|
||||||
|
protected abstract onDragEnd(e: IInteractionTarget): void;
|
||||||
|
|
||||||
|
protected abstract createFeature(e: ILngLat): FeatureCollection;
|
||||||
|
|
||||||
|
protected abstract moveFeature(e: ILngLat): Feature;
|
||||||
|
|
||||||
|
protected abstract editFeature(e: any): FeatureCollection;
|
||||||
|
|
||||||
|
protected ondrawLayerClick = () => {
|
||||||
|
if (this.currentFeature === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentFeature = null;
|
||||||
|
this.renderLayer.updateData();
|
||||||
|
this.centerLayer.setData([]);
|
||||||
|
this.drawLayer.setData(InitFeature);
|
||||||
|
this.drawLineLayer.setData(InitFeature);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
protected initDrawFillLayer() {
|
||||||
|
const style = this.getStyle('active_fill');
|
||||||
|
const linestyle = this.getStyle('active_line');
|
||||||
|
this.drawLayer = new PolygonLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.color(style.color)
|
||||||
|
.shape('fill')
|
||||||
|
.style(style.style);
|
||||||
|
this.drawLineLayer = new PolygonLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.color(linestyle.color)
|
||||||
|
.size(linestyle.size)
|
||||||
|
.shape('line')
|
||||||
|
.style(linestyle.style);
|
||||||
|
this.scene.addLayer(this.drawLayer);
|
||||||
|
this.scene.addLayer(this.drawLineLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public disable() {
|
protected updateDrawFillLayer(currentData: any) {
|
||||||
this.scene.off('dragstart', this.onDragStart);
|
this.drawLayer.setData(currentData);
|
||||||
this.scene.off('drag', this.onDragging);
|
this.drawLineLayer.setData(currentData);
|
||||||
this.scene.off('dragend', this.onDragEnd);
|
|
||||||
this.scene.off('click', this.onClick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract onDragStart(): any;
|
private removeDrawLayer() {
|
||||||
|
this.scene.removeLayer(this.drawLayer);
|
||||||
|
this.scene.removeLayer(this.drawLineLayer);
|
||||||
|
this.scene.removeLayer(this.centerLayer);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract onDragging(): any;
|
private createCircleData(center: ILngLat, endPoint: ILngLat) {
|
||||||
|
const radius = turfDistance(
|
||||||
|
point([center.lng, center.lat]),
|
||||||
|
point([endPoint.lng, endPoint.lat]),
|
||||||
|
this.getOption('units'),
|
||||||
|
);
|
||||||
|
const feature = turfCircle([center.lng, center.lat], radius, {
|
||||||
|
units: this.getOption('units'),
|
||||||
|
steps: this.getOption('steps'),
|
||||||
|
properties: {
|
||||||
|
id: `${CircleFeatureId++}`,
|
||||||
|
active: true,
|
||||||
|
radius,
|
||||||
|
center,
|
||||||
|
endPoint,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.currentFeature = feature as Feature;
|
||||||
|
return featureCollection([feature]);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract onDragEnd(): any;
|
private addDrawPopup(lnglat: ILngLat, dis: number) {
|
||||||
|
const popup = new Popup({
|
||||||
|
anchor: 'left',
|
||||||
|
closeButton: false,
|
||||||
|
})
|
||||||
|
.setLnglat(lnglat)
|
||||||
|
.setText(`半径:${dis.toFixed(2)}千米`);
|
||||||
|
this.scene.addPopup(popup);
|
||||||
|
this.popup = popup;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract onClick(): any;
|
private onModeChange = (mode: DrawModes[any]) => {
|
||||||
|
switch (mode) {
|
||||||
|
case DrawModes.DIRECT_SELECT:
|
||||||
|
this.selectLayer.hide();
|
||||||
|
this.editMode.setEditFeature(this.currentFeature as Feature);
|
||||||
|
this.editLayer.updateData(
|
||||||
|
featureCollection([this.currentFeature as Feature]),
|
||||||
|
);
|
||||||
|
this.editLayer.show();
|
||||||
|
break;
|
||||||
|
case DrawModes.SIMPLE_SELECT:
|
||||||
|
this.renderLayer.updateData();
|
||||||
|
this.selectMode.setSelectedFeature(this.currentFeature as Feature);
|
||||||
|
this.selectLayer.updateData(
|
||||||
|
featureCollection([this.currentFeature as Feature]),
|
||||||
|
);
|
||||||
|
this.selectLayer.show();
|
||||||
|
break;
|
||||||
|
case DrawModes.STATIC:
|
||||||
|
this.source.setFeatureUnActive(this.currentFeature as Feature);
|
||||||
|
this.renderLayer.updateData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private onDrawCreate = (feature: Feature) => {
|
||||||
|
this.source.addFeature(feature);
|
||||||
|
if (this.popup) {
|
||||||
|
this.popup.remove();
|
||||||
|
}
|
||||||
|
this.removeDrawLayer();
|
||||||
|
};
|
||||||
|
|
||||||
|
private onDrawUpdate = (feature: Feature) => {
|
||||||
|
this.source.updateFeature(this.currentFeature as Feature);
|
||||||
|
};
|
||||||
|
|
||||||
|
private onDrawMove = (delta: ILngLat) => {
|
||||||
|
const feature = this.moveFeature(delta);
|
||||||
|
this.currentFeature = feature;
|
||||||
|
this.selectLayer.updateData(featureCollection([feature]));
|
||||||
|
};
|
||||||
|
|
||||||
|
private onDrawEdit = (endpoint: ILngLat) => {
|
||||||
|
const feature = this.editFeature(endpoint);
|
||||||
|
this.currentFeature = feature.features[0];
|
||||||
|
this.editLayer.updateData(feature);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { IInteractionTarget, IPopup, Scene } from '@antv/l7';
|
||||||
|
import { Feature, FeatureCollection } from '@turf/helpers';
|
||||||
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import { merge, throttle } from 'lodash';
|
||||||
|
import DrawSource from '../source';
|
||||||
|
import LayerStyles from '../util/layerstyle';
|
||||||
|
|
||||||
|
export interface IDrawOption {
|
||||||
|
data: FeatureCollection;
|
||||||
|
style: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DrawStatus =
|
||||||
|
| 'Drawing'
|
||||||
|
| 'DrawSelected'
|
||||||
|
| 'DrawEdit'
|
||||||
|
| 'DrawFinish'
|
||||||
|
| 'EditFinish';
|
||||||
|
|
||||||
|
export default abstract class DrawMode extends EventEmitter {
|
||||||
|
public source: DrawSource;
|
||||||
|
public scene: Scene;
|
||||||
|
protected options: {
|
||||||
|
[key: string]: any;
|
||||||
|
} = {
|
||||||
|
style: LayerStyles,
|
||||||
|
};
|
||||||
|
protected drawStatus: DrawStatus = 'Drawing';
|
||||||
|
protected currentFeature: Feature | null;
|
||||||
|
protected isEnable: boolean = false;
|
||||||
|
protected popup: IPopup;
|
||||||
|
constructor(scene: Scene, options: Partial<IDrawOption> = {}) {
|
||||||
|
super();
|
||||||
|
const { data } = options;
|
||||||
|
this.scene = scene;
|
||||||
|
this.source = new DrawSource(data);
|
||||||
|
this.options = merge(this.options, this.getDefaultOptions(), options);
|
||||||
|
}
|
||||||
|
public enable() {
|
||||||
|
if (this.isEnable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
this.scene.map.dragPan.disable();
|
||||||
|
this.scene.on('dragstart', this.onDragStart);
|
||||||
|
this.scene.on('dragging', this.onDragging);
|
||||||
|
this.scene.on('dragend', this.onDragEnd);
|
||||||
|
this.setCursor(this.getOption('cursor'));
|
||||||
|
this.isEnable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public disable() {
|
||||||
|
if (!this.isEnable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.scene.off('dragstart', this.onDragStart);
|
||||||
|
this.scene.off('dragging', this.onDragging);
|
||||||
|
this.scene.off('dragend', this.onDragEnd);
|
||||||
|
// this.scene.off('click', this.onClick);
|
||||||
|
this.resetCursor();
|
||||||
|
// @ts-ignore
|
||||||
|
this.scene.map.dragPan.enable();
|
||||||
|
this.isEnable = false;
|
||||||
|
}
|
||||||
|
public setCurrentFeature(feature: Feature) {
|
||||||
|
this.currentFeature = feature;
|
||||||
|
this.source.setFeatureActive(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOption(key: string) {
|
||||||
|
return this.options[key];
|
||||||
|
}
|
||||||
|
public getStyle(id: string) {
|
||||||
|
return this.getOption('style')[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public setCursor(cursor: string) {
|
||||||
|
const container = this.scene.getContainer();
|
||||||
|
if (container) {
|
||||||
|
container.style.cursor = cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public resetCursor() {
|
||||||
|
const container = this.scene.getContainer();
|
||||||
|
if (container) {
|
||||||
|
container.style.cursor = 'default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getDefaultOptions() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract onDragStart(e: IInteractionTarget): void;
|
||||||
|
|
||||||
|
protected abstract onDragging(e: IInteractionTarget): void;
|
||||||
|
|
||||||
|
protected abstract onDragEnd(e: IInteractionTarget): void;
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
import { Feature, FeatureCollection, point } from '@turf/helpers';
|
||||||
|
import selectRender from '../render/selected';
|
||||||
|
import { DrawEvent, DrawModes, unitsType } from '../util/constant';
|
||||||
|
import { creatRect } from '../util/create_geometry';
|
||||||
|
import moveFeatures, { movePoint, moveRing } from '../util/move_featrues';
|
||||||
|
import DrawFeature, { IDrawFeatureOption } from './draw_feature';
|
||||||
|
export interface IDrawRectOption extends IDrawFeatureOption {
|
||||||
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
|
}
|
||||||
|
export default class DrawRect extends DrawFeature {
|
||||||
|
private startPoint: ILngLat;
|
||||||
|
private endPoint: ILngLat;
|
||||||
|
constructor(scene: Scene, options: Partial<IDrawRectOption> = {}) {
|
||||||
|
super(scene, options);
|
||||||
|
this.selectLayer = new selectRender(this);
|
||||||
|
}
|
||||||
|
protected onDragStart = (e: IInteractionTarget) => {
|
||||||
|
this.startPoint = e.lngLat;
|
||||||
|
this.setCursor('grabbing');
|
||||||
|
this.initCenterLayer();
|
||||||
|
this.initDrawFillLayer();
|
||||||
|
this.centerLayer.setData([this.startPoint]);
|
||||||
|
};
|
||||||
|
protected onDragging = (e: IInteractionTarget) => {
|
||||||
|
this.endPoint = e.lngLat;
|
||||||
|
const feature = this.createFeature();
|
||||||
|
this.updateDrawFillLayer(feature);
|
||||||
|
};
|
||||||
|
|
||||||
|
protected onDragEnd = () => {
|
||||||
|
this.emit(DrawEvent.CREATE, this.currentFeature);
|
||||||
|
this.emit(DrawEvent.MODE_CHANGE, DrawModes.SIMPLE_SELECT);
|
||||||
|
this.disable();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected moveFeature(delta: ILngLat): Feature {
|
||||||
|
const newFeature = moveFeatures([this.currentFeature as Feature], delta)[0];
|
||||||
|
const properties = newFeature.properties as {
|
||||||
|
startPoint: [number, number];
|
||||||
|
endPoint: [number, number];
|
||||||
|
};
|
||||||
|
const { startPoint, endPoint } = properties;
|
||||||
|
properties.startPoint = movePoint(startPoint, delta);
|
||||||
|
properties.endPoint = movePoint(endPoint, delta);
|
||||||
|
newFeature.properties = properties;
|
||||||
|
this.startPoint = {
|
||||||
|
lat: startPoint[1],
|
||||||
|
lng: startPoint[0],
|
||||||
|
};
|
||||||
|
this.endPoint = {
|
||||||
|
lat: endPoint[1],
|
||||||
|
lng: endPoint[0],
|
||||||
|
};
|
||||||
|
return newFeature;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createFeature(): FeatureCollection {
|
||||||
|
const feature = creatRect(
|
||||||
|
[this.startPoint.lng, this.startPoint.lat],
|
||||||
|
[this.endPoint.lng, this.endPoint.lat],
|
||||||
|
);
|
||||||
|
this.setCurrentFeature(feature as Feature);
|
||||||
|
return {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [feature],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected editFeature(endPoint: ILngLat): FeatureCollection {
|
||||||
|
this.endPoint = endPoint;
|
||||||
|
return this.createFeature();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initCenterLayer() {
|
||||||
|
const centerStyle = this.getStyle('active_point');
|
||||||
|
const layer = new PointLayer()
|
||||||
|
.source([this.startPoint], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
this.scene.addLayer(layer);
|
||||||
|
this.centerLayer = layer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
import turfCircle from '@turf/circle';
|
||||||
|
import turfDistance from '@turf/distance';
|
||||||
|
import { Feature, featureCollection, point } from '@turf/helpers';
|
||||||
|
import EditRender from '../render/selected';
|
||||||
|
import { DrawEvent, DrawModes } from '../util/constant';
|
||||||
|
import moveFeatures from '../util/move_featrues';
|
||||||
|
import DrawFeature, { IDrawOption } from './draw_mode';
|
||||||
|
export type unitsType = 'degrees' | 'radians' | 'miles' | 'kilometers';
|
||||||
|
export interface IDrawCircleOption extends IDrawOption {
|
||||||
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
|
}
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
export default class DrawSelect extends DrawFeature {
|
||||||
|
private center: ILngLat;
|
||||||
|
private dragStartPoint: ILngLat;
|
||||||
|
// 绘制完成之后显示
|
||||||
|
private editLayer: EditRender;
|
||||||
|
constructor(scene: Scene, options: Partial<IDrawCircleOption> = {}) {
|
||||||
|
super(scene, options);
|
||||||
|
// this.editLayer = new EditRender(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSelectedFeature(feature: Feature) {
|
||||||
|
this.currentFeature = feature;
|
||||||
|
// this.editLayer.updateData({
|
||||||
|
// type: 'FeatureCollection',
|
||||||
|
// features: [feature],
|
||||||
|
// });
|
||||||
|
// this.editLayer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDragStart = (e: IInteractionTarget) => {
|
||||||
|
// @ts-ignore
|
||||||
|
this.scene.map.dragPan.disable();
|
||||||
|
this.dragStartPoint = e.lngLat;
|
||||||
|
};
|
||||||
|
protected getDefaultOptions() {
|
||||||
|
return {
|
||||||
|
steps: 64,
|
||||||
|
units: 'kilometres',
|
||||||
|
cursor: 'move',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDragging = (e: IInteractionTarget) => {
|
||||||
|
const delta = {
|
||||||
|
lng: e.lngLat.lng - this.dragStartPoint.lng,
|
||||||
|
lat: e.lngLat.lat - this.dragStartPoint.lat,
|
||||||
|
};
|
||||||
|
this.emit(DrawEvent.Move, delta);
|
||||||
|
this.dragStartPoint = e.lngLat;
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected onDragEnd = () => {
|
||||||
|
this.emit(DrawEvent.UPDATE, this.currentFeature);
|
||||||
|
};
|
||||||
|
protected onClick = () => {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
private createCircleData(center: ILngLat, endPoint: ILngLat) {
|
||||||
|
const radius = turfDistance(
|
||||||
|
point([center.lng, center.lat]),
|
||||||
|
point([endPoint.lng, endPoint.lat]),
|
||||||
|
this.getOption('units'),
|
||||||
|
);
|
||||||
|
const feature = turfCircle([center.lng, center.lat], radius, {
|
||||||
|
units: this.getOption('units'),
|
||||||
|
steps: this.getOption('steps'),
|
||||||
|
properties: {
|
||||||
|
id: `${this.currentFeature?.properties?.id}`,
|
||||||
|
active: true,
|
||||||
|
radius,
|
||||||
|
center,
|
||||||
|
endPoint,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.currentFeature = feature as Feature;
|
||||||
|
return featureCollection([feature]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveCircle(feature: Feature, delta: ILngLat) {
|
||||||
|
const preCenter = feature?.properties?.center as ILngLat;
|
||||||
|
const preEndPoint = feature?.properties?.endPoint as ILngLat;
|
||||||
|
const newCenter = {
|
||||||
|
lng: preCenter.lng + delta.lng,
|
||||||
|
lat: preCenter.lat + delta.lat,
|
||||||
|
};
|
||||||
|
const newEndPoint = {
|
||||||
|
lng: preEndPoint.lng + delta.lng,
|
||||||
|
lat: preEndPoint.lat + delta.lat,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newCircle = this.createCircleData(newCenter, newEndPoint);
|
||||||
|
// this.centerLayer.setData([newCenter]);
|
||||||
|
this.editLayer.updateData(newCircle);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import DrawCircle from './draw_circle';
|
||||||
|
import DrawRect from './draw_rect';
|
||||||
|
export { DrawCircle, DrawRect };
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
import Draw from '../modes/draw_mode';
|
||||||
|
import { DrawEvent, DrawModes } from '../util/constant';
|
||||||
|
export default class DrawLayer {
|
||||||
|
private polygonLayer: ILayer;
|
||||||
|
private lineLayer: ILayer;
|
||||||
|
private draw: Draw;
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
public init() {
|
||||||
|
const style = this.draw.getStyle('normal_fill');
|
||||||
|
const linestyle = this.draw.getStyle('normal_line');
|
||||||
|
this.polygonLayer = new PolygonLayer({
|
||||||
|
zIndex: 0,
|
||||||
|
})
|
||||||
|
.source(InitFeature)
|
||||||
|
.filter('active', (active) => {
|
||||||
|
return !active;
|
||||||
|
})
|
||||||
|
.shape('fill')
|
||||||
|
.active(true)
|
||||||
|
.color(style.color)
|
||||||
|
.style(style.style);
|
||||||
|
|
||||||
|
this.lineLayer = new LineLayer({
|
||||||
|
zIndex: 1,
|
||||||
|
})
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('line')
|
||||||
|
.filter('active', (active) => {
|
||||||
|
return !active;
|
||||||
|
})
|
||||||
|
.size(linestyle.size)
|
||||||
|
.color(linestyle.color)
|
||||||
|
.style(linestyle.style);
|
||||||
|
this.draw.scene.addLayer(this.polygonLayer);
|
||||||
|
this.draw.scene.addLayer(this.lineLayer);
|
||||||
|
this.addLayerEvent();
|
||||||
|
}
|
||||||
|
public updateData() {
|
||||||
|
this.lineLayer.setData(this.draw.source.data);
|
||||||
|
this.polygonLayer.setData(this.draw.source.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.draw.scene.removeLayer(this.lineLayer);
|
||||||
|
this.draw.scene.removeLayer(this.polygonLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show() {
|
||||||
|
this.lineLayer.show();
|
||||||
|
this.polygonLayer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide() {
|
||||||
|
this.lineLayer.hide();
|
||||||
|
this.polygonLayer.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private addLayerEvent() {
|
||||||
|
this.polygonLayer.on('click', (e) => {
|
||||||
|
this.draw.setCurrentFeature(e.feature);
|
||||||
|
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.SIMPLE_SELECT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
import { Feature } from '@turf/helpers';
|
||||||
|
import Draw from '../modes/draw_feature';
|
||||||
|
import { DrawEvent, DrawModes } from '../util/constant';
|
||||||
|
export default class EditRenderLayer {
|
||||||
|
private polygonLayer: ILayer;
|
||||||
|
private lineLayer: ILayer;
|
||||||
|
private centerLayer: ILayer;
|
||||||
|
private endPointLayer: ILayer;
|
||||||
|
private draw: Draw;
|
||||||
|
private currentFeature: Feature;
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
public init() {
|
||||||
|
const style = this.draw.getStyle('active_fill');
|
||||||
|
const linestyle = this.draw.getStyle('active_line');
|
||||||
|
const centerStyle = this.draw.getStyle('active_point');
|
||||||
|
this.polygonLayer = new PolygonLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('fill')
|
||||||
|
.color(style.color)
|
||||||
|
.style(style.style);
|
||||||
|
|
||||||
|
this.lineLayer = new LineLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('line')
|
||||||
|
.size(linestyle.size)
|
||||||
|
.color(linestyle.color)
|
||||||
|
.style(linestyle.style);
|
||||||
|
this.centerLayer = new PointLayer({
|
||||||
|
zIndex: 3,
|
||||||
|
blend: 'normal',
|
||||||
|
})
|
||||||
|
.source([], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
this.endPointLayer = new PointLayer({
|
||||||
|
zIndex: 4,
|
||||||
|
blend: 'normal',
|
||||||
|
})
|
||||||
|
.source([], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
|
||||||
|
this.draw.scene.addLayer(this.polygonLayer);
|
||||||
|
this.draw.scene.addLayer(this.lineLayer);
|
||||||
|
this.draw.scene.addLayer(this.centerLayer);
|
||||||
|
this.draw.scene.addLayer(this.endPointLayer);
|
||||||
|
}
|
||||||
|
public updateData(data: any) {
|
||||||
|
if (this.currentFeature === undefined) {
|
||||||
|
this.addLayerEvent();
|
||||||
|
}
|
||||||
|
this.currentFeature = data.features[0];
|
||||||
|
this.lineLayer.setData(data);
|
||||||
|
this.polygonLayer.setData(data);
|
||||||
|
const properties = data.features[0].properties;
|
||||||
|
if (properties.startPoint) {
|
||||||
|
this.centerLayer.setData([
|
||||||
|
{
|
||||||
|
lng: properties.startPoint[0],
|
||||||
|
lat: properties.startPoint[1],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (properties.endPoint) {
|
||||||
|
this.endPointLayer.setData([
|
||||||
|
{
|
||||||
|
lng: properties.endPoint[0],
|
||||||
|
lat: properties.endPoint[1],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.draw.scene.removeLayer(this.lineLayer);
|
||||||
|
this.draw.scene.removeLayer(this.polygonLayer);
|
||||||
|
this.draw.scene.removeLayer(this.centerLayer);
|
||||||
|
this.draw.scene.removeLayer(this.endPointLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show() {
|
||||||
|
this.lineLayer.show();
|
||||||
|
this.polygonLayer.show();
|
||||||
|
this.centerLayer.show();
|
||||||
|
this.endPointLayer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide() {
|
||||||
|
this.lineLayer.hide();
|
||||||
|
this.polygonLayer.hide();
|
||||||
|
this.centerLayer.hide();
|
||||||
|
this.endPointLayer.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private addLayerEvent() {
|
||||||
|
this.endPointLayer.on('mousemove', (e) => {
|
||||||
|
this.draw.setCursor('move');
|
||||||
|
this.draw.editMode.enable();
|
||||||
|
});
|
||||||
|
this.endPointLayer.on('unmousemove', (e) => {
|
||||||
|
this.draw.resetCursor();
|
||||||
|
this.draw.editMode.disable();
|
||||||
|
});
|
||||||
|
this.polygonLayer.on('unclick', (e) => {
|
||||||
|
// 取消选中 回到初始态
|
||||||
|
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.STATIC);
|
||||||
|
this.draw.editMode.disable();
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
import Draw from '../modes/draw_mode';
|
||||||
|
import { DrawEvent, DrawModes } from '../util/constant';
|
||||||
|
export default class RenderLayer {
|
||||||
|
private polygonLayer: ILayer;
|
||||||
|
private lineLayer: ILayer;
|
||||||
|
private draw: Draw;
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
public init() {
|
||||||
|
const style = this.draw.getStyle('normal_fill');
|
||||||
|
const linestyle = this.draw.getStyle('normal_line');
|
||||||
|
this.polygonLayer = new PolygonLayer({
|
||||||
|
zIndex: 0,
|
||||||
|
})
|
||||||
|
.source(InitFeature)
|
||||||
|
.filter('active', (active) => {
|
||||||
|
return !active;
|
||||||
|
})
|
||||||
|
.shape('fill')
|
||||||
|
.active(true)
|
||||||
|
.color(style.color)
|
||||||
|
.style(style.style);
|
||||||
|
|
||||||
|
this.lineLayer = new LineLayer({
|
||||||
|
zIndex: 1,
|
||||||
|
})
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('line')
|
||||||
|
.filter('active', (active) => {
|
||||||
|
return !active;
|
||||||
|
})
|
||||||
|
.size(linestyle.size)
|
||||||
|
.color(linestyle.color)
|
||||||
|
.style(linestyle.style);
|
||||||
|
this.draw.scene.addLayer(this.polygonLayer);
|
||||||
|
this.draw.scene.addLayer(this.lineLayer);
|
||||||
|
this.addLayerEvent();
|
||||||
|
}
|
||||||
|
public updateData() {
|
||||||
|
this.lineLayer.setData(this.draw.source.data);
|
||||||
|
this.polygonLayer.setData(this.draw.source.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.draw.scene.removeLayer(this.lineLayer);
|
||||||
|
this.draw.scene.removeLayer(this.polygonLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show() {
|
||||||
|
this.lineLayer.show();
|
||||||
|
this.polygonLayer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide() {
|
||||||
|
this.lineLayer.hide();
|
||||||
|
this.polygonLayer.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private addLayerEvent() {
|
||||||
|
this.polygonLayer.on('click', (e) => {
|
||||||
|
this.draw.setCurrentFeature(e.feature);
|
||||||
|
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.SIMPLE_SELECT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
import {
|
||||||
|
IInteractionTarget,
|
||||||
|
ILayer,
|
||||||
|
ILngLat,
|
||||||
|
IPopup,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
Scene,
|
||||||
|
} from '@antv/l7';
|
||||||
|
const InitFeature = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
import { Feature } from '@turf/helpers';
|
||||||
|
import Draw from '../modes/draw_feature';
|
||||||
|
import { DrawEvent, DrawModes } from '../util/constant';
|
||||||
|
export default class EditRenderLayer {
|
||||||
|
private polygonLayer: ILayer;
|
||||||
|
private lineLayer: ILayer;
|
||||||
|
private centerLayer: ILayer;
|
||||||
|
private endPointLayer: ILayer;
|
||||||
|
private draw: Draw;
|
||||||
|
private currentFeature: Feature;
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
public init() {
|
||||||
|
const style = this.draw.getStyle('active_fill');
|
||||||
|
const linestyle = this.draw.getStyle('active_line');
|
||||||
|
const centerStyle = this.draw.getStyle('active_point');
|
||||||
|
this.polygonLayer = new PolygonLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('fill')
|
||||||
|
.color(style.color)
|
||||||
|
.style(style.style);
|
||||||
|
|
||||||
|
this.lineLayer = new LineLayer()
|
||||||
|
.source(InitFeature)
|
||||||
|
.shape('line')
|
||||||
|
.size(linestyle.size)
|
||||||
|
.color(linestyle.color)
|
||||||
|
.style(linestyle.style);
|
||||||
|
this.centerLayer = new PointLayer({
|
||||||
|
zIndex: 3,
|
||||||
|
blend: 'normal',
|
||||||
|
})
|
||||||
|
.source([], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
|
||||||
|
this.endPointLayer = new PointLayer({
|
||||||
|
zIndex: 4,
|
||||||
|
blend: 'normal',
|
||||||
|
})
|
||||||
|
.source([], {
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.color(centerStyle.color)
|
||||||
|
.size(centerStyle.size)
|
||||||
|
.style(centerStyle.style);
|
||||||
|
|
||||||
|
this.draw.scene.addLayer(this.polygonLayer);
|
||||||
|
this.draw.scene.addLayer(this.lineLayer);
|
||||||
|
this.draw.scene.addLayer(this.centerLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateData(data: any) {
|
||||||
|
if (this.currentFeature === undefined) {
|
||||||
|
this.addLayerEvent();
|
||||||
|
}
|
||||||
|
this.currentFeature = data.features[0];
|
||||||
|
this.lineLayer.setData(data);
|
||||||
|
this.polygonLayer.setData(data);
|
||||||
|
const properties = data.features[0].properties;
|
||||||
|
if (properties.startPoint) {
|
||||||
|
this.centerLayer.setData([
|
||||||
|
{
|
||||||
|
lng: properties.startPoint[0],
|
||||||
|
lat: properties.startPoint[1],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (properties.endPoint) {
|
||||||
|
this.endPointLayer.setData([
|
||||||
|
{
|
||||||
|
lng: properties.endPoint[0],
|
||||||
|
lat: properties.endPoint[1],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.draw.scene.removeLayer(this.lineLayer);
|
||||||
|
this.draw.scene.removeLayer(this.polygonLayer);
|
||||||
|
// this.draw.scene.removeLayer(this.centerLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show() {
|
||||||
|
this.lineLayer.show();
|
||||||
|
this.polygonLayer.show();
|
||||||
|
// this.centerLayer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide() {
|
||||||
|
this.lineLayer.hide();
|
||||||
|
this.polygonLayer.hide();
|
||||||
|
// this.centerLayer.hide();
|
||||||
|
}
|
||||||
|
private addLayerEvent() {
|
||||||
|
this.polygonLayer.on('mousemove', (e) => {
|
||||||
|
this.draw.setCursor('move');
|
||||||
|
this.draw.selectMode.enable();
|
||||||
|
});
|
||||||
|
this.polygonLayer.on('unmousemove', (e) => {
|
||||||
|
this.draw.resetCursor();
|
||||||
|
this.draw.selectMode.disable();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.polygonLayer.on('click', (e) => {
|
||||||
|
// 进入编辑态
|
||||||
|
this.draw.selectMode.disable();
|
||||||
|
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.DIRECT_SELECT);
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
this.polygonLayer.on('unclick', (e) => {
|
||||||
|
// 取消选中 回到初始态
|
||||||
|
this.draw.emit(DrawEvent.MODE_CHANGE, DrawModes.STATIC);
|
||||||
|
this.draw.selectMode.disable();
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Feature, FeatureCollection } from '@turf/helpers';
|
import { Feature, FeatureCollection } from '@turf/helpers';
|
||||||
export default class DrawSource {
|
export default class DrawSource {
|
||||||
private data: FeatureCollection;
|
public data: FeatureCollection;
|
||||||
constructor(data?: FeatureCollection) {
|
constructor(data?: FeatureCollection) {
|
||||||
this.data = data || this.getDefaultData();
|
this.data = data || this.getDefaultData();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,18 @@ export default class DrawSource {
|
||||||
this.data.features.splice(index, 1);
|
this.data.features.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public setFeatureActive(feature: Feature) {
|
||||||
|
const fe = this.getFeature(feature?.properties?.id);
|
||||||
|
if (fe && fe.properties) {
|
||||||
|
fe.properties.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public setFeatureUnActive(feature: Feature) {
|
||||||
|
const fe = this.getFeature(feature?.properties?.id);
|
||||||
|
if (fe && fe.properties) {
|
||||||
|
fe.properties.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
public updateFeature(feature: Feature) {
|
public updateFeature(feature: Feature) {
|
||||||
this.removeFeature(feature);
|
this.removeFeature(feature);
|
||||||
this.addFeature(feature);
|
this.addFeature(feature);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
export enum DrawEvent {
|
||||||
|
CREATE = 'draw.create',
|
||||||
|
DELETE = 'draw.delete',
|
||||||
|
Move = 'draw.move',
|
||||||
|
Edit = 'draw.edit',
|
||||||
|
UPDATE = 'draw.update',
|
||||||
|
SELECTION_CHANGE = 'draw.selectionchange',
|
||||||
|
MODE_CHANGE = 'draw.modechange',
|
||||||
|
ACTIONABLE = 'draw.actionable',
|
||||||
|
RENDER = 'draw.render',
|
||||||
|
COMBINE_FEATURES = 'draw.combine',
|
||||||
|
UNCOMBINE_FEATURES = 'draw.uncombine',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DrawModes {
|
||||||
|
DRAW_Circle = 'draw_circle',
|
||||||
|
DRAW_Rect = 'draw_react',
|
||||||
|
DRAW_LINE_STRING = 'draw_line_string',
|
||||||
|
DRAW_POLYGON = 'draw_polygon',
|
||||||
|
DRAW_POINT = 'draw_point',
|
||||||
|
SIMPLE_SELECT = 'simple_select',
|
||||||
|
DIRECT_SELECT = 'direct_select',
|
||||||
|
STATIC = 'static',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type unitsType = 'degrees' | 'radians' | 'miles' | 'kilometers';
|
||||||
|
|
||||||
|
export enum FeatureType {
|
||||||
|
FEATURE = 'Feature',
|
||||||
|
POLYGON = 'Polygon',
|
||||||
|
LINE_STRING = 'LineString',
|
||||||
|
POINT = 'Point',
|
||||||
|
FEATURE_COLLECTION = 'FeatureCollection',
|
||||||
|
MULTI_PREFIX = 'Multi',
|
||||||
|
MULTI_POINT = 'MultiPoint',
|
||||||
|
MULTI_LINE_STRING = 'MultiLineString',
|
||||||
|
MULTI_POLYGON = 'MultiPolygon',
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import turfCircle from '@turf/circle';
|
||||||
|
import turfDistance from '@turf/distance';
|
||||||
|
import { Feature, featureCollection, point } from '@turf/helpers';
|
||||||
|
import { unitsType } from './constant';
|
||||||
|
|
||||||
|
export function createCircle(
|
||||||
|
center: [number, number],
|
||||||
|
endPoint: [number, number],
|
||||||
|
options: {
|
||||||
|
units: unitsType;
|
||||||
|
steps: number;
|
||||||
|
id: string;
|
||||||
|
},
|
||||||
|
): Feature {
|
||||||
|
const radius = turfDistance(point(center), point(endPoint), options);
|
||||||
|
const feature = turfCircle(center, radius, {
|
||||||
|
units: options.units,
|
||||||
|
steps: options.steps,
|
||||||
|
properties: {
|
||||||
|
id: options.id,
|
||||||
|
active: true,
|
||||||
|
radius,
|
||||||
|
startPoint: center,
|
||||||
|
endPoint,
|
||||||
|
path: [center, endPoint],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return feature as Feature;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function creatRect(
|
||||||
|
startPoint: [number, number],
|
||||||
|
endPoint: [number, number],
|
||||||
|
): Feature {
|
||||||
|
const minX = Math.min(startPoint[0], endPoint[0]);
|
||||||
|
const minY = Math.min(startPoint[1], endPoint[1]);
|
||||||
|
const maxX = Math.max(startPoint[0], endPoint[0]);
|
||||||
|
const maxY = Math.max(startPoint[1], endPoint[1]);
|
||||||
|
const feature = {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
active: true,
|
||||||
|
startPoint,
|
||||||
|
endPoint,
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [
|
||||||
|
[
|
||||||
|
[minX, minY],
|
||||||
|
[minX, maxY],
|
||||||
|
[maxX, maxY],
|
||||||
|
[maxX, minY],
|
||||||
|
[minX, minY],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return feature as Feature;
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
const LayerStyles = {
|
||||||
|
// 正常显示样式
|
||||||
|
normal_fill: {
|
||||||
|
type: 'PolygonLayer',
|
||||||
|
shape: 'fill',
|
||||||
|
color: '#3bb2d0',
|
||||||
|
style: {
|
||||||
|
opacity: 0.1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// xai'm'z
|
||||||
|
active_fill: {
|
||||||
|
type: 'PolygonLayer',
|
||||||
|
shape: 'fill',
|
||||||
|
color: '#fbb03b',
|
||||||
|
style: {
|
||||||
|
opacity: 0.1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
normal_point: {
|
||||||
|
type: 'PointLayer',
|
||||||
|
shape: 'circle',
|
||||||
|
color: '#3bb2d0',
|
||||||
|
size: 3,
|
||||||
|
style: {
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mid_point: {
|
||||||
|
type: 'PointLayer',
|
||||||
|
shape: 'circle',
|
||||||
|
color: '#fbb03b',
|
||||||
|
size: 3,
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
active_point: {
|
||||||
|
type: 'PointLayer',
|
||||||
|
shape: 'circle',
|
||||||
|
color: '#fbb03b',
|
||||||
|
size: 5,
|
||||||
|
style: {
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
normal_line: {
|
||||||
|
type: 'LineLayer',
|
||||||
|
shape: 'line',
|
||||||
|
size: 1,
|
||||||
|
color: '#3bb2d0',
|
||||||
|
style: {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
active_line: {
|
||||||
|
type: 'LineLayer',
|
||||||
|
shape: 'line',
|
||||||
|
color: '#fbb03b',
|
||||||
|
size: 1,
|
||||||
|
style: {
|
||||||
|
opacity: 1,
|
||||||
|
lineType: 'dash',
|
||||||
|
dashArray: [2, 2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LayerStyles;
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { Feature, Geometry, Properties } from '@turf/helpers';
|
||||||
|
import { FeatureType } from './constant';
|
||||||
|
interface IDelta {
|
||||||
|
lng: number;
|
||||||
|
lat: number;
|
||||||
|
}
|
||||||
|
type RingType = Array<[number, number]>;
|
||||||
|
export default function(features: Feature[], delta: IDelta) {
|
||||||
|
features.forEach((feature) => {
|
||||||
|
const geometry = feature.geometry as Geometry;
|
||||||
|
let nextCoord;
|
||||||
|
const { type, coordinates } = geometry;
|
||||||
|
switch (type) {
|
||||||
|
case FeatureType.POINT:
|
||||||
|
nextCoord = movePoint(coordinates as [number, number], delta);
|
||||||
|
break;
|
||||||
|
case FeatureType.LINE_STRING:
|
||||||
|
case FeatureType.MULTI_POINT:
|
||||||
|
nextCoord = moveRing(coordinates as RingType, delta);
|
||||||
|
break;
|
||||||
|
case FeatureType.POLYGON:
|
||||||
|
case FeatureType.MULTI_LINE_STRING:
|
||||||
|
nextCoord = moveMultiPolygon(coordinates as RingType[], delta);
|
||||||
|
break;
|
||||||
|
case FeatureType.MULTI_POLYGON:
|
||||||
|
nextCoord = (coordinates as RingType[][]).map((mult) =>
|
||||||
|
moveMultiPolygon(mult as RingType[], delta),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nextCoord) {
|
||||||
|
geometry.coordinates = nextCoord;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function movePoint(
|
||||||
|
coord: [number, number],
|
||||||
|
delta: IDelta,
|
||||||
|
): [number, number] {
|
||||||
|
return [coord[0] + delta.lng, coord[1] + delta.lat];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveRing(coords: RingType, delta: IDelta) {
|
||||||
|
return coords.map((coord) => movePoint(coord, delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveMultiPolygon(mult: RingType[], delta: IDelta) {
|
||||||
|
return mult.map((ring) => moveRing(ring, delta));
|
||||||
|
}
|
|
@ -51,11 +51,13 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
||||||
filterData = dataArray.filter((record: IParseDataItem) => {
|
filterData = dataArray.filter((record: IParseDataItem) => {
|
||||||
return this.applyAttributeMapping(filter, record)[0];
|
return this.applyAttributeMapping(filter, record)[0];
|
||||||
});
|
});
|
||||||
|
filter.needRemapping = false;
|
||||||
}
|
}
|
||||||
if (attributesToRemapping.length) {
|
if (attributesToRemapping.length) {
|
||||||
// 过滤数据
|
// 过滤数据
|
||||||
if (filter?.needRemapping) {
|
if (filter?.needRemapping) {
|
||||||
layer.setEncodedData(this.mapping(attributes, filterData));
|
layer.setEncodedData(this.mapping(attributes, filterData));
|
||||||
|
filter.needRemapping = false;
|
||||||
} else {
|
} else {
|
||||||
layer.setEncodedData(
|
layer.setEncodedData(
|
||||||
this.mapping(
|
this.mapping(
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
|
||||||
normal: {
|
normal: {
|
||||||
blend: 'additive',
|
blend: 'additive',
|
||||||
},
|
},
|
||||||
fill: {},
|
fill: { blend: 'normal' },
|
||||||
extrude: {},
|
extrude: {},
|
||||||
image: {},
|
image: {},
|
||||||
icon: {},
|
icon: {},
|
||||||
|
|
|
@ -57,6 +57,8 @@ void main() {
|
||||||
float opacity_t = smoothstep(0.0, antialiased_blur, outer_df);
|
float opacity_t = smoothstep(0.0, antialiased_blur, outer_df);
|
||||||
if(u_stroke_width <0.01 ) {
|
if(u_stroke_width <0.01 ) {
|
||||||
gl_FragColor = v_color * opacity_t;
|
gl_FragColor = v_color * opacity_t;
|
||||||
|
gl_FragColor.a = gl_FragColor.a * u_opacity;
|
||||||
|
gl_FragColor = filterColor(gl_FragColor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(
|
float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"types": "es/index.d.ts",
|
"types": "es/index.d.ts",
|
||||||
|
"unpkg": "dist/l7-maps.js",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"files": [
|
"files": [
|
||||||
|
"dist",
|
||||||
"lib",
|
"lib",
|
||||||
"es",
|
"es",
|
||||||
"typings/index.d.ts",
|
"typings/index.d.ts",
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import pkg from './package.json';
|
||||||
|
import typescript from 'rollup-plugin-typescript';
|
||||||
|
import resolve from 'rollup-plugin-node-resolve';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import buble from 'rollup-plugin-buble';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: './src/index.ts',
|
||||||
|
plugins: [
|
||||||
|
typescript({
|
||||||
|
exclude: 'node_modules/**',
|
||||||
|
typescript: require('typescript')
|
||||||
|
}),
|
||||||
|
resolve(),
|
||||||
|
commonjs(),
|
||||||
|
buble({
|
||||||
|
transforms: { generator: false }
|
||||||
|
})
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
format: 'umd',
|
||||||
|
name: 'L7-Maps',
|
||||||
|
file: pkg.unpkg,
|
||||||
|
sourcemap: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
|
@ -3,6 +3,6 @@ export const MapTheme: {
|
||||||
} = {
|
} = {
|
||||||
dark: 'amap://styles/2a09079c3daac9420ee53b67307a8006?isPublic=true',
|
dark: 'amap://styles/2a09079c3daac9420ee53b67307a8006?isPublic=true',
|
||||||
light: 'amap://styles/1fd9f8ef9751298f11f5c56968312c70?isPublic=true',
|
light: 'amap://styles/1fd9f8ef9751298f11f5c56968312c70?isPublic=true',
|
||||||
normal: 'amap://styles/12db649ba3493333b098127ed892c0cb?isPublic=true',
|
normal: 'amap://styles/normal',
|
||||||
blank: 'amap://styles/07c17002b38775b32a7a76c66cf90e99?isPublic=true',
|
blank: 'amap://styles/07c17002b38775b32a7a76c66cf90e99?isPublic=true',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
# `react`
|
# `react`
|
||||||
|
|
||||||
> TODO: description
|
> L7
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
const react = require('react');
|
import { Scene } from '@antv/l7-react';
|
||||||
|
|
||||||
// TODO: DEMONSTRATE API
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -264,6 +264,9 @@ class Scene
|
||||||
this.mapService.panTo(pixel);
|
this.mapService.panTo(pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getContainer() {
|
||||||
|
return this.mapService.getContainer();
|
||||||
|
}
|
||||||
public setZoom(zoom: number): void {
|
public setZoom(zoom: number): void {
|
||||||
this.mapService.setZoom(zoom);
|
this.mapService.setZoom(zoom);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export enum anchorType {
|
||||||
'RIGHT' = 'right',
|
'RIGHT' = 'right',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const anchorTranslate = {
|
export const anchorTranslate: { [key: string]: string } = {
|
||||||
center: 'translate(-50%,-50%)',
|
center: 'translate(-50%,-50%)',
|
||||||
top: 'translate(-50%,0)',
|
top: 'translate(-50%,0)',
|
||||||
'top-left': 'translate(0,0)',
|
'top-left': 'translate(0,0)',
|
||||||
|
|
|
@ -40,7 +40,7 @@ function sum(x: number[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializing the sum as the first number in the array
|
// Initializing the sum as the first number in the array
|
||||||
let sumNum = x[0];
|
let sumNum = x[0] * 1;
|
||||||
|
|
||||||
// Keeping track of the floating-point error correction
|
// Keeping track of the floating-point error correction
|
||||||
let correction = 0;
|
let correction = 0;
|
||||||
|
@ -71,16 +71,45 @@ function mean(x: number[]) {
|
||||||
return sum(x) / x.length;
|
return sum(x) / x.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { sum, max, min, mean };
|
function mode(x: any[]) {
|
||||||
|
if (x.length === 0) {
|
||||||
|
throw new Error('mean requires at least one data point');
|
||||||
|
}
|
||||||
|
if (x.length < 3) {
|
||||||
|
return x[0];
|
||||||
|
}
|
||||||
|
x.sort();
|
||||||
|
let last = x[0];
|
||||||
|
let value = NaN;
|
||||||
|
let maxSeen = 0;
|
||||||
|
let seenThis = 1;
|
||||||
|
|
||||||
|
for (let i = 1; i < x.length + 1; i++) {
|
||||||
|
if (x[i] !== last) {
|
||||||
|
if (seenThis > maxSeen) {
|
||||||
|
maxSeen = seenThis;
|
||||||
|
value = last;
|
||||||
|
}
|
||||||
|
seenThis = 1;
|
||||||
|
last = x[i];
|
||||||
|
} else {
|
||||||
|
seenThis++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { sum, max, min, mean, mode };
|
||||||
export const statMap: { [key: string]: any } = {
|
export const statMap: { [key: string]: any } = {
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
mean,
|
mean,
|
||||||
sum,
|
sum,
|
||||||
|
mode,
|
||||||
};
|
};
|
||||||
export function getColumn(data: IItemData[], columnName: string) {
|
export function getColumn(data: IItemData[], columnName: string) {
|
||||||
return data.map((item: IItemData) => {
|
return data.map((item: IItemData) => {
|
||||||
return item[columnName] * 1;
|
return item[columnName];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { LineLayer, PointLayer, PolygonLayer, Popup, Scene } from '@antv/l7';
|
||||||
|
import { DrawCircle } from '@antv/l7-draw';
|
||||||
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
export default class Circle extends React.Component {
|
||||||
|
private scene: Scene;
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
this.scene.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
const scene = new Scene({
|
||||||
|
id: 'map',
|
||||||
|
map: new Mapbox({
|
||||||
|
pitch: 0,
|
||||||
|
style: 'light',
|
||||||
|
center: [113.775374, 28.31067],
|
||||||
|
zoom: 12,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
const drawCircle = new DrawCircle(scene);
|
||||||
|
drawCircle.enable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="map"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ export default class MultiPolygon extends React.Component {
|
||||||
scene.addLayer(circleLayer);
|
scene.addLayer(circleLayer);
|
||||||
scene.on('dragstart', (e: any) => {
|
scene.on('dragstart', (e: any) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
scene.map.dragdrag.disable();
|
scene.map.drag.disable();
|
||||||
startPoint = e.lngLat;
|
startPoint = e.lngLat;
|
||||||
const layer = new PointLayer()
|
const layer = new PointLayer()
|
||||||
.source([startPoint], {
|
.source([startPoint], {
|
||||||
|
|
|
@ -1,43 +1,9 @@
|
||||||
import { LineLayer, PointLayer, PolygonLayer, Popup, Scene } from '@antv/l7';
|
import { LineLayer, PointLayer, PolygonLayer, Popup, Scene } from '@antv/l7';
|
||||||
|
import { DrawRect } from '@antv/l7-draw';
|
||||||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
import * as React from 'react';
|
|
||||||
const createGeoJSONRect = (
|
|
||||||
point1: [number, number],
|
|
||||||
point2: [number, number],
|
|
||||||
) => {
|
|
||||||
const minX = Math.min(point1[0], point2[0]);
|
|
||||||
const minY = Math.min(point1[1], point2[1]);
|
|
||||||
const maxX = Math.max(point1[0], point2[0]);
|
|
||||||
const maxY = Math.max(point1[1], point2[1]);
|
|
||||||
|
|
||||||
return {
|
import * as React from 'react';
|
||||||
type: 'geojson',
|
export default class Circle extends React.Component {
|
||||||
data: {
|
|
||||||
type: 'FeatureCollection',
|
|
||||||
features: [
|
|
||||||
{
|
|
||||||
type: 'Feature',
|
|
||||||
properties: {},
|
|
||||||
geometry: {
|
|
||||||
type: 'Polygon',
|
|
||||||
coordinates: [
|
|
||||||
[
|
|
||||||
[minX, minY],
|
|
||||||
[minX, maxY],
|
|
||||||
[maxX, maxY],
|
|
||||||
[maxX, minY],
|
|
||||||
[minX, minY],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export default class MultiPolygon extends React.Component {
|
|
||||||
private gui: dat.GUI;
|
|
||||||
private $stats: Node;
|
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
|
@ -49,63 +15,16 @@ export default class MultiPolygon extends React.Component {
|
||||||
id: 'map',
|
id: 'map',
|
||||||
map: new Mapbox({
|
map: new Mapbox({
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'normal',
|
style: 'light',
|
||||||
center: [121.775374, 31.31067],
|
center: [113.775374, 28.31067],
|
||||||
zoom: 15,
|
zoom: 12,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
let startPoint = {};
|
const drawRect = new DrawRect(scene);
|
||||||
const circleLayer = new PolygonLayer()
|
drawRect.enable();
|
||||||
.source({
|
|
||||||
type: 'FeatureCollection',
|
|
||||||
features: [],
|
|
||||||
})
|
|
||||||
.color('#fbb03b')
|
|
||||||
.shape('fill')
|
|
||||||
.style({
|
|
||||||
opacity: 0.6,
|
|
||||||
});
|
|
||||||
scene.addLayer(circleLayer);
|
|
||||||
scene.on('panstart', (e: any) => {
|
|
||||||
// @ts-ignore
|
|
||||||
scene.map.dragPan.disable();
|
|
||||||
startPoint = e.lngLat;
|
|
||||||
const layer = new PointLayer()
|
|
||||||
.source([startPoint], {
|
|
||||||
parser: {
|
|
||||||
type: 'json',
|
|
||||||
x: 'lng',
|
|
||||||
y: 'lat',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.shape('circle')
|
|
||||||
.color('#fbb03b')
|
|
||||||
.size(5)
|
|
||||||
.style({
|
|
||||||
stroke: '#fff',
|
|
||||||
strokeWidth: 2,
|
|
||||||
});
|
|
||||||
scene.addLayer(layer);
|
|
||||||
});
|
|
||||||
scene.on('panmove', (e: any) => {
|
|
||||||
// @ts-ignore
|
|
||||||
const start = [startPoint.lng, startPoint.lat];
|
|
||||||
|
|
||||||
const circleData = createGeoJSONRect(start as [number, number], [
|
|
||||||
e.lngLat.lng,
|
|
||||||
e.lngLat.lat,
|
|
||||||
]);
|
|
||||||
circleLayer.setData(circleData.data);
|
|
||||||
// const popup = new Popup().setText(`${dis}`).setLnglat(e.lngLat);
|
|
||||||
// scene.addPopup(popup);
|
|
||||||
});
|
|
||||||
scene.on('panend', (e: any) => {
|
|
||||||
// @ts-ignore
|
|
||||||
scene.map.dragPan.enable();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { storiesOf } from '@storybook/react';
|
import { storiesOf } from '@storybook/react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import Circle from './Components/Circle';
|
||||||
import DrawCircle from './Components/DrawCircle';
|
import DrawCircle from './Components/DrawCircle';
|
||||||
import DrawPolygon from './Components/DrawPolygon';
|
import DrawPolygon from './Components/DrawPolygon';
|
||||||
import DrawRect from './Components/DrawRect';
|
import DrawRect from './Components/DrawRect';
|
||||||
|
|
||||||
storiesOf('绘制', module)
|
storiesOf('绘制', module)
|
||||||
|
.add('圆', () => <Circle />, {})
|
||||||
.add('绘制圆', () => <DrawCircle />, {})
|
.add('绘制圆', () => <DrawCircle />, {})
|
||||||
.add('四边形', () => <DrawRect />, {})
|
.add('四边形', () => <DrawRect />, {})
|
||||||
.add('绘制面', () => <DrawPolygon />, {});
|
.add('绘制面', () => <DrawPolygon />, {});
|
||||||
|
|
|
@ -2,8 +2,6 @@ import { HeatmapLayer, PointLayer, Scene } from '@antv/l7';
|
||||||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
import * as dat from 'dat.gui';
|
import * as dat from 'dat.gui';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
// @ts-ignore
|
|
||||||
import data from '../data/data.json';
|
|
||||||
export default class HexagonLayerDemo extends React.Component {
|
export default class HexagonLayerDemo extends React.Component {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
|
@ -16,87 +14,58 @@ export default class HexagonLayerDemo extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const response = await fetch(
|
|
||||||
'https://gw.alipayobjects.com/os/basement_prod/337ddbb7-aa3f-4679-ab60-d64359241955.json',
|
|
||||||
);
|
|
||||||
const pointsData = await response.json();
|
|
||||||
|
|
||||||
const scene = new Scene({
|
const scene = new Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
map: new GaodeMap({
|
map: new Mapbox({
|
||||||
center: [120.19382669582967, 30.258134],
|
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'light',
|
style: 'blank',
|
||||||
zoom: 3,
|
center: [140.067171, 36.26186],
|
||||||
|
zoom: 0,
|
||||||
|
maxZoom: 0,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const pointLayer = new HeatmapLayer({})
|
scene.on('loaded', () => {
|
||||||
.source(pointsData, {
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/3dadb1f5-8f54-4449-8206-72db6e142c40.json',
|
||||||
|
)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
const pointLayer = new HeatmapLayer({
|
||||||
|
autoFit: true,
|
||||||
|
})
|
||||||
|
.source(data, {
|
||||||
transforms: [
|
transforms: [
|
||||||
{
|
{
|
||||||
type: 'grid',
|
type: 'hexagon',
|
||||||
size: 500000,
|
size: 500000,
|
||||||
field: 'capacity',
|
field: 'name',
|
||||||
method: 'sum',
|
method: 'mode',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.shape('hexagon')
|
.shape('hexagon') // 支持 circle, hexagon,triangle
|
||||||
.style({
|
.color('mode', [
|
||||||
coverage: 0.9,
|
'#ffffe5',
|
||||||
angle: 0,
|
'#fff7bc',
|
||||||
opacity: 0.6,
|
'#fee391',
|
||||||
})
|
'#fec44f',
|
||||||
.color(
|
'#fe9929',
|
||||||
'sum',
|
'#ec7014',
|
||||||
[
|
'#cc4c02',
|
||||||
'#3F4BBA',
|
'#993404',
|
||||||
'#3F4BBA',
|
'#662506',
|
||||||
'#3F4BBA',
|
|
||||||
'#3F4BBA',
|
|
||||||
'#3C73DA',
|
|
||||||
'#3C73DA',
|
|
||||||
'#3C73DA',
|
|
||||||
'#0F62FF',
|
|
||||||
'#0F62FF',
|
|
||||||
'#30B2E9',
|
|
||||||
'#30B2E9',
|
|
||||||
'#40C4CE',
|
|
||||||
].reverse(),
|
|
||||||
);
|
|
||||||
scene.addLayer(pointLayer);
|
|
||||||
pointLayer.on('click', (e) => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.scene = scene;
|
|
||||||
|
|
||||||
const gui = new dat.GUI();
|
|
||||||
this.gui = gui;
|
|
||||||
const styleOptions = {
|
|
||||||
textAnchor: 'center',
|
|
||||||
strokeWidth: 1,
|
|
||||||
};
|
|
||||||
const rasterFolder = gui.addFolder('栅格可视化');
|
|
||||||
rasterFolder
|
|
||||||
.add(styleOptions, 'textAnchor', [
|
|
||||||
'center',
|
|
||||||
'left',
|
|
||||||
'right',
|
|
||||||
'top',
|
|
||||||
'bottom',
|
|
||||||
'top-left',
|
|
||||||
'bottom-right',
|
|
||||||
'bottom-left',
|
|
||||||
'top-right',
|
|
||||||
])
|
])
|
||||||
.onChange((anchor: string) => {
|
.active(false)
|
||||||
pointLayer.style({
|
.style({
|
||||||
textAnchor: anchor,
|
coverage: 0.7,
|
||||||
|
// angle: 0.5,
|
||||||
|
opacity: 1.0,
|
||||||
|
});
|
||||||
|
scene.addLayer(pointLayer);
|
||||||
|
console.log(pointLayer.getSource());
|
||||||
|
this.scene = scene;
|
||||||
});
|
});
|
||||||
scene.render();
|
|
||||||
});
|
});
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
Loading…
Reference in New Issue