sprite-glyphs
本文回答:sprite 图标集 / glyphs 字体 —— 如何为 symbol 图层提供图标与文字。
一、sprite 是什么
sprite 是合并的 PNG(精灵图)+ JSON(坐标表)。让 GPU 一次性加载所有图标。
sprite.png → 一张大 PNG
sprite.json → { "marker-15": { "x":0, "y":0, "width":16, "height":16 }, ... }
样式中指定根路径(会自动加 .png / .json):
{
version: 8,
sprite: svc.spriteUrl("mysprite"), // {服务地址}sprite/{name}
sources: { ... },
layers: [ ... ]
}
@2x 支持:
sprite.png / sprite.json // 标清
sprite@2x.png / sprite@2x.json // 高清
vjmap 侧取 sprite 地址:svc.spriteUrl(name)(必填 sprite 名,生成 {服务地址}sprite/{name},引擎会自动补 .png/.json/@2x);或 svc.setSprite(name) 设为默认 sprite(传含 : 的完整 URL 则原样使用)。图层不用 icon-image 时 style 可不写 sprite。
二、动态加载单张图片
map.loadImage("https://xxx/icon.png", (err, img) => {
if (err) throw err;
if (!map.hasImage("my-icon")) {
map.addImage("my-icon", img);
}
});
// vjmap 封装(返回 Promise)
await map.loadImageEx("my-icon", "https://xxx/icon.png");
// 使用
map.addLayer({
id: "poi", type: "symbol", source: "pts",
layout: { "icon-image": "my-icon", "icon-size": 1 }
});
SDF(单色模板图标,可改色):
map.addImage("my-icon", img, { sdf: true });
// 这样 "icon-color" paint 才会生效
三、loadImageEx(vjmap 扩展)
相比原生 loadImage,loadImageEx:
- 返回 Promise;
- 自动
addImage(data URI / SVG 分支同名时updateImage;普通 URL 分支同名会触发 error 事件); - 第二参是字符串时:图片 URL(含
blob:URL)、data:image/...base64、或以<svg开头的 SVG 标记文本(按options.width/height光栅化,默认 40×40); - 不支持 Canvas / SVG 元素:非字符串实参原样转给
addImage(只收HTMLImageElement/ImageBitmap/{width, height, data}),Canvas 请先ctx.getImageData(0, 0, w, h)或canvas.toDataURL()。
await map.loadImageEx("car", location.pathname + "images/car.png");
await map.loadImageEx("pin", "data:image/svg+xml;base64,PHN2ZyB4...");
四、移除图片
map.removeImage("my-icon");
map.hasImage("my-icon"); // true/false
map.listImages(); // 所有已加载图标名
五、icon-image 的动态表达式
// 按属性选图标
"icon-image": ["concat", "icon-", ["get", "type"]]
// 优先级备选(fallback)
"icon-image": [
"coalesce",
["image", ["concat", "icon-", ["get", "type"]]], // 不能写 "icon-" + [...](那是 JS 字符串拼接,得到 "icon-get,type")
["image", "icon-default"]
]
六、glyphs 是什么
glyphs 是文字字体,按 256 字符范围分片成 PBF(二进制)。symbol 图层 text-field 需要 glyphs。
{
glyphs: "https://vjmap.com/server/api/v1/service/fonts/{fontstack}/{range}.pbf?token=..." // 即 svc.glyphsUrl()(`{serverUrl}service/fonts/...`)
}
{fontstack} 是 text-font 数组用逗号拼成的一个字体栈名(如 "Arial Unicode MS Regular"),{range} 是 256 一档的范围(如 0-255, 256-511)。
⚠️ 中文等 CJK 字符默认不走 glyphs:Map 选项 localIdeographFontFamily 默认 'sans-serif',CJK 统一汉字 / 假名 / 谚文等由浏览器本地字体用 TinySDF 现画,不请求 PBF;text-font 对它们只影响字重(名字含 bold / medium / light),换不了字族。要让中文也用服务端字体,建图时传 localIdeographFontFamily: false。
vjmap 默认:svc.glyphsUrl()。
七、text-font 使用
{
id: "labels", type: "symbol", source: "pts",
layout: {
"text-field": ["get", "name"],
"text-font": ["Arial Unicode MS Regular"], // 官方示例用的 fontstack
"text-size": 12
},
paint: {
"text-color": "#000",
"text-halo-color": "#fff",
"text-halo-width": 1
}
}
text-font 数组不会在前端逐个回退:整个数组作为一个字体栈(逗号拼接)去请求 PBF,能否回退取决于服务端是否支持拼合该组合;字体栈不存在会 404,导致该瓦片解析失败。稳妥起见用官方示例的 ["Arial Unicode MS Regular"]。
八、自定义 glyphs
如果客户需要公司字体:
- 用
node-fontnik等 PBF 字体工具把 TTF 转成 PBF 目录。 - 部署到静态文件服务(路径
/fonts/{fontstack}/{range}.pbf)。 - 样式里
glyphs: "https://xxx/fonts/{fontstack}/{range}.pbf"。
九、预加载常用字符
文字图层在第一次显示时会按范围去拉 PBF,可能闪烁。默认配置下 CJK 走本地字体、不拉 PBF,预加载 CJK 段没有意义;只有关掉 localIdeographFontFamily 时才需要(URL 用 svc.glyphsUrl() 生成,字体栈与 text-font 一致):
// 仅在 new vjmap.Map({ localIdeographFontFamily: false, ... }) 时有用:预加载 U+4E00 到 U+9FFF
const tpl = svc.glyphsUrl().replace("{fontstack}", encodeURIComponent("Arial Unicode MS Regular"));
for (let i = 0x4E; i <= 0x9F; i++) {
fetch(tpl.replace("{range}", `${i * 0x100}-${i * 0x100 + 0xFF}`));
}
十、常见坑
- icon-image 不显示 → 名字拼错;或 symbol 图层被 filter 掉了;或
icon-allow-overlap: false挤不下。 - addImage 同名不覆盖也不抛异常:
map.addImage重名时fire一个error事件("An image with this name already exists."),原图保留、新图不生效——try/catch 抓不到,先hasImage/removeImage再注册。 2b. addImage 只接三类实参:HTMLImageElement/ImageBitmap/{width, height, data:Uint8Array}(ImageData 形态)。直接传Canvas→RangeError: mismatched image size;loadImageEx对非字符串实参也是原样转给 addImage,不做转换——Canvas 先getImageData或toDataURL(),SVG 传<svg …>标记字符串。 - SDF 没效果 → 导入时没加
{ sdf: true }。 - 文字不显示 → style 缺
glyphs时带text-field的图层直接校验失败;glyphs URL 错或字体栈 404 时整个瓦片解析失败(不会出现空方块占位)。打开 Network 面板看 pbf 请求。 - CJK 字体不对 / 想统一字体 → 默认 CJK 由浏览器本地
sans-serif绘制;要用服务端字体须localIdeographFontFamily: false(随之 CJK PBF 体量大、首显慢,可预加载常用段)。 - sprite 版本升级后缓存:URL 加
?v=xxx强制刷新。