基于TS封装的高德地图JS APi2.0实用工具(包含插件类型,基础类型)...持续更新

  1. 准备工作如下:
  2. 安装TS插件依赖 以及 地图基础类所需TS类型 tips:高德官方提供的地图类型与api2.0版本 存在问题,需要自行调整 github.com/Ludidi/amap...
  3. 自定义类型声明文件 amap.api.d.ts 内容如下
TS 复制代码
// 声明命名空间
type options = {
  key: string; // 高德地图的API Key
  version?: string; // API版本,默认为最新版本
  plugins?: string[]; // 需要加载的插件列表
  AMapUI?: any;
  Loca?: any;
};
declare namespace AMapLoader {
  export function load<T>(settings: options): Promise<T>;
}
  1. 申请好的Web端开发者Key,在项目入口文件引入 我使用的是Vue3的框架 如图:

tips:如果担心自己申请的秘钥被用户F12打开控制台查看后使用,可以让后端代理服务器转发

js 复制代码
 <script type="text/javascript">
        window._AMapSecurityConfig = {
            serviceHost: '你的代理服务器域名或地址/_AMapService',
        }
    </script>
    其中_AMapService为代理请求固定前缀,不可省略或修改
    //例如 :serviceHost:'http://1.1.1.1:80/_AMapService',

一 地图初始化

新建utils文件夹 /index.ts文件 封装工具,此工具内包含了 对高德地图api2,0的一些封装方法 内容如下: 1.1 初始化方法:

