Browse Source

重构editorAction

master
Cmen 3 years ago
parent
commit
5b91a604ef
  1. 1
      package.json
  2. 13
      src/editor/Catalog/index.tsx
  3. 12
      src/editor/Menu/File.tsx
  4. 17
      src/editor/Plot/Tools/index.tsx
  5. 23
      src/editor/Plot/index.tsx
  6. 203
      src/map/MapEditor.ts
  7. 223
      src/map/index.ts
  8. 26
      src/map/type.ts
  9. 18
      src/store/actions/StoreAction.ts
  10. 142
      src/store/actions/index.ts
  11. 15
      src/store/index.ts
  12. 3
      src/store/initState.ts
  13. 8
      src/store/reducers/index.ts
  14. 19
      src/store/reducers/map/index.ts
  15. 4
      src/store/selectors.ts
  16. 5
      src/store/type.ts
  17. 4
      src/store/utils/getGeoJSON.ts
  18. 5
      yarn.lock

1
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": {

13
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 (
<Collapse
defaultActiveKey={["1", "2", "3", "4"]}

12
src/editor/Menu/File.tsx

@ -1,4 +1,4 @@
import { globalController } from "@store";
import { editorAction } from "@store";
import MenuGroup from "./MenuGroup";
const FileMenu = () => {
@ -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",
},
],

17
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 <IconWithTip {...{ text, onClick, type, selected }} />;
};

23
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<HTMLDivElement>(null);
const mapState = useSelector(mapStateSelector);
const dispatch = useDispatch();
const [mapEditor, setMapEditor] = useState<MapEditor | null>(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;

203
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<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),
];
}
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";
}
}

223
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<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,
});
}
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";

26
src/map/type.ts

@ -0,0 +1,26 @@
import { EventTypes, OverlayTypes } from "@types";
export interface IMapEditor {
on(type: EventTypes, evt: any): void;
init(): Promise<void>;
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[];
}

18
src/store/actions.ts → 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<ActionTypes, ActionCreator> = {
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) {

142
src/store/GlobalController.ts → 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;
}
// 全局控制器, 用以复用一些快捷方法.
export class GlobelController implements IGlobalController {
store: IStore;
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 { 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() {

15
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;

3
src/store/initState.ts

@ -1,10 +1,9 @@
import { IEditorState } from "./type";
export const initState: IEditorState = {
map: {
status: null,
command: null,
overlayType: null,
map: {
polygons: [],
polylines: [],
circles: [],

8
src/store/reducers/index.ts

@ -26,9 +26,11 @@ const actionReducers: Record<ActionTypes, ActionReducer> = {
};
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) {

19
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;
});
}

4
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;

5
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<IEditorState, Action>;
export interface IOverlay {
@ -23,5 +24,7 @@ export interface IMapState {
}
export interface IEditorState {
map: IMapState;
map: IMapOptions;
status: Status | null;
overlayType: OverlayTypes | null;
}

4
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;

5
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"

Loading…
Cancel
Save