OpenLayers 量测合集(距离+面积)

关注我,带你一起学GIS ^

注:当前使用的是 ol [9.2.4] 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

前言

OpenLayers量测工具用于地理信息系统应用中的距离和面积量测功能,是GIS开发的常用功能。它通过Draw交互类和sphere对象实现,可创建指定量测类型(距离或面积)的对象,并添加到地图上,用户通过交互操作进行量测。量测时,OpenLayers会自动将地理坐标转换为像素坐标,方便操作。该工具广泛应用于地理信息测量、地图绘制与分析等领域,为用户提供便捷、高效的量测解决方案。

1. 初始化绘制参数

绘制参数主要有下图几种类型,包括交互绘制对象、提示信息元素以及叠加图层,还包含绘制图层数据源和绘制监听对象。

/**###########################初始化绘制参数开始############################**/
let drawAction = undefined  // 绘制对象
let sketch = undefined      // 绘制要素

let helpTooltip             // 绘制提示叠加层
let measureTooltip          // 测量提示叠加层

let helpTooltipElement      // 绘制提示元素
let measureTooltipElement   // 测量提示元素

let listener = undefined    // 绘制元素监听事件
let source = undefined      // 绘制图层数据源
/**###########################初始化绘制参数结束############################**/

2. 添加绘制图层

创建绘制图层函数,添加矢量图层和矢量数据源并设置绘制图层样式。使用setProperties方法添加layerName自定义属性,最后将绘制图层添加到地图上。

// 创建绘制图层
function addDrawLayer() {
    source = new ol.source.Vector()
    const drawLayer = new ol.layer.Vector({
        sourcesource,
        style: {
            'fill-color''rgba(255, 255, 255, 0.2)',
            'stroke-color''#ffcc33',
            'stroke-width': 2,
            'circle-radius': 7,
            'circle-fill-color''#ffcc33',
        },
    })
    // 自定义图层属性
    drawLayer.setProperties({ "layerName""measureLayer" })
    map.addLayer(drawLayer)
}

3. 计算绘制面积

OpenLayers中可以通过ol.sphere对象的**getArea**方法计算距离。该方法接收一个几何类型参数,传递面类型几何对象进去即可。对测量结果进行格式化输出,当测量结果大于10000时使用平方千米单位进行表示,否则使用平方米表示。OpenLayers面积测量单位默认为平方米,可根据精度[1km](undefined "undefined") [= 1000000m](undefined "undefined")进行转换。

// 计算面积并格式化输出结果
const formatArea = function (polygon) {
    const area = ol.sphere.getArea(polygon)
    let showArea = 0
    if (area > 10000) {
        showArea = Math.round((area / 1000000) * 100) / 100 + " " + "km<sup>2</sup>"
    } else {
        showArea = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>'
    }
    return showArea
}

4. 计算绘制距离

在OpenLayers中可以通过ol.sphere对象的getLength方法计算距离。该方法具有一个几何类型参数,将线几何传递进去即可。对于量测结果大于100时使用KM单位进行表示,否则使用m进行表示。

// 计算距离
const formatLength = function (line) {
    const length = ol.sphere.getLength(line)
    let output
    if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + " " + "KM"
    } else {
        output = Math.round(length * 100) / 100 + ' ' + 'm'
    }
    return output
}

5. 添加绘制样式

第二节中添加了图层样式,此处需要与图层样式做区分。在OpenLayers中,图层样式用于控制绘制完成之后的样式状态,而绘制样式用于控制在绘制过程中的样式状态。

// 绘制样式
const drawStyle = new ol.style.Style({
    fill: new ol.style.Fill({
        color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new ol.style.Stroke({
        color: '#ffcc33',
        lineDash: [10, 10],
        width: 2,
    }),
    image: new ol.style.Circle({
        radius: 5,
        stroke: new ol.style.Stroke({
            color: 'rgba(0, 0, 0, 0.7)',
        }),
        fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 0.2)',
        }),
    }),
});

6. 创建叠加图层

在OpenLayers有一个单独的图层类型Overlay,专门用于显示叠加图层。在创建提示信息、绘制信息等信息弹窗时特别有用。下面两个方法分别创建了绘制提示信息叠加图层、测量提示信息叠加图层。叠加图层对象接受一个HTML元素作为信息弹窗载体,可以通过offset属性调整其显示位置。offset参数为数组形式[x,y],其中x表示横坐标偏移量,也就是X轴,正值向右,负值向左;y表示纵坐标,也就是Y轴,正值向下,负值向上。

// 添加绘制提示
function createHelpTooltip() {
  if (helpTooltipElement) {
      helpTooltipElement.parentNode.remove(helpTooltipElement)
  }
  helpTooltipElement = document.createElement("div")
  helpTooltipElement.className = "ol-tooltip hidden"

  helpTooltip = new ol.Overlay({
      element: helpTooltipElement,
      offset: [5, 15],
      positionning: "center-left"
  })
  helpTooltip.setProperties({ "layerName""helpOverlay" })
  map.addOverlay(helpTooltip)
}

