📜  LeafletJS – 使用 JavaScript 与地图交互

📅  最后修改于: 2022-05-13 01:56:44.066000             🧑  作者: Mango

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. 制作包含标记的数据集

现在,我们需要在地图上添加一些指向某个位置的标记。我们已将数据保存在名为“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 存储库。