基于Leatlet标注Geojson下载器实现

cover

在上一篇文章中,我们学习了Leaflet的基础知识,包括如何创建地图、添加图层等。在本文中,我们将深入学习Leaflet中标注的创建和管理,包括如何添加标注、自定义标注图标、创建图层组、批量添加和删除标注、为标注添加属性和弹出框等。

一、介绍

Leaflet中的标注是指在地图上添加的一种标记,用于标识某个位置。在实际应用中,我们常常需要在地图上添加多个标注,并为其添加属性和弹出框,以便用户可以查看更详细的信息。在本文中,我们将学习如何创建和管理Leaflet中的标注。

二、内容

1.创建标注

在Leaflet中,我们可以使用L.marker方法创建一个标注,并将其添加到地图中。例如:

var marker = L.marker([34.063380, 108.951128]).addTo(map);

这里的[34.063380, 108.951128]就是标注的坐标。

2.自定义标注图标

在创建标注时,我们可以使用icon选项来自定义标注图标。例如:

var myIcon = L.icon({
    iconUrl: 'icon/marker.png',
    iconSize: [20, 30],
    iconAnchor: [10, 30]
});

var marker = L.marker([34.063380, 108.951128], {icon: myIcon}).addTo(map);

这里的iconUrl是图标文件的路径,iconSize是图标的大小,iconAnchor是图标的锚点。

3.创建图层组

如果我们需要在地图上添加多个标注,可以将它们添加到一个图层组中,然后将图层组添加到地图中。这样,多个标注就作为一个图层组呈现在地图上。当需要移除这些标注时,只需移除该图层组即可。例如:

var markers = L.layerGroup().addTo(map);

var marker1 = L.marker([34.063380, 108.951128]).addTo(markers);
var marker2 = L.marker([34.263380, 108.951128]).addTo(markers);
var marker3 = L.marker([34.063380, 109.151128]).addTo(markers);

// 移除所有标注
map.removeLayer(markers);

4.为标注添加属性和弹出框

在创建标注时,我们可以使用title选项来为标注添加一个提示框,使用bindPopup方法为标注添加一个弹出框。例如:

var marker = L.marker([34.063380, 108.951128], {title: '我的位置'}).addTo(map);

marker.bindPopup('CSDN 博主 GISer Liu 认证');

点击标注时,就会显示弹出框。

5.点击开始标注并填写属性

如果我们需要在点击地图时开始标注,并弹出一个弹出框让用户填写标注的属性,可以使用以下代码:

var markers = L.layerGroup().addTo(map);

function onMapClick(e) {
    var marker = L.marker(e.latlng, {draggable: true}).addTo(markers);

    var popupContent = '<form>' +
        '名称: <input id="name" type="text" />' +
        '<br />描述: <input id="desc" type="text" />' +
        '<br /><button id="save">保存</button>' +
        '</form>';

    marker.bindPopup(popupContent).openPopup(); // 设置popup 弹窗的innerHtml为popupContent,并打开该弹窗;

    L.DomEvent.on(marker, 'popupopen', function() {
        L.DomEvent.on('#save', 'click', function() {
            marker.options.title = L.DomUtil.get('name').value;
            marker.bindPopup(L.DomUtil.get('desc').value);
        });
    });
}

map.on('click', onMapClick);

点击地图时,会在该位置创建一个可拖动的标注,并弹出一个弹出框让用户填写标注的名称和描述。点击保存按钮后,会将名称和描述保存到标注的title和弹出框中。

6.右击设置标注属性

如果我们需要在右击标注时设置标注的属性,可以使用以下代码:

function onMarkerContextMenu(e) {
    var marker = e.target;
    var popupContent = '<form>' +
        '名称: <input id="name" type="text" value="' + marker.options.title + '" />' +
        '<br />描述: <input id="desc" type="text" value="' + marker.getPopup().getContent() + '" />' +
        '<br /><button type="button" id="save">保存</button>' +
        '</form>';

    marker.bindPopup(popupContent).openPopup();

    L.DomEvent.on(marker, 'popupopen', function() {
        L.DomEvent.on('#save', 'click', function() {
            marker.options.title = L.DomUtil.get('name').value;
            marker.bindPopup(L.DomUtil.get('desc').value);
        });
    });
}

