基于mapbox-gl实现测距、测面

1,043 阅读2分钟

Mapbox里面是有测量的功能的,测试了一下不怎么好用,于是基于turf.js自己实现了mapbox的测量,话不多说,看效果。

测距效果

测距.png

实现代码

//引入turf.js
 import * as turf from '@turf/turf'  
  function measureDistance(map) {  
let isFlag = true  
// 禁止双击缩放  
map.doubleClickZoom.disable()  
map.getCanvas().style.cursor = 'default'  
clearLayerAndSource(map)  
let jsonPoint = {  
type: 'FeatureCollection',  
features: []  
}  
let jsonLine = {  
type: 'FeatureCollection',  
features: []  
}  
let points = []  
const ele = document.createElement('div')  
ele.setAttribute('class', 'measure-result')  
const option = {  
element: ele,  
anchor: 'left',  
offset: [8, 0]  
}  
let tooltip = new mapboxgl.Marker(option).setLngLat([0, 0]).addTo(map)  
let 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) {  
let 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 (isFlag) {  
var coords = [_e.lngLat.lng, _e.lngLat.lat]  
addMeasureRes(coords)  
addPoint(coords)  
points.push(coords)  
}  
})  
  
map.on('mousemove', function (_e) {  
if (isFlag) {  
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 (isFlag) {  
var coords = [_e.lngLat.lng, _e.lngLat.lat]  
addPoint(coords)  
isFlag = 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: [70, 8]  
}  
ele.innerHTML = '×'  
new mapboxgl.Marker(option).setLngLat(coords).addTo(map)  
ele.onclick = function (__e) {  
__e.stopPropagation()  
map.doubleClickZoom.enable()  
clearLayerAndSource(map)  
}  
}  
})  
}
  

测面效果

测面.png 实现代码

function measureArea(map) {  
var isFlag = true  
// 禁止双击缩放  
map.doubleClickZoom.disable()  
map.getCanvas().style.cursor = 'default'  
clearLayerAndSource(map)  
  
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 (isFlag) {  
var coords = [_e.lngLat.lng, _e.lngLat.lat]  
points.push(coords)  
addPoint(coords)  
}  
})  
  
map.on('dblclick', function (_e) {  
if (isFlag) {  
var coords = [_e.lngLat.lng, _e.lngLat.lat]  
points.push(coords)  
isFlag = 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: [80, 8]  
}  
_ele.innerHTML = '×'  
new mapboxgl.Marker(option).setLngLat(coords).addTo(map)  
_ele.onclick = function (__e) {  
__e.stopPropagation()  
map.doubleClickZoom.enable()  
clearLayerAndSource(map)  
}  
}  
})  
  
map.on('mousemove', function (_e) {  
if (isFlag) {  
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)  
}  
})  
}

清除图层

function clearLayerAndSource(map) {  
const cleardom = document.querySelectorAll('.measure-result')  
Array.from(cleardom).forEach((item) => {  
item.remove()  
})  
  
if (map.getLayer('points')) {  
map.removeLayer('points')  
}  
if (map.getSource('points')) {  
map.removeSource('points')  
}  
if (map.getLayer('line')) {  
map.removeLayer('line')  
}  
if (map.getSource('line')) {  
map.removeSource('line')  
}  
  
if (map.getLayer('line-move')) {  
map.removeLayer('line-move')  
}  
if (map.getSource('line-move')) {  
map.removeSource('line-move')  
}  
if (map.getLayer('points-area')) {  
map.removeLayer('points-area')  
}  
if (map.getSource('points-area')) {  
map.removeSource('points-area')  
}  
if (map.getLayer('line-area-stroke')) {  
map.removeLayer('line-area-stroke')  
}  
if (map.getSource('line-area-stroke')) {  
map.removeSource('line-area-stroke')  
}  
if (map.getLayer('line-area')) {  
map.removeLayer('line-area')  
}  
if (map.getSource('line-area')) {  
map.removeSource('line-area')  
}  
}