参考: leaflet实用插件整理
1、Leaflet.AntPath 将通量动画(如蚂蚁行走)放入折线中
leaflet-ant-path:https://www.npmjs.com/package/leaflet-ant-path
在交通项目、管网应用的项目中,常常需要标注出道路的走向、河流的流向或者管线的流向等等,Leaflet Ant Path 能够很好的解决这类问题。
官网示例: https://rubenspgcavalcante.github.io/leaflet-ant-path/
安装:
npm i leaflet-ant-path
引用:
import { AntPath, antPath } from 'leaflet-ant-path';
使用:
<template>
<div id="map"></div>
</template>
<script lang="ts" setup>
import L from "leaflet";
import { onMounted, onBeforeUnmount } from "vue";
// @ts-ignore
import { antPath } from "leaflet-ant-path";
import route from "./route";
import { ATTRIBUTIONS } from "../../../constants";
let map: L.Map | null = null;
const initMap = () => {
//地图容器
map = L.map("map", {
//参考坐标系
crs: L.CRS.EPSG3857,
//显示中心
center: [30.5217, 114.3948],
//当前显示等级
zoom: 18,
});
//加载天地图矢量图层
L.tileLayer(
"http://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=55b4d4eaef95384c946e9bd1b99c5610",
{ noWrap: true, attribution: ATTRIBUTIONS }
).addTo(map);
//加载天地图矢量注记图层
L.tileLayer(
"http://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=55b4d4eaef95384c946e9bd1b99c5610",
{ noWrap: true, attribution: ATTRIBUTIONS }
).addTo(map);
const path = antPath(route, {
delay: 400,
dashArray: [10, 20],
weight: 5,
color: "#0000FF",
pulseColor: "#FFFFFF",
paused: false,
reverse: false,
hardwareAccelerated: true,
});
map.addLayer(path);
map.fitBounds(path.getBounds());
};
onMounted(() => {
initMap();
});
// 销毁地图
onBeforeUnmount(() => {
if (map) {
map.remove();
map = null;
}
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#map {
height: 650px;
color: #3a3a3a;
}
</style>
2、Leaflet.Path.DashFlow 对直线和圆圈的dashArray进行动画处理,创造一个基本的流动效果
参考:支持Canvas的Leaflet.Path.DashFlow动态流向线
插件可实现轨迹动态展示、管道流向动态展示、河流流向动态展示等,达到增强可视化展示的效果。
使用:
在项目中直接引入 L.Path.DashFlow.js
文件。
L.Path.DashFlow.js
// @class PolyLine
L.Path.mergeOptions({
// @option dashSpeed: Number
// The speed of the dash array, in pixels per second
dashSpeed: 0
});
var _originalBeforeAdd = L.Path.prototype.beforeAdd;
L.Path.include({
beforeAdd: function (map) {
_originalBeforeAdd.bind(this)(map);
if (this.options.dashSpeed) {
this._lastDashFrame = performance.now();
this._dashFrame = L.Util.requestAnimFrame(this._onDashFrame.bind(this));
}
},
_onDashFrame: function () {
if (!this._renderer) {
return;
}
var now = performance.now();
var dashOffsetDelta = (now - this._lastDashFrame) * this.options.dashSpeed / 1000;
this.options.dashOffset = Number(this.options.dashOffset || 0) + dashOffsetDelta;
this._renderer._updateStyle(this);
this._lastDashFrame = performance.now();
this._dashFrame = L.Util.requestAnimFrame(this._onDashFrame.bind(this));
},
_offDashFrame: function () {
L.Util.cancelAnimFrame(this._dashFrame);
},
onRemove: function () {
this._renderer._removePath(this);
this._offDashFrame();
}
});
// 针对Canvas添加dashOffset参数,解决Canvas下无法实现动态线问题
L.Canvas.include({
_updateDashArray: function (layer) {
if (typeof layer.options.dashArray === 'string') {
var parts = layer.options.dashArray.split(/[, ]+/),
dashArray = [],
dashValue,
i;
for (i = 0; i < parts.length; i++) {
dashValue = Number(parts[i]);
// Ignore dash array containing invalid lengths
if (isNaN(dashValue)) {
return;
}
dashArray.push(dashValue);
}
layer.options._dashArray = dashArray;
} else {
layer.options._dashArray = layer.options.dashArray;
}
if (layer.options.dashOffset) {
layer.options._dashOffset = layer.options.dashOffset;
}
},
_fillStroke: function (ctx, layer) {
var options = layer.options;
if (options.fill) {
ctx.globalAlpha = options.fillOpacity;
ctx.fillStyle = options.fillColor || options.color;
ctx.fill(options.fillRule || 'evenodd');
}
if (options.stroke && options.weight !== 0) {
if (ctx.setLineDash) {
ctx.setLineDash(layer.options && layer.options._dashArray || []);
}
if (layer.options._dashOffset) {
ctx.lineDashOffset = layer.options._dashOffset;
}
ctx.globalAlpha = options.opacity;
ctx.lineWidth = options.weight;
ctx.strokeStyle = options.color;
ctx.lineCap = options.lineCap;
ctx.lineJoin = options.lineJoin;
ctx.stroke();
}
},
})
示例:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"
integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
crossorigin=""></script>
<script src="L.Path.DashFlow.js"></script>
</head>
<body>
<div id="map" style="width: 800px; height: 600px; border: 1px solid #ccc"></div>
<script src="route.js"></script>
<script>
for (var i = 0, latlngs = [], len = route.length; i < len; i++) {
latlngs.push(new L.LatLng(route[i][0], route[i][1]));
}
var path = L.polyline(latlngs, {
dashArray: "15,15",
dashSpeed: -30
});
var map = L.map('map');
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="http://cartodb.com/attributions">CartoDB</a>'
}).addTo(map);
map.fitBounds(L.latLngBounds(latlngs));
map.addLayer(L.marker(latlngs[0]));
map.addLayer(L.marker(latlngs[len - 1]));
map.addLayer(path);
L.circleMarker([10, 70], {
dashArray: "15,15",
dashSpeed: -30,
radius: 147.5
}).addTo(map);
</script>
</body>
</html>
3、leaflet-icon-pulse :使用 CSS3 渲染脉冲图标。 它可用于位置标记
官方案例: http://mapshakers.com/projects/leaflet-pulse-icon/
下载和使用:
npm install @ansur/leaflet-pulse-icon
引入位于 \dist 目录中的 CSS 和 JavaScript 文件。
<script src="../L.Icon.Pulse.js" />
<link rel="stylesheet" href="../L.Icon.Pulse.css" />
var pulsingIcon = L.icon.pulse({iconSize:[20,20],color:'red'});
var marker = L.marker([50,15],{icon: pulsingIcon}).addTo(map);
4、Leaflet.Radar : 雷达扇区扫描动画
Leaflet.Radar: https://github.com/rwev/leaflet-radar
测试案例: http://examples.panzhiyue.website/leaflet.radar/examples/index.html
5、Leaflet.MovingMarker:允许以自定义的持续时间沿多段线移动标记
示例1: http://ewoken.github.io/Leaflet.MovingMarker/
示例2: https://zjffun.github.io/Leaflet.MovingMarker/examples/index.html
Leaflet中使用MovingMarker插件实现标记移动(轨迹回放效果)
Leaflet 带箭头轨迹以及沿轨迹带方向的动态marker
示例: http://gisarmory.xyz/blog/leaflet-RouteAnimate/demo.html
6、Esri Leaflet:一组用于将 ArcGIS 服务与 Leaflet 一起使用的工具。支持地图服务、要素图层、ArcGIS Online 切片等。
leaflet 加载arcgis发布的切片–L.esri.tiledMapLayer(影像),L.esri.dynamicMapLayer(矢量)
安装:
npm i esri-leaflet
7、Leaflet.ChineseTmsProviders:常用地图切换加载(TianDiTu、GaoDe、Google、OSM、Baidu)
安装:
npm i leaflet.chinatmsproviders
引用:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import "leaflet.chinatmsproviders";
使用:
// 影像
let imgm = L.tileLayer.chinaProvider('TianDiTu.Satellite.Map', {
key: '6a9f4b408cb773ba60fb639f3b713d61',
maxZoom: 18,
minZoom: 3,
})
let imga = L.tileLayer.chinaProvider('TianDiTu.Satellite.Annotion', {
key: '6a9f4b408cb773ba60fb639f3b713d61',
maxZoom: 18,
minZoom: 3,
})
this.imageLayer = L.layerGroup([imgm, imga])
this.maps.addLayer(this.imageLayer)
注意: 使用 leaflet.chinatmsproviders 加载的地图均使用 EPSG:3857
坐标参考系统(CRS)。
8、Leaflet.PM:用于在 Leaflet 1.0 中创建和编辑几何图形层的 Leaflet 插件
- 具有绘制、编辑、拖拽、剪切和捕捉功能。
- 在名称 "leaflet.pm "中,"pm"代表多边形管理。当时,该插件只支持多边形。现在,您可以编辑标记、多段线、多边形、圆、矩形、图层组、GeoJSON 以及更多即将推出的功能。
9、Leaflet-Geoman:用于创建和编辑几何图形层的 Leaflet 插件
说明: Leaflet 1.0 及更高版本的几何管理。 绘制、编辑、拖动、剪切、旋转、拆分、缩放、测量、捕捉和固定图层,如标记、CircleMarkers、折线、多边形、圆形、矩形、ImageOverlays、LayerGroups、GeoJSON、MultiLineStrings 和 MultiPolygons。 支持 polygons、canvas 模式等。
Leaflet-Geoman 官网: https://www.geoman.io/
Leaflet-Geoman 文档地址: https://www.geoman.io/docs
Leaflet-Geoman Demo在线地址: https://geoman.io/demo
使用教程: Leaflet-Geoman 帮助文档
leaflet-geoman 是一个商业化的插件,文档很详细,同时提供免费版本。
免费版本的功能同样强大,支持图形的绘制、编辑、拖动、剪切、分割、固定、跟踪、测量、缩放、旋转等操作。
免费版使用教程如下:
安装和使用:
npm 下载:
npm i @geoman-io/leaflet-geoman-free
CDN 在线引用:
CSS:
<link
rel="stylesheet"
href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css"
/>
JS:
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.js"></script>
ES6模块引入:
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
10、Leaflet.draw:通过一个非常漂亮的带有图标和提示的用户友好界面,实现了多段线、多边形、矩形、圆和标记等绘图功能。
11、leaflet-easyPrint:一个简单的插件,它添加了一个图标来打印你的 Leaflet 地图。
示例: https://rowanwins.github.io/leaflet-easyPrint/
12、Leaflet-Semicircle: 为 L.Circle 添加了绘制半圆的功能
示例: https://jieter.github.io/Leaflet-semicircle/examples/semicircle.html
https://jieter.github.io/Leaflet-semicircle/examples/semicircle.html
安装和使用:
npm i leaflet-semicircle
import "leaflet-semicircle";
/**
* [] 坐标
* radius 半径
* startAngle 开始角度
* endAngle 结束角度
* fill 填充
* fillColor 填充色
* fillOpacity 填充透明度
*/
L.semiCircle([51.5, -0.09], {
radius: 500,
startAngle: 45,
stopAngle: 135,
fill: true,
fillColor:'#f03',
fillOpacity: 0.5,
color: '#f03',
opacity: 0.5,
}).addTo(map);
参考: 探索地图新维度:Leaflet-Semicircle
13、leaflet-velocity: 用 Leaflet 观察 velocity 图层
leaflet-velocity: 该库的核心功能是解析气象数据,特别是来自 GDAS (Global Data Assimilation System) 或其他类似提供动态流数据服务的 API。它能够将这些时间序列数据转换成可视化的层,让你可以直观地看到风向、速度或任何其他随时间变化的现象。
常用于实现风场动态粒子效果。
应用场景
Leaflet-Velocity 能用于:
- 天气预报应用 - 显示风向、风速和其他气候变量的变化。
- 环境监测 - 监控海洋流动、空气污染扩散等。
- 航海与航空 - 提供实时的导航辅助信息。
- 科研可视化 - 在地图上呈现气候变化模型或其他动态地理数据。
- 教育与演示 - 为教学材料增添互动元素,使复杂的地理现象更易理解。
特点
- 兼容性好 - 与 Leaflet 兼容,适应各种浏览器和设备。
- 高性能 - 利用矢量瓦片技术,仅加载可视区域的数据,降低内存和带宽需求。
- 自定义丰富 - 支持颜色映射、动画速度控制等多种设置,满足个性化需求。
- 简单易用 - 简单的 API 设计,让集成到现有项目中变得容易。
- 开源社区支持 - 持续更新和完善,社区活跃,有问题可以寻求帮助。
安装:
npm install leaflet
npm install leaflet-velocity
引用:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import "leaflet.chinatmsproviders";
import "leaflet-velocity/dist/leaflet-velocity.css";
import "leaflet-velocity/dist/leaflet-velocity";
使用示例:加载风场粒子效果
// 加载风场数据
initWind() {
axios
.get("https://tf.istrongcloud.com/data/gfs/gfs.json")
.then(({ data }) => {
const arr = [];
for (const i in data) {
arr.push(data[i]);
}
this.windData = arr[0];
velocityLayer = L.velocityLayer({
displayValues: false,
displayOptions: {
velocityType: "GBR Wind",
displayPosition: "bottomleft",
displayEmptyString: "No wind data",
},
data: this.windData,
// choseValue: "aqi",
minVelocity: 0,
maxVelocity: 15,
velocityScale: 0.012,
// particleMultiplier: 1 / 1200, //粒子的数量
lineWidth: 2, //粒子的粗细
frameRate: 15, //定义每秒执行的次数
colorScale: ["rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
],
});
velocityLayer.addTo(maps);
this.mapWindDisabled = false;
});
},
14、Leaflet Measure Path : 显示路径上的测量值; 当前支持折线、多边形和圆
Leaflet Measure Path: https://www.npmjs.com/package/leaflet-measure-path
demo示例: https://prominentedge.com/leaflet-measure-path/
安装:
npm i leaflet-measure-path
引用:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import 'leaflet-measure-path/leaflet-measure-path.css'
import 'leaflet-measure-path/leaflet-measure-path.js'
使用:
显示测量值:
var polygon = L.polygon([ ... ])
.addTo(map)
.showMeasurements();
隐藏测量值:
var polygon = L.polygon([ ... ])
.addTo(map)
.hideMeasurements();
15、Leaflet.TileLayer.ColorFilter:一个简单轻量级的 Leaflet 插件,用于在地图图块上应用 CSS 过滤器
安装:
npm install --save leaflet.tilelayer.colorfilter
引入:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import "leaflet.tilelayer.colorfilter";
使用:
let map = L.map('map').setView([51.505, -0.09], 14);
let myFilter = [
'blur:0px',
'brightness:95%',
'contrast:130%',
'grayscale:20%',
'hue:290deg',
'opacity:100%',
'invert:100%',
'saturate:300%',
'sepia:10%',
];
let myTileLayer = L.tileLayer.colorFilter('https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png', {
attribution: '<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia</a>',
filter: myFilter,
}).addTo(map);
使用天地图:
http://t0.tianditu.gov.cn/DataServer?T=vec_c&x={x}&y={y}&l={z}&tk=你的key
滤镜:
CSS的滤镜功能是通过filter属性实现的,该属性提供了多种不同的视觉效果,用于改变网页元素的外观。这些效果包括模糊、亮度调整、对比度调整、灰度转换、色相旋转等。
CSS中的滤镜功能主要通过filter属性实现,该属性包含多种函数,每个函数对应不同的视觉效果。具体如下:
- 模糊: 通过
blur()
函数实现,可以设置高斯模糊效果,使图像或元素看起来模糊。例如,filter: blur(5px);
会使元素模糊5像素 - 亮度: 使用
brightness()
函数调整,值范围从0%(全黑)到100%(无变化),超过100%的值也可以使图像更亮。例如,filter: brightness(200%);
会使元素亮度加倍。 - 对比度: 通过
contrast()
函数调整,值范围也是0%到100%,超过100%意味着更低的对比度。例如,filter: contrast(200%);
会使元素对比度提高两倍。 - 灰度: 使用
grayscale()
函数将图像转换为灰度图,100%值完全转为灰度图像,0%则无变化。例如,filter: grayscale(100%);
将图像转换为黑白。 - 色相旋转: 通过
hue-rotate()
函数应用,值表示色环角度,如hue-rotate(90deg)
将图像色相旋转90度。 - 反色: 使用
invert()
函数实现颜色反转效果,100%值完全反转颜色,0%则无变化。例如,filter: invert(1);
会将元素的颜色完全反转。 - 阴影: 通过
drop-shadow()
函数为元素添加阴影效果,可以设置阴影偏移、模糊度和颜色。例如,filter: drop-shadow(4px 4px 10px black);
为元素添加了阴影。 - 透明度: 使用
opacity()
函数调整元素的透明度,百分比值控制透明程度。例如,filter: opacity(50%);
使元素50%透明。 - 饱和度: 通过
saturate()
函数调整图像的饱和度,0%完全不饱和,100%无变化,超过100%增加饱和度。例如,filter: saturate(200%);
会使图像饱和度加倍。 - 褐色: 使用
sepia()
函数将图像转换为深褐色,100%完全转换为褐色,0%无变化。例如,filter: sepia(100%);
将图像完全转换为深褐色。
16、leaflet-polycolor : 给每个多线段着色
前置知识: 在Leaflet中点对象使用SVG和Canvas两种模式的对比
官方示例Demo: https://oliv.github.io/leaflet-polycolor/
安装:
npm install --save leaflet-polycolor
使用:
ES6:
import L from 'leaflet';
import leafletPolycolor from 'leaflet-polycolor';
leafletPolycolor(L);
const map = L.map('map', {
center: [45.1834782, 5.7831946],
zoom: 13,
preferCanvas: true, // 重点
});
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);
const latLngs = [[45.187273, 5.758124], [45.182772, 5.758516], [45.185767, 5.747106], [45.176569, 5.752082], [45.171863, 5.757120], [45.168354, 5.755178]];
const colors = ['rgb(20, 200, 100)', 'rgb(200, 100, 20)', null, null, 'rgb(20, 200, 100)', 'rgb(0, 0, 0)'];
const polyline = L.polycolor(latLngs, {
colors: colors,
useGradient: true,
weight: 5
}).addTo(map);
17、Leaflet.ellipse:通过指定中心点、半长轴、半短轴和向西倾斜的角度在地图上绘制椭圆
Demo 示例地址: https://jdfergason.github.io/Leaflet.Ellipse/
安装:
npm install leaflet-ellipse
使用:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import "leaflet-ellipse";
let ellipse1 = L.ellipse([27.497730661009353, 111.68944804903713], [1000, 30], 45, {
color: "red",
});
let ellipse2 = L.ellipse([27.488190963817143, 111.70020006956051], [2500, 100], 45, {
color: "yellow",
// fillPattern: stripes,
fillOpacity: 0,
});
this.maps.addLayer(ellipse1);
this.maps.addLayer(ellipse2);
18、Leaflet.pattern:添加对路径上的图案填充的支持
安装:
npm install leaflet.pattern
使用:
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import "leaflet.pattern/dist/leaflet.pattern";
var stripes = new L.StripePattern({
weight: 5,
spaceWeight: 5,
// color: "#ffff00",
// spaceColor: "#ffff00",
opacity: 1,
spaceOpacity: 0,
});
stripes.addTo(this.maps);
var circle = new L.Circle([27.50409, 111.682279], 400.0, {
fillPattern: stripes,
stroke: false,
fillOpacity: 0.5,
});
circle.addTo(this.maps);
19、Leaflet-CanvasMarker:在 Canvas 而不是 DOM 上显示标记
Leaflet-CanvasMarker:Leaflet.Canvas-Markers的改进版本
Leaflet.Canvas-Markers:这个插件有个问题,就是地图缩放时,添加的数据不跟着同步缩放,而是等到缩放完成后,再去缩放。这样感觉缩放时,数据在飘着。
Leaflet-CanvasMarker 插件描述: 在Canvas上绘制Marker,而不是每个marker插件一个dom节点,极大地提高了渲染效率。主要代码参考自 https://github.com/eJuke/Leaflet.Canvas-Markers ,不过此插件有些Bug,github国内不方便,作者也不维护了,所以在gitee上新建一个仓库进行维护与升级。
npm下载
npm i @panzhiyue/leaflet-canvasmarker
使用
import {CanvasMarkerLayer} from "@panzhiyue/leaflet-canvasmarker"
示例
// 创建图层
var ciLayer = L.canvasMarkerLayer({
collisionFlg: true
}).addTo(map);
var icon = L.icon({
iconUrl: 'img/pothole.png',
iconSize: [20, 18],
iconAnchor: [10, 9]
});
// 定义Marker
var markers = [];
for (var i = 0; i < 100000; i++) {
var marker = L.marker([58.5578 + Math.random() * 1.8, 29.0087 + Math.random() * 3.6], {
icon: icon,
zIndex: 2
}).bindPopup("I Am " + i);
markers.push(marker);
}
// 把marker添加到图层
ciLayer.addLayers(markers);
//定义事件
ciLayer.addOnClickListener(function (e, data) {
console.log(data)
});
ciLayer.addOnHoverListener(function (e, data) {
console.log(data[0].data._leaflet_id)
});
20、Leaflet.markercluster:美丽、复杂、高性能的标记聚类解决方案,具有流畅的动画和许多强大的功能。 推荐!
中文文档: Leaflet.markercluster 中文文档 V1.5.4
官网: Documentation - Leaflet - 一个交互式地图 JavaScript 库
处理大量标记的示例:
该插件可以处理10,000 甚至 50,000 个标记 (在chrome浏览器下). IE9 在 50,000 数量下会存在一些问题。
下载
使用unpkg的CDN: https://unpkg.com/leaflet.markercluster@1.4.1/dist/
通过npm命令安装: npm install leaflet.markercluster
npm install leaflet.markercluster
对应自身情况,请斟酌引用 dist
目录下的文件:
MarkerCluster.css
MarkerCluster.Default.css
(如果你要使用自定义的iconCreateFunction
而不是默认的函数,则不需要引入)leaflet.markercluster.js
(或者引入未压缩版本leaflet.markercluster-src.js
)
引入
<!-- 引入 Leaflet.markercluster 相关依赖-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/MarkerCluster.css"
integrity="sha512-mQ77VzAakzdpWdgfL/lM1ksNy89uFgibRQANsNneSTMD/bj0Y/8+94XMwYhnbzx8eki2hrbPpDm0vD0CiT2lcg=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/MarkerCluster.Default.css"
integrity="sha512-6ZCLMiYwTeli2rVh3XAPxy3YoR5fVxGdH/pz+KMCzRY2M65Emgkw00Yqmhh8qLGeYQ3LbVZGdmOX9KUjSKr0TA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/leaflet.markercluster.js"
integrity="sha512-OFs3W4DIZ5ZkrDhBFtsCP6JXtMEDGmhl0QPlmWYBJay40TT1n3gt2Xuw8Pf/iezgW9CdabjkNChRqozl/YADmg=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- <link rel="stylesheet" href="https://unpkg.com/browse/leaflet.markercluster@1.4.1/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/browse/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/browse/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script> -->
// 引入 leaflet.markercluster 聚合插件
import "leaflet.markercluster/dist/MarkerCluster.css"
import "leaflet.markercluster/dist/MarkerCluster.Default.css"
import "leaflet.markercluster";
使用
通过聚合分组的方案也可以满足加载大量数据不卡顿,下面是使用案例,创建了十万个点渲染到页面上。
import 'leaflet.markercluster/dist/leaflet.markercluster';
import 'leaflet.markercluster/dist/MarkerCluster.css';
import 'leaflet.markercluster/dist/MarkerCluster.Default.css';
const addCluster = () => {
const clusterLayer = L.markerClusterGroup({
// showCoverageOnHover: false,
// zoomToBoundsOnClick: false,
// spiderfyOnMaxZoom: false,
// removeOutsideVisibleBounds: false,
// spiderLegPolylineOptions: {}
// 自定义聚合样式
// iconCreateFunction: function (cluster) {
// return L.divIcon({html: '<b class="bg-#[f40]">' + cluster.getChildCount() + '</b>'});
// }
});
for (let i = 0; i < 100000; i++) {
const marker = L.marker([18.8567 + Math.random(), 102.3508 + Math.random()], {
title: `点 ${i}`,
icon: L.icon({
iconUrl: Money,
iconSize: [20, 20],
iconAnchor: [0, 0]
})
});
marker.on('click', function (event) {
console.log('marker ====', event.latlng);
});
marker.on('clusterclick', function (a) {
// a.layer is actually a cluster
console.log('cluster ' + a.layer.getAllChildMarkers().length);
});
clusterLayer.addLayer(marker);
}
map.addLayer(clusterLayer);
};
markerClusterGroup配置对象
属性/方法 | 说明 |
---|---|
showCoverageOnHover | 将鼠标悬停在集群上时,它会显示其标记的边界 |
zoomToBoundsOnClick | 单击集群时,会缩放到其边界 |
spiderfyOnMaxZoom | 当您单击底部缩放级别的集群时,我们会对其进行蜘蛛化,以便您可以查看其所有标记 |
removeOutsideVisibleBounds | 为了提高性能,将从地图中删除离视口太远的聚类和标记 |
spiderLegPolylineOptions | 允许您指定 PolylineOptions 来设置蜘蛛腿的样式。默认情况下,它们是 { weight: 1.5, color: ‘#222’, opacity: 0.5 } |
animate | 在缩放和蜘蛛化时平滑拆分/合并集群子项 |
iconCreateFunction | Fn,自定义聚合样式 |
spiderfyShapePositions | Fn,覆盖蜘蛛形状位置 |
21、Leaflet.PolylineDecorator:允许你沿着折线或坐标路径绘制图案(如破折号、箭头或均匀间隔的标记)
访问地址: https://gitcode.com/gh_mirrors/le/Leaflet.PolylineDecorator
示例 Demo
https://bbecquet.github.io/Leaflet.PolylineDecorator/example/example.html
下载
npm i leaflet-polylinedecorator
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Leaflet.PolylineDecorator - 允许你沿着折线或坐标路径绘制图案(如破折号、箭头或均匀间隔的标记)</title>
<link rel="stylesheet" href="./js/leaflet.css" />
<script src="./js/leaflet.js"></script>
<script src="./js/leaflet.polylineDecorator.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.map-box {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="map-box" id="leafletMapService"></div>
<script>
// 加载天地图矢量图层
let tdtVecW = L.tileLayer(
"https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的天地图key"
);
// 加载天地图矢量注记图层
let tdtCvaW = L.tileLayer(
"https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的天地图key"
);
let maps = L.map('leafletMapService', {
// center: [27.50409, 111.682279],
center: [52.0, -11.0],
zoom: 5,
minZoom: 3,
maxZoom: 18,
zoomControl: true, // 是否隐藏左上角的缩放
attributionControl: false, // 是否隐藏右下角的信息显示
layers: [tdtVecW, tdtCvaW]
});
/**
* Pattern definition
*
* offset:(可选)第一个图案符号与线条起点的偏移量。默认值:0。
* endOffset:(可选)最后一个图案符号与线条终点的最小偏移量。默认值:0。
* repeat:(必填)图案符号的重复间隔。定义每个连续符号锚点之间的距离。
* symbol:(必填)符号工厂类的实例。是如何绘制每一段的定义,比如使用L.Symbol.dash, L.Symbol.arrowHead等
*
* offset、endOffset 和 repeat 可以分别定义为以像素为单位的数字,或以字符串为单位的行长百分比(例如:"10%")。
*/
// --- Simple arrow ---
let arrow = L.polyline([[57, -19], [60, -12]], {}).addTo(maps);
// 箭头
let arrowHead = L.polylineDecorator(arrow, {
patterns: [
{
offset: '100%',
repeat: 2,
symbol: L.Symbol.arrowHead({
pixelSize: 15,
polygon: false,
pathOptions: { stroke: true }
})
}
]
}).addTo(maps);
// --- Polygon, with an inner ring ---
let polygon = L.polygon([[[54, -6], [55, -7], [56, -2], [55, 1], [53, 0]], [[54, -3], [54, -2], [55, -1], [55, -5]]], { color: "#ff7800", weight: 1 }).addTo(maps);
let pd = L.polylineDecorator(polygon, {
patterns: [
{ offset: 0, repeat: 10, symbol: L.Symbol.dash({ pixelSize: 0 }) }
]
}).addTo(maps);
// --- Multi-pattern without Polyline ---
var pathPattern = L.polylineDecorator(
[[49.543519, -12.469833], [49.808981, -12.895285], [50.056511, -13.555761], [50.217431, -14.758789], [50.476537, -15.226512], [50.377111, -15.706069], [50.200275, -16.000263], [49.860606, -15.414253], [49.672607, -15.710152], [49.863344, -16.451037], [49.774564, -16.875042], [49.498612, -17.106036], [49.435619, -17.953064], [49.041792, -19.118781], [48.548541, -20.496888], [47.930749, -22.391501], [47.547723, -23.781959], [47.095761, -24.941630], [46.282478, -25.178463], [45.409508, -25.601434], [44.833574, -25.346101], [44.039720, -24.988345]],
{
patterns: [
{ offset: 12, repeat: 25, symbol: L.Symbol.dash({ pixelSize: 10, pathOptions: { color: '#f00', weight: 2 } }) },
{ offset: 0, repeat: 25, symbol: L.Symbol.dash({ pixelSize: 0 }) }
]
}
).addTo(maps);
// --- Markers proportionnaly located ---
var markerLine = L.polyline([[58.44773, -28.65234], [52.9354, -23.33496], [53.01478, -14.32617], [58.1707, -10.37109], [59.68993, -0.65918]], { color: '#ff0000', weight: 10 }).addTo(maps);
var markerPatterns = L.polylineDecorator(markerLine, {
patterns: [
{
offset: '5%', repeat: '25%', symbol: L.Symbol.marker({
rotate: true,
markerOptions: {
icon: L.icon({
// iconUrl: 'icon_plane.png',
iconUrl: './imgs/icon_plane.png',
iconAnchor: [16, 16]
})
}
})
}
]
}).addTo(maps);
// 绘制带箭头的线条(路径)
let arrowLine = L.polylineDecorator(markerLine, {
patterns: [
{
offset: 30, // 箭头起始位置距离线条两端的距离
repeat: 60, // 箭头重复的间隔
symbol: L.Symbol.arrowHead({
pixelSize: 5, // 箭头大小
headAngle: 75, // 角度
polygon: false,
pathOptions: { stroke: true, weight: 4, color: '#fff' }
})
}
]
}).addTo(maps);
// --- Example with a rotated marker ---
var pathPattern = L.polylineDecorator(
[[42.9, -15], [44.18, -11.4], [45.77, -8.0], [47.61, -6.4], [49.41, -6.1], [51.01, -7.2]],
{
patterns: [
{ offset: 0, repeat: 10, symbol: L.Symbol.dash({ pixelSize: 5, pathOptions: { color: '#000', weight: 1, opacity: 0.2 } }) },
{
offset: '16%', repeat: '33%', symbol: L.Symbol.marker(
{
rotate: true,
markerOptions: {
icon: L.icon({
// iconUrl: 'icon_plane.png',
iconUrl: './imgs/icon_plane.png',
iconAnchor: [16, 16]
})
}
}
)
}
]
}
).addTo(maps);
// --- Example with an array of Polylines ---
var multiCoords1 = [
[[47.5468, -0.7910], [48.8068, -0.1318], [49.1242, 1.6699], [49.4966, 3.2958], [51.4266, 2.8564], [51.7542, 2.1093]],
[[48.0193, -2.8125], [46.3165, -2.8564], [44.9336, -1.0107], [44.5278, 1.5820], [44.8714, 3.7353], [45.8287, 5.1855], [48.1953, 5.1416]],
[[45.9205, 0.4394], [46.7699, 0.9228], [47.6061, 2.5488], [47.7540, 3.3837]]
];
var plArray = [];
for (var i = 0; i < multiCoords1.length; i++) {
plArray.push(L.polyline(multiCoords1[i]).addTo(maps));
}
L.polylineDecorator(multiCoords1, {
patterns: [
{ offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({ pixelSize: 15, pathOptions: { fillOpacity: 1, weight: 0 } }) }
]
}).addTo(maps);
</script>
</body>
</html>