markers.on('contextmenu', onMarkerContextMenu);

点击标注时,会弹出一个弹出框让用户设置标注的名称和描述。点击保存按钮后,会将名称和描述保存到标注的title和弹出框中。

7. 移除已有标注

方法有二

①清除图层组
markers.clearLayers();
②移除整个图层组,然后重新初始化添加
map.removeLayer(markers);
markersInfo = [];
markers = L.layerGroup().addTo(map);

三、Leaflet标注Geojson数据下载器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #map {
            height: 100vh;
            width: 100vw;
            box-sizing: border-box;
            overflow: hidden;
            cursor: pointer;
            z-index: 0;
        }

        #map-click {
            position: absolute;
            top: 30px;
            left: 60px;
            border: none;
            outline: none;
            width: 60px;
            height: 60px;
            border-radius: 50%;
            box-sizing: border-box;
            transition: all 200ms;
            box-shadow: #333 4px 4px 8px;
            background-color: red;
            color: yellow;
            font-size: 1.2em;
            font-family: 'Courier New', Courier, monospace;
            z-index: 100;
        }

        #map-click:active {
            box-shadow: #e0dcdc 2px 2px 4px;
            background-color: green;
        }

        #download {
            position: absolute;
            width: 70px;
            height: 50px;
            top: 10px;
            right: 10px;
            z-index: 100;
            display: none;
        }

        #clear {
            position: absolute;
            width: 70px;
            height: 50px;
            top: 60px;
            right: 10px;
            z-index: 100;
            display: none;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <button id="map-click">mark</button>
    <button id="download">下载</button>
    <button id="clear">清除标注</button>


    <script>
        var map = L.map('map').setView([34.063380, 108.951128], 13)
        var clickBtn = document.querySelector('#map-click')
        var downloadBtn = document.querySelector('#download')
        var clearBtn = document.querySelector('#clear')
        // 存储构建的geojson数据
        var markersInfo = [];

        // 增加OSM底图
        L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        }).addTo(map);

        // 设置标注图标
        var myIcon = L.icon({
            iconUrl: '../assit/marker.png',
            iconSize: [20, 30], // 尺寸
            iconAnchor: [10, 15] // 图标左上角相对于标记点的偏移,这里图标大小为[20,30],则为了保证中央,我们要往左偏移10,向上偏移15;
        });

        // 创建图层组,本质也是一个数组对象
        var markers = L.layerGroup().addTo(map);

        // 创建地图点击事件
        function onMapClick(e) {
            var marker = L.marker(e.latlng, { icon: myIcon, draggable: true }).addTo(markers);
            var popupContent = document.createElement('div');

            var nameInput = document.createElement('input');
            nameInput.type = 'text';
            nameInput.placeholder = '名称';

            var descInput = document.createElement('input');
            descInput.type = 'text';
            descInput.placeholder = '描述';

            var saveBtn = document.createElement('button');
            saveBtn.type = 'button';
            saveBtn.textContent = '保存';

            popupContent.appendChild(nameInput);
            popupContent.appendChild(document.createElement('br'));
            popupContent.appendChild(descInput);
            popupContent.appendChild(document.createElement('br'));
            popupContent.appendChild(saveBtn);

            marker.bindPopup(popupContent);

            marker.on('popupopen', function () {
                downloadBtn.style.display = 'block'
                clearBtn.style.display = 'block'
                L.DomEvent.on(saveBtn, 'click', function () {
                    saveMarkerInfo(marker, nameInput, descInput);
                });
            });

            function saveMarkerInfo(marker, nameInput, descInput) {
                marker.options.title = nameInput.value;
                marker.setPopupContent(descInput.value);
                console.log(123);

                var markerInfo = {
                    title: marker.options.title,
                    desc: marker.getPopup().getContent(),
                    latlng: marker.getLatLng()
                };
                markersInfo.push(markerInfo);
                console.log(markersInfo);

            }

            marker.openPopup();
        }
        // 标注点击事件
        function onMarkerContextMenu(e) {
            var marker = e.target;
            var popupContent = '<form>' +
                '名称: <input id="name" type="text" value="' + marker.options.title + '" />' +
                '<br />描述: <input id="desc" type="text" value="' + marker.getPopup().getContent() + '" />' +
                '<br /><button id="save" type = "button">保存</button>' +
                '</form>';


            marker.bindPopup(popupContent).openPopup();

            L.DomEvent.on(marker, 'popupopen', function () {
                L.DomEvent.on('#save', 'click', function (event) {
                    marker.options.title = L.DomUtil.get('name').value;
                    marker.bindPopup(L.DomUtil.get('desc').value);
                    downloadBtn.style.display = "black"
                });
            });
        }

        // 标注切换点击事件
        flag = false
        clickBtn.addEventListener('click', () => {
            flag = !flag
            if (flag) {
                map.on('click', onMapClick);
            } else {
                map.off('click', onMapClick)
            }
        })
        markers.on('contextmenu', onMarkerContextMenu);

        // 监听下载按钮的点击事件
        downloadBtn.addEventListener('click', function () {
            // 构建 geojson 数据
            var geojsonData = {
                type: "FeatureCollection",
                features: []
            };
            // 遍历markersInfo 然后存储元素信息到geojson
            markersInfo.forEach(function (markerInfo) {
                // 构建geojson元素
                var feature = {
                    type: "Feature",
                    properties: {
                        name: markerInfo.title,
                        desc: markerInfo.desc
                    },
                    geometry: {
                        type: "Point",
                        coordinates: [markerInfo.latlng.lng, markerInfo.latlng.lat]
                    }
                };
                // 保存到features属性中
                geojsonData.features.push(feature);
            });


            // 将 geojsonData 序列化为 JSON 字符串,并指定 MIME 类型为 'application/json'
            var blob = new Blob([JSON.stringify(geojsonData)], { type: 'application/json' });
            // 创建一个 blob URL,用于下载
            var url = window.URL.createObjectURL(blob, { oneTimeOnly: true });
            // 创建一个新的超链接元素
            var a = document.createElement('a');
            // 设置超链接的 href 属性为 blob URL
            a.href = url;
            // 设置超链接的 download 属性为 'markers.geojson',表示下载的文件名为 'markers.geojson'
            a.download = 'markers.geojson';
            // 触发超链接的点击事件,开始下载
            a.click();
            window.URL.revokeObjectURL(url);
        });

        clearBtn.addEventListener('click', () => {
            // 移除 markers 图层组
            // map.removeLayer(markers);
            // 清空 markersInfo 数组
            // markersInfo = [];
            // 隐藏下载按钮
            // downloadBtn.style.display = 'none';
            // 重新创建一个空的图层组
            // markers = L.layerGroup().addTo(map);
            // 清空 markers 图层组
            markers.clearLayers();
            // 隐藏下载按钮
            downloadBtn.style.display = 'none';
            clearBtn.style.display = 'none';
        })

    </script>
