利用Leaflet.js创建交互式地图:多种形状单个区域绘制

news2024/12/23 4:50:33

引言

        在地图应用开发中,用户经常需要对特定区域进行标识和规划。本文将深入探讨如何利用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.coloradmin.cn/o/2092172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql基础语法——个人笔记

0 前言 以前学习且实践过mysql&#xff0c;但后来用得少&#xff0c;随着岁月更替&#xff0c;对其印象渐浅&#xff0c;所以每次需要用时&#xff0c;都会去再看一眼语法规范&#xff0c;然后才能放心动手操作 然而&#xff0c;在信息爆炸的时代&#xff0c;查语法规范时&am…

BUUCTF PWN wp--jarvisoj_level0

第一步 checksec &#xff0c;该题为64位。 分析一下二进制保护机制&#xff1a; Arch: amd64-64-little 这个字段表示二进制程序的架构是 64 位的小端序的 x86-64 架构。小端序意味着低位字节存储在内存中的低地址上&#xff0c;高位字节存储在高地址上。RELRO: No RELRO …

迁移学习之领域自适应(domain adaptation)

比如有一堆有标注的训练数据&#xff0c;这些数 据来自源领域&#xff0c;用这些数据训练出一个模型&#xff0c;这个模型可以用在不一样的领域。在训练的时 候&#xff0c;我们必须要对测试数据所在的目标领域有一些了解。 随着了解的程度不同&#xff0c;领域自适应的方法也不…

(C++ STL)vector类的简单模拟实现与源码展示

