font-text
本文回答:字体加载 —— opentype 字体加载、默认字体、按需加载。
一、核心 API(按 vjmapext.d.ts 核对)
// 加载内置默认字体(MapCadLayer 构造时已自动调用过一次,结果存 _fontReady)
await vjmapext.initDefaultFont(); // Promise<boolean>
// 加载自定义 ttf/otf
await vjmapext.loadOpentypeFont('/fonts/NotoSansSC-Regular.otf', 'NotoSansSC');
// 或 layer 方法(同上,另会 forceFullRender;但已渲染过的文字有字形缓存,见坑 1)
await mapcadLayer.loadFont('/fonts/arial.ttf', 'Arial');
// 查已加载
vjmapext.getLoadedFontNames(); // string[]
完成后即可在 TextEnt.font / MTextEnt.font 中引用字体名(属性名是 font,不是 fontName)。
二、默认字体与回退
- 未指定
font→ 用"当前默认字体":最近一次成功加载的字体(初始为内置simkai;每次loadOpentypeFont/loadFont成功都会把它设为默认) - 指定但未加载 → 同样回退到当前默认字体(字体名查找不区分大小写)
判一个字体是否已就绪——⚠️ getLoadedFontNames() 返回的是小写化后的注册名:
const ready = vjmapext.getLoadedFontNames().includes('cad'); // 注册时传 'CAD',这里也要查 'cad'
if (!ready) await vjmapext.loadOpentypeFont('/fonts/cad-full.ttf', 'CAD');
三、按需加载
字体文件通常大(10+ MB),建议分批:
// 初始:默认字体够用
await vjmapext.initDefaultFont();
// 用到 CAD 文字时再加载大字库
async function ensureCadFont() {
if (!vjmapext.getLoadedFontNames().includes('cad')) { // 名字已小写化
await vjmapext.loadOpentypeFont('/fonts/cad-full.ttf', 'CAD');
}
}
四、子集化
超大字库推荐子集(TTF → 只保留用到的字形):
- 打包阶段用
fonttools pyftsubset/subfont生成子集 - 运行时用
loadOpentypeFont加载子集,体积可从 15 MB 压到 500 KB
五、Web 字体 vs opentype
| 方式 | 场景 |
|---|---|
浏览器 @font-face |
DOM 元素(Marker / Popup / HTML 面板) |
loadOpentypeFont / mapcadLayer.loadFont |
CAD TextEnt / MTextEnt(WebGL 绘制) |
二者互不相干:DOM 文字不需要 loadOpentypeFont;CAD 文字只认它。
六、辅助函数
包内还有 measureTextWidth / estimateTextWidth / getTextWidth / getCharWidth / truncateTextToWidth 等排版测量导出(签名见 d.ts),自定义实体排版文字时可用。
语义(v1.0.x 源码):
measureTextWidth(text, size, fontName?)= 纯字形宽:取字体getAdvanceWidth或逐 glyphadvanceWidth累加;fontName未加载/不存在时回退当前默认字体测量,只有一个字体都没加载(内置 simkai 尚未就绪)时才返回 0。getTextWidth/getCharWidth=measureTextWidth结果 >0 用之,否则回退estimateTextWidth估算。estimateTextWidth= 规则估算(非测量):空格0.35×size、CJK 全角0.95×size、其他字符0.58×size——拉丁宽窄字(W vs i)在估算与 simkai 下都等宽,别指望它区分。truncateTextToWidth(text, maxWidth, size, fontName?)逐字累加getCharWidth,超宽截断返回前缀。initDefaultFont()幂等(内部 Promise 缓存),getLoadedFontNames()返回已注册名数组(默认字体simkai)。loadOpentypeFont(url, name)失败返回false不抛错(坏 URL/非字体内容皆然),且Pn全局默认字体指针会被成功加载的字体覆盖——加载顺序影响后续未指定字体的渲染。
七、常见坑
- loadFont 不 await 直接 addEntity:首次绘制时字体未就绪,用回退字体渲染。
TextEnt/MTextEnt把字形缓存在实体上(_tessCache),只有ent.changed()才清;loadFont的forceFullRender只清渲染缓存——后加载的字体不会自动替换已用回退字体渲染过的文字,须对这些实体逐个ent.changed()。最好先await字体再addEntity。 - 中文路径/空格:浏览器对 URL 编码敏感;路径用 ASCII 并 URL-encode。
- 跨域 CORS:CDN 字体需服务端设置
Access-Control-Allow-Origin。 - woff2 子集浏览器兼容:vjmapext 对 ttf/otf 支持最稳;woff/woff2 依赖浏览器。
- 字体内存占用:大字库加载后驻留;不需要的字体就别加载(1.0.1 没有 unloadFont,控制加载列表即可)。