高德地图Web端(JS API)实战使用

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 {
  /**
   * 申请好的Web端开发者Key,要么在 hook 里面的 DEFAULT_AMAP_KEY 写死,要么传 key 值
   * 否则报错【useDrawTraceMap.ts:180 请求 AMapUI 失败】
   */
  key: string;
  /**
   * 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
   */
  version?: string;
}

/**
 * 使用高德地图AMap绘制地图,包括起点、终点、轨迹
 * @returns
 */
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, // 申请好的Web端开发者Key,首次调用 load 时必填
        version: props?.version || "1.4.15", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
        plugins: ["AMap.Autocomplete"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        AMapUI: {
          // 是否加载 AMapUI,缺省不加载
          version: "1.1", // AMapUI 缺省 1.1
          plugins: ["overlay/SimpleMarker"], // 需要加载的 AMapUI ui插件
        },
        Loca: {
          // 是否加载 Loca, 缺省不加载
          version: "1.3.2", // Loca 版本,缺省 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) {
            // 创建一个起点 Icon
            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),
            });

            // 将【经纬度】和【icon】传入 marker
            startMarker = new AMap.Marker({
              position: new AMap.LngLat(
                parseFloat(String(startX)),
                parseFloat(String(startY))
              ),
              icon: startIcon,
              offset: new AMap.Pixel(-13, -30),
            });
          }

          if (endPoint) {
            // 创建一个终点 icon
            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),
            });

            // 将【经纬度】和【icon】传入 marker
            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))];
          }

          // 将 markers 添加到地图
          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", // 线颜色
              // strokeOpacity: 1,     //线透明度
              strokeWeight: 6, // 线宽
              // strokeStyle: "solid"  //线样式
            });
          }

          mapInstanceRef.current.setFitView();

          // mapInstanceRef.current.on("complete", function () {
          //   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 {
    /**
     * 挂载地图的容器元素 id
     */
    containerId: string;
    /**
     * 绘制地图函数
     * @param drawProps
     * @returns
     */
    drawTraceMap: (drawProps: DrawTraceMapProps) => Promise<void>;
    /**
     * 是否有地图实例,用于判断是否已经绘制过地图,可以用于判断是否需要重新绘制
     * @returns
     */
    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;

页面效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值