基于高德地图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
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"; |
|
} |
|
}
|
|
|