利用Leaflet.js创建交互式地图:多种形状单个区域绘制
引言
在地图应用开发中,用户经常需要对特定区域进行标识和规划。本文将深入探讨如何利用Vue.js的响应式特性与Leaflet.js的地图功能,打造一个支持多边形、矩形、圆形等多种形状绘制的交互式地图编辑器。
功能亮点
- 自由绘制多边形:用户可以自由地在地图上绘制多边形区域。
- 规则形状快速绘制:支持矩形和圆形的快速绘制,适用于规则区域标识。
- 灵活的区域编辑:提供区域删除和重新绘制功能,满足用户编辑需求。
- 个性化样式定制:用户可以自定义每个区域的名称和颜色,使地图更加个性化。
- 响应式文本标注:文本标注会根据地图缩放级别智能显示,提升用户体验。
实现步骤与代码示例
这里提供的代码块仅展示了部分关键功能,以帮助读者理解整个实现过程,完整的代码和项目资源可以在个人中心-资源库获取
1. 模板代码
模板代码是构建地图绘制功能界面的基础,结合Vue的数据绑定和事件处理能力,可以创建一个交互性强、用户友好的地图编辑工具
<template>
<div class="mapContainer">
<div id="mapRef" ref="mapRef" style="height: 400px;"></div>
<!-- 工具栏 -->
<div class="control" v-if="!enableMapClick">
<div class="color">
<div class="title">区域名称/颜色:</div>
<el-input v-model="polygonStyle.regionName" placeHolder="区域名称" style="width:150px"></el-input>
<el-color-picker v-model="polygonStyle.color"></el-color-picker>
</div>
<div class="shape" v-if="isDraw">
<div class="shapeItem" v-for="(item,index) in shapeList" :key="index" :class="{'active':polygonStyle.shape == index + 1}" @click="polygonStyle.shape = index + 1">
<img :src="polygonStyle.shape == index + 1 ? item.imgActive : item.img" alt="">
<div class="title">{{ item.name }}</div>
</div>
</div>
<div class="startOrdelete" @click="startDrawItems" v-if="isDraw">
<img src="@/assets/images/electronicChart/start.png" alt="">
</div>
<div class="startOrdelete" @click="clearDrawnItems" v-else>
<img src="@/assets/images/electronicChart/delete.png" alt="">
</div>
</div>
</div>
</template>
2. 地图初始化
在Vue组件的mounted
生命周期钩子中初始化地图,并设置地图的初始视图和交互行为
// 初始化加载
initMap() {
// 实例
this.map = L.map("mapRef", {
center: [21.582007, 111.824558], // 地图中心
zoom: 15, // 缩放比列
zoomControl: false, // 是否显示 + - 按钮
doubleClickZoom: false, // 是否双击放大
// scrollWheelZoom: false, // 是否可以通过滑轮缩放
attributionControl: false, // 是否显示右下角leaflet标识
});
// 加载出地图
this.name = L.tileLayer(
"http://webrd01.is.autonavi.com/....(省略地址)",
{
maxZoom: 18,
attribution: '© OpenStreetMap contributors',
},
).addTo(this.map);
if (!this.drawnItems) {
this.drawnItems = new L.FeatureGroup().addTo(this.map);
}
if(this.latitudeLongitude){
this.renderRegion()
this.isDraw = false
}
},
3.多边形/矩形/圆形绘制实现
处理绘制事件,为新创建的图层设置样式,并添加到地图上。
3.1 多边形绘制
3.2 矩形绘制
3.3 圆形绘制
// 开启绘制区域图层
startDrawItems(){
if(this.polygonStyle.regionName && this.polygonStyle.color && this.polygonStyle.shape){
if (!this.drawnItems) {
var drawnItems = new L.FeatureGroup();
this.drawnItems = drawnItems;
this.map.addLayer(this.drawnItems);
}
this.drawControl = new L.Control.Draw({
draw: { circlemarker: false },
edit: {
featureGroup: this.drawnItems,
},
});
this.drawnItems.clearLayers();
if(this.polygonStyle.shape == 1){
// 多边形绘制开启
this.polygon = new L.Draw.Polygon(
this.map,
this.drawControl.options.polygon
).enable();
}else if(this.polygonStyle.shape == 2){
// 矩形绘制开启
this.Rectangle = new L.Draw.Rectangle(
this.map,
this.drawControl.options.rectangle
).enable();
}else if(this.polygonStyle.shape == 3){
// 圆形绘制开启
this.circle = new L.Draw.Circle(
this.map,
this.drawControl.options.circle
).enable();
}
this.map.on(L.Draw.Event.CREATED, (event) => {
console.log(event, "绘制事件");
var type = event.layerType;
var layer = event.layer;
// 设置填充颜色
layer.setStyle({ color: this.polygonStyle.color,fillColor: this.polygonStyle.color });
// 添加文字标注
this.createTextDivIcon(layer);
// 添加到地图上
this.drawnItems.addLayer(layer);
console.log(layer._latlngs, "点位数据");
if (type === "polygon") {
// 多边形
this.polygonStyle.latitudeLongitude = this.convertPolygonsData(layer._latlngs)
} else if (type === "rectangle") {
// 矩形
this.polygonStyle.latitudeLongitude = this.convertPolygonsData(layer._latlngs)
} else if (type === "circle") {
// 圆形
this.polygonStyle.radius = layer._mRadius;
this.polygonStyle.latitudeLongitude = layer._latlng.lat + ',' + layer._latlng.lng;
}
this.isDraw = false
this.$emit('draw-clicked', this.polygonStyle); // 触发事件,传递绘制区域数据
})
}else{
this.$message({
message: "请选择区域名称、颜色、形状",
type: "warning",
});
}
},
// 创建一个文字标记,将文字图标放置在多边形的中心点
createTextDivIcon(layer){
let center;
if (layer instanceof L.Polygon || layer instanceof L.Rectangle) {
center = layer.getBounds().getCenter();
} else if (layer instanceof L.Circle) {
center = layer.getLatLng();
}
const textIcon = L.divIcon({
html: `<div class="berth-no-label">${this.polygonStyle.regionName}</div>`,
className: 'my-div-icon',
iconSize: [40, 14],
iconAnchor: [14, 9.5],
});
const marker = L.marker(center, { icon: textIcon });
marker.on('click', e => {
console.log('标记点击');
});
this.drawnItems.addLayer(marker); // 将标记添加到绘制的图层组
},
4.区域编辑与删除
提供方法以清除地图上的绘制区域,允许用户进行重新绘制或编辑。
// 清除绘制区域图层
clearDrawnItems() {
// 清空图层组中的所有图层
if (this.drawnItems) {
this.drawnItems.clearLayers();
}
this.drawnItems = null; // 重置drawnItems
this.isDraw = true
},
// 开启绘制区域图层
startDrawItems(){
......
},
5.样式自定义修改
允许用户通过界面元素设置区域的名称和颜色,这些设置将实时反映在地图上。
6. 响应式文本标注
根据地图的缩放级别动态调整文本标注的显示,优化视觉效果。
// 当缩放结束时触发(实现多边形上的文字随地图缩放而变化大小)
handleZoomChange(e) {
const zoomLevel = e.target._zoom;
const minZoomToShowText = 15; // 定义最小缩放级别以显示文本
// 获取所有文本标记
this.map.eachLayer((layer) => {
if (layer instanceof L.Marker) {
const icon = layer.options.icon;
if (icon.options.className === "my-div-icon") {
// 根据缩放级别调整文字大小或隐藏
if (zoomLevel < minZoomToShowText) {
// 缩小到一定程度,隐藏文本
layer.setOpacity(0);
} else {
// 其他情况,显示文本并可能调整大小
layer.setOpacity(1);
// 这里可以添加更多逻辑来调整文字大小
}
}
}
});
},
结语
本文详细介绍了如何使用Vue.js和Leaflet.js开发一个功能全面的地图编辑器,支持多种形状的绘制和编辑。通过实践这些步骤,开发者可以为用户提供一个强大且灵活的地图绘制工具,满足各种地理信息规划和展示的需求。希望本文能为有志于地图应用开发的你提供帮助和启发。