openlayers3 测距离,侧面积,测角度 (拿来就直接用)

本人并不是专业前端,所以写的不太好,但是应该拿来就可以用,方便小白学习,或者使用,现在还是有一点bug,就是测角度的时候,应该绘制两条线的时候就停止,但是还没时间研究, 用的时候别忘评论下,哈哈

measure.js

/**
 *
 * openlayer3测距离和面积(按钮版)
 *
 */

/**
 *
 * tooltips相关css (就是包裹长度或者面积的气泡的样式) (这里是备用,防止以后找不到,可以从这里复制)
 *
 *.tooltip {
 *    position: relative;
 *    background: rgba(0, 0, 0, 0.5);
 *    border-radius: 4px;
 *    color: white;
 *    padding: 4px 8px;
 *    opacity: 0.7;
 *    white-space: nowrap;
 *  }
 *  .tooltip-measure {
 *    opacity: 1;
 *    font-weight: bold;
 *  }
 *  .tooltip-static {
 *    background-color: #ffcc33;
 *    color: black;
 *    border: 1px solid white;
 *  }
 *  .tooltip-measure:before,
 *  .tooltip-static:before {
 *    border-top: 6px solid rgba(0, 0, 0, 0.5);
 *    border-right: 6px solid transparent;
 *    border-left: 6px solid transparent;
 *    content: "";
 *    position: absolute;
 *    bottom: -6px;
 *    margin-left: -7px;
 *    left: 50%;
 *  }
 *  .tooltip-static:before {
 *    border-top-color: #ffcc33;
 *  }
 *  
 *  <div class="btnGroup" style="position: absolute;top: 50px;">
 *      <button id="measure-length">测量距离</button>
 *      <button id="measure-area">测量面积</button>
 *      <button id="stop-measure">停止测量</button>  
 *      <label class="checkbox">
 *        <input type="checkbox" id="geodesic">
 *        使用大地测量
 *      </label>
 *  </div>
 * 
 */