js 复制代码
export function initMap(): Promise<typeof AMap> {
  return new Promise((resolve, reject) => {
    //如果全局已经存在AMap对象 则直接返回
    if (window.AMap) {
      resolve(window.AMap);
      return;
    }
    AMapLoader.load<typeof AMap>({
      key: "XXXXXXXXXXXXXX", // 申请好的Web端开发者Key,首次调用 load 时必填
      version: "2.0", // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
      plugins: [
        "AMap.MoveAnimation,AMap.MouseTool,AMap.PlaceSearch,AMap.DistrictSearch,AMap.Geocoder",
      ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
      // "AMapUI": { // 是否加载 AMapUI,缺省不加载
      //     "version": '1.1', // AMapUI 版本
      //     "plugins": [], // 需要加载的 AMapUI ui插件
      // },
      // "Loca": { // 是否加载 Loca, 缺省不加载
      //     "version": '2.0' // Loca 版本
      // },
    })
      .then((AMap) => {
        window.AMap = AMap;
        resolve(AMap); //防止上方全局添加amap失败手动返回Amap
      })
      .catch((e) => {
        console.error(e); //加载错误提示
        reject(e);
      });
  });
}

1.2 新建myMap 类

导入类型 import "@amap/amap-jsapi-types";

ts 复制代码
        /**
         * 高德地图使用的是 GCJ-02 坐标系,若采用的其他坐标系请初始化配置此处转换
         */
        type CoordinateType = "gcj02" | "wgs84" | "bd09";
        type MyMapOptions = {
          _AmapCoordinate: CoordinateType;
        } & AMap.MapOptions;

        class myMap {
            private _AmapCoordinate: CoordinateType = "gcj02"; //地图坐标系 默认自动转换(后续加上)

             public mapConfig: AMap.MapOptions = {
                zoom: 11,
                center: [121.732487, 31.086897],
                viewMode: "3D",
                mapStyle: "amap://styles/2a268264f80b6efc60d848838404e726",
                rotateEnable: false,
                pitchEnable: false,
                skyColor: "#002d56", //天空颜色 倾斜后才会产生 仅限于3D 模式下
              };
              
             public aMap!: AMap.Map; //地图对象    
               /**
               * 地图初始化
               * @param {dom元素} el    传入地图容器 DIV 的 ID 值或者 DIV 对象
               * @param {配置参数} config 对传入的配置合并
               * @return {Promise<void>} 返回一个 Promise 对象,表示地图初始化完成
               */
              public init(
                el: string | HTMLDivElement,
                config: MyMapOptions
              ): Promise<typeof AMap> {
                Object.assign(this.mapConfig, config);
                if (config._AmapCoordinate) {
                  this._AmapCoordinate = config._AmapCoordinate;
                }
                return new Promise((resolve, reject) => {
                  initMap().then((AMap) => {
                    this.aMap = new AMap.Map(el, {
                      ...this.mapConfig,
                    });
                    this.aMap.on("complete", () => {
                      resolve(AMap);
                    });
               });
         });
      }
}

掉用如下:

js 复制代码
<template>
     <div class="home" id="mapId"></div>
</template>

<script lang="ts" setup>
import { onMounted, ref, nextTick } from "vue";
import myMap from "@/utils/amap-utils";

let currentMap: myMap;
onMounted(() => {
  currentMap = new myMap();
  currentMap
    .init("mapId", { _AmapCoordinate: "gcj02" })
    .then((res) => {
      console.log("地图初始化成功", res);
     // currentMap.setMapAreaOutline();
    })
    .catch((err) => {
      console.error("地图初始化失败", err);
    });
});

</script>
.home{
   width:100vw;height:100vh
}

二 设置地图区域轮廓 (用于突出显示某块区域)

在原有类中添加方法 setMapAreaOutline

添加属性: private _areaOutlineFeatures!: AMap.Polygon; //地图区域轮覆盖物

js 复制代码
/**
   * 设置地图区域轮廓
   * 通过行政区查询获取地图区域轮廓,最后绘制轮廓
   * @param lineConfig 轮廓线条配置
   * @param districtOptions  区域查询配置
   */
  public setMapAreaOutline(
    lineConfig?: AMap.PolygonOptions,
    districtOptions?: { keyword: string } & AMap.DistrictSearchOptions
  ): void {
    const config: AMap.PolygonOptions = {
      strokeWeight: 4,
      strokeColor: "#004eff",
      fillColor: "",
      fillOpacity: 0.3,
      zIndex: 10,
      bubble: true,
    };
    Object.assign(config, lineConfig);
    let disOptipns: { keyword: string } & AMap.DistrictSearchOptions = {
      extensions: "all",
      level: "district",
      subdistrict: 1,
      showbiz: false, //最后一级返回街道信息
      keyword: "310115",
    };
    Object.assign(disOptipns, districtOptions);

    new AMap.DistrictSearch({
      extensions: "all",
      level: "district",
      subdistrict: 1,
      showbiz: false, //最后一级返回街道信息
    }).search(disOptipns.keyword, (status, result) => {
      if (status === "complete" && result.districtList.length > 0) {
        const holes = result.districtList[0].boundaries;
        this._areaOutlineFeatures = new AMap.Polygon();
        this._areaOutlineFeatures.setOptions({ ...config, path: holes });
        this.aMap.add(this._areaOutlineFeatures);
      }
    });
  }
   实际调用如下:
       currentMap.setMapAreaOutline();
   

三 添加点位以及信息窗体

原有类中添加属性:

js 复制代码
  private _overlaysMapObject = new Map<
    string,
    | AMap.Marker
    | AMap.Polyline
    | AMap.Polygon
    | AMap.Circle
    | AMap.Rectangle
    | AMap.MassMarks
  >(); //覆盖物对象集合

新增方法 addMarker

js 复制代码
  /**
   * 添加一个点位
   * @param markConfig mark配置
   */
  public addMarker(markConfig: MarkerOptions): void {
    const fconfig: MarkerOptions = {
      clickable: true,
      position: undefined,
      anchor: "bottom-center",
      icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
      extData: {},
      key: "",  //key 点位唯一标识 后期用于控制某个点
    };
    Object.assign(fconfig, markConfig);

     if (!this._overlaysMapObject.has(fconfig.key)) {  //地图已有点位则不再添加 而是直接显示,具体看实际业务需求
      const mark = new AMap.Marker({
        ...fconfig,
      });
      if (fconfig.markClickFn) {
        mark.on("click", (e) => {
          fconfig.markClickFn && fconfig.markClickFn(e);
        });
      }
      this._overlaysMapObject.set(fconfig.key, mark);
      this.aMap.add(mark);
    } else {
      this._overlaysMapObject.get(fconfig.key)?.show();
    }
  }
  
  //实际调用如下:仅仅添加点位 
   currentMap.addMarker({
    icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
    position: [121.698747, 31.12806],
    key: "mark1",
    title: "鼠标显示的内容",
    extData: {
      otherData: 111,
    },
    markClickFn: (e) => {
      console.log(e);
    },
  });
 

新增信息窗体方法: 原有类中添加属性

js 复制代码
  private _InfoWindow: AMap.InfoWindow | null = null; //信息窗体

    
方法如下:
 /**
   *
   * @param opt 信息窗体配置
   * @description 打开一个信息窗体
   * 关键参数 InfoOptions : {position:[123.22,31.22] , content:(String | HTMLElement)}
   */
  public openInfoWindow(opt: InfoOptions): void {
    const infoWindow = new AMap.InfoWindow({
      isCustom: true,
      // offset: new AMap.Pixel(0, -50), //信息窗体偏移量
      autoMove: true,
      ...opt,
    });
    this._InfoWindow = infoWindow;
    infoWindow.open(this.aMap, opt.position);
  }
  /**
   * 关闭信息窗体
   */
  public closeInfoWindow(): void {
    if (this._InfoWindow) {
      this._InfoWindow.close();
      this._InfoWindow = null;
    }
  }

使用:

js 复制代码
 currentMap.addMarker({
    icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
    position: [121.698652, 31.12706],
    key: "mark2",
    extData: {
      otherData: 111,
    },
    markClickFn: (e) => {
      showInfoWindow.value = true;
      nextTick(() => {
        currentMap.openInfoWindow({
          position: e.target.getPosition(),
          content: elemntRef.value,
          offset: new AMap.Pixel(0, -80), //信息窗体偏移量
        });
      });
    },
  });
templete 复制代码
   // dom元素如下:
    
     <div ref="elemntRef" class="InfoWindowClass" v-if="showInfoWindow">
      <div class="InfoWindowClass-header">
        <span>信息窗口标题{{ otherData.name }}</span>
        <span class="close-btn" @click="currentMap.closeInfoWindow()"></span>
      </div>
      <div class="InfoWindowClass-content">这里是信息窗口的内容区域...</div>
      <div class="InfoWindowClass-arrow"></div>
    </div>
    
    
    //js
    const elemntRef = ref();
    const showInfoWindow = ref(false);
    
    css 样式
    // 基础信息窗样式
.InfoWindowClass {
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  z-index: 1000;
  width: 300px;
  // 头部区域样式
  &-header {
    padding: 12px 16px;
    border-bottom: 1px solid #e8e8e8;
    position: relative;

    // 关闭按钮样式
    .close-btn {
      position: absolute;
      top: 12px;
      right: 12px;
      width: 16px;
      height: 16px;
      cursor: pointer;
      color: #999;
      font-size: 14px;
      line-height: 14px;

      &:hover {
        color: #333;
      }

      &:before,
      &:after {
        content: "";
        position: absolute;
        width: 16px;
        height: 2px;
        background-color: currentColor;
        top: 50%;
        left: 0;
        transform: translateY(-50%);
      }

      &:before {
        transform: translateY(-50%) rotate(45deg);
      }

      &:after {
        transform: translateY(-50%) rotate(-45deg);
      }
    }
  }

  // 内容区域样式
  &-content {
    padding: 16px;
    font-size: 14px;
    line-height: 1.5;
  }

  // 底部箭头样式
  &-arrow {
    position: absolute;
    bottom: -7px;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 12px solid transparent;
    border-right: 12px solid transparent;
    border-top: 12px solid #fff;
    border-bottom: 0;
    z-index: 1;

    // // 阴影增强立体感
    // &:after {
    //   content: "";
    //   position: absolute;
    //   top: 1px;
    //   left: -12px;
    //   width: 0;
    //   height: 0;
    //   border-left: 12px solid transparent;
    //   border-right: 12px solid transparent;
    //   border-top: 12px solid rgba(0, 0, 0, 0.2);
    //   border-bottom: 0;
    //   z-index: -1;
    // }
  }
}
    

效果如下:

四 添加海量点

js 复制代码
 /**
   * @param config 海量点配置
   * @param data.style 样式索引值 对应的是config.style的自定义点的样式下标索引(与z-index无关)
   * @description 在地图上显示大量的点位数据
   * click事件回调通过InfoWindow 将页面的dom 和 InfoWindow相关联亦可实现海量点信息窗展示
   */
  public addMassMarks<T>(
    data: { lnglat: AMap.Vector2; otherData: T; style: number }[],
    config: AMap.MassMarkersOptions & MarkerOptions
  ): void {
    if (!this._overlaysMapObject.has(config.key)) {
      const mass = new AMap.MassMarks(data, {
        ...config,
      });
      if (config.markClickFn) {
        mass.on("click", (e) => {
          config.markClickFn && config.markClickFn(e);
        });
      }
      mass.setMap(this.aMap);
      this._overlaysMapObject.set(config.key, mass);
    }
  }
  
  //实际调用
interface MassDataType {   //用于点击海量点后的自定义的数据,可用于信息窗体展示,如无则无需添加
  name: string;
  age: number;
}


    currentMap.addMassMarks<MassDataType>(
    [
      {
        lnglat: [121.698652, 31.12706],
        otherData: {
          name: "景县1111",
          age: 17,
        },
        style: 0,
      },
      {
        lnglat: [121.698421, 31.1212],
        otherData: {
          name: "景县2222",
          age: 17,
        },
        style: 1,
      },
      {
        lnglat: [121.694153, 31.12412],
        otherData: {
          name: "景县3333",
          age: 17,
        },
        style: 1,
      },
      {
        lnglat: [121.698121, 31.12711],
        otherData: {
          name: "景县4444",
          age: 17,
        },
        style: 0,
      },
      {
        lnglat: [121.698147, 31.124516],
        otherData: {
          name: "景县5555",
          age: 17,
        },
        style: 1,
      },
    ],
    {
      key: "mass1",
      style: [
        {
          url: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
          size: new AMap.Size(30, 30),
          rotation: 0,
        },
        {
          url: "https://webapi.amap.com/images/mass/mass1.png",
          size: new AMap.Size(30, 30),
          rotation: 0,
        },
      ],
      zIndex: 130,
      markClickFn: (e) => {
        console.log("海量点点击事件", e);
        otherData.value = e.data.otherData;
        showInfoWindow.value = true;
        nextTick(() => {
          currentMap.openInfoWindow({
            position: e.data.lnglat,
            content: elemntRef.value,
            offset: [15, 0],
          });
        });
      },
    }
  );

效果如图:(此处只举例了几条数据测试使用 实际可承载上千条数据并不会卡顿)

五 使用mouseTool 插件 绘制电子围栏

原有类中添加属性

js 复制代码
 private _MouseTool: AMap.MouseTool | null = null; //鼠标工具
 private _polygonList: AMap.Polygon[] = []; //多边形列表
 
  /**
   *  使用mouseTool 插件 绘制电子围栏
   *  鼠标单击地图选点/线,右键结束
   * @param drawConfig: {nobatch : 是否批量绘制 电子围栏(多边形)} nobatch ? '每次只能绘制一个' : '不限制'
   * @param drawCompletedfn 每次绘制完毕的回调
   */
  public drawpolygon(
    polygonConfig: AMap.PolygonOptions,
    drawConfig: DrawConfigType
  ): void {
    if (!this._MouseTool) {
      this._MouseTool = new AMap.MouseTool(this.aMap);
    }
    const initPolyConfig: AMap.PolygonOptions = {
      fillColor: "#00b0ff",
      strokeColor: "#80d8ff",
      strokeWeight: 2,
      bubble: true,
      zIndex: 130,
    };
    Object.assign(initPolyConfig, polygonConfig);
    this._MouseTool.polygon(initPolyConfig);

    this._MouseTool.on("draw", (e: any) => {
      //每次绘制完图形的回调

      if (drawConfig.nobatch) {
        if (this._polygonList.length) {
          this.aMap.remove(this._polygonList);
          this._polygonList = [];
        }
      }
      this._polygonList.push(e.obj);

      drawConfig.drawCompletedfn(e);
    });
  }

  /**
   * 关闭鼠标工具
   */
  public closeDrawpolygon(): void {
    if (this._MouseTool) {
      this._MouseTool.close();
      this._MouseTool = null;
    }
  }
  
  
  //开始绘制围栏方法
   currentMap.drawpolygon(
    {
      strokeColor: "#FF33FF", //线颜色
      fillColor: "#1791fc", //填充颜色
      strokeWeight: 3, //线宽
      fillOpacity: 0.2, //填充透明度
      zIndex: 100,
    },
    {
      nobatch: false,
      drawCompletedfn: (e: any) => {
        console.log("绘制完成回调", e);
        console.log(currentMap.getDrawedpolygon());
      },
    }
  );
  
  //结束绘制围栏方法
  currentMap.closeDrawpolygon();

最后补充一个填充多边形的方法

js 复制代码
  /**
   * 填充电子围栏(多边形)
   */
  public setPolygonList(polygonList: AMap.PolygonOptions[]): void {
    const config: AMap.PolygonOptions = {
      strokeWeight: 4,
      strokeColor: "#004eff",
      fillColor: "#80d8ff",
      fillOpacity: 0.3,
      zIndex: 10,
      bubble: true,
    };
    polygonList.forEach((citem) => {
      const poly = new AMap.Polygon();
      poly.setOptions({ ...config, ...citem, path: citem.path });
      this.aMap.add(poly);
      this._polygonList.push(poly);
    });
  }
  
  //实际使用
   currentMap.setPolygonList([
    {
      path: [
        [121.568722, 31.317126],
        [121.65112, 31.317126],
        [121.64906, 31.28251],
        [121.566662, 31.286031],
      ],
    },
    {
      path: [
        [121.776895, 31.121916],
        [121.628117, 31.194152],
        [121.607861, 31.102773],
        [121.751026, 31.051903],
      ],
    },
  ]);

六 绘制车辆实时轨迹

js 复制代码
  /**
   * 清除轨迹相关的覆盖物
   */
  public clearTrajectory(): void {
    this._overlaysMapObject.forEach((overlay, key) => {
      if (key.includes("map-traj")) {
        if (
          overlay instanceof AMap.Marker &&
          overlay.getExtData() == "stopdrawGj"
        ) {
          overlay.stopMove(); //停止正在移动的轨迹
        }
        this.aMap.remove(overlay);
        this._overlaysMapObject.delete(key);
      }
    });
  }
  
  /**
   *
   * @param 轨迹数据 cj02坐标 arrPath :[[121.4363,31.222]] || [[[121.4363,31.222],[121.4363,31.222]]]
   * @param *轨迹线条样式 options
   * 内含车辆开始位置,结束位置,以及车辆运行时轨迹动画
   * 如果是成千上万条的轨迹数据 得使用https://lbs.amap.com/api/amap-ui/reference-amap-ui/mass-data/pathsimplifier 组件
   */
  public drawTrajectory(
    arrPath: [number, number][],
    options?: AMap.PolylineOptions
  ): void {
    let polylineStyle: AMap.PolylineOptions = {
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 7, //线宽
      lineJoin: "round",
      isOutline: true,
      showDir: true, //显示箭头  3D 模式下不支持
      borderWeight: 1,
      dirColor: "#fff",
      strokeStyle: "solid", //线样式
    };
    Object.assign(polylineStyle, options);
    const start = arrPath[0]; //开始点
    const end = arrPath[arrPath.length - 1]; //结束点
    this.clearTrajectory(); //每次绘制下一次轨迹前 先清除上一次轨迹
    this.addMarker({
      icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
      position: start,
      key: "vehicleMarkStart",
      title: "车辆开始位置",
    });

    const driveCar = new AMap.Marker({
      position: start,
      icon: new AMap.Icon({
        image: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png", //注意车头的方向
        imageOffset: new AMap.Pixel(0, 0),
      }),
      offset: new AMap.Pixel(-13, -26),
      extData: "stopdrawGj",
      map: this.aMap,
    });
    const polyline = new AMap.Polyline({
      ...polylineStyle,
    });
    this.aMap.add(polyline);
    // 路程总览
    const allPahtline = new AMap.Polyline({
      path: arrPath,
      showDir: true,
      strokeColor: "#28F", //线颜色
      strokeWeight: 6, //线宽
    });
    this.aMap.add(allPahtline);
    this.aMap.setFitView([polyline]);

    driveCar.on("moving" as any, (e) => {
      polyline.setPath(e.passedPath);
      this.aMap.setCenter(e.target.getPosition(), true); //镜头随着动画移动
    });

    //开始绘制轨迹 //对于每秒钟接收的轨迹数据 做简化,否则会卡顿且会被延迟播放
    driveCar.moveAlong(arrPath, {
      // // 每一段的时长
      duration: 200,
      // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
      autoRotation: true,
    });

    driveCar.on("movealong" as any, (e) => {
      console.log("动画执行结束");
      //最终动画执行结束
      this.addMarker({
        icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
        position: end,
        key: "vehicleMarkEnd",
        title: "车辆结束位置",
      });
      driveCar.hide();
    });

    this._overlaysMapObject.set("map-traj-driveCar", driveCar);
    this._overlaysMapObject.set("map-traj-live-polyline", polyline);
    this._overlaysMapObject.set("map-traj-all-polyline", allPahtline);
  }
  
  //调用
    const tdata: [number, number][] = [
    [121.5326, 31.17348],
    [121.5327, 31.1734],
    [121.5327, 31.1734],
    [121.5327, 31.17339],
    [121.5327, 31.1734],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17335],
    [121.5326, 31.17335],
    [121.5326, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5326, 31.17335],
    [121.5327, 31.17332],
    [121.533, 31.1731],
    [121.533, 31.173],
    [121.5336, 31.17312],
    [121.5344, 31.17336],
    [121.5255, 31.16332],
    [121.5267, 31.16382],
    [121.5278, 31.16425],
    [121.5292, 31.1647],
    [121.5305, 31.16506],
    [121.5316, 31.16553],
    [121.5321, 31.16562],
    [121.5322, 31.16532],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5323, 31.16524],
    [121.5326, 31.16475],
    [121.5328, 31.1644],
    [121.5328, 31.16429],
    [121.5331, 31.16372],
    [121.5334, 31.16321],
    [121.5335, 31.16302],
    [121.5335, 31.1627],
    [121.5328, 31.16236],
    [121.532, 31.162],
    [121.5311, 31.16157],
    [121.5308, 31.16145],
    [121.5307, 31.16146],
    [121.5307, 31.16147],
    [121.5307, 31.16147],
    [121.5307, 31.16147],
    [121.5307, 31.16146],
    [121.5307, 31.16146],
    [121.5307, 31.16146],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16146],
    [121.5304, 31.16122],
    [121.5303, 31.16122],
    [121.5303, 31.16123],
    [121.5302, 31.16115],
    [121.5299, 31.16081],
    [121.5304, 31.16002],
    [121.531, 31.15898],
    [121.5311, 31.15876],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5312, 31.1586],
    [121.5315, 31.1581],
    [121.532, 31.1572],
    [121.5326, 31.15606],
    [121.533, 31.15545],
    [121.5327, 31.15534],
    [121.5325, 31.15534],
    [121.5325, 31.15536],
    [121.5325, 31.15538],
    [121.5325, 31.15537],
    [121.5325, 31.15537],
    [121.5325, 31.15537],
    [121.5325, 31.15535],
    [121.5325, 31.15535],
    [121.5325, 31.15533],
    [121.5326, 31.15533],
    [121.5326, 31.15531],
    [121.5324, 31.15527],
    [121.5316, 31.15508],
    [121.5308, 31.15487],
    [121.5305, 31.15475],
    [121.5305, 31.15473],
    [121.5303, 31.15461],
    [121.5295, 31.15433],
    [121.5289, 31.15353],
    [121.5293, 31.15257],
    [121.5297, 31.15203],
    [121.5297, 31.15202],
    [121.5297, 31.15202],
    [121.5297, 31.15201],
    [121.5297, 31.15168],
    [121.5299, 31.15163],
  ];
  // currentMap.drawEasyrajectory(tdata);
  currentMap.drawTrajectory(tdata)

