最近处理了个webgis相关的功能(拖拽标记点位,测量面积,测量距离)
用的leaflet库
使用的是离线地图
地图是谷歌二维瓦片数据
其他插件:
leaflet-draw(地图测距和测面时绘制线段的功能)
leaflet-measure-path(处理绘制完成的线或者面的显示功能)
leaflet-editable(绘制完成后编辑线段或图形的功能)
以下是对应版本:
"leaflet": "^1.9.4",
"leaflet-draw": "^1.0.4",
"leaflet-measure-path": "^1.5.0",
"leaflet-editable": "^1.2.0",
效果图如下:
以下便是所有代码:
<template>
<div class="container">
<div id="map" @dragover.prevent @drop="onDrop"></div>
<div class="leftbox">
<div
draggable="true"
class="smallbox"
@mousedown="onMousedown($event)"
@dragstart="onDragstart($event)"
@dragend="onDragEnd($event)"
>
按住拖拽
</div>
<div class="smallbox" @click="measureDistance">测距</div>
<div class="smallbox" @click="measureArea">测面</div>
</div>
</div>
</template>
<script>
import L from "leaflet"
// 编辑
import "leaflet-editable"
import "leaflet/dist/leaflet.css"
// 绘制
import "leaflet-draw"
import "leaflet-draw/dist/leaflet.draw.css"
// 鹰眼图
import "./assets/minimap/Control.MiniMap.min.css"
import "./assets/minimap/Control.MiniMap.min.js"
// leaflet-measure-path
import "./assets/path/leaflet-measure-path.js"
import "./assets/path/leaflet-measure-path.css"
export default {
name: "app",
data() {
return {
coordinates: [],
map: null,
marker: "",
lat: "",
lng: "",
polyline: null,
polygon: null,
drawGroupPolyline: null,
drawGroupPolygon: null,
isDrawLine: false,
isDrawPolygon: false,
mainMap: null
}
},
computed: {},
mounted() {
this.initMap()
// 获取delBtn按钮
// 绑定点击事件,使用onclick
},
methods: {
onDrop(event) {
//获取鼠标所在的经纬度
let latlng = this.map.mouseEventToLatLng(event)
console.log(latlng)
this.addIcon(latlng)
},
onMousedown(event) {
console.log("onMousedown")
},
onDragstart(event) {
console.log("onDragstart")
},
onDragEnd(event) {},
initMap() {
// 创建地图实例,将其绑定到 id 参数为 "map" 的 DOM 元素上
this.map = L.map("map", {
zoomControl: false,
attributionControl: false,
editable: true
})
// 设置地图中心点坐标(维度,经度)和初始缩放级别
this.map.setView([22.26, 114.19], 14)
// 创建图层并添加到地图上
var stamenLayer = L.tileLayer(
"http://127.0.0.1:8888/map/{z}/{x}/{y}.png", //自行下载地图瓦片数据后通过nginx部署到服务器或者本地
{
attribution: "地图", // 图层属性信息
minZoom: 12, // 最小缩放级别
maxZoom: 18 // 最大缩放级别
}
).addTo(this.map)
// 默认添加一个多边形框选
let polygon = L.polygon(
[
[22.26, 114.19],
[22.26, 114.2],
[22.27, 114.2],
[22.27, 114.19]
],
{
showMeasurements: true,
weight: 1
}
).addTo(this.map)
polygon.enableEdit()
// 多边形的右击事件
polygon.on("contextmenu", (e) => {
L.popup({
closeButton: false
})
.setLatLng(e.latlng)
.setContent("<button id='delBtn'>删除</button>")
.openOn(this.map)
const delBtn = document.querySelector("#delBtn")
console.log(delBtn)
delBtn.onclick = () => {
this.map.removeLayer(e.target)
// 关闭弹框
this.map.closePopup()
}
})
// 监听多边形的拖拽编辑事件
this.map.on(
"editable:vertex:drag editable:vertex:deleted",
polygon.updateMeasurements,
polygon
)
// 鹰眼图
// 定义一个底图,鹰眼图的layer不能和地图上共用一个,否则无法加载
const minilayer = L.tileLayer(
`http://127.0.0.1:8888/map/{z}/{x}/{y}.png`,
{
minZoom: 12,
maxZoom: 18
}
)
// 使用鹰眼图,添加到地图上
const miniMap = new L.Control.MiniMap(minilayer, {
// 鹰眼图配置项,参数非必须,可以忽略使用默认配置
width: 300, // 鹰眼图宽度
height: 200, // 鹰眼图高度
toggleDisplay: true, // 是否显示最小化按钮
minimized: false // 是否最小化位置开始
}).addTo(this.map)
//监听事件
this.map.on("click", (e) => {
let latlng = e.latlng
})
//
this.getData()
},
//添加图标
addIcon(latlng) {
L.marker([latlng.lat, latlng.lng], {
icon: new L.divIcon({
// iconUrl: "@/assets/logo.png",
className: "lmap-icon",
iconSize: [48, 48],
iconAnchor: [12, 12],
// 标记显示文字和图片,图片使用本地的路径
html: `<img src=${require("@/assets/logo.png")} class="dot-img"/>`
}),
draggable: true
}).addTo(this.map)
},
/**
* 绘制多边形
*/
drawPolygon() {
let map = this.map
this.polygon = new L.Draw.Polygon(map, {
shapeOptions: {
weight: 1,
color: "#3388ff",
opacity: 0.8,
fillColor: "#3388ff"
},
showArea: true
})
this.polygon.enable()
},
/**
* 绘制线段
*/
drawPolyline() {
let map = this.map
this.polyline = new L.Draw.Polyline(map, {
shapeOptions: {
weight: 1,
color: "#3388ff",
opacity: 0.8
}
})
this.polyline.enable()
},
measureDistance() {
if (this.polygon) {
this.polygon.disable()
}
if (this.polyline) {
this.polyline.disable()
}
// 距离
this.isDrawLine = true
this.drawPolyline()
},
measureArea() {
if (this.polyline) {
this.polyline.disable()
}
if (this.polygon) {
this.polygon.disable()
}
this.isDrawPolygon = true
this.drawPolygon()
},
getData() {
// 绘制线段或者面时每点击一下的事件
this.map.on("draw:drawvertex", (e) => {
const { layers } = e
// 获取layers._layers对象最后一个属性
const lastKey = Object.keys(layers._layers)[
Object.keys(layers._layers).length - 1
]
// 获取layers._layers对象倒数第二个属性
const flagKey = Object.keys(layers._layers)[
Object.keys(layers._layers).length - 2
]
// 添加到数组中给leaflet-measure-path绘制最终完成的线段或者面
this.coordinates.push([
layers._layers[lastKey]._latlng.lat,
layers._layers[lastKey]._latlng.lng
])
})
this.drawGroupPolyline = L.featureGroup().addTo(this.map)
this.drawGroupPolygon = L.featureGroup().addTo(this.map)
//绘制时创建事件
this.map.on(L.Draw.Event.CREATED, (event) => {
const { layer, layerType } = event
if (layerType === "polygon") {
// 添加图层
this.drawGroupPolygon.addLayer(layer)
} else if (layerType === "polyline") {
// 添加图层
this.drawGroupPolyline.addLayer(layer)
}
})
// 结束绘制监听
this.map.on(L.Draw.Event.DRAWSTOP, (e) => {
// 绘制完成后判断绘制的类型
if (e.layerType == "polyline") {
let polyline = L.polyline([...this.coordinates], {
showMeasurements: true,
measurementOptions: {
imperial: true,
// 格式化线段上显示的距离单位
formatDistance: function (val) {
return (val / 1000).toFixed(2) + "km"
}
},
// 线条宽度
weight: 1
}).addTo(this.map)
// 可编辑
polyline.enableEdit()
// 点击事件
polyline.on("click", (e) => {
// 弹框
L.popup({
closeButton: false
})
.setLatLng(e.latlng)
.setContent("<button id='delBtn'>删除</button>")
.openOn(this.map)
// 监听按钮事件
const delBtn = document.querySelector("#delBtn")
console.log(delBtn)
delBtn.onclick = () => {
// 删除线段
this.map.removeLayer(e.target)
// 关闭弹框
this.map.closePopup()
}
})
this.map.on(
"editable:vertex:drag editable:vertex:deleted",
polyline.updateMeasurements,
polyline
)
// 清除线段绘制时的线段,上方已将绘制完成的显示在地图上
this.clearMeasureDistance()
// 清空经纬度数组
this.coordinates = []
} else if (e.layerType == "polygon") {
let polygon = L.polygon([...this.coordinates], {
showMeasurements: true,
weight: 1
}).addTo(this.map)
polygon.enableEdit()
polygon.on("contextmenu", (e) => {
// 停止事件冒泡
L.popup({
closeButton: false
})
.setLatLng(e.latlng)
.setContent("<button id='delBtn'>删除</button>")
.openOn(this.map)
const delBtn = document.querySelector("#delBtn")
delBtn.onclick = () => {
this.map.removeLayer(e.target)
// 关闭弹框
this.map.closePopup()
}
})
this.map.on(
"editable:vertex:drag editable:vertex:deleted",
polygon.updateMeasurements,
polygon
)
this.clearMeasureArea()
this.coordinates = []
}
})
//添加画图的提示信息
L.drawLocal.draw.handlers.polyline = {
tooltip: {
start: "点击地图开始画线",
cont: "继续选择",
end: "双击完成绘制"
}
}
L.drawLocal.draw.handlers.polygon = {
tooltip: {
start: "点击地图开始绘制多边形",
cont: "继续选择",
end: "点击第一个顶点完成绘制"
}
}
},
clearMeasureDistance() {
// 距离
this.isDrawLine = false
if (this.polyline) {
this.polyline.disable()
}
// 下面代码是清除画的点
let obj = document.getElementsByClassName("my-div-icon")
for (let i = 0; i < obj.length; i++) {
obj[i].innerHTML = ""
}
// 下面的代码是清除画的线
if (this.drawGroupPolyline) {
this.drawGroupPolyline.clearLayers()
}
},
clearMeasureArea() {
// 面
this.isDrawPolygon = false
if (this.polygon) {
this.polygon.disable()
}
let obj = document.getElementsByClassName("my-div-icon")
for (let i = 0; i < obj.length; i++) {
obj[i].innerHTML = ""
}
if (this.drawGroupPolygon) {
this.drawGroupPolygon.clearLayers()
}
}
}
}
</script>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.container {
height: 100vh;
width: 100%;
position: relative;
#map {
width: 100%;
height: 100%;
.dot-img {
width: 50px;
height: 50px;
}
.leaflet-marker-icon {
width: 100px;
}
.dot-text {
font-size: 20px;
font-weight: 600;
color: rgb(11, 21, 215);
}
}
.leftbox {
z-index: 9999;
width: 100px;
height: 100vh;
background-color: #fff;
position: absolute;
left: 0;
top: 0;
margin-left: 0;
display: flex;
flex-direction: column;
align-items: center;
.smallbox {
width: 50px;
height: 50px;
margin-bottom: 10px;
background-color: red;
}
}
}
.leftbg {
width: 100%;
height: 500px;
}
.lengthbg {
width: 20px;
height: 20px;
background: url(../public/favicon.ico) no-repeat;
background-size: 100% 100%;
margin-bottom: 0.19rem;
}
.areabg {
width: 20px;
height: 20px;
background: url(../public/favicon.ico) no-repeat;
background-size: 100% 100%;
}
.lengthbg_select {
width: 20px;
height: 20px;
background: url(../public/favicon.ico) no-repeat;
background-size: 100% 100%;
margin-bottom: 0.19rem;
}
.areabg_select {
width: 20px;
height: 20px;
background: url(../public/favicon.ico) no-repeat;
background-size: 100% 100%;
}
.leaflet-measure-path-measurement {
font-size: 20px;
color: red;
}
#delBtn {
/* 按照element的按钮样式 */
background-color: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
-moz-appearance: none;
outline: none;
cursor: pointer;
transition: 0.1s;
font-weight: 500;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
&:hover {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
</style>
总结:
总体来说不复杂,网上案例也挺多,对应着leaflet的api文档来处理的话,相对是很轻松的,现在项目中接触到webgis还是挺多的,后期还会继续在这方面处理其他功能