如何使用Jquery在Leaflet地图上绘制多个标记
标记是地理空间工具,用于指出或显示所需对象的位置,给定一个地理坐标系统(GCS)。GCS是一个与地球上的位置相关的坐标系统。纬度和经度是地理坐标系统的类型。东经和北纬是网格系统,属于地理坐标系统的类型。
Leaflet.js使得使用一行简单的代码在特定地点绘制标记变得更加容易。有了jquery和一个简单的前端模态,我们可以更上一层楼。
我们将向你展示如何建立一个输入框来填入这些坐标并在地图上呈现。有geojson代替吗,我们将指导你如何将JSON文件上传到你的地图上的过程。
那我们就开始吧!
前提条件
读者应该有以下的知识。
- [JavaScript]
- [HTML]
- [CSS]
- [Bootstrap]
- [Leaflet基础知识]
- [Visual studio代码]
- [Sublime text]
目标
在本指南中,我们将向读者展示在小册子地图上绘制多个标记的三种方法。
在本教程结束时,读者应该能够。
- 添加一个瓦片层。
- 在他们的代码中用geojson绘制标记,使用leaflet。
- 将geojson标记文件上传到前端的地图上。
- 使用jquery在前端绘制标记作为输入。
开始使用
添加一个瓦片层
为了开始,我们将初始化我们的HTML5模板,并使用内容交付网络(CDN)导入leaflet.js JavaScript和CSS文件。
例子
<html lang="en">
<head>
<title>Multiple Markers</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
</head>
<body>
</body>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
</html>
接下来,我们将在我们的HTML中创建一个style 、div 和script 标签。div 将作为我们的地图的容器,所以我们将给它一个id名:map 。style 标签是用来设计我们的容器布局的,而script 标签包含初始化地图的JavaScript代码。
我们有一个例子,如下所示。
<div id="map"></div>
body {
padding: 0;
margin: 0;
}
#map {
height: 100vh;
width: 100%;
}
var map = L.map('map').setView([9.0820, 8.6753], 7)
L.tileLayer('https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', {
maxZoom: 20,
attribution: '<a href="https://github.com/cyclosm/cyclosm-cartocss-style/releases" title="CyclOSM - Open Bicycle render">CyclOSM</a> | Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
所有这些汇集在一起,我们应该有我们的baselayer(OSM层)准备好,如下图所示。

使用leaflet用geojson绘制标记物
根据维基百科,"GeoJSON是一种开放的标准格式,用于表示简单的地理特征,以及它们的非空间属性。它是基于JSON格式的"。
像geojson.io这样的网站已经简化了获得你想要的地理JSON数据的格式。Leaflet让我们更容易使用一小行代码在地图上呈现这些数据。
首先,我们要导入JSON文件。将JSON文件导入JavaScript有多种方法,但在本节中,我们必须将其内容复制出来并粘贴到一个给定的JavaScript变量中。
我们冒昧地获取了一个带有标记特征的geojson,以用于下面的例子。
var sample_json = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
9.778320312499999,
7.557417356841308
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
9.943115234375001,
7.801090616449597
]
}
}
]
}
然后我们用下面的代码把它添加到地图上。
L.geoJSON(sample_json).addTo(map);
将所有这些特征加在一起,我们应该有以下的结果。

使用文件上传和小册子用geojson绘制标记物
本节与上节有一些相似之处。不同的是,虽然我们之前将JSON作为一个JavaScript变量添加,但在这里它将作为一个文件在前端上传。通过json.parse() 方法,我们将把一个json字符串解析为一个javascript对象。
为了开始,我们将创建一个文件上传和提交按钮。
<nav class="navbar navbar-inverse">
<div class="conatiner-fluid">
<form method="post" enctype="multipart/form-data">
<div class="form-group form-inline">
<input class="form-control" name="files[]" type="file" accept=".json">
<input class="btn btn-primary" type="submit" value="Upload File" name="submit">
</div>
</form>
</div>
</nav>
注意:我们使用bootstrap 5进行设计。
我们此刻应该有这样的东西。

我们需要抓取表单和输入字段并监听提交事件。如果我们点击提交按钮,我们将需要一个函数来处理它。在上传区域没有文件而我们点击提交按钮的情况下,event.preventDefault() 方法可以防止采取任何行动。接下来,我们将创建一个新的文件阅读器对象,并在文件被读取时创建一个回调事件。
我们在下面有一个这样的实现的例子。
let form = document.querySelector('#upload');
let file = document.querySelector('#file');
form.addEventListener('submit', handleSubmit);
function handleSubmit(event) {
event.preventDefault();
if (!file.value.length) return;
let reader = new FileReader();
reader.onload = logFile;
reader.readAsText(file.files[0]);
}
一旦完成这些,我们将创建一个函数logfile (回调事件)。在那里,我们将得到文件的结果(数据),并将其解析为一个JavaScript对象,添加到地图中。
let json = null;
function logFile(event) {
let str = event.target.result;
json = JSON.parse(str);
let geo = L.geoJSON(json).addTo(map);
}
我们的结果应该是这样的。

