前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mapboxGL测量实现

mapboxGL测量实现

作者头像
lzugis
发布2020-04-22 14:46:53
9070
发布2020-04-22 14:46:53
举报

概述

讲真,MapboxGL里面虽然有测量的功能,但是不太好用,于是就萌生了自己实现的方法。本文几个turf.js来说说mapboxGL中测量的实现。

效果

测距
测距
测面
测面

实现

1、实现思路

  1. 按照绘制的流程,需要涉及到map的三个事件:click,dblclick,mousemove,其中click为绘制,dblclick为结束绘制,mousemove为绘制中。这样,定义一个状态标识isMeasure,在点击开始绘制的按钮的时候,将标识设置为true,在map的三个事件中都会根据这个标识判断是否为绘制状态。
  2. 地图的展示分layer和marker来分别展示;
  3. layer里面区分点和线(面)图层,以达到比较好的展示效果。

2、实现代码

1.样式
代码语言:javascript
复制
.measure-result {
  background-color: white;
  border-radius: 3px;
  height: 16px;
  line-height: 16px;
  padding: 0 3px;
  font-size: 12px;
  box-shadow: 0 0 0 1px #ccc;
  &.close {
    cursor: pointer;
    width: 14px;
    height: 14px;
    line-height: 16px;
    text-align: center;
    padding: 0;
  }
}
2.测量距离
代码语言:javascript
复制
function measureLength() {
  var isMeasure = true;
  // 禁止双击缩放
  map.doubleClickZoom.disable();
  map.getCanvas().style.cursor = 'default';

  function clearMeasure() {
    $(".measure-result").remove();
    var source = map.getSource('points');
    var json = {
      'type': 'FeatureCollection',
      'features': []
    };
    if(source) {
      map.getSource('points').setData(json);
      map.getSource('line-move').setData(json);
      map.getSource('line').setData(json);
    }
    var sourceArea = map.getSource('points-area');
    if(sourceArea) {
      map.getSource('points-area').setData(json);
      map.getSource('line-area').setData(json);
    }
  }

  clearMeasure();

  var jsonPoint = {
    'type': 'FeatureCollection',
    'features': []
  };
  var jsonLine = {
    'type': 'FeatureCollection',
    'features': []
  };
  var points = [];
  const ele = document.createElement('div');
  ele.setAttribute('class', 'measure-result');
  const option = {
    element: ele,
    anchor: 'left',
    offset: [8, 0]
  };
  var tooltip = new mapboxgl.Marker(option)
          .setLngLat([0, 0])
          .addTo(map);
  var markers = [];

  var source = map.getSource('points');
  if(source) {
    map.getSource('points').setData(jsonPoint);
    map.getSource('line-move').setData(jsonLine);
    map.getSource('line').setData(jsonLine);
  } else {
    map.addSource('points', {
      type: 'geojson',
      data: jsonPoint
    });
    map.addSource('line', {
      type: 'geojson',
      data: jsonLine
    });
    map.addSource('line-move', {
      type: 'geojson',
      data: jsonLine
    });
    map.addLayer({
      id: 'line-move',
      type: 'line',
      source: 'line-move',
      paint: {
        'line-color': '#ff0000',
        'line-width': 2,
        'line-opacity': 0.65
      }
    });
    map.addLayer({
      id: 'line',
      type: 'line',
      source: 'line',
      paint: {
        'line-color': '#ff0000',
        'line-width': 2,
        'line-opacity': 0.65
      }
    });
    map.addLayer({
      id: 'points',
      type: 'circle',
      source: 'points',
      paint: {
        'circle-color': '#ffffff',
        'circle-radius': 3,
        'circle-stroke-width': 2,
        'circle-stroke-color': '#ff0000'
      }
    });
  }
  function addPoint(coords) {
    if(jsonPoint.features.length > 0) {
      var prev = jsonPoint.features[jsonPoint.features.length - 1];
      jsonLine.features.push({
        type: 'Feature',
        geometry: {
          type: 'LineString',
          coordinates: [prev.geometry.coordinates, coords]
        }
      });
      map.getSource('line').setData(jsonLine);
    }
    jsonPoint.features.push({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: coords
      }
    });
    map.getSource('points').setData(jsonPoint);
  }

  function getLength(coords) {
    var _points = points.concat([coords]);
    var line = turf.lineString(_points);
    var len = turf.length(line);
    if(len < 1) {
      len = Math.round(len * 1000) + 'm';
    } else {
      len = len.toFixed(2) + 'km';
    }
    return len;
  }

  function addMeasureRes(coords) {
    const ele = document.createElement('div');
    ele.setAttribute('class', 'measure-result');
    const option = {
      element: ele,
      anchor: 'left',
      offset: [8, 0]
    };
    ele.innerHTML = points.length === 0 ? '起点' : getLength(coords);
    var marker = new mapboxgl.Marker(option)
            .setLngLat(coords)
            .addTo(map);
    markers.push(marker);
  }

  map.on('click', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      addMeasureRes(coords);
      addPoint(coords);
      points.push(coords);
    }
  });

  map.on('mousemove', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      if (jsonPoint.features.length > 0) {
        var prev = jsonPoint.features[jsonPoint.features.length - 1];
        var json = {
          type: 'Feature',
          geometry: {
            type: 'LineString',
            coordinates: [prev.geometry.coordinates, coords]
          }
        };
        map.getSource('line-move').setData(json);
        ele.innerHTML = getLength(coords);

      } else {
        ele.innerHTML = '点击地图开始测量';
      }
      tooltip.setLngLat(coords);
    }
  });

  map.on('dblclick', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      addPoint(coords);
      isMeasure = false;
      map.getCanvas().style.cursor = '';
      jsonPoint.features = [];
      jsonLine.features = [];
      tooltip.remove();
      // 添加关闭按钮
      const ele = document.createElement('div');
      ele.setAttribute('class', 'measure-result close');
      const option = {
        element: ele,
        anchor: 'bottom-left',
        offset: [-5, -10]
      };
      ele.innerHTML = '×';
      new mapboxgl.Marker(option)
              .setLngLat(coords)
              .addTo(map);
      ele.onclick = function (__e) {
        __e.stopPropagation();
        map.doubleClickZoom.enable();
        clearMeasure();
      }
    }
  });
}  
3.测量面积
代码语言:javascript
复制
function measureArea() {  
  var isMeasure = true;
  // 禁止双击缩放
  map.doubleClickZoom.disable();
  map.getCanvas().style.cursor = 'default';
  function clearMeasure() {
    $(".measure-result").remove();
    var source = map.getSource('points');
    var json = {
      'type': 'FeatureCollection',
      'features': []
    };
    if(source) {
      map.getSource('points').setData(json);
      map.getSource('line-move').setData(json);
      map.getSource('line').setData(json);
    }
    var sourceArea = map.getSource('points-area');
    if(sourceArea) {
      map.getSource('points-area').setData(json);
      map.getSource('line-area').setData(json);
    }
  }
  clearMeasure();
  var jsonPoint = {
    'type': 'FeatureCollection',
    'features': []
  };
  var jsonLine = {
    'type': 'FeatureCollection',
    'features': []
  };
  var points = [];
  var ele = document.createElement('div');
  ele.setAttribute('class', 'measure-result');
  const option = {
    element: ele,
    anchor: 'left',
    offset: [8, 0]
  };
  var tooltip = new mapboxgl.Marker(option)
          .setLngLat([0, 0])
          .addTo(map);
  var source = map.getSource('points-area');
  if(source) {
    map.getSource('points-area').setData(jsonPoint);
    map.getSource('line-area').setData(jsonLine);
  } else {
    map.addSource('points-area', {
      type: 'geojson',
      data: jsonPoint
    });
    map.addSource('line-area', {
      type: 'geojson',
      data: jsonLine
    });
    map.addLayer({
      id: 'line-area',
      type: 'fill',
      source: 'line-area',
      paint: {
        'fill-color': '#ff0000',
        'fill-opacity': 0.1
      }
    });
    map.addLayer({
      id: 'line-area-stroke',
      type: 'line',
      source: 'line-area',
      paint: {
        'line-color': '#ff0000',
        'line-width': 2,
        'line-opacity': 0.65
      }
    });
    map.addLayer({
      id: 'points-area',
      type: 'circle',
      source: 'points-area',
      paint: {
        'circle-color': '#ffffff',
        'circle-radius': 3,
        'circle-stroke-width': 2,
        'circle-stroke-color': '#ff0000'
      }
    });
  }

  function getArea(coords) {
    var pts = points.concat([coords]);
    pts = pts.concat([points[0]]);
    var polygon = turf.polygon([pts]);
    var area = turf.area(polygon);
    if(area < 1000) {
      area = Math.round(area) + 'm²';
    } else {
      area = (area / 1000000).toFixed(2) + 'km²';
    }
    return area;
  }
  function addPoint(coords) {
    jsonPoint.features.push({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: coords
      }
    });
    map.getSource('points-area').setData(jsonPoint);
  }
  
  map.on('click', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      points.push(coords);
      addPoint(coords);
    }
  });

  map.on('dblclick', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      points.push(coords);
      isMeasure = false;
      ele.innerHTML = getArea(coords);
      tooltip.setLngLat(coords);
      // 添加关闭按钮
      var _ele = document.createElement('div');
      _ele.setAttribute('class', 'measure-result close');
      var option = {
        element: _ele,
        anchor: 'bottom-left',
        offset: [-5, -10]
      };
      _ele.innerHTML = '×';
      new mapboxgl.Marker(option)
              .setLngLat(coords)
              .addTo(map);
      _ele.onclick = function (__e) {
        __e.stopPropagation();
        map.doubleClickZoom.enable();
        clearMeasure();
      }
    }
  });

  map.on('mousemove', function (_e) {
    if(isMeasure) {
      var coords = [_e.lngLat.lng, _e.lngLat.lat];
      var len = jsonPoint.features.length;
      if (len === 0) {
        ele.innerHTML = '点击地图开始测量';
      } else if (len ===1) {
        ele.innerHTML = '点击地图继续绘制';
      } else {
        var pts = points.concat([coords]);
        pts = pts.concat([points[0]]);
        var json = {
          type: 'Feature',
          geometry: {
            type: 'Polygon',
            coordinates: [pts]
          }
        };
        map.getSource('line-area').setData(json);
        ele.innerHTML = getArea(coords);
      }
      tooltip.setLngLat(coords);
    }
  });
}  
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 效果
  • 实现
    • 1、实现思路
      • 2、实现代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档