kfb-view 2.2.2 → 2.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.
- package/.idea/workspace.xml +36 -31
- package/config/webpack.dev.conf.js +2 -1
- package/example/index.js +17 -4
- package/lib/kfb-view.js +1 -1
- package/package.json +1 -1
- package/src/components/area/index.js +1 -1
- package/src/components/board/index.js +1 -1
- package/src/components/common/common.js +24 -7
- package/src/components/graduation/index.js +9 -19
- package/src/components/grid/index.js +117 -0
- package/src/components/index.js +1 -0
- package/src/components/navigator/index.js +16 -4
- package/src/const/component.js +1 -0
- package/src/tool/Brush.js +7 -8
- package/src/view.js +19 -1
package/package.json
CHANGED
|
@@ -563,7 +563,7 @@ export class Area extends ViewerCommon {
|
|
|
563
563
|
}
|
|
564
564
|
this[label.tool].setContent(this.canvas, {...label});
|
|
565
565
|
if (label.measure && label.select) {
|
|
566
|
-
this[label.tool].drawMeasureInfo(label,
|
|
566
|
+
this[label.tool].drawMeasureInfo.call(this, label,
|
|
567
567
|
this.getMeasureContent(label), scale);
|
|
568
568
|
}
|
|
569
569
|
}
|
|
@@ -185,7 +185,7 @@ export class ViewerCommon extends EventEmitter {
|
|
|
185
185
|
left: 0,
|
|
186
186
|
top: 0,
|
|
187
187
|
angle: 0,
|
|
188
|
-
|
|
188
|
+
texts: [],
|
|
189
189
|
};
|
|
190
190
|
if (label.points.length <= 1) return content;
|
|
191
191
|
const scale = this.getImageZoom(true) / label.scale;
|
|
@@ -230,7 +230,7 @@ export class ViewerCommon extends EventEmitter {
|
|
|
230
230
|
left: p.x + distX * scale,
|
|
231
231
|
top: p.y + distY * scale,
|
|
232
232
|
angle: deg,
|
|
233
|
-
|
|
233
|
+
texts: [
|
|
234
234
|
`长:${(Math.sqrt(w * w + h * h) * this.options.imageCapRes).toFixed(
|
|
235
235
|
2)}${this.options.unit}`],
|
|
236
236
|
};
|
|
@@ -250,7 +250,7 @@ export class ViewerCommon extends EventEmitter {
|
|
|
250
250
|
left: p.x + 10 * scale,
|
|
251
251
|
top: p.y,
|
|
252
252
|
angle: 0,
|
|
253
|
-
|
|
253
|
+
texts: [
|
|
254
254
|
`长轴:${(w * this.options.imageCapRes).toFixed(
|
|
255
255
|
2)}${this.options.unit}`,
|
|
256
256
|
`短轴:${(h * this.options.imageCapRes).toFixed(
|
|
@@ -274,7 +274,7 @@ export class ViewerCommon extends EventEmitter {
|
|
|
274
274
|
left: p.x + 10 * scale,
|
|
275
275
|
top: p.y,
|
|
276
276
|
angle: 0,
|
|
277
|
-
|
|
277
|
+
texts: [
|
|
278
278
|
`长:${(w * this.options.imageCapRes).toFixed(
|
|
279
279
|
2)}${this.options.unit}`,
|
|
280
280
|
`宽:${(h * this.options.imageCapRes).toFixed(
|
|
@@ -298,7 +298,7 @@ export class ViewerCommon extends EventEmitter {
|
|
|
298
298
|
left: p.x,
|
|
299
299
|
top: p.y,
|
|
300
300
|
angle: 0,
|
|
301
|
-
|
|
301
|
+
texts: [
|
|
302
302
|
`周长:${(pt * this.options.imageCapRes).toFixed(
|
|
303
303
|
2)}${this.options.unit}`],
|
|
304
304
|
};
|
|
@@ -309,12 +309,17 @@ export class ViewerCommon extends EventEmitter {
|
|
|
309
309
|
left: 0,
|
|
310
310
|
right: 0,
|
|
311
311
|
angle: 0,
|
|
312
|
-
|
|
312
|
+
texts: [],
|
|
313
313
|
};
|
|
314
314
|
}
|
|
315
315
|
break;
|
|
316
316
|
}
|
|
317
|
-
return
|
|
317
|
+
return {
|
|
318
|
+
...content,
|
|
319
|
+
texts: this.options.measure.handler ?
|
|
320
|
+
this.options.measure.handler(content.texts, label) :
|
|
321
|
+
content.texts,
|
|
322
|
+
};
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
/**
|
|
@@ -417,6 +422,18 @@ export class ViewerCommon extends EventEmitter {
|
|
|
417
422
|
|
|
418
423
|
}
|
|
419
424
|
|
|
425
|
+
/**
|
|
426
|
+
* updated
|
|
427
|
+
* @param {Object=} options
|
|
428
|
+
*/
|
|
429
|
+
updated(options = {}) {
|
|
430
|
+
this.options = {
|
|
431
|
+
...this.options,
|
|
432
|
+
...options,
|
|
433
|
+
};
|
|
434
|
+
this.change();
|
|
435
|
+
}
|
|
436
|
+
|
|
420
437
|
/**
|
|
421
438
|
* 清除canvas
|
|
422
439
|
*/
|
|
@@ -15,28 +15,15 @@ export class Graduation extends ViewerCommon {
|
|
|
15
15
|
constructor({viewer, canvas, cache, options}) {
|
|
16
16
|
super(viewer, canvas, cache, options);
|
|
17
17
|
this.scales = options.scales ||
|
|
18
|
-
[0.1, 0.4, 0.6, 1, 2, 4, 8, 10, 20, 40,
|
|
18
|
+
[0.1, 0.4, 0.6, 1, 2, 4, 8, 10, 20, 40, 60, 100, 140, 200];
|
|
19
19
|
this.microns = options.microns ||
|
|
20
|
-
[5000, 2000, 1250, 1000, 500, 250, 200, 100, 50, 25, 10, 5];
|
|
21
|
-
this.init();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 初始化函数
|
|
26
|
-
*/
|
|
27
|
-
init() {
|
|
28
|
-
this.viewer.addHandler('animation', (res) => {
|
|
29
|
-
this.changeZoom();
|
|
30
|
-
});
|
|
31
|
-
setTimeout(() => {
|
|
32
|
-
this.changeZoom();
|
|
33
|
-
}, 100);
|
|
20
|
+
[5000, 2000, 1250, 1000, 500, 250, 200, 100, 50, 25, 20, 10, 5, 2];
|
|
34
21
|
}
|
|
35
22
|
|
|
36
23
|
/**
|
|
37
24
|
* 倍率大小改变
|
|
38
25
|
*/
|
|
39
|
-
|
|
26
|
+
change() {
|
|
40
27
|
const scales = [...this.scales];
|
|
41
28
|
const zoom = this.viewport.viewportToImageZoom(
|
|
42
29
|
this.viewport.getZoom(true)) * 40;
|
|
@@ -72,6 +59,9 @@ export class Graduation extends ViewerCommon {
|
|
|
72
59
|
const height = this.canvas.height;
|
|
73
60
|
ctx.beginPath();
|
|
74
61
|
ctx.clearRect(0, 0, width, height);
|
|
62
|
+
if (!this.options.show) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
75
65
|
const {left, top, right, bottom} = this.options;
|
|
76
66
|
let x = 10;
|
|
77
67
|
let y = height - 10;
|
|
@@ -88,16 +78,16 @@ export class Graduation extends ViewerCommon {
|
|
|
88
78
|
ctx.beginPath();
|
|
89
79
|
ctx.strokeStyle = '#000000';
|
|
90
80
|
ctx.lineWidth = 3;
|
|
91
|
-
ctx.moveTo(x, y -
|
|
81
|
+
ctx.moveTo(x, y - 8);
|
|
92
82
|
ctx.lineTo(x, y);
|
|
93
83
|
ctx.lineTo(x + lineWidth, y);
|
|
94
|
-
ctx.lineTo(x + lineWidth, y -
|
|
84
|
+
ctx.lineTo(x + lineWidth, y - 8);
|
|
95
85
|
ctx.stroke();
|
|
96
86
|
ctx.beginPath();
|
|
97
87
|
ctx.fillStyle = '#000000';
|
|
98
88
|
ctx.font = 'bold 16px Arial';
|
|
99
89
|
const t = txt.toFixed(0) + this.options.unit;
|
|
100
90
|
const fontWidth = ctx.measureText(t).width;
|
|
101
|
-
ctx.fillText(t, x + lineWidth / 2 - fontWidth / 2, top ? y +
|
|
91
|
+
ctx.fillText(t, x + lineWidth / 2 - fontWidth / 2, top ? y + 12 : y - 12);
|
|
102
92
|
}
|
|
103
93
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {ViewerCommon} from '../common/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 网格
|
|
5
|
+
* @class
|
|
6
|
+
*/
|
|
7
|
+
export class Grid extends ViewerCommon {
|
|
8
|
+
/**
|
|
9
|
+
* 初始化视图测量工具
|
|
10
|
+
* @param {Object} viewer
|
|
11
|
+
* @param {Object} canvas
|
|
12
|
+
* @param {Object} cache
|
|
13
|
+
* @param {Object} options
|
|
14
|
+
*/
|
|
15
|
+
constructor({viewer, canvas, cache, options}) {
|
|
16
|
+
super(viewer, canvas, cache, options);
|
|
17
|
+
if (!this.options.scale) {
|
|
18
|
+
this.options.scale = 20;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
change() {
|
|
23
|
+
const imageViewStartPoint = this.viewerElementToImageCoordinates(0, 0);
|
|
24
|
+
const imageViewXEndPoint = this.viewerElementToImageCoordinates(
|
|
25
|
+
this.canvas.width, 0);
|
|
26
|
+
const imageViewYEndPoint = this.viewerElementToImageCoordinates(0,
|
|
27
|
+
this.canvas.height);
|
|
28
|
+
let currentZoom = this.getImageZoom(true) * this.options.scale;
|
|
29
|
+
let baseScale = this.options.scale === 40 ? 3200 : 1600;
|
|
30
|
+
let twoCount = 0;
|
|
31
|
+
if (currentZoom >= 1) {
|
|
32
|
+
while (currentZoom / 2 >= 1) {
|
|
33
|
+
twoCount++;
|
|
34
|
+
currentZoom = currentZoom / 2;
|
|
35
|
+
}
|
|
36
|
+
if (twoCount) {
|
|
37
|
+
baseScale /= Math.pow(2, twoCount);
|
|
38
|
+
}
|
|
39
|
+
} else if (currentZoom < 1) {
|
|
40
|
+
while (currentZoom * 2 <= 1) {
|
|
41
|
+
twoCount++;
|
|
42
|
+
currentZoom = currentZoom * 2;
|
|
43
|
+
}
|
|
44
|
+
if (twoCount) {
|
|
45
|
+
baseScale *= Math.pow(2, twoCount);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const distX = imageViewXEndPoint.distanceTo(imageViewStartPoint);
|
|
49
|
+
const distY = imageViewYEndPoint.distanceTo(imageViewStartPoint);
|
|
50
|
+
const minX = Math.floor(imageViewStartPoint.x / baseScale);
|
|
51
|
+
const maxX = Math.floor((imageViewXEndPoint.x + distX) / baseScale);
|
|
52
|
+
const minY = Math.floor(imageViewStartPoint.y / baseScale);
|
|
53
|
+
const maxY = Math.floor((imageViewYEndPoint.y + distY) / baseScale);
|
|
54
|
+
const ctx = this.canvas.getContext('2d');
|
|
55
|
+
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
56
|
+
if (this.options.show) {
|
|
57
|
+
ctx.beginPath();
|
|
58
|
+
ctx.lineWidth = 1;
|
|
59
|
+
for (let i = minX; i <= maxX + 1; i++) {
|
|
60
|
+
const point = this.imageToViewerElementCoordinates(i * baseScale, 0);
|
|
61
|
+
ctx.moveTo(point.x, 0);
|
|
62
|
+
ctx.lineTo(point.x, this.canvas.height);
|
|
63
|
+
}
|
|
64
|
+
for (let i = minY; i <= maxY + 1; i++) {
|
|
65
|
+
const point = this.imageToViewerElementCoordinates(0, i * baseScale);
|
|
66
|
+
ctx.moveTo(0, point.y);
|
|
67
|
+
ctx.lineTo(this.canvas.width, point.y);
|
|
68
|
+
}
|
|
69
|
+
ctx.stroke();
|
|
70
|
+
}
|
|
71
|
+
if (this.options.ruler) {
|
|
72
|
+
const basePx = this.imageToViewerElementCoordinates(baseScale, 0).
|
|
73
|
+
minus(this.imageToViewerElementCoordinates(0, 0)).x;
|
|
74
|
+
ctx.beginPath();
|
|
75
|
+
ctx.strokeStyle = 'rgba(0, 0, 0, .8)';
|
|
76
|
+
ctx.fillStyle = 'rgba(0, 0, 0, .3)';
|
|
77
|
+
ctx.font = '14px Arial';
|
|
78
|
+
ctx.clearRect(0, 0, 20, this.canvas.height);
|
|
79
|
+
ctx.clearRect(0, 0, this.canvas.width, 20);
|
|
80
|
+
ctx.moveTo(20, 20);
|
|
81
|
+
ctx.lineTo(20, this.canvas.height);
|
|
82
|
+
ctx.moveTo(20, 20);
|
|
83
|
+
ctx.lineTo(this.canvas.width, 20);
|
|
84
|
+
for (let i = minX; i <= maxX + 1; i++) {
|
|
85
|
+
const point = this.imageToViewerElementCoordinates(i * baseScale, 0);
|
|
86
|
+
ctx.moveTo(point.x, 0);
|
|
87
|
+
ctx.lineTo(point.x, 20);
|
|
88
|
+
for (let j = 1; j < 5; j++) {
|
|
89
|
+
ctx.moveTo(point.x + (basePx / 5) * j, 16);
|
|
90
|
+
ctx.lineTo(point.x + (basePx / 5) * j, 20);
|
|
91
|
+
if (i !== minX) {
|
|
92
|
+
ctx.fillText(i * baseScale, point.x + 5, 13);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (let i = minY; i <= maxY + 1; i++) {
|
|
97
|
+
const point = this.imageToViewerElementCoordinates(0, i * baseScale);
|
|
98
|
+
ctx.moveTo(0, point.y);
|
|
99
|
+
ctx.lineTo(20, point.y);
|
|
100
|
+
for (let j = 1; j < 5; j++) {
|
|
101
|
+
ctx.moveTo(16, point.y + (basePx / 5) * j);
|
|
102
|
+
ctx.lineTo(20, point.y + (basePx / 5) * j);
|
|
103
|
+
if (i !== minY) {
|
|
104
|
+
ctx.save();
|
|
105
|
+
ctx.translate(3, point.y + 5);
|
|
106
|
+
ctx.rotate(Math.PI / 2);
|
|
107
|
+
ctx.fillText(i * baseScale, 0, 0);
|
|
108
|
+
ctx.restore();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
ctx.stroke();
|
|
113
|
+
ctx.beginPath();
|
|
114
|
+
ctx.clearRect(0, 0, 20, 20);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/components/index.js
CHANGED
|
@@ -81,6 +81,7 @@ export class Navigator extends EventEmitter {
|
|
|
81
81
|
top: top,
|
|
82
82
|
width: rect.clientWidth,
|
|
83
83
|
height: rect.clientHeight,
|
|
84
|
+
scale: [...this.vestige.zooms].reverse()[index],
|
|
84
85
|
color: [...this.vestige.colors].reverse()[index],
|
|
85
86
|
};
|
|
86
87
|
this.pointList.push(rectObj);
|
|
@@ -104,9 +105,10 @@ export class Navigator extends EventEmitter {
|
|
|
104
105
|
const colorCanvas = this.element.getElementsByClassName(
|
|
105
106
|
'navigator-color-rect')[0];
|
|
106
107
|
const ctx = colorCanvas.getContext('2d');
|
|
107
|
-
this.pointList.
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
this.pointList.sort((a, b) => a.scale > b.scale ? 1 : -1).
|
|
109
|
+
forEach((item) => {
|
|
110
|
+
this.drawRect(ctx, item);
|
|
111
|
+
});
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
/**
|
|
@@ -301,7 +303,7 @@ export class Navigator extends EventEmitter {
|
|
|
301
303
|
if (this.clearTimeId) window.clearTimeout(this.clearTimeId);
|
|
302
304
|
const currentImageZoom = this.viewport.viewportToImageZoom(currentZoom);
|
|
303
305
|
const index = [...this.vestige.zooms].reverse().findIndex(
|
|
304
|
-
(z) => currentImageZoom
|
|
306
|
+
(z) => currentImageZoom >= (z / (this.options.scale || 40)));
|
|
305
307
|
if (index !== -1) {
|
|
306
308
|
this.clearTimeId = window.setTimeout(() => {
|
|
307
309
|
this.$emit('rect-draw', index);
|
|
@@ -379,4 +381,14 @@ export class Navigator extends EventEmitter {
|
|
|
379
381
|
};
|
|
380
382
|
img.src = this.options.thumbnail; // 设置图片源地
|
|
381
383
|
}
|
|
384
|
+
|
|
385
|
+
toggleNavigator() {
|
|
386
|
+
const navigatorMain = this.element.getElementsByClassName(
|
|
387
|
+
'navigator-main')[0];
|
|
388
|
+
if (navigatorMain.style.display === 'none') {
|
|
389
|
+
navigatorMain.style.display = 'block';
|
|
390
|
+
} else {
|
|
391
|
+
navigatorMain.style.display = 'none';
|
|
392
|
+
}
|
|
393
|
+
}
|
|
382
394
|
}
|
package/src/const/component.js
CHANGED
package/src/tool/Brush.js
CHANGED
|
@@ -62,27 +62,26 @@ class Brush {
|
|
|
62
62
|
* @param {number} [scale=1]
|
|
63
63
|
*/
|
|
64
64
|
drawMeasureInfo(label, info, scale = 1) {
|
|
65
|
-
const {left, top,
|
|
65
|
+
const {left, top, texts, angle} = info;
|
|
66
66
|
const ctx = this.canvas.getContext('2d');
|
|
67
67
|
ctx.save();
|
|
68
68
|
ctx.beginPath();
|
|
69
69
|
ctx.translate(left, top);
|
|
70
70
|
ctx.rotate(angle);
|
|
71
71
|
ctx.scale(scale, scale);
|
|
72
|
-
ctx.font = `14px Arial`;
|
|
73
72
|
const widthList = [];
|
|
74
|
-
|
|
73
|
+
ctx.font = `${this.options.measure.fontSize}px Arial`;
|
|
74
|
+
texts.forEach((info) => {
|
|
75
75
|
widthList.push(ctx.measureText(info).width);
|
|
76
76
|
});
|
|
77
77
|
const width = Math.max(...widthList);
|
|
78
|
-
ctx.fillStyle =
|
|
79
|
-
const height =
|
|
78
|
+
ctx.fillStyle = this.options.measure.backgroundColor;
|
|
79
|
+
const height = texts.length * 20 + 16 + (texts.length - 1) * 4;
|
|
80
80
|
ctx.rect(0, 0, width + 22, height);
|
|
81
81
|
ctx.fill();
|
|
82
82
|
ctx.beginPath();
|
|
83
|
-
ctx.
|
|
84
|
-
|
|
85
|
-
content.forEach((info, index) => {
|
|
83
|
+
ctx.fillStyle = this.options.measure.color;
|
|
84
|
+
texts.forEach((info, index) => {
|
|
86
85
|
ctx.fillText(info, 11, 8 + 14 + index * 24);
|
|
87
86
|
});
|
|
88
87
|
ctx.fill();
|
package/src/view.js
CHANGED
|
@@ -19,6 +19,7 @@ export default class KfbView extends EventEmitter {
|
|
|
19
19
|
* @constructs
|
|
20
20
|
* @param {Object} config 配置参数
|
|
21
21
|
* @param {HTMLElement|string} config.el 图像容器
|
|
22
|
+
* @param {number=} config.scale 图像的最大倍率
|
|
22
23
|
* @param {Object} config.openSeadragonOptions openSeadragon参数
|
|
23
24
|
* @param {function=} config.tileDrawing openSeadragon绘制tile-drawing事件回调
|
|
24
25
|
* @param {Object} [config.navigator = {}] navigator参数
|
|
@@ -57,9 +58,17 @@ export default class KfbView extends EventEmitter {
|
|
|
57
58
|
* @param {boolean=} config.board.ROI 是否开启ROI,开启后只能在标注类型是ROI的区域内绘制图形
|
|
58
59
|
* @param {Object} config.graduation 刻度参数
|
|
59
60
|
* @param {boolean=} config.graduation.disabled 是否禁用刻度
|
|
61
|
+
* @param {boolean=} config.graduation.show 是否显刻度
|
|
60
62
|
* @param {boolean=} config.graduation.custom 是否自定义刻度,抛出graduation-change事件
|
|
61
63
|
* @param {array=} config.graduation.scales 倍率数组
|
|
62
64
|
* @param {array=} config.graduation.microns 刻度长度数组,在对应倍率范围内显示的刻度长度
|
|
65
|
+
* @param {boolean=} config.grid.disabled 是否禁用网格线
|
|
66
|
+
* @param {boolean=} config.grid.show 是否显示网格线
|
|
67
|
+
* @param {boolean=} config.grid.ruler 是否启用标尺
|
|
68
|
+
* @param {function=} config.measure.handler 标注信息的回调处理
|
|
69
|
+
* @param {boolean=} config.measure.color 标注注释颜色
|
|
70
|
+
* @param {boolean=} config.measure.backgroundColor 标注注释背景色
|
|
71
|
+
* @param {boolean=} config.measure.fontSize 标注注释文字大小
|
|
63
72
|
* @param {array} config.labelList 标注列表
|
|
64
73
|
*/
|
|
65
74
|
constructor(config) {
|
|
@@ -261,7 +270,16 @@ function initComponentsOptions(kv, type) {
|
|
|
261
270
|
cache: kv.cache,
|
|
262
271
|
canvas: createCanvas(kv),
|
|
263
272
|
options: {
|
|
264
|
-
|
|
273
|
+
scale: config.scale,
|
|
274
|
+
measure: {
|
|
275
|
+
backgroundColor: 'rgba(0,0,0,.5)',
|
|
276
|
+
color: '#FFF',
|
|
277
|
+
fontSize: 14,
|
|
278
|
+
...(config.measure || {}),
|
|
279
|
+
},
|
|
280
|
+
...config[type],
|
|
281
|
+
...pxConversion,
|
|
282
|
+
thumb: config.thumb ? {
|
|
265
283
|
radius: 5,
|
|
266
284
|
activeRadius: 7,
|
|
267
285
|
activeBgColor: '#01d0b0',
|