</body>

</html>
效果如下:

output

四、总结

本文介绍了Leaflet中标注的创建和管理,包括如何添加标注、自定义标注图标、创建图层组、批量添加和删除标注、为标注添加属性和弹出框等。通过示例代码,我们学会了如何实现点击开始标注并填写属性,以及右击设置标注属性。最后实现了一个地图标注geojson下载器,这些知识在实际应用中非常有用,希望对大家有所帮助。

文章参考

  • Leaflet 官方文档:https://leafletjs.com/reference.html
  • Leaflet 中文网:https://leafletjs.com.cn/

项目地址

  • Github地址
  • 拓展阅读

如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/440258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二、TensorFlow结构分析(4)

TF数据流图图与TensorBoard会话张量Tensor变量OP高级API 目录 1、变量 2、高级API 1、变量 2、高级API

[嵌入式系统-37]:龙芯1B 开发学习套件 -6-协处理器CP0之CPU异常处理与外部中断控制器的中断处理

目录 一、MPIS CPU Core与32个异常exception 1.1 龙芯1B的MIPS CPU IP Core 1.2 MIP32指令系统 1.3 MIPS CPU寄存器 1.4 MIPS CPU的异常向量与异常向量号 1.5 龙芯异常exception与中断interrupt的区别 二、协议处理器CP0的中断控制与8个中断 2.1 CP0概述 2.2 协处理器…