最后附上一个简易版的轨迹 直接传入数据 然后绘制轨迹

js 复制代码
  /**
   *
   * @param 轨迹数据 arrPath
   * @param 轨迹线条样式 options
   * 简易车辆轨迹 不包含动画-直接生成轨迹
   */
  public drawEasyrajectory(
    arrPath: [number, number][],
    options?: AMap.PolylineOptions
  ): void {
    let polylineStyle: AMap.PolylineOptions = {
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 7, //线宽
      lineJoin: "round",
      isOutline: true,
      showDir: true, //显示箭头  3D 模式下不支持
      borderWeight: 1,
      dirColor: "#fff",
      strokeStyle: "solid", //线样式
    };
    Object.assign(polylineStyle, options);
    this.clearTrajectory(); //每次绘制下一次轨迹前 先清除上一次轨迹
    // 路程总览
    const allPahtline = new AMap.Polyline({
      path: arrPath,
      showDir: true,
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 10, //线宽
    });
    this.aMap.add(allPahtline);
    this._overlaysMapObject.set("map-traj-all-polyline", allPahtline);
  }

七 逆地理编码(地址 -> 坐标),(坐标 -> 地址)支持批量最多20

根据地址 查询对应坐标信息,以及根据坐标查询地址信息

js 复制代码
  /**
   * 逆地理编码(地址 -> 坐标)
   * @param {*}geocoder 配置
   * @param {*}address 文本地址批量查询时字符串以逗号分开传入,最多20个
   * @param {*}successCollbackFn 成功后的信息的回调
   */
  public byAddressGetLocation(
    geoOptions: AMap.GeocoderOptions,
    address: string,
    successCollbackFn: (r: Regeocode[]) => void
  ): void {
    const geocoder = new AMap.Geocoder({
      extensions: "all",
      ...geoOptions,
    });
    //@ts-ignore
    geocoder.getLocation(address, (status, result: GeocodeResponse) => {
      if (status === "complete" && result.regeocodes) {
        successCollbackFn(result.regeocodes);
      } else {
        successCollbackFn([]);
      }
    });
  }

  /**
   * 逆地理编码(坐标 -> 地址)支持批量最多20
   * @param geoOptions geocoder 配置
   * @param location 二维的坐标数组,以批量的传入以及返回形式
   * @param successCollbackFn 成功后的信息的回调
   */
  public byLocationGetAddress(
    geoOptions: AMap.GeocoderOptions,
    location: AMap.Vector2[],
    successCollbackFn: (r: Regeocode[]) => void
  ): void {
    const geocoder = new AMap.Geocoder({
      radius: 1000,
      extensions: "all",
      ...geoOptions,
    });
    //经纬度转地址
    geocoder.getAddress(
      //@ts-ignore  //根据官方提供的类型存在问题 此处忽悠类型
      location,
      (status: string, result: GeocodeResponse) => {
        console.log(status);
        console.log(result);
        if (status === "complete" && result.regeocodes) {
          successCollbackFn(result.regeocodes);
        } else {
          successCollbackFn([]);
        }
      }
    );
  }
  
  
  调用如下:

  //根据坐标查询
  urrentMap.byLocationGetAddress(
    {
      city: "上海",
    },
    [[121.5326, 31.17348]],
    (r) => {
      console.log(r);
    }
  );

