npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

leaflet-velocity-csl

v1.0.4

Published

A custom layer for leaflet to visualise arbitrary velocities with ES module and UMD support

Readme

Leaflet Velocity 中文使用文档

一个用于在 Leaflet 地图上可视化风场、洋流等矢量数据的插件。

特性

  • 🌊 支持风场和洋流数据可视化
  • 🎨 粒子动画效果,直观展示矢量方向和强度
  • 📱 响应式设计,支持移动端
  • 🔧 灵活的配置选项
  • 📦 支持 ES 模块和 UMD 两种引入方式
  • 🎯 轻量级,性能优化

安装

NPM 安装

npm install leaflet-velocity-csl

CDN 引入

<!-- 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

  • ✨ 新增自定义颜色映射
  • 🔧 改进数据处理逻辑