kfb-view 2.1.18 → 2.2.0
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 +130 -123
- package/example/index.js +13 -4
- package/lib/kfb-view.js +1 -1
- package/package.json +1 -1
- package/src/components/area/index.js +74 -45
- package/src/components/board/index.js +127 -26
- package/src/components/rotation/index.js +2 -3
- package/src/components/shape/index.js +72 -52
- package/src/components/tailoring/index.js +1 -2
- package/src/const/event.js +3 -0
- package/src/tool/Brush.js +1 -1
- package/src/tool/Combination.js +1 -0
- package/src/tool/Polygon.js +8 -1
- package/src/tool/Thumb.js +2 -2
- package/src/util/calculate.js +26 -3
- package/src/view.js +103 -22
package/src/const/event.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
export const EVENT_START_PAINTING = 'start-painting';
|
|
2
3
|
export const EVENT_IN_PAINTING = 'in-painting';
|
|
3
4
|
export const EVENT_END_PAINTING = 'end-painting';
|
|
@@ -13,4 +14,6 @@ export const EVENT_CACHE_BACK = 'cache-back';
|
|
|
13
14
|
export const EVENT_CACHE_FORWARD = 'cache-forward';
|
|
14
15
|
export const EVENT_HIDDEN_LABEL = 'hidden-label';
|
|
15
16
|
export const EVENT_DELETE_LABEL = 'delete-label';
|
|
17
|
+
export const EVENT_DELETE_POLYGON_POINT = 'delete-polygon-point';
|
|
18
|
+
export const EVENT_ADD_POLYGON_POINT = 'add-polygon-point';
|
|
16
19
|
export const EVENT_NAVIGATOR_VESTIGE = 'navigator-vestige';
|
package/src/tool/Brush.js
CHANGED
package/src/tool/Combination.js
CHANGED
package/src/tool/Polygon.js
CHANGED
|
@@ -16,7 +16,8 @@ class Polygon extends Brush {
|
|
|
16
16
|
ctx.lineWidth = this.options.lineWidth;
|
|
17
17
|
ctx.strokeStyle = this.options.strokeStyle;
|
|
18
18
|
ctx.moveTo(points[0].x, points[0].y);
|
|
19
|
-
points.forEach((point) => {
|
|
19
|
+
points.forEach((point, index) => {
|
|
20
|
+
if (index === 0) return;
|
|
20
21
|
ctx.lineTo(point.x, point.y);
|
|
21
22
|
});
|
|
22
23
|
if (this.options.isClose) {
|
|
@@ -26,6 +27,12 @@ class Polygon extends Brush {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
drawPoints(points, config) {
|
|
32
|
+
points.forEach((point) => {
|
|
33
|
+
this.drawThumb(point, config);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
export {
|
package/src/tool/Thumb.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const ThumbConfig = {
|
|
2
2
|
lineWidth: 2,
|
|
3
|
-
|
|
3
|
+
radius: 5,
|
|
4
4
|
fillStyle: 'rgba(255, 255, 255, 1)',
|
|
5
5
|
strokeStyle: '#01d0b0',
|
|
6
6
|
};
|
|
@@ -51,7 +51,7 @@ class Thumb {
|
|
|
51
51
|
config = this.getConfig(config);
|
|
52
52
|
ctx.beginPath();
|
|
53
53
|
ctx.lineWidth = config.lineWidth;
|
|
54
|
-
ctx.arc(x, y, config.
|
|
54
|
+
ctx.arc(x, y, config.radius, 0, Math.PI * 2, !1);
|
|
55
55
|
ctx.fillStyle = config.fillStyle;
|
|
56
56
|
ctx.fill();
|
|
57
57
|
ctx.strokeStyle = config.strokeStyle;
|
package/src/util/calculate.js
CHANGED
|
@@ -132,9 +132,8 @@ function isPointInPolygon(p, poly) {
|
|
|
132
132
|
if ((sy < py && ty >= py) || (sy >= py && ty < py)) {
|
|
133
133
|
// 线段上与射线 Y 坐标相同的点的 X 坐标
|
|
134
134
|
const x = sx + (py - sy) * (tx - sx) / (ty - sy);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (x === px) {
|
|
135
|
+
// 点在多边形的边上,8像素的偏差
|
|
136
|
+
if (Math.abs(x - px) < 10) {
|
|
138
137
|
return true;
|
|
139
138
|
}
|
|
140
139
|
|
|
@@ -149,6 +148,29 @@ function isPointInPolygon(p, poly) {
|
|
|
149
148
|
return flag;
|
|
150
149
|
}
|
|
151
150
|
|
|
151
|
+
/**
|
|
152
|
+
* 判断一个点是否在一条线段上
|
|
153
|
+
* @param {Object} p
|
|
154
|
+
* @param {Object[]} points
|
|
155
|
+
* @return {boolean}
|
|
156
|
+
*/
|
|
157
|
+
function isPointInLine(p, points) {
|
|
158
|
+
const startPoint = points[0];
|
|
159
|
+
const endPoint = points[1];
|
|
160
|
+
// 判断线段两端点是否在射线两侧
|
|
161
|
+
if ((startPoint.y < p.y && endPoint.y >= p.y) ||
|
|
162
|
+
(startPoint.y >= p.y && endPoint.y < p.y)) {
|
|
163
|
+
// 线段上与射线 Y 坐标相同的点的 X 坐标
|
|
164
|
+
const x = startPoint.x + (p.y - startPoint.y) *
|
|
165
|
+
(endPoint.x - startPoint.x) / (endPoint.y - startPoint.y);
|
|
166
|
+
// 点在多边形的边上,8像素的偏差
|
|
167
|
+
if (Math.abs(x - p.x) < 8) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
|
|
152
174
|
/**
|
|
153
175
|
* points转换成Region
|
|
154
176
|
* @param {Object[]} points - 绘制的点
|
|
@@ -366,6 +388,7 @@ export {
|
|
|
366
388
|
pointsToRegion,
|
|
367
389
|
regionToPoint,
|
|
368
390
|
isPointInPolygon,
|
|
391
|
+
isPointInLine,
|
|
369
392
|
isNegNumber,
|
|
370
393
|
baseNumber,
|
|
371
394
|
acreage,
|
package/src/view.js
CHANGED
|
@@ -6,7 +6,7 @@ import {pointsToRegion} from './util/calculate';
|
|
|
6
6
|
import * as COMPONENTS from './const/component';
|
|
7
7
|
import * as EVENTS from './const/event';
|
|
8
8
|
import * as Components from './components';
|
|
9
|
-
import {MARKS} from './const/mark';
|
|
9
|
+
import {MARKS, POLYGON} from './const/mark';
|
|
10
10
|
import {LabelModel} from './model/label.model';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -37,9 +37,14 @@ export default class KfbView extends EventEmitter {
|
|
|
37
37
|
* @param {Object} config.area 交互区域,触发点击、拖动等事件
|
|
38
38
|
* @param {boolean=} config.area.disabled 是否禁用area
|
|
39
39
|
* @param {boolean=} config.area.drag 是否允许拖动
|
|
40
|
-
* @param {
|
|
41
|
-
* @param {boolean=} config.
|
|
42
|
-
* @param {
|
|
40
|
+
* @param {Object} config.thumb 选中区域时标注点配置
|
|
41
|
+
* @param {boolean=} config.thumb.show 选中区域时是否标注点
|
|
42
|
+
* @param {number=} config.thumb.radius 选中区域标注点的半径
|
|
43
|
+
* @param {String=} config.thumb.color 选中区域标注点的颜色
|
|
44
|
+
* @param {String=} config.thumb.bgColor 选中区域标注点的背景颜色
|
|
45
|
+
* @param {number=} config.thumb.activeRadius 标注点激活状态下的半径
|
|
46
|
+
* @param {boolean=} config.thumb.activeColor 标注点激活状态下颜色
|
|
47
|
+
* @param {boolean=} config.thumb.activeBgColor 标注点激活状态下背景颜色
|
|
43
48
|
* @param {Object} config.rotation 旋转图像参数
|
|
44
49
|
* @param {boolean=} config.rotation.disabled 是否禁用旋转
|
|
45
50
|
* @param {Object} config.tailoring 裁剪图像参数
|
|
@@ -254,7 +259,18 @@ function initComponentsOptions(kv, type) {
|
|
|
254
259
|
viewer: kv.viewer,
|
|
255
260
|
cache: kv.cache,
|
|
256
261
|
canvas: createCanvas(kv),
|
|
257
|
-
options: {
|
|
262
|
+
options: {
|
|
263
|
+
...config[type], ...pxConversion, thumb: config.thumb ? {
|
|
264
|
+
radius: 5,
|
|
265
|
+
activeRadius: 7,
|
|
266
|
+
activeBgColor: '#01d0b0',
|
|
267
|
+
...config.thumb,
|
|
268
|
+
} : {
|
|
269
|
+
radius: 5,
|
|
270
|
+
activeRadius: 7,
|
|
271
|
+
activeBgColor: '#01d0b0',
|
|
272
|
+
},
|
|
273
|
+
},
|
|
258
274
|
};
|
|
259
275
|
}
|
|
260
276
|
|
|
@@ -287,8 +303,7 @@ function initEvent(kv) {
|
|
|
287
303
|
e.preventDefaultAction = true;
|
|
288
304
|
kv.tailoring.onCanvasDrag(e.position);
|
|
289
305
|
} else if (kv.area?.movePoint) {
|
|
290
|
-
e.
|
|
291
|
-
kv.area.onCanvasDrag(e.position);
|
|
306
|
+
kv.area.onCanvasDrag(e.position, e);
|
|
292
307
|
kv.change();
|
|
293
308
|
}
|
|
294
309
|
});
|
|
@@ -308,17 +323,27 @@ function initEvent(kv) {
|
|
|
308
323
|
e.preventDefaultAction = true;
|
|
309
324
|
const {originalEvent} = e;
|
|
310
325
|
handlerCacheEvent(originalEvent, kv);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
kv.
|
|
314
|
-
|
|
315
|
-
kv.tailoring?.
|
|
316
|
-
|
|
326
|
+
if (kv.board?.isInDraw) {
|
|
327
|
+
kv.board?.onCanvasKey?.(e);
|
|
328
|
+
} else if (kv.rotation?.isInRotation) {
|
|
329
|
+
kv.rotation?.onCanvasKey?.(e);
|
|
330
|
+
} else if (kv.tailoring?.isInTailoring) {
|
|
331
|
+
kv.tailoring?.onCanvasKey?.(e);
|
|
332
|
+
} else {
|
|
333
|
+
handlerLabelEvent(originalEvent, kv);
|
|
334
|
+
kv.area?.change?.(e);
|
|
335
|
+
kv.shape?.change?.(e);
|
|
336
|
+
}
|
|
317
337
|
}, 100));
|
|
318
338
|
|
|
319
339
|
kv.viewer.addHandler('canvas-double-click', (e) => {
|
|
320
|
-
kv.
|
|
321
|
-
|
|
340
|
+
if (kv.board?.isInDraw) {
|
|
341
|
+
kv.board.onCanvasDblClick(e.position);
|
|
342
|
+
} else if (kv.tailoring?.isInTailoring) {
|
|
343
|
+
kv.tailoring?.onCanvasDblClick?.(e.position);
|
|
344
|
+
} else {
|
|
345
|
+
kv.area?.onCanvasDblClick?.(e.position);
|
|
346
|
+
}
|
|
322
347
|
});
|
|
323
348
|
|
|
324
349
|
kv.viewer.addHandler('resize', (e) => {
|
|
@@ -331,6 +356,43 @@ function initEvent(kv) {
|
|
|
331
356
|
kv.board.onCanvasMove(e);
|
|
332
357
|
}
|
|
333
358
|
}, true, kv.$el);
|
|
359
|
+
|
|
360
|
+
let isRightDown = false;
|
|
361
|
+
let dragPosition;
|
|
362
|
+
|
|
363
|
+
kv.viewer.canvas.addEventListener('contextmenu', function(event) {
|
|
364
|
+
if (kv.board?.isInDraw) {
|
|
365
|
+
event.preventDefault();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
kv.viewer.addHandler('canvas-nonprimary-press', function(e) {
|
|
370
|
+
console.log('nonprimary press');
|
|
371
|
+
if (e.button === 2) {
|
|
372
|
+
isRightDown = true;
|
|
373
|
+
}
|
|
374
|
+
dragPosition = e.position.clone();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
kv.viewer.addHandler('canvas-nonprimary-release', function(e) {
|
|
378
|
+
console.log('nonprimary release');
|
|
379
|
+
if (e.button === 2) {
|
|
380
|
+
isRightDown = false;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
new openSeadragon.MouseTracker({
|
|
385
|
+
element: kv.viewer.canvas,
|
|
386
|
+
moveHandler: function(event) {
|
|
387
|
+
if (isRightDown && kv.board?.isInDraw) {
|
|
388
|
+
console.log('nonprimary drag');
|
|
389
|
+
let delta = event.position.minus(dragPosition);
|
|
390
|
+
dragPosition = event.position.clone();
|
|
391
|
+
kv.viewer.viewport.panBy(
|
|
392
|
+
kv.viewer.viewport.deltaPointsFromPixels(delta.negate()));
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
});
|
|
334
396
|
}
|
|
335
397
|
|
|
336
398
|
function handlerCacheEvent(e, kv) {
|
|
@@ -349,17 +411,36 @@ function handlerCacheEvent(e, kv) {
|
|
|
349
411
|
}
|
|
350
412
|
|
|
351
413
|
function handlerLabelEvent(e, kv) {
|
|
414
|
+
const index = kv.labelList.findIndex((item) => item.select);
|
|
415
|
+
const label = kv.labelList[index];
|
|
352
416
|
if (e.key === 'h') {
|
|
353
|
-
const label = kv.labelList.find((label) => label.select);
|
|
354
417
|
if (!label) return;
|
|
355
418
|
label.show = false;
|
|
356
419
|
kv.$emit(EVENTS.EVENT_HIDDEN_LABEL, label);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
420
|
+
} else if (e.key === 'Delete' || e.key === 'Backspace') {
|
|
421
|
+
if (!label) return;
|
|
422
|
+
if (kv.area?.movePoint?.label?.tool === POLYGON) {
|
|
423
|
+
const movePoint = kv.area.movePoint;
|
|
424
|
+
movePoint.label.points.splice(movePoint.position, 1);
|
|
425
|
+
if (movePoint.label.points.length === 0) {
|
|
426
|
+
kv.$emit(EVENTS.EVENT_DELETE_LABEL, label);
|
|
427
|
+
kv.labelList.splice(index, 1);
|
|
428
|
+
} else {
|
|
429
|
+
kv.$emit(EVENTS.EVENT_DELETE_POLYGON_POINT, movePoint.label);
|
|
430
|
+
}
|
|
431
|
+
kv.area.movePoint = undefined;
|
|
432
|
+
} else {
|
|
433
|
+
kv.$emit(EVENTS.EVENT_DELETE_LABEL, label);
|
|
434
|
+
kv.labelList.splice(index, 1);
|
|
435
|
+
}
|
|
436
|
+
} else if (e.key === 'Escape') {
|
|
437
|
+
if (label) {
|
|
438
|
+
kv.$emit(EVENTS.EVENT_CANCEL_SELECT_LABEL, label);
|
|
439
|
+
}
|
|
440
|
+
kv.labelList.forEach((item) => {
|
|
441
|
+
item.select = false;
|
|
442
|
+
item.show = true;
|
|
443
|
+
});
|
|
363
444
|
}
|
|
364
445
|
}
|
|
365
446
|
|