以前小弟只有使用过需要付费的 Google Map,也没有特别找开源地图,因为最近口罩政策,大家都在开发口罩地图,于是顺便学习一下如何使用~
OpenStreetMap
OpenStreetMap 简称 OSM,是採用协作编辑的开源全球地图,此篇会使用 Leaflet 串接此地图製作範例
Leaflet
Leaflet 是一个开源 JavaScript 的 library,其主要使用于地图的绘製,也提供许多方法可使用,用法也相当的简单,让我们绘製地图更加地容易
载入资源
我们依照官网官网的步骤,依序载入 css 与 js 档案
<!-- css --><link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
<!-- js --><script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>
创建地图
接下来我们建立一个满版的地图
<head> <style> html,body { padding: 0; margin: 0; } #myMap { width: 100vw; height: 100vh; } </style></head><body> <div id="myMap"></div> <script> // 设定地图中心点与放大级别 const map = L.map("myMap", { center: [22.595153, 120.306923], zoom: 17 }); // 载入图资 L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); // 弹出视窗 L.marker([22.595153, 120.306923]) .addTo(map) .bindPopup("梦时代购物中心") .openPopup(); </script></body>
成果如下图~
方法介绍
因为可以使用的方法非常多,这边只介绍简单常用的,详细可以看官方文件
L.map(id, options)
此方法用于创建地图
id:为 id 字串( 不用加# )或元素optionscenter:地图的中心位置zoom:地图的放大级别,数值为 0 ~ 20zoomControl:地图放大缩小的控件是否显示,预设为true
// 範例const map = L.map("myMap", { center: [22.595153, 120.306923], zoom: 17, zoomControl: false});
L.tileLayer(urlTemplate, options).addTo(map)
此方法用于载入图资到地图内
urlTemplate:需要载入的图资 urloptionsattribution:可以放入版权资讯的字串,格式为 html// 範例L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '<a href="#">copyright</a>' }).addTo(map);
L.icon(options)
此方法用于客製化标记点 icon
iconUrl:设定 icon 图片路径iconSize:资料为阵列,设定宽度与高度iconAnchor:资料为阵列,设定 icon 的 X 轴与 Y 轴偏移量popupAnchor:资料为阵列,设定弹跳视窗的 X 轴与 Y 轴偏移量shadowUrl:设定阴影图片路径shadowSize:资料为阵列,设定阴影图片的宽度与高度shadowAnchor:资料为阵列,设定阴影图片的 X 轴与 Y 轴偏移量// 範例const myIcon = L.icon({ iconUrl: 'my-icon.png', iconSize: [38, 95], iconAnchor: [22, 94], popupAnchor: [-3, -76], shadowUrl: 'my-icon-shadow.png', shadowSize: [68, 95], shadowAnchor: [22, 94]});L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
L.marker(latlng, options).addTo(map).bindPopup(content).openPopup()
marker
方法在地图上创建标记点,bindPopup
方法绑定弹出视窗,openPopup
则是开启弹跳视窗
[22.595153, 120.306923]
optionstitle:设定标记点 hover 时的文字icon:设定标记点 iconcontent:设定弹出视窗样式,格式为 html
// 範例 L.marker([22.595153, 120.306923], { title: "梦时代购物中心", icon: myIcon }) .addTo(map) .bindPopup("梦时代购物中心") .openPopup();
Demo
这边模拟 OpenData 将 JSON 格式依序显示在地图上,皆採用 CDN 的方式载入资源
<html> <head> <!-- 载入 leaflet --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" /> <style> html, body { padding: 0; margin: 0; } #myMap { width: 100vw; height: 100vh; } </style> </head> <body> <div id="myMap"></div> <script> // 模拟资料 const data = [ { name: "梦时代购物中心", local: [22.595153, 120.306923] }, { name: "汉神百货", local: [22.61942, 120.296386] }, { name: "汉神巨蛋", local: [22.669603, 120.302288] }, { name: "大统百货", local: [22.630748, 120.318033] } ]; // 设定地图中心点与放大倍率 const map = L.map("myMap", { center: [22.630748, 120.318033], zoom: 13 }); // 载入图资 L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); // 创建 icon (金色) const goldIcon = new L.Icon({ iconUrl: "https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-gold.png", shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); // 创建 icon (黑色) const blackIcon = new L.Icon({ iconUrl: "https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-black.png", shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); // 处理资料 data.forEach(item => { // 梦时代购物中心 icon 显示金色,其余则为黑色 let myIcon; if (item.name === "梦时代购物中心") { myIcon = goldIcon; } else { myIcon = blackIcon; } // 添加标记点 L.marker(item.local, { title: item.name, icon: myIcon }) .addTo(map) .bindPopup(item.name); }); </script> <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin="" ></script> </body></html>
灯冷~~成果如下图~
plugin
上面的範例只有几个点,若是真正的 OpenData 可能会有上千个点,一次显示所有的点效能会非常低落,所以这边要介绍 markercluster 这个插件,此插件为图层的概念,依照放大级别将标记点整合成一个群组,并放置于创建的图层上,使用的方法也相当简单,这边使用 CDN 做示範,依序载入 css 与 js 档案
<!-- css --><link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css"/><link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css"/>
<!-- js --><script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
处理资料的部分须要改写一下,其余大部分皆相同
// 宣告一个图层const markers = new L.MarkerClusterGroup().addTo(map);// 处理资料data.forEach(item => { // icon 部分 let myIcon; if (item.name === "梦时代购物中心") { myIcon = goldIcon; } else { myIcon = blackIcon; } // 将标记点新增于图层 markers.addLayer( L.marker(item.local, { title: item.name, icon: myIcon }) .addTo(map) .bindPopup(item.name) );});
最后就可以看到成果啦~~
结语
小弟一开始只有用过 google map,经过这次用下来发现,其实地图的应用都大同小异,只要了解基础的原理,后面要去学习其他的东西都非常的快速唷!