jmgraph 3.2.22 → 3.2.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -55,10 +55,14 @@ class jmGraphImpl extends jmGraphCore {
55
55
  if(typeof option == 'function') {
56
56
  callback = option;
57
57
  option = {};
58
- }
58
+ }
59
59
 
60
60
  super(canvas, option, callback);
61
61
  }
62
+
63
+ static create(...args) {
64
+ return new jmGraphImpl(...args);
65
+ }
62
66
  }
63
67
 
64
68
  //创建实例,支持不加 new 直接调用
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "family": "jmgraph",
3
3
  "name": "jmgraph",
4
- "version": "3.2.22",
4
+ "version": "3.2.24",
5
5
  "description": "一个简单的canvas画图库",
6
6
  "homepage": "https://surl.fit/tools/tools/jmgraph",
7
7
  "keywords": [
@@ -90,7 +90,8 @@ export default class jmGradient {
90
90
  let sy2 = Number(y2) + bounds.top;
91
91
  if(this.type === 'linear') {
92
92
  if(control.mode === 'webgl' && control.webglControl) {
93
- gradient = control.webglControl.createLinearGradient(x1, y1, x2, y2, bounds);
93
+ // WebGL 着色器中 v_text_coord 是绝对坐标,需要传递绝对坐标
94
+ gradient = control.webglControl.createLinearGradient(sx1, sy1, sx2, sy2, bounds);
94
95
  gradient.key = this.toString();
95
96
  }
96
97
  else {
@@ -109,7 +110,8 @@ export default class jmGradient {
109
110
  r2 = d * r2;
110
111
  }
111
112
  if(control.mode === 'webgl' && control.webglControl) {
112
- gradient = control.webglControl.createRadialGradient(x1, y1, r1, x2, y2, r2, bounds);
113
+ // WebGL 着色器中 v_text_coord 是绝对坐标,需要传递绝对坐标
114
+ gradient = control.webglControl.createRadialGradient(sx1, sy1, r1, sx2, sy2, r2, bounds);
113
115
  gradient.key = this.toString();
114
116
  }
115
117
  //offsetLine = Math.abs(r2 - r1);//二圆半径差
@@ -85,8 +85,6 @@ export default class jmGraph extends jmControl {
85
85
  else {
86
86
  this.context = canvas.getContext(this.mode);
87
87
  }
88
-
89
- this.textureCanvas = option.textureCanvas || null;
90
88
 
91
89
  // webgl模式
92
90
  if(this.mode === 'webgl') {
@@ -1,6 +1,6 @@
1
1
 
2
2
  import earcut from '../earcut.js';
3
- import webglGradient from './gradient.js';
3
+ import webglGradient, { MAX_STOPS } from './gradient.js';
4
4
  import {
5
5
  createProgram,
6
6
  useProgram,
@@ -56,8 +56,8 @@ const pathVertexSource = `
56
56
  vec4 pos = translatePosition(a_position, a_center_point.x, a_center_point.y);
57
57
  gl_Position = pos;
58
58
  v_color = a_color;
59
- if(a_type == 2) {
60
- v_text_coord = a_text_coord;
59
+ if(a_type == 2 || a_type == 5) {
60
+ v_text_coord = a_position.xy;
61
61
  }
62
62
  }
63
63
  `;
@@ -67,21 +67,73 @@ const pathFragmentSource = `
67
67
  uniform sampler2D u_sample;
68
68
  uniform vec4 v_texture_bounds; // 纹理的左上坐标和大小 x,y,z,w
69
69
  uniform vec4 v_single_color;
70
+ // GLSL 渐变 uniforms
71
+ uniform int u_gradient_type; // 0=无 1=线性 2=径向
72
+ uniform vec4 u_gradient_start; // 线性:{x1,y1,0,0} 径向:{cx,cy,r1,0}
73
+ uniform vec4 u_gradient_end; // 线性:{x2,y2,0,0} 径向:{cx,cy,r2,0}
74
+ uniform int u_gradient_stop_count;
75
+ uniform float u_gradient_offsets[${MAX_STOPS}];
76
+ uniform vec4 u_gradient_colors[${MAX_STOPS}]; // {r, g, b, a} 0~1 范围
70
77
  varying float v_type;
71
78
  varying vec4 v_color;
72
79
  varying vec2 v_text_coord;
73
80
 
74
81
  ${convertTexturePosition}
75
82
 
83
+ // 在 sorted stops 中按 t 值采样颜色
84
+ // 兼容 GLSL ES 1.0:循环仅与常量比较,无 break/continue
85
+ vec4 sampleGradient(float t) {
86
+ t = clamp(t, 0.0, 1.0);
87
+ // 正向扫描:始终遍历 MAX_STOPS-1 次,找到 t 所在段并覆盖结果
88
+ float localT = 0.0;
89
+ vec4 c0 = u_gradient_colors[0];
90
+ vec4 c1 = u_gradient_colors[0];
91
+ for(int i = 0; i < ${MAX_STOPS - 1}; i++) {
92
+ float s0 = u_gradient_offsets[i];
93
+ float s1 = u_gradient_offsets[i + 1];
94
+ if(t >= s0) {
95
+ float range = s1 - s0;
96
+ localT = range > 0.0001 ? clamp((t - s0) / range, 0.0, 1.0) : 0.0;
97
+ c0 = u_gradient_colors[i];
98
+ c1 = u_gradient_colors[i + 1];
99
+ }
100
+ }
101
+ return mix(c0, c1, localT);
102
+ }
103
+
76
104
  void main() {
77
105
  // 如果是fill,则直接填充颜色
78
106
  if(v_type == 1.0) {
79
107
  gl_FragColor = v_single_color;
80
108
  }
81
- // 渐变色
109
+ // 渐变色 (旧方式,顶点颜色插值)
82
110
  else if(v_type == 3.0) {
83
111
  gl_FragColor = v_color;
84
112
  }
113
+ // GLSL 渐变填充 (type=5)
114
+ else if(v_type == 5.0) {
115
+ float t;
116
+ if(u_gradient_type == 2) {
117
+ // 径向渐变
118
+ vec2 d = v_text_coord - u_gradient_start.xy;
119
+ float dist = length(d);
120
+ float r1 = u_gradient_start.z;
121
+ float r2 = u_gradient_end.z;
122
+ float range = r2 - r1;
123
+ t = range > 0.001 ? (dist - r1) / range : 0.0;
124
+ } else {
125
+ // 线性渐变
126
+ vec2 dir = u_gradient_end.xy - u_gradient_start.xy;
127
+ float lenSq = dot(dir, dir);
128
+ if(lenSq > 0.001) {
129
+ vec2 pos = v_text_coord - u_gradient_start.xy;
130
+ t = dot(pos, dir) / lenSq;
131
+ } else {
132
+ t = 0.0;
133
+ }
134
+ }
135
+ gl_FragColor = sampleGradient(t) * v_single_color.a;
136
+ }
85
137
  else if(v_type == 2.0) {
86
138
  vec2 pos = translateTexturePosition(v_text_coord, v_texture_bounds);
87
139
  gl_FragColor = texture2D(u_sample, pos);
@@ -152,7 +204,7 @@ class WeblBase {
152
204
  rotate(angle) {
153
205
  const cos = Math.cos(angle);
154
206
  const sin = Math.sin(angle);
155
- const [a, b, c, d, tx, ty] = this.transformMatrix;
207
+ const [a, b, c, d] = this.transformMatrix;
156
208
 
157
209
  // 更新变换矩阵
158
210
  this.transformMatrix[0] = a * cos - b * sin;
@@ -183,21 +235,20 @@ class WeblBase {
183
235
  };
184
236
  }
185
237
 
186
- // 纹理绘制canvas
187
- get textureCanvas() {
188
- let canvas = this.graph.textureCanvas;
189
- if(!canvas) {
190
- if(typeof document === 'undefined') return null;
191
- canvas = this.graph.textureCanvas = document.createElement('canvas');
238
+ // 文本测量用的离屏 canvas context(1x1 单例缓存,不依赖 textureCanvas)
239
+ get _measureCtx() {
240
+ if(!this.__measureCtx) {
241
+ try {
242
+ if(typeof document !== 'undefined') {
243
+ const c = document.createElement('canvas');
244
+ c.width = c.height = 1;
245
+ this.__measureCtx = c.getContext('2d');
246
+ }
247
+ } catch(e) {
248
+ this.__measureCtx = null;
249
+ }
192
250
  }
193
- return canvas;
194
- }
195
- // 纹理绘制canvas ctx
196
- get textureContext() {
197
- const ctx = this.textureCanvas.ctx || (this.textureCanvas.ctx = this.textureCanvas.getContext('2d', {
198
- willReadFrequently: true
199
- }));
200
- return ctx;
251
+ return this.__measureCtx;
201
252
  }
202
253
 
203
254
  // i当前程序
@@ -243,23 +294,37 @@ class WeblBase {
243
294
  // 把传统颜色转为webgl识别的
244
295
  convertColor(color) {
245
296
  if(this.isGradient(color)) return color;
246
- if(typeof color === 'string') color = this.graph.utils.hexToRGBA(color);
247
- return this.graph.utils.rgbToDecimal(color);
248
- }
249
-
250
- setTextureStyle(style, value='') {
251
-
252
- if(typeof style === 'string') {
253
- if(['fillStyle', 'strokeStyle', 'shadowColor'].indexOf(style) > -1) {
254
- value = this.graph.utils.toColor(value);
297
+ if(typeof color === 'string') {
298
+ // 先尝试 hexToRGBA 解析
299
+ color = this.graph.utils.hexToRGBA(color);
300
+ // hexToRGBA 对无法识别的格式(如 hsl)会原样返回字符串
301
+ // 利用离屏 canvas 将任意 CSS 颜色转为 rgba
302
+ if(typeof color === 'string') {
303
+ color = this.__parseCSSColor(color);
255
304
  }
256
- this.textureContext[style] = value;
257
305
  }
258
- else {
259
- for(const name in style) {
260
- if(name === 'constructor') continue;
261
- this.setTextureStyle(name, style[name]);
306
+ if(typeof color === 'object' && color.r !== undefined) {
307
+ return this.graph.utils.rgbToDecimal(color);
308
+ }
309
+ return color;
310
+ }
311
+
312
+ // 利用离屏 canvas 解析任意 CSS 颜色(hsl/hsla/命名颜色等)
313
+ __parseCSSColor(colorStr) {
314
+ const ctx = this._measureCtx;
315
+ if(!ctx) return { r: 0, g: 0, b: 0, a: 0 };
316
+ try {
317
+ ctx.clearRect(0, 0, 1, 1);
318
+ ctx.fillStyle = '#000000';
319
+ ctx.fillStyle = colorStr;
320
+ ctx.fillRect(0, 0, 1, 1);
321
+ const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
322
+ if(ctx.fillStyle === '#000000' && colorStr !== '#000000' && colorStr !== 'black') {
323
+ return { r: 0, g: 0, b: 0, a: 0 };
262
324
  }
325
+ return { r, g, b, a: a / 255 };
326
+ } catch(e) {
327
+ return { r: 0, g: 0, b: 0, a: 0 };
263
328
  }
264
329
  }
265
330
 
@@ -434,70 +499,24 @@ class WeblBase {
434
499
  return obj && obj instanceof webglGradient;
435
500
  }
436
501
 
437
- /**
502
+ /**
438
503
  * 测试获取文本所占大小
439
504
  *
440
505
  * @method testSize
441
506
  * @return {object} 含文本大小的对象
442
507
  */
443
508
  testSize(text, style=this.style) {
444
-
445
- this.textureContext.save && this.textureContext.save();
446
- // 修改字体,用来计算
447
- if(style.font || style.fontSize) this.textureContext.font = style.font || (style.fontSize + 'px ' + style.fontFamily);
448
-
449
- //计算宽度
450
- const size = this.textureContext.measureText?
451
- this.textureContext.measureText(text):
452
- {width:15};
453
- this.textureContext.restore &&this.textureContext.restore();
454
- size.height = this.style.fontSize? this.style.fontSize: 15;
509
+ const ctx = this._measureCtx;
510
+ if(!ctx) return { width: 15, height: style.fontSize || 15 };
511
+
512
+ ctx.save && ctx.save();
513
+ if(style.font || style.fontSize) ctx.font = style.font || (style.fontSize + 'px ' + style.fontFamily);
514
+ const size = ctx.measureText ? ctx.measureText(text) : { width: 15 };
515
+ ctx.restore && ctx.restore();
516
+ size.height = style.fontSize ? parseInt(style.fontSize) : 15;
455
517
  return size;
456
518
  }
457
-
458
- // 使用纹理canvas生成图,
459
- // 填充可以是颜色或渐变对象
460
- // 如果指定了points,则表明要绘制不规则的图形
461
- toFillTexture(fillStyle, bounds, points=null) {
462
- const canvas = this.textureCanvas;
463
- if(!canvas) {
464
- return fillStyle;
465
- }
466
- canvas.width = bounds.width;
467
- canvas.height = bounds.height;
468
-
469
- if(!canvas.width || !canvas.height) {
470
- return fillStyle;
471
- }
472
-
473
- this.textureContext.clearRect(0, 0, canvas.width, canvas.height);
474
-
475
- this.textureContext.fillStyle = fillStyle;
476
-
477
- // 规则图形用 fillRect,比 beginPath/lineTo/fill 快
478
- if(!points || !points.length) {
479
- this.textureContext.fillRect(0, 0, bounds.width, bounds.height);
480
- } else {
481
- this.textureContext.beginPath();
482
- for(const p of points) {
483
- //移至当前坐标
484
- if(p.m) {
485
- this.textureContext.moveTo(p.x - bounds.left, p.y - bounds.top);
486
- }
487
- else {
488
- this.textureContext.lineTo(p.x - bounds.left, p.y - bounds.top);
489
- }
490
- }
491
- this.textureContext.closePath();
492
- this.textureContext.fill();
493
- }
494
-
495
- const data = this.textureContext.getImageData(0, 0, canvas.width, canvas.height);
496
- return {
497
- data,
498
- points
499
- };
500
- }
501
519
  }
502
520
 
503
- export default WeblBase;
521
+ export default WeblBase;
522
+ export { pathVertexSource, pathFragmentSource, MAX_STOPS };
@@ -1,8 +1,11 @@
1
- const WebglGradientTextureCache = {};
2
- // 渐变
1
+ const MAX_STOPS = 16;
2
+
3
+ /**
4
+ * WebGL 渐变对象
5
+ * 支持 GLSL 着色器直接计算渐变色,无需 textureCanvas
6
+ */
3
7
  class WebglGradient {
4
- // type:[linear= 线性渐变,radial=放射性渐变]
5
- constructor(type='linear', params={}) {
8
+ constructor(type = 'linear', params = {}) {
6
9
  this.type = type || 'linear';
7
10
 
8
11
  this.x1 = params.x1 || 0;
@@ -17,166 +20,120 @@ class WebglGradient {
17
20
  top: 0,
18
21
  width: 0,
19
22
  height: 0
20
- }
23
+ };
21
24
 
22
25
  this.control = params.control;
23
26
 
24
27
  this.stops = [];
25
- this.init();
26
- }
27
-
28
- init() {
29
- const dx = this.x2 - this.x1;
30
- const dy = this.y2 - this.y1;
31
-
32
- if(this.type === 'radial') {
33
- this.length = this.r2 - this.r1;
34
- }
35
- else if(dx === 0 && dy === 0) {
36
- this.length = 0;
37
- }
38
- else {
39
- // 渐变中心的距离
40
- this.length = Math.sqrt(Math.pow(dx, 2), Math.pow(dy, 2));
41
- this.sin = dy / this.length;
42
- this.cos = dx / this.length;
43
- }
28
+ this._sortedStops = null;
29
+ this._paramsHash = null;
44
30
  }
45
31
 
46
- // 渐变颜色
32
+ /**
33
+ * 添加颜色断点
34
+ */
47
35
  addColorStop(offset, color) {
48
36
  this.stops.push({
49
- offset,
37
+ offset: Math.max(0, Math.min(1, offset)),
50
38
  color
51
39
  });
40
+ this._sortedStops = null;
41
+ this._paramsHash = null;
52
42
  }
53
43
 
54
- // 转为渐变为纹理
55
- toImageData(control, bounds, points=null) {
56
- // 缓存基于渐变参数(不含 bounds,因为同一个渐变只是位置不同时纹理相同)
57
- const gradientKey = this.toString();
58
- if(this.__cachedData && this.__cacheKey === gradientKey &&
59
- this.__cachedData.data && this.__cachedData.data.width === Math.ceil(bounds.width) &&
60
- this.__cachedData.data.data && this.__cachedData.data.data.height === Math.ceil(bounds.height)) {
61
- return this.__cachedData;
62
- }
63
-
64
- if(!control.textureContext) {
65
- return null;
66
- }
67
- let gradient = null;
68
- if(this.type === 'linear') {
69
- gradient = control.textureContext.createLinearGradient(this.x1, this.y1, this.x2, this.y2);
70
- }
71
- else {
72
- gradient = control.textureContext.createRadialGradient(this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
73
- }
74
- this.stops.forEach(function(s, i) {
75
- const c = control.graph.utils.toColor(s.color);
76
- gradient && gradient.addColorStop(s.offset, c);
77
- });
78
-
79
- const data = control.toFillTexture(gradient, bounds, points);
44
+ /**
45
+ * 获取排序后的 stops(带解析后的颜色)
46
+ */
47
+ _getSortedStops() {
48
+ if (this._sortedStops) return this._sortedStops;
80
49
 
81
- this.__cachedData = data;
82
- this.__cacheKey = gradientKey;
50
+ const utils = this.control && this.control.graph && this.control.graph.utils;
51
+ this._sortedStops = this.stops
52
+ .map(s => {
53
+ let c = s.color;
54
+ if (utils && typeof c === 'string') {
55
+ c = utils.hexToRGBA(c);
56
+ }
57
+ if (typeof c === 'object' && c !== null) {
58
+ // hexToRGBA 返回 r/g/b 为 0~255,a 为 0~1
59
+ // 但如果已经是 0~1 范围(由 rgbToDecimal 处理过),需要检测
60
+ const needNormalize = (c.r > 1 || c.g > 1 || c.b > 1) ? 255 : 1;
61
+ return {
62
+ offset: s.offset,
63
+ r: (c.r !== undefined ? c.r : 0) / needNormalize,
64
+ g: (c.g !== undefined ? c.g : 0) / needNormalize,
65
+ b: (c.b !== undefined ? c.b : 0) / needNormalize,
66
+ a: c.a !== undefined ? c.a : 1
67
+ };
68
+ }
69
+ return { offset: s.offset, r: 0, g: 0, b: 0, a: 1 };
70
+ })
71
+ .sort((a, b) => a.offset - b.offset);
83
72
 
84
- return data;
73
+ return this._sortedStops;
85
74
  }
86
75
 
87
- // 当渐变参数变化时使缓存失效
88
- invalidateCache() {
89
- this.__cachedData = null;
90
- this.__cacheKey = null;
91
- }
76
+ /**
77
+ * 将渐变参数以 uniform 形式传递给着色器
78
+ * 返回 { type, start, end, stopCount, stops } 供着色器使用
79
+ */
80
+ toUniformParams() {
81
+ const stops = this._getSortedStops();
82
+ const count = Math.min(stops.length, MAX_STOPS);
92
83
 
93
- // 根据绘制图形的坐标计算出对应点的颜色
94
- /*
95
- toPointColors(points) {
96
- const stops = this.getStops();
97
- const colors = [];
98
- for(let i=0; i<points.length; i+=2) {
99
- const p = {
100
- x: points[i],
101
- y: points[i+1]
102
- }
103
- if(this.type === 'radial') {
104
- const dx = p.x - this.x1;
105
- const dy = p.y - this.y1;
106
- const len = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
107
- const rang = this.getStopRange(len, stops);
108
- if(!rang.start && rang.end) {
109
- colors.push(rang.end.color);
110
- }
111
- else if(!rang.end && rang.start) {
112
- colors.push(rang.start.color);
113
- }
114
- else {
115
- const rangLength = rang.end.length - rang.start.length;
116
- const offlen = len - rang.start.length;
117
- const per = offlen / rangLength;
118
- const color = {
119
- r: rang.start.color.r + (rang.end.color.r - rang.start.color.r) * per,
120
- g: rang.start.color.g + (rang.end.color.g - rang.start.color.g) * per,
121
- b: rang.start.color.b + (rang.end.color.b - rang.start.color.b) * per,
122
- a: rang.start.color.a + (rang.end.color.a - rang.start.color.a) * per,
123
- };
124
- colors.push(color);
125
- }
126
- }
84
+ // 展平为 Float32Array: [offset, r, g, b, a, ...]
85
+ const flatStops = new Float32Array(count * 5);
86
+ for (let i = 0; i < count; i++) {
87
+ const s = stops[i];
88
+ flatStops[i * 5 + 0] = s.offset;
89
+ flatStops[i * 5 + 1] = s.r;
90
+ flatStops[i * 5 + 2] = s.g;
91
+ flatStops[i * 5 + 3] = s.b;
92
+ flatStops[i * 5 + 4] = s.a;
127
93
  }
128
- return colors;
94
+
95
+ return {
96
+ gradientType: this.type === 'radial' ? 2 : 1,
97
+ gradientStart: new Float32Array([
98
+ this.x1, this.y1,
99
+ this.type === 'radial' ? Math.max(0, this.r1) : 0,
100
+ 0
101
+ ]),
102
+ gradientEnd: new Float32Array([
103
+ this.x2, this.y2,
104
+ this.type === 'radial' ? Math.max(0, this.r2) : 0,
105
+ 0
106
+ ]),
107
+ stopCount: count,
108
+ stops: flatStops
109
+ };
129
110
  }
130
- */
131
- // 根据起点距离获取边界stop
132
- /*
133
- getStopRange(len, stops) {
134
- const res = {};
135
- for(const s of stops) {
136
- if(s.length <= len) {
137
- res.start = s;
138
- }
139
- else {
140
- res.end = s;
141
- }
142
- }
143
- return res;
111
+
112
+ /**
113
+ * 使缓存失效
114
+ */
115
+ invalidateCache() {
116
+ this._sortedStops = null;
117
+ this._paramsHash = null;
144
118
  }
145
119
 
146
- // 根据stop计算offset长度
147
- getStops() {
148
- const stops = this.stops.sort((p1, p2) => p1.offset - p2.offset); // 渐变色排序从小于大
149
- for(const s of stops) {
150
-
151
- const color = typeof s.color === 'string'? this.control.graph.utils.hexToRGBA(s.color) : s.color;
152
- console.log(s, color);
153
- s.color = this.control.graph.utils.rgbToDecimal(color);
154
- s.length = s.offset * this.length;
120
+ /**
121
+ * 转换为渐变的字符串表达
122
+ */
123
+ toString() {
124
+ let str = this.type + '-gradient(';
125
+ if (this.type == 'linear') {
126
+ str += this.x1 + ' ' + this.y1 + ' ' + this.x2 + ' ' + this.y2;
155
127
  }
156
- return stops;
128
+ else {
129
+ str += this.x1 + ' ' + this.y1 + ' ' + this.r1 + ' ' + this.x2 + ' ' + this.y2 + ' ' + this.r2;
130
+ }
131
+ this.stops.forEach(function(s) {
132
+ str += ',' + s.color + ' ' + s.offset;
133
+ });
134
+ return str + ')';
157
135
  }
158
- */
159
- /**
160
- * 转换为渐变的字符串表达
161
- *
162
- * @method toString
163
- * @for jmGradient
164
- * @return {string} linear-gradient(x1 y1 x2 y2, color1 step, color2 step, ...); //radial-gradient(x1 y1 r1 x2 y2 r2, color1 step,color2 step, ...);
165
- */
166
- toString() {
167
- let str = this.type + '-gradient(';
168
- if(this.type == 'linear') {
169
- str += this.x1 + ' ' + this.y1 + ' ' + this.x2 + ' ' + this.y2;
170
- }
171
- else {
172
- str += this.x1 + ' ' + this.y1 + ' ' + this.r1 + ' ' + this.x2 + ' ' + this.y2 + ' ' + this.r2;
173
- }
174
- //颜色渐变
175
- this.stops.forEach(function(s) {
176
- str += ',' + s.color + ' ' + s.offset;
177
- });
178
- return str + ')';
179
- }
180
136
  }
181
137
 
182
- export default WebglGradient;
138
+ export default WebglGradient;
139
+ export { MAX_STOPS };
@@ -105,23 +105,22 @@ class webgl {
105
105
  // 由具体的绘制方法处理
106
106
  }
107
107
 
108
- // 测量文本宽度(复用纹理 canvas 的 context)
108
+ // 测量文本宽度
109
109
  measureText(text) {
110
- const ctx = this.base.textureContext;
111
- if(ctx && ctx.measureText) return ctx.measureText(text);
112
- const canvas = document.createElement('canvas');
113
- const ctx2 = canvas.getContext('2d');
114
- return ctx2.measureText(text);
110
+ if(this.base && this.base._measureCtx) {
111
+ return this.base._measureCtx.measureText(text);
112
+ }
113
+ return { width: 15 };
115
114
  }
116
115
 
117
116
  // 创建线性渐变
118
- createLinearGradient(x1, y1, x2, y2) {
119
- return this.base.createLinearGradient(x1, y1, x2, y2);
117
+ createLinearGradient(x1, y1, x2, y2, bounds) {
118
+ return this.base.createLinearGradient(x1, y1, x2, y2, bounds);
120
119
  }
121
120
 
122
121
  // 创建径向渐变
123
- createRadialGradient(x1, y1, r1, x2, y2, r2) {
124
- return this.base.createRadialGradient(x1, y1, r1, x2, y2, r2);
122
+ createRadialGradient(x1, y1, r1, x2, y2, r2, bounds) {
123
+ return this.base.createRadialGradient(x1, y1, r1, x2, y2, r2, bounds);
125
124
  }
126
125
 
127
126
  // 绘制图像