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

node-leaflet

v1.1.1

Published

Leaflet风格的后端地图库,基于@napi-rs/canvas

Readme

node-leaflet

基于 @napi-rs/canvas 的后端地图瓦片生成库,保持 Leaflet 风格的 API 设计,支持自定义图层绘制、多投影系统和瓦片缓存机制,适用于后端批量生成地图瓦片场景。

核心特性

| 功能分类 | 具体能力 | |------------------|--------------------------------------------------------------------------| | 图层系统 | 支持 Marker(标记点)、Polyline(折线)、Polygon(多边形)、Circle(圆形)、Rectangle(矩形)、Text(文本标注) | | 样式控制 | 支持颜色、透明度、线宽、虚线样式(dashArray)、线帽/线连接样式、渐变填充、图片填充 | | 投影系统 | 内置 Web 墨卡托投影(EPSG:3857,Leaflet 默认)、等矩形投影(EPSG:4326) | | 瓦片缓存 | 支持内存缓存 + 文件系统缓存双重机制,避免重复生成,可配置缓存过期时间 | | 自定义绘制 | 支持添加自定义绘制函数,直接操作 Canvas 上下文实现灵活扩展 | | 类型安全 | 基于 TypeScript 开发,提供完整类型定义,减少开发错误 |

安装

前提条件

  • Node.js 14+
  • npm 6+ 或 yarn 1+

安装依赖

npm install @napi-rs/canvas
# 或
yarn add @napi-rs/canvas

项目初始化(可选)

若从零开始使用,可创建如下项目结构:

node-leaflet-project/
├── src/                  # 库源码目录
│   ├── geo/              # 地理坐标相关类
│   ├── layers/           # 图层类
│   ├── cache/            # 缓存相关
│   ├── projections/      # 投影系统
│   └── Map.ts            # 核心地图类
├── example.ts            # 使用示例
├── tsconfig.json         # TypeScript 配置
├── package.json          # 项目依赖
└── README.md             # 文档(本文档)

快速开始

1. 基础瓦片生成示例

// example.ts
import { Map } from './src/Map';
import { LatLng } from './src/geo/LatLng';
import { TileLayer } from './src/layers/TileLayer';
import { Marker } from './src/layers/Marker';
import { Circle } from './src/layers/Circle';

async function main() {
  try {
    // 1. 创建地图实例(中心坐标:北京,默认缩放级别13,瓦片大小256x256)
    const map = new Map({
      center: new LatLng(39.9042, 116.4074), // 北京经纬度
      zoom: 13,
      outputDir: './example-tiles', // 瓦片输出目录
      cacheDir: './example-cache', // 缓存目录
      tileSize: 256,
      cacheTTL: 7 * 24 * 60 * 60 * 1000, // 缓存过期时间:7天
    });

    // 2. 添加基础瓦片层(背景+网格)
    map.addLayer(new TileLayer({
      tileColor: '#f0f7ff', // 瓦片背景色
      gridColor: '#cbd5e0', // 网格线颜色
      textColor: '#334155', // 文本颜色
    }));

    // 3. 添加标记点(北京市中心)
    map.addLayer(new Marker(new LatLng(39.9042, 116.4074), {
      color: '#3498db', // 标记颜色
      size: 20, // 标记大小(像素)
    }));

    // 4. 添加圆形(半径1000米)
    map.addLayer(new Circle(
      new LatLng(39.9042, 116.4074),
      1000, // 半径(米)
      {
        color: '#e74c3c',
        fillColor: '#e74c3c',
        fillOpacity: 0.1,
        weight: 2,
      }
    ));

    // 5. 批量生成瓦片(缩放级别10~14,中心周围1个瓦片范围)
    await map.generateTiles({
      minZoom: 10,
      maxZoom: 14,
      radius: 1, // 中心瓦片周围的瓦片数量(1表示3x3范围)
    });

    console.log('瓦片生成完成!输出目录:./example-tiles');
  } catch (error) {
    console.error('瓦片生成失败:', error);
  }
}

main();

2. 编译与运行

  1. 编译 TypeScript 代码:
    tsc
  2. 运行示例:
    node dist/example.js
  3. 查看结果:
    • 生成的瓦片会按 zoom/x/y.png 结构保存在 ./example-tiles
    • 缓存文件保存在 ./example-cache,避免重复生成

核心 API 文档

1. 基础地理类

LatLng(经纬度)

表示地理坐标,自动校验和归一化经纬度范围。

// 创建经纬度实例(纬度[-90,90],经度自动归一化到[-180,180])
const latlng = new LatLng(39.9042, 116.4074);

// 方法
latlng.clone(); // 复制实例
latlng.equals(otherLatLng); // 判断是否与另一个坐标相等(考虑浮点数精度)
latlng.toString(6); // 转为字符串(默认保留6位小数)
latlng.toArray(); // 转为 [lat, lng] 数组
LatLng.fromArray([39.9042, 116.4074]); // 从数组创建实例

Point(像素坐标)

表示 Canvas 上的像素坐标。

const point = new Point(100, 200);

// 方法
point.add(otherPoint); // 坐标相加
point.subtract(otherPoint); // 坐标相减
point.multiply(scalar); // 乘以系数
point.divide(scalar); // 除以系数
point.distanceTo(otherPoint); // 计算与另一点的距离

2. Map 类(核心)

