基于高德地图JS api开发的geojson编辑器. http://geojson.finevis.cc/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

214 lines
5.7 KiB

import Emitter from "@finevis/emitter";
import "@amap/amap-jsapi-types";
import { getOverlayPaths, getUID, registerHotkey } from "@utils";
import {
BaseOverlayEditor,
RectangleEditor,
PolygonEditor,
PolylineEditor,
CircleEditor,
} from "./editors";
import { IMapOptions, IMapEditor } from "./type";
import { PolygonOptions, PolylineOptions, SelectedOptions } from "./constants";
import { EventTypes, OverlayTypes } from "../types/enum";
type AMapOverlayEditor =
| AMap.RectangleEditor
| AMap.PolygonEditor
| AMap.PolylineEditor
| AMap.CircleEditor;
type OverlayTemp = {
type: OverlayTypes;
target: AMap.MapOverlay;
};
const getOverlayOptions = (type: OverlayTypes) =>
type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions;
export class MapEditor extends Emitter implements IMapEditor {
dom: HTMLDivElement;
private _map: AMap.Map | undefined;
private overlayEditors: BaseOverlayEditor<AMapOverlayEditor>[] = [];
private overlayMap: Record<string, OverlayTemp> = {};
private currentOverlayEditor:
| BaseOverlayEditor<AMapOverlayEditor>
| undefined;
private selectedIds: string[] = [];
private editorStatus: "editing" | "creating" | null = null;
constructor(dom: HTMLDivElement) {
super();
this.dom = dom;
}
get map() {
return this._map!;
}
async init() {
await AMapLoader.load({
key: "a4171ad2d7df42823b4de7d25c8c35ee",
version: "2.0",
plugins: [
"AMap.RectangleEditor",
"AMap.PolylineEditor",
"AMap.PolygonEditor",
"AMap.CircleEditor",
"AMap.PlaceSearch",
"AMap.AutoComplete",
],
});
this._map = new AMap.Map(this.dom);
this.initEditors();
// Space的key是空字符串, 这就离谱.
registerHotkey(" ", { callback: this.finishEditOverlay.bind(this) });
registerHotkey("e", {
callback: this.editSelectedOverlay.bind(this),
alt: true,
});
}
initEditors() {
const { map } = this;
this.overlayEditors = [
new RectangleEditor(map),
new PolygonEditor(map),
new PolylineEditor(map),
new CircleEditor(map),
];
}
getCenter() {
const { lng, lat } = this.map.getCenter();
return [lng, lat];
}
getZoom() {
return this.map.getZoom();
}
getEditorByType(overlayType: OverlayTypes) {
return this.overlayEditors.find(
(editor) => editor.getType() === overlayType
)!;
}
importProject(options: IMapOptions) {
this.clearOverlays();
const { overlays } = options;
const overlayEditors: Record<
OverlayTypes,
BaseOverlayEditor<AMapOverlayEditor>
> = {
[OverlayTypes.Rectangle]: this.getEditorByType(OverlayTypes.Rectangle),
[OverlayTypes.Polygon]: this.getEditorByType(OverlayTypes.Polygon),
[OverlayTypes.Polyline]: this.getEditorByType(OverlayTypes.Polyline),
[OverlayTypes.Circle]: this.getEditorByType(OverlayTypes.Circle),
};
if (options.center) {
const [lng, lat] = options.center;
this.map.setCenter(new AMap.LngLat(lng, lat));
}
if (options.zoom != null) {
this.map.setZoom(options.zoom);
}
overlays.forEach((overlay) => {
const { type, id } = overlay;
const target = overlayEditors[type].build(overlay);
this.overlayMap[id] = {
type,
target,
};
target.setOptions(
type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions
);
this.map.add(target);
});
}
importGeoJSON(geojson: GeoJSON.FeatureCollection): void {
throw new Error("Method not implemented.");
}
// 清空所有覆盖物
clearOverlays() {
for (let id in this.overlayMap) {
this.map.remove(this.overlayMap[id].target);
}
this.overlayMap = {};
this.selectedIds = [];
}
createOverlay(type: OverlayTypes) {
this.currentOverlayEditor = this.getEditorByType(type!);
this.currentOverlayEditor?.create();
this.editorStatus = "creating";
}
selectOverlays(ids?: string[]) {
this.selectedIds?.forEach((id) => {
const { target, type } = this.overlayMap[id];
target.setOptions(getOverlayOptions(type));
});
if (ids == null) return;
this.selectedIds = ids;
ids.forEach((id) => {
const { target } = this.overlayMap[id];
target.setOptions(SelectedOptions);
});
}
deleteOverlays() {
if (this.selectedIds?.length === 0) return;
this.selectedIds.forEach((id) => {
const { target } = this.overlayMap[id];
this.map.remove(target);
delete this.overlayMap[id];
});
this.selectedIds = [];
}
finishEditOverlay() {
if (this.currentOverlayEditor == null) return;
const target = this.currentOverlayEditor.finish();
if (target == null) return;
const type = this.currentOverlayEditor.getType();
const isCreatingOverlay = this.editorStatus === "creating";
let id = getUID();
if (isCreatingOverlay) {
this.overlayMap[id] = { type, target };
} else {
id = this.selectedIds[0];
}
const evt: any = { id, type };
if (type === OverlayTypes.Circle) {
const circle = target as AMap.Circle;
const { lng, lat } = circle.getCenter();
evt.lngLat = [lng, lat];
evt.radius = circle.getRadius();
} else {
evt.path = getOverlayPaths(target, type);
}
target.setOptions(
type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions
);
this.emit(EventTypes.FinishEditOverlay, evt);
this.editorStatus = null;
}
editSelectedOverlay() {
if (this.selectedIds.length !== 1) return;
const [id] = this.selectedIds;
const { target, type } = this.overlayMap[id];
this.currentOverlayEditor = this.getEditorByType(type);
this.currentOverlayEditor?.edit(target);
this.editorStatus = "editing";
}
}