Blame view

node_modules/zrender/src/core/platform.ts 3.63 KB
bd028579   易尊强   2/28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  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+)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];
          }
      }
  }