vector类的简单模拟实现 一、前言二、vector 的成员变量三、vector 部分函数实现size、capacityreserveresizeinsert 与注意事项erase构造、析构、赋值拷贝 四、vector 源代码 以下代码环境为 VS2022 C。 一、前言 vector类 本质上就是数据结构中的顺序表。(可参考&#xff1…

【最新华为OD机试E卷】boos的收入(100分)-多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,…

4.负载均衡

文章目录 1.多级部署2.实现请求计数器3.负载均衡3.1服务端负载均衡3.2客户端负载均衡3.3自定义负载均衡3.4负载均衡策略3.5 LoadBalance 原理 4.部署实现 大家好&#xff0c;我是晓星航。今天为大家带来的是 负载均衡 相关的讲解&#xff01;&#x1f600; 1.多级部署 复制一…

C语言 | Leetcode C语言题解之第378题有序矩阵中第K小的元素

题目&#xff1a; 题解&#xff1a; bool check(int **matrix, int mid, int k, int n) {int i n - 1;int j 0;int num 0;while (i > 0 && j < n) {if (matrix[i][j] < mid) {num i 1;j;} else {i--;}}return num > k; }int kthSmallest(int **matri…

面试题小总结

一、为什么要使用Redis&#xff1f; 因为它是内存数据库&#xff0c;运行速度快因为它的工作线程是单线程&#xff0c;具有串行化&#xff0c;原子性具有IO模型&#xff0c;天生支撑高并发是kv模型&#xff0c;v具有多个数据结构具有本地方法&#xff0c;可以计算数据移动是二…

Mac用户必备:轻松添加Git SSH密钥全攻略

最近新买了一台MacBook笔记本&#xff0c;然后安装了git&#xff0c;准备下载代码&#xff0c;正好遇到配置GitHub的ssh密钥&#xff0c;记录一下整个操作流程。 操作步骤 在Mac上添加Git SSH密钥的步骤如下&#xff1a; 检查是否已有SSH密钥&#xff1a; 打开终端&#xff0…

Nginx: https解决安全问题

https原理 1 &#xff09;http协议存在的问题 数据使用明文传输&#xff0c;可能被黑客窃取 (需要信息加密)报文的完整性无法验证&#xff0c;可能被黑客篡改 (需要完整性校验)无法验证通信双方的身份&#xff0c;可能被黑客伪装 (需要身份认证) 2 ) https 原理 所谓 https,…

新160个crackme - 043-riijj_cm_20041121

运行分析 除了主程序还有一个dll文件&#xff0c;应该是要加载pf1.dll这个动态链接库运行主程序&#xff0c;需破解Name和Serial&#xff0c;点击注册无反应 PE分析 C程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 尝试ida动调加载动态链接库pf1.dll&#xff0c…

全能型AI“草莓”:未来趋势还是市场泡沫?

你好&#xff0c;我是三桥君 近日&#xff0c;OpenAI宣布将在秋季推出代号为“草莓”的新AI模型。这一消息迅速引起了科技界和市场的广泛关注。 OpenAI的新项目“草莓”&#xff08;Strawberry&#xff09;是一个备受关注的人工智能模型&#xff0c;预计将在今年秋季发布。这个…

算法复盘——LeetCode hot100:哈希

文章目录 哈希表哈希表的基本概念哈希表的使用1. 插入操作2. 查找操作3. 删除操作 哈希表的优点和缺点1.两数之和复盘 242.有效的字母异位词复盘 49.字母异位词分组复盘 128. 最长连续序列复盘HashSet 哈希表 先来搞清楚什么是哈希表吧~ 概念不清楚方法不清楚怎么做题捏 哈希表…

MongonDB-索引

一、索引-index (一) 概述 索引支持在MongoDB中高效地执行查询。如果没有索引&#xff0c;MongoDB必须执行全集合扫描&#xff0c;即扫描集合中的每个文档&#xff0c;以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的&#xff0c;特别在处理大量的数据时&am…

firewalld 防火墙常用命令,新手必看

firewalld 防火墙常用命令 防火墙状态命令 systemctl start firewalld #启动防火墙 systemctl stop firewalld #关闭防火墙 systemctl restart firewalld #重启防火墙 systemctl enable firewalld #设置开机自启 systemctl disable firewalld #禁用开机自启 systemctl s…

自己开发完整项目一、登录功能-03(使用springSecurity安全框架,查询用户角色权限)

一、说明 在前面两章节&#xff0c;实现了通过springsecurity来进行用的登录认证&#xff0c;当用户输入用户名和密码之后&#xff0c;通过额数据库中的信息比对&#xff0c;比对成功那么放行。但是还存在一个问题&#xff1a;因为系统的所有页面包括按钮都是有各自的权限&…

全网最全robotframework自动化测试环境搭建

一、前言 1、在2019年之前&#xff0c;robotframework-ride的版本一直是1.5.2.1&#xff0c;是2016年1月份的版本&#xff0c;只能安装在python2.7的环境上&#xff0c;导致如果想同时使用robotframework做测试且又需要python3环境编写python代码的小伙伴都需要在操作系统上安…

Golang 读取文件

GoLang读取文件需要用到os类去打开文件&#xff0c;然后再用其他方式分析文件里的内容。打开文件比较简单&#xff0c;使用os.Open就可以了&#xff0c;记住用defer关闭就行。但是读取文件内容就头疼了&#xff0c;以文本文件为例子&#xff0c;就有各种方式 读取到byte数组 首…

渐进式衰老?医美三剑客的“市梦率”幻灭了

医美股神话彻底幻灭了。 从股价蒸发到业绩失速&#xff0c;“医美三剑客”上演着繁华落幕&#xff0c;回归平凡的剧本。 近一年来&#xff0c;爱美客、华熙生物、昊海生科股价分别累计下跌52.97%、46.03%、16.09%。 “医美三剑客”近一年累计跌幅&#xff08;资料来源&#x…

分水岭算法简介

分水岭算法是一种经典的图像分割技术&#xff0c;广泛应用于图像处理领域。它的名称源自地理学中的“分水岭”概念&#xff0c;即在地形中&#xff0c;水从高处流向低处&#xff0c;最终汇聚成河流的过程。在图像分割中&#xff0c;分水岭算法将灰度图像视为地形&#xff0c;将…