Word文档一键转换成电子书,告别繁琐操作!

你是否曾经为了将Word文档转换为电子书而苦恼&#xff1f;手动复制粘贴、调整格式、排版等等繁琐的操作&#xff0c;不仅耗时费力&#xff0c;还容易出错。现在我教你只需轻轻一点&#xff0c;即可将Word文档轻松转换为电子书&#xff0c;无需任何手动操作 一、Word转换电子书步…

基于React低代码平台开发:直击最新应用构建

文章目录 前言一、React与低代码平台的结合优势二、基于React的低代码平台开发挑战三、基于React的低代码平台开发实践四、未来展望《低代码平台开发实践&#xff1a;基于React》编辑推荐内容简介作者简介目录前言为什么要写这本书读者对象如何阅读本书 前言 随着数字化转型的…

Word论文格式怎么设置 Word论文查重功能在哪里 论文格式要求及字体大小 论文查重怎么查 WPS论文查重准确吗

Word文档是由Microsoft Word处理软件创建和编辑的文档。Word文档通常用于创建各种类型的文档&#xff0c;如信函、报告、简历、论文等。本篇文章将为大家介绍Word论文格式怎么设置以及Word论文查重功能在哪里。 一、Word论文格式怎么设置 一个好的论文格式&#xff0c;是论文…

【框架设计】MVC、MVP、MVVM对比图

1. MVC&#xff08;Model-View-Controller&#xff09; 2. MVP&#xff08;Model-View-Presenter&#xff09; 3. MVVM&#xff08;Model-View-ViewModel&#xff09;

ai数字人虚拟直播:AI大模型带给你不一样的体验

AI数字人虚拟直播&#xff0c;这一新兴的科技形式&#xff0c;正逐渐融入人们的生活之中。通过AI大模型的技术支持&#xff0c;数字人可以实现高度仿真的互动体验&#xff0c;让观众感受到前所未有的沉浸式乐趣。 数字人虚拟直播的魅力在于其超越了传统直播形式的局限性&#…

Python爬虫——Scrapy-1

目录 简介 安装 基本使用 1. 创建爬虫的项目 2. 创建爬虫文件 3. 运行爬虫代码 scrapy项目组成 scrapy工作原理 ​编辑 58同城 scrapy架构组成 汽车之家 总结 简介 Scrapy 是一个基于 Python 的开源网络爬虫框架&#xff0c;它可以帮助开发者快速、高效地构…

数据结构从入门到精通——栈

栈 前言一、栈1.1栈的概念及结构1.2栈的实现1.3栈的面试题 二、栈的具体实现代码栈的初始化栈的销毁入栈出栈返回栈顶元素返回栈中的元素个数检测是否为空Stack.hStack.ctest.c 前言 栈&#xff0c;作为一种后进先出&#xff08;LIFO&#xff09;的数据结构&#xff0c;在计算…

Windows系统搭建it-tools工具箱并结合内网穿透实现公网远程访问

文章目录 1. 使用Docker本地部署it-tools2. 本地访问it-tools3. 安装cpolar内网穿透4. 固定it-tools公网地址 本篇文章将介绍如何在Windows上使用Docker本地部署IT- Tools&#xff0c;并且同样可以结合cpolar实现公网访问。 在前一篇文章中我们讲解了如何在Linux中使用Docker搭…

FPGA FIFO 读取模式

