在 MapLibre 生态中,Sprite(精灵图) 是地图样式中图标渲染的核心资源。传统工作流需要预先使用工具(如 spritezero)将 SVG 合成为 PNG 精灵图和 JSON 索引文件,每次图标变更都要重新生成。Martin 的亮点在于完全自动化------只需提供一个 SVG 目录,它就能按需生成符合 MapLibre 规范的精灵图资源。
一、Sprite 在地图中的作用
MapLibre 样式文件(style.json)中,sprite 字段指向精灵图服务:
json
{
"sprite": "https://tiles.example.com/sprite/my_icons",
"glyphs": "https://tiles.example.com/font/{fontstack}/{range}.pbf",
"layers": [
{
"id": "poi-bicycle",
"type": "symbol",
"source": "my_source",
"layout": {
"icon-image": "bicycle"
}
}
]
}
客户端会同时请求:
sprite/my_icons.png--- 包含所有图标的 PNG 精灵图sprite/my_icons.json--- 描述每个图标在精灵图中位置和尺寸的索引
Martin 的 Sprite 模块会实时读取 SVG 文件、渲染为 PNG、生成索引,无需预构建步骤。
二、配置 Sprite 源
2.1 配置文件方式(推荐)
在 config.yaml 中添加 sprites 配置:
yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/maplibre/martin/main/schemas/config.json
sprites:
# 方式一:扫描目录,目录名自动作为 sprite_id
paths:
- /path/to/my_icons # 生成 sprite_id: my_icons
# 方式二:显式命名映射
sources:
transport_icons: /path/to/transport
poi_icons: /path/to/poi
# 缓存配置(可选)
cache:
size_mb: 64 # 精灵图缓存大小,默认继承全局 cache 的 12.5%
expiry: 1h # 缓存过期时间
idle_timeout: 30m
目录结构约定:
/path/to/my_icons/
├── bicycle.svg
├── bus.svg
├── restaurant.svg
└── icons/
├── hospital.svg
└── school.svg
Martin 会递归扫描目录,子目录名作为前缀:
bicycle.svg→ sprite ID:bicycleicons/hospital.svg→ sprite ID:icons/hospital
2.2 命令行方式
bash
martin --sprite /path/to/my_icons --sprite poi=/path/to/poi
三、API 端点与请求
配置完成后,Martin 暴露以下端点:
| 端点 | 说明 |
|---|---|
GET /sprite/<sprite_id>.png |
标准分辨率 PNG 精灵图 |
GET /sprite/<sprite_id>@2x.png |
高 DPI(Retina)PNG 精灵图 |
GET /sprite/<sprite_id>.json |
图标索引(含位置、尺寸) |
GET /sprite/<sprite_id>@2x.json |
高 DPI 索引(坐标自动翻倍) |
GET /catalog |
查看所有可用的 sprite、font、style 源 |
3.1 JSON 索引示例
请求 GET /sprite/my_icons.json 返回:
json
{
"bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 20,
"y": 16
},
"bus": {
"height": 18,
"pixelRatio": 1,
"width": 18,
"x": 40,
"y": 16
},
"icons/hospital": {
"height": 20,
"pixelRatio": 1,
"width": 20,
"x": 60,
"y": 16
}
}
@2x 版本会自动将 pixelRatio 设为 2,坐标和尺寸翻倍。
四、多源合并:动态组合精灵图
Martin 支持将多个 Sprite 源实时合并为一个精灵图,语法与瓦片多源合并一致:
bash
# 合并 transport_icons 和 poi_icons
GET /sprite/transport_icons,poi_icons.png
GET /sprite/transport_icons,poi_icons.json
注意事项:
- 不执行 ID 重命名,同名图标会被后者覆盖
- 合并后的精灵图尺寸为各源图标的并集
- 适合将"基础图标"和"业务图标"分层管理
也可在配置中定义别名(Alias):
yaml
sprites:
aliases:
all_icons:
sources:
- transport_icons
- poi_icons
paths:
- /path/to/transport
- /path/to/poi
然后直接访问 /sprite/all_icons.png。
五、SDF 精灵图:运行时着色
如果你的图标需要在地图样式中动态变色(如通过 icon-color 属性),需要使用 Signed Distance Field(SDF) 精灵图。SDF 将图标编码为距离场,支持运行时着色,但只能显示单色。
端点:
| 端点 | 说明 |
|---|---|
GET /sdf_sprite/<sprite_id>.png |
SDF 格式 PNG |
GET /sdf_sprite/<sprite_id>.json |
SDF 索引 |
GET /sdf_sprite/<sprite_id>@2x.png |
高 DPI SDF |
MapLibre 样式中使用:
json
{
"layout": {
"icon-image": "bicycle",
"icon-color": "#ff0000",
"icon-halo-color": "#ffffff",
"icon-halo-width": 2
}
}
限制: 如需多色图标,必须将多个单色图标叠加渲染。
六、完整配置示例
yaml
# config.yaml
listen_addresses: "0.0.0.0:3000"
# 瓦片源(PostGIS / MBTiles / PMTiles)
postgres:
connection_string: postgres://user:pass@localhost/db
auto_publish: true
# 精灵图配置
sprites:
paths:
- ./assets/sprites/default
- ./assets/sprites/transport
sources:
custom_poi: ./assets/sprites/poi
aliases:
full_set:
sources:
- default
- transport
- custom_poi
cache:
size_mb: 32
expiry: 30m
# 字体配置
fonts:
paths:
- ./assets/fonts
# 样式配置
styles:
paths:
- ./styles
启动后验证:
bash
# 查看所有资源
curl http://localhost:3000/catalog | jq '.sprites'
# 获取精灵图
curl -o sprite.png http://localhost:3000/sprite/full_set.png
curl -o sprite.json http://localhost:3000/sprite/full_set.json
七、性能与缓存
Martin 的 Sprite 生成是计算密集型操作(SVG 解析 → 栅格化 → PNG 编码),因此内置了基于 Moka 的 LRU 缓存:
- 默认缓存大小:全局
cache.size_mb的 12.5%(如全局 512MB,则 Sprite 缓存约 64MB) - 可独立配置
sprites.cache.size_mb - 缓存键包含文件修改时间,目录更新后自动失效
优化建议:
- SVG 文件尽量精简,避免复杂路径
- 图标尺寸统一(推荐 15×15、20×20、24×24 等标准尺寸)
- 高并发场景增大缓存,或前置 CDN 缓存
@2x版本
八、与样式系统的联动
Martin 的 Sprite 服务天然与 Style 服务配合。你可以在 style.json 中直接引用 Martin 提供的 Sprite 端点:
json
{
"version": 8,
"name": "My Map Style",
"sprite": "http://localhost:3000/sprite/full_set",
"glyphs": "http://localhost:3000/font/{fontstack}/{range}.pbf",
"sources": {
"basemap": {
"type": "vector",
"url": "http://localhost:3000/basemap.json"
}
},
"layers": [
{
"id": "poi-restaurant",
"type": "symbol",
"source": "basemap",
"source-layer": "poi",
"layout": {
"icon-image": "restaurant",
"icon-size": 1,
"text-field": "{name}",
"text-font": ["Noto Sans Regular"]
},
"paint": {
"icon-color": "#c62828",
"text-color": "#333333"
}
}
]
}
将样式文件放入 styles/ 目录,Martin 会自动通过 /style/<style_id> 端点提供,形成瓦片 + 精灵图 + 字体 + 样式的完整自托管地图服务。
九、总结
| 特性 | 说明 |
|---|---|
| 零预构建 | 直接读取 SVG 目录,无需手动合成精灵图 |
| 递归扫描 | 子目录自动作为 ID 前缀 |
| 多源合并 | 支持逗号分隔组合多个 Sprite 源 |
| SDF 支持 | 运行时动态着色,适合主题切换 |
| 实时更新 | 文件变更后自动反映(有缓存失效) |
| 缓存优化 | 独立缓存配置,支持高并发场景 |
Martin 的 Sprite 生成能力消除了地图图标管理中的"构建步骤",让图标迭代与地图样式开发同步进行,是构建自托管 MapLibre 地图服务时不可或缺的组件。