var measurementTool = (function () {
  //**************全局配置******************/
  // 绘制时线的颜色
  var The_color_of_the_draw_line = 'rgba(0, 0, 0, 0.5)'
  // 绘制时线的宽度
  var The_width_of_the_draw_line = 2
  // 绘制时虚线的间隔
  var The_dash_of_the_draw_line = [10, 10]
  // 绘制时鼠标小圆球边框颜色
  var The_Small_ball_border_color = 'rgba(0, 0, 0, 0.7)'
  // 绘制时鼠标小圆球填充颜色
  var The_Small_ball_fill_color = 'rgba(255, 255, 255, 0.2)'
  // 绘制时区域填充颜色
  var The_fill_color_of_the_draw_area = 'rgba(255, 255, 255, 0.2)'
  // 绘制后的线的颜色
  var The_color_of_the_drawn_line = '#ffff00'
  // 绘制后的线的宽度
  var The_width_of_the_drawn_line = 2
  // 绘制后的区域的填充颜色
  var The_fill_color_of_the_drawn_area = 'rgba(255, 255, 255, 0.2)'
  //********************************/

  var wgs84Sphere = new ol.Sphere(6378137)

  // 瓦片图层
  // var raster = new ol.layer.Tile({
  //   source: new ol.source.OSM()
  // });

  // 矢量图层的源
  var source = new ol.source.Vector()

  // 矢量图层
  var vector = new ol.layer.Vector({
    source: source,
    style: new ol.style.Style({
      fill: new ol.style.Fill({
        // color: 'rgba(255, 255, 255, 0.2)'
        color: The_fill_color_of_the_drawn_area
      }),
      stroke: new ol.style.Stroke({
        color: The_color_of_the_drawn_line,
        width: The_width_of_the_drawn_line
      }),
      image: new ol.style.Circle({
        radius: 7,
        fill: new ol.style.Fill({
          color: The_color_of_the_drawn_line
        })
      })
    })
  })

  /**
   * 当前绘制的特征。
   * @type {ol.Feature}
   */
  var sketch

  /**
   * 帮助工具提示元素。
   * @type {Element}
   */
  var helpTooltipElement

  /**
   * 显示帮助信息的覆盖层。
   * @type {ol.Overlay}
   */
  var helpTooltip

  /**
   * 测量工具提示元素。
   * @type {Element}
   */
  var measureTooltipElement

  /**
   * 显示测量结果的覆盖层。
   * @type {ol.Overlay}
   */
  var measureTooltip

  /**
   * 用户绘制多边形时显示的信息。
   * @type {string}
   */
  var continuePolygonMsg = '点击继续绘制多边形'

  /**
   * 用户绘制线条时显示的信息。
   * @type {string}
   */
  var continueLineMsg = '点击继续绘制线条'


  // 进行角度绘制时的显示的信息
  var  continueAngleMsg = '点击继续绘制角度'

  // 是否在测量角度? 测量角度和测量角度时候因为都是在绘制线,所以这里用一个变量来控制
  var isAngleMeasurement = false; // 初始化标志变量

  /**
   * 处理指针移动事件。
   * @param {ol.MapBrowserEvent} evt 事件。
   */
  var pointerMoveHandler = function (evt) {
    if (evt.dragging) {
      return
    }
    /** @type {string} */
    var helpMsg = '点击开始绘制'

    if (sketch) {
      var geom = sketch.getGeometry()
      if (geom instanceof ol.geom.Polygon) {
        helpMsg = continuePolygonMsg
      } else if (geom instanceof ol.geom.LineString) {
        // 判断是否在测量角度
        if (isAngleMeasurement) {
          helpMsg =  continueAngleMsg
        }else {
          helpMsg = continueLineMsg
        }
      }
    }

    helpTooltipElement.innerHTML = helpMsg
    helpTooltip.setPosition(evt.coordinate)

    helpTooltipElement.classList.remove('hidden')
  }

  // map.addLayer(vector);

  var typeSelect = document.getElementById('type')
  var geodesicCheckbox = document.getElementById('geodesic')

  var draw // 全局变量,以便稍后可以删除它

  /**
   * 格式化长度输出。
   * @param {ol.geom.LineString} line 线。
   * @return {string} 格式化的长度。
   */
  var formatLength = function (line) {
    var length
    if (geodesicCheckbox.checked) {
      var coordinates = line.getCoordinates()
      length = 0
      var sourceProj = map.getView().getProjection()
      for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
        var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326')
        var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326')
        length += wgs84Sphere.haversineDistance(c1, c2)
      }
    } else {
      length = Math.round(line.getLength() * 100) / 100
    }
    //todo 在这里修改长度单位
    var output
    if (length > 100) {
      output = Math.round((length / 1000) * 100) / 100 + ' ' + '千米' // 单位改为千米
    } else {
      output = Math.round(length * 100) / 100 + ' ' + '米' // 单位改为米
    }
    return output
  }

  /**
   * 格式化面积输出。
   * @param {ol.geom.Polygon} polygon 多边形。
   * @return {string} 格式化的面积。
   */
  var formatArea = function (polygon) {
    var area
    if (geodesicCheckbox.checked) {
      var sourceProj = map.getView().getProjection()
      var geom = /** @type {ol.geom.Polygon} */ (
        polygon.clone().transform(sourceProj, 'EPSG:4326')
      )
      var coordinates = geom.getLinearRing(0).getCoordinates()
      area = Math.abs(wgs84Sphere.geodesicArea(coordinates))
    } else {
      area = polygon.getArea()
    }
    //todo 在这里修改面积单位
    var output
    if (area > 10000) {
      output = Math.round((area / 1000000) * 100) / 100 + ' ' + '平方千米' // 单位改为平方千米
    } else {
      output = Math.round(area * 100) / 100 + ' ' + '平方米' // 单位改为平方米
    }
    return output
  }



// 格式化角度
var formatAngle = function (line) {
  var coordinates = line.getCoordinates();
  var angle = 0;
  var sourceProj = map.getView().getProjection();
  
  if (coordinates.length < 3) {
      return "0度";
  }

  // 获取三个点的坐标
  var c1 = ol.proj.transform(coordinates[coordinates.length - 3], sourceProj, 'EPSG:4326');
  var c2 = ol.proj.transform(coordinates[coordinates.length - 2], sourceProj, 'EPSG:4326');
  var c3 = ol.proj.transform(coordinates[coordinates.length - 1], sourceProj, 'EPSG:4326');
  
  // 计算两边的距离
  var disa = wgs84Sphere.haversineDistance(c1, c2);
  var disb = wgs84Sphere.haversineDistance(c2, c3);
  var disc = wgs84Sphere.haversineDistance(c1, c3);

  // 计算角度(使用余弦定理)
  if (disa !== 0 && disb !== 0) {
      var cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb);
      angle = Math.acos(cos) * 180 / Math.PI; // 转为度
      angle = angle.toFixed(2) + " 度";
  } 

  return angle; // 返回角度
};



  function addInteraction(type) {
    draw = new ol.interaction.Draw({
      source: source,
      type: type,
      style: new ol.style.Style({
        fill: new ol.style.Fill({
          color: The_fill_color_of_the_draw_area
        }),
        stroke: new ol.style.Stroke({
          color: The_color_of_the_draw_line,
          lineDash: The_dash_of_the_draw_line,
          width: The_width_of_the_draw_line
        }),
        image: new ol.style.Circle({
          radius: 5,
          stroke: new ol.style.Stroke({
            color: The_Small_ball_border_color
          }),
          fill: new ol.style.Fill({
            color: The_Small_ball_fill_color
          })
        })
      })
    });
    map.addInteraction(draw)

    createMeasureTooltip()
    createHelpTooltip()

    var listener
    draw.on(
      'drawstart',
      function (evt) {
        // 设置当前草图
        sketch = evt.feature

        /** @type {ol.Coordinate|undefined} */
        var tooltipCoord = evt.coordinate

        listener = sketch.getGeometry().on('change', function (evt) {
          var geom = evt.target
          var output
          // console.log("位置" + geom.getLastCoordinate());
          // console.log("组" + geom.getCoordinates()[1]);
          
          if (geom instanceof ol.geom.Polygon) { 
            output = formatArea(geom)
            tooltipCoord = geom.getInteriorPoint().getCoordinates()
          } 
          else if (geom instanceof ol.geom.LineString) {
             // 判断是否在测量角度
            if (isAngleMeasurement) {
              output = formatAngle(geom); // 调用测量角度函数
              tooltipCoord = geom.getCoordinates()[1];//角度显示在第二个点的位置i
            } else {
              output = formatLength(geom); // 调用测量长度函数
              tooltipCoord = geom.getLastCoordinate();//长度显示在最后一个点的位置
            }
        
           
          }
          // else if (geom instanceof ol.geom.LineString) {
            // console.log(geom);

            // output = formatLength(geom)
            // tooltipCoord = geom.getLastCoordinate()
          // }else{
            // output = formatAngle(geom)
            // tooltipCoord = geom.getLastCoordinate()
          // }
          measureTooltipElement.innerHTML = output
          measureTooltip.setPosition(tooltipCoord)
        })
      },
      this
    )

    draw.on(
      'drawend',
      function () {
        measureTooltipElement.className = 'tooltip tooltip-static'
        measureTooltip.setOffset([0, -7])

        // 取消草图
        sketch = null
        // 取消工具提示,以便可以创建新的
        measureTooltipElement = null
        createMeasureTooltip()
        ol.Observable.unByKey(listener)
      },
      this
    )
  }

  /**
   * 创建新的帮助工具提示
   */
  function createHelpTooltip() {
    if (helpTooltipElement) {
      helpTooltipElement.parentNode.removeChild(helpTooltipElement)
    }
    helpTooltipElement = document.createElement('div')
    helpTooltipElement.className = 'tooltip hidden'
    helpTooltip = new ol.Overlay({
      element: helpTooltipElement,
      offset: [15, 0],
      positioning: 'center-left'
    })
    map.addOverlay(helpTooltip)
  }

  /**
   * 创建新的测量工具提示
   */
  function createMeasureTooltip() {
    if (measureTooltipElement) {
      measureTooltipElement.parentNode.removeChild(measureTooltipElement)
    }
    measureTooltipElement = document.createElement('div')
    measureTooltipElement.className = 'tooltip tooltip-measure'
    measureTooltip = new ol.Overlay({
      element: measureTooltipElement,
      offset: [0, -15],
      positioning: 'bottom-center'
    })
    map.addOverlay(measureTooltip)
  }


  return {
    init: function () {
      map.addLayer(vector)
      // 绑定测量距离按钮
      document.getElementById('measure-length').onclick = function () {
        map.removeInteraction(draw)
        map.on('pointermove', pointerMoveHandler)
        map.getViewport().addEventListener('mouseout', function () {
          helpTooltipElement.classList.add('hidden')
        })
        isAngleMeasurement = false; // 清除标志变量
        addInteraction('LineString')
      }

      // 绑定测量面积按钮
      document.getElementById('measure-area').onclick = function () {
        map.removeInteraction(draw)
        map.on('pointermove', pointerMoveHandler)
        map.getViewport().addEventListener('mouseout', function () {
          helpTooltipElement.classList.add('hidden')
        })
        addInteraction('Polygon')
      }


      // 绑定测量角度按钮
      document.getElementById('measure-angle').onclick = function () {
        map.removeInteraction(draw)
        map.on('pointermove', pointerMoveHandler)
        map.getViewport().addEventListener('mouseout', function () {
          helpTooltipElement.classList.add('hidden')
        })
        isAngleMeasurement = true; // 设置标志变量
        addInteraction('LineString')
      }


      // 绑定停止测量按钮
      document.getElementById('stop-measure').onclick = function () {
        map.removeInteraction(draw)
        // helpTooltipElement.classList.add('hidden')
        // 移除鼠标移动事件监听器,防止 `helpTooltip` 继续显示
        map.un('pointermove', pointerMoveHandler);
        
        // 显式隐藏并移除 `helpTooltip`
        if (helpTooltip) {
            map.removeOverlay(helpTooltip);
            helpTooltipElement = null;
            helpTooltip = null;
        }
      }
    }
  }
})()

measurementTool.init()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值