最后附上全部代码

js 复制代码
import "@amap/amap-jsapi-types";
/**
 * 高德地图使用的是 GCJ-02 坐标系,若采用的其他坐标系请初始化配置此处转换
 */
type CoordinateType = "gcj02" | "wgs84" | "bd09";
type MyMapOptions = {
  _AmapCoordinate: CoordinateType;
} & AMap.MapOptions;

interface MarkerOptions extends AMap.MarkerOptions {
  key: string; //标记的唯一标识
  markClickFn?: (e: any) => void;
}
interface InfoOptions extends AMap.InfoOptions {
  position: AMap.Vector2; //信息窗体类型扩展
}
interface DrawConfigType {
  nobatch: boolean;
  drawCompletedfn: (e: any) => void;
}
// 逆地理编码结果项类型
interface Regeocode {
  addressComponent: any;
  formattedAddress: string;
}
interface GeocodeResponse {
  info: string;
  regeocodes: Regeocode[];
}

//枚举所有点位类型
type AllLocationDataType =
  | AMap.Vector2
  | AMap.LngLat
  | AMap.LngLatLike[]
  | AMap.LngLatLike[][]
  | AMap.LngLatLike[][][]
  | [number, number][];

class myMap {
  private _polygonList: AMap.Polygon[] = []; //多边形列表
  private _InfoWindow: AMap.InfoWindow | null = null; //信息窗体
  private _areaOutlineFeatures!: AMap.Polygon; //地图区域轮覆盖物
  private _MouseTool: AMap.MouseTool | null = null; //鼠标工具
  private _AmapCoordinate: CoordinateType = "gcj02"; //地图坐标系 默认自动转换(后续加上)
  private _overlaysMapObject = new Map<
    string,
    | AMap.Marker
    | AMap.Polyline
    | AMap.Polygon
    | AMap.Circle
    | AMap.Rectangle
    | AMap.MassMarks
  >(); //覆盖物对象集合

