利用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开发一个功能全面的地图编辑器,支持多种形状的绘制和编辑。通过实践这些步骤,开发者可以为用户提供一个强大且灵活的地图绘制工具,满足各种地理信息规划和展示的需求。希望本文能为有志于地图应用开发的你提供帮助和启发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小金子J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值