Mapboxgl Chrome75版本下发现问题:中文标签无法加载,由Canvas的measureText()方法导致
很刁钻的问题,排查了好久。
我自己开发测试用的浏览器(版本为112)运行正常,在老版本(75)谷歌浏览器报错如下:
mapbox-gl.js:32 Uncaught TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': Value is not of type 'long'.
at Mp.TinySDF.draw (mapbox-gl.js:32)
at Mp._tinySDF (mapbox-gl.js:32)
at mapbox-gl.js:32
at mapbox-gl.js:31
at Array.forEach (<anonymous>)
at M (mapbox-gl.js:31)
at Mp.getGlyphs (mapbox-gl.js:32)
at Jt.getGlyphs (mapbox-gl.js:36)
at t.Actor.processTask (mapbox-gl.js:32)
at t.Actor.receive (mapbox-gl.js:32)
起初以为是Mapboxgl的问题(虽然最终也确实是有一点关系),后来经过艰难排查发现是Canvas的measureText()方法在老版本谷歌浏览器中无法正常返回中文字符的宽度。
在Mapboxgl源码中出问题的部分在这里:
draw(char) {
const {
width: glyphAdvance,
actualBoundingBoxAscent,
actualBoundingBoxDescent,
actualBoundingBoxLeft,
actualBoundingBoxRight
} = this.ctx.measureText(char);
// The integer/pixel part of the top alignment is encoded in metrics.glyphTop
// The remainder is implicitly encoded in the rasterization
const glyphTop = Math.ceil(actualBoundingBoxAscent);
const glyphLeft = 0;
// If the glyph overflows the canvas size, it will be clipped at the bottom/right
const glyphWidth = Math.max(0, Math.min(this.size - this.buffer, Math.ceil(actualBoundingBoxRight - actualBoundingBoxLeft)));
const glyphHeight = Math.min(this.size - this.buffer, glyphTop + Math.ceil(actualBoundingBoxDescent));
const width = glyphWidth + 2 * this.buffer;
const height = glyphHeight + 2 * this.buffer;
const len = Math.max(width * height, 0);
const data = new Uint8ClampedArray(len);
const glyph = {data, width, height, glyphWidth, glyphHeight, glyphTop, glyphLeft, glyphAdvance};
if (glyphWidth === 0 || glyphHeight === 0) return glyph;
const {ctx, buffer, gridInner, gridOuter} = this;
ctx.clearRect(buffer, buffer, glyphWidth, glyphHeight);
ctx.fillText(char, buffer, buffer + glyphTop);
const imgData = ctx.getImageData(buffer, buffer, glyphWidth, glyphHeight);
...
}
打印发现glyphWidth, glyphHeight是undefined。这几个值由最上面的actualBoundingBoxAscent, actualBoundingBoxDescent, actualBoundingBoxLeft, actualBoundingBoxRight计算得来,而这四个值在对象是中文字符时没有正常返回,从而导致整个绘制流程出错,结果表现就是带有中文字符标签(text-field)的symbol图层无法加载。
解决办法:
- 规避。升级浏览器,或避免标签出现中文。
- 修改该部分源码,在测量方法不能正常返回值时给glyphWidth和glyphHeight默认值,这样也可以绘制出中文标签