  public mapConfig: AMap.MapOptions = {
    zoom: 11,
    center: [121.732487, 31.086897],
    viewMode: "3D",
    mapStyle: "amap://styles/2a268264f80b6efc60d848838404e726",
    rotateEnable: false,
    pitchEnable: false,
    skyColor: "#002d56", //天空颜色 倾斜后才会产生 仅限于3D 模式下
  };
  public aMap!: AMap.Map; //地图对象

  /**
   * 地图初始化
   * @param {dom元素} el    传入地图容器 DIV 的 ID 值或者 DIV 对象
   * @param {配置参数} config 对传入的配置合并
   * @return {Promise<void>} 返回一个 Promise 对象,表示地图初始化完成
   */
  public init(
    el: string | HTMLDivElement,
    config: MyMapOptions
  ): Promise<typeof AMap> {
    Object.assign(this.mapConfig, config);
    if (config._AmapCoordinate) {
      this._AmapCoordinate = config._AmapCoordinate;
    }
    return new Promise((resolve, reject) => {
      initMap().then((AMap) => {
        this.aMap = new AMap.Map(el, {
          ...this.mapConfig,
        });
        this.aMap.on("complete", () => {
          resolve(AMap);
        });
      });
    });
  }

  /**
   * 设置地图区域轮廓
   * 通过行政区查询获取地图区域轮廓,最后绘制轮廓
   * @param lineConfig 轮廓线条配置
   * @param districtOptions  区域查询配置
   */
  public setMapAreaOutline(
    lineConfig?: AMap.PolygonOptions,
    districtOptions?: { keyword: string } & AMap.DistrictSearchOptions
  ): void {
    const config: AMap.PolygonOptions = {
      strokeWeight: 4,
      strokeColor: "#004eff",
      fillColor: "",
      fillOpacity: 0.3,
      zIndex: 10,
      bubble: true,
    };
    Object.assign(config, lineConfig);
    let disOptipns: { keyword: string } & AMap.DistrictSearchOptions = {
      extensions: "all",
      level: "district",
      subdistrict: 1,
      showbiz: false, //最后一级返回街道信息
      keyword: "310115",
    };
    Object.assign(disOptipns, districtOptions);

    new AMap.DistrictSearch({
      extensions: "all",
      level: "district",
      subdistrict: 1,
      showbiz: false, //最后一级返回街道信息
    }).search(disOptipns.keyword, (status, result) => {
      if (status === "complete" && result.districtList.length > 0) {
        const holes = result.districtList[0].boundaries;
        this._areaOutlineFeatures = new AMap.Polygon();
        this._areaOutlineFeatures.setOptions({ ...config, path: holes });
        this.aMap.add(this._areaOutlineFeatures);
      }
    });
  }

  /**
   * 添加一个点位
   * @param markConfig mark配置
   */
  public addMarker(markConfig: MarkerOptions): void {
    const fconfig: MarkerOptions = {
      clickable: true,
      position: undefined,
      anchor: "bottom-center",
      icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
      extData: {},
      key: "",  //key 点位唯一标识 后期用于控制某个点
    };
    Object.assign(fconfig, markConfig);

    if (!this._overlaysMapObject.has(fconfig.key)) {
      const mark = new AMap.Marker({
        ...fconfig,
      });
      if (fconfig.markClickFn) {
        mark.on("click", (e) => {
          fconfig.markClickFn && fconfig.markClickFn(e);
        });
      }
      this._overlaysMapObject.set(fconfig.key, mark);
      this.aMap.add(mark);
    } else {
      this._overlaysMapObject.get(fconfig.key)?.show();
    }
  }

  /**
   *
   * @param opt 信息窗体配置
   * @description 打开一个信息窗体
   * 关键参数 InfoOptions : {position:[123.22,31.22] , content:(String | HTMLElement)}
   */
  public openInfoWindow(opt: InfoOptions): void {
    const infoWindow = new AMap.InfoWindow({
      isCustom: true,
      // offset: new AMap.Pixel(0, -50), //信息窗体偏移量
      autoMove: true,
      ...opt,
    });
    this._InfoWindow = infoWindow;
    infoWindow.open(this.aMap, opt.position);
  }
  /**
   * 关闭信息窗体
   */
  public closeInfoWindow(): void {
    if (this._InfoWindow) {
      this._InfoWindow.close();
      this._InfoWindow = null;
    }
  }
  /**
   * @param config 海量点配置
   * @param data.style 样式索引值 对应的是config.style的自定义点的样式下标索引(与z-index无关)
   * @description 在地图上显示大量的点位数据
   * click事件回调通过InfoWindow 将页面的dom 和 InfoWindow相关联亦可实现海量点信息窗展示
   */
  public addMassMarks<T>(
    data: { lnglat: AMap.Vector2; otherData: T; style: number }[],
    config: AMap.MassMarkersOptions & MarkerOptions
  ): void {
    if (!this._overlaysMapObject.has(config.key)) {
      const mass = new AMap.MassMarks(data, {
        ...config,
      });
      if (config.markClickFn) {
        mass.on("click", (e) => {
          config.markClickFn && config.markClickFn(e);
        });
      }
      mass.setMap(this.aMap);
      this._overlaysMapObject.set(config.key, mass);
    }
  }

  /**
   *  使用mouseTool 插件 绘制电子围栏
   *  鼠标单击地图选点/线,右键结束
   * @param drawConfig: {nobatch : 是否批量绘制 电子围栏(多边形)} nobatch ? '每次只能绘制一个' : '不限制'
   * @param drawCompletedfn 每次绘制完毕的回调
   */
  public drawpolygon(
    polygonConfig: AMap.PolygonOptions,
    drawConfig: DrawConfigType
  ): void {
    if (!this._MouseTool) {
      this._MouseTool = new AMap.MouseTool(this.aMap);
    }
    const initPolyConfig: AMap.PolygonOptions = {
      fillColor: "#00b0ff",
      strokeColor: "#80d8ff",
      strokeWeight: 2,
      bubble: true,
      zIndex: 130,
    };
    Object.assign(initPolyConfig, polygonConfig);
    this._MouseTool.polygon(initPolyConfig);

    this._MouseTool.on("draw", (e: any) => {
      //每次绘制完图形的回调

      if (drawConfig.nobatch) {
        if (this._polygonList.length) {
          this.aMap.remove(this._polygonList);
          this._polygonList = [];
        }
      }
      this._polygonList.push(e.obj);

      drawConfig.drawCompletedfn(e);
    });
  }

  /**
   * 关闭鼠标工具
   */
  public closeDrawpolygon(): void {
    if (this._MouseTool) {
      this._MouseTool.close();
      this._MouseTool = null;
    }
  }

