当前位置: 首页 > article >正文

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


http://www.kler.cn/a/284419.html

相关文章:

  • Docker compose部署portainer
  • (六)Spark大数据开发实战:豆瓣电影数据处理与分析(scala版)
  • 基于OpenCV的自制Python访客识别程序
  • 使用 Keras 训练一个卷积神经网络(CNN)(入门篇)
  • 搭建深度学习开发环境
  • 【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据,LabVIEW 上位机绘制演化曲线
  • 揭秘!糖尿病:从绝望到希望的治愈之路
  • mysql实用系列:coalesce函数的使用
  • 【GIT】idea中实用的git操作,撤回commit,撤回push、暂存区使用
  • 一些好用的网站和api合集
  • 【Python机器学习】NLP词频背后的含义——隐性狄利克雷分布(LDiA)
  • JavaWeb - Maven
  • GMS——利用 ChatGPT 和扩散模型进行制造业革命
  • css-functions-图形函数
  • 08:Logic软件原理图添加元件
  • 【Java设计模式】指挥官模式:轻松编排复杂命令
  • zookeeper命令 及 ACL控制
  • 什么是计算机视觉?
  • IOS 14 封装网络请求框架
  • 银河麒麟高级服务器操作系统(Host版)V10 安装
  • Java算法之梳排序(Comb Sort)
  • Spring Security基于token的极简示例
  • Django 框架中F和Q的作用
  • Stable Diffusion 必备插件推荐,菜鸟轻松成高手!
  • unsloth的微调示例学习-model的构建
  • 70.爬楼梯