kfb-view 3.2.2 → 3.2.4

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.
@@ -8,7 +8,7 @@ import {
8
8
  isPointInEllipse,
9
9
  isPointInMatrix,
10
10
  isPointInPolygon,
11
- calculatePolygonArea,
11
+ calculatePolygonArea, getRectPointV2,
12
12
  } from '../../util/calculate';
13
13
  import {Point, Rect} from '../../plugin/openseadragon/openseadragon';
14
14
  import {
@@ -93,6 +93,9 @@ export class ViewerCommon {
93
93
  * @return {boolean}
94
94
  */
95
95
  isContainerInRegion(point, {region, tool, points, isClose}) {
96
+ if (tool === POLYGON && isClose) {
97
+ return isPointInPolygon(point, points);
98
+ }
96
99
  const p1 = {x: region.x, y: region.y};
97
100
  const p2 = {x: region.x + region.width, y: region.y};
98
101
  const p3 = {x: region.x, y: region.y + region.height};
@@ -107,9 +110,6 @@ export class ViewerCommon {
107
110
  if (tool === RECTANGLE) {
108
111
  return isPointInMatrix(p1, p2, p3, p4, point);
109
112
  }
110
- if (tool === POLYGON && isClose) {
111
- return isPointInPolygon(point, points);
112
- }
113
113
  return false;
114
114
  }
115
115
 
@@ -178,6 +178,23 @@ export class ViewerCommon {
178
178
  });
179
179
  }
180
180
 
181
+
182
+ /**
183
+ * 转化图像点数组到元素坐标点数组
184
+ * @param {Array} points
185
+ * @return {{}[]}
186
+ */
187
+ viewerElementToImagePoints(points) {
188
+ return (points || []).map((point) => {
189
+ const p = this.viewerElementToImageCoordinates(point.x, point.y);
190
+ return {
191
+ canMove: point.canMove,
192
+ x: p.x,
193
+ y: p.y,
194
+ };
195
+ });
196
+ }
197
+
181
198
  /**
182
199
  * 返回图像倍率
183
200
  * @param {boolean} current Pass true for the current location; defaults to false (target location).
@@ -224,36 +241,12 @@ export class ViewerCommon {
224
241
  };
225
242
  const w = Math.abs(endPoint.x - startPoint.x);
226
243
  const h = Math.abs(endPoint.y - startPoint.y);
227
- const center = {
228
- x: (endPoint.x + startPoint.x) / 2,
229
- y: (endPoint.y + startPoint.y) / 2,
230
- };
231
- const deg = getAngle(startPoint, {...startPoint, x: startPoint.x + 1},
232
- endPoint);
233
- const p = this.imageToViewerElementCoordinates(center.x,
234
- center.y);
235
- let distY = -50;
236
- let distX = -50;
237
- if (endPoint.y < startPoint.y && endPoint.x > startPoint.x) {
238
- distY = -50;
239
- distX = -50;
240
- }
241
- if (endPoint.y < startPoint.y && endPoint.x < startPoint.x) {
242
- distY = -10;
243
- distX = 50;
244
- }
245
- if (endPoint.y > startPoint.y && endPoint.x > startPoint.x) {
246
- distY = 10;
247
- distX = -50;
248
- }
249
- if (endPoint.y > startPoint.y && endPoint.x < startPoint.x) {
250
- distY = 50;
251
- distX = 80;
252
- }
244
+ const p = this.imageToViewerElementCoordinates(endPoint.x,
245
+ endPoint.y);
253
246
  content = {
254
- left: p.x + distX * scale,
255
- top: p.y + distY * scale,
256
- angle: deg,
247
+ left: p.x + 10 * scale,
248
+ top: p.y,
249
+ angle: 0,
257
250
  texts: [
258
251
  `长:${this.getUnitNumber((Math.sqrt(w * w + h * h) * this.options.imageCapRes).toFixed(2))}`],
259
252
  };
@@ -17,7 +17,7 @@ export class Graduation extends ViewerCommon {
17
17
  constructor({viewer, canvas, cache, options}) {
18
18
  super(viewer, canvas, cache, options);
19
19
  this.microns = options.microns ||
20
- [5000, 2000, 1500, 1250, 1000, 800, 500, 400, 250, 200, 150, 125, 100, 80, 60, 40, 20, 10, 8, 5];
20
+ [5000, 2000, 1500, 1250, 1000, 800, 500, 400, 250, 200, 150, 125, 100, 80, 60, 40, 20, 10, 8, 5, 4, 2, 1];
21
21
  }
22
22
 
23
23
  /**
@@ -25,8 +25,9 @@ export class Graduation extends ViewerCommon {
25
25
  */
26
26
  change() {
27
27
  const microns = this.microns;
28
- const rect = this.viewerElementToImageRectangle({x: 0, y: 0, width: 50, height: 50});
29
- const max = rect.height * this.options.imageCapRes;
28
+ const startPoint = this.viewerElementToImageCoordinates(0, 0);
29
+ const endPoint = this.viewerElementToImageCoordinates(50, 0);
30
+ const max = endPoint.distanceTo(startPoint) * this.options.imageCapRes;
30
31
  const index = this.microns.findIndex((i) => i <= max);
31
32
  if (!~index) {
32
33
  this.setScaleLine(microns[microns.length - 1],
@@ -45,7 +46,7 @@ export class Graduation extends ViewerCommon {
45
46
  setScaleLine(txt, px) {
46
47
  const startPoint = this.imageToViewerElementCoordinates(0, 0);
47
48
  const endPoint = this.imageToViewerElementCoordinates(px, 0);
48
- const width = Math.abs(endPoint.x - startPoint.x);
49
+ const width = endPoint.distanceTo(startPoint);
49
50
  if (this.options.custom) {
50
51
  this.mitt.$emit(EVENT_GRADUATION_CHANGE, {width, txt});
51
52
  } else {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HAS_NO_FILL_TYPES,
3
- HAS_REGION_TYPES, IMAGE,
3
+ IMAGE,
4
4
  MARKS, POINT_TYPES, POLYGON, REGION_TYPES,
5
5
  } from '../../const/mark';
6
6
  import {ViewerCommon} from '../common/common';
@@ -51,7 +51,7 @@ export class Shape extends ViewerCommon {
51
51
  change() {
52
52
  this.clearCanvas();
53
53
  const bounds = this.viewport.viewportToImageRectangle(
54
- this.viewport.getBounds());
54
+ this.viewport.getBoundsNoRotate());
55
55
  // strokeStyle, lineWidth, fillStyle 相同认为是一个路径下的图形,一起绘制,优化性能
56
56
  const sameFixWidthLabel = {}; // star, flag, star, font lineWidth固定为2
57
57
  const sameNormalLabel = {};
@@ -173,7 +173,7 @@ export class Shape extends ViewerCommon {
173
173
  }, item.child.map(({points, tool}) => ({
174
174
  points: this.imageToViewerElementPoints(points),
175
175
  tool,
176
- })), this.viewport.getRotation());
176
+ })), this.getAngle(item.angle));
177
177
  });
