jmgraph 3.2.20 → 3.2.21
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/README.md +137 -4
- package/dist/jmgraph.core.min.js +1 -1
- package/dist/jmgraph.core.min.js.map +1 -1
- package/dist/jmgraph.js +976 -827
- package/dist/jmgraph.min.js +1 -1
- package/index.js +13 -26
- package/package.json +1 -1
- package/src/core/jmControl.js +199 -30
- package/src/core/jmFilter.js +150 -0
- package/src/core/jmGraph.js +16 -265
- package/src/core/jmUtils.js +46 -37
- package/src/lib/webgl/base.js +10 -36
- package/src/lib/webgl/gradient.js +16 -3
- package/src/lib/webgl/index.js +5 -4
- package/src/lib/webgl/path.js +156 -33
- package/src/shapes/jmLabel.js +1 -62
- package/src/shapes/jmRect.js +107 -29
package/src/lib/webgl/path.js
CHANGED
|
@@ -9,6 +9,40 @@ class WebglPath extends WebglBase {
|
|
|
9
9
|
this.needCut = option.needCut || false;
|
|
10
10
|
this.control = option.control;
|
|
11
11
|
this.points = [];
|
|
12
|
+
// 缓存 buffer 和纹理,避免每帧创建/销毁
|
|
13
|
+
this.__cachedBuffers = [];
|
|
14
|
+
this.__cachedTexture = null;
|
|
15
|
+
this.__cachedTextureKey = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 释放缓存的 WebGL 资源
|
|
19
|
+
dispose() {
|
|
20
|
+
for(const buf of this.__cachedBuffers) {
|
|
21
|
+
this.deleteBuffer(buf);
|
|
22
|
+
}
|
|
23
|
+
this.__cachedBuffers = [];
|
|
24
|
+
if(this.__cachedTexture) {
|
|
25
|
+
this.deleteTexture(this.__cachedTexture);
|
|
26
|
+
this.__cachedTexture = null;
|
|
27
|
+
this.__cachedTextureKey = null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 获取或创建 buffer,优先复用缓存
|
|
32
|
+
getOrCreateBuffer(data, attr) {
|
|
33
|
+
let buffer = this.__cachedBuffers.find(b => b.attr === attr);
|
|
34
|
+
if(buffer) {
|
|
35
|
+
const gl = this.context;
|
|
36
|
+
const float32 = new Float32Array(data);
|
|
37
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
|
|
38
|
+
gl.bufferData(gl.ARRAY_BUFFER, float32, gl.DYNAMIC_DRAW);
|
|
39
|
+
buffer.data = data;
|
|
40
|
+
return buffer;
|
|
41
|
+
}
|
|
42
|
+
buffer = this.createFloat32Buffer(data);
|
|
43
|
+
buffer.attr = attr;
|
|
44
|
+
this.__cachedBuffers.push(buffer);
|
|
45
|
+
return buffer;
|
|
12
46
|
}
|
|
13
47
|
|
|
14
48
|
// 应用变换到点
|
|
@@ -63,6 +97,7 @@ class WebglPath extends WebglBase {
|
|
|
63
97
|
endDraw() {
|
|
64
98
|
if(this.points) delete this.points;
|
|
65
99
|
if(this.pathPoints) delete this.pathPoints;
|
|
100
|
+
// 缓存的纹理保留到下次绘制(渐变可能不变)
|
|
66
101
|
}
|
|
67
102
|
|
|
68
103
|
// 图形封闭
|
|
@@ -74,21 +109,47 @@ class WebglPath extends WebglBase {
|
|
|
74
109
|
}
|
|
75
110
|
}
|
|
76
111
|
|
|
77
|
-
//
|
|
112
|
+
// 绘制点数组(使用 DYNAMIC_DRAW 复用 buffer,避免每帧 create/delete)
|
|
78
113
|
writePoints(points, attr = this.program.attrs.a_position) {
|
|
79
|
-
|
|
80
114
|
const fixedPoints = [];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
const [a, b, c, d, tx, ty] = this.transformMatrix;
|
|
116
|
+
const isIdentity = (a === 1 && b === 0 && c === 0 && d === 1 && tx === 0 && ty === 0);
|
|
117
|
+
const offsetLeft = this.parentAbsoluteBounds.left;
|
|
118
|
+
const offsetTop = this.parentAbsoluteBounds.top;
|
|
119
|
+
|
|
120
|
+
if(isIdentity) {
|
|
121
|
+
// 单位矩阵时直接加偏移,避免逐点调用 applyTransform
|
|
122
|
+
for(let i = 0; i < points.length; i++) {
|
|
123
|
+
fixedPoints.push(points[i].x + offsetLeft, points[i].y + offsetTop);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
for(const p of points) {
|
|
127
|
+
const transformedPoint = this.applyTransform(p);
|
|
128
|
+
fixedPoints.push(
|
|
129
|
+
transformedPoint.x + offsetLeft,
|
|
130
|
+
transformedPoint.y + offsetTop
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const float32 = new Float32Array(fixedPoints);
|
|
135
|
+
const gl = this.context;
|
|
136
|
+
|
|
137
|
+
// 复用已有 buffer 或创建新的
|
|
138
|
+
if(this.__cachedBuffers.length > 0) {
|
|
139
|
+
// 找一个同 attr 的 buffer 复用
|
|
140
|
+
let buffer = this.__cachedBuffers.find(b => b.attr === attr);
|
|
141
|
+
if(buffer) {
|
|
142
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
|
|
143
|
+
gl.bufferData(gl.ARRAY_BUFFER, float32, gl.DYNAMIC_DRAW);
|
|
144
|
+
buffer.data = fixedPoints;
|
|
145
|
+
this.writeVertexAttrib(buffer, attr, 2, 0, 0);
|
|
146
|
+
return buffer;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const vertexBuffer = this.createFloat32Buffer(float32, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
|
|
90
150
|
this.writeVertexAttrib(vertexBuffer, attr, 2, 0, 0);
|
|
91
151
|
vertexBuffer.attr = attr;
|
|
152
|
+
this.__cachedBuffers.push(vertexBuffer);
|
|
92
153
|
return vertexBuffer;
|
|
93
154
|
}
|
|
94
155
|
|
|
@@ -370,9 +431,10 @@ class WebglPath extends WebglBase {
|
|
|
370
431
|
|
|
371
432
|
// 分割成一个个规则的三角形,不规则的多边形不全割的话纹理就会没法正确覆盖
|
|
372
433
|
getTriangles(points) {
|
|
373
|
-
|
|
374
434
|
this.trianglesCache = this.trianglesCache||(this.trianglesCache={});
|
|
375
|
-
|
|
435
|
+
// 快速缓存 key:用长度和首尾点坐标(比 JSON.stringify 快几个数量级)
|
|
436
|
+
const len = points.length;
|
|
437
|
+
const key = len + '_' + points[0].x + '_' + points[0].y + '_' + points[len-1].x + '_' + points[len-1].y;
|
|
376
438
|
if(this.trianglesCache[key]) return this.trianglesCache[key];
|
|
377
439
|
|
|
378
440
|
const res = [];
|
|
@@ -411,10 +473,9 @@ class WebglPath extends WebglBase {
|
|
|
411
473
|
points = regular? points : this.pathToPoints(points);
|
|
412
474
|
const buffer = this.writePoints(points);
|
|
413
475
|
this.context.drawArrays(regular? this.context.LINE_LOOP: this.context.POINTS, 0, points.length);
|
|
414
|
-
|
|
476
|
+
// buffer 由 endDraw 统一清理
|
|
415
477
|
}
|
|
416
|
-
colorBuffer && this.
|
|
417
|
-
colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
|
|
478
|
+
colorBuffer && this.disableVertexAttribArray(colorBuffer && colorBuffer.attr);
|
|
418
479
|
}
|
|
419
480
|
|
|
420
481
|
// 填充图形
|
|
@@ -445,8 +506,7 @@ class WebglPath extends WebglBase {
|
|
|
445
506
|
|
|
446
507
|
this.fillPolygons(points);
|
|
447
508
|
|
|
448
|
-
colorBuffer && this.
|
|
449
|
-
colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
|
|
509
|
+
colorBuffer && this.disableVertexAttribArray(colorBuffer && colorBuffer.attr);
|
|
450
510
|
|
|
451
511
|
}
|
|
452
512
|
|
|
@@ -456,8 +516,24 @@ class WebglPath extends WebglBase {
|
|
|
456
516
|
fillImage(img, points, bounds) {
|
|
457
517
|
if(!img) return;
|
|
458
518
|
|
|
459
|
-
//
|
|
460
|
-
|
|
519
|
+
// 对于 ImageData,生成缓存 key(基于渐变参数或 bounds),复用纹理
|
|
520
|
+
let texture = null;
|
|
521
|
+
if(img instanceof ImageData) {
|
|
522
|
+
const key = `${img.width}_${img.height}_${bounds.width}_${bounds.height}_${bounds.left}_${bounds.top}`;
|
|
523
|
+
if(this.__cachedTexture && this.__cachedTextureKey === key) {
|
|
524
|
+
texture = this.__cachedTexture;
|
|
525
|
+
} else {
|
|
526
|
+
texture = this.createDataTexture(img);
|
|
527
|
+
// 释放旧纹理
|
|
528
|
+
if(this.__cachedTexture) {
|
|
529
|
+
this.deleteTexture(this.__cachedTexture);
|
|
530
|
+
}
|
|
531
|
+
this.__cachedTexture = texture;
|
|
532
|
+
this.__cachedTextureKey = key;
|
|
533
|
+
}
|
|
534
|
+
} else {
|
|
535
|
+
texture = this.createImgTexture(img);
|
|
536
|
+
}
|
|
461
537
|
this.context.uniform1i(this.program.uniforms.u_sample.location, 0); // 纹理单元传递给着色器
|
|
462
538
|
|
|
463
539
|
// 指定纹理区域尺寸
|
|
@@ -470,7 +546,10 @@ class WebglPath extends WebglBase {
|
|
|
470
546
|
|
|
471
547
|
this.fillTexture(points);
|
|
472
548
|
|
|
473
|
-
|
|
549
|
+
// 仅对非缓存纹理(非 ImageData)立即删除
|
|
550
|
+
if(!(img instanceof ImageData)) {
|
|
551
|
+
this.deleteTexture(texture);
|
|
552
|
+
}
|
|
474
553
|
}
|
|
475
554
|
|
|
476
555
|
fillTexture(points) {
|
|
@@ -486,23 +565,67 @@ class WebglPath extends WebglBase {
|
|
|
486
565
|
|
|
487
566
|
// 进行多边形填充
|
|
488
567
|
fillPolygons(points, isTexture = false) {
|
|
489
|
-
if(points.length
|
|
490
|
-
|
|
491
|
-
if(triangles.length) {
|
|
492
|
-
for(const triangle of triangles) {
|
|
493
|
-
this.fillPolygons(triangle, isTexture);// 这里就变成了规则的图形了
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
568
|
+
if(points.length <= 3) {
|
|
569
|
+
// 3个点以下的三角形直接画
|
|
498
570
|
const buffer = this.writePoints(points);
|
|
499
|
-
// 纹理坐标
|
|
500
571
|
const coordBuffer = isTexture? this.writePoints(points, this.program.attrs.a_text_coord): null;
|
|
572
|
+
this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
501
575
|
|
|
576
|
+
// 规则图形(凸多边形,如圆):直接用 TRIANGLE_FAN 一次性绘制,无需 earcut
|
|
577
|
+
if(this.isRegular) {
|
|
578
|
+
const buffer = this.writePoints(points);
|
|
579
|
+
const coordBuffer = isTexture? this.writePoints(points, this.program.attrs.a_text_coord): null;
|
|
502
580
|
this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
|
|
503
|
-
|
|
504
|
-
coordBuffer && this.deleteBuffer(coordBuffer);
|
|
581
|
+
return;
|
|
505
582
|
}
|
|
583
|
+
|
|
584
|
+
// 不规则图形:需要 earcut 三角化后,合并为一个大的顶点缓冲区,单次 drawArrays
|
|
585
|
+
const triangles = this.needCut? this.earCutPointsToTriangles(points): this.getTriangles(points);
|
|
586
|
+
if(!triangles.length) return;
|
|
587
|
+
|
|
588
|
+
// 合并所有三角形的顶点到一个数组
|
|
589
|
+
const allVertices = [];
|
|
590
|
+
const allTexCoords = [];
|
|
591
|
+
for(const triangle of triangles) {
|
|
592
|
+
for(const p of triangle) {
|
|
593
|
+
allVertices.push(p.x, p.y);
|
|
594
|
+
if(isTexture) allTexCoords.push(p.x, p.y);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 一次性上传所有数据并绘制
|
|
599
|
+
const vertexData = new Float32Array(allVertices);
|
|
600
|
+
const gl = this.context;
|
|
601
|
+
|
|
602
|
+
// 复用或创建 position buffer
|
|
603
|
+
let posBuffer = this.__cachedBuffers.find(b => b.attr === this.program.attrs.a_position);
|
|
604
|
+
if(!posBuffer) {
|
|
605
|
+
posBuffer = this.createFloat32Buffer(vertexData, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
|
|
606
|
+
posBuffer.attr = this.program.attrs.a_position;
|
|
607
|
+
this.__cachedBuffers.push(posBuffer);
|
|
608
|
+
} else {
|
|
609
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer.buffer);
|
|
610
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.DYNAMIC_DRAW);
|
|
611
|
+
}
|
|
612
|
+
this.writeVertexAttrib(posBuffer, this.program.attrs.a_position, 2, 0, 0);
|
|
613
|
+
|
|
614
|
+
if(isTexture && allTexCoords.length) {
|
|
615
|
+
const texData = new Float32Array(allTexCoords);
|
|
616
|
+
let texBuffer = this.__cachedBuffers.find(b => b.attr === this.program.attrs.a_text_coord);
|
|
617
|
+
if(!texBuffer) {
|
|
618
|
+
texBuffer = this.createFloat32Buffer(texData, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
|
|
619
|
+
texBuffer.attr = this.program.attrs.a_text_coord;
|
|
620
|
+
this.__cachedBuffers.push(texBuffer);
|
|
621
|
+
} else {
|
|
622
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texBuffer.buffer);
|
|
623
|
+
gl.bufferData(gl.ARRAY_BUFFER, texData, gl.DYNAMIC_DRAW);
|
|
624
|
+
}
|
|
625
|
+
this.writeVertexAttrib(texBuffer, this.program.attrs.a_text_coord, 2, 0, 0);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
gl.drawArrays(gl.TRIANGLES, 0, allVertices.length / 2);
|
|
506
629
|
}
|
|
507
630
|
|
|
508
631
|
// 填充图形
|
package/src/shapes/jmLabel.js
CHANGED
|
@@ -22,7 +22,7 @@ export default class jmLabel extends jmControl {
|
|
|
22
22
|
this.style.textAlign = this.style.textAlign || 'left';
|
|
23
23
|
//文字垂直对齐
|
|
24
24
|
this.style.textBaseline = this.style.textBaseline || 'middle';
|
|
25
|
-
this.text = params.text || '';
|
|
25
|
+
this.text = params.text || params.value || '';
|
|
26
26
|
|
|
27
27
|
this.center = params.center || null;
|
|
28
28
|
}
|
|
@@ -311,67 +311,6 @@ export default class jmLabel extends jmControl {
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
|
-
//如果有指定边框,则画出边框
|
|
315
|
-
if(this.style.border) {
|
|
316
|
-
//如果指定了边框样式
|
|
317
|
-
if(this.style.border.style) {
|
|
318
|
-
this.context.save && this.context.save();
|
|
319
|
-
this.setStyle(this.style.border.style);
|
|
320
|
-
}
|
|
321
|
-
if(this.mode === '2d') {
|
|
322
|
-
this.context.moveTo(this.points[0].x + bounds.left,this.points[0].y + bounds.top);
|
|
323
|
-
if(this.style.border.top) {
|
|
324
|
-
this.context.lineTo(this.points[1].x + bounds.left,this.points[1].y + bounds.top);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if(this.style.border.right) {
|
|
328
|
-
this.context.moveTo(this.points[1].x + bounds.left,this.points[1].y + bounds.top);
|
|
329
|
-
this.context.lineTo(this.points[2].x + bounds.left,this.points[2].y + bounds.top);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if(this.style.border.bottom) {
|
|
333
|
-
this.context.moveTo(this.points[2].x + bounds.left,this.points[2].y + bounds.top);
|
|
334
|
-
this.context.lineTo(this.points[3].x + bounds.left,this.points[3].y + bounds.top);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if(this.style.border.left) {
|
|
338
|
-
this.context.moveTo(this.points[3].x + bounds.left,this.points[3].y + bounds.top);
|
|
339
|
-
this.context.lineTo(this.points[0].x + bounds.left,this.points[0].y + bounds.top);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
const points = [];
|
|
344
|
-
if(this.style.border.top) {
|
|
345
|
-
points.push(this.points[0]);
|
|
346
|
-
points.push(this.points[1]);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if(this.style.border.right) {
|
|
350
|
-
points.push({
|
|
351
|
-
...this.points[1],
|
|
352
|
-
m: true
|
|
353
|
-
});
|
|
354
|
-
points.push(this.points[2]);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if(this.style.border.bottom) {
|
|
358
|
-
points.push({
|
|
359
|
-
...this.points[2],
|
|
360
|
-
m: true
|
|
361
|
-
});
|
|
362
|
-
points.push(this.points[3]);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if(this.style.border.left) {
|
|
366
|
-
points.push({
|
|
367
|
-
...this.points[3],
|
|
368
|
-
m: true
|
|
369
|
-
});
|
|
370
|
-
points.push(this.points[0]);
|
|
371
|
-
}
|
|
372
|
-
points.length && this.webglControl && this.webglControl.stroke(points);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
314
|
}
|
|
376
315
|
|
|
377
316
|
endDraw() {
|
package/src/shapes/jmRect.js
CHANGED
|
@@ -8,6 +8,7 @@ import {jmLine} from './jmLine.js';
|
|
|
8
8
|
* @class jmRect
|
|
9
9
|
* @extends jmPath
|
|
10
10
|
* @param {object} params 参数 position=矩形左上角顶点坐标,width=宽,height=高,radius=边角弧度
|
|
11
|
+
* radius支持数字(四角相同)或对象 { topLeft, topRight, bottomRight, bottomLeft }
|
|
11
12
|
*/
|
|
12
13
|
export default class jmRect extends jmPath {
|
|
13
14
|
|
|
@@ -17,12 +18,24 @@ export default class jmRect extends jmPath {
|
|
|
17
18
|
super(params, t);
|
|
18
19
|
|
|
19
20
|
this.style.close = true;
|
|
20
|
-
|
|
21
|
+
const r = params.radius || this.style.radius || this.style.borderRadius || 0;
|
|
22
|
+
if(typeof r === 'object' && r !== null) {
|
|
23
|
+
// 四角独立圆角
|
|
24
|
+
this.radius = {
|
|
25
|
+
topLeft: Number(r.topLeft) || 0,
|
|
26
|
+
topRight: Number(r.topRight) || 0,
|
|
27
|
+
bottomRight: Number(r.bottomRight) || 0,
|
|
28
|
+
bottomLeft: Number(r.bottomLeft) || 0
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.radius = r;
|
|
33
|
+
}
|
|
21
34
|
}
|
|
22
35
|
/**
|
|
23
|
-
*
|
|
36
|
+
* 圆角半径,支持数字或四角独立对象
|
|
24
37
|
* @property radius
|
|
25
|
-
* @type {number}
|
|
38
|
+
* @type {number|object}
|
|
26
39
|
*/
|
|
27
40
|
get radius() {
|
|
28
41
|
return this.property('radius');
|
|
@@ -30,6 +43,36 @@ export default class jmRect extends jmPath {
|
|
|
30
43
|
set radius(v) {
|
|
31
44
|
this.needUpdate = true;
|
|
32
45
|
return this.property('radius', v);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 获取规范化的圆角值(四角独立)
|
|
50
|
+
* @returns {object} { topLeft, topRight, bottomRight, bottomLeft }
|
|
51
|
+
*/
|
|
52
|
+
getNormalizedRadius() {
|
|
53
|
+
const r = this.radius;
|
|
54
|
+
if(typeof r === 'number') {
|
|
55
|
+
const v = Math.max(0, r);
|
|
56
|
+
return { topLeft: v, topRight: v, bottomRight: v, bottomLeft: v };
|
|
57
|
+
}
|
|
58
|
+
if(typeof r === 'object' && r !== null) {
|
|
59
|
+
return {
|
|
60
|
+
topLeft: Math.max(0, Number(r.topLeft) || 0),
|
|
61
|
+
topRight: Math.max(0, Number(r.topRight) || 0),
|
|
62
|
+
bottomRight: Math.max(0, Number(r.bottomRight) || 0),
|
|
63
|
+
bottomLeft: Math.max(0, Number(r.bottomLeft) || 0)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0 };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 检查是否有圆角
|
|
71
|
+
* @returns {boolean}
|
|
72
|
+
*/
|
|
73
|
+
hasRadius() {
|
|
74
|
+
const nr = this.getNormalizedRadius();
|
|
75
|
+
return nr.topLeft > 0 || nr.topRight > 0 || nr.bottomRight > 0 || nr.bottomLeft > 0;
|
|
33
76
|
}
|
|
34
77
|
|
|
35
78
|
/**
|
|
@@ -92,7 +135,7 @@ export default class jmRect extends jmPath {
|
|
|
92
135
|
|
|
93
136
|
/**
|
|
94
137
|
* 初始化图形点
|
|
95
|
-
*
|
|
138
|
+
* 支持四角独立圆角,借助圆弧对象计算描点
|
|
96
139
|
*
|
|
97
140
|
* @method initPoints
|
|
98
141
|
* @private
|
|
@@ -109,32 +152,67 @@ export default class jmRect extends jmPath {
|
|
|
109
152
|
this.dottedLine = this.graph.createShape(jmLine, {style: this.style});
|
|
110
153
|
}
|
|
111
154
|
|
|
112
|
-
|
|
113
|
-
|
|
155
|
+
const nr = this.getNormalizedRadius();
|
|
156
|
+
const hasRadius = this.hasRadius();
|
|
157
|
+
|
|
158
|
+
// 如果有圆角(支持四角独立),借助圆弧对象计算描点
|
|
159
|
+
if(hasRadius) {
|
|
114
160
|
let q = Math.PI / 2;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
161
|
+
|
|
162
|
+
// 限制圆角不超过短边的一半
|
|
163
|
+
const maxR = Math.min(location.width / 2, location.height / 2);
|
|
164
|
+
const rtl = Math.min(nr.topLeft, maxR);
|
|
165
|
+
const rtr = Math.min(nr.topRight, maxR);
|
|
166
|
+
const rbr = Math.min(nr.bottomRight, maxR);
|
|
167
|
+
const rbl = Math.min(nr.bottomLeft, maxR);
|
|
168
|
+
|
|
169
|
+
// 左上角圆弧
|
|
170
|
+
if(rtl > 0) {
|
|
171
|
+
let arc = this.graph.createShape(jmArc,{radius:rtl,anticlockwise:false});
|
|
172
|
+
arc.center = {x:location.left + rtl, y:location.top + rtl};
|
|
173
|
+
arc.startAngle = Math.PI;
|
|
174
|
+
arc.endAngle = Math.PI + q;
|
|
175
|
+
var ps1 = arc.initPoints();
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
var ps1 = [p1];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 右上角圆弧
|
|
182
|
+
if(rtr > 0) {
|
|
183
|
+
let arc = this.graph.createShape(jmArc,{radius:rtr,anticlockwise:false});
|
|
184
|
+
arc.center = {x:p2.x - rtr, y:p2.y + rtr};
|
|
185
|
+
arc.startAngle = Math.PI + q;
|
|
186
|
+
arc.endAngle = Math.PI * 2;
|
|
187
|
+
var ps2 = arc.initPoints();
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
var ps2 = [p2];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 右下角圆弧
|
|
194
|
+
if(rbr > 0) {
|
|
195
|
+
let arc = this.graph.createShape(jmArc,{radius:rbr,anticlockwise:false});
|
|
196
|
+
arc.center = {x:p3.x - rbr, y:p3.y - rbr};
|
|
197
|
+
arc.startAngle = 0;
|
|
198
|
+
arc.endAngle = q;
|
|
199
|
+
var ps3 = arc.initPoints();
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
var ps3 = [p3];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 左下角圆弧
|
|
206
|
+
if(rbl > 0) {
|
|
207
|
+
let arc = this.graph.createShape(jmArc,{radius:rbl,anticlockwise:false});
|
|
208
|
+
arc.center = {x:p4.x + rbl, y:p4.y - rbl};
|
|
209
|
+
arc.startAngle = q;
|
|
210
|
+
arc.endAngle = Math.PI;
|
|
211
|
+
var ps4 = arc.initPoints();
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
var ps4 = [p4];
|
|
215
|
+
}
|
|
138
216
|
this.points = ps1.concat(ps2,ps3,ps4);
|
|
139
217
|
}
|
|
140
218
|
else {
|