diff --git a/src/editor/Property/OverlayBackground.tsx b/src/editor/Property/OverlayBackground.tsx
new file mode 100644
index 0000000..1769023
--- /dev/null
+++ b/src/editor/Property/OverlayBackground.tsx
@@ -0,0 +1,43 @@
+import { CSSProperties } from "react";
+import { Upload } from "antd";
+import { IOverlay } from "@map";
+import { editorAction } from "@store";
+
+export type OverlayBackgroundProps = {
+ overlay: IOverlay;
+};
+
+export const OverlayBackground = (props: OverlayBackgroundProps) => {
+ const { overlay } = props;
+ const { id, backgroundImage } = overlay;
+
+ const beforeUpload = (file: File) => {
+ const reader = new FileReader();
+ reader.onload = () => {
+ editorAction.updateOverlay({
+ id,
+ backgroundImage: reader.result as string,
+ });
+ };
+ reader.readAsDataURL(file);
+ return false;
+ };
+
+ const style: CSSProperties = {};
+ if (backgroundImage) {
+ style.backgroundImage = `url(${backgroundImage})`;
+ }
+
+ return (
+
+
+ 上传
+
+
+ );
+};
diff --git a/src/editor/Property/index.less b/src/editor/Property/index.less
index 0789f7b..f72d49d 100644
--- a/src/editor/Property/index.less
+++ b/src/editor/Property/index.less
@@ -1,3 +1,22 @@
.property-area{
padding: 8px;
+}
+.overlay-background{
+ background-size: cover;
+}
+.overlay-background-upload{
+ display: inline-block;
+ width: 100%;
+ height: 120px;
+ line-height: 120px;
+ text-align: center;
+ vertical-align: middle;
+ background-color: rgba(0, 0, 0, .2);
+ border: 1px dashed #d9d9d9;
+ border-radius: 2px;
+ cursor: pointer;
+ transition: border-color .3s;
+}
+.ant-form-item .ant-upload{
+ color: #fff;
}
\ No newline at end of file
diff --git a/src/editor/Property/index.tsx b/src/editor/Property/index.tsx
index 7540a4f..f7ae30a 100644
--- a/src/editor/Property/index.tsx
+++ b/src/editor/Property/index.tsx
@@ -1,11 +1,12 @@
-import { useDispatch, useSelector } from "react-redux";
-import { Form, Input, Select } from "antd";
-import { selectedIdsSelector, mapOptionsSelector, StoreAction } from "@store";
+import { useSelector } from "react-redux";
+import { Form, Select } from "antd";
+import { selectedIdsSelector, mapOptionsSelector, editorAction } from "@store";
import { OverlayCategory, IOverlay } from "@map";
import { OverlayTypes } from "@types";
import { FineInput } from "./FineInput";
+import { OverlayBackground } from "./OverlayBackground";
import "./index.less";
@@ -19,14 +20,12 @@ const { Option } = Select;
const Property = () => {
const selectedIds = useSelector(selectedIdsSelector);
const { overlays } = useSelector(mapOptionsSelector);
- const dispatch = useDispatch();
if (!selectedIds?.length) return <>>;
const [id] = selectedIds;
const overlay = overlays.find((overlay) => overlay.id === id)!;
- const updateOverlayProps = (props: Partial) => {
- dispatch(StoreAction.updateOverlayProps(props));
- };
+ const updateOverlayProps = (props: Partial) =>
+ editorAction.updateOverlay(props);
const categorys: CategoryItem[] = [];
if (overlay.type === OverlayTypes.Polyline) {
@@ -83,6 +82,11 @@ const Property = () => {
/>
) : null}
+ {overlay.type === OverlayTypes.Rectangle ? (
+
+
+
+ ) : null}
);
diff --git a/src/map/MapEditor.ts b/src/map/MapEditor.ts
index 5bd40e6..22be735 100644
--- a/src/map/MapEditor.ts
+++ b/src/map/MapEditor.ts
@@ -11,7 +11,7 @@ import {
CircleEditor,
} from "./editors";
-import { IMapOptions, IMapEditor } from "./type";
+import { IMapOptions, IMapEditor, IOverlay } from "./type";
import { PolygonOptions, PolylineOptions, SelectedOptions } from "./constants";
@@ -35,6 +35,7 @@ export class MapEditor extends Emitter implements IMapEditor {
private _map: AMap.Map | undefined;
private overlayEditors: BaseOverlayEditor[] = [];
private overlayMap: Record = {};
+ private imageLayerMap: Record = {};
private currentOverlayEditor:
| BaseOverlayEditor
| undefined;
@@ -122,14 +123,14 @@ export class MapEditor extends Emitter implements IMapEditor {
overlays.forEach((overlay) => {
const { type, id } = overlay;
const target = overlayEditors[type].build(overlay);
- this.overlayMap[id] = {
- type,
- target,
- };
+ this._addOverlay(id, { type, target });
target.setOptions(
type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions
);
this.map.add(target);
+ if (overlay.backgroundImage) {
+ this.updateOverlayBackground(id, overlay.backgroundImage);
+ }
});
}
@@ -146,6 +147,28 @@ export class MapEditor extends Emitter implements IMapEditor {
this.selectedIds = [];
}
+ updateOverlayBackground(id: string, src?: string) {
+ if (this.overlayMap[id] == null) return;
+ const overlay = this.overlayMap[id];
+ // 只支持矩形
+ if (overlay.type !== OverlayTypes.Rectangle) return;
+ const rect = overlay.target as AMap.Rectangle;
+ const rectBounds = rect.getBounds()!;
+
+ if (this.imageLayerMap[id] == null && src) {
+ const { southWest, northEast } = rectBounds;
+ this.imageLayerMap[id] = new AMap.ImageLayer({
+ url: src,
+ // 居然不一样.....
+ bounds: [southWest.lng, southWest.lat, northEast.lng, northEast.lat],
+ zIndex: 0,
+ });
+ this.map.add(this.imageLayerMap[id]);
+ }
+ this.imageLayerMap[id]?.setBounds(rectBounds);
+ src && this.imageLayerMap[id]?.setImageUrl(src);
+ }
+
createOverlay(type: OverlayTypes) {
this.currentOverlayEditor = this.getEditorByType(type!);
this.currentOverlayEditor?.create();
@@ -171,6 +194,10 @@ export class MapEditor extends Emitter implements IMapEditor {
const { target } = this.overlayMap[id];
this.map.remove(target);
delete this.overlayMap[id];
+ if (this.imageLayerMap[id]) {
+ this.map.remove(this.imageLayerMap[id]);
+ delete this.imageLayerMap[id];
+ }
});
this.selectedIds = [];
}
@@ -183,10 +210,20 @@ export class MapEditor extends Emitter implements IMapEditor {
const isCreatingOverlay = this.editorStatus === "creating";
let id = getUID();
if (isCreatingOverlay) {
- this.overlayMap[id] = { type, target };
+ this._addOverlay(id, { type, target });
} else {
id = this.selectedIds[0];
}
+ this._updateOverlay(id);
+ target.setOptions(
+ type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions
+ );
+ this.editorStatus = null;
+ }
+
+ _updateOverlay(id: string) {
+ if (this.overlayMap[id] == null) return;
+ const { type, target } = this.overlayMap[id];
const evt: any = { id, type };
if (type === OverlayTypes.Circle) {
const circle = target as AMap.Circle;
@@ -196,11 +233,8 @@ export class MapEditor extends Emitter implements IMapEditor {
} else {
evt.path = getOverlayPaths(target, type);
}
- target.setOptions(
- type === OverlayTypes.Polyline ? PolylineOptions : PolygonOptions
- );
this.emit(EventTypes.FinishEditOverlay, evt);
- this.editorStatus = null;
+ this.updateOverlayBackground(id);
}
editSelectedOverlay() {
@@ -211,4 +245,13 @@ export class MapEditor extends Emitter implements IMapEditor {
this.currentOverlayEditor?.edit(target);
this.editorStatus = "editing";
}
+
+ onOverlayDragEnd(id: string) {
+ this._updateOverlay(id);
+ }
+
+ _addOverlay(id: string, overlay: OverlayTemp) {
+ this.overlayMap[id] = overlay;
+ overlay.target.on("dragend", () => this.onOverlayDragEnd(id));
+ }
}
diff --git a/src/map/type.ts b/src/map/type.ts
index 7d55525..0e85f9c 100644
--- a/src/map/type.ts
+++ b/src/map/type.ts
@@ -11,6 +11,7 @@ export interface IMapEditor {
clearOverlays(): void;
getCenter(): GeoJSON.Position;
getZoom(): number;
+ updateOverlayBackground(id: string, src?: string): void;
}
export enum OverlayCategory {
diff --git a/src/store/actions/index.ts b/src/store/actions/index.ts
index f2f8cc4..18d4e4f 100644
--- a/src/store/actions/index.ts
+++ b/src/store/actions/index.ts
@@ -94,6 +94,13 @@ export class EditorAction {
}
}
+ updateOverlay(props: Partial) {
+ this.dispatch(StoreAction.updateOverlayProps(props));
+ if (props.backgroundImage && props.id) {
+ this.mapEditor?.updateOverlayBackground(props.id, props.backgroundImage);
+ }
+ }
+
saveGeoJSON() {
const geojson = getGeoJSON(this.mapOptions);
downloadJSON(geojson, "fine.geojson");
diff --git a/src/store/reducers/map/index.ts b/src/store/reducers/map/index.ts
index ee00246..2b08e67 100644
--- a/src/store/reducers/map/index.ts
+++ b/src/store/reducers/map/index.ts
@@ -35,7 +35,10 @@ export function finishEditOverlay(state = initState, payload: any) {
const { overlays } = draft.map;
const existed = overlays.find((overlay) => overlay.id === id);
if (existed) {
- overlays[overlays.indexOf(existed)] = overlay;
+ overlays[overlays.indexOf(existed)] = {
+ ...existed,
+ ...overlay,
+ };
} else {
overlays.push(overlay);
}