Browse Source

选中交互

master
Cmen 3 years ago
parent
commit
dbd0684bd1
  1. 17
      src/editor/Catalog/index.tsx
  2. 7
      src/editor/Catalog/style.less
  3. 4
      src/editor/Plot/Tools/index.tsx
  4. 2
      src/editor/Plot/index.tsx
  5. 4
      src/editor/Plot/mapHooks.ts
  6. 4
      src/map/constants.ts
  7. 44
      src/map/index.ts
  8. 23
      src/store/actions.ts
  9. 2
      src/store/index.ts
  10. 3
      src/store/initState.ts
  11. 3
      src/store/reducers/index.ts
  12. 17
      src/store/reducers/map/index.ts
  13. 7
      src/store/type.ts
  14. 13
      src/types/enum.ts

17
src/editor/Catalog/index.tsx

@ -1,10 +1,10 @@
import { Collapse } from "antd";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import { mapStateSelector } from "@store";
import { IOverlay } from "@store";
import { IOverlay, EditorAction, mapStateSelector } from "@store";
import "./style.less";
import classNames from "classnames";
const { Panel } = Collapse;
@ -14,12 +14,21 @@ 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);
return (
<>
{overlays.map((overlay, index) => {
const selected = selectedIds && selectedIds.indexOf(overlay.id) >= 0;
const className = classNames("overlay-item", {
"overlay-item-selected": selected,
});
return (
<div key={index} className="overlay-item">
<div key={index} className={className} onClick={onClick(overlay.id)}>
{overlay.name}
</div>
);

7
src/editor/Catalog/style.less

@ -10,7 +10,10 @@
.overlay-item{
margin-bottom: 4px;
cursor: pointer;
&:hover, &[data-selected]{
background-color: #f7fafc;
&:hover{
background-color: #e5e6e7;
}
}
.overlay-item-selected{
background-color: #e5e6e7;
}

4
src/editor/Plot/Tools/index.tsx

@ -1,7 +1,7 @@
import { Tooltip } from "antd";
import { useDispatch, useSelector } from "react-redux";
import classnames from "classnames";
import { editorAction, OverlayNamePrefixs, mapStateSelector } from "@store";
import { EditorAction, OverlayNamePrefixs, mapStateSelector } from "@store";
import { OverlayTypes } from "@types";
type IconWithTipProps = {
@ -43,7 +43,7 @@ const OverlayTool = (props: OverlayToolProps) => {
const { overlayType } = useSelector(mapStateSelector);
const selected = type === overlayType;
const onClick = () => dispatch(editorAction.createOverlay(type));
const onClick = () => dispatch(EditorAction.createOverlay(type));
return <IconWithTip {...{ text, onClick, type, selected }} />;
};

2
src/editor/Plot/index.tsx

@ -2,7 +2,7 @@ import { Layout } from "antd";
import { useEffect, useRef, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { MapEditor } from "@map";
import { editorAction, IEditorState } from "@store";
import { IEditorState } from "@store";
import Tools from "./Tools";
import { registerMapEventHooks } from "./mapHooks";

4
src/editor/Plot/mapHooks.ts

@ -1,5 +1,5 @@
import { Dispatch } from "react";
import { editorAction, IEditorState } from "@store";
import { EditorAction, IEditorState } from "@store";
import { MapEditor } from "@map";
import { EventTypes } from "../../types/enum";
@ -7,6 +7,6 @@ import { EventTypes } from "../../types/enum";
export function registerMapEventHooks(map: MapEditor, dispatch: Dispatch<any>) {
//
map.on(EventTypes.FinishCreateOverlay, (evt: any) =>
dispatch(editorAction.finishCreateOverlay(evt))
dispatch(EditorAction.finishCreateOverlay(evt))
);
}

4
src/map/constants.ts

@ -26,3 +26,7 @@ export const PolylineOptions: OverlayOptions = {
draggable: false,
bubble: true,
};
export const SelectedOptions: OverlayOptions = {
strokeColor: SelectedStroke,
};

44
src/map/index.ts

@ -13,9 +13,9 @@ import {
} from "./editors";
import { registerHotkey } from "../utils/hotkeys";
import { PolygonOptions, PolylineOptions } from "./constants";
import { PolygonOptions, PolylineOptions, SelectedOptions } from "./constants";
import { EventTypes, OverlayTypes } from "../types/enum";
import { Command, EventTypes, OverlayTypes } from "../types/enum";
let uuid = 0;
const getUuid = () => ++uuid;
@ -26,11 +26,16 @@ type AMapOverlayEditor =
| 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<number, AMap.MapOverlay> = {};
private overlayMap: Record<string, OverlayTemp> = {};
private _currentOverlayEditor:
| BaseOverlayEditor<AMapOverlayEditor>
| undefined;
@ -63,23 +68,40 @@ export class MapEditor extends Emitter {
}
update(mapState: IMapState) {
const { status, overlayType } = mapState;
if (status === "createOverlay") {
this.finishCreateOverlay();
this._currentOverlayEditor = this.overlayEditors.find(
(editor) => editor.getType() === overlayType
);
this._currentOverlayEditor?.create();
const { command } = mapState;
switch (command) {
case Command.CreateOverlay:
this._createOverlay(mapState);
break;
case Command.SelectOverlay:
this._selectOverlays(mapState.selectedIds);
}
}
_createOverlay(mapState: IMapState) {
const { overlayType } = mapState;
this.finishCreateOverlay();
this._currentOverlayEditor = this.overlayEditors.find(
(editor) => editor.getType() === overlayType
);
this._currentOverlayEditor?.create();
}
_selectOverlays(ids?: string[]) {
if (!ids?.length) return;
ids.forEach((id) => {
const { target } = this.overlayMap[id];
target.setOptions(SelectedOptions);
});
}
finishCreateOverlay() {
if (this._currentOverlayEditor == null) return;
const target = this._currentOverlayEditor.finish();
if (target == null) return;
const id = getUuid();
const type = this._currentOverlayEditor.getType();
this.overlayMap[id] = target;
this.overlayMap[id] = { type, target };
const evt: any = { id, type };
if (type === OverlayTypes.Circle) {
const circle = target as AMap.Circle;

23
src/store/actions.ts

@ -4,28 +4,33 @@ export enum ActionTypes {
// AddRect = "addRect",
CreateOverlay = "createOverlay",
FinishCreateOverlay = "finishCreateOverlay",
SelectOverlay = "selectOverlay",
}
export type CreatedOverlay = {
id: string;
type: OverlayTypes;
};
export class EditorAction {
// addRect() {
// return {
// type: ActionTypes.AddRect,
// };
// }
type ActionCreator = (payload: any) => { type: ActionTypes; payload: any };
export const EditorAction: Record<ActionTypes, ActionCreator> = {
createOverlay(type: OverlayTypes) {
return {
type: ActionTypes.CreateOverlay,
payload: type,
};
}
},
finishCreateOverlay(overlay: any) {
return {
type: ActionTypes.FinishCreateOverlay,
payload: overlay as CreatedOverlay,
};
}
}
},
selectOverlay(id: string) {
return {
type: ActionTypes.SelectOverlay,
payload: id,
};
},
};

2
src/store/index.ts

@ -15,7 +15,7 @@ const store: IStore = createStore(reducer);
export { store };
export const editorAction = new EditorAction();
export { EditorAction };
export const StoreContext = createContext<IStore | null>(
null

3
src/store/initState.ts

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

3
src/store/reducers/index.ts

@ -1,6 +1,6 @@
import { initState } from "../initState";
import { ActionTypes } from "../actions";
import { createOverlay, finishCreateOverlay } from "./map";
import { createOverlay, finishCreateOverlay, selectOverlay } from "./map";
import { IEditorState } from "@store";
export type Action = {
@ -13,6 +13,7 @@ type ActionReducer = (state: IEditorState, payload: any) => IEditorState;
const actionReducers: Record<ActionTypes, ActionReducer> = {
[ActionTypes.CreateOverlay]: createOverlay,
[ActionTypes.FinishCreateOverlay]: finishCreateOverlay,
[ActionTypes.SelectOverlay]: selectOverlay,
// addRect: undefined
};

17
src/store/reducers/map/index.ts

@ -1,11 +1,12 @@
import produce from "immer";
import { initState } from "../../initState";
import { IOverlay, OverlayNamePrefixs } from "@store";
import { OverlayTypes } from "@types";
import { OverlayTypes, Status, Command } from "@types";
export function createOverlay(state = initState, payload: any) {
return produce(state, (draft) => {
draft.map.status = "createOverlay";
draft.map.status = Status.CreateOverlay;
draft.map.command = Command.CreateOverlay;
draft.map.overlayType = payload as OverlayTypes;
});
}
@ -16,7 +17,8 @@ export function finishCreateOverlay(state = initState, payload: any) {
const { type } = overlay;
// todo: uniqueName.
overlay.name = OverlayNamePrefixs[type] + overlay.id;
draft.map.status = "";
draft.map.status = null;
draft.map.command = null;
draft.map.overlayType = null;
(type === OverlayTypes.Rectangle
? draft.map.rectangles
@ -28,3 +30,12 @@ export function finishCreateOverlay(state = initState, payload: any) {
).push(overlay);
});
}
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;
});
}

7
src/store/type.ts

@ -1,4 +1,4 @@
import { OverlayTypes } from "@types";
import { OverlayTypes, Status, Command } from "@types";
export interface IOverlay {
id: string;
@ -8,14 +8,15 @@ export interface IOverlay {
paths?: number[][];
radius?: number;
}
export interface IMapState {
status: string;
status: Status | null;
command: Command | null;
overlayType: OverlayTypes | null;
polygons: IOverlay[];
polylines: IOverlay[];
circles: IOverlay[];
rectangles: IOverlay[];
selectedIds?: string[];
}
export interface IEditorState {

13
src/types/enum.ts

@ -8,3 +8,16 @@ export enum OverlayTypes {
Polyline = "polyline",
Circle = "circle",
}
// 操作指令集
export enum Command {
CreateOverlay = "createOveraly",
SelectOverlay = "selectOverlay",
}
// 地图状态.
export enum Status {
CreateOverlay = "createOverlay",
Searching = "searching",
Selecting = "selecing",
}

Loading…
Cancel
Save