  /**
   * 填充电子围栏(多边形)
   */
  public setPolygonList(polygonList: AMap.PolygonOptions[]): void {
    const config: AMap.PolygonOptions = {
      strokeWeight: 4,
      strokeColor: "#004eff",
      fillColor: "#80d8ff",
      fillOpacity: 0.3,
      zIndex: 10,
      bubble: true,
    };
    polygonList.forEach((citem) => {
      const poly = new AMap.Polygon();
      poly.setOptions({ ...config, ...citem, path: citem.path });
      this.aMap.add(poly);
      this._polygonList.push(poly);
    });
  }
  /**
   * 获取已绘制的图形路径
   * @return 多边形轮廓线的节点坐标数组。 支持 单个普通多边形({Array }),单个带孔多边形({Array<Array >}),多个带孔多边形({Array<Array<Array >>})
   */
  public getDrawedpolygon():
    | AMap.LngLat[]
    | AMap.LngLat[][]
    | AMap.LngLat[][][] {
    return this._polygonList.map((polygon) => {
      return polygon.getPath() as AMap.LngLat[];
    });
  }

  /**
   *
   * @param 轨迹数据 cj02坐标 arrPath :[[121.4363,31.222]] || [[[121.4363,31.222],[121.4363,31.222]]]
   * @param *轨迹线条样式 options
   * 内含车辆开始位置,结束位置,以及车辆运行时轨迹动画
   * 如果是成千上万条的轨迹数据 得使用https://lbs.amap.com/api/amap-ui/reference-amap-ui/mass-data/pathsimplifier 组件
   */
  public drawTrajectory(
    arrPath: [number, number][],
    options?: AMap.PolylineOptions
  ): void {
    let polylineStyle: AMap.PolylineOptions = {
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 7, //线宽
      lineJoin: "round",
      isOutline: true,
      showDir: true, //显示箭头  3D 模式下不支持
      borderWeight: 1,
      dirColor: "#fff",
      strokeStyle: "solid", //线样式
    };
    Object.assign(polylineStyle, options);
    const start = arrPath[0]; //开始点
    const end = arrPath[arrPath.length - 1]; //结束点
    this.clearTrajectory(); //每次绘制下一次轨迹前 先清除上一次轨迹
    this.addMarker({
      icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
      position: start,
      key: "vehicleMarkStart",
      title: "车辆开始位置",
    });

    const driveCar = new AMap.Marker({
      position: start,
      icon: new AMap.Icon({
        image: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png", //注意车头的方向
        imageOffset: new AMap.Pixel(0, 0),
      }),
      offset: new AMap.Pixel(-13, -26),
      extData: "stopdrawGj",
      map: this.aMap,
    });
    const polyline = new AMap.Polyline({
      ...polylineStyle,
    });
    this.aMap.add(polyline);
    // 路程总览
    const allPahtline = new AMap.Polyline({
      path: arrPath,
      showDir: true,
      strokeColor: "#28F", //线颜色
      strokeWeight: 6, //线宽
    });
    this.aMap.add(allPahtline);
    this.aMap.setFitView([polyline]);

    driveCar.on("moving" as any, (e) => {
      polyline.setPath(e.passedPath);
      this.aMap.setCenter(e.target.getPosition(), true); //镜头随着动画移动
    });

    //开始绘制轨迹 //对于每秒钟接收的轨迹数据 做简化,否则会卡顿且会被延迟播放
    driveCar.moveAlong(arrPath, {
      // // 每一段的时长
      duration: 200,
      // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
      autoRotation: true,
    });

    driveCar.on("movealong" as any, (e) => {
      console.log("动画执行结束");
      //最终动画执行结束
      this.addMarker({
        icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
        position: end,
        key: "vehicleMarkEnd",
        title: "车辆结束位置",
      });
      driveCar.hide();
    });

    this._overlaysMapObject.set("map-traj-driveCar", driveCar);
    this._overlaysMapObject.set("map-traj-live-polyline", polyline);
    this._overlaysMapObject.set("map-traj-all-polyline", allPahtline);
  }

  /**
   *
   * @param 轨迹数据 arrPath
   * @param 轨迹线条样式 options
   * 简易车辆轨迹 不包含动画-直接生成轨迹
   */
  public drawEasyrajectory(
    arrPath: [number, number][],
    options?: AMap.PolylineOptions
  ): void {
    let polylineStyle: AMap.PolylineOptions = {
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 7, //线宽
      lineJoin: "round",
      isOutline: true,
      showDir: true, //显示箭头  3D 模式下不支持
      borderWeight: 1,
      dirColor: "#fff",
      strokeStyle: "solid", //线样式
    };
    Object.assign(polylineStyle, options);
    this.clearTrajectory(); //每次绘制下一次轨迹前 先清除上一次轨迹
    // 路程总览
    const allPahtline = new AMap.Polyline({
      path: arrPath,
      showDir: true,
      strokeColor: "#1cac2e", //线颜色
      strokeWeight: 10, //线宽
    });
    this.aMap.add(allPahtline);
    this._overlaysMapObject.set("map-traj-all-polyline", allPahtline);
  }

  /**
   * 逆地理编码(地址 -> 坐标)
   * @param {*}geocoder 配置
   * @param {*}address 文本地址批量查询时字符串以逗号分开传入,最多20个
   * @param {*}successCollbackFn 成功后的信息的回调
   */
  public byAddressGetLocation(
    geoOptions: AMap.GeocoderOptions,
    address: string,
    successCollbackFn: (r: Regeocode[]) => void
  ): void {
    const geocoder = new AMap.Geocoder({
      extensions: "all",
      ...geoOptions,
    });
    //@ts-ignore
    geocoder.getLocation(address, (status, result: GeocodeResponse) => {
      if (status === "complete" && result.regeocodes) {
        successCollbackFn(result.regeocodes);
      } else {
        successCollbackFn([]);
      }
    });
  }

  /**
   * 逆地理编码(坐标 -> 地址)支持批量最多20
   * @param geoOptions geocoder 配置
   * @param location 二维的坐标数组,以批量的传入以及返回形式
   * @param successCollbackFn 成功后的信息的回调
   */
  public byLocationGetAddress(
    geoOptions: AMap.GeocoderOptions,
    location: AMap.Vector2[],
    successCollbackFn: (r: Regeocode[]) => void
  ): void {
    const geocoder = new AMap.Geocoder({
      radius: 1000,
      extensions: "all",
      ...geoOptions,
    });
    //经纬度转地址
    geocoder.getAddress(
      //@ts-ignore  //根据官方提供的类型存在问题 此处忽悠类型
      location,
      (status: string, result: GeocodeResponse) => {
        console.log(status);
        console.log(result);
        if (status === "complete" && result.regeocodes) {
          successCollbackFn(result.regeocodes);
        } else {
          successCollbackFn([]);
        }
      }
    );
  }