FPGA FIFO 读取模式分两种&#xff1a; Normal Mode: In normal mode, the “rdreq” signal serves as the read request or read enable. When this signal goes high, the data output provides the first data from the FIFO.Essentially, in normal mode, data is availa…

pytest测试框架使用基础07 fixture—parametrize获取参数的几种常用形式

【pytest】parametrize获取参数的几种常用形式: a.数据结构 b.文件 c.数据库 d.conftest.py配置一、直接在标签上传参 1.1 一个参数多个值 pytest.mark.parametrize("参数", (参数值1, 参数值2, 参数值3))示例&#xff1a; import pytest # 单个参数的情况 pytest.…

如何向各大媒体网站投稿 海外媒体发稿平台有哪些

在数字化时代&#xff0c;各大媒体网站是企业推广和个人展示的重要平台。通过在媒体网站上发布文章&#xff0c;可以有效地扩大影响力和提升知名度。但是&#xff0c;如何投稿到各大媒体网站呢&#xff1f;以下是一些常用的方法和步骤。 1. 研究目标媒体 在投稿之前&#xff0…

宠物空气净化器值得入手吗?选购宠物空气净化器关注哪些方面?

一开始养猫时&#xff0c;每天看着可爱的猫咪在家里快乐奔跑&#xff0c;让人心情愉悦。然而&#xff0c;作为铲屎官都知道&#xff0c;猫咪会掉毛&#xff0c;特别是在换毛期间&#xff0c;地板、沙发上都会有一大堆猫毛&#xff0c;甚至衣服也可能沾满猫毛。养猫家庭中&#…

安装邮件服务器postfix、mail客户端发送邮件

安装邮件服务器postfix、mail客户端发送邮件 1 安装postfix sudo apt-get update sudo apt-get install postfix -y安装过程中会让你选择一种Postfix配置类型&#xff0c;直接选择默认的第二种配置Internet Site就可以了。 选择ok之后会让你填入域名&#xff0c;一般会自动填…

鞋服品牌怎样合理把控订货深度和宽度

在鞋服品牌的运营管理中&#xff0c;订货深度和宽度是两个至关重要的概念。订货深度指的是某一款式或规格的产品数量&#xff0c;而订货宽度则代表品牌所涵盖的产品种类和款式。合理把控订货深度和宽度对于品牌的库存管理、销售情况以及顾客满意度都有着深远的影响。本文将探讨…

MindOpt优化器: 浅谈版本0.x和1.x之间API的差异

Mindopt 是一个优化求解器&#xff0c;如果它有两个主要版本——0.xx和1.x.x&#xff08;最新版本1.1.1&#xff09;&#xff0c;它们代表着软件开发的两个不同阶段。版本1.0.0表示软件的一个大的里程碑&#xff0c;代表着软件第一个正式的“成熟”发布版本&#xff0c;而0.25是…

【保姆级爬虫】微博关键词搜索并获取博文和评论内容(python+selenium+chorme)

微博爬虫记录 写这个主要是为了防止自己忘记以及之后的组内工作交接&#xff0c;至于代码美不美观&#xff0c;写的好不好&#xff0c;统统不考虑&#xff0c;我只能说&#xff0c;能跑就不错了&#xff0c;上学压根没学过python好吧&#xff0c;基本上是crtlc&ctrlv丝滑小…

说说flexbox(弹性盒布局模型)及适用场景?

文章目录 一、是什么二、属性flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-contentorderflex-growflex-basisflexalign-self 三、应用场景参考文献 一、是什么 Flexible Box 简称 flex&#xff0c;意为”弹性布局”&#xff0c;可以简便、完整、响应式地…

轻松关掉电脑用户账户控制弹窗!

对于新装的或者是电脑自带的系统来说,是不是会经常遇到的一个情况是,就是在你运行某些程序或者改动一些系统设置的时候,每次都会弹出个提示框,以提示你这个操作是安全的,某一个提示还行,但是每次运行程序都有提示框弹出,就会有点烦了,那么这个提示框是什么呐,如何关闭…