jmgraph 3.2.2 → 3.2.3

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.
@@ -0,0 +1,679 @@
1
+ import WebglBase from './base.js';
2
+
3
+ // 把canvas坐标转为webgl坐标系
4
+ const convertPointSource = `
5
+ vec4 translatePosition(vec4 point, float x, float y) {
6
+ point.x = (point.x-x)/x;
7
+ point.y = (y-point.y)/y;
8
+ return point;
9
+ }`;
10
+ // 把纹理的canvas坐标转为纹理的坐标系
11
+ const convertTexturePosition = `
12
+ vec2 translateTexturePosition(in vec2 point, vec4 bounds) {
13
+ point.x = (point.x-bounds.x)/bounds.z; // 离左上角位置的X长比上纹理宽 0-1
14
+ point.y = 1.0-(point.y-bounds.y)/bounds.w; // 离左上角位置的Y长比上高,因为纹理坐标是左下角起,所以要用1-
15
+ return point;
16
+ }`;
17
+
18
+ // path顶点着色器源码
19
+ const pathVertexSource = `
20
+ attribute vec4 a_position;
21
+ attribute vec4 a_color;
22
+ attribute vec2 a_text_coord;
23
+ uniform vec2 a_center_point; // 当前canvas的中心位置
24
+ uniform float a_point_size; // 点的大小
25
+ uniform int a_type;
26
+ varying vec4 v_color;
27
+ varying vec2 v_text_coord;
28
+ varying float v_type;
29
+
30
+ ${convertPointSource}
31
+
32
+ void main() {
33
+ gl_PointSize = a_point_size == 0.0? 1.0 : a_point_size;
34
+ v_type = float(a_type);
35
+ vec4 pos = translatePosition(a_position, a_center_point.x, a_center_point.y);
36
+ gl_Position = pos;
37
+ v_color = a_color;
38
+ if(a_type == 2) {
39
+ v_text_coord = a_text_coord;
40
+ }
41
+ }
42
+ `;
43
+ // path 片段着色器源码
44
+ const pathFragmentSource = `
45
+ precision highp float;
46
+ uniform sampler2D u_sample;
47
+ uniform vec4 v_texture_bounds; // 纹理的左上坐标和大小 x,y,z,w
48
+ uniform vec4 v_single_color;
49
+ varying float v_type;
50
+ varying vec4 v_color;
51
+ varying vec2 v_text_coord;
52
+
53
+ ${convertTexturePosition}
54
+
55
+ void main() {
56
+ // 如果是fill,则直接填充颜色
57
+ if(v_type == 1.0) {
58
+ gl_FragColor = v_single_color;
59
+ }
60
+ // 渐变色
61
+ else if(v_type == 3.0) {
62
+ gl_FragColor = v_color;
63
+ }
64
+ else if(v_type == 2.0) {
65
+ vec2 pos = translateTexturePosition(v_text_coord, v_texture_bounds);
66
+ gl_FragColor = texture2D(u_sample, pos);
67
+ }
68
+ else {
69
+ float r = distance(gl_PointCoord, vec2(0.5, 0.5));
70
+ //根据距离设置片元
71
+ if(r <= 0.5){
72
+ // 方形区域片元距离几何中心半径小于0.5,像素颜色设置红色
73
+ gl_FragColor = v_single_color;
74
+ }else {
75
+ // 方形区域距离几何中心半径不小于0.5的片元剪裁舍弃掉:
76
+ discard;
77
+ }
78
+ }
79
+ }
80
+ `;
81
+
82
+ // path 绘制类
83
+ class WebglPath extends WebglBase {
84
+ constructor(graph, option) {
85
+ super(graph, option);
86
+ // 是否是规则的,不规则的处理方式更为复杂和耗性能
87
+ this.isRegular = option.isRegular || false;
88
+ this.needCut = option.needCut || false;
89
+
90
+ this.points = [];
91
+ }
92
+
93
+ // i当前程序
94
+ get program() {
95
+ // 默认所有path用同一个编译好的program
96
+ return this.graph.context.pathProgram || (this.graph.context.pathProgram=this.createProgram(pathVertexSource, pathFragmentSource));
97
+ }
98
+
99
+ // 设置样式
100
+ setStyle(style = this.style, value = '') {
101
+ this.useProgram();
102
+
103
+ if(typeof style === 'string') {
104
+ const obj = {};
105
+ obj[style] = value;
106
+ style = obj;
107
+ }
108
+
109
+ // 设置线条颜色或填充色
110
+ if(style.strokeStyle) {
111
+ let color = style.strokeStyle;
112
+ if(typeof color === 'string') color = this.graph.utils.hexToRGBA(color);
113
+ this.style.strokeStyle = this.graph.utils.rgbToDecimal(color);
114
+ delete style.strokeStyle;
115
+ }
116
+ else if(style.fillStyle) {
117
+ let color = style.fillStyle;
118
+ if(this.isGradient(color)) {
119
+ this.style.fillStyle = color;
120
+ }
121
+ else {
122
+ if(typeof color === 'string') color = this.graph.utils.hexToRGBA(color);
123
+ this.style.fillStyle = this.graph.utils.rgbToDecimal(color);
124
+ }
125
+ delete style.fillStyle;
126
+ }
127
+
128
+ this.style = {
129
+ ...this.style,
130
+ ...style
131
+ }
132
+ }
133
+
134
+ setParentBounds(parentBounds = this.parentAbsoluteBounds) {
135
+
136
+ //this.useProgram();
137
+
138
+ if(parentBounds) this.parentAbsoluteBounds = parentBounds;
139
+ // 写入当前canvas大小
140
+ this.context.uniform2f(this.program.uniforms.a_center_point.location, this.graph.width / 2, this.graph.height / 2);
141
+ }
142
+
143
+ setFragColor(color) {
144
+
145
+ if(!Array.isArray(color)) {
146
+ if(typeof color === 'string') color = this.graph.utils.hexToRGBA(color);
147
+ if(typeof color.a === 'undefined') color.a = 1;
148
+ this.context.uniform4f(this.program.uniforms.v_single_color.location, color.r, color.g, color.b, color.a * this.style.globalAlpha);
149
+ return null;
150
+ }
151
+
152
+ const colorData = [];
153
+ for(let c of color) {
154
+ if(typeof c === 'string') c = this.graph.utils.hexToRGBA(c);
155
+ if(typeof c.a === 'undefined') c.a = 1;
156
+ colorData.push(c.r, c.g, c.b, c.a * this.style.globalAlpha);
157
+ }
158
+
159
+ const colorBuffer = this.createFloat32Buffer(colorData);
160
+ this.writeVertexAttrib(colorBuffer, this.program.attrs.a_color, 4, 0, 0);
161
+ colorBuffer.attr = this.program.attrs.a_color;
162
+ return colorBuffer;
163
+ }
164
+
165
+ beginDraw() {
166
+ this.useProgram();
167
+ }
168
+
169
+ // 开始绘制
170
+ draw(points, parentBounds = this.parentAbsoluteBounds) {
171
+ //this.useProgram();
172
+
173
+ this.setParentBounds(parentBounds);
174
+
175
+ this.points = points;
176
+ }
177
+
178
+ endDraw() {
179
+ if(this.points) delete this.points;
180
+ if(this.pathPoints) delete this.pathPoints;
181
+ }
182
+
183
+ // 图形封闭
184
+ closePath() {
185
+ if(this.points && this.points.length > 2 && this.points[0] !== this.points[this.points.length-1]) {
186
+ const start = this.points[0];
187
+ const end = this.points[this.points.length-1];
188
+ if(start != end && !(start.x === end.x && start.y === end.y)) this.points.push(start);
189
+ }
190
+ }
191
+
192
+ // 绘制点数组
193
+ writePoints(points, attr = this.program.attrs.a_position) {
194
+
195
+ const fixedPoints = [];
196
+ for(const p of points) {
197
+ fixedPoints.push(
198
+ p.x + this.parentAbsoluteBounds.left,
199
+ p.y + this.parentAbsoluteBounds.top
200
+ );
201
+ }
202
+ const vertexBuffer = this.createFloat32Buffer(fixedPoints);
203
+ this.writeVertexAttrib(vertexBuffer, attr, 2, 0, 0);
204
+ vertexBuffer.attr = attr;
205
+ return vertexBuffer;
206
+ }
207
+
208
+ // 连接二个点
209
+ genLinePoints(start, end) {
210
+ const points = [start];
211
+ const dx = end.x - start.x;
212
+ const dy = end.y - start.y;
213
+ if(dx !== 0 || dy !== 0) {
214
+ const len = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
215
+ const cos = dx / len;
216
+ const sin = dy / len;
217
+ const step = 0.5;
218
+ for(let l=step; l<len; l+=step) {
219
+ const x = start.x + cos * l;
220
+ const y = start.y + sin * l;
221
+ points.push({
222
+ x: Number(x.toFixed(2)),
223
+ y: Number(y.toFixed(2))
224
+ });
225
+ }
226
+ }
227
+ points.push(end);
228
+ return points;
229
+ }
230
+
231
+ // 把path坐标集合分解成一个个点,并且处理moveTo线段能力
232
+ pathToPoints(points=this.points) {
233
+ let start = null;
234
+ const res = [];
235
+ for(let i=0; i<points.length; i++) {
236
+ const p = points[i];
237
+ if(start && !p.m) {
238
+ const linePoints = this.genLinePoints(start, p);
239
+ res.push(...linePoints);
240
+ }
241
+ else if(start && !res.includes(start)) {
242
+ res.push(start);
243
+ }
244
+ start = p;
245
+ }
246
+ if(!res.includes(start)) res.push(start);
247
+ return res;
248
+ }
249
+ // 二点是否重合
250
+ equalPoint(p1, p2) {
251
+ return p1.x === p2.x && p1.y === p2.y;
252
+ }
253
+ // 把path坐标集合转为线段集
254
+ pathToLines(points) {
255
+ let start = null;
256
+ const res = [];
257
+ for(let i=0; i<points.length; i++) {
258
+ const p = points[i];
259
+ // 不重合的二个点,组成线段
260
+ if(start && !p.m && !(start.x == p.x && start.y == p.y)) {
261
+ const line = {
262
+ start,
263
+ end: p,
264
+ };
265
+ res.push(line);
266
+ }
267
+ start = p;
268
+ }
269
+ return res;
270
+ }
271
+
272
+ // 裁剪线段,如果二段线段有交点,则分割成四段, 端头相交的线段不用分割
273
+ cutLines(lines, index1=0, index2=0) {
274
+ if(lines && lines.length < 3) return lines;
275
+
276
+ index2 = Math.max(index1 + 1, index2); //如果指定了比下一个更大的索引,则用更大的,说明前面的已经处理过了,不需要重复
277
+
278
+ // 找出线段相交的点,并切割线段
279
+ while(index1 < lines.length) {
280
+ const line1 = lines[index1];
281
+
282
+ while(index2 < lines.length) {
283
+ const line2 = lines[index2];
284
+ // 如果二条线顶点有重合,则不用处理
285
+ if(this.equalPoint(line1.start, line2.start) || this.equalPoint(line1.end, line2.end) ||
286
+ this.equalPoint(line1.start, line2.end) || this.equalPoint(line1.end, line2.start)) {
287
+ index2++;
288
+ continue;
289
+ }
290
+ let cuted = false;
291
+ const intersection = this.getIntersection(line1, line2);// 计算交点
292
+ if(intersection) {
293
+ // 如果交点不是线段的端点,则分割成二条线段
294
+ if(!this.equalPoint(line1.start, intersection) && !this.equalPoint(line1.end, intersection)) {
295
+ const sub1 = {
296
+ start: line1.start,
297
+ end: intersection
298
+ };
299
+ const sub2 = {
300
+ start: intersection,
301
+ end: line1.end
302
+ };
303
+ // 从原数组中删除当前线段,替换成新的线段
304
+ lines.splice(index1, 1, sub1, sub2);
305
+ // 当前线段被重新替换,需要重新从它开始处理
306
+ cuted = true;
307
+ index2 ++;// 因为多加入了一个线段,则对比线索引需要加1
308
+ }
309
+ // 如果交点不是线段的端点,则分割成二条线段
310
+ if(!this.equalPoint(line2.start, intersection) && !this.equalPoint(line2.end, intersection)) {
311
+ const sub1 = {
312
+ start: line2.start,
313
+ end: intersection
314
+ };
315
+ const sub2 = {
316
+ start: intersection,
317
+ end: line2.end
318
+ };
319
+ // 从原数组中删除当前线段,替换成新的线段
320
+ lines.splice(index2, 1, sub1, sub2);
321
+ index2 ++; // 线段2也切成了二段,对比索引要继续加1
322
+ }
323
+ }
324
+ index2++;
325
+ // 如果已经分割了起始线段,则第一个子线段开始,重新对比后面还未对比完的。直接所有对比完成返回
326
+ if(cuted) return this.cutLines(lines, index1, index2);
327
+ }
328
+ index1++;
329
+ index2 = index1 + 1;
330
+ }
331
+ return lines;
332
+ }
333
+
334
+ // 计算二个线段的交点
335
+ getIntersection(line1, line2) {
336
+ // 如果首尾相接,也认为是有交点
337
+ if(this.equalPoint(line1.start, line2.start) || this.equalPoint(line1.start, line2.end)) return line1.start;
338
+ if(this.equalPoint(line1.end, line2.start) || this.equalPoint(line1.end, line2.end)) return line1.end;
339
+
340
+ // 三角形abc 面积的2倍
341
+ const area_abc = (line1.start.x - line2.start.x) * (line1.end.y - line2.start.y) - (line1.start.y - line2.start.y) * (line1.end.x - line2.start.x);
342
+
343
+ // 三角形abd 面积的2倍
344
+ const area_abd = (line1.start.x - line2.end.x) * (line1.end.y - line2.end.y) - (line1.start.y - line2.end.y) * (line1.end.x - line2.end.x);
345
+
346
+ // 面积符号相同则两点在线段同侧,不相交 (=0表示在线段顶点上);
347
+ if (area_abc * area_abd > 0) {
348
+ return null;
349
+ }
350
+
351
+ // 三角形cda 面积的2倍
352
+ const area_cda = (line2.start.x - line1.start.x) * (line2.end.y - line1.start.y) - (line2.start.y - line1.start.y) * (line2.end.x - line1.start.x);
353
+ // 三角形cdb 面积的2倍
354
+ // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
355
+ const area_cdb = area_cda + area_abc - area_abd ;
356
+ if(area_cda * area_cdb > 0) {
357
+ return null ;
358
+ }
359
+ if(area_abd === area_abc) return null;
360
+
361
+ //计算交点坐标
362
+ const t = area_cda / (area_abd - area_abc);
363
+ const dx= t * (line1.end.x - line1.start.x);
364
+ const dy= t * (line1.end.y - line1.start.y);
365
+
366
+ return {
367
+ x: Number((line1.start.x + dx).toFixed(2)),
368
+ y: Number((line1.start.y + dy).toFixed(2))
369
+ };
370
+ }
371
+
372
+ // 找出跟当前线段尾部相交的所有线段
373
+ getIntersectionLines(line, lines, index, point=line.end, points=[], root=null) {
374
+ const res = {
375
+ line,
376
+ polygons: []
377
+ };
378
+
379
+ points.push(point);
380
+
381
+ if(root && this.equalPoint(root.line.start, point)) {
382
+ points.unshift(root.line.start); // 把起始地址加入进去
383
+ root.polygons.push(points);
384
+ return res;
385
+ }
386
+
387
+ for(;index<lines.length; index++) {
388
+ const l = lines[index];
389
+ if(this.equalPoint(point, l.start)) {
390
+ if(points.includes(l.end)) continue;
391
+ this.getIntersectionLines(l, lines, index+1, l.end, [...points], root||res);
392
+ }
393
+ else if(this.equalPoint(point, l.end)) {
394
+ if(points.includes(l.start)) continue;
395
+ this.getIntersectionLines(l, lines, index+1, l.start, [...points], root||res);
396
+ }
397
+ }
398
+ return res;
399
+ }
400
+
401
+ // 根据路径点坐标,切割出封闭的多边形
402
+ getPolygon(points) {
403
+ let polygons = [];
404
+ let lines = this.pathToLines(points); // 分解得到线段
405
+ if(lines && lines.length > 2) {
406
+ lines = this.cutLines(lines); // 把所有相交点切割线段找出来
407
+ for(let i=0; i<lines.length-1; i++) {
408
+ const line1 = lines[i];
409
+ let polygon = [];// 当前图形
410
+
411
+ const treeLine = this.getIntersectionLines(line1, lines, i+1);
412
+
413
+ if(treeLine.polygons.length) polygons.push(...treeLine.polygons);
414
+ continue;
415
+ let lastLine = line1; // 下一个还在连接状态的线
416
+ for(let j=i+1; j<lines.length; j++) {
417
+ const line2 = lines[j];
418
+ // 如果跟下一条线相接,则表示还在形成图形中
419
+ if(this.equalPoint(lastLine.end, line2.start)) {
420
+ polygon.push(lastLine.end);
421
+ lastLine = line2;
422
+ if(i === j+1) continue; //下一条相连 则不需要处理相交情况
423
+ }
424
+ else {
425
+ polygon = [];
426
+ }
427
+ // 因为前面进行了分割线段,则里只有处理端点相连的情况
428
+ const intersection = this.equalPoint(line1.start, line2.end)? line1.start: null;//this.getIntersection(line1, line2);// 计算交点
429
+ if(intersection) {
430
+ polygon.push(intersection);// 交叉点为图形顶点
431
+ // 如果上一个连接线不是当前交叉线,则表示重新开始闭合
432
+ // 如果上一个连接线是当前交叉线,形成了封闭的图形
433
+ if(lastLine === line2 && polygon.length > 1) {
434
+ polygons.push(polygon);
435
+
436
+ // 封闭后,下一个起始线条就是从交点开始计算起
437
+ /*lastLine = {
438
+ start: intersection,
439
+ end: line2.end
440
+ };*/
441
+ polygon = [];// 重新开始新一轮找图形
442
+
443
+ /*
444
+ // 如果交点是上一条线的终点,则新图形为空
445
+ if(this.equalPoint(line2.end, intersection)) {
446
+ polygon = [];// 重新开始新一轮找图形
447
+ }
448
+ else {
449
+ // 同时交点也要加到上一个图形中第一个点,形成封闭
450
+ polygon.unshift(intersection);
451
+
452
+ polygon = [ intersection ];// 重新开始新一轮找图形
453
+ }*/
454
+ }
455
+ else {
456
+ lastLine = line2;
457
+ }
458
+ }
459
+ }
460
+ }
461
+ }
462
+
463
+ // 当有多个封闭图形时,再弟归一下,里面是不是有封闭图形内还有子封闭图形
464
+ /*if(polygons.length > 1) {
465
+ const newPolygons = [];
466
+ for(const polygon of polygons) {
467
+ // 只有大于4才有可能有子封闭图形
468
+ if(polygon.length > 4) {
469
+ const childPolygons = this.getPolygon(polygon);
470
+ // 当有多个子图形时,表示它不是最终封闭图形,跳过,
471
+ // 因为它的子图形之前有加入的,不需要重复加入
472
+ if(childPolygons.length > 1) {
473
+ //newPolygons.push(...childPolygons);
474
+ continue;
475
+ }
476
+ }
477
+ newPolygons.push(polygon);
478
+ }
479
+ polygons = newPolygons;
480
+ }*/
481
+ return polygons;
482
+ }
483
+
484
+ // 画线条
485
+ stroke(points = this.points, color = this.style.strokeStyle, lineWidth = this.style.lineWidth) {
486
+ if(!points || !points.length) return;
487
+ // this.useProgram();
488
+
489
+ let colorBuffer = null;
490
+ if(color) {
491
+ colorBuffer = this.setFragColor(color);
492
+ }
493
+ // 线宽
494
+ if(lineWidth) {
495
+ this.context.uniform1f(this.program.uniforms.a_point_size.location, lineWidth);// * this.graph.devicePixelRatio
496
+ }
497
+ // 标注为stroke
498
+ if(this.program.uniforms.a_type) {
499
+ // 4表示单画一个圆点,1表示方块形成的线条
500
+ this.context.uniform1i(this.program.uniforms.a_type.location, points.length === 1? 4 :1);
501
+ }
502
+ if(points && points.length) {
503
+ const regular = this.isRegular && (lineWidth == 1);
504
+ points = regular? points : this.pathToPoints(points);
505
+ //this.context.lineWidth(10);
506
+ const buffer = this.writePoints(points);
507
+ this.context.drawArrays(regular? this.context.LINES: this.context.POINTS, 0, points.length);
508
+ this.deleteBuffer(buffer);
509
+ }
510
+ colorBuffer && this.deleteBuffer(colorBuffer);
511
+ colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
512
+ }
513
+
514
+ // 填充图形
515
+ fill(bounds = {left: 0, top: 0, width: 0, height: 0}, type = 1) {
516
+ //this.useProgram();
517
+
518
+ if(this.points && this.points.length) {
519
+
520
+ // 如果是颜色rgba
521
+ if(this.style.fillStyle) {
522
+
523
+ let filled = false;// 是否成功填充
524
+ // 3个以上的点,且非规则图形才需要切割
525
+ if(this.points.length > 3) {
526
+ if(this.isRegular && this.needCut) {
527
+ // 需要分割三角形,不然填充会有问题
528
+ const triangles = this.earCutPointsToTriangles(this.points);// 切割得到三角形顶点二维数组
529
+
530
+ if(triangles && triangles.length) {
531
+ for(const triangle of triangles) {
532
+ this.fillColor(triangle, this.style.fillStyle, bounds, type); // 单独为每个分割的图形填充
533
+
534
+ // 如果指定的是img,则采用填充图片的方式
535
+ if(this.style.fillImage) {
536
+ this.fillImage(this.style.fillImage, triangle, bounds);
537
+ }
538
+ }
539
+ filled = true;// 表示已填充过了
540
+ }
541
+ }
542
+ else if(!this.isRegular) {
543
+ const polygons = this.getPolygon(this.points);
544
+ if(polygons.length) {
545
+ for(const polygon of polygons) {
546
+ // 需要分割三角形,不然填充会有问题
547
+ const triangles = this.earCutPointsToTriangles(polygon);// 切割得到三角形顶点二维数组
548
+
549
+ if(triangles && triangles.length) {
550
+ for(const triangle of triangles) {
551
+ this.fillColor(triangle, this.style.fillStyle, bounds, type); // 单独为每个分割的图形填充
552
+
553
+ // 如果指定的是img,则采用填充图片的方式
554
+ if(this.style.fillImage) {
555
+ this.fillImage(this.style.fillImage, triangle, bounds);
556
+ }
557
+ }
558
+ filled = true;// 表示已填充过了
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+ // 如果前面的条件没有填充成功,则直接按正常填充
565
+ if(!filled) {
566
+ this.fillColor(this.points, this.style.fillStyle, bounds, type);// 如果指定的是img,则采用填充图片的方式
567
+ if(this.style.fillImage) {
568
+ this.fillImage(this.style.fillImage, this.points, bounds);
569
+ }
570
+ }
571
+
572
+ }
573
+ }
574
+ }
575
+
576
+ fillColor(points, color, bounds, type=1) {
577
+
578
+ // 如果是渐变色,则需要计算偏移量的颜色
579
+ if(this.isGradient(color)) {
580
+ const imgData = color.toImageData(this, bounds);
581
+ return this.fillImage(imgData, points, bounds);
582
+ }
583
+
584
+ // 标注为fill
585
+ this.context.uniform1i(this.program.uniforms.a_type.location, type);
586
+ const colorBuffer = this.setFragColor(color);
587
+
588
+ const buffer = this.writePoints(points);
589
+ this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
590
+ if(buffer) {
591
+ this.deleteBuffer(buffer);
592
+ this.disableVertexAttribArray(buffer.attr);
593
+ }
594
+ colorBuffer && this.deleteBuffer(colorBuffer);
595
+ colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
596
+
597
+ // 为线段顶点绘制
598
+ /*for(const p of points) {
599
+ this.stroke([p], 'red', 10);
600
+ }*/
601
+ }
602
+
603
+ // 区域填充图片
604
+ // points绘制的图形顶点
605
+ // 图片整体绘制区域
606
+ fillImage(img, points, bounds) {
607
+ if(!img) return;
608
+
609
+ // 设置纹理
610
+ const texture = img instanceof ImageData? this.createDataTexture(img) : this.createImgTexture(img);
611
+ this.context.uniform1i(this.program.uniforms.u_sample.location, 0); // 纹理单元传递给着色器
612
+
613
+ // 指定纹理区域尺寸
614
+ this.context.uniform4f(this.program.uniforms.v_texture_bounds.location,
615
+ bounds.left + this.parentAbsoluteBounds.left,
616
+ bounds.top + this.parentAbsoluteBounds.top,
617
+ bounds.width,
618
+ bounds.height,
619
+ ); // 纹理单元传递给着色器
620
+
621
+ // 标注为纹理对象
622
+ this.context.uniform1i(this.program.uniforms.a_type.location, 2);
623
+
624
+ let filled = false;// 是否成功填充
625
+ // 3个以上的点,且非规则图形才需要切割
626
+ if(points.length > 3 && !this.isRegular) {
627
+ const polygons = this.getPolygon(points);
628
+ if(polygons.length) {
629
+ for(const polygon of polygons) {
630
+ // 需要分割三角形,不然填充会有问题
631
+ const triangles = this.earCutPointsToTriangles(polygon);// 切割得到三角形顶点二维数组
632
+
633
+ if(triangles && triangles.length) {
634
+ for(const triangle of triangles) {
635
+ this.fillTexture(triangle); // 单独为每个分割的图形填充
636
+ }
637
+ filled = true;// 表示已填充过了
638
+ }
639
+ }
640
+ }
641
+ }
642
+ // 如果前面的条件没有填充成功,则直接按正常填充
643
+ if(!filled) {
644
+ this.fillTexture(points);
645
+ }
646
+ this.deleteTexture(texture);
647
+ }
648
+
649
+ // 填充图形
650
+ drawImage(img, left=0, top=0, width=img.width, height=img.height) {
651
+ width = width || img.width;
652
+ height = height || img.height;
653
+
654
+ //this.useProgram();
655
+
656
+ this.fillImage(img, this.points, {
657
+ left,
658
+ top,
659
+ width,
660
+ height
661
+ });
662
+ }
663
+
664
+ fillTexture(points) {
665
+ // 纹理坐标
666
+ const coordBuffer = this.writePoints(points, this.program.attrs.a_text_coord);
667
+
668
+ if(points && points.length) {
669
+ const buffer = this.writePoints(points);
670
+ this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
671
+ this.deleteBuffer(buffer);
672
+ this.disableVertexAttribArray(buffer.attr);
673
+ }
674
+ this.disableVertexAttribArray(coordBuffer.attr);
675
+ this.deleteBuffer(coordBuffer);
676
+ }
677
+ }
678
+
679
+ export default WebglPath;