React H5中,高德地图API实战使用封装
一、定义封装hook useDrawTraceMap
:绘制轨迹地图,包括起点、终点、行车轨迹
import { useCallback, useEffect, useRef } from "react";
import AMapLoader from "@amap/amap-jsapi-loader";
import { nanoid } from "nanoid";
export interface LatLng {
lat: number | string;
lng: number | string;
}
export interface DrawTraceMapProps {
track?: LatLng[] | null;
startPoint?: LatLng | null;
endPoint?: LatLng | null;
}
interface UseDrawTraceMapProps {
key: string;
version?: string;
}
const useDrawTraceMap = (props?: UseDrawTraceMapProps) => {
const DEFAULT_AMAP_KEY = "your_amap_key";
const mapInstanceRef = useRef<any>(null);
const containerIdRef = useRef<string>(nanoid());
const drawTraceMap = useCallback(
async (drawProps: DrawTraceMapProps) => {
const { track = null, startPoint = null, endPoint = null } = drawProps;
if (!(startPoint || endPoint)) return;
await AMapLoader.load({
key: props?.key || DEFAULT_AMAP_KEY,
version: props?.version || "1.4.15",
plugins: ["AMap.Autocomplete"],
AMapUI: {
version: "1.1",
plugins: ["overlay/SimpleMarker"],
},
Loca: {
version: "1.3.2",
},
})
.then((AMap) => {
let startMarker = null;
let endMarker = null;
const startX = startPoint?.lng?.toString() || "";
const startY = startPoint?.lat?.toString() || "";
const endX = endPoint?.lng?.toString() || "";
const endY = endPoint?.lat?.toString() || "";
if (startPoint) {
const startIcon = new AMap.Icon({
size: new AMap.Size(25, 34),
image:
"//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png",
imageSize: new AMap.Size(135, 40),
imageOffset: new AMap.Pixel(-9, -3),
});
startMarker = new AMap.Marker({
position: new AMap.LngLat(
parseFloat(String(startX)),
parseFloat(String(startY))
),
icon: startIcon,
offset: new AMap.Pixel(-13, -30),
});
}
if (endPoint) {
const endIcon = new AMap.Icon({
size: new AMap.Size(25, 34),
image:
"//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png",
imageSize: new AMap.Size(135, 40),
imageOffset: new AMap.Pixel(-95, -3),
});
endMarker = new AMap.Marker({
position: new AMap.LngLat(
parseFloat(String(endX)),
parseFloat(String(endY))
),
icon: endIcon,
offset: new AMap.Pixel(-13, -30),
});
}
let center: number[] = [
parseFloat(String(startX)),
parseFloat(String(startY)),
];
if (!startPoint) {
center = [parseFloat(String(endX)), parseFloat(String(endY))];
}
mapInstanceRef.current = new AMap.Map(containerIdRef.current, {
center: center,
zoom: 12,
resizeEnable: true,
mapStyle: "amap://styles/macaron",
});
const addPoints = [startMarker, endMarker].filter((item) => !!item);
mapInstanceRef.current?.add(addPoints);
if (
startPoint &&
endPoint &&
Array.isArray(track) &&
!!track?.length
) {
const path = track?.map((item) => {
return [item.lng, item.lat];
});
new AMap.Polyline({
map: mapInstanceRef.current,
path,
showDir: true,
strokeColor: "#28F",
strokeWeight: 6,
});
}
mapInstanceRef.current.setFitView();
})
.catch((e) => {
console.error(e);
});
},
[props]
);
const hasMapInstance = useCallback(() => {
return !!mapInstanceRef.current;
}, []);
useEffect(() => {
return () => {
if (mapInstanceRef.current) {
mapInstanceRef.current?.destroy?.();
}
};
}, []);
return {
containerId: containerIdRef.current,
drawTraceMap,
hasMapInstance,
} as {
containerId: string;
drawTraceMap: (drawProps: DrawTraceMapProps) => Promise<void>;
hasMapInstance: () => boolean;
};
};
export default useDrawTraceMap;
二、useDrawTraceMap的使用示例
import useDrawTraceMap, { DrawTraceMapProps } from "@/hooks/useDrawTraceMap";
import { useEffect } from "react";
const drawData: DrawTraceMapProps = {
track: [
{
lat: 23.1291,
lng: 113.2644,
},
{
lat: 23.0,
lng: 113.5,
},
{
lat: 22.9,
lng: 113.7,
},
{
lat: 22.8,
lng: 113.9,
},
{
lat: 22.7,
lng: 114.1,
},
{
lat: 22.5431,
lng: 114.0579,
},
],
startPoint: {
lat: 23.1291,
lng: 113.2644,
},
endPoint: {
lat: 22.5431,
lng: 114.0579,
},
};
const TestMap = () => {
const { containerId, drawTraceMap } = useDrawTraceMap({
key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
});
useEffect(() => {
drawTraceMap(drawData);
}, [drawTraceMap]);
return (
<div
style={{
height: "100vh",
background: "rgb(221, 228, 235)",
padding: "24px",
}}
>
<div style={{ height: "300px" }} id={containerId} />
</div>
);
};
export default TestMap;
页面效果
