| 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 = /^([0-9]*?)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 unkown methods. | 
|         if ((newPlatformApis as any)[key]) { | 
|             (platformApi as any)[key] = (newPlatformApis as any)[key]; | 
|         } | 
|     } | 
| } |