function createMeasureTooltip() {
  if (measureTooltipElement) {
      measureTooltipElement.parentNode.remove(measureTooltipElement)
  }

  measureTooltipElement = document.createElement("div")
  measureTooltipElement.className = "ol-tooltip ol-tooltip-measure"

  measureTooltip = new ol.Overlay({
      element: measureTooltipElement,
      offset: [-38, -35],
      positionning: "bottom-center",
      stopEvent: false,
      insertFirst: true
  })
  measureTooltip.setProperties({ "layerName""measureOverlay" })
  map.addOverlay(measureTooltip)
}

7. 创建绘制对象

通过interaction类创建绘制对象,使用addInteraction方法将其添加到地图中并且添加绘制样式类。addInteraction方法接受一个几何类型参数,为字符串参数,如绘制几何线对象时该参数为"LineString",绘制几何面对象时该参数为"Polygon"。之后添加信息提示叠加图层。后面重要的两步是监听开始绘制事件和监听绘制结束事件。

  • 监听开始绘制事件

获取当前绘制对象,并监听其几何属性,在几何对象change事件中,根据几何对象类型更新量测计算结果和提示信息。

  • 监听绘制结束事件

当绘制完成后,移除几何对象监听事件,将监听要素和测量元素设置为空,并且更新最终量测结果。

function addDrawAction(geomType) {
    // 创建交互绘制对象
    drawAction = new ol.interaction.Draw({
        sourcesource,
        type: geomType,
        style: drawStyle
    })
    map.addInteraction(drawAction)

    // 创建叠加层
    createMeasureTooltip();
    createHelpTooltip();

    // 监听开始绘制事件
    drawAction.on('drawstart'function (evt) {
        // 绘制要素
        sketch = evt.feature
        let tooltipCoord = evt.coordinate

        listener = sketch.getGeometry().on('change'function (evt) {
            const targetGeom = evt.target
            let measureResult
            if (targetGeom instanceof ol.geom.Polygon) {
                measureResult = formatArea(targetGeom)
                tooltipCoord = targetGeom.getInteriorPoint().getCoordinates()
            } else if (targetGeom instanceof ol.geom.LineString) {
                measureResult = formatLength(targetGeom)
                tooltipCoord = targetGeom.getLastCoordinate()
            }

            measureTooltipElement.innerHTML = measureResult;
            measureTooltip.setPosition(tooltipCoord);
        })
    })
    // 监听结束绘制事件
    drawAction.on('drawend'function (evt) {
        measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
        measureTooltip.setOffset([-40, -30])
        sketch = null

        measureTooltipElement = null

        createMeasureTooltip()
        // 移除绘制事件
        ol.Observable.unByKey(listener)
    })
}

8. 监听鼠标移动事件

在鼠标移动事件中更改绘制提示信息,当还未开始绘制时显示”点击开始绘制”,当绘制开始后,更新提示信息为”点击继续绘制面”。并且更新会绘制信息叠加图层显示坐标。

// 监听鼠标移动事件
const pointMoveHandler = function (evt) {
    if (evt.dragging) {
        return
    }
    let helpMsg = "点击开始绘制"
    if (sketch) {
        const geom = sketch.getGeometry()
        if (geom instanceof ol.geom.Polygon) {
            helpMsg = "点击继续绘制面"
        }
    }
    if (helpTooltipElement) {
        helpTooltipElement.innerHTML = helpMsg
        helpTooltipElement.classList.remove("hidden")
    }
    helpTooltip.setPosition(evt.coordinate)
}

9. 开始绘制事件

当点击绘制按钮时将鼠标指针修改为**”crosshair”,然后添加绘制图层和绘制对象,并监听鼠标移动事件。绘制测量长度:**

document.querySelector(".measure-distance").addEventListener('click'function (evt) {
    removeActionAndHideElement()
    setCursor("crosshair")
    addDrawLayer()
    addDrawAction("LineString")
    // 监听鼠标移动事件
    map.on('pointermove', pointMoveHandler)
})

绘制测量面积:

document.querySelector(".measure-area").addEventListener('click'function (evt) {
    removeActionAndHideElement()
    setCursor("crosshair")
    addDrawLayer()
    addDrawAction("Polygon")
    // 监听鼠标移动事件
    map.on('pointermove', pointMoveHandler)
})

10. 清除图层

当点击清除按钮时,移除绘制交互对象,结束绘制,并移除所有绘制对象,包括绘制图层以及绘制提示信息和测量提示信息叠加图层,将鼠标指针恢复为默认样式。

document.querySelector(".measure-clear").addEventListener('click'function () {
    setCursor("default")
    removeAllLayer()
    removeActionAndHideElement()
})

创建removeActionAndHideElement方法用于移除绘制交互对象以及清除监听事件并隐藏提示元素。

// 移除绘制交互事件和提示元素
function removeActionAndHideElement() {
    map.removeInteraction(drawAction)
    // 移除绘制事件
    ol.Observable.unByKey(listener)

    sketch = null
    if (measureTooltipElement) {
        measureTooltipElement.parentNode.remove(measureTooltipElement)
        measureTooltipElement = null
    }

    if (helpTooltipElement) {
        helpTooltipElement.parentNode.remove(helpTooltipElement)
        helpTooltipElement = null
    }
}

注:本文参考OpenLayers官方例子修改。

OpenLayers示例数据下载,请在公众号后台回复:ol数据

全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试

GIS之路公众号已经接入了智能助手,欢迎大家前来提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏+关注 

本号不定时更新有关 GIS开发  相关内容,欢迎关注 

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部