kfb-view 2.1.16 → 2.1.19
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/.idea/workspace.xml +77 -73
- package/example/index.js +26 -1
- package/lib/kfb-view.js +1 -1
- package/package.json +1 -1
- package/src/components/board/index.js +15 -1
- package/src/components/common/common.js +48 -28
- package/src/components/shape/index.js +55 -21
- package/src/model/label.model.js +2 -1
- package/src/tool/Brush.js +1 -3
- package/src/tool/Font.js +2 -3
- package/src/tool/Polygon.js +17 -0
- package/src/tool/Star.js +0 -1
- package/src/util/canvas.js +0 -1
- package/src/view.js +0 -2
- package/test.html +24 -93
package/package.json
CHANGED
|
@@ -74,6 +74,7 @@ export class Board extends ViewerCommon {
|
|
|
74
74
|
measure: true,
|
|
75
75
|
clear: true,
|
|
76
76
|
isClose: true,
|
|
77
|
+
showStartPoint: true,
|
|
77
78
|
...options,
|
|
78
79
|
lineWidth: !options.lineWidth ?
|
|
79
80
|
(this.tool === STAR ? 15 :
|
|
@@ -103,6 +104,7 @@ export class Board extends ViewerCommon {
|
|
|
103
104
|
text: '',
|
|
104
105
|
measure: true,
|
|
105
106
|
clear: true,
|
|
107
|
+
showStartPoint: true,
|
|
106
108
|
...options,
|
|
107
109
|
lineWidth: !options.lineWidth ?
|
|
108
110
|
(this.tool === STAR ? 15 :
|
|
@@ -143,6 +145,11 @@ export class Board extends ViewerCommon {
|
|
|
143
145
|
this[tool].startDraw();
|
|
144
146
|
this[tool].draw(this.imageToViewerElementPoints(this.points));
|
|
145
147
|
this[tool].endDraw();
|
|
148
|
+
if (tool === POLYGON) {
|
|
149
|
+
const point = this.imageToViewerElementCoordinates(this.points[0].x,
|
|
150
|
+
this.points[0].y);
|
|
151
|
+
this[tool].drawPoint(point);
|
|
152
|
+
}
|
|
146
153
|
this.$emit(EVENT_START_PAINTING, this.getPaintOptions());
|
|
147
154
|
}
|
|
148
155
|
|
|
@@ -171,6 +178,11 @@ export class Board extends ViewerCommon {
|
|
|
171
178
|
this[tool].startDraw();
|
|
172
179
|
this[tool].draw(this.imageToViewerElementPoints(this.points));
|
|
173
180
|
this[tool].endDraw();
|
|
181
|
+
if (tool === POLYGON) {
|
|
182
|
+
const point = this.imageToViewerElementCoordinates(this.points[0].x,
|
|
183
|
+
this.points[0].y);
|
|
184
|
+
this[tool].drawPoint(point);
|
|
185
|
+
}
|
|
174
186
|
this.$emit(EVENT_IN_PAINTING, this.getPaintOptions());
|
|
175
187
|
}
|
|
176
188
|
|
|
@@ -249,8 +261,10 @@ export class Board extends ViewerCommon {
|
|
|
249
261
|
this.points.push(point);
|
|
250
262
|
this.clearCanvas();
|
|
251
263
|
this[tool].startDraw();
|
|
252
|
-
this
|
|
264
|
+
const points = this.imageToViewerElementPoints(this.points);
|
|
265
|
+
this[tool].draw(points);
|
|
253
266
|
this[tool].endDraw();
|
|
267
|
+
this[tool].drawPoint(points[0]);
|
|
254
268
|
this.$emit(EVENT_IN_PAINTING, this.getPaintOptions());
|
|
255
269
|
}
|
|
256
270
|
}
|
|
@@ -71,29 +71,40 @@ export class ViewerCommon extends EventEmitter {
|
|
|
71
71
|
* @return {boolean}
|
|
72
72
|
*/
|
|
73
73
|
isContainerLabel(point, list) {
|
|
74
|
-
const contain = list.find((
|
|
75
|
-
const p1 = {x: region.x, y: region.y};
|
|
76
|
-
const p2 = {x: region.x + region.width, y: region.y};
|
|
77
|
-
const p3 = {x: region.x, y: region.y + region.height};
|
|
78
|
-
const p4 = {x: region.x + region.width, y: region.y + region.height};
|
|
79
|
-
const center = {
|
|
80
|
-
x: region.x + region.width / 2, y: region.y + region.height / 2,
|
|
81
|
-
};
|
|
82
|
-
if (tool === ELLIPSE) {
|
|
83
|
-
return isPointInEllipse(point, center, Math.abs(region.width / 2),
|
|
84
|
-
Math.abs(region.height / 2 >> 0));
|
|
85
|
-
}
|
|
86
|
-
if (tool === RECTANGLE) {
|
|
87
|
-
return isPointInMatrix(p1, p2, p3, p4, point);
|
|
88
|
-
}
|
|
89
|
-
if (tool === POLYGON && isClose) {
|
|
90
|
-
return isPointInPolygon(point, points);
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
});
|
|
74
|
+
const contain = list.find((item) => this.isContainerInRegion(point, item));
|
|
94
75
|
return !!contain;
|
|
95
76
|
}
|
|
96
77
|
|
|
78
|
+
/**
|
|
79
|
+
* 判断点是否在某个区域内
|
|
80
|
+
* @param {Object} point
|
|
81
|
+
* @param {Object} region
|
|
82
|
+
* @param {String} tool
|
|
83
|
+
* @param {Array} points
|
|
84
|
+
* @param {boolean} isClose
|
|
85
|
+
* @return {boolean}
|
|
86
|
+
*/
|
|
87
|
+
isContainerInRegion(point, {region, tool, points, isClose}) {
|
|
88
|
+
const p1 = {x: region.x, y: region.y};
|
|
89
|
+
const p2 = {x: region.x + region.width, y: region.y};
|
|
90
|
+
const p3 = {x: region.x, y: region.y + region.height};
|
|
91
|
+
const p4 = {x: region.x + region.width, y: region.y + region.height};
|
|
92
|
+
const center = {
|
|
93
|
+
x: region.x + region.width / 2, y: region.y + region.height / 2,
|
|
94
|
+
};
|
|
95
|
+
if (tool === ELLIPSE) {
|
|
96
|
+
return isPointInEllipse(point, center, Math.abs(region.width / 2),
|
|
97
|
+
Math.abs(region.height / 2 >> 0));
|
|
98
|
+
}
|
|
99
|
+
if (tool === RECTANGLE) {
|
|
100
|
+
return isPointInMatrix(p1, p2, p3, p4, point);
|
|
101
|
+
}
|
|
102
|
+
if (tool === POLYGON && isClose) {
|
|
103
|
+
return isPointInPolygon(point, points);
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
/**
|
|
98
109
|
* 转化图像区域到元素坐标区域
|
|
99
110
|
* @param {number} x
|
|
@@ -149,10 +160,14 @@ export class ViewerCommon extends EventEmitter {
|
|
|
149
160
|
* @return {{}[]}
|
|
150
161
|
*/
|
|
151
162
|
imageToViewerElementPoints(points) {
|
|
152
|
-
return (points || []).map((point) =>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
return (points || []).map((point) => {
|
|
164
|
+
const p = this.imageToViewerElementCoordinates(point.x, point.y);
|
|
165
|
+
return {
|
|
166
|
+
canMove: point.canMove,
|
|
167
|
+
x: p.x,
|
|
168
|
+
y: p.y,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
/**
|
|
@@ -372,12 +387,17 @@ export class ViewerCommon extends EventEmitter {
|
|
|
372
387
|
/**
|
|
373
388
|
* 判断region是否在canvas中
|
|
374
389
|
* @param {Object} region
|
|
390
|
+
* @param {boolean} status
|
|
375
391
|
* @return {boolean}
|
|
376
392
|
*/
|
|
377
|
-
isInCanvas(region) {
|
|
378
|
-
const startPoint =
|
|
379
|
-
|
|
380
|
-
region.x
|
|
393
|
+
isInCanvas(region, status = false) {
|
|
394
|
+
const startPoint = status ?
|
|
395
|
+
{x: region.x, y: region.y} :
|
|
396
|
+
this.imageToViewerElementCoordinates(region.x, region.y);
|
|
397
|
+
const endPoint = status ?
|
|
398
|
+
{x: region.x + region.width, y: region.y + region.height} :
|
|
399
|
+
this.imageToViewerElementCoordinates(
|
|
400
|
+
region.x + region.width, region.y + region.height);
|
|
381
401
|
if (endPoint.x < startPoint.x) {
|
|
382
402
|
const x = startPoint.x;
|
|
383
403
|
startPoint.x = endPoint.x;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
HAS_REGION_TYPES,
|
|
3
|
-
NO_NORMAL_REGION_TYPES, POINT_TYPES, POLYGON, REGION_TYPES,
|
|
2
|
+
HAS_REGION_TYPES,
|
|
3
|
+
MARKS, NO_NORMAL_REGION_TYPES, POINT_TYPES, POLYGON, REGION_TYPES,
|
|
4
4
|
} from '../../const/mark';
|
|
5
5
|
import {ViewerCommon} from '../common/common';
|
|
6
6
|
import * as Tools from '../../tool';
|
|
@@ -58,21 +58,34 @@ export class Shape extends ViewerCommon {
|
|
|
58
58
|
change() {
|
|
59
59
|
this.clearCanvas();
|
|
60
60
|
// 区域标注列表
|
|
61
|
-
const regionLabelList =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
const regionLabelList = [];
|
|
62
|
+
const polygonLabelList = [];
|
|
63
|
+
this.labelList.forEach(
|
|
64
|
+
(item) => {
|
|
65
|
+
if (item.tool === POLYGON) {
|
|
66
|
+
polygonLabelList.push(item);
|
|
67
|
+
}
|
|
68
|
+
if (REGION_TYPES.includes(item.tool) || item.isClose && item.tool ===
|
|
69
|
+
POLYGON) {
|
|
70
|
+
regionLabelList.push({
|
|
71
|
+
...item,
|
|
72
|
+
child: [],
|
|
73
|
+
self: item,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
69
77
|
// strokeStyle, lineWidth, fillStyle 相同认为是一个路径下的图形,一起绘制,优化性能
|
|
70
78
|
const sameFixWidthLabel = {}; // star, flag, star, font lineWidth固定为2
|
|
71
79
|
const sameNormalLabel = {};
|
|
72
80
|
this.labelList.forEach((item) => {
|
|
73
|
-
if (!this.isInCanvas(item.region)) return;
|
|
74
81
|
if (item.show === false) return;
|
|
75
82
|
if (!this[item.tool]) return;
|
|
83
|
+
if (!this.isInCanvas(item.region)) return;
|
|
84
|
+
/* const point = this.imageToViewerElementCoordinates(item.points[0].x,
|
|
85
|
+
item.points[0].y);
|
|
86
|
+
if ((point.x > this.canvas.width ||
|
|
87
|
+
point.y > this.canvas.height ||
|
|
88
|
+
point.x < 0 || point.y < 0)) return;*/
|
|
76
89
|
const key = `${item.strokeStyle ?? ''}_${item.lineWidth ??
|
|
77
90
|
''}_${item.fillStyle ?? ''}`;
|
|
78
91
|
const regionKey = `${item.strokeStyle ?? ''}_${item.lineWidth ?? ''}`;
|
|
@@ -90,37 +103,48 @@ export class Shape extends ViewerCommon {
|
|
|
90
103
|
}
|
|
91
104
|
}
|
|
92
105
|
const parent = regionLabelList.find(
|
|
93
|
-
(parent) => parent.
|
|
94
|
-
|
|
106
|
+
(parent) => HAS_REGION_TYPES.includes(parent.tool) && parent.self !==
|
|
107
|
+
item && item.points.every(
|
|
108
|
+
(point) => this.isContainerInRegion(point, parent)));
|
|
95
109
|
if (parent) {
|
|
96
110
|
parent.child.push(item);
|
|
97
111
|
}
|
|
98
112
|
});
|
|
113
|
+
const ctx = this.canvas.getContext('2d');
|
|
99
114
|
Object.values(sameFixWidthLabel).forEach((labels) => {
|
|
100
|
-
const ctx = this.canvas.getContext('2d');
|
|
101
115
|
ctx.beginPath();
|
|
102
116
|
labels.forEach((item) => {
|
|
103
117
|
this.drawLabel(item);
|
|
104
118
|
});
|
|
105
|
-
|
|
106
|
-
if (
|
|
119
|
+
const firstLabel = labels?.[0];
|
|
120
|
+
if (firstLabel?.fillStyle) {
|
|
121
|
+
ctx.fillStyle = firstLabel.fillStyle;
|
|
107
122
|
ctx.fill();
|
|
108
123
|
}
|
|
124
|
+
ctx.strokeStyle = firstLabel.strokeStyle;
|
|
125
|
+
ctx.stroke();
|
|
109
126
|
});
|
|
110
127
|
Object.values(sameNormalLabel).forEach((labels) => {
|
|
111
|
-
const ctx = this.canvas.getContext('2d');
|
|
112
128
|
ctx.beginPath();
|
|
113
129
|
labels.forEach((item) => {
|
|
114
130
|
this.drawLabel(item);
|
|
115
131
|
});
|
|
132
|
+
const firstLabel = labels?.[0];
|
|
133
|
+
ctx.lineWidth = firstLabel.lineWidth;
|
|
134
|
+
ctx.strokeStyle = firstLabel.strokeStyle;
|
|
116
135
|
ctx.stroke();
|
|
117
136
|
});
|
|
118
137
|
|
|
119
138
|
regionLabelList.forEach((item) => {
|
|
120
|
-
if (!this.isInCanvas(item.region)) return;
|
|
121
139
|
if (item.show === false) return;
|
|
122
140
|
if (!this[item.tool]) return;
|
|
123
|
-
this.
|
|
141
|
+
if (!this.isInCanvas(item.region)) return;
|
|
142
|
+
/* const point = this.imageToViewerElementCoordinates(item.points[0].x,
|
|
143
|
+
item.points[0].y);
|
|
144
|
+
if ((point.x > this.canvas.width ||
|
|
145
|
+
point.y > this.canvas.height ||
|
|
146
|
+
point.x < 0 || point.y < 0)) return;*/
|
|
147
|
+
this.combination.setContent(this.canvas, item);
|
|
124
148
|
this.combination.draw({
|
|
125
149
|
points: this.imageToViewerElementPoints(item.points),
|
|
126
150
|
tool: item.tool,
|
|
@@ -129,16 +153,26 @@ export class Shape extends ViewerCommon {
|
|
|
129
153
|
tool,
|
|
130
154
|
})), this.viewport.getRotation());
|
|
131
155
|
});
|
|
156
|
+
|
|
157
|
+
polygonLabelList.forEach((item) => {
|
|
158
|
+
if (item.show === false) return;
|
|
159
|
+
if (!this[item.tool]) return;
|
|
160
|
+
if (!this.isInCanvas(item.region)) return;
|
|
161
|
+
const point = this.imageToViewerElementCoordinates(item.points[0].x,
|
|
162
|
+
item.points[0].y);
|
|
163
|
+
this[item.tool].setContent(this.canvas, item);
|
|
164
|
+
this[item.tool].drawPoint(point);
|
|
165
|
+
});
|
|
132
166
|
}
|
|
133
167
|
|
|
134
168
|
drawLabel(item) {
|
|
135
|
-
const scale = this.getImageZoom(true) / item.scale;
|
|
136
169
|
const points = this.imageToViewerElementPoints(item.points);
|
|
137
|
-
this[item.tool].setContent(this.canvas,
|
|
170
|
+
this[item.tool].setContent(this.canvas, item);
|
|
138
171
|
if (!NO_NORMAL_REGION_TYPES.includes(item.tool)) {
|
|
139
172
|
this[item.tool].draw(points, this.viewport.getRotation(),
|
|
140
173
|
this.imageToViewerElementRectangle(item.region));
|
|
141
174
|
} else {
|
|
175
|
+
const scale = this.getImageZoom(true) / item.scale;
|
|
142
176
|
this[item.tool].draw(points, scale);
|
|
143
177
|
}
|
|
144
178
|
}
|
package/src/model/label.model.js
CHANGED
|
@@ -11,7 +11,7 @@ export class LabelModel {
|
|
|
11
11
|
this.strokeStyle = data.strokeStyle || '#027AFF'; // 标注颜色
|
|
12
12
|
this.fillStyle = data.fillStyle; // 填充颜色
|
|
13
13
|
this.description = data.description; // 描述
|
|
14
|
-
this.fontSize = data.fontSize; // 字号
|
|
14
|
+
this.fontSize = data.fontSize || 14; // 字号
|
|
15
15
|
this.text = data.text; // 文字
|
|
16
16
|
this.angle = data.angle ?? 0; // 旋转角度
|
|
17
17
|
this.measure = data.measure; // 是否显示测量信息
|
|
@@ -23,6 +23,7 @@ export class LabelModel {
|
|
|
23
23
|
this.resize = data.resize; // 是否可拖动大小
|
|
24
24
|
this.isROI = data.isROI ?? false; // 是否是ROI
|
|
25
25
|
this.isClose = data.isClose ?? true; // 是否是闭合标注
|
|
26
|
+
this.showStartPoint = data.showStartPoint ?? true; // 是否默认显示开始点,只针对曲线
|
|
26
27
|
this.select = data.select ?? false; // 是否是选中状态
|
|
27
28
|
this.show = data.show ?? true; // 是否显示
|
|
28
29
|
this.__other__ = data.__other__ || {}; // 其他信息
|
package/src/tool/Brush.js
CHANGED
package/src/tool/Font.js
CHANGED
|
@@ -24,13 +24,12 @@ class Font extends Brush {
|
|
|
24
24
|
const angle = this.options.angle || 0;
|
|
25
25
|
const text = this.options.text || '编辑文字';
|
|
26
26
|
const ctx = this.canvas.getContext('2d');
|
|
27
|
-
ctx.fillStyle = this.options.
|
|
28
|
-
'#FDFDFD';
|
|
27
|
+
ctx.fillStyle = this.options.strokeStyle;
|
|
29
28
|
ctx.save();
|
|
30
29
|
ctx.translate(point.x, point.y);
|
|
31
30
|
ctx.rotate(angle / 180 * Math.PI);
|
|
32
31
|
ctx.scale(scale, scale);
|
|
33
|
-
ctx.font = `${this.options.fontSize
|
|
32
|
+
ctx.font = `${this.options.fontSize}px Arial`;
|
|
34
33
|
ctx.fillText(text, 0, 0);
|
|
35
34
|
ctx.restore();
|
|
36
35
|
}
|
package/src/tool/Polygon.js
CHANGED
|
@@ -26,6 +26,23 @@ class Polygon extends Brush {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
drawPoint(point) {
|
|
31
|
+
if (this.options.showStartPoint) {
|
|
32
|
+
const ctx = this.canvas.getContext('2d');
|
|
33
|
+
ctx.beginPath();
|
|
34
|
+
ctx.fillStyle = '#0000008d';
|
|
35
|
+
ctx.fillRect(point.x - 20, point.y - 25, 40, 20);
|
|
36
|
+
ctx.beginPath();
|
|
37
|
+
ctx.font = `14px Arial`;
|
|
38
|
+
ctx.fillStyle = '#ffffff';
|
|
39
|
+
ctx.fillText('起点', point.x - 15, point.y - 10);
|
|
40
|
+
this.thumb.draw(point, {
|
|
41
|
+
thumbRadius: this.options.thumbRadius ?? 5,
|
|
42
|
+
strokeStyle: this.options.thumbColor,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
export {
|
package/src/tool/Star.js
CHANGED
|
@@ -24,7 +24,6 @@ class Star extends Brush {
|
|
|
24
24
|
let dist = this.options.lineWidth;
|
|
25
25
|
const point = points[0];
|
|
26
26
|
dist *= scale;
|
|
27
|
-
this.endPoint = {x: point.x, y: point.y};
|
|
28
27
|
const angle = 36 / 180 * Math.PI;
|
|
29
28
|
const angle1 = 54 / 180 * Math.PI;
|
|
30
29
|
const long_side = Math.sin(angle) * dist * 2;
|
package/src/util/canvas.js
CHANGED
|
@@ -60,7 +60,6 @@ CanvasRenderingContext2D.prototype.drawOval = function drawOval(
|
|
|
60
60
|
this.save();
|
|
61
61
|
// 选择a、b中的较大者作为arc方法的半径参数
|
|
62
62
|
const r = (a > b) ? a : b;
|
|
63
|
-
console.log(r);
|
|
64
63
|
const ratioX = a / r; // 横轴缩放比率
|
|
65
64
|
const ratioY = b / r; // 纵轴缩放比率
|
|
66
65
|
this.scale(ratioX, ratioY); // 进行缩放(均匀压缩)
|
package/src/view.js
CHANGED
|
@@ -96,7 +96,6 @@ export default class KfbView extends EventEmitter {
|
|
|
96
96
|
this.labelList = list.map((item) => new LabelModel({
|
|
97
97
|
...item,
|
|
98
98
|
region: item.region || pointsToRegion(item.points),
|
|
99
|
-
strokeStyle: item.strokeStyle || '#0000FF',
|
|
100
99
|
__data__: deepClone(item),
|
|
101
100
|
}));
|
|
102
101
|
this.board?.setLabelList?.(this.labelList);
|
|
@@ -109,7 +108,6 @@ export default class KfbView extends EventEmitter {
|
|
|
109
108
|
...this.labelList, ...list.map((item) => new LabelModel({
|
|
110
109
|
...item,
|
|
111
110
|
region: item.region || pointsToRegion(item.points),
|
|
112
|
-
strokeStyle: item.strokeStyle || '#0000FF',
|
|
113
111
|
__data__: deepClone(item),
|
|
114
112
|
}))];
|
|
115
113
|
this.board?.setLabelList?.(this.labelList);
|
package/test.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
|
|
9
9
|
<canvas id="canvas" width="800" height="600"></canvas>
|
|
10
|
-
|
|
10
|
+
<button id="reDraw">重绘</button>
|
|
11
11
|
<script>
|
|
12
12
|
/**
|
|
13
13
|
* 清除圆形区域
|
|
@@ -206,109 +206,40 @@
|
|
|
206
206
|
</script>
|
|
207
207
|
<script>
|
|
208
208
|
const canvas = document.getElementById('canvas');
|
|
209
|
+
const reDrawBtn = document.getElementById('reDraw');
|
|
209
210
|
const ctx = canvas.getContext('2d');
|
|
210
|
-
ctx.beginPath();
|
|
211
|
-
|
|
212
|
-
drawA([{x: 10, y: 10}, {x: 50, y: 40}]);
|
|
213
|
-
drawA([{x: 70, y: 70}, {x: 120, y: 120}]);
|
|
214
|
-
|
|
215
|
-
drawB([{x: 130, y: 130}, {x: 90, y: 60}]);
|
|
216
|
-
drawB([{x: 20, y: 20}, {x: 20, y: 90}]);
|
|
217
|
-
drawF([{x: 300, y: 200}]);
|
|
218
|
-
drawF([{x: 100, y: 500}]);
|
|
219
|
-
|
|
220
|
-
function drawA(points) {
|
|
221
|
-
const startPoint = points[0];
|
|
222
|
-
const endPoint = points[points.length - 1];
|
|
223
|
-
ctx.lineWidth = 2;
|
|
224
|
-
ctx.strokeStyle = '#0000FF';
|
|
225
|
-
ctx.moveTo(startPoint.x, startPoint.y);
|
|
226
|
-
ctx.lineTo(endPoint.x, endPoint.y);
|
|
227
|
-
ctx.drawArrow(startPoint, endPoint);
|
|
228
|
-
ctx.stroke();
|
|
229
|
-
}
|
|
230
211
|
|
|
231
|
-
function
|
|
232
|
-
|
|
233
|
-
const endPoint = points[points.length - 1];
|
|
234
|
-
ctx.lineWidth = 2;
|
|
235
|
-
ctx.strokeStyle = '#00FF00';
|
|
236
|
-
ctx.moveTo(startPoint.x, startPoint.y);
|
|
237
|
-
ctx.lineTo(endPoint.x, endPoint.y);
|
|
238
|
-
ctx.drawArrow(startPoint, endPoint);
|
|
239
|
-
ctx.drawArrow(endPoint, startPoint);
|
|
240
|
-
ctx.stroke();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function drawF(points, scale = 1) {
|
|
244
|
-
let dist = 30;
|
|
245
|
-
dist *= scale;
|
|
212
|
+
function drwaP(points) {
|
|
213
|
+
let dist = 4 * 1;
|
|
246
214
|
const point = points[0];
|
|
215
|
+
const ctx = canvas.getContext('2d');
|
|
216
|
+
const {x, y} = point;
|
|
247
217
|
ctx.lineWidth = 2;
|
|
248
|
-
ctx.
|
|
249
|
-
ctx.
|
|
250
|
-
ctx.lineTo(point.x, point.y - dist);
|
|
251
|
-
const _dist = dist / 5;
|
|
252
|
-
const p1 = {
|
|
253
|
-
x: point.x + _dist,
|
|
254
|
-
y: point.y - dist,
|
|
255
|
-
};
|
|
256
|
-
const p2 = {
|
|
257
|
-
x: point.x + _dist * 2,
|
|
258
|
-
y: point.y - dist - _dist,
|
|
259
|
-
};
|
|
260
|
-
const p3 = {
|
|
261
|
-
x: point.x + _dist * 4,
|
|
262
|
-
y: point.y - dist + _dist,
|
|
263
|
-
};
|
|
264
|
-
const p4 = {
|
|
265
|
-
x: point.x + dist,
|
|
266
|
-
y: point.y - dist,
|
|
267
|
-
};
|
|
268
|
-
ctx.bezierCurve([p1, p2, p3, p4]);
|
|
269
|
-
ctx.moveTo(p4.x, p4.y);
|
|
270
|
-
ctx.lineTo(p4.x, p4.y + dist / 2);
|
|
271
|
-
const p11 = {
|
|
272
|
-
x: point.x + _dist,
|
|
273
|
-
y: point.y - dist / 2,
|
|
274
|
-
};
|
|
275
|
-
const p22 = {
|
|
276
|
-
x: point.x + _dist * 2,
|
|
277
|
-
y: point.y - dist / 2 - _dist,
|
|
278
|
-
};
|
|
279
|
-
const p33 = {
|
|
280
|
-
x: point.x + _dist * 4,
|
|
281
|
-
y: point.y - dist / 2 + _dist,
|
|
282
|
-
};
|
|
283
|
-
const p44 = {
|
|
284
|
-
x: point.x + dist,
|
|
285
|
-
y: point.y - dist / 2,
|
|
286
|
-
};
|
|
287
|
-
ctx.bezierCurve([p11, p22, p33, p44]);
|
|
288
|
-
ctx.moveTo(p1.x, p1.y);
|
|
289
|
-
ctx.lineTo(p11.x, p11.y);
|
|
290
|
-
ctx.stroke();
|
|
218
|
+
ctx.moveTo(x + dist, y);
|
|
219
|
+
ctx.arc(x, y, dist, 0, Math.PI * 2, !1);
|
|
291
220
|
}
|
|
292
221
|
|
|
293
|
-
|
|
294
|
-
console.time('draw');
|
|
222
|
+
ctx.beginPath();
|
|
295
223
|
ctx.fillStyle = '#ff0000';
|
|
296
224
|
ctx.strokeStyle = '#00ff00';
|
|
297
225
|
ctx.lineWidth = 2;
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
for (let j = 0; j < 600; j++) {
|
|
301
|
-
if (i % 50 === 0 && j % 50 === 0) {
|
|
302
|
-
ctx.moveTo(i + 4, j);
|
|
303
|
-
ctx.arc(i, j, 4, 0, Math.PI * 2, !1);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
226
|
+
for (let i = 0; i < 4000; i++) {
|
|
227
|
+
drwaP([{x: Math.random() * 800, y: Math.random() * 600}]);
|
|
306
228
|
}
|
|
307
|
-
ctx.fill();
|
|
308
229
|
ctx.stroke();
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
230
|
+
reDrawBtn.addEventListener('click', (e) => {
|
|
231
|
+
ctx.clearRect(0, 0, 800, 600);
|
|
232
|
+
console.time('draw');
|
|
233
|
+
ctx.beginPath();
|
|
234
|
+
ctx.fillStyle = '#ff0000';
|
|
235
|
+
ctx.strokeStyle = '#00ff00';
|
|
236
|
+
ctx.lineWidth = 2;
|
|
237
|
+
for (let i = 0; i < 10000; i++) {
|
|
238
|
+
drwaP([{x: Math.random() * 800, y: Math.random() * 600}]);
|
|
239
|
+
}
|
|
240
|
+
ctx.stroke();
|
|
241
|
+
console.timeEnd('draw');
|
|
242
|
+
});
|
|
312
243
|
|
|
313
244
|
</script>
|
|
314
245
|
</body>
|