高德地图2.0 绘制、编辑多边形覆盖物(电子围栏)

在这里插入图片描述

1. 安装

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

移步:官方文档

2. map组件封装

<script lang="ts" setup>
import AMapLoader from '@amap/amap-jsapi-loader'
import { onMounted, ref } from 'vue'
import { propTypes } from '@/utils/propTypes'

defineOptions({ name: 'Map' })

const props = defineProps({
  bindId: propTypes.string.def('mapContainer'),
  modelValue: propTypes.array.def([]),
  title: propTypes.string.def(''),
  width: propTypes.string.def('100%'),
  height: propTypes.string.def('600px'),
  polygonPaths: propTypes.array.def([]), // 回显多边形路径 得是<nubmer[]>类型,不然无法编辑
  districtCode: propTypes.string.def('140101') // 行政区划代码
})

watch(
  () => props.districtCode,
  (newVal, oldVal) => {
    if (newVal !== oldVal) {
      drawBounds()
    }
  }
)

window._AMapSecurityConfig = {
  securityJsCode: '4e6ca573a89ac3176f29813d3fcc895e'
}
const mouseTool = ref()
const mapRef = ref(null)
const overlays = ref<object[]>([])
const polyEditor = ref<any>()
const district = ref<any>()
const AMapObj = ref<any>()

// 新建
const createPolygon = () => {
  polyEditor.value.close()
  polyEditor.value.setTarget()
  polyEditor.value.open()
}

const emits = defineEmits(['update:modelValue'])
//获取
const getPolygon = () => {
  let overlays = mapRef.value?.getAllOverlays('polygon')
  let polygonPaths = overlays.map((overlay: any) => overlay.getPath())
  polygonPaths.shift() // 去掉第一个多边形
  console.log('🚀 ~ getPolygon ~ polygonPaths:', polygonPaths)
  const paths: object[] = []
  polygonPaths.forEach((item: any) => {
    const pathItem = item.map((cItem: any) => {
      const lnglat = `${cItem.lng},${cItem.lat}`
      return lnglat
    })
    paths.push(pathItem)
  })
  emits('update:modelValue', paths)
}

defineExpose({ getPolygon })

//清除绘制的多边形
const clearPolygon = () => {
  try {
    closeEditor()
    mapRef.value?.clearMap()
    drawBounds()
  } catch (e) {
    console.log(e)
  }
}

// 开启编辑
const openEditor = () => {
  if (polyEditor.value) {
    polyEditor.value.open()
  }
}

// 关闭编辑
const closeEditor = () => {
  if (polyEditor.value) {
    polyEditor.value.close()
  }
}

//加载行政区划插件
const drawBounds = () => {
  if (!district.value) {
    //实例化DistrictSearch
    var opts = {
      subdistrict: 0, //获取边界不需要返回下级行政区
      extensions: 'all', //返回行政区边界坐标组等具体信息
      level: 'district' //查询行政级别为 市
    }
    district.value = new AMap.DistrictSearch(opts)
  }
  //行政区查询
  district.value.setLevel('district')
  var keyword = props.districtCode
  if (keyword === '') {
    console.warn('行政区划不能为空')
    return
  }
  let polygon = null
  district.value.search(keyword, function (status, result) {
    if (polygon) {
      mapRef.value?.remove(polygon) //清除上次结果
      polygon = null
    }
    if (!result || !result.districtList || !result.districtList[0]) {
      console.warn('请正确填写名称或更新其他名称')
      return
    }
    var bounds = result.districtList[0].boundaries
    if (bounds) {
      //生成行政区划polygon
      for (var i = 0; i < bounds.length; i += 1) {
        //构造MultiPolygon的path
        bounds[i] = [bounds[i]]
      }
      polygon = new AMap.Polygon({
        path: bounds,
        strokeColor: '#F56C6C',
        strokeWeight: 4,
        fillOpacity: 0.1,
        fillColor: '#F56C6C',
        strokeStyle: 'dashed',
        strokeDasharray: [12, 3],
        zIndex: 0
      })
      mapRef.value?.add(polygon)
      mapRef.value?.setFitView(polygon) //视口自适应
    }
  })
}

