@cornerstonejs/tools 5.6.13 → 5.7.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/dist/esm/eventDispatchers/shared/getTouchCallbackWithMouseFallback.d.ts +1 -0
- package/dist/esm/eventDispatchers/shared/getTouchCallbackWithMouseFallback.js +24 -0
- package/dist/esm/eventDispatchers/shared/releaseToolForMultiTouchGesture.d.ts +2 -0
- package/dist/esm/eventDispatchers/shared/releaseToolForMultiTouchGesture.js +30 -0
- package/dist/esm/eventDispatchers/touchEventHandlers/touchDrag.js +7 -4
- package/dist/esm/eventDispatchers/touchEventHandlers/touchStart.js +7 -4
- package/dist/esm/eventDispatchers/touchEventHandlers/touchStartActivate.js +7 -2
- package/dist/esm/eventDispatchers/touchEventHandlers/touchTap.d.ts +2 -2
- package/dist/esm/eventDispatchers/touchEventHandlers/touchTap.js +29 -3
- package/dist/esm/eventDispatchers/touchToolEventDispatcher.js +1 -0
- package/dist/esm/eventListeners/touch/touchStartListener.js +7 -2
- package/dist/esm/store/ToolGroupManager/ToolGroup.js +1 -1
- package/dist/esm/store/filterMoveableAnnotationTools.js +2 -1
- package/dist/esm/store/filterToolsWithMoveableHandles.js +2 -1
- package/dist/esm/tools/AdvancedMagnifyTool.d.ts +11 -4
- package/dist/esm/tools/AdvancedMagnifyTool.js +141 -7
- package/dist/esm/tools/CrosshairsTool.d.ts +1 -1
- package/dist/esm/tools/CrosshairsTool.js +9 -8
- package/dist/esm/tools/MagnifyTool.d.ts +2 -0
- package/dist/esm/tools/MagnifyTool.js +19 -4
- package/dist/esm/tools/TrackballRotateTool.js +7 -0
- package/dist/esm/tools/VolumeCroppingTool.js +8 -0
- package/dist/esm/tools/VolumeRotateTool.d.ts +5 -1
- package/dist/esm/tools/VolumeRotateTool.js +24 -3
- package/dist/esm/tools/annotation/ArrowAnnotateTool.d.ts +1 -1
- package/dist/esm/tools/annotation/ArrowAnnotateTool.js +3 -3
- package/dist/esm/tools/annotation/ClickSegmentTool.d.ts +1 -0
- package/dist/esm/tools/annotation/ClickSegmentTool.js +14 -0
- package/dist/esm/tools/annotation/DragProbeTool.js +3 -1
- package/dist/esm/tools/annotation/LivewireContourTool.d.ts +3 -0
- package/dist/esm/tools/annotation/LivewireContourTool.js +36 -2
- package/dist/esm/tools/annotation/ProbeTool.d.ts +10 -2
- package/dist/esm/tools/annotation/ProbeTool.js +22 -3
- package/dist/esm/tools/annotation/RegionSegmentTool.js +6 -0
- package/dist/esm/tools/annotation/SplineROITool.d.ts +4 -0
- package/dist/esm/tools/annotation/SplineROITool.js +41 -3
- package/dist/esm/tools/annotation/WholeBodySegmentTool.js +7 -1
- package/dist/esm/tools/base/BaseTool.d.ts +7 -1
- package/dist/esm/tools/base/BaseTool.js +16 -0
- package/dist/esm/tools/base/ContourSegmentationBaseTool.d.ts +4 -0
- package/dist/esm/tools/base/ContourSegmentationBaseTool.js +23 -0
- package/dist/esm/tools/segmentation/BrushTool.d.ts +3 -0
- package/dist/esm/tools/segmentation/BrushTool.js +62 -4
- package/dist/esm/tools/segmentation/CircleScissorsTool.js +6 -1
- package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +5 -0
- package/dist/esm/tools/segmentation/LabelmapBaseTool.js +15 -0
- package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +1 -0
- package/dist/esm/tools/segmentation/RectangleScissorsTool.js +6 -1
- package/dist/esm/tools/segmentation/SegmentLabelTool.js +1 -1
- package/dist/esm/tools/segmentation/SegmentSelectTool.js +1 -1
- package/dist/esm/tools/segmentation/SphereScissorsTool.js +6 -1
- package/dist/esm/utilities/touch/constants.d.ts +4 -0
- package/dist/esm/utilities/touch/constants.js +4 -0
- package/dist/esm/utilities/touch/index.d.ts +3 -1
- package/dist/esm/utilities/touch/index.js +7 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +4 -4
|
@@ -82,6 +82,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
82
82
|
type: SplineTypesEnum.CatmullRom,
|
|
83
83
|
drawPreviewEnabled: true,
|
|
84
84
|
enableTwoPointPreview: false,
|
|
85
|
+
touchCloseCurveDistance: 36,
|
|
85
86
|
lastControlPointDeletionKeys: ['Backspace', 'Delete'],
|
|
86
87
|
},
|
|
87
88
|
actions: {
|
|
@@ -113,6 +114,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
113
114
|
'BSplineROI',
|
|
114
115
|
'CardinalSplineROI',
|
|
115
116
|
];
|
|
117
|
+
this.handlesMultiTouchGestures = true;
|
|
116
118
|
this.isHandleOutsideImage = false;
|
|
117
119
|
this.fireChangeOnUpdate = null;
|
|
118
120
|
this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
|
|
@@ -229,11 +231,22 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
229
231
|
const { renderingEngine } = getEnabledElement(element);
|
|
230
232
|
const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
|
|
231
233
|
this.editData.lastCanvasPoint = evt.detail.currentPoints.canvas;
|
|
234
|
+
this.editData.closeCurveDistance =
|
|
235
|
+
evt.type === Events.TOUCH_DRAG
|
|
236
|
+
? this.configuration.spline.touchCloseCurveDistance
|
|
237
|
+
: SPLINE_CLICK_CLOSE_CURVE_DIST;
|
|
232
238
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
233
239
|
evt.preventDefault();
|
|
234
240
|
};
|
|
235
241
|
this._mouseDownCallback = (evt) => {
|
|
236
|
-
const
|
|
242
|
+
const isTouchEvent = evt.type === Events.TOUCH_TAP || evt.type === Events.TOUCH_END;
|
|
243
|
+
const doubleTap = evt.type === Events.TOUCH_TAP &&
|
|
244
|
+
evt.detail.taps >= 2;
|
|
245
|
+
const doubleClick = evt.type === Events.MOUSE_DOUBLE_CLICK || doubleTap;
|
|
246
|
+
if (doubleTap &&
|
|
247
|
+
this.isTouchTapEchoOfLiftCommit(evt.detail.currentPoints.canvas)) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
237
250
|
const { annotation, viewportIdsToRender } = this.editData;
|
|
238
251
|
const { data } = annotation;
|
|
239
252
|
if (data.contour.closed) {
|
|
@@ -255,7 +268,10 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
255
268
|
if (data.handles.points.length >= 3) {
|
|
256
269
|
this.createMemo(element, annotation);
|
|
257
270
|
const { instance: spline } = data.spline;
|
|
258
|
-
const
|
|
271
|
+
const closeCurveDistance = isTouchEvent
|
|
272
|
+
? this.configuration.spline.touchCloseCurveDistance
|
|
273
|
+
: SPLINE_CLICK_CLOSE_CURVE_DIST;
|
|
274
|
+
const closestControlPoint = spline.getClosestControlPointWithinDistance(canvasPoint, closeCurveDistance);
|
|
259
275
|
if (closestControlPoint?.index === 0) {
|
|
260
276
|
addNewPoint = false;
|
|
261
277
|
closeContour = !this.configuration.allowOpenSplines;
|
|
@@ -275,6 +291,24 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
275
291
|
}
|
|
276
292
|
evt.preventDefault();
|
|
277
293
|
};
|
|
294
|
+
this._touchDragDuringDrawCallback = (evt) => {
|
|
295
|
+
if (evt.detail.currentPointsList.length > 1) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
this._mouseMoveCallback(evt);
|
|
299
|
+
};
|
|
300
|
+
this._touchEndDuringDrawCallback = (evt) => {
|
|
301
|
+
const { startPointsList, currentPointsList, startPoints, currentPoints } = evt.detail;
|
|
302
|
+
if (startPointsList.length > 1 || currentPointsList.length > 1) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const dragDistance = math.point.distanceToPoint(startPoints.canvas, currentPoints.canvas);
|
|
306
|
+
if (dragDistance <= _a.TOUCH_TAP_MAX_CANVAS_DISTANCE) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
this.recordTouchLiftCommit(currentPoints.canvas);
|
|
310
|
+
this._mouseDownCallback(evt);
|
|
311
|
+
};
|
|
278
312
|
this._dragCallback = (evt) => {
|
|
279
313
|
this.isDrawing = true;
|
|
280
314
|
const eventDetail = evt.detail;
|
|
@@ -343,6 +377,8 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
343
377
|
element.addEventListener(Events.MOUSE_DOWN, this._mouseDownCallback);
|
|
344
378
|
element.addEventListener(Events.MOUSE_DOUBLE_CLICK, this._mouseDownCallback);
|
|
345
379
|
element.addEventListener(Events.TOUCH_TAP, this._mouseDownCallback);
|
|
380
|
+
element.addEventListener(Events.TOUCH_DRAG, this._touchDragDuringDrawCallback);
|
|
381
|
+
element.addEventListener(Events.TOUCH_END, this._touchEndDuringDrawCallback);
|
|
346
382
|
};
|
|
347
383
|
this._deactivateDraw = (element) => {
|
|
348
384
|
state.isInteractingWithTool = false;
|
|
@@ -351,6 +387,8 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
351
387
|
element.removeEventListener(Events.MOUSE_DOWN, this._mouseDownCallback);
|
|
352
388
|
element.removeEventListener(Events.MOUSE_DOUBLE_CLICK, this._mouseDownCallback);
|
|
353
389
|
element.removeEventListener(Events.TOUCH_TAP, this._mouseDownCallback);
|
|
390
|
+
element.removeEventListener(Events.TOUCH_DRAG, this._touchDragDuringDrawCallback);
|
|
391
|
+
element.removeEventListener(Events.TOUCH_END, this._touchEndDuringDrawCallback);
|
|
354
392
|
};
|
|
355
393
|
this._renderStats = (annotation, enabledElement, svgDrawingHelper) => {
|
|
356
394
|
const data = annotation.data;
|
|
@@ -631,7 +669,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
631
669
|
});
|
|
632
670
|
}
|
|
633
671
|
else if (spline.numControlPoints > 1) {
|
|
634
|
-
const previewPolylinePoints = spline.getPreviewPolylinePoints(lastCanvasPoint, SPLINE_CLICK_CLOSE_CURVE_DIST);
|
|
672
|
+
const previewPolylinePoints = spline.getPreviewPolylinePoints(lastCanvasPoint, this.editData?.closeCurveDistance ?? SPLINE_CLICK_CLOSE_CURVE_DIST);
|
|
635
673
|
drawPolylineSvg(svgDrawingHelper, annotationUID, 'previewSplineChange', previewPolylinePoints, {
|
|
636
674
|
color: '#9EA0CA',
|
|
637
675
|
lineDash: lineDash,
|
|
@@ -40,8 +40,8 @@ class WholeBodySegmentTool extends GrowCutBaseTool {
|
|
|
40
40
|
const { element } = eventData;
|
|
41
41
|
const enabledElement = getEnabledElement(element);
|
|
42
42
|
const { viewport } = enabledElement;
|
|
43
|
-
await this.runGrowCut();
|
|
44
43
|
this._deactivateDraw(element);
|
|
44
|
+
await this.runGrowCut();
|
|
45
45
|
this.growCutData = null;
|
|
46
46
|
resetElementCursor(element);
|
|
47
47
|
triggerAnnotationRenderForViewportUIDs([viewport.id]);
|
|
@@ -50,6 +50,9 @@ class WholeBodySegmentTool extends GrowCutBaseTool {
|
|
|
50
50
|
element.removeEventListener(Events.MOUSE_UP, this._endCallback);
|
|
51
51
|
element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
52
52
|
element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
53
|
+
element.removeEventListener(Events.TOUCH_END, this._endCallback);
|
|
54
|
+
element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
55
|
+
element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
53
56
|
};
|
|
54
57
|
}
|
|
55
58
|
async preMouseDownCallback(evt) {
|
|
@@ -152,6 +155,9 @@ class WholeBodySegmentTool extends GrowCutBaseTool {
|
|
|
152
155
|
element.addEventListener(Events.MOUSE_UP, this._endCallback);
|
|
153
156
|
element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
154
157
|
element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
158
|
+
element.addEventListener(Events.TOUCH_END, this._endCallback);
|
|
159
|
+
element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
160
|
+
element.addEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
155
161
|
}
|
|
156
162
|
_projectWorldPointAcrossSlices(viewport, worldEdgePoint, vecDirection) {
|
|
157
163
|
const volume = this._getViewportVolume(viewport);
|
|
@@ -2,11 +2,16 @@ import { utilities as csUtils } from '@cornerstonejs/core';
|
|
|
2
2
|
import type { Types } from '@cornerstonejs/core';
|
|
3
3
|
import ToolModes from '../../enums/ToolModes.js';
|
|
4
4
|
import type StrategyCallbacks from '../../enums/StrategyCallbacks.js';
|
|
5
|
-
import type { InteractionTypes, ToolProps, PublicToolProps, ToolConfiguration, AnnotationData, MeasurementTargetCandidate } from '../../types/index.js';
|
|
5
|
+
import type { EventTypes, InteractionTypes, ToolProps, PublicToolProps, ToolConfiguration, AnnotationData, MeasurementTargetCandidate } from '../../types/index.js';
|
|
6
6
|
declare abstract class BaseTool {
|
|
7
7
|
static toolName: any;
|
|
8
8
|
static activeCursorTool: any;
|
|
9
|
+
static readonly TOUCH_PROXIMITY = 36;
|
|
10
|
+
static readonly MOUSE_PROXIMITY = 6;
|
|
11
|
+
static readonly TOUCH_TAP_MAX_CANVAS_DISTANCE = 24;
|
|
12
|
+
static readonly TOUCH_TAP_TOLERANCE_MS = 300;
|
|
9
13
|
supportedInteractionTypes: InteractionTypes[];
|
|
14
|
+
handlesMultiTouchGestures: boolean;
|
|
10
15
|
configuration: Record<string, any>;
|
|
11
16
|
get configurationTyped(): ToolConfiguration;
|
|
12
17
|
toolGroupId: string;
|
|
@@ -32,6 +37,7 @@ declare abstract class BaseTool {
|
|
|
32
37
|
applyActiveStrategyCallback(enabledElement: Types.IEnabledElement, operationData: unknown, callbackType: StrategyCallbacks | string, ...extraArgs: any[]): any;
|
|
33
38
|
setConfiguration(newConfiguration: Record<string, any>): void;
|
|
34
39
|
setActiveStrategy(strategyName: string): void;
|
|
40
|
+
protected _isTouchInteraction(evt?: EventTypes.InteractionEventType): boolean;
|
|
35
41
|
protected getTargetImageData(targetId: string): Types.IImageData | Types.CPUIImageData;
|
|
36
42
|
protected getTargetId(viewport: Types.IViewport, data?: AnnotationData): string | undefined;
|
|
37
43
|
protected getMeasurementTargets(viewport: Types.IViewport, data?: AnnotationData): string[];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { cache, metaData, utilities as csUtils, viewportHasPan, viewportHasZoom, } from '@cornerstonejs/core';
|
|
2
2
|
import ToolModes from '../../enums/ToolModes.js';
|
|
3
|
+
import Events from '../../enums/Events.js';
|
|
4
|
+
import { MOUSE_PROXIMITY, TOUCH_PROXIMITY, TOUCH_TAP_MAX_CANVAS_DISTANCE, TOUCH_TAP_TOLERANCE_MS, } from '../../utilities/touch/constants.js';
|
|
3
5
|
import measurementTargetFilters from './measurementTargetFilters.js';
|
|
4
6
|
const { DefaultHistoryMemo } = csUtils.HistoryMemo;
|
|
5
7
|
class BaseTool {
|
|
@@ -7,6 +9,7 @@ class BaseTool {
|
|
|
7
9
|
return this.configuration;
|
|
8
10
|
}
|
|
9
11
|
constructor(toolProps, defaultToolProps) {
|
|
12
|
+
this.handlesMultiTouchGestures = false;
|
|
10
13
|
this.isPrimary = false;
|
|
11
14
|
const mergedDefaults = BaseTool.mergeDefaultProps(BaseTool.defaults, defaultToolProps);
|
|
12
15
|
const initialProps = csUtils.deepMerge(mergedDefaults, toolProps);
|
|
@@ -50,6 +53,15 @@ class BaseTool {
|
|
|
50
53
|
setActiveStrategy(strategyName) {
|
|
51
54
|
this.setConfiguration({ activeStrategy: strategyName });
|
|
52
55
|
}
|
|
56
|
+
_isTouchInteraction(evt) {
|
|
57
|
+
const eventName = evt?.detail?.eventName;
|
|
58
|
+
return (eventName === Events.TOUCH_START ||
|
|
59
|
+
eventName === Events.TOUCH_START_ACTIVATE ||
|
|
60
|
+
eventName === Events.TOUCH_DRAG ||
|
|
61
|
+
eventName === Events.TOUCH_END ||
|
|
62
|
+
eventName === Events.TOUCH_TAP ||
|
|
63
|
+
eventName === Events.TOUCH_PRESS);
|
|
64
|
+
}
|
|
53
65
|
getTargetImageData(targetId) {
|
|
54
66
|
if (targetId.startsWith('imageId:')) {
|
|
55
67
|
const imageId = targetId.split('imageId:')[1];
|
|
@@ -293,6 +305,10 @@ class BaseTool {
|
|
|
293
305
|
return true;
|
|
294
306
|
}
|
|
295
307
|
}
|
|
308
|
+
BaseTool.TOUCH_PROXIMITY = TOUCH_PROXIMITY;
|
|
309
|
+
BaseTool.MOUSE_PROXIMITY = MOUSE_PROXIMITY;
|
|
310
|
+
BaseTool.TOUCH_TAP_MAX_CANVAS_DISTANCE = TOUCH_TAP_MAX_CANVAS_DISTANCE;
|
|
311
|
+
BaseTool.TOUCH_TAP_TOLERANCE_MS = TOUCH_TAP_TOLERANCE_MS;
|
|
296
312
|
BaseTool.defaults = {
|
|
297
313
|
configuration: {
|
|
298
314
|
strategies: {},
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
1
2
|
import type { Annotation, EventTypes, PublicToolProps, ToolProps, AnnotationRenderContext, Annotations } from '../../types/index.js';
|
|
2
3
|
import type { ContourAnnotation } from '../../types/ToolSpecificAnnotationTypes.js';
|
|
3
4
|
import type { StyleSpecifier } from '../../types/AnnotationStyle.js';
|
|
4
5
|
import ContourBaseTool from './ContourBaseTool.js';
|
|
5
6
|
declare abstract class ContourSegmentationBaseTool extends ContourBaseTool {
|
|
6
7
|
static PreviewSegmentIndex: number;
|
|
8
|
+
private _touchLiftCommit?;
|
|
7
9
|
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps);
|
|
10
|
+
protected recordTouchLiftCommit(canvasPoint: Types.Point2): void;
|
|
11
|
+
protected isTouchTapEchoOfLiftCommit(canvasPoint: Types.Point2): boolean;
|
|
8
12
|
protected onSetToolConfiguration(): void;
|
|
9
13
|
protected isContourSegmentationTool(): boolean;
|
|
10
14
|
protected createAnnotation(evt: EventTypes.InteractionEventType): ContourAnnotation;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getEnabledElement, utilities } from '@cornerstonejs/core';
|
|
2
|
+
import { distanceToPoint } from '../../utilities/math/point/index.js';
|
|
2
3
|
import { SegmentationRepresentations } from '../../enums/index.js';
|
|
3
4
|
import ContourBaseTool from './ContourBaseTool.js';
|
|
4
5
|
import { triggerSegmentationDataModified } from '../../stateManagement/segmentation/triggerSegmentationEvents.js';
|
|
@@ -20,6 +21,28 @@ class ContourSegmentationBaseTool extends ContourBaseTool {
|
|
|
20
21
|
InterpolationManager.addTool(this.getToolName());
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
recordTouchLiftCommit(canvasPoint) {
|
|
25
|
+
this._touchLiftCommit = { canvasPoint, time: Date.now() };
|
|
26
|
+
}
|
|
27
|
+
isTouchTapEchoOfLiftCommit(canvasPoint) {
|
|
28
|
+
if (!this._touchLiftCommit) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const { canvasPoint: committedPoint, time } = this._touchLiftCommit;
|
|
32
|
+
const withinTime = Date.now() - time <=
|
|
33
|
+
2 * ContourSegmentationBaseTool.TOUCH_TAP_TOLERANCE_MS;
|
|
34
|
+
if (!withinTime) {
|
|
35
|
+
this._touchLiftCommit = undefined;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const withinDistance = distanceToPoint(canvasPoint, committedPoint) <=
|
|
39
|
+
ContourSegmentationBaseTool.TOUCH_TAP_MAX_CANVAS_DISTANCE;
|
|
40
|
+
if (!withinDistance) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
this._touchLiftCommit = undefined;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
23
46
|
onSetToolConfiguration() {
|
|
24
47
|
if (this.configuration.interpolation?.enabled) {
|
|
25
48
|
InterpolationManager.addTool(this.getToolName());
|
|
@@ -4,6 +4,7 @@ import LabelmapBaseTool from './LabelmapBaseTool.js';
|
|
|
4
4
|
declare class BrushTool extends LabelmapBaseTool {
|
|
5
5
|
static toolName: any;
|
|
6
6
|
private _lastDragInfo;
|
|
7
|
+
private _drawStartTimeStamp;
|
|
7
8
|
private _lazyEdit;
|
|
8
9
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
9
10
|
onSetToolPassive: (_evt: any) => void;
|
|
@@ -20,7 +21,9 @@ declare class BrushTool extends LabelmapBaseTool {
|
|
|
20
21
|
mouseMoveCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
21
22
|
previewCallback: () => void;
|
|
22
23
|
protected updateCursor(evt: EventTypes.InteractionEventType): void;
|
|
24
|
+
private _clearCursor;
|
|
23
25
|
private _dragCallback;
|
|
26
|
+
protected _cancelTouchDraw(element: HTMLDivElement): void;
|
|
24
27
|
private _calculateCursor;
|
|
25
28
|
private _endCallback;
|
|
26
29
|
getStatistics(element: any, segmentIndices?: any): any;
|
|
@@ -83,6 +83,7 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
83
83
|
}) {
|
|
84
84
|
super(toolProps, defaultToolProps);
|
|
85
85
|
this._lastDragInfo = null;
|
|
86
|
+
this._drawStartTimeStamp = 0;
|
|
86
87
|
this._lazyEdit = new LazyBrushEditController();
|
|
87
88
|
this.onSetToolPassive = (_evt) => {
|
|
88
89
|
this.disableCursor();
|
|
@@ -113,6 +114,7 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
113
114
|
this._editData = this.createEditData(element);
|
|
114
115
|
this._previewData.isDrag = false;
|
|
115
116
|
this._previewData.timerStart = Date.now();
|
|
117
|
+
this._drawStartTimeStamp = eventData.event?.timeStamp ?? 0;
|
|
116
118
|
const canvasPoint = vec2.clone(currentPoints.canvas);
|
|
117
119
|
const worldPoint = viewport.canvasToWorld([
|
|
118
120
|
canvasPoint[0],
|
|
@@ -128,6 +130,7 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
128
130
|
return false;
|
|
129
131
|
}
|
|
130
132
|
this._calculateCursor(element, canvasPoint);
|
|
133
|
+
BrushTool.activeCursorTool = this;
|
|
131
134
|
this._resetLazyEditState();
|
|
132
135
|
if (this._isLazyLabelmapEditingEnabled(this._hoverData.viewport)) {
|
|
133
136
|
this._lazyEdit.appendStrokePoint(worldPoint);
|
|
@@ -217,6 +220,11 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
217
220
|
this._dragCallback = (evt) => {
|
|
218
221
|
const eventData = evt.detail;
|
|
219
222
|
const { element, currentPoints } = eventData;
|
|
223
|
+
const { currentPointsList } = eventData;
|
|
224
|
+
if (currentPointsList?.length > 1) {
|
|
225
|
+
this._cancelTouchDraw(element);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
220
228
|
const enabledElement = getEnabledElement(element);
|
|
221
229
|
const { viewport } = enabledElement;
|
|
222
230
|
this.updateCursor(evt);
|
|
@@ -286,6 +294,12 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
286
294
|
this._endCallback = (evt) => {
|
|
287
295
|
const eventData = evt.detail;
|
|
288
296
|
const { element } = eventData;
|
|
297
|
+
if (eventData.eventName === Events.TOUCH_TAP) {
|
|
298
|
+
const tapTimeStamp = eventData.event?.timeStamp ?? 0;
|
|
299
|
+
if (tapTimeStamp < this._drawStartTimeStamp) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
289
303
|
const enabledElement = getEnabledElement(element);
|
|
290
304
|
const operationData = this.getOperationData(element);
|
|
291
305
|
if (!operationData) {
|
|
@@ -307,12 +321,17 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
307
321
|
this._editData = null;
|
|
308
322
|
this._lastDragInfo = null;
|
|
309
323
|
if (isLazyLabelmapEditing && this._previewData.isDrag) {
|
|
310
|
-
this._scheduleLazyPreviewCleanup(element, evt.detail.currentPoints.canvas, enabledElement.viewport.id, operationData.segmentationId);
|
|
324
|
+
this._scheduleLazyPreviewCleanup(element, evt.detail.currentPoints.canvas, enabledElement.viewport.id, operationData.segmentationId, this._isTouchInteraction(evt));
|
|
311
325
|
triggerAnnotationRenderForViewportUIDs(this._hoverData.viewportIdsToRender);
|
|
312
326
|
}
|
|
313
327
|
else {
|
|
314
328
|
this._resetLazyEditState();
|
|
315
|
-
this.
|
|
329
|
+
if (this._isTouchInteraction(evt)) {
|
|
330
|
+
this._clearCursor(element);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
this.updateCursor(evt);
|
|
334
|
+
}
|
|
316
335
|
}
|
|
317
336
|
this.applyActiveStrategyCallback(enabledElement, operationData, StrategyCallbacks.OnInteractionEnd);
|
|
318
337
|
if (!this._previewData.isDrag) {
|
|
@@ -323,11 +342,17 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
323
342
|
element.addEventListener(Events.MOUSE_UP, this._endCallback);
|
|
324
343
|
element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
325
344
|
element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
345
|
+
element.addEventListener(Events.TOUCH_END, this._endCallback);
|
|
346
|
+
element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
347
|
+
element.addEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
326
348
|
};
|
|
327
349
|
this._deactivateDraw = (element) => {
|
|
328
350
|
element.removeEventListener(Events.MOUSE_UP, this._endCallback);
|
|
329
351
|
element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
330
352
|
element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
353
|
+
element.removeEventListener(Events.TOUCH_END, this._endCallback);
|
|
354
|
+
element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
355
|
+
element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
331
356
|
};
|
|
332
357
|
}
|
|
333
358
|
disableCursor() {
|
|
@@ -354,13 +379,15 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
354
379
|
BrushTool.activeCursorTool = this;
|
|
355
380
|
triggerAnnotationRenderForViewportUIDs(this._hoverData.viewportIdsToRender);
|
|
356
381
|
}
|
|
357
|
-
_scheduleLazyPreviewCleanup(element, centerCanvas, viewportId, segmentationId) {
|
|
382
|
+
_scheduleLazyPreviewCleanup(element, centerCanvas, viewportId, segmentationId, isTouch = false) {
|
|
358
383
|
this._lazyEdit.scheduleCleanup({
|
|
359
384
|
element,
|
|
360
385
|
centerCanvas,
|
|
361
386
|
viewportId,
|
|
362
387
|
segmentationId,
|
|
363
|
-
refreshCursor:
|
|
388
|
+
refreshCursor: isTouch
|
|
389
|
+
? (cleanupElement) => this._clearCursor(cleanupElement)
|
|
390
|
+
: this._refreshCursor.bind(this),
|
|
364
391
|
});
|
|
365
392
|
}
|
|
366
393
|
_captureLazyPreviewCircle() {
|
|
@@ -376,6 +403,37 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
376
403
|
const centerCanvas = currentPoints.canvas;
|
|
377
404
|
this._refreshCursor(element, centerCanvas);
|
|
378
405
|
}
|
|
406
|
+
_clearCursor(element) {
|
|
407
|
+
const viewportIdsToRender = this._hoverData?.viewportIdsToRender;
|
|
408
|
+
this._hoverData = undefined;
|
|
409
|
+
if (viewportIdsToRender?.length) {
|
|
410
|
+
triggerAnnotationRenderForViewportUIDs(viewportIdsToRender);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const enabledElement = getEnabledElement(element);
|
|
414
|
+
if (enabledElement) {
|
|
415
|
+
triggerAnnotationRenderForViewportUIDs([enabledElement.viewport.id]);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
_cancelTouchDraw(element) {
|
|
419
|
+
const { memo } = this;
|
|
420
|
+
if (memo?.commitMemo?.()) {
|
|
421
|
+
memo.restoreMemo(true);
|
|
422
|
+
}
|
|
423
|
+
this.memo = null;
|
|
424
|
+
this._deactivateDraw(element);
|
|
425
|
+
resetElementCursor(element);
|
|
426
|
+
this._editData = null;
|
|
427
|
+
this._lastDragInfo = null;
|
|
428
|
+
this._previewData.preview = null;
|
|
429
|
+
this._previewData.isDrag = false;
|
|
430
|
+
if (this._previewData.timer) {
|
|
431
|
+
window.clearTimeout(this._previewData.timer);
|
|
432
|
+
this._previewData.timer = null;
|
|
433
|
+
}
|
|
434
|
+
this._resetLazyEditState();
|
|
435
|
+
this._clearCursor(element);
|
|
436
|
+
}
|
|
379
437
|
_calculateCursor(element, _centerCanvas) {
|
|
380
438
|
const enabledElement = getEnabledElement(element);
|
|
381
439
|
const operationData = this.getOperationData(element);
|
|
@@ -123,9 +123,14 @@ class CircleScissorsTool extends LabelmapBaseTool {
|
|
|
123
123
|
return true;
|
|
124
124
|
};
|
|
125
125
|
this._dragCallback = (evt) => {
|
|
126
|
-
this.isDrawing = true;
|
|
127
126
|
const eventDetail = evt.detail;
|
|
128
127
|
const { element } = eventDetail;
|
|
128
|
+
const { currentPointsList } = eventDetail;
|
|
129
|
+
if (currentPointsList?.length > 1) {
|
|
130
|
+
this._cancelTouchDraw(element);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this.isDrawing = true;
|
|
129
134
|
const { currentPoints } = eventDetail;
|
|
130
135
|
const currentCanvasPoints = currentPoints.canvas;
|
|
131
136
|
const enabledElement = getEnabledElement(element);
|
|
@@ -58,6 +58,10 @@ export default class LabelmapBaseTool extends BaseTool {
|
|
|
58
58
|
viewport: Types.IViewport;
|
|
59
59
|
};
|
|
60
60
|
static previewData?: PreviewData;
|
|
61
|
+
protected isDrawing?: boolean;
|
|
62
|
+
protected editData?: {
|
|
63
|
+
viewportIdsToRender?: string[];
|
|
64
|
+
} | null;
|
|
61
65
|
protected memoMap: Map<string, LabelmapMemo.LabelmapMemo>;
|
|
62
66
|
protected acceptedMemoIds: Map<string, {
|
|
63
67
|
element: HTMLDivElement;
|
|
@@ -65,6 +69,7 @@ export default class LabelmapBaseTool extends BaseTool {
|
|
|
65
69
|
}>;
|
|
66
70
|
protected memo: LabelmapMemo.LabelmapMemo;
|
|
67
71
|
constructor(toolProps: any, defaultToolProps: any);
|
|
72
|
+
protected _cancelTouchDraw(element: HTMLDivElement): void;
|
|
68
73
|
protected _historyRedoHandler(evt: any): void;
|
|
69
74
|
protected get _previewData(): PreviewData;
|
|
70
75
|
hasPreviewData(): boolean;
|
|
@@ -17,6 +17,8 @@ import { fillInsideCircle } from './strategies/index.js';
|
|
|
17
17
|
import getViewportLabelmapRenderMode from '../../stateManagement/segmentation/helpers/getViewportLabelmapRenderMode.js';
|
|
18
18
|
import { getOrCreateLabelmapVolume, resolveLabelmapForSegment, } from '../../stateManagement/segmentation/helpers/labelmapSegmentationState.js';
|
|
19
19
|
import getViewportICamera from '../../utilities/getViewportICamera.js';
|
|
20
|
+
import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds.js';
|
|
21
|
+
import { resetElementCursor } from '../../cursors/elementCursor.js';
|
|
20
22
|
class LabelmapBaseTool extends BaseTool {
|
|
21
23
|
constructor(toolProps, defaultToolProps) {
|
|
22
24
|
super(toolProps, defaultToolProps);
|
|
@@ -29,6 +31,19 @@ class LabelmapBaseTool extends BaseTool {
|
|
|
29
31
|
changedIndices: [],
|
|
30
32
|
};
|
|
31
33
|
}
|
|
34
|
+
_cancelTouchDraw(element) {
|
|
35
|
+
if (!this.isDrawing) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const viewportIdsToRender = this.editData?.viewportIdsToRender;
|
|
39
|
+
this._deactivateDraw(element);
|
|
40
|
+
resetElementCursor(element);
|
|
41
|
+
this.editData = null;
|
|
42
|
+
this.isDrawing = false;
|
|
43
|
+
if (viewportIdsToRender) {
|
|
44
|
+
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
_historyRedoHandler(evt) {
|
|
33
48
|
const { id, operationType } = evt.detail;
|
|
34
49
|
if (operationType !== 'labelmap') {
|
|
@@ -20,6 +20,7 @@ import { getPixelValueUnits } from '../../utilities/getPixelValueUnits.js';
|
|
|
20
20
|
const { transformWorldToIndex } = csUtils;
|
|
21
21
|
class RectangleROIStartEndThresholdTool extends RectangleROITool {
|
|
22
22
|
constructor(toolProps = {}, defaultToolProps = {
|
|
23
|
+
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
23
24
|
configuration: {
|
|
24
25
|
storePointData: false,
|
|
25
26
|
numSlicesToPropagate: 10,
|
|
@@ -115,9 +115,14 @@ class RectangleScissorsTool extends LabelmapBaseTool {
|
|
|
115
115
|
return true;
|
|
116
116
|
};
|
|
117
117
|
this._dragCallback = (evt) => {
|
|
118
|
-
this.isDrawing = true;
|
|
119
118
|
const eventDetail = evt.detail;
|
|
120
119
|
const { element } = eventDetail;
|
|
120
|
+
const { currentPointsList } = eventDetail;
|
|
121
|
+
if (currentPointsList?.length > 1) {
|
|
122
|
+
this._cancelTouchDraw(element);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.isDrawing = true;
|
|
121
126
|
const { annotation, viewportIdsToRender, handleIndex } = this.editData;
|
|
122
127
|
const { data } = annotation;
|
|
123
128
|
const { currentPoints } = eventDetail;
|
|
@@ -9,7 +9,7 @@ import { state } from '../../store/state.js';
|
|
|
9
9
|
import { ToolModes } from '../../enums/index.js';
|
|
10
10
|
class SegmentSelectTool extends BaseTool {
|
|
11
11
|
constructor(toolProps = {}, defaultToolProps = {
|
|
12
|
-
supportedInteractionTypes: ['Mouse'
|
|
12
|
+
supportedInteractionTypes: ['Mouse'],
|
|
13
13
|
configuration: {
|
|
14
14
|
hoverTimeout: 100,
|
|
15
15
|
mode: SegmentSelectTool.SelectMode.Border,
|
|
@@ -110,9 +110,14 @@ class SphereScissorsTool extends LabelmapBaseTool {
|
|
|
110
110
|
return true;
|
|
111
111
|
};
|
|
112
112
|
this._dragCallback = (evt) => {
|
|
113
|
-
this.isDrawing = true;
|
|
114
113
|
const eventDetail = evt.detail;
|
|
115
114
|
const { element } = eventDetail;
|
|
115
|
+
const { currentPointsList } = eventDetail;
|
|
116
|
+
if (currentPointsList?.length > 1) {
|
|
117
|
+
this._cancelTouchDraw(element);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
this.isDrawing = true;
|
|
116
121
|
const { currentPoints } = eventDetail;
|
|
117
122
|
const currentCanvasPoints = currentPoints.canvas;
|
|
118
123
|
const enabledElement = getEnabledElement(element);
|
|
@@ -7,4 +7,6 @@ declare function copyPointsList(points: ITouchPoints[]): ITouchPoints[];
|
|
|
7
7
|
declare function copyPoints(points: ITouchPoints): ITouchPoints;
|
|
8
8
|
declare function getMeanPoints(points: IPoints[]): IPoints;
|
|
9
9
|
declare function getMeanTouchPoints(points: ITouchPoints[]): ITouchPoints;
|
|
10
|
-
|
|
10
|
+
declare function isMobile(): boolean;
|
|
11
|
+
export { getMeanPoints, getMeanTouchPoints, copyPoints, copyPointsList, getDeltaDistanceBetweenIPoints, getDeltaPoints, getDeltaDistance, getDeltaRotation, isMobile, };
|
|
12
|
+
export { TOUCH_PROXIMITY, MOUSE_PROXIMITY, TOUCH_TAP_MAX_CANVAS_DISTANCE, TOUCH_TAP_TOLERANCE_MS, } from './constants.js';
|
|
@@ -150,4 +150,10 @@ function _getDistance3D(point0, point1) {
|
|
|
150
150
|
Math.pow(point0[1] - point1[1], 2) +
|
|
151
151
|
Math.pow(point0[2] - point1[2], 2));
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
function isMobile() {
|
|
154
|
+
return (typeof window !== 'undefined' &&
|
|
155
|
+
typeof window.matchMedia === 'function' &&
|
|
156
|
+
window.matchMedia('(any-pointer:coarse)').matches);
|
|
157
|
+
}
|
|
158
|
+
export { getMeanPoints, getMeanTouchPoints, copyPoints, copyPointsList, getDeltaDistanceBetweenIPoints, getDeltaPoints, getDeltaDistance, getDeltaRotation, isMobile, };
|
|
159
|
+
export { TOUCH_PROXIMITY, MOUSE_PROXIMITY, TOUCH_TAP_MAX_CANVAS_DISTANCE, TOUCH_TAP_TOLERANCE_MS, } from './constants.js';
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "5.
|
|
1
|
+
export declare const version = "5.7.0";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.
|
|
1
|
+
export const version = '5.7.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"types": "./dist/esm/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -126,11 +126,11 @@
|
|
|
126
126
|
"lodash.get": "4.4.2"
|
|
127
127
|
},
|
|
128
128
|
"devDependencies": {
|
|
129
|
-
"@cornerstonejs/core": "5.
|
|
129
|
+
"@cornerstonejs/core": "5.7.0",
|
|
130
130
|
"canvas": "3.2.0"
|
|
131
131
|
},
|
|
132
132
|
"peerDependencies": {
|
|
133
|
-
"@cornerstonejs/core": "5.
|
|
133
|
+
"@cornerstonejs/core": "5.7.0",
|
|
134
134
|
"@kitware/vtk.js": "36.4.1",
|
|
135
135
|
"@types/d3-array": "3.2.1",
|
|
136
136
|
"@types/d3-interpolate": "3.0.4",
|
|
@@ -149,5 +149,5 @@
|
|
|
149
149
|
"type": "individual",
|
|
150
150
|
"url": "https://ohif.org/donate"
|
|
151
151
|
},
|
|
152
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "49e9ce38a3d34844f5b5a58e0e796469b7ea50bd"
|
|
153
153
|
}
|