LeafletJS – 使用 JavaScript 与地图交互
地图已成为我们日常生活中不可或缺的一部分。从开车到某个地方,到在附近寻找一些餐馆或商店,或者在计划旅行时,几乎每种类型的应用程序都使用地图。使用地图可以帮助我们在应用程序中添加基于位置的服务。
在 Web 应用程序中添加地图的一种方法是使用 Leaflet JS。 Leaflet JS 是一个开源的 JavaScript 库,用于添加简单的交互式 web 地图。它可以将地图数据添加到地图图层中,并具有大多数应用程序所需的平移、缩放等功能。尽管传单提供了任何地图应用程序所需的一些核心功能,但增加地图功能的一种简单方法是使用第三方插件。由于leaflet 是一个开源库,即它的源代码可以在GitHub 上获得,因此已经有很多贡献并且有很多可用的插件。您可以在此处获取插件列表。
因此,Leaflet 是一个地图 API,它帮助我们与地图数据进行交互,但它不提供任何数据。它也不提供地图本身,因为它不是地图服务。那么我们如何获取地图呢?答案是Leaflet 依赖第三方来提供底图,即Leaflet 的构建方式使其可以与多个底图图层一起使用。通常,Leaflet 与 OpenStreetMaps 一起使用,但我们甚至可以使用其他地图提供者,如 Mapbox、Ersi、Bing Map Layers 等。您可以在此处查看不同的底图提供者。
因此,让我们逐步了解如何使用传单与地图进行交互:
1.目录结构
这是本示例中将遵循的目录结构。您也可以有不同的目录结构,但要确保它也反映在您的代码中。
2. HTML Boilerplate 和添加 Leaflet References
HTML
Playing Around With Leaflet JS
Javascript
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 20,
minZoom: 2,
tileSize: 512,
zoomOffset: -1
}).addTo(map);
Javascript
let marker = L.marker([latitude, longitude]).bindPopup(` ${title}
${description}
`).on('click', () => {
map.flyTo([latitude, longitude], zoomLevel);
}).addTo(map);
Javascript
let iconOption = {
iconUrl: './assets/location-marker.svg',
iconSize: [30, 30]
};
let ourCustomIcon = L.icon(iconOption);
let marker = L.marker([latitude, longitude],
{icon: ourCustomIcon}).bindPopup(` ${title}
${description}
`).on('click', () => {
map.flyTo([latitude, longitude], zoomLevel);
}).addTo(map);
Javascript
map.setView([latitude, longitude], zoomLevel);
map.flyTo([latitude, longitude], zoomLevel);
HTML
Playing Around With LeafletJS
Some Indian Monuments
CSS
body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
.heading {
font-family: monospace;
font-size: 40px;
text-align: center;
margin: 2.5vh 0;
}
#mymap {
width: 90vw;
height: 70vh;
margin: 0 5vw 2vh;
border: 3px solid #888;
}
.button-group {
justify-content: space-evenly !important;
}
.map-zoom-out-btn, .search-btn {
background-color: #0072B5;
color: #FFF;
padding: 10px 35px;
border: none;
font-size: 17px;
border-radius: 5px;
cursor: pointer;
}
.select-dropdown {
display: inline-block;
margin: 0 15px 0 0;
padding: 10px 35px;
border: 1px solid #AAA;
font: inherit;
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
appearance: none;
background: #FFF;
background-repeat: no-repeat;
background-image:
linear-gradient(45deg, transparent 50%, currentColor 50%),
linear-gradient(135deg, currentColor 50%, transparent 50%);
background-position: right 15px top 1em, right 10px top 1em;
background-size: 5px 5px, 5px 5px;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-size: 17px;
padding-bottom: 8px;
}
.footer a {
padding: 0 5px 0 5px;
color: #000;
cursor: pointer;
}
.flex-style {
display: flex;
justify-content: center;
align-items: center;
}
Javascript
let map = L.map("mymap").setView([19.5937, 78.9629], 5);
let ourData = [];
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
maxZoom: 20,
minZoom: 2,
tileSize: 512,
zoomOffset: -1,
}).addTo(map);
let iconOption = {
iconUrl: "./assets/location-marker.svg",
iconSize: [30, 30],
};
let ourCustomIcon = L.icon(iconOption);
fetch("./assets/location-data.json")
.then((response) => response.json())
.then((data) => {
ourData = data;
for (let i = 0; i < data.length; i++) {
let option = document.createElement("option");
option.value = i + 1;
option.text = data[i].title;
document.querySelector(".select-dropdown").appendChild(option);
let marker = L.marker([data[i].latitude, data[i].longitude], {
icon: ourCustomIcon,
})
.bindPopup(
` ${data[i].title}
${data[i].description}
`
)
.on("click", () => {
map.flyTo([data[i].latitude, data[i].longitude], data[i].zoomLevel);
})
.addTo(map);
}
})
.catch((error) => alert(error));
document.querySelector(".map-zoom-out-btn").addEventListener("click", () => {
map.flyTo([19.5937, 78.9629], 5);
});
document.querySelector(".search-btn").addEventListener("click", () => {
let select = document.querySelector(".select-dropdown");
let value = select.options[select.selectedIndex].value;
map.flyTo(
[ourData[value - 1].latitude, ourData[value - 1].longitude],
ourData[value - 1].zoomLevel
);
});
要将地图添加到我们的网页,需要简单的网络技术,如 HTML、CSS 和 JavaScript。要在您的代码中使用 Leaflet,您需要添加 Leaflet CSS 和 Leaflet JS。您可以下载它们,也可以通过包含它们的 CDN 来使用它们(参见上面的代码示例)。
3.创建Map容器并创建Map对象
我们首先定义一个容器元素,我们要在其中加载地图并为其提供 id “mymap”。
let map = L.map('mymap').setView([19.5937, 78.9629], 5);
现在,我们创建一个地图对象,我们将使用它创建一个地图并对其进行操作。我们使用上面创建的容器元素的 id 实例化地图对象,即“mymap”。 setview 方法用于设置地图的中心和缩放级别。
4.使用TileLayer添加地图瓦片
Javascript
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 20,
minZoom: 2,
tileSize: 512,
zoomOffset: -1
}).addTo(map);
为了加载和显示我们的地图,我们使用 TileLayer 类来创建一个图层并指定地图瓦片的 URL。地图分为多个图块,我们使用 OpenStreetMap 来显示地图图块。您可以在此处获取磁贴提供商列表。我们确实指定了一些附加参数,例如最小缩放级别、最大缩放级别、图块大小。当我们使用 OpenStreetMap 的地图图块时,我们需要为 OpenStreetMap(或您使用的任何地图图块提供商)提供适当的归属(或信用)以使用他们的地图图块。要在地图上添加这一层,我们使用 addTo() 方法。
5. 制作包含标记的数据集
https://github.com/OptimalLearner/Leaflet-JS-Example-Code/blob/master/assets/location-data.json
现在,我们需要在地图上添加一些指向某个位置的标记。我们已将数据保存在名为“location-data.json”的不同文件中。此文件包含标记详细信息,例如纬度和经度坐标等。您可以从上面提供的链接访问数据并将其与代码一起保存。如果您想将数据保留在您的 JS 文件本身中,您可以创建一个变量并将其分配给上述数据。
6. 创建标记、绑定弹窗和事件处理
Javascript
let marker = L.marker([latitude, longitude]).bindPopup(` ${title}
${description}
`).on('click', () => {
map.flyTo([latitude, longitude], zoomLevel);
}).addTo(map);
标记用于识别和突出显示地图上的位置。要在 Leaflet 中添加标记,我们初始化标记类并传递我们需要标记指向的位置的坐标。您可以根据需要添加任意数量的标记。现在要确定标记标记了哪个位置,我们可以向标记添加一个弹出窗口,它会告诉我们位置信息。我们使用 bindPopup 方法添加一个弹出窗口来显示位置名称和位置的一些描述。
Leaflet 还具有对我们生成的事件做出反应的能力。我们可以使用“on”函数为特定事件(在我们的例子中为“click”)添加一个事件侦听器,该事件侦听器侦听包含某些操作集的函数。最后,我们将此标记添加到我们的地图中。
7.自定义标记图标
Javascript
let iconOption = {
iconUrl: './assets/location-marker.svg',
iconSize: [30, 30]
};
let ourCustomIcon = L.icon(iconOption);
let marker = L.marker([latitude, longitude],
{icon: ourCustomIcon}).bindPopup(` ${title}
${description}
`).on('click', () => {
map.flyTo([latitude, longitude], zoomLevel);
}).addTo(map);
不是每个人都愿意使用相同的默认标记图标。因此,这里有自定义标记图标的功能来拯救。您需要使用 Icon 类并传递要用作标记的图标的 URL,并添加图标的大小 [width, height],以像素(px)为单位。现在我们需要将图标添加到标记。在添加坐标后的 Marker 类中,我们可以传递自定义标记图标来渲染标记。
8. 什么最适合您:flyTo 或 setView?
Javascript
map.setView([latitude, longitude], zoomLevel);
map.flyTo([latitude, longitude], zoomLevel);
两者都在做相同的工作,将位置更改为特定坐标,但 flyTo() 方法提供了一些动画,将飞到使用坐标指定的位置。如果你需要一些动画,那么你可以使用 flyTo() 方法,否则 setView() 也可以改变位置。
还有另一种称为 panTo([latitude, longitude]) 的方法,它只是调用 setView() 将缩放级别保持在当前地图的缩放级别。 setView() 方法甚至允许您设置缩放级别,但 panTo() 并非如此。
9.完整的代码和结果
HTML
Playing Around With LeafletJS
Some Indian Monuments
CSS
body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
.heading {
font-family: monospace;
font-size: 40px;
text-align: center;
margin: 2.5vh 0;
}
#mymap {
width: 90vw;
height: 70vh;
margin: 0 5vw 2vh;
border: 3px solid #888;
}
.button-group {
justify-content: space-evenly !important;
}
.map-zoom-out-btn, .search-btn {
background-color: #0072B5;
color: #FFF;
padding: 10px 35px;
border: none;
font-size: 17px;
border-radius: 5px;
cursor: pointer;
}
.select-dropdown {
display: inline-block;
margin: 0 15px 0 0;
padding: 10px 35px;
border: 1px solid #AAA;
font: inherit;
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
appearance: none;
background: #FFF;
background-repeat: no-repeat;
background-image:
linear-gradient(45deg, transparent 50%, currentColor 50%),
linear-gradient(135deg, currentColor 50%, transparent 50%);
background-position: right 15px top 1em, right 10px top 1em;
background-size: 5px 5px, 5px 5px;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-size: 17px;
padding-bottom: 8px;
}
.footer a {
padding: 0 5px 0 5px;
color: #000;
cursor: pointer;
}
.flex-style {
display: flex;
justify-content: center;
align-items: center;
}
Javascript
let map = L.map("mymap").setView([19.5937, 78.9629], 5);
let ourData = [];
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
maxZoom: 20,
minZoom: 2,
tileSize: 512,
zoomOffset: -1,
}).addTo(map);
let iconOption = {
iconUrl: "./assets/location-marker.svg",
iconSize: [30, 30],
};
let ourCustomIcon = L.icon(iconOption);
fetch("./assets/location-data.json")
.then((response) => response.json())
.then((data) => {
ourData = data;
for (let i = 0; i < data.length; i++) {
let option = document.createElement("option");
option.value = i + 1;
option.text = data[i].title;
document.querySelector(".select-dropdown").appendChild(option);
let marker = L.marker([data[i].latitude, data[i].longitude], {
icon: ourCustomIcon,
})
.bindPopup(
` ${data[i].title}
${data[i].description}
`
)
.on("click", () => {
map.flyTo([data[i].latitude, data[i].longitude], data[i].zoomLevel);
})
.addTo(map);
}
})
.catch((error) => alert(error));
document.querySelector(".map-zoom-out-btn").addEventListener("click", () => {
map.flyTo([19.5937, 78.9629], 5);
});
document.querySelector(".search-btn").addEventListener("click", () => {
let select = document.querySelector(".select-dropdown");
let value = select.options[select.selectedIndex].value;
map.flyTo(
[ourData[value - 1].latitude, ourData[value - 1].longitude],
ourData[value - 1].zoomLevel
);
});
使用 HTML 样板,我们添加了一个地图容器、一个用于缩小地图的按钮,以及一个包含地图上标记的位置的下拉菜单。通过添加对外部样式表的引用,我们使用外部 CSS 将一些样式应用于我们的组件。在脚本文件中,我们创建了一个地图对象并将地图切片添加到该对象。然后我们创建我们的自定义图标对象并将图标的大小和 URL 添加到我们将添加到标记的图标选项中,同时为每个位置创建标记。
使用 Fetch API,我们通过提供数据的 URL 来请求我们的数据。我们得到响应对象,然后将其转换为 json。使用这个包含位置信息的 json 数据,我们使用 DOM 将位置选项动态添加到下拉列表中,并为每个位置创建标记以及弹出窗口和 onclick 事件侦听器。如果出现任何错误,将向用户发出错误消息警报。
我们在 Zoom Out 按钮上添加了一个 onclick 事件侦听器,它将我们带到初始坐标和缩放级别。我们还在搜索按钮上添加了一个事件侦听器,它获取下拉列表的值,并使用我们选择位置的值并将地图缩放到该选定位置。
上述示例的结果如下所示:
要在本地运行网页,您需要通过本地服务器运行网页。您可以使用 WAMP 或 XAMPP 或 simpleNode.js http-server。如果您在两者之间遇到问题,可以参考这个 GitHub 存储库。