// 编辑事件处理
const editPolygon = () => {
  polyEditor.value.on('add', function (data) {
    var polygon = data.target
    polyEditor.value.addAdsorbPolygons(polygon)
    polygon.on('dblclick', (e) => {
      polyEditor.value.setTarget(polygon)
      polyEditor.value.open()
    })
  })
  // polyEditor.value.on('adjust', function (data) {
  //   console.log('🚀 ~ polyEditor-adjust', data)
  // })
  // polyEditor.value.on('addnode', function (data) {
  //   console.log('🚀 ~ polyEditor-addnode', data)
  // })
  // polyEditor.value.on('end', function (data) {
  //   console.log('🚀 ~ polyEditor-end', data)
  // })
}

// 回显多边形
const showPolygon = (polygonArr: any) => {
  // const polygonArr = [[116.368904, 39.913423], [116.382122, 39.901176],[116.387271, 39.912501],[116.398258, 39.9046]]
  const polygon = new AMap.Polygon({
    path: polygonArr,
    strokeColor: '#1791fc',
    strokeOpacity: 0.9,
    strokeWeight: 4,
    fillColor: '#1791fc',
    fillOpacity: 0.3,
    strokeStyle: 'solid', //solid, 线样式还支持 'dashed',
    strokeDasharray: [12, 4], // strokeStyle是dashed时有效
    zIndex: 16
  })
  // polygon.on('click', (e) => {
  //   console.log('🚀 ~ polygon.on ~ e:', e)
  // })
  mapRef.value?.add(polygon)
  polyEditor.value.addAdsorbPolygons([polygon])
  polygon.on('dblclick', () => {
    polyEditor.value.setTarget(polygon)
    polyEditor.value.open()
  })
  mapRef.value?.setFitView(polygon) //视口自适应
}

// defineExpose({ showPolygon })

// 加载高德地图
const loader = () => {
  AMapLoader.load({
    key: '947ec8e0b6869f9ef9fc6badda641a06',
    version: '2.0', // 使用合适的版本
    plugins: ['AMap.Scale', 'AMap.MouseTool', 'AMap.PolygonEditor', 'AMap.DistrictSearch']
  })
    .then((AMap) => {
      AMapObj.value = AMap
      // 初始化地图
      mapRef.value = new AMap.Map(props.bindId, {
        zoom: 15,
        center: [116.397428, 39.90923] // 设置地图中心点
      })
      // 加载行政区划插件
      drawBounds()
      // 编辑事件处理
      polyEditor.value = new AMap.PolygonEditor(mapRef.value)
      editPolygon()
      // 回显保存的多边形
      props.polygonPaths.forEach((item: any) => {
        showPolygon(item)
      })

      mapRef.value?.on('click', (e) => {
        console.log('🚀 ~ mapRef.value.on ~ e:', e)
      })
    })
    .catch((error) => {
      console.error('加载高德地图失败', error)
    })
}

onMounted(() => {
  loader()
})
</script>

<template>
  <div class="mb-14px">
    <el-button @click="createPolygon" type="primary">新建</el-button>
    <!-- <el-button @click="openEditor" type="primary">编辑</el-button> -->
    <el-button @click="closeEditor" type="primary">关闭编辑</el-button>
    <el-button @click="clearPolygon" type="danger" plain>清空</el-button>
    <!-- <el-button @click="getPolygon" type="primary">获取</el-button> -->
  </div>

  <div :id="props.bindId" :style="{ width: width, height: height }"></div>
</template>

3. 使用组件

<template>
  <el-drawer v-model="drawer2" :direction="direction" size="75%" :show-close="false">
    <template #header>
      <div>
        <div
          class="w-full flex items-center justify-between border-b border-b-[var(--el-border-color)] border-b-solid pb14px"
        >
          <div class="font-size-4">服务区域</div>
          <el-button type="primary" @click="close" size="small" circle>
            <Icon icon="ep:close-bold" :size="16" @click="cancelClick" />
          </el-button>
        </div>
      </div>
    </template>
    <template #default>
      <div class="flex items-center justify-center pb30px font-size-15px color-#666">
        起始地: {{ curRow.startDistrictName }}
        <el-icon class="mx-20px"><Switch /></el-icon>
        目的地: {{ curRow.endDistrictName }}
      </div>
      <div class="flex justify-center">
        <div class="mx-10px w-50%">
          <div>
            <Map
              bindId="startMap"
              v-model:modelValue="startPolygonPaths"
              v-if="drawer2"
              ref="StartMapRef"
              :polygonPaths="startDetailPaths"
              :districtCode="curRow.startDistrictCode"
            />
          </div>
        </div>
        <div class="mx-10px w-50%">
          <div>
            <Map
              bindId="endMap"
              v-model:modelValue="endPolygonPaths"
              v-if="drawer2"
              ref="EndMapRef"
              :polygonPaths="endDetailPaths"
              :districtCode="curRow.endDistrictCode"
            />
          </div>
        </div>
      </div>
    </template>
    <template #footer>
      <div style="flex: auto">
        <el-button @click="cancelClick">取消</el-button>
        <el-button type="primary" @click="confirmClick">确认</el-button>
      </div>
    </template>
  </el-drawer>
