node-leaflet
v1.1.1
Published
Leaflet风格的后端地图库,基于@napi-rs/canvas
Maintainers
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. 编译与运行
- 编译 TypeScript 代码:
tsc - 运行示例:
node dist/example.js - 查看结果:
- 生成的瓦片会按
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,需替换所有 Context 或 CanvasRenderingContext2D 为 SKRSContext2D,并从 @napi-rs/canvas 导入。
2. 瓦片生成缓慢?
解决方案:
- 启用缓存(默认开启),避免重复生成已存在的瓦片
- 减少
generateTiles的radius参数(缩小生成范围) - 降低
maxZoom(减少高缩放级别的瓦片数量)
3. 圆形/多边形位置偏移?
解决方案:检查投影系统是否一致(后端 node-leaflet 与前端 Leaflet 需使用相同投影,默认均为 Web 墨卡托)。
扩展建议
- 添加新投影:在
src/projections目录下实现Projection接口,支持更多投影(如 UTM、阿尔伯斯等积圆锥投影)。 - 新增图层类型:继承
Layer基类,实现draw方法,支持热力图、栅格图层等。 - 优化缓存:添加 LRU 缓存淘汰策略,限制内存缓存大小。
- 性能优化:使用多线程(如
worker_threads)并行生成瓦片。
许可证
MIT License - 详见 LICENSE 文件(需自行创建)。
