GIS相关GIS加油站开源

mapboxGL测量实现

2020-04-21  本文已影响0人  牛老师讲webgis

概述

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

效果

测距 测面

实现

1、实现思路

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

2、实现代码

1.样式
.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.测量距离
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.测量面积
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);
    }
  });
}  

技术博客
CSDN:http://blog.csdn.NET/gisshixisheng
联系方式

类型 内容
qq 1004740957
公众号 lzugis15
e-mail niujp08@qq.com
webgis群 452117357
LZUGIS
上一篇下一篇

猜你喜欢

热点阅读