前言
很久以前,我喜欢用一个名叫 Hexo-tag-map 的插件,但是后来发现这个插件可控性太差,不是很方便就弃用了,现在我们研究一下它的原始库 Leaflet.js 以求更好的可控性!
资源
-
Quick Start Guide - Leaflet - 一个交互式地图 JavaScript 库 (leafletjs.cn)
-
neoayi/leaflet-tileLayer-baidu: leaflet 加载百度瓦片地图图层 以及高德、天地图等国内常用地图 (github.com)
快速开始
引入相关资源:
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""/>
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""></script>对于地图框,还可以自定义 CSS:
<style>
#map { height: 280px; }
</style>放置地图框以及控制地图框的 JS:
<div no-fancybox id="map"></div>
<script src="map.js"></script>no-fancybox 是为了防止标签被 fancybox 给识别了。
map.js 里对地图 <div id="map"></div> 一阵操作!
// 创建一个 Leaflet 地图对象,设置了一些参数,如缩放级别、最大缩放级别、是否可编辑等,并将地图视图移动到指定的经纬度位置。
var map = L.map('map',
{
zoomSnap: 0.1, // 地图的有效缩放级别
maxZoom: 18, // 最大缩放级别
// crs: L.CRS.EPSG4326, // 高德不是这个坐标系
zoomControl: true,
editable: true,
// wheelPxPerZoomLevel: 60 // 鼠标滚轮缩放 较小的值将使滚轮轮缩放更快
}).setView([26.078799594917704, 119.29471468823111], 14); // 待显示地点的经纬度和缩放级别
// 创建一个瓦片图层对象 baseLayer,指定了高德地图的瓦片地址和一些参数,然后将该图层添加到地图中。
// 目前 http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x} 也是可用的。
let baseLayer = L.tileLayer("http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}", {
attribution: '© 高德地图',
maxZoom: 18, // 应与 var map 里的 maxZoom 一致,不然显示不出来图片。
minZoom: 3,
subdomains: "1234",
zoom: 3
});
map.addLayer(baseLayer);
// 监听地图的点击事件,当用户点击地图时会输出当前点击的经纬度信息。
map.on('click', function (event) {
// console.log(event); // 返回当前点击的所有信息
let { lat, lng } = event.latlng; // 经纬度信息
console.log("[" + lat + ", " + lng + "]"); // 输出经纬度信息,便于调试
});
// 监听地图的缩放开始事件(zoomstart),当缩放级别发生改变时会输出当前的缩放级别。
map.on('zoomstart', function () {
var zoomLevel = map.getZoom();
console.log(zoomLevel); // 显示缩放等级(好像只能显示滚动之前的)
});
// 给某个点做标记
var marker = L.marker([26.081476491742904, 119.29704755981834]).addTo(map);
marker.bindPopup("<b>这个地方真是太好玩了!</b><br/>这是屁股树的坐标😍!");
// 定义路径点的坐标数组
var latlngs = [
[26.08009367221409,119.29242494512384],
[26.080079217568272,119.29223174932305],
[26.08009367221409,119.29216735072279],
[26.080310491686973,119.29212978487263],
[26.080296037067946,119.29162532917066],
[26.080453431663422,119.29152938351272],
[26.080381158638648,119.29095499726753],
[26.07820812885429,119.29081367507568],
[26.07815030932909,119.29159187052262],
[26.078212947146778,119.29209635584687]
];
// 创建路径对象并添加到地图上
var polyline = L.polyline(latlngs, {color: 'green'}).addTo(map);
polyline.bindPopup("上学去了😭");
// 定义多边形的边界点坐标数组
var latlngs = [
[26.074889884389435,119.2912822984996],
[26.073579264327183,119.2915720922007],
[26.073902102248386,119.2926293025549],
[26.07466823643904,119.29226437715347],
[26.075150079274067,119.29180822040166]
];
// 创建多边形对象并添加到地图上
var polygon = L.polygon(latlngs, {color: 'blue'}).addTo(map);
polygon.bindPopup("乌石山下,白马河旁~");
// 绘制圆
var circle = L.circle([26.077862817425885, 119.29212395568047], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 32.6 // 这个单位是米。
}).addTo(map);
circle.bindPopup("阿公阿妈家~");
// 定义矩形的地理边界
var bounds = [[26.081312674254516, 119.2925756072068], [26.08073449305117, 119.29365965031108]];
// 创建一个橙色的矩形
var rectangle = L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
rectangle.bindPopup("就没见它开张过!😠");
// 创建 SVG,但好像 Popup 不能被点开
var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg");
svgElement.setAttribute('viewBox', "0 0 200 200");
svgElement.innerHTML = '<rect width="200" height="200"/><rect x="75" y="23" width="50" height="50" style="fill:red"/><rect x="75" y="123" width="50" height="50" style="fill:#0013ff"/>';
var svgElementBounds = [[26.077898151572324, 119.30137317389199], [26.07745968496554, 119.30187226304396]];
var svg = L.svgOverlay(svgElement, svgElementBounds).addTo(map);
// 纯 popup
var popup = L.popup()
.setLatLng([26.079171783403833, 119.2939243421818])
.setContent("小迷糊和小小怪最喜欢吃的百姓鲜捞~")
.openOn(map);项目演示。点击一些标注可以弹出 popup!
可以用 坐标拾取器 | 高德地图 API (amap.com) 获取精确的坐标(注意经纬度是反的),也可以直接在上面的地图上点击,然后从控制窗口中获取想要的坐标。
更多牛逼的功能可以看 Documentation - Leaflet - 一个交互式地图 JavaScript 库 (leafletjs.cn),好像还能玩得挺花。
封装成一个类,以更便捷地实现基本的地图展示功能:
class LeafletMap {
constructor(id, coordinate, zoom, marker) {
this.id = id;
this.coordinate = coordinate;
this.zoom = zoom;
this.marker = marker;
}
render() {
$("#" + this.id).css({height: "280px"});
$("#" + this.id).css({margin: "5px 0"});
var map = L.map(this.id,
{
zoomSnap: 0.1,
maxZoom: 18,
zoomControl: true,
editable: true,
}).setView(this.coordinate, this.zoom);
let baseLayer = L.tileLayer("http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}", {
attribution: '© 高德地图',
maxZoom: 18,
minZoom: 3,
subdomains: "1234",
zoom: 3
});
map.addLayer(baseLayer);
var marker = L.marker(this.coordinate).addTo(map);
marker.bindPopup(this.marker).openPopup();
}
}调用方法:
<div no-fancybox id="map_XX"></div>
<script defer>new LeafletMap("map_XX", [26.XX, 119.XX]
, 17, "XX").render()</script>