diff --git a/package.json b/package.json index 772367f..c1e6caa 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "@amap/amap-jsapi-types": "^0.0.8", + "@types/geojson": "^7946.0.8", "@types/react": "^17.0.33", "@types/react-dom": "^17.0.10", "@vitejs/plugin-react": "^1.0.7", diff --git a/src/store/GlobalController.ts b/src/store/GlobalController.ts new file mode 100644 index 0000000..134ea70 --- /dev/null +++ b/src/store/GlobalController.ts @@ -0,0 +1,110 @@ +import { IStore } from "./type"; +import { registerHotkey } from "@utils"; +import { getGeoJSON } from "./utils/getGeoJSON"; +import { OverlayTypes } from "../types/enum"; +import { EditorAction } from "./actions"; +interface IGlobalController { + saveGeoJSON: () => void; + saveProject: () => void; + saveTemp: () => void; + clearEditor: () => void; + openGeoJSON: () => void; + openProject: () => void; + showCommand: () => void; + createRectangle: () => void; + createPolygon: () => void; + createPolyline: () => void; + createCircle: () => void; +} + +// 全局控制器, 用以复用一些快捷方法. +export class GlobelController implements IGlobalController { + _store: IStore; + constructor(store: IStore) { + this._store = store; + + this._bindOperations(); + this._registerHotkeys(); + } + + get mapState() { + return this._store.getState().map; + } + + saveGeoJSON() { + const geojson = getGeoJSON(this.mapState); + console.log(geojson); + } + + saveProject() { + // + } + saveTemp() { + // + } + clearEditor() { + // + } + openGeoJSON() { + // + } + openProject() { + // + } + showCommand() { + // + } + createRectangle() { + this._createOverlay(OverlayTypes.Rectangle); + } + createPolygon() { + this._createOverlay(OverlayTypes.Polygon); + } + createPolyline() { + this._createOverlay(OverlayTypes.Polyline); + } + createCircle() { + this._createOverlay(OverlayTypes.Circle); + } + + private _createOverlay(type: OverlayTypes) { + this._store.dispatch(EditorAction.createOverlay(type)); + } + + private _bindOperations() { + this.saveGeoJSON = this.saveGeoJSON.bind(this); + this.createRectangle = this.createRectangle.bind(this); + this.createPolygon = this.createPolygon.bind(this); + this.createPolyline = this.createPolyline.bind(this); + this.createCircle = this.createCircle.bind(this); + } + + private _registerHotkeys() { + registerHotkey("s", { callback: this.saveGeoJSON, ctrl: true }); + registerHotkey("s", { + callback: this.saveProject, + ctrl: true, + alt: true, + }); + registerHotkey("s", { callback: this.saveTemp, alt: true }); + registerHotkey("c", { callback: this.clearEditor, alt: true }); + registerHotkey("o", { callback: this.openGeoJSON, alt: true }); + registerHotkey("o", { + callback: this.openProject, + alt: true, + ctrl: true, + }); + registerHotkey("p", { callback: this.showCommand, alt: true }); + registerHotkey("1", { + callback: this.createRectangle, + alt: true, + }); + registerHotkey("2", { callback: this.createPolygon, alt: true }); + registerHotkey("3", { + callback: this.createPolyline, + alt: true, + }); + registerHotkey("4", { callback: this.createCircle, alt: true }); + // registerHotkey("5", { callback: () => {}, alt: true }); + } +} diff --git a/src/store/index.ts b/src/store/index.ts index 98f58b8..942f737 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,22 +1,28 @@ -import { createStore, Store } from "redux"; -import { createContext, Context } from "react"; -import { reducer, Action } from "./reducers"; -import { IEditorState } from "./type"; +import { createStore } from "redux"; +// import { createContext, Context } from "react"; +import { reducer } from "./reducers"; +import { IStore } from "./type"; import { EditorAction } from "./actions"; +import { GlobelController } from "./GlobalController"; export * from "./type"; export * from "./selectors"; export * from "./constants"; -type IStore = Store; -const store: IStore = createStore(reducer); +export { EditorAction }; -(window as any).store = store; +declare global { + interface Window { + store: IStore; + } +} -export { store }; +export const store: IStore = createStore(reducer); -export { EditorAction }; +export const globalController = new GlobelController(store); + +window.store = store; -export const StoreContext = createContext( - null -) as Context; +// export const StoreContext = createContext( +// null +// ) as Context; diff --git a/src/store/type.ts b/src/store/type.ts index fe4dbca..3540e1b 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -1,11 +1,14 @@ +import { Store } from "redux"; +import { Action } from "./reducers"; import { OverlayTypes, Status, Command } from "@types"; +export type IStore = Store; export interface IOverlay { id: string; name: string; type: OverlayTypes; - lngLat?: number[]; - paths?: number[][]; + lngLat?: GeoJSON.Position; + path?: GeoJSON.Position[]; radius?: number; } export interface IMapState { diff --git a/src/store/utils/getGeoJSON.ts b/src/store/utils/getGeoJSON.ts new file mode 100644 index 0000000..5740958 --- /dev/null +++ b/src/store/utils/getGeoJSON.ts @@ -0,0 +1,25 @@ +import { IMapState } from "../type"; + +export function getGeoJSON(state: IMapState): GeoJSON.FeatureCollection { + // + const features: GeoJSON.Feature[] = []; + const { rectangles, polygons, polylines, circles } = state; + + rectangles.forEach((rect) => { + const path = rect.path!; + + features.push({ + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [[path]], + }, + properties: {}, + }); + }); + + return { + type: "FeatureCollection", + features, + }; +} diff --git a/src/types/amap.d.ts b/src/types/amap.d.ts new file mode 100644 index 0000000..8d9730e --- /dev/null +++ b/src/types/amap.d.ts @@ -0,0 +1,36 @@ +import "@amap/amap-jsapi-types"; +declare global { + namespace AMapLoader { + const load: (config: any) => Promise; + } + namespace AMap { + interface IBaseEditor { + // new (map: AMap.Map): any; + } + type MapOverlay = + | AMap.Rectangle + | AMap.Polygon + | AMap.Polyline + | AMap.Circle; + class BaseEditor implements IBaseEditor { + constructor(map: AMap.Map); + setTarget(target: any): void; + getTarget(): MapOverlay; + open(): void; + close(): void; + destroy(): void; + } + class PolygonEditor extends BaseEditor { + // + } + class RectangleEditor extends BaseEditor { + // + } + class PolylineEditor extends BaseEditor { + // + } + class CircleEditor extends BaseEditor { + // + } + } +} diff --git a/src/types/index.ts b/src/types/index.ts index 33d7790..cf91f83 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,36 +1 @@ -declare global { - namespace AMapLoader { - const load: (config: any) => Promise; - } - namespace AMap { - interface IBaseEditor { - // new (map: AMap.Map): any; - } - type MapOverlay = - | AMap.Rectangle - | AMap.Polygon - | AMap.Polyline - | AMap.Circle; - class BaseEditor implements IBaseEditor { - constructor(map: AMap.Map); - setTarget(target: any): void; - getTarget(): MapOverlay; - open(): void; - close(): void; - destroy(): void; - } - class PolygonEditor extends BaseEditor { - // - } - class RectangleEditor extends BaseEditor { - // - } - class PolylineEditor extends BaseEditor { - // - } - class CircleEditor extends BaseEditor { - // - } - } -} export * from "./enum"; diff --git a/yarn.lock b/yarn.lock index faf6c8f..b5afd59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1361,6 +1361,11 @@ resolved "https://registry.npmmirror.com/@rushstack/eslint-patch/download/@rushstack/eslint-patch-1.1.0.tgz#7f698254aadf921e48dda8c0a6b304026b8a9323" integrity sha1-f2mCVKrfkh5I3ajAprMEAmuKkyM= +"@types/geojson@^7946.0.8": + version "7946.0.8" + resolved "https://registry.npmmirror.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" + integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== + "@types/hoist-non-react-statics@^3.3.0": version "3.3.1" resolved "https://registry.npmmirror.com/@types/hoist-non-react-statics/download/@types/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"