diff --git a/package.json b/package.json index ce2f327..478709c 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-dom": "^17.0.2", "react-redux": "^7.2.6", "redux": "^4.1.2", + "redux-thunk": "^2.4.1", "uid": "^2.0.0" }, "devDependencies": { diff --git a/src/editor/Catalog/index.tsx b/src/editor/Catalog/index.tsx index c3f41e4..eb41e53 100644 --- a/src/editor/Catalog/index.tsx +++ b/src/editor/Catalog/index.tsx @@ -1,7 +1,7 @@ import { Collapse } from "antd"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; -import { IOverlay, EditorAction, mapStateSelector } from "@store"; +import { IOverlay, editorAction, mapOptionsSelector } from "@store"; import "./style.less"; import classNames from "classnames"; @@ -14,11 +14,8 @@ export type OverlayListProps = { const OverlayList = (props: OverlayListProps) => { const { overlays } = props; - const dispatch = useDispatch(); - - const onClick = (id: string) => () => - dispatch(EditorAction.selectOverlay(id)); - const { selectedIds } = useSelector(mapStateSelector); + const onClick = (id: string) => () => editorAction.selectOverlay(id); + const { selectedIds } = useSelector(mapOptionsSelector); return ( <> @@ -39,7 +36,7 @@ const OverlayList = (props: OverlayListProps) => { const Catalog = () => { const { rectangles, polygons, polylines, circles } = - useSelector(mapStateSelector); + useSelector(mapOptionsSelector); return ( { @@ -9,27 +9,27 @@ const FileMenu = () => { items: [ { name: "打开GeoJSON", - onClick: globalController.openGeoJSON, + onClick: editorAction.openGeoJSON, hotkey: "Alt+O", }, { name: "打开工程", - onClick: globalController.openProject, + onClick: editorAction.openProject, hotkey: "Ctrl+O", }, { name: "暂存工程", - onClick: globalController.saveTemp, + onClick: editorAction.saveTemp, hotkey: "Alt+S", }, { name: "保存GeoJSON", - onClick: globalController.saveGeoJSON, + onClick: editorAction.saveGeoJSON, hotkey: "Ctrl+S", }, { name: "保存工程", - onClick: globalController.saveProject, + onClick: editorAction.saveProject, hotkey: "Ctrl+Alt+S", }, ], diff --git a/src/editor/Plot/Tools/index.tsx b/src/editor/Plot/Tools/index.tsx index d758df6..2c3e698 100644 --- a/src/editor/Plot/Tools/index.tsx +++ b/src/editor/Plot/Tools/index.tsx @@ -1,8 +1,13 @@ import { Tooltip } from "antd"; import { useSelector } from "react-redux"; import classnames from "classnames"; -import { globalController, OverlayNamePrefixs, mapStateSelector } from "@store"; -import { OverlayTypes } from "@types"; +import { + editorAction, + OverlayNamePrefixs, + statusSelector, + overlayTypeSelector, +} from "@store"; +import { OverlayTypes, Status } from "@types"; type IconWithTipProps = { type: string; @@ -39,10 +44,12 @@ const OverlayTool = (props: OverlayToolProps) => { const { type } = props; const text = OverlayNamePrefixs[type]; - const { overlayType } = useSelector(mapStateSelector); - const selected = type === overlayType; + const overlayType = useSelector(overlayTypeSelector); + const status = useSelector(statusSelector); - const onClick = () => globalController.createOverlay(type); + const selected = status === Status.CreateOverlay && type === overlayType; + + const onClick = () => editorAction.createOverlay(type); return ; }; diff --git a/src/editor/Plot/index.tsx b/src/editor/Plot/index.tsx index c7a5bb0..e8e9195 100644 --- a/src/editor/Plot/index.tsx +++ b/src/editor/Plot/index.tsx @@ -1,22 +1,13 @@ -import { Layout } from "antd"; import { useEffect, useRef, useState } from "react"; -import { useSelector, useDispatch } from "react-redux"; import { MapEditor } from "@map"; -import { IEditorState } from "@store"; +import { IEditorState, editorAction } from "@store"; import Tools from "./Tools"; -import { registerMapEventHooks } from "./mapHooks"; import "./index.less"; -const mapStateSelector = (state: IEditorState) => state.map; - -const { Header, Footer, Sider, Content } = Layout; - const Plot = () => { const mapStageRef = useRef(null); - const mapState = useSelector(mapStateSelector); - const dispatch = useDispatch(); const [mapEditor, setMapEditor] = useState(null); @@ -25,13 +16,9 @@ const Plot = () => { const editor = new MapEditor(mapStageRef.current!); (window as any).mapEditor = editor; setMapEditor(editor); - registerMapEventHooks(editor, dispatch); - editor.init().then(() => { - editor.update(mapState); - }); + editorAction.registerMapEditor(editor); } - }); - mapEditor?.update(mapState); + }, [mapEditor]); return ( <> @@ -44,8 +31,4 @@ const Plot = () => { ); }; -// const mapStateToProps = (state: IEditorState) => { -// return state.map; -// }; - export default Plot; diff --git a/src/map/MapEditor.ts b/src/map/MapEditor.ts new file mode 100644 index 0000000..8ffbae4 --- /dev/null +++ b/src/map/MapEditor.ts @@ -0,0 +1,203 @@ +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; +}; + +export class MapEditor extends Emitter implements IMapEditor { + dom: HTMLDivElement; + private _map: AMap.Map | undefined; + private overlayEditors: BaseOverlayEditor[] = []; + private overlayMap: Record = {}; + private currentOverlayEditor: + | BaseOverlayEditor + | 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), + ]; + } + + getEditorByType(overlayType: OverlayTypes) { + return this.overlayEditors.find( + (editor) => editor.getType() === overlayType + ); + } + + importProject(options: IMapOptions) { + this.clearOverlays(); + const { rectangles, polygons, polylines, circles } = options; + const rectangleEditor = this.getEditorByType(OverlayTypes.Rectangle); + const polygonEditor = this.getEditorByType(OverlayTypes.Polygon); + const polylineEditor = this.getEditorByType(OverlayTypes.Polyline); + const circleEditor = this.getEditorByType(OverlayTypes.Circle); + + const addOverlay = ( + id: string, + target: AMap.MapOverlay, + type: OverlayTypes + ) => { + this.overlayMap[id] = { + type, + target, + }; + this.map.add(target); + }; + + rectangles.forEach((rect) => + addOverlay(rect.id, rectangleEditor!.build(rect), OverlayTypes.Rectangle) + ); + polygons.forEach((polygon) => + addOverlay( + polygon.id, + polygonEditor!.build(polygon), + OverlayTypes.Polygon + ) + ); + polylines.forEach((polyline) => + addOverlay( + polyline.id, + polylineEditor!.build(polyline), + OverlayTypes.Polyline + ) + ); + circles.forEach((circle) => + addOverlay(circle.id, circleEditor!.build(circle), OverlayTypes.Circle) + ); + } + + 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 = {}; + } + + createOverlay(type: OverlayTypes) { + this.currentOverlayEditor = this.getEditorByType(type!); + this.currentOverlayEditor?.create(); + this.editorStatus = "creating"; + } + + selectOverlays(ids?: string[]) { + if (!ids?.length) 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]; + }); + } + + 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"; + } +} diff --git a/src/map/index.ts b/src/map/index.ts index 884aa81..463f9fe 100644 --- a/src/map/index.ts +++ b/src/map/index.ts @@ -1,221 +1,2 @@ -import Emitter from "@finevis/emitter"; -import "@amap/amap-jsapi-types"; - -import { IMapState, IOverlay } from "@store"; -import { getOverlayPaths, getUID } from "@utils"; - -import { - BaseOverlayEditor, - RectangleEditor, - PolygonEditor, - PolylineEditor, - CircleEditor, -} from "./editors"; - -import { registerHotkey } from "../utils/hotkeys"; -import { PolygonOptions, PolylineOptions, SelectedOptions } from "./constants"; - -import { Command, EventTypes, OverlayTypes } from "../types/enum"; - -type AMapOverlayEditor = - | AMap.RectangleEditor - | AMap.PolygonEditor - | AMap.PolylineEditor - | AMap.CircleEditor; - -type OverlayTemp = { - type: OverlayTypes; - target: AMap.MapOverlay; -}; - -export class MapEditor extends Emitter { - dom: HTMLDivElement; - private _map: AMap.Map | undefined; - private overlayEditors: BaseOverlayEditor[] = []; - private overlayMap: Record = {}; - private _currentOverlayEditor: - | BaseOverlayEditor - | 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, - }); - } - - update(mapState: IMapState) { - if (this._editorStatus != null) { - this._finishEditOverlay(); - } - const { command } = mapState; - switch (command) { - case Command.CreateOverlay: - this._createOverlay(mapState); - break; - case Command.SelectOverlay: - this._selectOverlays(mapState.selectedIds); - break; - case Command.DeleteOverlays: - this._deleteOverlays(); - break; - case Command.OpenProject: - this.importOverlays(mapState); - break; - } - } - - initEditors() { - const { map } = this; - this.overlayEditors = [ - new RectangleEditor(map), - new PolygonEditor(map), - new PolylineEditor(map), - new CircleEditor(map), - ]; - } - - getEditorByType(overlayType: OverlayTypes) { - return this.overlayEditors.find( - (editor) => editor.getType() === overlayType - ); - } - - importOverlays(mapState: IMapState) { - this.clearOverlays(); - const { rectangles, polygons, polylines, circles } = mapState; - const rectangleEditor = this.getEditorByType(OverlayTypes.Rectangle); - const polygonEditor = this.getEditorByType(OverlayTypes.Polygon); - const polylineEditor = this.getEditorByType(OverlayTypes.Polyline); - const circleEditor = this.getEditorByType(OverlayTypes.Circle); - - const addOverlay = ( - id: string, - target: AMap.MapOverlay, - type: OverlayTypes - ) => { - this.overlayMap[id] = { - type, - target, - }; - this.map.add(target); - }; - - rectangles.forEach((rect) => - addOverlay(rect.id, rectangleEditor!.build(rect), OverlayTypes.Rectangle) - ); - polygons.forEach((polygon) => - addOverlay( - polygon.id, - polygonEditor!.build(polygon), - OverlayTypes.Polygon - ) - ); - polylines.forEach((polyline) => - addOverlay( - polyline.id, - polylineEditor!.build(polyline), - OverlayTypes.Polyline - ) - ); - circles.forEach((circle) => - addOverlay(circle.id, circleEditor!.build(circle), OverlayTypes.Circle) - ); - } - - // 清空所有覆盖物 - clearOverlays() { - for (let id in this.overlayMap) { - this.map.remove(this.overlayMap[id].target); - } - this.overlayMap = {}; - } - - _createOverlay(mapState: IMapState) { - const { overlayType } = mapState; - this._currentOverlayEditor = this.getEditorByType(overlayType!); - this._currentOverlayEditor?.create(); - this._editorStatus = "creating"; - } - - _selectOverlays(ids?: string[]) { - if (!ids?.length) 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]; - }); - } - - _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"; - } -} +export * from "./MapEditor"; +export * from "./type"; diff --git a/src/map/type.ts b/src/map/type.ts new file mode 100644 index 0000000..7f3e095 --- /dev/null +++ b/src/map/type.ts @@ -0,0 +1,26 @@ +import { EventTypes, OverlayTypes } from "@types"; + +export interface IMapEditor { + on(type: EventTypes, evt: any): void; + init(): Promise; + createOverlay(type: OverlayTypes): void; + importProject(options: IMapOptions): void; + importGeoJSON(geojson: GeoJSON.FeatureCollection): void; + selectOverlays(ids: string[]): void; +} + +export interface IOverlay { + id: string; + name: string; + type: OverlayTypes; + lngLat?: GeoJSON.Position; + path?: GeoJSON.Position[]; + radius?: number; +} +export interface IMapOptions { + polygons: IOverlay[]; + polylines: IOverlay[]; + circles: IOverlay[]; + rectangles: IOverlay[]; + selectedIds?: string[]; +} diff --git a/src/store/actions.ts b/src/store/actions/StoreAction.ts similarity index 68% rename from src/store/actions.ts rename to src/store/actions/StoreAction.ts index cf411e9..a1f30e6 100644 --- a/src/store/actions.ts +++ b/src/store/actions/StoreAction.ts @@ -1,8 +1,7 @@ import { OverlayTypes } from "@types"; -import { IEditorState } from "./type"; - +import { IOverlay } from "@map"; +import { IEditorState } from "../type"; export enum ActionTypes { - // AddRect = "addRect", CreateOverlay = "createOverlay", FinishEditOverlay = "finishEditOverlay", SelectOverlay = "selectOverlay", @@ -10,24 +9,17 @@ export enum ActionTypes { ReplaceState = "replaceState", } -export type CreatedOverlay = { - id: string; - type: OverlayTypes; -}; - -type ActionCreator = (payload?: any) => { type: ActionTypes; payload: any }; - -export const EditorAction: Record = { +export const StoreAction = { createOverlay(type: OverlayTypes) { return { type: ActionTypes.CreateOverlay, payload: type, }; }, - finishEditOverlay(overlay: any) { + finishEditOverlay(overlay: IOverlay) { return { type: ActionTypes.FinishEditOverlay, - payload: overlay as CreatedOverlay, + payload: overlay, }; }, selectOverlay(id: string) { diff --git a/src/store/GlobalController.ts b/src/store/actions/index.ts similarity index 62% rename from src/store/GlobalController.ts rename to src/store/actions/index.ts index bead52f..6609f98 100644 --- a/src/store/GlobalController.ts +++ b/src/store/actions/index.ts @@ -1,61 +1,99 @@ -import { message, Popconfirm, Modal } from "antd"; +import { IMapEditor } from "@map"; +import { Action } from "redux"; +import { Modal } from "antd"; import { registerHotkey, downloadJSON } from "@utils"; -import { IStore, IEditorState } from "./type"; -import { getGeoJSON } from "./utils"; -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; - deleteOverlays: () => void; -} +import { getGeoJSON } from "../utils"; +import { OverlayTypes, EventTypes } from "@types"; +import { IOverlay, IMapOptions } from "@map"; +import { StoreAction } from "./StoreAction"; +import { IStore, IEditorState } from "../type"; +import { initState } from "../initState"; -// 全局控制器, 用以复用一些快捷方法. -export class GlobelController implements IGlobalController { - store: IStore; +export { ActionTypes } from "./StoreAction"; +export class EditorAction { + mapEditor: IMapEditor | null = null; + store: IStore; constructor(store: IStore) { this.store = store; - this._bindOperations(); this._registerHotkeys(); + } + get mapOptions() { + return this.store.getState().map; + } + + dispatch(action: Action) { + this.store.dispatch(action); + } + + registerMapEditor(mapEditor: IMapEditor) { + this.mapEditor = mapEditor; + + this.mapEditor.init().then(() => { + this.mapReady(); + }); + + // 创建覆盖物结束 + this.mapEditor.on(EventTypes.FinishEditOverlay, (overlay: IOverlay) => { + this.dispatch(StoreAction.finishEditOverlay(overlay)); + }); + } + + mapReady() { const cached = sessionStorage.getItem("fine-geojson"); if (cached != null) { setTimeout(() => { - this._replaceState(JSON.parse(cached)); + this._openProject(JSON.parse(cached)); }, 3000); } setInterval(() => { - sessionStorage.setItem( - "fine-geojson", - JSON.stringify(this.store.getState()) - ); + sessionStorage.setItem("fine-geojson", JSON.stringify(this.mapOptions)); console.log("updated!"); }, 10000); } + // ---------- public methods ------------- + createRectangle() { + this.createOverlay(OverlayTypes.Rectangle); + } + createPolygon() { + this.createOverlay(OverlayTypes.Polygon); + } + createPolyline() { + this.createOverlay(OverlayTypes.Polyline); + } + createCircle() { + this.createOverlay(OverlayTypes.Circle); + } - get mapState() { - return this.store.getState().map; + createOverlay(type: OverlayTypes) { + this.mapEditor?.createOverlay(type); + this.dispatch(StoreAction.createOverlay(type)); + } + + deleteOverlays() { + const { selectedIds } = this.mapOptions; + if (selectedIds?.length == 0) return; + Modal.confirm({ + title: "确定删除覆盖物吗?", + onOk: () => { + // this.store.dispatch(EditorAction.deleteOverlays()); + }, + }); } saveGeoJSON() { - const geojson = getGeoJSON(this.mapState); + const geojson = getGeoJSON(this.mapOptions); downloadJSON(geojson, "fine.geojson"); } + selectOverlay(id: string) { + // + } + saveProject() { // } @@ -71,39 +109,19 @@ export class GlobelController implements IGlobalController { openProject() { // } + showCommand() { // } - createRectangle() { - this.createOverlay(OverlayTypes.Rectangle); - } - createPolygon() { - this.createOverlay(OverlayTypes.Polygon); - } - createPolyline() { - this.createOverlay(OverlayTypes.Polyline); - } - createCircle() { - this.createOverlay(OverlayTypes.Circle); - } - - createOverlay(type: OverlayTypes) { - this.store.dispatch(EditorAction.createOverlay(type)); - } - - deleteOverlays() { - const { selectedIds } = this.mapState; - if (selectedIds?.length == 0) return; - Modal.confirm({ - title: "确定删除覆盖物吗?", - onOk: () => { - this.store.dispatch(EditorAction.deleteOverlays()); - }, - }); - } - private _replaceState(state: IEditorState) { - this.store.dispatch(EditorAction.replaceState(state)); + private _openProject(options: IMapOptions) { + this.mapEditor?.importProject(options); + this.dispatch( + StoreAction.replaceState({ + ...initState, + map: options, + }) + ); } private _bindOperations() { diff --git a/src/store/index.ts b/src/store/index.ts index 942f737..fb3005c 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,15 +1,16 @@ -import { createStore } from "redux"; +import { createStore, applyMiddleware } from "redux"; +import thunk from "redux-thunk"; // import { createContext, Context } from "react"; import { reducer } from "./reducers"; import { IStore } from "./type"; import { EditorAction } from "./actions"; -import { GlobelController } from "./GlobalController"; +import { initState } from "./initState"; export * from "./type"; export * from "./selectors"; export * from "./constants"; -export { EditorAction }; +// export { EditorAction }; declare global { interface Window { @@ -17,9 +18,13 @@ declare global { } } -export const store: IStore = createStore(reducer); +export const store: IStore = createStore( + reducer, + initState, + applyMiddleware(thunk) +); -export const globalController = new GlobelController(store); +export const editorAction = new EditorAction(store); window.store = store; diff --git a/src/store/initState.ts b/src/store/initState.ts index 2552d65..dd4383f 100644 --- a/src/store/initState.ts +++ b/src/store/initState.ts @@ -1,10 +1,9 @@ import { IEditorState } from "./type"; export const initState: IEditorState = { + status: null, + overlayType: null, map: { - status: null, - command: null, - overlayType: null, polygons: [], polylines: [], circles: [], diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts index f88ed64..d5ff9e3 100644 --- a/src/store/reducers/index.ts +++ b/src/store/reducers/index.ts @@ -26,9 +26,11 @@ const actionReducers: Record = { }; function replaceState(state = initState, payload: IEditorState) { - return produce(payload, (draft) => { - draft.map.command = Command.OpenProject; - }); + return payload; + // return produce(payload, (draft) => { + // // draft.map.command = Command.OpenProject; + // retr + // }); } export function reducer(state = initState, action: Action) { diff --git a/src/store/reducers/map/index.ts b/src/store/reducers/map/index.ts index fef3464..0461a5e 100644 --- a/src/store/reducers/map/index.ts +++ b/src/store/reducers/map/index.ts @@ -1,13 +1,13 @@ import produce from "immer"; import { initState } from "../../initState"; import { IOverlay, OverlayNamePrefixs } from "@store"; -import { OverlayTypes, Status, Command } from "@types"; +import { OverlayTypes, Status } from "@types"; -export function createOverlay(state = initState, payload: any) { +export function createOverlay(state = initState, payload: OverlayTypes) { return produce(state, (draft) => { - draft.map.status = Status.CreateOverlay; - draft.map.command = Command.CreateOverlay; - draft.map.overlayType = payload as OverlayTypes; + draft.status = Status.CreateOverlay; + draft.overlayType = payload; + console.log(123); }); } @@ -17,7 +17,7 @@ export function deleteOverlays(state = initState, payload: any) { const filterFunc = (overlay: IOverlay) => overlay.id !== id; return produce(state, (draft) => { // draft.map.status = Status.CreateOverlay; - draft.map.command = Command.DeleteOverlays; + // draft.map.command = Command.DeleteOverlays; draft.map.rectangles = draft.map.rectangles.filter(filterFunc); draft.map.polygons = draft.map.polygons.filter(filterFunc); draft.map.polylines = draft.map.polylines.filter(filterFunc); @@ -33,9 +33,6 @@ export function finishEditOverlay(state = initState, payload: any) { const { type, id } = overlay; // todo: uniqueName. overlay.name = OverlayNamePrefixs[type] + overlay.id; - draft.map.status = null; - draft.map.command = null; - draft.map.overlayType = null; const overlays = type === OverlayTypes.Rectangle ? draft.map.rectangles @@ -50,14 +47,14 @@ export function finishEditOverlay(state = initState, payload: any) { } else { overlays.push(overlay); } + draft.overlayType = null; + draft.status = null; }); } export function selectOverlay(state = initState, payload: any) { const id = payload as string; return produce(state, (draft) => { - draft.map.command = Command.SelectOverlay; draft.map.selectedIds = [id]; - draft.map.status = null; }); } diff --git a/src/store/selectors.ts b/src/store/selectors.ts index 5c49f02..4a4cce4 100644 --- a/src/store/selectors.ts +++ b/src/store/selectors.ts @@ -1,3 +1,5 @@ import { IEditorState } from "@store"; -export const mapStateSelector = (state: IEditorState) => state.map; +export const mapOptionsSelector = (state: IEditorState) => state.map; +export const overlayTypeSelector = (state: IEditorState) => state.overlayType; +export const statusSelector = (state: IEditorState) => state.status; diff --git a/src/store/type.ts b/src/store/type.ts index 3540e1b..5d77330 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -1,6 +1,7 @@ import { Store } from "redux"; import { Action } from "./reducers"; import { OverlayTypes, Status, Command } from "@types"; +import { IMapOptions } from "@map"; export type IStore = Store; export interface IOverlay { @@ -23,5 +24,7 @@ export interface IMapState { } export interface IEditorState { - map: IMapState; + map: IMapOptions; + status: Status | null; + overlayType: OverlayTypes | null; } diff --git a/src/store/utils/getGeoJSON.ts b/src/store/utils/getGeoJSON.ts index 1a70bff..36c4597 100644 --- a/src/store/utils/getGeoJSON.ts +++ b/src/store/utils/getGeoJSON.ts @@ -1,9 +1,9 @@ import { OverlayTypes } from "../../types/enum"; -import { IMapState } from "../type"; +import { IMapOptions } from "@map"; const EarthRadius = 6378137; -export function getGeoJSON(state: IMapState): GeoJSON.FeatureCollection { +export function getGeoJSON(state: IMapOptions): GeoJSON.FeatureCollection { // const features: GeoJSON.Feature[] = []; const { rectangles, polygons, polylines, circles } = state; diff --git a/yarn.lock b/yarn.lock index ee22f37..a1abbb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4016,6 +4016,11 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" +redux-thunk@^2.4.1: + version "2.4.1" + resolved "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714" + integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== + redux@^4.0.0, redux@^4.1.2: version "4.1.2" resolved "https://registry.npmmirror.com/redux/download/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104"