使用jquery绘制标记作为输入
为了开始,我们将使用内容传递网络导入jquery的JavaScript文件。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
接下来,我们将创建一个嵌入按钮的模态。这个模态将有经度和纬度的输入,添加和删除行的按钮,以及用于显示输入坐标的可视化按钮。
<button class="btn btn-primary" data-toggle="modal" data-target="#myModal">Add Coordinate</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add Coordinate</h4>
</div>
<div class="modal-body">
<div class="container">
<br />
<form>
<button type="button" onclick="addRow('dataTable')" class="btn btn-success btn-sm"> Add row </button>
<button type="button" onclick="deleteRow('dataTable')" class="btn btn-danger btn-sm">
Delete Row</button>
<br /><br />
<table>
<tr>
<th># </th>
<th>Latitude </th>
<th>Longitude</th>
</tr>
<tbody id="dataTable" width="350px" border="1">
<tr>
<td><input type="checkbox" name="chk[]" id="chk_1" /></td>
<td><input type="number" name="lat[]" id="lat_1"
placeholder="Latitude" class="form-control lat_1" />
</td>
<td><input type="number" name="lng[]" id="lng_1"
placeholder="Longitude" class="form-control lng_1" />
</td>
</tr>
</tbody>
<input type="hidden" name="count" id="count" value="1">
<tr>
<td colspan="5"> </td>
</tr>
</table>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-dismiss="modal"
onclick="getInputValue();">Visualise</button>
</div>
</div>
</div>
</div>
实现后,我们应该有以下内容。


为了赋予模态功能,我们将使用下面的jquery代码。
function addRow(tableID) {
var table = document.getElementById(tableID);
var count = document.getElementById('count').value;
//alert(count);
var c = parseInt(count) + parseInt(1);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var colCount = table.rows[0].cells.length;
for (var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[0].cells[i].innerHTML;
switch (newcell.childNodes[0].type) {
case "text": newcell.childNodes[0].value = "";
var node_id = newcell.childNodes[0].id;
var node_id_arr = node_id.split('_');
newcell.childNodes[0].id = node_id_arr[0] + '_' + c;
break;
case "checkbox": newcell.childNodes[0].checked = false;
var node_id = newcell.childNodes[0].id;
var node_id_arr = node_id.split('_');
newcell.childNodes[0].id = node_id_arr[0] + '_' + c;
break;
}
$('#count').val(c);
}
}
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
var ids = row.cells[0].childNodes[0].id;
if (null != chkbox && true == chkbox.checked) {
var count = document.getElementById('count').value;
var c = parseInt(count) - parseInt(1);
if (rowCount <= 1) {
alert("Cannot delete all the rows.");
break;
}
table.deleteRow(i);
rowCount--;
i--;
$('#count').val(c);
}
}
}
catch (e) {
alert(e);
}
}
我们会有以下的结果。

我们剩下的就是将坐标发送到地图上。为了做到这一点,我们将使用for循环来加载每一个填充的行,并在地图上绘制坐标。
我们在下面有一个这样的实施例子。
function getInputValue() {
// Selecting the input element and get its value
var inputVal_lat = document.getElementsByClassName("lat_1");
var inputVal_lng = document.getElementsByClassName("lng_1");
var visualmarker;
for (let i = 0; i < inputVal_lat.length; i++) {
visualmarker = L.marker([inputVal_lat[i].value, inputVal_lng[i].value]);
visualmarker.addTo(map);
}
}
当我们把所有这些单独的特征放在一起时,我们应该有。
<html lang="en">
<head>
<title>Multiple Marker</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="src/index.css">
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="conatiner-fluid">
<form id="upload" method="post" enctype="multipart/form-data">
<div class="form-group form-inline">
<input class="form-control" id="file" name="files" type="file" accept=".json">
<button class="btn btn-primary">Upload</button>
<button class="btn btn-primary" data-toggle="modal" data-target="#myModal">Add Coordinate</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add Coordinate</h4>
</div>
<div class="modal-body">
<div class="container">
<br />
<form>
<button type="button" onclick="addRow('dataTable')" class="btn btn-success btn-sm"> Add row </button>
<button type="button" onclick="deleteRow('dataTable')" class="btn btn-danger btn-sm">
Delete Row</button>
<br /><br />
<table>
<tr>
<th># </th>
<th>Latitude </th>
<th>Longitude</th>
</tr>
<tbody id="dataTable" width="350px" border="1">
<tr>
<td><input type="checkbox" name="chk[]" id="chk_1" /></td>
<td><input type="number" name="lat[]" id="lat_1"
placeholder="Latitude" class="form-control lat_1" />
</td>
<td><input type="number" name="lng[]" id="lng_1"
placeholder="Longitude" class="form-control lng_1" />
</td>
</tr>
</tbody>
<input type="hidden" name="count" id="count" value="1">
<tr>
<td colspan="5"> </td>
</tr>
</table>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button class="btn btn-primary" data-bs-dismiss="modal"
onclick="getInputValue();">Visualise</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</nav>
<div id="map"></div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<script src="src/index.js"></script>
<script src="src/geojson.js"></script>
<script src="src/file-upload.js"></script>
<script src="src/multi-marker.js"></script>
</html>
这样做的结果如下所示。

结语
最后,我们学会了如何使用geojson添加多个标记,通过文件上传和使用一个简单的前端模态,所有这些都是通过vanilla javascript、jquery、bootstrap和leaflet.js实现的。