178
178
  } else {
179
179
  this.delaytimer = setTimeout(() => {
@@ -184,16 +184,20 @@ export class Shape extends ViewerCommon {
184
184
  }
185
185
  }
186
186
 
187
+ getAngle(angle) {
188
+ const currentAngle = this.viewport.getRotation() % 360;
189
+ return angle ? angle > currentAngle ? currentAngle - angle + 360 : currentAngle - angle : currentAngle;
190
+ }
191
+
187
192
  drawLabel(item) {
188
193
  item.viewerElementPoints = this.imageToViewerElementPoints(item.points);
189
194
  const points = item.viewerElementPoints;
190
195
  this[item.tool].setContent(this.canvas, item);
191
196
  if (REGION_TYPES.includes(item.tool)) {
192
- this[item.tool].draw(points, this.viewport.getRotation(),
193
- this.imageToViewerElementRectangle(item.region));
197
+ this[item.tool].draw(points, this.getAngle(item.angle));
194
198
  } else {
195
199
  const scale = this.getImageZoom(true) / item.scale;
196
- this[item.tool].draw(points, scale);
200
+ this[item.tool].draw(points, scale, this.getAngle(item.angle));
197
201
  }
198
202
  }
199
203
  }
@@ -1,6 +1,6 @@
1
1
  import {Brush} from './Brush';
2
2
  import {POLYGON, ELLIPSE, RECTANGLE} from '../const/mark';
3
- import {pointsToRegion} from '../util/calculate';
3
+ import {getRectPoints, pointsToRegion} from '../util/calculate';
4
4
 
5
5
  /**
6
6
  * 曲线类
@@ -17,16 +17,23 @@ class Combination extends Brush {
17
17
  */
18
18
  draw(parent, children, rotation = 0) {
19
19
  const ctx = this.canvas.getContext('2d');
20
- const {tool, points} = parent;
20
+ let {tool, points} = parent;
21
21
  ctx.beginPath();
22
22
  ctx.save();
23
+ if (points.length === 2) {
24
+ points = getRectPoints(points);
25
+ }
23
26
  const region = pointsToRegion(points);
24
27
  const centerPoint = {
25
28
  x: region.x + region.width / 2,
26
29
  y: region.y + region.height / 2,
27
30
  };
28
31
  ctx.translate(centerPoint.x, centerPoint.y);
29
- ctx.rotate(rotation * Math.PI / 180);
32
+ if (rotation < 0) {
33
+ rotation += 360;
34
+ }
35
+ const _rotation = rotation % 360;
36
+ ctx.rotate(_rotation * Math.PI / 180);
30
37
  if (tool === POLYGON) {
31
38
  ctx.drawPolygon(points.map((p) => ({
32
39
  x: p.x - centerPoint.x,
@@ -48,6 +55,9 @@ class Combination extends Brush {
48
55
  ctx.closePath();
49
56
  ctx.restore();
50
57
  children.forEach(({tool, points}) => {
58
+ if (points.length === 2) {
59
+ points = getRectPoints(points);
60
+ }
51
61
  ctx.save();
52
62
  const region = pointsToRegion(points);
53
63
  const centerPoint = {
@@ -55,7 +65,7 @@ class Combination extends Brush {
55
65
  y: region.y + region.height / 2,
56
66
  };
57
67
  ctx.translate(centerPoint.x, centerPoint.y);
58
- ctx.rotate(rotation * Math.PI / 180);
68
+ ctx.rotate(_rotation * Math.PI / 180);
59
69
  if (tool === POLYGON) {
60
70
  ctx.drawPolygon(points.map((p) => ({
61
71
  x: p.x - centerPoint.x,
@@ -1,4 +1,5 @@
1
1
  import {Brush} from './Brush';
2
+ import {getDistance, getRectPoints} from '../util/calculate';
2
3
 
3
4
  /**
4
5
  * 椭圆类
@@ -18,9 +19,8 @@ class Ellipse extends Brush {
18
19
  * @param {number} points[].x - 绘制的点x坐标
19
20
  * @param {number} points[].y - 绘制的点y坐标
20
21
  * @param {number} rotation
21
- * @param {Object} region
22
22
  */
23
- draw(points, rotation = 0, region) {
23
+ draw(points, rotation = 0) {
24
24
  const startPoint = points[0];
25
25
  const endPoint = points[points.length - 1];
26
26
  const ctx = this.canvas.getContext('2d');
@@ -29,24 +29,23 @@ class Ellipse extends Brush {
29
29
  if (this.options.fillStyle) {
30
30
  ctx.fillStyle = this.options.fillStyle;
31
31
  }
32
+ if (points.length === 2) {
33
+ points = getRectPoints(points);
34
+ }
32
35
  ctx.save();
33
36
  const centerPoint = {
34
37
  x: (startPoint.x + endPoint.x) / 2,
35
38
  y: (startPoint.y + endPoint.y) / 2,
36
39
  };
37
- const width = region?.width ?
38
- Math.abs(region.width) :
39
- Math.abs(endPoint.x - startPoint.x);
40
- const height = region?.height ?
41
- Math.abs(region.height) :
42
- Math.abs(endPoint.y - startPoint.y);
40
+ const width = getDistance(points[1], points[0]);
41
+ const height = getDistance(points[2], points[0]);
43
42
  ctx.translate(centerPoint.x, centerPoint.y);
44
- ctx.rotate(rotation * Math.PI / 180);
45
- if (rotation < 90 && rotation >= 0 || rotation > 180 && rotation < 270) {
46
- ctx.drawOval(0, 0, width / 2, height / 2);
47
- } else {
48
- ctx.drawOval(0, 0, height / 2, width / 2);
43
+ if (rotation < 0) {
44
+ rotation += 360;
49
45
  }
46
+ const _rotation = rotation % 360;
47
+ ctx.rotate(_rotation * Math.PI / 180);
48
+ ctx.drawOval(0, 0, width / 2, height / 2);
50
49
  ctx.restore();
51
50
  }
52
51
  }
package/src/tool/Font.js CHANGED
@@ -18,16 +18,17 @@ class Font extends Brush {
18
18
  * @param {number} points[].x - 绘制的点x坐标
19
19
  * @param {number} points[].y - 绘制的点y坐标
20
20
  * @param {number=} scale
21
+ * @param {number} rotation
21
22
  */
22
- draw(points, scale = 1) {
23
+ draw(points, scale = 1, rotation = 0) {
23
24
  const point = points[0];
24
- const angle = this.options.angle || 0;
25
25
  const text = this.options.text || '编辑文字';
26
26
  const ctx = this.canvas.getContext('2d');
27
27
  ctx.fillStyle = this.options.strokeStyle;
28
28
  ctx.save();
29
+ const _rotation = rotation % 360;
29
30
  ctx.translate(point.x, point.y);
30
- ctx.rotate(angle / 180 * Math.PI);
31
+ ctx.rotate(_rotation * Math.PI / 180);
31
32
  ctx.scale(scale, scale);
32
33
  ctx.font = `${this.options.fontSize}px Arial`;
33
34
  const texts = text.split('\n');
@@ -1,4 +1,5 @@
1
1
  import {Brush} from './Brush';
2
+ import {getRectPoints} from '../util/calculate';
2
3
 
3
4
  /**
4
5
  * 矩形类
@@ -17,12 +18,11 @@ class Rectangle extends Brush {
17
18
  * @param {Object[]} points - 绘制的点
18
19
  * @param {number} points[].x - 绘制的点x坐标
19
20
  * @param {number} points[].y - 绘制的点y坐标
20
- * @param {number} rotation
21
- * @param {Object} region
22
21
  */
23
- draw(points, rotation = 0, region) {
24
- const startPoint = points[0];
25
- const endPoint = points[points.length - 1];
22
+ draw(points) {
23
+ if (points.length === 2) {
24
+ points = getRectPoints(points);
25
+ }
26
26
  const ctx = this.canvas.getContext('2d');
27
27
  ctx.lineWidth = this.options.lineWidth;
28
28
  ctx.strokeStyle = this.options.strokeStyle;
@@ -30,24 +30,11 @@ class Rectangle extends Brush {
30
30
  ctx.fillStyle = this.options.fillStyle;
31
31
  }
32
32
  ctx.save();
33
- const centerPoint = {
34
- x: (startPoint.x + endPoint.x) / 2,
35
- y: (startPoint.y + endPoint.y) / 2,
36
- };
37
- const width = region?.width ?
38
- Math.abs(region.width) :
39
- Math.abs(endPoint.x - startPoint.x);
40
- const height = region?.height ?
41
- Math.abs(region.height) :
42
- Math.abs(endPoint.y - startPoint.y);
43
- ctx.translate(centerPoint.x, centerPoint.y);
44
- if (rotation < 90 && rotation >= 0 || rotation > 180 && rotation < 270) {
45
- ctx.rotate(rotation * Math.PI / 180);
46
- ctx.rect(-width / 2, -height / 2, width, height);
47
- } else {
48
- ctx.rotate(rotation * Math.PI / 180);
49
- ctx.rect(-height / 2, -width / 2, height, width);
50
- }
33
+ ctx.moveTo(points[0].x, points[0].y);
34
+ ctx.lineTo(points[1].x, points[1].y);
35
+ ctx.lineTo(points[3].x, points[3].y);
36
+ ctx.lineTo(points[2].x, points[2].y);
37
+ ctx.lineTo(points[0].x, points[0].y);
51
38
  ctx.restore();
52
39
  }
53
40
  }
@@ -51,6 +51,43 @@ function getRectPoint(startPoint, endPoint, deg = 0) {
51
51
  }];
52
52
  }
53
53
 
54
+ /**
55
+ * 通过起始点和结束点获取矩形中的9个点
56
+ * @param {Object} points
57
+ * @param {number=} deg
58
+ * @return {*[]}
59
+ */
60
+ function getRectPointV2(points, deg = 0) {
61
+ if (points.length === 2) {
62
+ return getRectPoint(points[0], points[1], deg);
63
+ }
64
+ const centerX = (points[0].x + points[3].x) / 2;
65
+ const centerY = (points[0].y + points[3].y) / 2;
66
+ return [
67
+ points[0],
68
+ {
69
+ x: (points[1].x + points[0].x) / 2,
70
+ y: (points[1].y + points[0].y) / 2,
71
+ },
72
+ points[1],
73
+ {
74
+ x: (points[2].x + points[0].x) / 2,
75
+ y: (points[2].y + points[0].y) / 2,
76
+ }, {
77
+ x: centerX,
78
+ y: centerY,
79
+ }, {
80
+ x: (points[1].x + points[3].x) / 2,
81
+ y: (points[1].y + points[3].y) / 2,
82
+ },
83
+ points[2],
84
+ {
85
+ x: (points[2].x + points[3].x) / 2,
86
+ y: (points[2].y + points[3].y) / 2,
87
+ },
88
+ points[3]];
89
+ }
90
+
54
91
  /*
55
92
  * 叉乘计算公式 a×b =(x1y2-x2y1)
56
93
  * @param {Object} p1
@@ -239,6 +276,14 @@ function pointsToRegion(points) {
239
276
  height: points[1].y - points[0].y,
240
277
  };
241
278
  }
279
+ if (points.length === 4) {
280
+ return {
281
+ x: points[0].x,
282
+ y: points[0].y,
283
+ width: getDistance(points[1], points[0]) * (points[0].x < points[1].x ? 1 : -1),
284
+ height: getDistance(points[2], points[0]) * (points[0].y < points[2].y ? 1 : -1),
285
+ };
286
+ }
242
287
  const sortPointX = [...points].sort((a, b) => a.x - b.x);
243
288
  const sortPointY = [...points].sort((a, b) => a.y - b.y);
244
289
  const startPoint = {x: sortPointX[0].x, y: sortPointY[0].y};
@@ -334,6 +379,21 @@ function getPoint(cen, first, deg) {
334
379
  };
335
380
  }
336
381
 
382
+ /**
383
+ * 通过两个点计算矩形的四个点
384
+ * @param {array} points
385
+ * */
386
+ function getRectPoints(points) {
387
+ return [
388
+ points[0], {
389
+ x: points[1].x,
390
+ y: points[0].y,
391
+ }, {
392
+ x: points[0].x,
393
+ y: points[1].y,
394
+ }, points[1]];
395
+ }
396
+
337
397
  /**
338
398
  * 计算三点之间的夹角
339
399
  * @param {object} cen
@@ -472,4 +532,6 @@ export {
472
532
  getDistance,
473
533
  calculatePolygonArea,
474
534
  getRandomId,
535
+ getRectPoints,
536
+ getRectPointV2,
475
537
  };