地图实例,管理图层、瓦片生成和缓存。

构造参数

| 参数名 | 类型 | 默认值 | 说明 | |--------------|---------------|-------------------------|-------------------------------| | center | LatLng | new LatLng(0, 0) | 地图中心点 | | zoom | number | 13 | 默认缩放级别 | | tileSize | number | 256 | 瓦片大小(像素) | | outputDir | string | ./tiles | 瓦片输出目录 | | cacheDir | string | ./tile-cache | 缓存目录 | | cacheTTL | number | 7天(毫秒) | 缓存过期时间 | | projection | Projection | WebMercatorProjection | 投影系统 |

核心方法

| 方法名 | 参数说明 | 返回值 | 说明 | |----------------------|-------------------------------------------|--------------|-------------------------------| | addLayer(layer) | layer: 图层实例(如 Marker、Polygon) | Map | 添加图层(支持链式调用) | | addCustomDraw(fn) | fn: (ctx: SKRSContext2D, zoom: number, tileX: number, tileY: number) => void | Map | 添加自定义绘制函数 | | generateTiles(opt) | opt: { minZoom: number, maxZoom: number, radius: number } | Promise<void> | 批量生成瓦片(radius:中心周围瓦片数量) |

3. 图层类使用示例

3.1 Polyline(折线)

import { Polyline } from './src/layers/Polyline';

const polyline = new Polyline(
  [
    new LatLng(39.91, 116.39),
    new LatLng(39.92, 116.41),
    new LatLng(39.90, 116.42),
  ],
  {
    color: '#e67e22', // 线条颜色
    weight: 4, // 线宽(像素)
    dashArray: '10, 5', // 虚线样式(实线10px,间隔5px)
    lineCap: 'round', // 线帽样式
    lineJoin: 'round', // 线连接样式
    opacity: 0.8, // 透明度
  }
);

map.addLayer(polyline);

3.2 Polygon(多边形)

import { Polygon } from './src/layers/Polygon';

const polygon = new Polygon(
  [
    new LatLng(39.92, 116.38),
    new LatLng(39.93, 116.43),
    new LatLng(39.89, 116.41),
  ],
  {
    color: '#2ecc71', // 边框颜色
    fillColor: '#2ecc71', // 填充颜色
    fillOpacity: 0.3, // 填充透明度
    weight: 2,
  }
);

map.addLayer(polygon);

3.3 Text(文本标注)

import { Text } from './src/layers/Text';

const text = new Text(
  '北京市中心', // 文本内容
  new LatLng(39.9042, 116.4074), // 文本位置
  {
    fontSize: 14, // 字体大小(像素)
    color: '#2c3e50', // 文本颜色
    fontFamily: 'Arial, sans-serif', // 字体
    offset: new Point(0, -30), // 偏移量(相对于位置点)
    backgroundColor: 'rgba(255, 255, 255, 0.8)', // 背景色
    padding: 5, // 内边距
  }
);

map.addLayer(text);

4. 自定义绘制

通过 addCustomDraw 实现灵活的自定义绘制:

map.addCustomDraw((ctx, zoom, tileX, tileY) => {
  // 在瓦片左下角绘制瓦片信息
  ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
  ctx.font = '10px Arial';
  ctx.fillText(`z:${zoom}, x:${tileX}, y:${tileY}`, 5, 250); // 250为瓦片高度-10

  // 绘制自定义图形(示例:红色矩形)
  ctx.fillStyle = 'rgba(231, 76, 60, 0.5)';
  ctx.fillRect(10, 10, 30, 30);
});

瓦片使用

生成的瓦片可直接用于前端 Leaflet 地图,示例:

<!-- 前端 HTML -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

<div id="map" style="width: 100vw; height: 100vh;"></div>

<script>
  const map = L.map('map').setView([39.9042, 116.4074], 13);

  // 加载后端生成的瓦片
  L.tileLayer('/example-tiles/{z}/{x}/{y}.png', {
    maxZoom: 14,
    minZoom: 10,
    attribution: 'Custom Tiles by node-leaflet',
  }).addTo(map);
</script>

常见问题

1. 编译错误:Module '"@napi-rs/canvas"' has no exported member 'Context'

解决方案:@napi-rs/canvas 的 2D 上下文类型为 SKRSContext2D,需替换所有 ContextCanvasRenderingContext2DSKRSContext2D,并从 @napi-rs/canvas 导入。

2. 瓦片生成缓慢?

解决方案:

  • 启用缓存(默认开启),避免重复生成已存在的瓦片
  • 减少 generateTilesradius 参数(缩小生成范围)
  • 降低 maxZoom(减少高缩放级别的瓦片数量)

3. 圆形/多边形位置偏移?

解决方案:检查投影系统是否一致(后端 node-leaflet 与前端 Leaflet 需使用相同投影,默认均为 Web 墨卡托)。

扩展建议

  1. 添加新投影:在 src/projections 目录下实现 Projection 接口,支持更多投影(如 UTM、阿尔伯斯等积圆锥投影)。
  2. 新增图层类型:继承 Layer 基类,实现 draw 方法,支持热力图、栅格图层等。
  3. 优化缓存:添加 LRU 缓存淘汰策略,限制内存缓存大小。
  4. 性能优化:使用多线程(如 worker_threads)并行生成瓦片。

许可证

MIT License - 详见 LICENSE 文件(需自行创建)。