leaflet-velocity-csl
v1.0.4
Published
A custom layer for leaflet to visualise arbitrary velocities with ES module and UMD support
Maintainers
Readme
Leaflet Velocity 中文使用文档
一个用于在 Leaflet 地图上可视化风场、洋流等矢量数据的插件。
特性
- 🌊 支持风场和洋流数据可视化
- 🎨 粒子动画效果,直观展示矢量方向和强度
- 📱 响应式设计,支持移动端
- 🔧 灵活的配置选项
- 📦 支持 ES 模块和 UMD 两种引入方式
- 🎯 轻量级,性能优化
安装
NPM 安装
npm install leaflet-velocity-cslCDN 引入
<!-- Leaflet 依赖 -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Leaflet Velocity 插件 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet-velocity-csl/dist/leaflet-velocity.css" />
<script src="https://unpkg.com/leaflet-velocity-csl/dist/leaflet-velocity.js"></script>使用方式
方式一:UMD 格式(传统 script 标签引入)
适用于传统的 HTML 页面开发:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<link rel="stylesheet" href="./dist/leaflet-velocity.css" />
</head>
<body>
<div id="map" style="height: 500px;"></div>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="./dist/leaflet-velocity.js"></script>
<script>
// 初始化地图
const map = L.map('map').setView([25, 121], 6);
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// 加载风场数据
fetch('./demo/wind-gbr.json')
.then(response => response.json())
.then(data => {
// 创建风场图层
const velocityLayer = L.velocityLayer({
data: data,
lineWidth: 2,
displayOptions: {
velocityType: 'Wind',
displayPosition: 'bottomleft',
displayEmptyString: '无数据'
}
});
// 添加到地图
velocityLayer.addTo(map);
// 添加控制面板
const control = L.control.velocity().addTo(map);
});
</script>
</body>
</html>方式二:ES 模块引入
适用于现代前端框架(Vue、React、Angular 等):
基础引入
// 引入 Leaflet
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
// 引入 Leaflet Velocity
import { velocityLayer, controlVelocity } from 'leaflet-velocity-csl';
import 'leaflet-velocity-csl/dist/leaflet-velocity.css';
// 初始化地图
const map = L.map('map').setView([25, 121], 6);
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// 加载并添加风场数据
fetch('./wind-data.json')
.then(response => response.json())
.then(data => {
const velocity = velocityLayer({
data: data,
lineWidth: 2,
displayOptions: {
velocityType: 'Wind',
displayPosition: 'bottomleft'
}
});
velocity.addTo(map);
// 添加控制面板
const control = controlVelocity().addTo(map);
});按需引入
// 只引入需要的组件
import { VelocityLayer, ControlVelocity } from 'leaflet-velocity-csl';
// 或者使用 API 获取函数
import { getLeafletVelocityAPI } from 'leaflet-velocity-csl';
const api = getLeafletVelocityAPI();
const { velocityLayer, controlVelocity } = api;Vue 3 示例
<template>
<div id="map" ref="mapContainer" style="height: 500px;"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { velocityLayer } from 'leaflet-velocity-csl';
import 'leaflet-velocity-csl/dist/leaflet-velocity.css';
const mapContainer = ref(null);
let map = null;
onMounted(() => {
// 初始化地图
map = L.map(mapContainer.value).setView([25, 121], 6);
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// 加载风场数据
loadWindData();
});
const loadWindData = async () => {
try {
const response = await fetch('./wind-data.json');
const data = await response.json();
const velocity = velocityLayer({
data: data,
lineWidth: 2,
displayOptions: {
velocityType: '风场',
displayPosition: 'bottomleft',
displayEmptyString: '无风场数据'
}
});
velocity.addTo(map);
} catch (error) {
console.error('加载风场数据失败:', error);
}
};
</script>React 示例
import React, { useEffect, useRef } from 'react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { velocityLayer } from 'leaflet-velocity-csl';
import 'leaflet-velocity-csl/dist/leaflet-velocity.css';
const WindMap = () => {
const mapRef = useRef(null);
const mapInstance = useRef(null);
useEffect(() => {
if (!mapInstance.current) {
// 初始化地图
mapInstance.current = L.map(mapRef.current).setView([25, 121], 6);
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
.addTo(mapInstance.current);
// 加载风场数据
loadWindData();
}
return () => {
if (mapInstance.current) {
mapInstance.current.remove();
}
};
}, []);
const loadWindData = async () => {
try {
const response = await fetch('./wind-data.json');
const data = await response.json();
const velocity = velocityLayer({
data: data,
lineWidth: 2,
displayOptions: {
velocityType: 'Wind',
displayPosition: 'bottomleft'
}
});
velocity.addTo(mapInstance.current);
} catch (error) {
console.error('Failed to load wind data:', error);
}
};
return <div ref={mapRef} style={{ height: '500px', width: '100%' }} />;
};
export default WindMap;配置选项
VelocityLayer 选项
const options = {
// 数据源
data: windData, // 风场数据(必需)
// 显示选项
displayOptions: {
velocityType: 'Wind', // 显示类型:'Wind'、'Ocean'、'Custom'
displayPosition: 'bottomleft', // 控制面板位置
displayEmptyString: '无数据', // 无数据时显示的文本
speedUnit: 'm/s', // 速度单位
directionString: '风向', // 方向标签
speedString: '风速' // 速度标签
},
// 粒子效果
lineWidth: 2, // 粒子轨迹宽度
colorScale: [
'rgb(36,104, 180)',
'rgb(60,157, 194)',
'rgb(128,205,193)',
'rgb(151,218,168)',
'rgb(198,231,181)',
'rgb(238,247,217)',
'rgb(255,238,159)',
'rgb(252,217,125)',
'rgb(255,182,119)',
'rgb(252,150,75)',
'rgb(250,112,52)',
'rgb(245,64,32)',
'rgb(237,45,28)',
'rgb(220,24,32)',
'rgb(180,0,35)'
], // 颜色映射
// 性能选项
maxVelocity: 10, // 最大速度值
velocityScale: 0.005, // 速度缩放因子
particleAge: 90, // 粒子生命周期
particleMultiplier: 1/300 // 粒子密度
};Control 选项
const controlOptions = {
position: 'bottomleft', // 控制面板位置
emptyString: '无数据', // 无数据显示文本
angleConvention: 'bearingCCW', // 角度约定
showCardinal: true, // 显示基数方向
velocityUnit: 'm/s', // 速度单位
directionString: '方向:', // 方向标签
speedString: '速度:' // 速度标签
};数据格式
风场数据需要符合以下 JSON 格式:
[
{
"header": {
"parameterCategory": 2,
"parameterNumber": 2,
"dx": 0.5,
"dy": 0.5,
"la1": 90.0,
"la2": -90.0,
"lo1": 0.0,
"lo2": 359.5,
"nx": 720,
"ny": 361
},
"data": [/* U 分量数据数组 */]
},
{
"header": {
"parameterCategory": 2,
"parameterNumber": 3,
"dx": 0.5,
"dy": 0.5,
"la1": 90.0,
"la2": -90.0,
"lo1": 0.0,
"lo2": 359.5,
"nx": 720,
"ny": 361
},
"data": [/* V 分量数据数组 */]
}
]数据说明
parameterNumber: 2- U 分量(东西方向)parameterNumber: 3- V 分量(南北方向)dx,dy- 网格间距(度)la1,la2- 纬度范围lo1,lo2- 经度范围nx,ny- 网格数量data- 对应的数值数组
API 参考
L.velocityLayer(options)
创建一个新的风场图层。
参数:
options(Object) - 配置选项
返回:
- VelocityLayer 实例
L.control.velocity(options)
创建一个风场控制面板。
参数:
options(Object) - 控制面板选项
返回:
- Control.Velocity 实例
实例方法
velocityLayer.setData(data)
更新风场数据。
参数:
data(Array) - 新的风场数据
velocityLayer.setOptions(options)
更新配置选项。
参数:
options(Object) - 新的配置选项
常见问题
Q: 如何处理大数据量的风场数据?
A: 可以通过以下方式优化性能:
const options = {
data: windData,
particleMultiplier: 1/500, // 减少粒子密度
particleAge: 60, // 缩短粒子生命周期
lineWidth: 1 // 减小线宽
};Q: 如何自定义颜色映射?
A: 修改 colorScale 选项:
const customColors = [
'#0000FF', // 蓝色 - 低速
'#00FF00', // 绿色 - 中速
'#FFFF00', // 黄色 - 高速
'#FF0000' // 红色 - 极高速
];
const velocityLayer = L.velocityLayer({
data: windData,
colorScale: customColors
});Q: 如何在移动端优化性能?
A: 针对移动端可以使用以下配置:
const mobileOptions = {
data: windData,
particleMultiplier: 1/800, // 更少的粒子
lineWidth: 1, // 更细的线条
particleAge: 45, // 更短的生命周期
velocityScale: 0.01 // 调整速度缩放
};浏览器支持
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
- 移动端浏览器
许可证
详见 LICENSE.md 文件。
贡献
欢迎提交 Issue 和 Pull Request!
更新日志
v2.1.4
- ✨ 新增 ES 模块支持
- 🔧 优化构建配置
- 📚 完善文档
- 🐛 修复已知问题
v2.1.3
- 🐛 修复性能问题
- 🔧 优化粒子渲染
v2.1.2
- ✨ 新增自定义颜色映射
- 🔧 改进数据处理逻辑