  /**
   * 清除轨迹相关的覆盖物
   */
  public clearTrajectory(): void {
    this._overlaysMapObject.forEach((overlay, key) => {
      if (key.includes("map-traj")) {
        if (
          overlay instanceof AMap.Marker &&
          overlay.getExtData() == "stopdrawGj"
        ) {
          overlay.stopMove(); //停止正在移动的轨迹
        }
        this.aMap.remove(overlay);
        this._overlaysMapObject.delete(key);
      }
    });
  }
  /**
   * 清除地图覆盖物(不包括轮廓),但包括停止轨迹
   */
  public clearMap(): void {
    this.aMap.clearInfoWindow();
    this._overlaysMapObject.forEach((overlay, key) => {
      if (
        overlay instanceof AMap.Marker &&
        overlay.getExtData() == "stopdrawGj"
      ) {
        overlay.stopMove(); //停止正在移动的轨迹
      }
      this.aMap.remove(overlay);
    });
    this._overlaysMapObject.clear();
    this.aMap.remove(this._polygonList); //清除多边形
  }
  /**
   * 对外暴露的获取地图对象方法
   * @returns {AMap.Map} 返回地图对象
   */
  public getAmapObj(): AMap.Map {
    return this.aMap;
  }

  // /**
  //  * 对高德坐标系进行转换
  //  * 全部统一转换为高德所需坐标系 gcj-02
  //  */

  // public formatCoordinateType(
  //   type: CoordinateType = this._AmapCoordinate,
  //   geoData: AllLocationDataType
  // ): AllLocationDataType {
  //   function getDataType(data: AllLocationDataType) {
  //     if(data){

  //     }
  //   }

  //   switch (type) {
  //     case "bd09":
  //       break;
  //     case "wgs84":
  //       break;
  //     case "gcj02":
  //       return geoData;
  //   }
  //   return geoData;
  // }
}

export function initMap(): Promise<typeof AMap> {
  return new Promise((resolve, reject) => {
    //如果全局已经存在AMap对象 则直接返回
    if (window.AMap) {
      resolve(window.AMap);
      return;
    }
    AMapLoader.load<typeof AMap>({
      key: "XXXX", // 申请好的Web端开发者Key,首次调用 load 时必填
      version: "2.0", // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
      plugins: [
        "AMap.MoveAnimation,AMap.MouseTool,AMap.PlaceSearch,AMap.DistrictSearch,AMap.Geocoder",
      ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
      // "AMapUI": { // 是否加载 AMapUI,缺省不加载
      //     "version": '1.1', // AMapUI 版本
      //     "plugins": [], // 需要加载的 AMapUI ui插件
      // },
      // "Loca": { // 是否加载 Loca, 缺省不加载
      //     "version": '2.0' // Loca 版本
      // },
    })
      .then((AMap) => {
        window.AMap = AMap;
        resolve(AMap); //防止上方全局添加amap失败手动返回Amap
      })
      .catch((e) => {
        console.error(e); //加载错误提示
        reject(e);
      });
  });
}
export default myMap;

vue代码:
<template>
  <div class="home" id="mapId">
    <div class="btnList">
      <el-button size="small" @click="addMark()">添加点位</el-button>
      <el-button size="small" @click="openMarkInfoWindow()"
        >点击点位打开信息窗体</el-button
      >
      <el-button size="small" @click="addMassMarks()">添加海量点</el-button>
      <el-button size="small" @click="startDrawRect()"
        >点击开始绘制围栏</el-button
      >
      <el-button size="small" @click="closeDrawRect()">结束绘制围栏</el-button>
      <el-button size="small" @click="fillRect()">填充绘制围栏</el-button>
      <el-button size="small" @click="currentMap.clearMap()"
        >清除地图覆盖物</el-button
      >
      <el-button size="small" @click="playMapTrajectory()"
        >开始绘制轨迹</el-button
      >
      <el-button size="small" @click="searchAddress()">地址查询</el-button>
      <el-button size="small" @click="getLocation()">获取坐标</el-button>
    </div>
    <div ref="elemntRef" class="InfoWindowClass" v-if="showInfoWindow">
      <div class="InfoWindowClass-header">
        <span>信息窗口标题{{ otherData.name }}</span>
        <span class="close-btn" @click="currentMap.closeInfoWindow()"></span>
      </div>
      <div class="InfoWindowClass-content">这里是信息窗口的内容区域...</div>
      <div class="InfoWindowClass-arrow"></div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import myMap from "@/utils/amap-utils";
import { onMounted, ref, nextTick } from "vue";

const elemntRef = ref();
const showInfoWindow = ref(false);
const otherData: any = ref({});

interface MassDataType {
  name: string;
  age: number;
}

let currentMap: myMap;
onMounted(() => {
  currentMap = new myMap();
  currentMap
    .init("mapId", { _AmapCoordinate: "gcj02" })
    .then((res) => {
      console.log("地图初始化成功", res);
      currentMap.setMapAreaOutline();
    })
    .catch((err) => {
      console.error("地图初始化失败", err);
    });
});

const addMark = () => {
  currentMap.addMarker({
    icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
    position: [121.698747, 31.12806],
    key: "mark1",
    title: "鼠标显示的内容",
    extData: {
      otherData: 111,
    },
    markClickFn: (e) => {
      console.log(e);
    },
  });
};

const openMarkInfoWindow = () => {
  currentMap.addMarker({
    icon: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
    position: [121.698652, 31.12706],
    key: "mark2",
    extData: {
      otherData: 111,
    },
    markClickFn: (e) => {
      showInfoWindow.value = true;
      nextTick(() => {
        currentMap.openInfoWindow({
          position: e.target.getPosition(),
          content: elemntRef.value,
          offset: new AMap.Pixel(0, -80), //信息窗体偏移量
        });
      });
    },
  });
};

const addMassMarks = () => {
  currentMap.addMassMarks<MassDataType>(
    [
      {
        lnglat: [121.698652, 31.12706],
        otherData: {
          name: "景县1111",
          age: 17,
        },
        style: 0,
      },
      {
        lnglat: [121.698421, 31.1212],
        otherData: {
          name: "景县2222",
          age: 17,
        },
        style: 1,
      },
      {
        lnglat: [121.694153, 31.12412],
        otherData: {
          name: "景县3333",
          age: 17,
        },
        style: 1,
      },
      {
        lnglat: [121.698121, 31.12711],
        otherData: {
          name: "景县4444",
          age: 17,
        },
        style: 0,
      },
      {
        lnglat: [121.698147, 31.124516],
        otherData: {
          name: "景县5555",
          age: 17,
        },
        style: 1,
      },
    ],
    {
      key: "mass1",
      style: [
        {
          url: "https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
          size: new AMap.Size(30, 30),
          rotation: 0,
        },
        {
          url: "https://webapi.amap.com/images/mass/mass1.png",
          size: new AMap.Size(30, 30),
          rotation: 0,
        },
      ],
      zIndex: 130,
      markClickFn: (e) => {
        console.log("海量点点击事件", e);
        otherData.value = e.data.otherData;
        showInfoWindow.value = true;
        nextTick(() => {
          currentMap.openInfoWindow({
            position: e.data.lnglat,
            content: elemntRef.value,
            offset: [15, 0],
          });
        });
      },
    }
  );
};

const startDrawRect = () => {
  currentMap.drawpolygon(
    {
      strokeColor: "#FF33FF", //线颜色
      fillColor: "#1791fc", //填充颜色
      strokeWeight: 3, //线宽
      fillOpacity: 0.2, //填充透明度
      zIndex: 100,
    },
    {
      nobatch: false,
      drawCompletedfn: (e: any) => {
        console.log("绘制完成回调", e);
        console.log(currentMap.getDrawedpolygon());
      },
    }
  );
};

const closeDrawRect = () => {
  currentMap.closeDrawpolygon();
};

const fillRect = () => {
  currentMap.setPolygonList([
    {
      path: [
        [121.568722, 31.317126],
        [121.65112, 31.317126],
        [121.64906, 31.28251],
        [121.566662, 31.286031],
      ],
    },
    {
      path: [
        [121.776895, 31.121916],
        [121.628117, 31.194152],
        [121.607861, 31.102773],
        [121.751026, 31.051903],
      ],
    },
  ]);
};

const playMapTrajectory = () => {
  const tdata: [number, number][] = [
    [121.5326, 31.17348],
    [121.5327, 31.1734],
    [121.5327, 31.1734],
    [121.5327, 31.17339],
    [121.5327, 31.1734],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5327, 31.17338],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17337],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17336],
    [121.5326, 31.17335],
    [121.5326, 31.17335],
    [121.5326, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5327, 31.17335],
    [121.5326, 31.17335],
    [121.5327, 31.17332],
    [121.533, 31.1731],
    [121.533, 31.173],
    [121.5336, 31.17312],
    [121.5344, 31.17336],
    [121.5255, 31.16332],
    [121.5267, 31.16382],
    [121.5278, 31.16425],
    [121.5292, 31.1647],
    [121.5305, 31.16506],
    [121.5316, 31.16553],
    [121.5321, 31.16562],
    [121.5322, 31.16532],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.1653],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5322, 31.16529],
    [121.5323, 31.16524],
    [121.5326, 31.16475],
    [121.5328, 31.1644],
    [121.5328, 31.16429],
    [121.5331, 31.16372],
    [121.5334, 31.16321],
    [121.5335, 31.16302],
    [121.5335, 31.1627],
    [121.5328, 31.16236],
    [121.532, 31.162],
    [121.5311, 31.16157],
    [121.5308, 31.16145],
    [121.5307, 31.16146],
    [121.5307, 31.16147],
    [121.5307, 31.16147],
    [121.5307, 31.16147],
    [121.5307, 31.16146],
    [121.5307, 31.16146],
    [121.5307, 31.16146],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16148],
    [121.5307, 31.16146],
    [121.5304, 31.16122],
    [121.5303, 31.16122],
    [121.5303, 31.16123],
    [121.5302, 31.16115],
    [121.5299, 31.16081],
    [121.5304, 31.16002],
    [121.531, 31.15898],
    [121.5311, 31.15876],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5311, 31.15875],
    [121.5312, 31.1586],
    [121.5315, 31.1581],
    [121.532, 31.1572],
    [121.5326, 31.15606],
    [121.533, 31.15545],
    [121.5327, 31.15534],
    [121.5325, 31.15534],
    [121.5325, 31.15536],
    [121.5325, 31.15538],
    [121.5325, 31.15537],
    [121.5325, 31.15537],
    [121.5325, 31.15537],
    [121.5325, 31.15535],
    [121.5325, 31.15535],
    [121.5325, 31.15533],
    [121.5326, 31.15533],
    [121.5326, 31.15531],
    [121.5324, 31.15527],
    [121.5316, 31.15508],
    [121.5308, 31.15487],
    [121.5305, 31.15475],
    [121.5305, 31.15473],
    [121.5303, 31.15461],
    [121.5295, 31.15433],
    [121.5289, 31.15353],
    [121.5293, 31.15257],
    [121.5297, 31.15203],
    [121.5297, 31.15202],
    [121.5297, 31.15202],
    [121.5297, 31.15201],
    [121.5297, 31.15168],
    [121.5299, 31.15163],
  ];
  // currentMap.drawEasyrajectory(tdata);
  currentMap.drawTrajectory(tdata);
};

