diff --git a/package.json b/package.json
index 52f504e..a68ff34 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"devDependencies": {
"@amap/amap-jsapi-types": "^0.0.8",
"@types/geojson": "^7946.0.8",
+ "@types/lodash": "^4.14.179",
"@types/react": "^17.0.33",
"@types/react-dom": "^17.0.10",
"@vitejs/plugin-react": "^1.0.7",
diff --git a/src/editor/Plot/Tools/SearchModal.tsx b/src/editor/Plot/Tools/SearchModal.tsx
new file mode 100644
index 0000000..85a6e4c
--- /dev/null
+++ b/src/editor/Plot/Tools/SearchModal.tsx
@@ -0,0 +1,41 @@
+import { Modal, Input } from "antd";
+import { debounce } from "lodash";
+import { useState } from "react";
+import { editorAction, searchResultsSelector } from "@store";
+import { useSelector } from "react-redux";
+
+export type SearchModalProps = {
+ visible: boolean;
+ onCancel: () => void;
+};
+
+const delaySearch = debounce((keyword: string) => {
+ editorAction.searchPlace(keyword);
+}, 500);
+
+export const SearchModal = (props: SearchModalProps) => {
+ const { visible, onCancel } = props;
+ const [keyword, setKeyword] = useState("");
+ const searchResults = useSelector(searchResultsSelector);
+ const searchPlace = (keyword: string) => {
+ setKeyword(keyword);
+ delaySearch(keyword);
+ };
+
+ return (
+
+ searchPlace(e.target.value)}
+ />
+
+ {searchResults.map((item) => (
+
+ {item.name}
+
+ ))}
+
+
+ );
+};
diff --git a/src/editor/Plot/Tools/index.tsx b/src/editor/Plot/Tools/index.tsx
index 76f5d72..7721ca2 100644
--- a/src/editor/Plot/Tools/index.tsx
+++ b/src/editor/Plot/Tools/index.tsx
@@ -8,6 +8,8 @@ import {
overlayTypeSelector,
} from "@store";
import { OverlayTypes, Status } from "@types";
+import { SearchModal } from "./SearchModal";
+import { useState } from "react";
type IconWithTipProps = {
type: string;
@@ -55,6 +57,8 @@ const OverlayTool = (props: OverlayToolProps) => {
};
const Tools = () => {
+ const [searchModalVisible, setSearchModalVisible] = useState(false);
+
return (
<>
@@ -65,12 +69,21 @@ const Tools = () => {
-
+ setSearchModalVisible(true)}
+ />
{/*
*/}
+ setSearchModalVisible(false)}
+ />
>
);
};
diff --git a/src/map/MapEditor.ts b/src/map/MapEditor.ts
index 3a52160..7aaa434 100644
--- a/src/map/MapEditor.ts
+++ b/src/map/MapEditor.ts
@@ -41,6 +41,8 @@ export class MapEditor extends Emitter implements IMapEditor {
| undefined;
private selectedIds: string[] = [];
private editorStatus: "editing" | "creating" | null = null;
+ private autoComplete: AMap.AutoComplete | undefined;
+ private placeSearch: AMap.PlaceSearch | undefined;
constructor(dom: HTMLDivElement) {
super();
this.dom = dom;
@@ -64,6 +66,8 @@ export class MapEditor extends Emitter implements IMapEditor {
],
});
this._map = new AMap.Map(this.dom);
+ this.autoComplete = new AMap.AutoComplete({});
+ this.placeSearch = new AMap.PlaceSearch(this._map);
this.initEditors();
// Space的key是空字符串, 这就离谱.
registerHotkey(" ", { callback: this.finishEditOverlay.bind(this) });
@@ -217,6 +221,18 @@ export class MapEditor extends Emitter implements IMapEditor {
return id;
}
+ searchPlace(keyword: string) {
+ return new Promise((resolve: (items: AMap.SearchResultItem[]) => void) => {
+ this.autoComplete?.search(keyword, (status, result) => {
+ if (status !== "complete") {
+ resolve([]);
+ } else {
+ resolve(result.tips);
+ }
+ });
+ });
+ }
+
_buildFromOverlay(overlay: IOverlay) {
const { type, id } = overlay;
const editor = this.overlayEditors.find(
diff --git a/src/map/type.ts b/src/map/type.ts
index 67ac1f5..37e970b 100644
--- a/src/map/type.ts
+++ b/src/map/type.ts
@@ -13,6 +13,7 @@ export interface IMapEditor {
getCenter(): GeoJSON.Position;
getZoom(): number;
updateOverlayBackground(id: string, src?: string): void;
+ searchPlace(keyword: string): Promise;
}
export enum OverlayCategory {
diff --git a/src/store/actions/StoreAction.ts b/src/store/actions/StoreAction.ts
index ad5a6ed..7b12610 100644
--- a/src/store/actions/StoreAction.ts
+++ b/src/store/actions/StoreAction.ts
@@ -9,6 +9,7 @@ export enum ActionTypes {
ReplaceState = "replaceState",
ClearOverlays = "clearOverlays",
UpdateOverlayProps = "updateOverlayProps",
+ SearchPlace = "searchPlace",
}
type ActionCreator = (payload?: any) => {
@@ -58,4 +59,10 @@ export const StoreAction: Record = {
payload,
};
},
+ searchPlace(payload: AMap.SearchResultItem[]) {
+ return {
+ type: ActionTypes.SearchPlace,
+ payload,
+ };
+ },
};
diff --git a/src/store/actions/index.ts b/src/store/actions/index.ts
index 53d9912..5b5790c 100644
--- a/src/store/actions/index.ts
+++ b/src/store/actions/index.ts
@@ -163,6 +163,11 @@ export class EditorAction {
//
}
+ async searchPlace(keyword: string) {
+ const results = await this.mapEditor!.searchPlace(keyword);
+ this.dispatch(StoreAction.searchPlace(results));
+ }
+
private _openGeoJSON(geojson: GeoJSON.FeatureCollection) {
console.log(geojson);
}
diff --git a/src/store/initState.ts b/src/store/initState.ts
index f83cf34..c65b7eb 100644
--- a/src/store/initState.ts
+++ b/src/store/initState.ts
@@ -7,4 +7,5 @@ export const initState: IEditorState = {
map: {
overlays: [],
},
+ searchResults: [],
};
diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts
index 091fdfc..5e6d2c7 100644
--- a/src/store/reducers/index.ts
+++ b/src/store/reducers/index.ts
@@ -26,8 +26,15 @@ const actionReducers: Record = {
[ActionTypes.ReplaceState]: replaceState,
[ActionTypes.ClearOverlays]: clearOverlays,
[ActionTypes.UpdateOverlayProps]: updateOverlayProps,
+ [ActionTypes.SearchPlace]: searchPlace,
};
+function searchPlace(state = initState, payload: AMap.SearchResultItem[]) {
+ return produce(state, (draft) => {
+ draft.searchResults = payload;
+ });
+}
+
function updateOverlayProps(state = initState, payload: Partial) {
return produce(state, (draft) => {
const { id, ...rest } = payload;
diff --git a/src/store/selectors.ts b/src/store/selectors.ts
index e764c82..64c5fad 100644
--- a/src/store/selectors.ts
+++ b/src/store/selectors.ts
@@ -4,3 +4,5 @@ export const mapOptionsSelector = (state: IEditorState) => state.map;
export const overlayTypeSelector = (state: IEditorState) => state.overlayType;
export const statusSelector = (state: IEditorState) => state.status;
export const selectedIdsSelector = (state: IEditorState) => state.selectedIds;
+export const searchResultsSelector = (state: IEditorState) =>
+ state.searchResults;
diff --git a/src/store/type.ts b/src/store/type.ts
index 93e2360..d8d8dfb 100644
--- a/src/store/type.ts
+++ b/src/store/type.ts
@@ -10,4 +10,5 @@ export interface IEditorState {
status: Status | null;
selectedIds: string[];
overlayType: OverlayTypes | null;
+ searchResults: AMap.SearchResultItem[];
}
diff --git a/src/types/amap.d.ts b/src/types/amap.d.ts
index 8d9730e..79520aa 100644
--- a/src/types/amap.d.ts
+++ b/src/types/amap.d.ts
@@ -32,5 +32,24 @@ declare global {
class CircleEditor extends BaseEditor {
//
}
+ class PlaceSearch {
+ constructor(map: AMap.Map);
+ setCity(code: string): void;
+ search(name: string): void;
+ }
+
+ type SearchResultItem = {
+ name: string;
+ adcode: string;
+ };
+
+ type AutoCompleteCallback = (
+ status: string,
+ result: { tips: SearchResultItem[] }
+ ) => void;
+ class AutoComplete {
+ constructor(options: any);
+ search(name: string, callback: AutoCompleteCallback): void;
+ }
}
}
diff --git a/yarn.lock b/yarn.lock
index 57e4fc5..dbd24db 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2526,6 +2526,11 @@
resolved "https://registry.nlark.com/@types/json5/download/@types/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
+"@types/lodash@^4.14.179":
+ version "4.14.179"
+ resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5"
+ integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==
+
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.npmmirror.com/@types/parse-json/download/@types/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@@ -4447,7 +4452,7 @@ lodash.merge@^4.6.2:
lodash@^4.17.21:
version "4.17.21"
- resolved "https://registry.npmmirror.com/lodash/download/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-update@^4.0.0: