【天地图-点线面最全功能】天地图实现功能:回显、绘制、编辑、删除任意点线面

实现效果图

实现功能

1. 回显点线面数据
2. 绘制点线面,保存可获取点线面数据
3. 编辑点线面,保存可获取最新编辑后的点线面数据
4. 删除任意点线面(解决删除按钮不能随元素位置变化(地图拖拽/放大缩小时)而变化问题->地图放大缩小拖动时处理删除按钮消失)

完整代码:

bash 复制代码
<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <title>回显、绘制、编辑、删除任意点线面</title>
  <script src="http://api.tianditu.gov.cn/api?v=4.0&amp;tk=应用KEY值"
    type="text/javascript"></script>
  <style type="text/css">
    body,
    html {
      width: 100%;
      height: 100%;
      margin: 0;
      font-family: '微软雅黑';
    }

    #map {
      height: 400px;
      width: 100%;
    }

    input {
      margin-top: 10px;
      margin-left: 5px;
      font-size: 14px;
    }

    #contextMenu {
      position: absolute;
      background: white;
      border: 1px solid #ccc;
      box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.2);
      z-index: 1000;
      display: none;
    }

    .context-menu-item {
      padding: 2px 12px;
      cursor: pointer;
      font-size: 14px;
    }

    .context-menu-item:hover {
      background: #f0f0f0;
    }
  </style>
  <script>
    var map, zoom = 10, handler;
    let isEdit = false; // 是否启用编辑
    // 右键菜单相关变量
    let contextMenu = null;
    let currentFeature = null; // 当前右键点击的元素
    let currentIndex = -1;     // 当前元素的索引
    let featureType = '';      // 元素类型:point/line/polygon

    let viewChangeHandler = null;// 地图视图变化监听器

    // 点数据
    let pointOriginalArr = [
      [120.2536, 30.27093]
    ]
    // 线数据
    let lineOriginalArr = [
      [
        [119.86084, 30.41702],
        [119.96796, 30.47353],
        [119.98718, 30.36758],
      ],
      [
        [119.91714, 30.1855],
        [120.10666, 30.27923],
      ]
    ]
    // 面数据
    let polygonOriginalArr = [
      [
        [119.5752, 30.35392],
        [119.72488, 30.35273],
        [119.65347, 30.26025],
      ],
      [
        [120.49118, 30.29109],
        [120.70541, 30.30532],
        [120.50629, 30.20211],
        [120.69855, 30.22703]
      ]
    ]

    function onLoad () {
      // 创建右键菜单
      createContextMenu();
      //初始化地图对象
      map = new T.Map("map");
      //设置显示地图的中心点和级别
      map.centerAndZoom(new T.LngLat(120.216329, 30.252589), zoom);
      // 绑定地图点击事件隐藏菜单
      map.addEventListener('click', hideContextMenu);

      // 地图视图变化监听
      viewChangeHandler = function () {
        if (currentFeature) {
          updateMenuPosition();
        }
      };
      map.addEventListener('movestart', hideContextMenu);
      map.addEventListener('moveend', viewChangeHandler);
      map.addEventListener('zoomend', viewChangeHandler);


      // 初始显示
      showPoint()
      showPolyLine()
      showPolygon()
    }

    // 位置更新
    function updateMenuPosition () {
      if (!currentFeature) return;

      let centerLngLat;
      switch (featureType) {
        case 'point':
          centerLngLat = currentFeature.getLngLat();
          break;
        case 'line':
          const lineLnglats = currentFeature.getLngLats();
          centerLngLat = getCenter(lineLnglats);
          break;
        case 'polygon':
          const polygonRings = currentFeature.getLngLats();
          centerLngLat = getCenter(polygonRings[0]);
          break;
      }

      const containerPoint = map.lngLatToContainerPoint(centerLngLat);
      const mapRect = map.getContainer().getBoundingClientRect();

      contextMenu.style.left = (containerPoint.x + mapRect.left) + 'px';
      contextMenu.style.top = (containerPoint.y + mapRect.top) + 'px';
    }

    // 几何中心计算方法
    function getCenter (lnglats) {
      // 确保有效的坐标数组
      if (!lnglats || lnglats.length === 0) return null;

      // 计算所有坐标点的平均值
      const sum = lnglats.reduce((acc, curr) => {
        // 处理不同格式的坐标(支持T.LngLat对象和普通数组)
        const lng = curr instanceof T.LngLat ? curr.lng : curr[0];
        const lat = curr instanceof T.LngLat ? curr.lat : curr[1];
        return {
          lng: acc.lng + lng,
          lat: acc.lat + lat
        };
      }, { lng: 0, lat: 0 });

      // 返回新的T.LngLat对象
      return new T.LngLat(
        sum.lng / lnglats.length,
        sum.lat / lnglats.length
      );
    }

    // 创建右键菜单
    function createContextMenu () {
      contextMenu = document.createElement('div');
      contextMenu.id = 'contextMenu';
      contextMenu.innerHTML = `
        <div class="context-menu-item" onclick="deleteFeature()">删除</div>
      `;
      document.body.appendChild(contextMenu);
    }

    // 显示右键菜单
    function showContextMenu (e, feature, index, type) {
      // 获取天地图事件中的原生事件对象
      const originalEvent = e.originalEvent || e.event || e;
      if (originalEvent.preventDefault) {
        originalEvent.preventDefault();
      }

      currentFeature = feature;
      currentIndex = index;
      featureType = type;

      updateMenuPosition(); // 初始定位

      contextMenu.style.display = 'block';
      // 使用原生事件的坐标,定位菜单项
      contextMenu.style.left = originalEvent.clientX + 'px';
      contextMenu.style.top = originalEvent.clientY + 'px';
    }

    // 隐藏右键菜单
    function hideContextMenu () {
      contextMenu.style.display = 'none';
      currentFeature = null;
      currentIndex = -1;
      featureType = '';
    }

    // 删除要素
    function deleteFeature () {
      if (currentIndex === -1) return;

      switch (featureType) {
        case 'point':
          pointOriginalArr.splice(currentIndex, 1);
          break;
        case 'line':
          lineOriginalArr.splice(currentIndex, 1);
          break;
        case 'polygon':
          polygonOriginalArr.splice(currentIndex, 1);
          break;
      }
      refreshMap();
      hideContextMenu();
    }

    // 刷新地图
    function refreshMap () {
      map.clearOverLays();
      showPoint();
      showPolyLine();
      showPolygon();
    }

    // 显示点
    function showPoint () {
      let pointArr = [];
      pointOriginalArr.forEach((item, index) => {
        let arr = []
        arr.push(new T.LngLat(item[0], item[1]))
        pointArr.push(arr);
      })
      pointArr.forEach((item, index) => {
        var marker = new T.Marker(item[0], {
          icon: new T.Icon({
            iconUrl: './imgs/marker-icon.png',
          }),
        });
        map.addOverLay(marker);

        // 右键菜单事件绑定(添加event参数传递)
        marker.addEventListener('contextmenu', function (apiEvent) {
          showContextMenu(apiEvent, marker, index, 'point');
        });

        if (!isEdit) return;
        marker.enableDragging();
        marker.addEventListener('dragend', function (e) {
          updatePointOriginalList([e.lnglat.lng, e.lnglat.lat], index)
        })
      })
    }

    // 更新点的数据,用于最后保存
    function updatePointOriginalList (arr, index) {
      pointOriginalArr[index] = arr
    }

    // 显示线
    function showPolyLine () {
      let lineArr = []
      lineOriginalArr.forEach((item, index) => {
        let arr = []
        item.forEach((item1) => {
          arr.push(new T.LngLat(item1[0], item1[1]))
        })
        lineArr.push(arr)
      })
      lineArr.forEach((item, index) => {
        var line = new T.Polyline(item);
        map.addOverLay(line);

        // 右键菜单事件绑定(添加event参数传递)
        line.addEventListener('contextmenu', function (apiEvent) {
          showContextMenu(apiEvent, line, index, 'line');
        });

        if (!isEdit) return
        line.enableEdit();
        line.addEventListener('edit', function (e) {
          const ht = line.getLngLats()
          let arr = []
          ht.forEach((item) => {
            arr.push([item.lng, item.lat])
          })
          updateLineOriginalList(arr, index)
        })
      })
    }

    // 更新线的数据,用于最后保存
    function updateLineOriginalList (arr, index) {
      lineOriginalArr[index] = arr
    }

    // 显示面
    function showPolygon () {
      let polygonArr = []
      polygonOriginalArr.forEach((item, index) => {
        let arr = []
        item.forEach((item1) => {
          arr.push(new T.LngLat(item1[0], item1[1]))
        })
        polygonArr.push(arr)
      })
      polygonArr.forEach((item, index) => {
        var polygon = new T.Polygon(item);
        map.addOverLay(polygon);

        // 右键菜单事件绑定(添加event参数传递)
        polygon.addEventListener('contextmenu', function (apiEvent) {
          showContextMenu(apiEvent, polygon, index, 'polygon');
        });

        if (!isEdit) return
        polygon.enableEdit();
        polygon.addEventListener('edit', function (e) {
          const ht = polygon.getLngLats()[0]
          let arr = []
          ht.forEach((item) => {
            arr.push([item.lng, item.lat])
          })
          updatePolygonOriginalList(arr, index)
        })
      })
    }

    // 更新面的数据,用于最后保存
    function updatePolygonOriginalList (arr, index) {
      polygonOriginalArr[index] = arr
    }

    // 打点
    function openMarkerTool () {
      if (handler) handler.close();
      handler = new T.MarkTool(map, {
        follow: true,
        icon: new T.Icon({
          iconUrl: './imgs/marker-icon.png',
          // iconSize: new T.Point(24, 28), // 图标可视区域的大小
        }),
      });
      handler.open();
      handler.addEventListener('mouseup', function (e) {
        // 这里可以获取到当前点位的坐标
        pointOriginalArr.push([e.currentLnglat.lng, e.currentLnglat.lat])
        // 重新绘制地图,否则编辑不了
        refreshMap();
        handler.clear()
      })
    }

    // 画线
    function openPolylineTool () {
      if (handler) handler.close();
      handler = new T.PolylineTool(map);
      handler.open();
      handler.addEventListener('draw', function (e) {
        const currentLnglats = e.currentLnglats
        let arr = []
        currentLnglats.forEach((item, index) => {
          arr.push([item.lng, item.lat])
        })
        lineOriginalArr.push(arr)
        // 重新绘制地图,否则编辑不了
        refreshMap();
        handler.clear()
      })
    }

    // 画面
    function openPolygonTool () {
      if (handler) handler.close();
      handler = new T.PolygonTool(map);
      handler.open();
      handler.addEventListener('draw', function (e) {
        const currentLnglats = e.currentLnglats
        let arr = []
        currentLnglats.forEach((item, index) => {
          arr.push([item.lng, item.lat])
        })
        polygonOriginalArr.push(arr)
        // 重新绘制地图,否则编辑不了
        refreshMap();
        handler.clear()
      })
    }

    // 开启编辑
    function editClick () {
      isEdit = true
      map.clearOverLays()
      showPoint()
      showPolyLine()
      showPolygon()
    }
    // 保存
    function saveClick () {
      console.log("点数据:", pointOriginalArr); // 两层结构:大数组中,包含点的小数组
      console.log("线数据:", lineOriginalArr); // 三层结构:大数组中包含线的数组,线的数组中包含经纬度小数组
      console.log("面数据:", polygonOriginalArr); // 三层结构:大数组中包含面的数组,面的数组中包含经纬小数组
      isEdit = false
      map.clearOverLays()
      showPoint()
      showPolyLine()
      showPolygon()

    }
    // 清空画布
    function clearClick () {
      isEdit = false
      map.clearOverLays()
      pointOriginalArr = []
      lineOriginalArr = []
      polygonOriginalArr = []
    }

  </script>
