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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kfb-view",
3
3
  "description": "一个在线kfb的阅片软件",
4
- "version": "2.2.2",
4
+ "version": "2.2.3",
5
5
  "author": "qifeng.fan <qifeng.fan@hzztai.com>",
6
6
  "license": "MIT",
7
7
  "main": "lib/kfb-view.js",
@@ -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
  }
@@ -370,7 +370,7 @@ export class Board extends ViewerCommon {
370
370
  tool: this.tool,
371
371
  });
372
372
  if (form.measure) {
373
- this[this.tool].drawMeasureInfo(form,
373
+ this[this.tool].drawMeasureInfo.call(this, form,
374
374
  this.getMeasureContent(form));
375
375
  }
376
376
  return form;
@@ -185,7 +185,7 @@ export class ViewerCommon extends EventEmitter {
185
185
  left: 0,
186
186
  top: 0,
187
187
  angle: 0,
188
- content: [],
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
- content: [
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
- content: [
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
- content: [
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
- content: [
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
- content: [],
312
+ texts: [],
313
313
  };
314
314
  }
315
315
  break;
316
316
  }
317
- return content;
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, 80, 100];
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
- changeZoom() {
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 - 5);
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 - 5);
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 + 10 : y - 10);
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
+ }
@@ -6,3 +6,4 @@ export {Shape} from './shape';
6
6
  export {Area} from './area';
7
7
  export {Board} from './board';
8
8
  export {Graduation} from './graduation';
9
+ export {Grid} from './grid';
@@ -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.forEach((item) => {
108
- this.drawRect(ctx, item);
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 > (z / (this.options.scale || 40)));
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
  }
@@ -6,3 +6,4 @@ export const COMPONENT_ROTATION = 'rotation';
6
6
  export const COMPONENT_TAILORING = 'tailoring';
7
7
  export const COMPONENT_NAVIGATOR = 'navigator';
8
8
  export const COMPONENT_CACHE = 'cache';
9
+ export const COMPONENT_FRID = 'grid';
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, content, angle} = info;
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
- content.forEach((info) => {
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 = 'rgba(0,0,0,.5)';
79
- const height = content.length * 20 + 16 + (content.length - 1) * 4;
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.font = `14px Arial`;
84
- ctx.fillStyle = '#FDFDFD';
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
- ...config[type], ...pxConversion, thumb: config.thumb ? {
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',