高德地图添加圆标记及编辑圆

接到一个需求,需要实现在地图上标记一些打卡范围点,需要能够编辑范围的大小以及坐标,开始对这个需求有点蒙,去找了高德地图的各种示例才有了思路,最后开干。
在这里插入图片描述

一、准备

1.申请 key 和安全密钥,点击 高德操作文档

2.安装所需包

npm i @amap/amap-jsapi-loader --save

3.高德使用示例及文档链接

https://lbs.amap.com/api/javascript-api-v2/guide/abc/amap-vue

二、画圆(添加圆标记)

1.JS API 的加载和地图初始化

使用 JS API Loader 来加载,引入在控制台申请的 key安全密钥

<template>  
<div id="mapContainer"></div>
</template>

<script setup lang="ts">

  let map = null    //地图容器
   const polyEditor = ref(null)  //当前编辑的矢量图
  const polygonPaths = ref([])  //编辑后的多边形对象
  const polygonList = ref([])  //绘制的矢量图数组

  const inspectionRouteList = ref([]);//巡查点数组,从后端获取
  
  const initMap = () => {//初始化地图
    window._AMapSecurityConfig = {
      securityJsCode: '你申请的应用密钥',
    }
    AMapLoader.load({
      key: "你申请的应用Key", // 申请好的Web端开发者Key,首次调用 load 时必填
      version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: ["AMap.CircleEditor"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
    }).then((AMap) => {
      map = new AMap.Map("mapContainer", {
        // 设置地图容器id
        viewMode: "3D", // 是否为3D地图模式
        zoom: 17, // 初始化地图级别
        center: [105.31082153320312, 27.29510506985128],//初始化地图中心点位置 props.coordinate
      });
      initPatroMap()//添加圆标记的方法
    }).catch((e) => {
      console.log(e);
    });
  }
  //页面渲染完成调用初始化
   onMounted(() => {
    initMap()
  });
</script>
2.添加圆标记
 const initPatroMap = () => {//添加圆标记
    polyEditor.value?.close()//先把当前编辑的对象关闭
    map.clearMap()
    polyEditor.value = null
    polygonList.value = []
    inspectionRouteList.value.forEach((item, index) => {
      var polygon = null
      polygon = new AMap.Circle({
        center: item.coordinate.split(","),
        radius: item.radius ? item.radius : 50, //半径
        borderWeight: 3,
        strokeColor: '#1791fc',
        strokeOpacity: 1,
        strokeWeight: 1,
        fillOpacity: 0.4,
        strokeStyle: 'dashed',
        strokeDasharray: [10, 10],
        // 线样式还支持 'dashed'
        fillColor: '#1791fc',
        zIndex: 50,
        visible: true
      })
      polygon.on("click", () => {//注册圆的点击事件,点击的时候显示编辑
        polyEditor.value?.close()
        editPoly(index)
      })
      polygonList.value.push(polygon)
    })
    map.add(polygonList.value);

  }

三、编辑圆

 // 选择某一行的巡查点
  const handleSelectPatro = (row) => {
    var i = row.index
    polyEditor.value?.close()
    editPoly(i)
  }

  // 开始编辑某个圆
  const editPoly = (i) => {
    let patroItem = inspectionRouteList.value[i]
    let opts = {
      movePoint: {//编辑圆时圆心显示的内容
        draggable: true,//是否可拖动
        label: {
          content: patroItem.name,
          offset: new AMap.Pixel(0, 0),
          direction: 'right'
        }
      },
      // resizePoint:{draggable: true}
    }
    if (polygonList.value.length > 0) {
      polyEditor.value = new AMap.CircleEditor(map, polygonList.value[i], opts)
    } else {
      polyEditor.value = new AMap.CircleEditor(map)
    }
    polyEditor.value.open()

    //关闭多边形编辑polygonEditor.close()触发该方法;
    polyEditor.value.on('adjust', async (event) => {
      inspectionRouteList.value[i].radius = event.radius
      inspectionRouteList.value[i].coordinate = event.lnglat.lng + "," + event.lnglat.lat
      console.log('inspection' + i, inspectionRouteList.value[i]);
      // 调用接口修改
      await updateInspectionRoute(inspectionRouteList.value[i])
        .catch(async (err) => {
          await getList()
          initPatroMap()
        })
        .finally(() => buttonLoading.value = false);
    })
    // 移动触发事件
    polyEditor.value.on('move', async (event) => {
      // inspectionRouteList.value[i].radius=event.radius
      inspectionRouteList.value[i].coordinate = event.lnglat.lng + "," + event.lnglat.lat
      // 调用接口修改
      await updateInspectionRoute(inspectionRouteList.value[i])
        .catch(async (err) => {
          await getList()
          initPatroMap()
        })
        .finally(() => buttonLoading.value = false);
    })

  }

四、完整示例

<template>
  <div id="mapContainer"></div>
  <div class="search" v-show="showSearch">
    <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="auto">
      <el-form-item label="巡逻点名称" prop="name">
        <el-input v-model="queryParams.name" placeholder="请输入巡逻点名称" clearable style="width: 240px"
          @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="NFC编码" prop="code">
        <el-input v-model="queryParams.code" placeholder="请输入NFC编码" clearable style="width: 240px"
          @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
  </div>

  <el-card shadow="never">
    <template #header>
      <el-row :gutter="10" class="mb2">
        <el-col :span="1.5">
          <el-button type="primary" plain icon="Plus" @click="handleAdd"
            v-auth="['campus:inspectionRoute:add']">新增</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
            v-auth="['campus:inspectionRoute:edit']">修改</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
            v-auth="['campus:inspectionRoute:remove']">删除</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button type="warning" plain icon="Download" @click="handleExport"
            v-auth="['campus:inspectionRoute:export']">导出</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button type="success" plain icon="Check" @click="polyEditor?.close()"
            v-auth="['campus:inspectionRoute:edit']">完成修改</el-button>
        </el-col>
        <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
      </el-row>
    </template>

    <el-table v-loading="loading" :data="inspectionRouteList" @selection-change="handleSelectionChange"
      :row-class-name="tableRowClassName">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="巡逻点名称" align="center" prop="name" />
      <el-table-column label="中心点坐标" align="center" prop="coordinate" />
      <el-table-column label="半径(米)" align="center" prop="radius" />
      <el-table-column label="NFC编码" align="center" prop="code" />

      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template #default="scope">
          <el-button size="small" type="primary" @click="handleUpdate(scope.row)"
            v-auth="['campus:inspectionRoute:edit']">修改信息</el-button>
          <el-tooltip effect="dark" content="拖动白点或圆心进行修改" placement="top-start">
            <el-button size="small" type="primary" @click="handleSelectPatro(scope.row)"
              v-auth="['campus:inspectionRoute:edit']">修改范围</el-button>
          </el-tooltip>
          <el-button size="small" type="danger" @click="handleDelete(scope.row)"
            v-auth="['campus:inspectionRoute:remove']">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
      @pagination="getList" />
  </el-card>
  <!-- 点击地图的弹出层 -->
  <el-dialog title="获取巡更点经纬度" v-model="mapShow" width="50%" @close="false" center destroy-on-close>
    <AddPatrolMap @mapClick="mapClick" />
  </el-dialog>
  <!-- 添加或修改巡更点对话框 -->
  <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
    <el-form ref="inspectionRouteFormRef" :model="form" :rules="rules" label-width="auto">
      <el-form-item label="巡逻点名称" prop="name">
        <el-input v-model="form.name" placeholder="请输入巡逻点名称" />
      </el-form-item>
      <!-- 		<el-form-item label="坐标经纬度" prop="coordinate">
					<template #default="scope">
						<div>
							<el-input v-model="form.coordinate" placeholder="请输入坐标经纬度" />
							<el-button @click="mapShow = true">打开地图获取</el-button>
						</div>
					</template>
				</el-form-item> -->
      <el-form-item label="NFC编码" prop="code">
        <el-input v-model="form.code" placeholder="请输入NFC编码" />
      </el-form-item>
      <!-- <el-form-item label="二维码图片地址" prop="qrCode">
					<image-upload v-model="form.qrCode" />
				</el-form-item> -->
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup name="InspectionRoute" lang="ts">
  import {
    addInspectionRoute,
    getInspectionRoute,
    listInspectionRoute,
    updateInspectionRoute,
    delInspectionRoute
  } from '@/api/campus/inspectionRoute';
  import AddPatrolMap from "@/components/Map/addPatrolMap.vue";
  import { download as fileDownload } from '@/api/index'
  import AMapLoader from '@amap/amap-jsapi-loader';

  let map = null    //地图容器

  const { proxy } = getCurrentInstance() as ComponentInternalInstance;


  const polyEditor = ref(null)  //当前编辑的矢量图
  const polygonPaths = ref([])  //编辑后的多边形对象
  const polygonList = ref([])  //绘制的矢量图数组

  const inspectionRouteList = ref(//巡查点数组,从后端获取
  []);
  const buttonLoading = ref(false);
  const loading = ref(true);
  const showSearch = ref(true);
  const ids = ref([]);
  const single = ref(true);
  const multiple = ref(true);
  const total = ref(0);
  const coordinate = ref('');
  const mapShow = ref(false);

  const queryFormRef = ref();
  const inspectionRouteFormRef = ref();

  const dialog = reactive({
    visible: false,
    title: ''
  });

  const initFormData = {
    id: undefined,
    name: undefined,
    coordinate: "105.308322,27.293105",//新增时的默认坐标
    code: undefined,
    qrCode: undefined,
    radius: 50
  }
  const data = reactive({
    form: { ...initFormData },
    queryParams: {
      pageNum: 1,
      pageSize: 10,
      name: undefined,
      coordinate: undefined,
      code: undefined,
      qrCode: undefined,
      params: {
      }
    },
    rules: {
      id: [
        { required: true, message: "主键不能为空", trigger: "blur" }
      ],
      name: [
        { required: true, message: "巡逻点名称不能为空", trigger: "blur" }
      ],
      coordinate: [
        { required: true, message: "坐标经纬度不能为空", trigger: "blur" }
      ],
      code: [
        { required: true, message: "NFC编码不能为空", trigger: "blur" }
      ]
    }
  });

  const { queryParams, form, rules } = toRefs(data);

  /** 查询巡更点列表 */
  const getList = async () => {
    loading.value = true;
    const res = await listInspectionRoute(queryParams.value);
    inspectionRouteList.value = res.rows;
    total.value = res.total;
    loading.value = false;
  }

  const mapClick = (e) => {
    form.value.coordinate = e;
    mapShow.value = false;
  }

  /** 取消按钮 */
  const cancel = () => {
    reset();
    dialog.visible = false;
  }

  /** 表单重置 */
  const reset = () => {
    form.value = { ...initFormData };
    inspectionRouteFormRef.value?.resetFields();
  }

  /** 搜索按钮操作 */
  const handleQuery = () => {
    queryParams.value.pageNum = 1;
    getList();
  }

  /** 重置按钮操作 */
  const resetQuery = () => {
    queryFormRef.value?.resetFields();
    handleQuery();
  }

  /** 多选框选中数据 */
  const handleSelectionChange = (selection) => {
    ids.value = selection.map(item => item.id);
    single.value = selection.length != 1;
    multiple.value = !selection.length;
  }

  /** 新增按钮操作 */
  const handleAdd = () => {
    dialog.visible = true;
    dialog.title = "添加巡更点";
    nextTick(() => {
      reset();
    });
  }

  /** 修改按钮操作 */
  const handleUpdate = (row) => {
    loading.value = true
    dialog.visible = true;
    dialog.title = "修改巡更点";
    nextTick(async () => {
      reset();
      const _id = row?.id || ids.value[0]
      const res = await getInspectionRoute(_id);
      loading.value = false;
      Object.assign(form.value, res.data);
    });
  }

  /** 提交按钮 */
  const submitForm = () => {
    inspectionRouteFormRef.value?.validate(async (valid : boolean) => {
      if (valid) {
        buttonLoading.value = true;
        if (form.value.id) {
          await updateInspectionRoute(form.value).finally(() => buttonLoading.value = false);
        } else {
          await addInspectionRoute(form.value).finally(() => buttonLoading.value = false);
        }
        proxy?.$modal.msgSuccess("操作成功");
        dialog.visible = false;
        await getList();
        initPatroMap()
      }
    });
  }

  /** 删除按钮操作 */
  const handleDelete = async (row) => {
    const _ids = row?.id || ids.value;

    await proxy?.$modal.confirm('是否确认删除巡更点"' + row?.name + '"?').finally(() => loading.value = false);
    await delInspectionRoute(_ids);
    proxy?.$modal.msgSuccess("删除成功");
    await getList();
    initPatroMap()
  }

  /** 导出按钮操作 */
  const handleExport = () => {
    fileDownload('campus/inspectionRoute/export', {
      ...queryParams.value
    }, `inspectionRoute_${new Date().getTime()}.xlsx`)
  }
  const tableRowClassName = ({ row, rowIndex }) => {
    row.index = rowIndex;
  }
  // 选择某一行的巡查点
  const handleSelectPatro = (row) => {
    var i = row.index
    polyEditor.value?.close()
    editPoly(i)
  }

  // 开始编辑某个圆
  const editPoly = (i) => {
    let patroItem = inspectionRouteList.value[i]
    let opts = {
      movePoint: {
        draggable: true,
        label: {
          content: patroItem.name,
          offset: new AMap.Pixel(0, 0),
          direction: 'right'
        }
      },
      // resizePoint:{draggable: true}
    }
    if (polygonList.value.length > 0) {
      polyEditor.value = new AMap.CircleEditor(map, polygonList.value[i], opts)
    } else {
      polyEditor.value = new AMap.CircleEditor(map)
    }
    polyEditor.value.open()

    //关闭多边形编辑polygonEditor.close()触发该方法;
    polyEditor.value.on('adjust', async (event) => {
      inspectionRouteList.value[i].radius = event.radius
      inspectionRouteList.value[i].coordinate = event.lnglat.lng + "," + event.lnglat.lat
      console.log('inspection' + i, inspectionRouteList.value[i]);
      // 调用接口修改
      await updateInspectionRoute(inspectionRouteList.value[i])
        .catch(async (err) => {
          await getList()
          initPatroMap()
        })
        .finally(() => buttonLoading.value = false);
    })
    // 移动触发事件
    polyEditor.value.on('move', async (event) => {
      // inspectionRouteList.value[i].radius=event.radius
      inspectionRouteList.value[i].coordinate = event.lnglat.lng + "," + event.lnglat.lat
      // 调用接口修改
      await updateInspectionRoute(inspectionRouteList.value[i])
        .catch(async (err) => {
          await getList()
          initPatroMap()
        })
        .finally(() => buttonLoading.value = false);
    })

  }

  const initPatroMap = () => {
    polyEditor.value?.close()
    map.clearMap()
    polyEditor.value = null
    polygonList.value = []
    inspectionRouteList.value.forEach((item, index) => {
      var polygon = null
      polygon = new AMap.Circle({
        center: item.coordinate.split(","),
        radius: item.radius ? item.radius : 50, //半径
        borderWeight: 3,
        strokeColor: '#1791fc',
        strokeOpacity: 1,
        strokeWeight: 1,
        fillOpacity: 0.4,
        strokeStyle: 'dashed',
        strokeDasharray: [10, 10],
        // 线样式还支持 'dashed'
        fillColor: '#1791fc',
        zIndex: 50,
        visible: true
      })
      polygon.on("click", () => {
        polyEditor.value?.close()
        editPoly(index)
      })
      polygonList.value.push(polygon)
    })
    map.add(polygonList.value);

  }

  const initMap = () => {
    window._AMapSecurityConfig = {
      securityJsCode: 'b9a0a661b101316ea7aea94f299f9e78',
    }
    AMapLoader.load({
      key: "190c5081f604474144a2b763642f9b37", // 申请好的Web端开发者Key,首次调用 load 时必填
      version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: ["AMap.CircleEditor"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
    }).then((AMap) => {
      map = new AMap.Map("mapContainer", {
        // 设置地图容器id
        viewMode: "3D", // 是否为3D地图模式
        zoom: 17, // 初始化地图级别
        center: [105.31082153320312, 27.29510506985128],//初始化地图中心点位置 props.coordinate
      });
      initPatroMap()
    }).catch((e) => {
      console.log(e);
    });
  }

  onMounted(async () => {
    await getList();
    initMap()
  });

  onUnmounted(() => {
    map?.destroy();
  });
</script>

<style lang='scss'>
  #mapContainer {
    width: 100%;
    height: 600px;
  }
</style>

效果
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2ab1a8d6bcba464c9d555f90854864c6.gif在这里插入图片描述

最后

这只是圆形范围的示例,可以做多边形的,更灵活,把添加和编辑圆的方法细化可以实现各种形状(圆,正方形,长方形,多边形)的标记和编辑,没精力搞了,靠大家去完善了。

高德地图添加标记点(Marker)可以通过以下步骤实现: 1. 引入高德地图 JavaScript API 在 HTML 文件中引入高德地图 JavaScript API,例如: ```html <script src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script> ``` 其中 `key` 值需要替换为您自己申请的高德地图开发者 Key。 2. 创建地图容器 在 HTML 文件中创建一个地图容器,例如: ```html <div id="mapContainer" style="width: 100%; height: 500px;"></div> ``` 该容器的宽度和高度可以根据实际需求进行调整。 3. 创建地图对象 在 JavaScript 中创建地图对象,并将其显示在地图容器中,例如: ```javascript var map = new AMap.Map('mapContainer', { center: [116.397428, 39.90923], zoom: 13 }); ``` 其中 `center` 表示地图的中心点坐标,`zoom` 表示地图的缩放级别。 4. 添加标记点 通过 `AMap.Marker` 类创建一个标记点对象,并设置其位置、图标等属性,例如: ```javascript var marker = new AMap.Marker({ position: [116.397428, 39.90923], icon: 'https://webapi.amap.com/images/marker_sprite.png' }); ``` 其中 `position` 表示标记点的位置坐标,`icon` 表示标记点的图标。如果不设置图标,则默认使用高德地图提供的红色图钉样式。 5. 将标记添加地图中 通过 `AMap.Map` 对象的 `add` 方法将标记添加地图中,例如: ```javascript map.add(marker); ``` 完成以上步骤后,您就可以在高德地图中看到一个带有标记点的地图了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值