zrender
Version:
A lightweight graphic library providing 2d draw for Apache ECharts
112 lines (101 loc) • 3.72 kB
text/typescript
export const DEFAULT_FONT_SIZE = 12;
export const DEFAULT_FONT_FAMILY = 'sans-serif';
export const DEFAULT_FONT = `${DEFAULT_FONT_SIZE}px ${DEFAULT_FONT_FAMILY}`;
interface Platform {
// TODO CanvasLike?
createCanvas(): HTMLCanvasElement
measureText(text: string, font?: string): { width: number }
loadImage(
src: string,
onload: () => void | HTMLImageElement['onload'],
onerror: () => void | HTMLImageElement['onerror']
): HTMLImageElement
}
// Text width map used for environment there is no canvas
// Only common ascii is used for size concern.
// Generated from following code
//
// ctx.font = '12px sans-serif';
// const asciiRange = [32, 126];
// let mapStr = '';
// for (let i = asciiRange[0]; i <= asciiRange[1]; i++) {
// const char = String.fromCharCode(i);
// const width = ctx.measureText(char).width;
// const ratio = Math.round(width / 12 * 100);
// mapStr += String.fromCharCode(ratio + 20))
// }
// mapStr.replace(/\\/g, '\\\\');
const OFFSET = 20;
const SCALE = 100;
// TODO other basic fonts?
// eslint-disable-next-line
const defaultWidthMapStr = `007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N`;
function getTextWidthMap(mapStr: string): Record<string, number> {
const map: Record<string, number> = {};
if (typeof JSON === 'undefined') {
return map;
}
for (let i = 0; i < mapStr.length; i++) {
const char = String.fromCharCode(i + 32);
const size = (mapStr.charCodeAt(i) - OFFSET) / SCALE;
map[char] = size;
}
return map;
}
export const DEFAULT_TEXT_WIDTH_MAP = getTextWidthMap(defaultWidthMapStr);
export const platformApi: Platform = {
// Export methods
createCanvas() {
return typeof document !== 'undefined'
&& document.createElement('canvas');
},
measureText: (function () {
let _ctx: CanvasRenderingContext2D;
let _cachedFont: string;
return (text: string, font?: string) => {
if (!_ctx) {
const canvas = platformApi.createCanvas();
_ctx = canvas && canvas.getContext('2d');
}
if (_ctx) {
if (_cachedFont !== font) {
_cachedFont = _ctx.font = font || DEFAULT_FONT;
}
return _ctx.measureText(text);
}
else {
text = text || '';
font = font || DEFAULT_FONT;
// Use font size if there is no other method can be used.
const res = /((?:\d+)?\.?\d*)px/.exec(font);
const fontSize = res && +res[1] || DEFAULT_FONT_SIZE;
let width = 0;
if (font.indexOf('mono') >= 0) { // is monospace
width = fontSize * text.length;
}
else {
for (let i = 0; i < text.length; i++) {
const preCalcWidth = DEFAULT_TEXT_WIDTH_MAP[text[i]];
width += preCalcWidth == null ? fontSize : (preCalcWidth * fontSize);
}
}
return { width };
}
};
})(),
loadImage(src, onload, onerror) {
const image = new Image();
image.onload = onload;
image.onerror = onerror;
image.src = src;
return image;
}
};
export function setPlatformAPI(newPlatformApis: Partial<Platform>) {
for (let key in platformApi) {
// Don't assign unknown methods.
if ((newPlatformApis as any)[key]) {
(platformApi as any)[key] = (newPlatformApis as any)[key];
}
}
}