const searchAddress = () => {
  currentMap.byLocationGetAddress(
    {
      city: "上海",
    },
    [[121.5326, 31.17348]],
    (r) => {
      console.log(r);
    }
  );
};

const getLocation = () => {
  currentMap.byAddressGetLocation(
    {
      city: "上海",
    },
    "上海市浦东新区",
    (r) => {
      console.log(r);
    }
  );
};
</script>
<style lang="less" scoped>
.border {
  border: 1px solid red;
  box-sizing: border-box;
}
// 基础信息窗样式
.InfoWindowClass {
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  z-index: 1000;
  width: 300px;
  // 头部区域样式
  &-header {
    padding: 12px 16px;
    border-bottom: 1px solid #e8e8e8;
    position: relative;

    // 关闭按钮样式
    .close-btn {
      position: absolute;
      top: 12px;
      right: 12px;
      width: 16px;
      height: 16px;
      cursor: pointer;
      color: #999;
      font-size: 14px;
      line-height: 14px;

      &:hover {
        color: #333;
      }

      &:before,
      &:after {
        content: "";
        position: absolute;
        width: 16px;
        height: 2px;
        background-color: currentColor;
        top: 50%;
        left: 0;
        transform: translateY(-50%);
      }

      &:before {
        transform: translateY(-50%) rotate(45deg);
      }

      &:after {
        transform: translateY(-50%) rotate(-45deg);
      }
    }
  }

  // 内容区域样式
  &-content {
    padding: 16px;
    font-size: 14px;
    line-height: 1.5;
  }

  // 底部箭头样式
  &-arrow {
    position: absolute;
    bottom: -7px;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 12px solid transparent;
    border-right: 12px solid transparent;
    border-top: 12px solid #fff;
    border-bottom: 0;
    z-index: 1;

    // // 阴影增强立体感
    // &:after {
    //   content: "";
    //   position: absolute;
    //   top: 1px;
    //   left: -12px;
    //   width: 0;
    //   height: 0;
    //   border-left: 12px solid transparent;
    //   border-right: 12px solid transparent;
    //   border-top: 12px solid rgba(0, 0, 0, 0.2);
    //   border-bottom: 0;
    //   z-index: -1;
    // }
  }
}
.home {
  position: relative;
  width: 100vw;
  height: 100vh;
  .btnList {
    position: absolute;
    top: 0;
    left: 0;
    width: 150px;
    height: 250px;
    z-index: 10;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    background-color: rgb(211, 201, 187);
    align-items: center;
  }
  .el-button + .el-button {
    margin-left: 0;
  }
}
</style>

后续若有其他未实现的方法 亦可自行添加即可

相关推荐
吹牛不交税9 分钟前
Axure RP Extension for Chrome插件安装使用
前端·chrome·axure
薛定谔的算法25 分钟前
# 前端路由进化史:从白屏到丝滑体验的技术突围
前端·react.js·前端框架
拾光拾趣录1 小时前
Element Plus表格表头动态刷新难题:零闪动更新方案
前端·vue.js·element
Adolf_19932 小时前
React 中 props 的最常用用法精选+useContext
前端·javascript·react.js
前端小趴菜052 小时前
react - 根据路由生成菜单
前端·javascript·react.js
喝拿铁写前端2 小时前
`reduce` 究竟要不要用?到底什么时候才“值得”用?
前端·javascript·面试
空の鱼2 小时前
js与vue基础学习
javascript·vue.js·学习
鱼樱前端2 小时前
2025前端SSR框架之十分钟快速上手Nuxt3搭建项目
前端·vue.js
極光未晚2 小时前
React Hooks 中的时空穿梭:模拟 ComponentDidMount 的奇妙冒险
前端·react.js·源码
Codebee2 小时前
OneCode 3.0 自治UI 弹出菜单组件功能介绍
前端·人工智能·开源