jmgraph 3.2.16 → 3.2.18
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/LICENSE +21 -21
- package/README.md +251 -428
- package/build/gulpfile.js +142 -142
- package/build/package-lock.json +10666 -0
- package/build/package.json +71 -71
- package/dev.js +9 -9
- package/dist/jmgraph.core.min.js +1 -1
- package/dist/jmgraph.core.min.js.map +1 -1
- package/dist/jmgraph.js +3500 -2668
- package/dist/jmgraph.min.js +1 -1
- package/example/ball.html +216 -216
- package/example/base.html +111 -111
- package/example/canvas.html +53 -53
- package/example/cell.html +283 -283
- package/example/controls/arc.html +128 -128
- package/example/controls/arrowline.html +77 -77
- package/example/controls/bezier.html +298 -298
- package/example/controls/img.html +96 -96
- package/example/controls/label.html +86 -86
- package/example/controls/line.html +172 -172
- package/example/controls/prismatic.html +62 -62
- package/example/controls/rect.html +63 -63
- package/example/controls/resize.html +111 -111
- package/example/controls/test.html +359 -359
- package/example/es.html +69 -69
- package/example/es5module.html +62 -63
- package/example/heartarc.html +115 -115
- package/example/index.html +46 -46
- package/example/js/require.js +4 -4
- package/example/love/img/bling/bling.tps +265 -265
- package/example/love/img/bling.json +87 -87
- package/example/love/img/bling.tps +295 -295
- package/example/love/img/love.json +95 -95
- package/example/love/img/love.tps +315 -315
- package/example/love/img/qq/qq.tps +399 -399
- package/example/love/img/qq.json +242 -242
- package/example/love/index.html +40 -40
- package/example/love/js/game.js +558 -558
- package/example/music.html +210 -210
- package/example/node/test.js +137 -137
- package/example/pdf.html +186 -186
- package/example/progress.html +172 -172
- package/example/pso.html +147 -147
- package/example/sort.html +804 -815
- package/example/tweenjs.html +83 -83
- package/example/webgl.html +278 -278
- package/example/xfj/index.html +331 -331
- package/example/xfj/shake.js +48 -48
- package/example/xfj/testori.html +75 -75
- package/index.js +99 -99
- package/package.json +58 -56
- package/src/core/jmControl.js +1376 -1531
- package/src/core/jmEvents.js +240 -281
- package/src/core/jmGradient.js +231 -231
- package/src/core/jmGraph.js +569 -569
- package/src/core/jmList.js +92 -157
- package/src/core/jmObject.js +83 -103
- package/src/core/jmPath.js +35 -35
- package/src/core/jmProperty.js +71 -110
- package/src/core/jmShadow.js +65 -65
- package/src/core/jmUtils.js +906 -919
- package/src/lib/earcut.js +680 -680
- package/src/lib/earcut.md +73 -73
- package/src/lib/webgl/base.js +522 -452
- package/src/lib/webgl/core/buffer.js +48 -48
- package/src/lib/webgl/core/mapSize.js +40 -40
- package/src/lib/webgl/core/mapType.js +43 -43
- package/src/lib/webgl/core/program.js +138 -138
- package/src/lib/webgl/core/shader.js +13 -13
- package/src/lib/webgl/core/texture.js +60 -60
- package/src/lib/webgl/gradient.js +168 -168
- package/src/lib/webgl/index.js +137 -11
- package/src/lib/webgl/path.js +568 -561
- package/src/shapes/jmArrowLine.js +36 -36
- package/src/shapes/jmImage.js +244 -244
- package/src/shapes/jmLabel.js +271 -271
- package/src/shapes/jmResize.js +332 -330
package/src/lib/webgl/path.js
CHANGED
|
@@ -1,562 +1,569 @@
|
|
|
1
|
-
import WebglBase from './base.js';
|
|
2
|
-
|
|
3
|
-
// path 绘制类
|
|
4
|
-
class WebglPath extends WebglBase {
|
|
5
|
-
constructor(graph, option) {
|
|
6
|
-
super(graph, option);
|
|
7
|
-
// 是否是规则的,不规则的处理方式更为复杂和耗性能
|
|
8
|
-
this.isRegular = option.isRegular || false;
|
|
9
|
-
this.needCut = option.needCut || false;
|
|
10
|
-
this.control = option.control;
|
|
11
|
-
this.points = [];
|
|
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
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if(this.
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
start
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
start
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
polygon
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
this.
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
this.
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
this.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
1
|
+
import WebglBase from './base.js';
|
|
2
|
+
|
|
3
|
+
// path 绘制类
|
|
4
|
+
class WebglPath extends WebglBase {
|
|
5
|
+
constructor(graph, option) {
|
|
6
|
+
super(graph, option);
|
|
7
|
+
// 是否是规则的,不规则的处理方式更为复杂和耗性能
|
|
8
|
+
this.isRegular = option.isRegular || false;
|
|
9
|
+
this.needCut = option.needCut || false;
|
|
10
|
+
this.control = option.control;
|
|
11
|
+
this.points = [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 应用变换到点
|
|
15
|
+
applyTransform(point) {
|
|
16
|
+
return super.applyTransform(point);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setParentBounds(parentBounds = this.parentAbsoluteBounds) {
|
|
20
|
+
|
|
21
|
+
//this.useProgram();
|
|
22
|
+
|
|
23
|
+
if(parentBounds) this.parentAbsoluteBounds = parentBounds;
|
|
24
|
+
// 写入当前canvas大小
|
|
25
|
+
this.context.uniform2f(this.program.uniforms.a_center_point.location, this.graph.width / 2, this.graph.height / 2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setFragColor(color) {
|
|
29
|
+
|
|
30
|
+
if(!Array.isArray(color)) {
|
|
31
|
+
color = this.convertColor(color);
|
|
32
|
+
if(typeof color.a === 'undefined') color.a = 1;
|
|
33
|
+
this.context.uniform4f(this.program.uniforms.v_single_color.location, color.r, color.g, color.b, color.a * this.style.globalAlpha);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const colorData = [];
|
|
38
|
+
for(let c of color) {
|
|
39
|
+
c = this.convertColor(c);
|
|
40
|
+
if(typeof c.a === 'undefined') c.a = 1;
|
|
41
|
+
colorData.push(c.r, c.g, c.b, c.a * this.style.globalAlpha);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const colorBuffer = this.createFloat32Buffer(colorData);
|
|
45
|
+
this.writeVertexAttrib(colorBuffer, this.program.attrs.a_color, 4, 0, 0);
|
|
46
|
+
colorBuffer.attr = this.program.attrs.a_color;
|
|
47
|
+
return colorBuffer;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
beginDraw() {
|
|
51
|
+
this.useProgram();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 开始绘制
|
|
55
|
+
draw(points, parentBounds = this.parentAbsoluteBounds) {
|
|
56
|
+
//this.useProgram();
|
|
57
|
+
|
|
58
|
+
this.setParentBounds(parentBounds);
|
|
59
|
+
|
|
60
|
+
this.points = points;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
endDraw() {
|
|
64
|
+
if(this.points) delete this.points;
|
|
65
|
+
if(this.pathPoints) delete this.pathPoints;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 图形封闭
|
|
69
|
+
closePath() {
|
|
70
|
+
if(this.points && this.points.length > 2 && this.points[0] !== this.points[this.points.length-1]) {
|
|
71
|
+
const start = this.points[0];
|
|
72
|
+
const end = this.points[this.points.length-1];
|
|
73
|
+
if(start != end && !(start.x === end.x && start.y === end.y)) this.points.push(start);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 绘制点数组
|
|
78
|
+
writePoints(points, attr = this.program.attrs.a_position) {
|
|
79
|
+
|
|
80
|
+
const fixedPoints = [];
|
|
81
|
+
for(const p of points) {
|
|
82
|
+
// 应用变换矩阵
|
|
83
|
+
const transformedPoint = this.applyTransform(p);
|
|
84
|
+
fixedPoints.push(
|
|
85
|
+
transformedPoint.x + this.parentAbsoluteBounds.left,
|
|
86
|
+
transformedPoint.y + this.parentAbsoluteBounds.top
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const vertexBuffer = this.createFloat32Buffer(fixedPoints);
|
|
90
|
+
this.writeVertexAttrib(vertexBuffer, attr, 2, 0, 0);
|
|
91
|
+
vertexBuffer.attr = attr;
|
|
92
|
+
return vertexBuffer;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 连接二个点
|
|
96
|
+
genLinePoints(start, end) {
|
|
97
|
+
const points = [start];
|
|
98
|
+
const dx = end.x - start.x;
|
|
99
|
+
const dy = end.y - start.y;
|
|
100
|
+
if(dx !== 0 || dy !== 0) {
|
|
101
|
+
const len = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
|
|
102
|
+
const cos = dx / len;
|
|
103
|
+
const sin = dy / len;
|
|
104
|
+
const step = 0.5;
|
|
105
|
+
for(let l=step; l<len; l+=step) {
|
|
106
|
+
const x = start.x + cos * l;
|
|
107
|
+
const y = start.y + sin * l;
|
|
108
|
+
points.push({
|
|
109
|
+
x,
|
|
110
|
+
y
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
points.push(end);
|
|
115
|
+
return points;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 把path坐标集合分解成一个个点,并且处理moveTo线段能力
|
|
119
|
+
pathToPoints(points=this.points) {
|
|
120
|
+
let start = null;
|
|
121
|
+
const res = [];
|
|
122
|
+
for(let i=0; i<points.length; i++) {
|
|
123
|
+
const p = points[i];
|
|
124
|
+
if(start && !p.m) {
|
|
125
|
+
const linePoints = this.genLinePoints(start, p);
|
|
126
|
+
res.push(...linePoints);
|
|
127
|
+
}
|
|
128
|
+
else if(start && !res.includes(start)) {
|
|
129
|
+
res.push(start);
|
|
130
|
+
}
|
|
131
|
+
start = p;
|
|
132
|
+
}
|
|
133
|
+
if(!res.includes(start)) res.push(start);
|
|
134
|
+
return res;
|
|
135
|
+
}
|
|
136
|
+
// 二点是否重合
|
|
137
|
+
equalPoint(p1, p2) {
|
|
138
|
+
return p1.x === p2.x && p1.y === p2.y;
|
|
139
|
+
}
|
|
140
|
+
// 把path坐标集合转为线段集
|
|
141
|
+
pathToLines(points) {
|
|
142
|
+
let start = null;
|
|
143
|
+
const res = [];
|
|
144
|
+
for(let i=0; i<points.length; i++) {
|
|
145
|
+
const p = points[i];
|
|
146
|
+
// 不重合的二个点,组成线段
|
|
147
|
+
if(start && !p.m && !(start.x == p.x && start.y == p.y)) {
|
|
148
|
+
const line = {
|
|
149
|
+
start,
|
|
150
|
+
end: p,
|
|
151
|
+
};
|
|
152
|
+
res.push(line);
|
|
153
|
+
}
|
|
154
|
+
start = p;
|
|
155
|
+
}
|
|
156
|
+
return res;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 裁剪线段,如果二段线段有交点,则分割成四段, 端头相交的线段不用分割
|
|
160
|
+
cutLines(lines, index1=0, index2=0) {
|
|
161
|
+
if(lines && lines.length < 3) return lines;
|
|
162
|
+
|
|
163
|
+
index2 = Math.max(index1 + 1, index2); //如果指定了比下一个更大的索引,则用更大的,说明前面的已经处理过了,不需要重复
|
|
164
|
+
|
|
165
|
+
// 找出线段相交的点,并切割线段
|
|
166
|
+
while(index1 < lines.length) {
|
|
167
|
+
const line1 = lines[index1];
|
|
168
|
+
|
|
169
|
+
while(index2 < lines.length) {
|
|
170
|
+
const line2 = lines[index2];
|
|
171
|
+
// 如果二条线顶点有重合,则不用处理
|
|
172
|
+
if(this.equalPoint(line1.start, line2.start) || this.equalPoint(line1.end, line2.end) ||
|
|
173
|
+
this.equalPoint(line1.start, line2.end) || this.equalPoint(line1.end, line2.start)) {
|
|
174
|
+
index2++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
let cuted = false;
|
|
178
|
+
const intersection = this.getIntersection(line1, line2);// 计算交点
|
|
179
|
+
if(intersection) {
|
|
180
|
+
// 如果交点不是线段的端点,则分割成二条线段
|
|
181
|
+
if(!this.equalPoint(line1.start, intersection) && !this.equalPoint(line1.end, intersection)) {
|
|
182
|
+
const sub1 = {
|
|
183
|
+
start: line1.start,
|
|
184
|
+
end: intersection
|
|
185
|
+
};
|
|
186
|
+
const sub2 = {
|
|
187
|
+
start: intersection,
|
|
188
|
+
end: line1.end
|
|
189
|
+
};
|
|
190
|
+
// 从原数组中删除当前线段,替换成新的线段
|
|
191
|
+
lines.splice(index1, 1, sub1, sub2);
|
|
192
|
+
// 当前线段被重新替换,需要重新从它开始处理
|
|
193
|
+
cuted = true;
|
|
194
|
+
index2 ++;// 因为多加入了一个线段,则对比线索引需要加1
|
|
195
|
+
}
|
|
196
|
+
// 如果交点不是线段的端点,则分割成二条线段
|
|
197
|
+
if(!this.equalPoint(line2.start, intersection) && !this.equalPoint(line2.end, intersection)) {
|
|
198
|
+
const sub1 = {
|
|
199
|
+
start: line2.start,
|
|
200
|
+
end: intersection
|
|
201
|
+
};
|
|
202
|
+
const sub2 = {
|
|
203
|
+
start: intersection,
|
|
204
|
+
end: line2.end
|
|
205
|
+
};
|
|
206
|
+
// 从原数组中删除当前线段,替换成新的线段
|
|
207
|
+
lines.splice(index2, 1, sub1, sub2);
|
|
208
|
+
index2 ++; // 线段2也切成了二段,对比索引要继续加1
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
index2++;
|
|
212
|
+
// 如果已经分割了起始线段,则第一个子线段开始,重新对比后面还未对比完的。直接所有对比完成返回
|
|
213
|
+
if(cuted) return this.cutLines(lines, index1, index2);
|
|
214
|
+
}
|
|
215
|
+
index1++;
|
|
216
|
+
index2 = index1 + 1;
|
|
217
|
+
}
|
|
218
|
+
return lines;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 计算二个线段的交点
|
|
222
|
+
getIntersection(line1, line2) {
|
|
223
|
+
// 如果首尾相接,也认为是有交点
|
|
224
|
+
if(this.equalPoint(line1.start, line2.start) || this.equalPoint(line1.start, line2.end)) return line1.start;
|
|
225
|
+
if(this.equalPoint(line1.end, line2.start) || this.equalPoint(line1.end, line2.end)) return line1.end;
|
|
226
|
+
|
|
227
|
+
// 三角形abc 面积的2倍
|
|
228
|
+
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);
|
|
229
|
+
|
|
230
|
+
// 三角形abd 面积的2倍
|
|
231
|
+
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);
|
|
232
|
+
|
|
233
|
+
// 面积符号相同则两点在线段同侧,不相交 (=0表示在线段顶点上);
|
|
234
|
+
if (area_abc * area_abd > 0) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 三角形cda 面积的2倍
|
|
239
|
+
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);
|
|
240
|
+
// 三角形cdb 面积的2倍
|
|
241
|
+
// 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
|
|
242
|
+
const area_cdb = area_cda + area_abc - area_abd ;
|
|
243
|
+
if(area_cda * area_cdb > 0) {
|
|
244
|
+
return null ;
|
|
245
|
+
}
|
|
246
|
+
if(area_abd === area_abc) return null;
|
|
247
|
+
|
|
248
|
+
//计算交点坐标
|
|
249
|
+
const t = area_cda / (area_abd - area_abc);
|
|
250
|
+
const dx= t * (line1.end.x - line1.start.x);
|
|
251
|
+
const dy= t * (line1.end.y - line1.start.y);
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
x: line1.start.x + dx,
|
|
255
|
+
y: line1.start.y + dy
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 找出跟当前线段尾部相交的所有线段
|
|
260
|
+
getIntersectionLines(line, lines, index, point=line.end, points=[], root=null) {
|
|
261
|
+
const res = {
|
|
262
|
+
line,
|
|
263
|
+
polygons: []
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
points.push(point);
|
|
267
|
+
|
|
268
|
+
if(root && this.equalPoint(root.line.start, point)) {
|
|
269
|
+
points.unshift(root.line.start); // 把起始地址加入进去
|
|
270
|
+
root.polygons.push(points);
|
|
271
|
+
return res;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for(;index<lines.length; index++) {
|
|
275
|
+
const l = lines[index];
|
|
276
|
+
if(this.equalPoint(point, l.start)) {
|
|
277
|
+
if(points.includes(l.end)) continue;
|
|
278
|
+
this.getIntersectionLines(l, lines, index+1, l.end, [...points], root||res);
|
|
279
|
+
}
|
|
280
|
+
else if(this.equalPoint(point, l.end)) {
|
|
281
|
+
if(points.includes(l.start)) continue;
|
|
282
|
+
this.getIntersectionLines(l, lines, index+1, l.start, [...points], root||res);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return res;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 根据路径点坐标,切割出封闭的多边形
|
|
289
|
+
getPolygon(points) {
|
|
290
|
+
let polygons = [];
|
|
291
|
+
let lines = this.pathToLines(points); // 分解得到线段
|
|
292
|
+
if(lines && lines.length > 2) {
|
|
293
|
+
lines = this.cutLines(lines); // 把所有相交点切割线段找出来
|
|
294
|
+
for(let i=0; i<lines.length-1; i++) {
|
|
295
|
+
const line1 = lines[i];
|
|
296
|
+
let polygon = [];// 当前图形
|
|
297
|
+
|
|
298
|
+
const treeLine = this.getIntersectionLines(line1, lines, i+1);
|
|
299
|
+
|
|
300
|
+
if(treeLine.polygons.length) polygons.push(...treeLine.polygons);
|
|
301
|
+
continue;
|
|
302
|
+
let lastLine = line1; // 下一个还在连接状态的线
|
|
303
|
+
for(let j=i+1; j<lines.length; j++) {
|
|
304
|
+
const line2 = lines[j];
|
|
305
|
+
// 如果跟下一条线相接,则表示还在形成图形中
|
|
306
|
+
if(this.equalPoint(lastLine.end, line2.start)) {
|
|
307
|
+
polygon.push(lastLine.end);
|
|
308
|
+
lastLine = line2;
|
|
309
|
+
if(i === j+1) continue; //下一条相连 则不需要处理相交情况
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
polygon = [];
|
|
313
|
+
}
|
|
314
|
+
// 因为前面进行了分割线段,则里只有处理端点相连的情况
|
|
315
|
+
const intersection = this.equalPoint(line1.start, line2.end)? line1.start: null;//this.getIntersection(line1, line2);// 计算交点
|
|
316
|
+
if(intersection) {
|
|
317
|
+
polygon.push(intersection);// 交叉点为图形顶点
|
|
318
|
+
// 如果上一个连接线不是当前交叉线,则表示重新开始闭合
|
|
319
|
+
// 如果上一个连接线是当前交叉线,形成了封闭的图形
|
|
320
|
+
if(lastLine === line2 && polygon.length > 1) {
|
|
321
|
+
polygons.push(polygon);
|
|
322
|
+
|
|
323
|
+
// 封闭后,下一个起始线条就是从交点开始计算起
|
|
324
|
+
/*lastLine = {
|
|
325
|
+
start: intersection,
|
|
326
|
+
end: line2.end
|
|
327
|
+
};*/
|
|
328
|
+
polygon = [];// 重新开始新一轮找图形
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
// 如果交点是上一条线的终点,则新图形为空
|
|
332
|
+
if(this.equalPoint(line2.end, intersection)) {
|
|
333
|
+
polygon = [];// 重新开始新一轮找图形
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// 同时交点也要加到上一个图形中第一个点,形成封闭
|
|
337
|
+
polygon.unshift(intersection);
|
|
338
|
+
|
|
339
|
+
polygon = [ intersection ];// 重新开始新一轮找图形
|
|
340
|
+
}*/
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
lastLine = line2;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// 当有多个封闭图形时,再弟归一下,里面是不是有封闭图形内还有子封闭图形
|
|
351
|
+
/*if(polygons.length > 1) {
|
|
352
|
+
const newPolygons = [];
|
|
353
|
+
for(const polygon of polygons) {
|
|
354
|
+
// 只有大于4才有可能有子封闭图形
|
|
355
|
+
if(polygon.length > 4) {
|
|
356
|
+
const childPolygons = this.getPolygon(polygon);
|
|
357
|
+
// 当有多个子图形时,表示它不是最终封闭图形,跳过,
|
|
358
|
+
// 因为它的子图形之前有加入的,不需要重复加入
|
|
359
|
+
if(childPolygons.length > 1) {
|
|
360
|
+
//newPolygons.push(...childPolygons);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
newPolygons.push(polygon);
|
|
365
|
+
}
|
|
366
|
+
polygons = newPolygons;
|
|
367
|
+
}*/
|
|
368
|
+
return polygons;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// 分割成一个个规则的三角形,不规则的多边形不全割的话纹理就会没法正确覆盖
|
|
372
|
+
getTriangles(points) {
|
|
373
|
+
|
|
374
|
+
//this.trianglesCache = this.trianglesCache||(this.trianglesCache={});
|
|
375
|
+
//const key = JSON.stringify(points);
|
|
376
|
+
//if(this.trianglesCache[key]) return this.trianglesCache[key];
|
|
377
|
+
|
|
378
|
+
const res = [];
|
|
379
|
+
const polygons = this.getPolygon(points);
|
|
380
|
+
if(polygons.length) {
|
|
381
|
+
for(const polygon of polygons) {
|
|
382
|
+
// 需要分割三角形,不然填充会有问题
|
|
383
|
+
const triangles = this.earCutPointsToTriangles(polygon);
|
|
384
|
+
res.push(...triangles);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
//this.trianglesCache[key] = res;
|
|
388
|
+
return res;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// 画线条
|
|
392
|
+
stroke(points = this.points, color = this.style.strokeStyle, lineWidth = this.style.lineWidth) {
|
|
393
|
+
if(!points || !points.length) return;
|
|
394
|
+
// this.useProgram();
|
|
395
|
+
|
|
396
|
+
let colorBuffer = null;
|
|
397
|
+
if(color) {
|
|
398
|
+
colorBuffer = this.setFragColor(color);
|
|
399
|
+
}
|
|
400
|
+
// 线宽
|
|
401
|
+
if(lineWidth) {
|
|
402
|
+
this.context.uniform1f(this.program.uniforms.a_point_size.location, lineWidth);// * this.graph.devicePixelRatio
|
|
403
|
+
}
|
|
404
|
+
// 标注为stroke
|
|
405
|
+
if(this.program.uniforms.a_type) {
|
|
406
|
+
// 4表示单画一个圆点,1表示方块形成的线条
|
|
407
|
+
this.context.uniform1i(this.program.uniforms.a_type.location, points.length === 1? 4 :1);
|
|
408
|
+
}
|
|
409
|
+
if(points && points.length) {
|
|
410
|
+
const regular = lineWidth <= 1.2;
|
|
411
|
+
points = regular? points : this.pathToPoints(points);
|
|
412
|
+
const buffer = this.writePoints(points);
|
|
413
|
+
this.context.drawArrays(regular? this.context.LINE_LOOP: this.context.POINTS, 0, points.length);
|
|
414
|
+
this.deleteBuffer(buffer);
|
|
415
|
+
}
|
|
416
|
+
colorBuffer && this.deleteBuffer(colorBuffer);
|
|
417
|
+
colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 填充图形
|
|
421
|
+
fill(bounds = {left: 0, top: 0, width: 0, height: 0}, type = 1) {
|
|
422
|
+
|
|
423
|
+
if(this.points && this.points.length) {
|
|
424
|
+
// 如果是颜色rgba
|
|
425
|
+
if(this.style.fillStyle) {
|
|
426
|
+
this.fillColor(this.style.fillStyle, this.points, bounds, type);
|
|
427
|
+
}
|
|
428
|
+
if(this.style.fillImage) {
|
|
429
|
+
this.fillImage(this.style.fillImage, this.points, bounds, type);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
fillColor(color, points, bounds, type=1) {
|
|
435
|
+
|
|
436
|
+
// 如果是渐变色,则需要计算偏移量的颜色
|
|
437
|
+
if(this.isGradient(color)) {
|
|
438
|
+
const imgData = color.toImageData(this, bounds, points);
|
|
439
|
+
return this.fillImage(imgData.data, imgData.points, bounds);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// 标注为fill
|
|
443
|
+
this.context.uniform1i(this.program.uniforms.a_type.location, type);
|
|
444
|
+
const colorBuffer = this.setFragColor(color);
|
|
445
|
+
|
|
446
|
+
this.fillPolygons(points);
|
|
447
|
+
|
|
448
|
+
colorBuffer && this.deleteBuffer(colorBuffer);
|
|
449
|
+
colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// 区域填充图片
|
|
454
|
+
// points绘制的图形顶点
|
|
455
|
+
// 图片整体绘制区域
|
|
456
|
+
fillImage(img, points, bounds) {
|
|
457
|
+
if(!img) return;
|
|
458
|
+
|
|
459
|
+
// 设置纹理
|
|
460
|
+
const texture = img instanceof ImageData? this.createDataTexture(img) : this.createImgTexture(img);
|
|
461
|
+
this.context.uniform1i(this.program.uniforms.u_sample.location, 0); // 纹理单元传递给着色器
|
|
462
|
+
|
|
463
|
+
// 指定纹理区域尺寸
|
|
464
|
+
this.context.uniform4f(this.program.uniforms.v_texture_bounds.location,
|
|
465
|
+
bounds.left + this.parentAbsoluteBounds.left,
|
|
466
|
+
bounds.top + this.parentAbsoluteBounds.top,
|
|
467
|
+
bounds.width,
|
|
468
|
+
bounds.height,
|
|
469
|
+
); // 纹理单元传递给着色器
|
|
470
|
+
|
|
471
|
+
this.fillTexture(points);
|
|
472
|
+
|
|
473
|
+
this.deleteTexture(texture);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
fillTexture(points) {
|
|
477
|
+
if(points && points.length) { // 标注为纹理对象
|
|
478
|
+
this.context.uniform1i(this.program.uniforms.a_type.location, 2);
|
|
479
|
+
// 纹理坐标
|
|
480
|
+
//const coordBuffer = this.writePoints(points, this.program.attrs.a_text_coord);
|
|
481
|
+
this.fillPolygons(points, true);
|
|
482
|
+
//this.deleteBuffer(coordBuffer);
|
|
483
|
+
this.disableVertexAttribArray(this.program.attrs.a_text_coord);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// 进行多边形填充
|
|
488
|
+
fillPolygons(points, isTexture = false) {
|
|
489
|
+
//const indexBuffer = this.createUint16Buffer(triangles, this.context.ELEMENT_ARRAY_BUFFER);
|
|
490
|
+
//this.context.drawElements(this.context.TRIANGLES, triangles.length, this.context.UNSIGMED_SHORT, 0);
|
|
491
|
+
//this.deleteBuffer(indexBuffer);
|
|
492
|
+
/*if(points.length > 3 && (!regular || this.needCut)) {
|
|
493
|
+
const triangles = regular && this.needCut? this.earCutPointsToTriangles(points): this.getTriangles(points);
|
|
494
|
+
if(triangles.length) {
|
|
495
|
+
for(const triangle of triangles) {
|
|
496
|
+
this.fillPolygons(triangle, isTexture);// 这里就变成了规则的图形了
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else {*/
|
|
501
|
+
const buffer = this.writePoints(points);
|
|
502
|
+
// 纹理坐标
|
|
503
|
+
const coordBuffer = isTexture? this.writePoints(points, this.program.attrs.a_text_coord): null;
|
|
504
|
+
|
|
505
|
+
this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
|
|
506
|
+
this.deleteBuffer(buffer);
|
|
507
|
+
coordBuffer && this.deleteBuffer(coordBuffer);
|
|
508
|
+
//}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// 填充图形
|
|
512
|
+
drawImage(img, left=0, top=0, width=img.width, height=img.height) {
|
|
513
|
+
width = width || img.width;
|
|
514
|
+
height = height || img.height;
|
|
515
|
+
|
|
516
|
+
this.fillImage(img, this.points, {
|
|
517
|
+
left,
|
|
518
|
+
top,
|
|
519
|
+
width,
|
|
520
|
+
height
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
drawText(text, x, y, bounds) {
|
|
525
|
+
let canvas = this.textureCanvas;
|
|
526
|
+
if(!canvas) {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
canvas.width = bounds.width;
|
|
530
|
+
canvas.height = bounds.height;
|
|
531
|
+
|
|
532
|
+
if(!canvas.width || !canvas.height) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
this.textureContext.clearRect(0, 0, canvas.width, canvas.height);
|
|
537
|
+
// 修改字体
|
|
538
|
+
this.textureContext.font = this.style.font || (this.style.fontSize + 'px ' + this.style.fontFamily);
|
|
539
|
+
|
|
540
|
+
x -= bounds.left;
|
|
541
|
+
y -= bounds.top;
|
|
542
|
+
|
|
543
|
+
this.setTextureStyle(this.style);
|
|
544
|
+
|
|
545
|
+
if(this.style.fillStyle && this.textureContext.fillText) {
|
|
546
|
+
|
|
547
|
+
if(this.style.maxWidth) {
|
|
548
|
+
this.textureContext.fillText(text, x, y, this.style.maxWidth);
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
this.textureContext.fillText(text, x, y);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if(this.textureContext.strokeText) {
|
|
555
|
+
|
|
556
|
+
if(this.style.maxWidth) {
|
|
557
|
+
this.textureContext.strokeText(text, x, y, this.style.maxWidth);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
this.textureContext.strokeText(text, x, y);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
// 用纹理图片代替文字
|
|
564
|
+
const data = this.textureContext.getImageData(0, 0, canvas.width, canvas.height);
|
|
565
|
+
this.fillImage(data, this.points, bounds);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
562
569
|
export default WebglPath;
|