</head>

<body onLoad="onLoad()">
  <div id="map"></div>
  <div class="line-btn">
    <input type="button" value="点工具" onClick="openMarkerTool() " />
    <input type="button" value="线工具" onClick="openPolylineTool() " />
    <input type="button" value="面工具" onClick="openPolygonTool() " />
    <input type="button" value="编辑" onClick="editClick() " />
    <input type="button" value="保存" onClick="saveClick() " />
    <input type="button" value="清除" onClick="clearClick() " />
  </div>
</body>

</html>

复制上面代码,替换应用KEY值即可看到功能效果。

相关推荐
勘察加熊人7 分钟前
angular日历
前端·javascript·angular.js
NoneCoder11 分钟前
JavaScript系列(86)--现代构建工具详解
开发语言·javascript·rust
weixin_4440090015 分钟前
浏览器JS打不上断点,一点就跳到其他文件里。浏览器控制台 js打断点,指定的位置打不上断点,一打就跳到其他地方了。
开发语言·javascript·ecmascript
Ama_tor30 分钟前
网页制作10-html,css,javascript初认识の适用XHTML
javascript·css·html
程序员SKY37 分钟前
JavaScript 系列之:垃圾回收机制
javascript
Chocolate_men1 小时前
echarts 环形图 指定区域从右侧中心点展开
javascript·vue.js
荣--1 小时前
重构的艺术:在代码演进中寻找优雅
javascript·微信小程序·重构·nodejs
祈澈菇凉2 小时前
如何使用useContext进行全局状态管理?
前端·javascript·react.js
澄江静如练_3 小时前
vue3中的标签属性中的Ref
前端·javascript·vue.js
IT、木易4 小时前
大白话React第八章React 深入进阶与实践拓展阶段
javascript·react.js·ecmascript