</template>

<script lang="ts" setup>
import { Switch } from '@element-plus/icons-vue'
import { ref, nextTick } from 'vue'
import { Map } from '@/components/Map/index'
import { getLinesServiceAreaList, saveLinesServiceArea } from '@/api/routeManage/routeList/index.ts'
const drawer2 = ref(false)
const direction = ref('rtl')
const curRow = ref<object>({})
const dcistrictCode = ref('')
const startPolygonPaths = ref([])
const endPolygonPaths = ref([])
const startDetailPaths = ref([])
const endDetailPaths = ref([])
const message = useMessage()

// 打开推窗
const open = async (row) => {
  curRow.value = row
  await getDetail()
  drawer2.value = true
}
defineExpose({ open })

const StartMapRef = ref(null)
const EndMapRef = ref(null)
const getDetail = async () => {
  const params = {...}
  try {
    const data = await getLinesServiceAreaList(params)
	...
    startDetailPaths.value =[[112.557711,37.731122],[112.625256,37.734871],[112.558896,37.680496],[112.558896,37.680496]]
    endDetailPaths.value = [[112.676067,36.378644],[112.79624,36.385946],[112.732752,36.29097],[112.732752,36.29097]]
  } finally {
  }
}

// 获取起点数据
const getStartData = () => {
  const linesServiceAreaList = startPolygonPaths.value.map((item) => {
    if (item) {
      return { areaType: 1, pointList: item }
    }
  })
  return linesServiceAreaList || []
}

// 获取终点数据
const getEndData = () => {
  const linesServiceAreaList = endPolygonPaths.value.map((item) => {
    if (item) {
      return { areaType: 1, pointList: item }
    }
  })
  return linesServiceAreaList || []
}

const confirmClick = async () => {
  await StartMapRef.value?.getPolygon()
  await EndMapRef.value?.getPolygon()
  const params = {areaList: [...getStartData(), ...getEndData()]}
  try {
    await saveLinesServiceArea(params)
    message.success('保存成功')
  } finally {
    drawer2.value = false
  }
}

function cancelClick() {
  drawer2.value = false
}
</script>

### 高德地图API多边形绘制与数据采集方法 在高德地图中进行多边形绘制和数据采集是一项重要的功能,尤其对于地理信息系统(GIS)应用来说。通过调用高德地图JavaScript API中的`AMap.PolygonEditor`类[^2],开发者可以在地图上动态创建并编辑多边形。 #### 创建多边形对象 要开始一个多边形绘制工作,首先要实例化一个Polygon对象: ```javascript var polygon = new AMap.Polygon({ strokeColor: "#FF33FF", strokeWeight: 6, strokeOpacity: 0.2, fillOpacity: 0.4, fillColor: '#1791fc', zIndex: 50 }); ``` 此代码片段设置了新多边形的一些基本样式属性,比如线条颜色(`strokeColor`)、宽度(`strokeWeight`)以及填充色(`fillColor`)等参数。 #### 启用多边形编辑器 为了让用户能够交互式地调整已有的多边形形状或者新增节点来完成新的区域划定,则需启用PolygonEditor工具: ```javascript // 初始化编辑器 var editor = new AMap.PolygonEditor(map, polygon); // 开启编辑模式 editor.open(); ``` 上述命令会激活多边形编辑状态,在这种状态下允许拖拽顶点改变位置或是点击边界线添加额外控制点以扩展图形范围。 #### 获取多边形坐标集 当完成了满意的多边形构建之后,可以通过访问polygon.getPath()方法获得该几何体所对应的经纬度数组表示形式,这些信息可用于后续的数据处理或存储操作。 ```javascript console.log(polygon.getPath()); ``` 这一步骤非常重要因为它提供了精确的空间描述供其他业务逻辑使用,例如计算面积大小、判断某地点是否位于指定区域内等问题求解的基础资料输入。 #### 数据保存与管理 一旦获取到了完整的多边形路径数据,就可以考虑将其持久化到服务器端数据库或者其他任何形式适合长期保持的地方去。通常情况下还会涉及到版本控制系统以便追踪历史变更记录,并确保团队成员之间协作顺畅无误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1234Wu

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值