@cornerstonejs/tools 5.6.14 → 5.7.1
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
|
@@ -14,6 +14,7 @@ import getViewportICamera from '../utilities/getViewportICamera.js';
|
|
|
14
14
|
import { resetElementCursor, hideElementCursor, } from '../cursors/elementCursor.js';
|
|
15
15
|
import liangBarksyClip from '../utilities/math/vec2/liangBarksyClip.js';
|
|
16
16
|
import { getSlabThicknessOrDefault, jumpToFocalPoint, } from '../utilities/genericViewportToolHelpers.js';
|
|
17
|
+
import { isMobile } from '../utilities/touch/index.js';
|
|
17
18
|
import * as lineSegment from '../utilities/math/line/index.js';
|
|
18
19
|
import { isAnnotationLocked } from '../stateManagement/annotation/annotationLocking.js';
|
|
19
20
|
import triggerAnnotationRenderForViewportIds from '../utilities/triggerAnnotationRenderForViewportIds.js';
|
|
@@ -48,7 +49,7 @@ const OPERATION = {
|
|
|
48
49
|
};
|
|
49
50
|
class CrosshairsTool extends AnnotationTool {
|
|
50
51
|
constructor(toolProps = {}, defaultToolProps = {
|
|
51
|
-
supportedInteractionTypes: ['Mouse'],
|
|
52
|
+
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
52
53
|
configuration: {
|
|
53
54
|
shadow: true,
|
|
54
55
|
viewportIndicators: false,
|
|
@@ -77,7 +78,7 @@ class CrosshairsTool extends AnnotationTool {
|
|
|
77
78
|
size: 2,
|
|
78
79
|
},
|
|
79
80
|
mobile: {
|
|
80
|
-
enabled:
|
|
81
|
+
enabled: isMobile(),
|
|
81
82
|
opacity: 0.8,
|
|
82
83
|
handleRadius: 9,
|
|
83
84
|
referenceLinesCenterGapRatio: 0.05,
|
|
@@ -231,7 +232,7 @@ class CrosshairsTool extends AnnotationTool {
|
|
|
231
232
|
data.handles.activeOperation = OPERATION.DRAG;
|
|
232
233
|
evt.preventDefault();
|
|
233
234
|
hideElementCursor(element);
|
|
234
|
-
this._activateModify(element);
|
|
235
|
+
this._activateModify(element, evt);
|
|
235
236
|
return filteredAnnotations[0];
|
|
236
237
|
};
|
|
237
238
|
this.cancel = () => {
|
|
@@ -241,12 +242,12 @@ class CrosshairsTool extends AnnotationTool {
|
|
|
241
242
|
const eventDetail = evt.detail;
|
|
242
243
|
const { element } = eventDetail;
|
|
243
244
|
annotation.highlighted = true;
|
|
244
|
-
this._activateModify(element);
|
|
245
|
+
this._activateModify(element, evt);
|
|
245
246
|
hideElementCursor(element);
|
|
246
247
|
evt.preventDefault();
|
|
247
248
|
};
|
|
248
249
|
this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
|
|
249
|
-
if (this._pointNearTool(element, annotation, canvasCoords,
|
|
250
|
+
if (this._pointNearTool(element, annotation, canvasCoords, proximity)) {
|
|
250
251
|
return true;
|
|
251
252
|
}
|
|
252
253
|
return false;
|
|
@@ -255,7 +256,7 @@ class CrosshairsTool extends AnnotationTool {
|
|
|
255
256
|
const eventDetail = evt.detail;
|
|
256
257
|
const { element } = eventDetail;
|
|
257
258
|
annotation.highlighted = true;
|
|
258
|
-
this._activateModify(element);
|
|
259
|
+
this._activateModify(element, evt);
|
|
259
260
|
hideElementCursor(element);
|
|
260
261
|
evt.preventDefault();
|
|
261
262
|
};
|
|
@@ -959,13 +960,13 @@ class CrosshairsTool extends AnnotationTool {
|
|
|
959
960
|
state.isInteractingWithTool = false;
|
|
960
961
|
return true;
|
|
961
962
|
};
|
|
962
|
-
this._activateModify = (element) => {
|
|
963
|
+
this._activateModify = (element, evt) => {
|
|
963
964
|
this._syncVolumeListenersWithToolGroup();
|
|
964
965
|
this._recomputeToolCenterFromAbsoluteCameras({
|
|
965
966
|
emitEvent: false,
|
|
966
967
|
updateViewportCameras: false,
|
|
967
968
|
});
|
|
968
|
-
state.isInteractingWithTool = !this.configuration.mobile?.enabled;
|
|
969
|
+
state.isInteractingWithTool = !(this._isTouchInteraction(evt) && this.configuration.mobile?.enabled);
|
|
969
970
|
element.addEventListener(Events.MOUSE_UP, this._endCallback);
|
|
970
971
|
element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
971
972
|
element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
@@ -9,12 +9,14 @@ declare class MagnifyTool extends BaseTool {
|
|
|
9
9
|
enabledElement: Types.IEnabledElement;
|
|
10
10
|
renderingEngine: Types.IRenderingEngine;
|
|
11
11
|
currentPoints: IPoints;
|
|
12
|
+
isTouch: boolean;
|
|
12
13
|
} | null;
|
|
13
14
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
14
15
|
private _hasBeenRemoved;
|
|
15
16
|
_getReferencedImageId(viewport: Types.IViewport): string | undefined;
|
|
16
17
|
preMouseDownCallback: (evt: EventTypes.InteractionEventType) => boolean;
|
|
17
18
|
preTouchStartCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
19
|
+
private _positionMagnifyElement;
|
|
18
20
|
_createMagnificationViewport: () => void;
|
|
19
21
|
_cancelCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
20
22
|
_dragCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
@@ -15,6 +15,7 @@ class MagnifyTool extends BaseTool {
|
|
|
15
15
|
magnifySize: 10,
|
|
16
16
|
magnifyWidth: 250,
|
|
17
17
|
magnifyHeight: 250,
|
|
18
|
+
touchOffset: 40,
|
|
18
19
|
},
|
|
19
20
|
}) {
|
|
20
21
|
super(toolProps, defaultToolProps);
|
|
@@ -33,12 +34,14 @@ class MagnifyTool extends BaseTool {
|
|
|
33
34
|
throw new Error('MagnifyTool: No referenced image id found, reconstructed planes not supported yet');
|
|
34
35
|
}
|
|
35
36
|
const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
|
|
37
|
+
const isTouch = evt.type === Events.TOUCH_START;
|
|
36
38
|
this.editData = {
|
|
37
39
|
referencedImageId,
|
|
38
40
|
viewportIdsToRender,
|
|
39
41
|
enabledElement,
|
|
40
42
|
renderingEngine,
|
|
41
43
|
currentPoints,
|
|
44
|
+
isTouch,
|
|
42
45
|
};
|
|
43
46
|
this._createMagnificationViewport();
|
|
44
47
|
this._activateDraw(element);
|
|
@@ -50,6 +53,20 @@ class MagnifyTool extends BaseTool {
|
|
|
50
53
|
this.preTouchStartCallback = (evt) => {
|
|
51
54
|
this.preMouseDownCallback(evt);
|
|
52
55
|
};
|
|
56
|
+
this._positionMagnifyElement = (magnifyElement, canvasPos, element) => {
|
|
57
|
+
const { magnifyWidth, magnifyHeight, touchOffset } = this.configuration;
|
|
58
|
+
let left = canvasPos[0] - magnifyWidth / 2;
|
|
59
|
+
let top = canvasPos[1] - magnifyHeight / 2;
|
|
60
|
+
if (this.editData?.isTouch) {
|
|
61
|
+
top = canvasPos[1] - magnifyHeight - (touchOffset ?? 0);
|
|
62
|
+
const maxLeft = Math.max(element.clientWidth - magnifyWidth, 0);
|
|
63
|
+
const maxTop = Math.max(element.clientHeight - magnifyHeight, 0);
|
|
64
|
+
left = Math.min(Math.max(left, 0), maxLeft);
|
|
65
|
+
top = Math.min(Math.max(top, 0), maxTop);
|
|
66
|
+
}
|
|
67
|
+
magnifyElement.style.top = `${top}px`;
|
|
68
|
+
magnifyElement.style.left = `${left}px`;
|
|
69
|
+
};
|
|
53
70
|
this._createMagnificationViewport = () => {
|
|
54
71
|
const { enabledElement, referencedImageId, viewportIdsToRender, renderingEngine, currentPoints, } = this.editData;
|
|
55
72
|
const { viewport } = enabledElement;
|
|
@@ -81,8 +98,7 @@ class MagnifyTool extends BaseTool {
|
|
|
81
98
|
};
|
|
82
99
|
renderingEngine.enableElement(viewportInput);
|
|
83
100
|
}
|
|
84
|
-
magnifyToolElement
|
|
85
|
-
magnifyToolElement.style.left = `${canvasPos[0] - this.configuration.magnifyWidth / 2}px`;
|
|
101
|
+
this._positionMagnifyElement(magnifyToolElement, canvasPos, element);
|
|
86
102
|
const magnifyViewport = renderingEngine.getViewport(MAGNIFY_VIEWPORT_ID);
|
|
87
103
|
magnifyViewport.setStack([referencedImageId]).then(() => {
|
|
88
104
|
if (this._hasBeenRemoved) {
|
|
@@ -146,8 +162,7 @@ class MagnifyTool extends BaseTool {
|
|
|
146
162
|
if (!magnifyElement) {
|
|
147
163
|
return;
|
|
148
164
|
}
|
|
149
|
-
magnifyElement
|
|
150
|
-
magnifyElement.style.left = `${canvasPos[0] - this.configuration.magnifyWidth / 2}px`;
|
|
165
|
+
this._positionMagnifyElement(magnifyElement, canvasPos, element);
|
|
151
166
|
const { focalPoint, position } = magnifyViewport.getCamera();
|
|
152
167
|
const updatedPosition = [
|
|
153
168
|
position[0] + deltaPointsWorld[0],
|
|
@@ -37,13 +37,20 @@ class TrackballRotateTool extends BaseTool {
|
|
|
37
37
|
this._hasResolutionChanged = true;
|
|
38
38
|
if (this.cleanUp !== null) {
|
|
39
39
|
document.removeEventListener('mouseup', this.cleanUp);
|
|
40
|
+
document.removeEventListener('touchend', this.cleanUp);
|
|
41
|
+
document.removeEventListener('touchcancel', this.cleanUp);
|
|
40
42
|
}
|
|
41
43
|
this.cleanUp = () => {
|
|
44
|
+
document.removeEventListener('mouseup', this.cleanUp);
|
|
45
|
+
document.removeEventListener('touchend', this.cleanUp);
|
|
46
|
+
document.removeEventListener('touchcancel', this.cleanUp);
|
|
42
47
|
mapper.setSampleDistance(originalSampleDistance);
|
|
43
48
|
viewport.render();
|
|
44
49
|
this._hasResolutionChanged = false;
|
|
45
50
|
};
|
|
46
51
|
document.addEventListener('mouseup', this.cleanUp, { once: true });
|
|
52
|
+
document.addEventListener('touchend', this.cleanUp, { once: true });
|
|
53
|
+
document.addEventListener('touchcancel', this.cleanUp, { once: true });
|
|
47
54
|
}
|
|
48
55
|
return true;
|
|
49
56
|
};
|
|
@@ -17,6 +17,7 @@ import { isDragOwnedBy } from '../utilities/interactionDragCoordinator.js';
|
|
|
17
17
|
import { applyViewportPresentation, getViewportPresentation, } from '../utilities/viewportPresentation.js';
|
|
18
18
|
class VolumeCroppingTool extends BaseTool {
|
|
19
19
|
constructor(toolProps = {}, defaultToolProps = {
|
|
20
|
+
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
20
21
|
configuration: {
|
|
21
22
|
showCornerSpheres: true,
|
|
22
23
|
showHandles: true,
|
|
@@ -125,8 +126,13 @@ class VolumeCroppingTool extends BaseTool {
|
|
|
125
126
|
this._hasResolutionChanged = true;
|
|
126
127
|
if (this.cleanUp !== null) {
|
|
127
128
|
document.removeEventListener('mouseup', this.cleanUp);
|
|
129
|
+
document.removeEventListener('touchend', this.cleanUp);
|
|
130
|
+
document.removeEventListener('touchcancel', this.cleanUp);
|
|
128
131
|
}
|
|
129
132
|
this.cleanUp = () => {
|
|
133
|
+
document.removeEventListener('mouseup', this.cleanUp);
|
|
134
|
+
document.removeEventListener('touchend', this.cleanUp);
|
|
135
|
+
document.removeEventListener('touchcancel', this.cleanUp);
|
|
130
136
|
mapper.setSampleDistance(originalSampleDistance);
|
|
131
137
|
evt.target.style.cursor = '';
|
|
132
138
|
if (this.draggingSphereIndex !== null) {
|
|
@@ -148,6 +154,8 @@ class VolumeCroppingTool extends BaseTool {
|
|
|
148
154
|
this._hasResolutionChanged = false;
|
|
149
155
|
};
|
|
150
156
|
document.addEventListener('mouseup', this.cleanUp, { once: true });
|
|
157
|
+
document.addEventListener('touchend', this.cleanUp, { once: true });
|
|
158
|
+
document.addEventListener('touchcancel', this.cleanUp, { once: true });
|
|
151
159
|
}
|
|
152
160
|
return true;
|
|
153
161
|
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { BaseTool } from './base/index.js';
|
|
2
|
-
import type { PublicToolProps, ToolProps } from '../types/index.js';
|
|
2
|
+
import type { EventTypes, PublicToolProps, ToolProps } from '../types/index.js';
|
|
3
3
|
import type { MouseWheelEventType } from '../types/EventTypes.js';
|
|
4
4
|
declare class VolumeRotateTool extends BaseTool {
|
|
5
5
|
static toolName: any;
|
|
6
6
|
_configuration: unknown;
|
|
7
7
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
8
8
|
mouseWheelCallback(evt: MouseWheelEventType): void;
|
|
9
|
+
mouseDragCallback(evt: EventTypes.InteractionEventType): void;
|
|
10
|
+
touchDragCallback(evt: EventTypes.InteractionEventType): void;
|
|
11
|
+
_dragCallback(evt: EventTypes.InteractionEventType): void;
|
|
12
|
+
_rotate(element: HTMLDivElement, angle: number): void;
|
|
9
13
|
}
|
|
10
14
|
export default VolumeRotateTool;
|
|
@@ -15,21 +15,42 @@ class VolumeRotateTool extends BaseTool {
|
|
|
15
15
|
configuration: {
|
|
16
16
|
direction: DIRECTIONS.Z,
|
|
17
17
|
rotateIncrementDegrees: 30,
|
|
18
|
+
rotateDragDegreesPerPixel: 0.5,
|
|
18
19
|
},
|
|
19
20
|
}) {
|
|
20
21
|
super(toolProps, defaultToolProps);
|
|
21
22
|
}
|
|
22
23
|
mouseWheelCallback(evt) {
|
|
23
24
|
const { element, wheel } = evt.detail;
|
|
25
|
+
const { rotateIncrementDegrees } = this.configuration;
|
|
26
|
+
const { direction: deltaY } = wheel;
|
|
27
|
+
const angle = (deltaY * (rotateIncrementDegrees * Math.PI)) / 180;
|
|
28
|
+
this._rotate(element, angle);
|
|
29
|
+
}
|
|
30
|
+
mouseDragCallback(evt) {
|
|
31
|
+
this._dragCallback(evt);
|
|
32
|
+
}
|
|
33
|
+
touchDragCallback(evt) {
|
|
34
|
+
this._dragCallback(evt);
|
|
35
|
+
}
|
|
36
|
+
_dragCallback(evt) {
|
|
37
|
+
const { element, deltaPoints } = evt.detail;
|
|
38
|
+
const { rotateDragDegreesPerPixel } = this.configuration;
|
|
39
|
+
const deltaX = deltaPoints.canvas[0];
|
|
40
|
+
if (!deltaX) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const angle = (deltaX * rotateDragDegreesPerPixel * Math.PI) / 180;
|
|
44
|
+
this._rotate(element, angle);
|
|
45
|
+
}
|
|
46
|
+
_rotate(element, angle) {
|
|
24
47
|
const enabledElement = getEnabledElement(element);
|
|
25
48
|
const { viewport } = enabledElement;
|
|
26
|
-
const { direction
|
|
49
|
+
const { direction } = this.configuration;
|
|
27
50
|
const camera = getViewportICamera(viewport);
|
|
28
51
|
const { viewUp, position, focalPoint } = camera;
|
|
29
|
-
const { direction: deltaY } = wheel;
|
|
30
52
|
const [cx, cy, cz] = focalPoint;
|
|
31
53
|
const [ax, ay, az] = direction;
|
|
32
|
-
const angle = (deltaY * (rotateIncrementDegrees * Math.PI)) / 180;
|
|
33
54
|
const newPosition = [0, 0, 0];
|
|
34
55
|
const newFocalPoint = [0, 0, 0];
|
|
35
56
|
const newViewUp = [0, 0, 0];
|
|
@@ -30,7 +30,7 @@ declare class ArrowAnnotateTool extends AnnotationTool {
|
|
|
30
30
|
_endCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
31
31
|
_dragCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
32
32
|
touchTapCallback: (evt: EventTypes.TouchTapEventType) => void;
|
|
33
|
-
doubleClickCallback: (evt: EventTypes.TouchTapEventType) => void;
|
|
33
|
+
doubleClickCallback: (evt: EventTypes.TouchTapEventType, proximity?: number) => void;
|
|
34
34
|
_doneChangingTextCallback(element: any, annotation: any, updatedLabel: any): void;
|
|
35
35
|
cancel: (element: HTMLDivElement) => string;
|
|
36
36
|
_activateModify: (element: HTMLDivElement) => void;
|
|
@@ -181,10 +181,10 @@ class ArrowAnnotateTool extends AnnotationTool {
|
|
|
181
181
|
};
|
|
182
182
|
this.touchTapCallback = (evt) => {
|
|
183
183
|
if (evt.detail.taps == 2) {
|
|
184
|
-
this.doubleClickCallback(evt);
|
|
184
|
+
this.doubleClickCallback(evt, _a.TOUCH_PROXIMITY);
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
|
-
this.doubleClickCallback = (evt) => {
|
|
187
|
+
this.doubleClickCallback = (evt, proximity = _a.MOUSE_PROXIMITY) => {
|
|
188
188
|
const eventDetail = evt.detail;
|
|
189
189
|
const { element } = eventDetail;
|
|
190
190
|
let annotations = getAnnotations(this.getToolName(), element);
|
|
@@ -192,7 +192,7 @@ class ArrowAnnotateTool extends AnnotationTool {
|
|
|
192
192
|
if (!annotations?.length) {
|
|
193
193
|
return;
|
|
194
194
|
}
|
|
195
|
-
const clickedAnnotation = annotations.find((annotation) => this.isPointNearTool(element, annotation, eventDetail.currentPoints.canvas,
|
|
195
|
+
const clickedAnnotation = annotations.find((annotation) => this.isPointNearTool(element, annotation, eventDetail.currentPoints.canvas, proximity));
|
|
196
196
|
if (!clickedAnnotation) {
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
@@ -36,6 +36,7 @@ declare class ClickSegmentTool extends GrowCutBaseTool {
|
|
|
36
36
|
private runConfinementDryRun;
|
|
37
37
|
private probeAppliesToClick;
|
|
38
38
|
preMouseDownCallback(evt: EventTypes.MouseDownActivateEventType): Promise<boolean>;
|
|
39
|
+
preTouchStartCallback: (evt: EventTypes.TouchStartEventType) => Promise<boolean>;
|
|
39
40
|
private runClick;
|
|
40
41
|
private fillWithRange;
|
|
41
42
|
private indexToWorld;
|
|
@@ -52,6 +52,20 @@ class ClickSegmentTool extends GrowCutBaseTool {
|
|
|
52
52
|
this.dryRunToken = null;
|
|
53
53
|
this.confirmedRegion = null;
|
|
54
54
|
this.rejectedRegions = [];
|
|
55
|
+
this.preTouchStartCallback = async (evt) => {
|
|
56
|
+
if (this.mode !== ToolModes.Active || this.segmentationInProgress) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
await this.runHoverProbe(evt);
|
|
60
|
+
if (this.lastProbe && !this.lastProbe.ok) {
|
|
61
|
+
growCutLog.info('tap ignored: probe reported no proper region', {
|
|
62
|
+
canvasPoint: this.lastProbe.canvas,
|
|
63
|
+
});
|
|
64
|
+
this.notifySegmentationError('No meaningful region at the tapped location; nothing was segmented.');
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return this.preMouseDownCallback(evt);
|
|
68
|
+
};
|
|
55
69
|
}
|
|
56
70
|
notifySegmentationError(message) {
|
|
57
71
|
const event = new CustomEvent(CoreEnums.Events.ERROR_EVENT, {
|
|
@@ -2,6 +2,7 @@ import { getEnabledElement } from '@cornerstonejs/core';
|
|
|
2
2
|
import { drawHandles as drawHandlesSvg, drawTextBox as drawTextBoxSvg, } from '../../drawingSvg/index.js';
|
|
3
3
|
import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters/index.js';
|
|
4
4
|
import { hideElementCursor } from '../../cursors/elementCursor.js';
|
|
5
|
+
import { Events } from '../../enums/index.js';
|
|
5
6
|
import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds.js';
|
|
6
7
|
import getViewportICamera from '../../utilities/getViewportICamera.js';
|
|
7
8
|
import ProbeTool from './ProbeTool.js';
|
|
@@ -18,9 +19,10 @@ class DragProbeTool extends ProbeTool {
|
|
|
18
19
|
this.postMouseDownCallback = (evt) => {
|
|
19
20
|
const eventDetail = evt.detail;
|
|
20
21
|
const { currentPoints, element } = eventDetail;
|
|
21
|
-
const worldPos = currentPoints.world;
|
|
22
22
|
const enabledElement = getEnabledElement(element);
|
|
23
23
|
const { viewport } = enabledElement;
|
|
24
|
+
const isTouch = evt.type === Events.TOUCH_START;
|
|
25
|
+
const worldPos = this.getTouchAdjustedWorldPos(viewport, currentPoints, isTouch);
|
|
24
26
|
this.isDrawing = true;
|
|
25
27
|
const camera = getViewportICamera(viewport);
|
|
26
28
|
const { viewPlaneNormal, viewUp } = camera;
|
|
@@ -29,6 +29,7 @@ declare class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
29
29
|
contourHoleProcessingEnabled?: boolean;
|
|
30
30
|
} | null;
|
|
31
31
|
isDrawing: boolean;
|
|
32
|
+
handlesMultiTouchGestures: boolean;
|
|
32
33
|
isHandleOutsideImage: boolean;
|
|
33
34
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
34
35
|
protected setupBaseEditData(worldPos: any, element: any, annotation: any, nextPos?: any, contourHoleProcessingEnabled?: any): void;
|
|
@@ -41,6 +42,8 @@ declare class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
41
42
|
triggerChangeEvent: (annotation: LivewireContourAnnotation, enabledElement: Types.IEnabledElement, changeType?: ChangeTypes, contourHoleProcessingEnabled?: boolean) => void;
|
|
42
43
|
private _mouseDownCallback;
|
|
43
44
|
private _mouseMoveCallback;
|
|
45
|
+
private _touchDragDuringDrawCallback;
|
|
46
|
+
private _touchEndDuringDrawCallback;
|
|
44
47
|
editHandle(worldPos: Types.Point3, element: any, annotation: LivewireContourAnnotation, handleIndex: number): void;
|
|
45
48
|
protected _dragCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
46
49
|
cancel: (element: HTMLDivElement) => string;
|
|
@@ -25,6 +25,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
25
25
|
preventHandleOutsideImage: false,
|
|
26
26
|
contourHoleAdditionModifierKey: KeyboardBindings.Shift,
|
|
27
27
|
snapHandleNearby: 2,
|
|
28
|
+
touchCloseCurveDistance: 36,
|
|
28
29
|
interpolation: {
|
|
29
30
|
enabled: false,
|
|
30
31
|
nearestEdge: 2,
|
|
@@ -47,6 +48,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
47
48
|
},
|
|
48
49
|
}) {
|
|
49
50
|
super(toolProps, defaultToolProps);
|
|
51
|
+
this.handlesMultiTouchGestures = true;
|
|
50
52
|
this.isHandleOutsideImage = false;
|
|
51
53
|
this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
|
|
52
54
|
const enabledElement = getEnabledElement(element);
|
|
@@ -137,7 +139,14 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
137
139
|
}
|
|
138
140
|
};
|
|
139
141
|
this._mouseDownCallback = (evt) => {
|
|
140
|
-
const
|
|
142
|
+
const isTouchEvent = evt.type === Events.TOUCH_TAP || evt.type === Events.TOUCH_END;
|
|
143
|
+
const doubleTap = evt.type === Events.TOUCH_TAP &&
|
|
144
|
+
evt.detail.taps >= 2;
|
|
145
|
+
const doubleClick = evt.type === Events.MOUSE_DOUBLE_CLICK || doubleTap;
|
|
146
|
+
if (doubleTap &&
|
|
147
|
+
this.isTouchTapEchoOfLiftCommit(evt.detail.currentPoints.canvas)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
141
150
|
const { annotation, viewportIdsToRender, worldToSlice, sliceToWorld, newAnnotation, } = this.editData;
|
|
142
151
|
if (this.editData.closed) {
|
|
143
152
|
return;
|
|
@@ -160,12 +169,15 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
160
169
|
index: -1,
|
|
161
170
|
distSquared: Infinity,
|
|
162
171
|
};
|
|
172
|
+
const closeDistSquared = isTouchEvent
|
|
173
|
+
? this.configuration.touchCloseCurveDistance ** 2
|
|
174
|
+
: CLICK_CLOSE_CURVE_SQR_DIST;
|
|
163
175
|
for (let i = 0, len = controlPoints.length; i < len; i++) {
|
|
164
176
|
const controlPoint = controlPoints[i];
|
|
165
177
|
const worldControlPoint = sliceToWorld(controlPoint);
|
|
166
178
|
const canvasControlPoint = viewport.worldToCanvas(worldControlPoint);
|
|
167
179
|
const distSquared = math.point.distanceToPointSquared(canvasPos, canvasControlPoint);
|
|
168
|
-
if (distSquared <=
|
|
180
|
+
if (distSquared <= closeDistSquared &&
|
|
169
181
|
distSquared < closestHandlePoint.distSquared) {
|
|
170
182
|
closestHandlePoint.distSquared = distSquared;
|
|
171
183
|
closestHandlePoint.index = i;
|
|
@@ -224,6 +236,24 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
224
236
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
225
237
|
evt.preventDefault();
|
|
226
238
|
};
|
|
239
|
+
this._touchDragDuringDrawCallback = (evt) => {
|
|
240
|
+
if (evt.detail.currentPointsList.length > 1) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this._mouseMoveCallback(evt);
|
|
244
|
+
};
|
|
245
|
+
this._touchEndDuringDrawCallback = (evt) => {
|
|
246
|
+
const { startPointsList, currentPointsList, startPoints, currentPoints } = evt.detail;
|
|
247
|
+
if (startPointsList.length > 1 || currentPointsList.length > 1) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const dragDistance = math.point.distanceToPoint(startPoints.canvas, currentPoints.canvas);
|
|
251
|
+
if (dragDistance <= LivewireContourTool.TOUCH_TAP_MAX_CANVAS_DISTANCE) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this.recordTouchLiftCommit(currentPoints.canvas);
|
|
255
|
+
this._mouseDownCallback(evt);
|
|
256
|
+
};
|
|
227
257
|
this._dragCallback = (evt) => {
|
|
228
258
|
this.isDrawing = true;
|
|
229
259
|
const eventDetail = evt.detail;
|
|
@@ -274,6 +304,8 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
274
304
|
element.addEventListener(Events.MOUSE_DOWN, this._mouseDownCallback);
|
|
275
305
|
element.addEventListener(Events.MOUSE_DOUBLE_CLICK, this._mouseDownCallback);
|
|
276
306
|
element.addEventListener(Events.TOUCH_TAP, this._mouseDownCallback);
|
|
307
|
+
element.addEventListener(Events.TOUCH_DRAG, this._touchDragDuringDrawCallback);
|
|
308
|
+
element.addEventListener(Events.TOUCH_END, this._touchEndDuringDrawCallback);
|
|
277
309
|
};
|
|
278
310
|
this._deactivateDraw = (element) => {
|
|
279
311
|
state.isInteractingWithTool = false;
|
|
@@ -281,6 +313,8 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
281
313
|
element.removeEventListener(Events.MOUSE_DOWN, this._mouseDownCallback);
|
|
282
314
|
element.removeEventListener(Events.MOUSE_DOUBLE_CLICK, this._mouseDownCallback);
|
|
283
315
|
element.removeEventListener(Events.TOUCH_TAP, this._mouseDownCallback);
|
|
316
|
+
element.removeEventListener(Events.TOUCH_DRAG, this._touchDragDuringDrawCallback);
|
|
317
|
+
element.removeEventListener(Events.TOUCH_END, this._touchEndDuringDrawCallback);
|
|
284
318
|
};
|
|
285
319
|
this._calculateCachedStats = (annotation, element) => {
|
|
286
320
|
if (!this.configuration.calculateStats) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import { AnnotationTool } from '../base/index.js';
|
|
3
3
|
import { ChangeTypes } from '../../enums/index.js';
|
|
4
|
-
import type { EventTypes, ToolHandle, PublicToolProps, SVGDrawingHelper } from '../../types/index.js';
|
|
4
|
+
import type { EventTypes, ToolHandle, PublicToolProps, SVGDrawingHelper, InteractionTypes } from '../../types/index.js';
|
|
5
5
|
import type { ProbeAnnotation } from '../../types/ToolSpecificAnnotationTypes.js';
|
|
6
6
|
declare class ProbeTool extends AnnotationTool {
|
|
7
7
|
static toolName: string;
|
|
@@ -16,6 +16,10 @@ declare class ProbeTool extends AnnotationTool {
|
|
|
16
16
|
x: number;
|
|
17
17
|
y: number;
|
|
18
18
|
};
|
|
19
|
+
touchCanvasOffset: {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
};
|
|
19
23
|
};
|
|
20
24
|
};
|
|
21
25
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: any);
|
|
@@ -28,8 +32,12 @@ declare class ProbeTool extends AnnotationTool {
|
|
|
28
32
|
viewplaneNormal?: Types.Point3;
|
|
29
33
|
viewUp?: Types.Point3;
|
|
30
34
|
}) => ProbeAnnotation;
|
|
31
|
-
addNewAnnotation: (evt: EventTypes.InteractionEventType) => ProbeAnnotation;
|
|
35
|
+
addNewAnnotation: (evt: EventTypes.InteractionEventType, interactionType?: InteractionTypes) => ProbeAnnotation;
|
|
32
36
|
getHandleNearImagePoint(element: HTMLDivElement, annotation: ProbeAnnotation, canvasCoords: Types.Point2, proximity: number): ToolHandle | undefined;
|
|
37
|
+
protected getTouchAdjustedWorldPos(viewport: Types.IViewport, currentPoints: {
|
|
38
|
+
canvas: Types.Point2;
|
|
39
|
+
world: Types.Point3;
|
|
40
|
+
}, isTouch: boolean): Types.Point3;
|
|
33
41
|
handleSelectedCallback(evt: EventTypes.InteractionEventType, annotation: ProbeAnnotation): void;
|
|
34
42
|
_endCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
35
43
|
_dragCallback: (evt: any) => void;
|
|
@@ -20,12 +20,13 @@ const { transformWorldToIndex } = csUtils;
|
|
|
20
20
|
class ProbeTool extends AnnotationTool {
|
|
21
21
|
constructor(toolProps = {}, defaultToolProps) {
|
|
22
22
|
super(toolProps, AnnotationTool.mergeDefaultProps(_a.probeDefaults, defaultToolProps));
|
|
23
|
-
this.addNewAnnotation = (evt) => {
|
|
23
|
+
this.addNewAnnotation = (evt, interactionType = 'Mouse') => {
|
|
24
24
|
const eventDetail = evt.detail;
|
|
25
25
|
const { currentPoints, element } = eventDetail;
|
|
26
|
-
const worldPos = currentPoints.world;
|
|
27
26
|
const enabledElement = getEnabledElement(element);
|
|
28
27
|
const { viewport } = enabledElement;
|
|
28
|
+
const isTouch = interactionType.toLowerCase() === 'touch';
|
|
29
|
+
const worldPos = this.getTouchAdjustedWorldPos(viewport, currentPoints, isTouch);
|
|
29
30
|
this.isDrawing = true;
|
|
30
31
|
const annotation = (this.constructor).createAnnotationForViewport(viewport, {
|
|
31
32
|
data: {
|
|
@@ -75,7 +76,9 @@ class ProbeTool extends AnnotationTool {
|
|
|
75
76
|
this.isDrawing = true;
|
|
76
77
|
const eventDetail = evt.detail;
|
|
77
78
|
const { currentPoints, element } = eventDetail;
|
|
78
|
-
const
|
|
79
|
+
const { viewport } = getEnabledElement(element);
|
|
80
|
+
const isTouch = evt.type === Events.TOUCH_DRAG;
|
|
81
|
+
const worldPos = this.getTouchAdjustedWorldPos(viewport, currentPoints, isTouch);
|
|
79
82
|
const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
|
|
80
83
|
const { data } = annotation;
|
|
81
84
|
this.createMemo(element, annotation, { newAnnotation });
|
|
@@ -231,6 +234,18 @@ class ProbeTool extends AnnotationTool {
|
|
|
231
234
|
return point;
|
|
232
235
|
}
|
|
233
236
|
}
|
|
237
|
+
getTouchAdjustedWorldPos(viewport, currentPoints, isTouch) {
|
|
238
|
+
const { touchCanvasOffset } = this.configuration;
|
|
239
|
+
if (!isTouch || !touchCanvasOffset) {
|
|
240
|
+
return currentPoints.world;
|
|
241
|
+
}
|
|
242
|
+
const { x = 0, y = 0 } = touchCanvasOffset;
|
|
243
|
+
if (!x && !y) {
|
|
244
|
+
return currentPoints.world;
|
|
245
|
+
}
|
|
246
|
+
const [canvasX, canvasY] = currentPoints.canvas;
|
|
247
|
+
return viewport.canvasToWorld([canvasX + x, canvasY + y]);
|
|
248
|
+
}
|
|
234
249
|
handleSelectedCallback(evt, annotation) {
|
|
235
250
|
const eventDetail = evt.detail;
|
|
236
251
|
const { element } = eventDetail;
|
|
@@ -336,6 +351,10 @@ ProbeTool.probeDefaults = {
|
|
|
336
351
|
x: 6,
|
|
337
352
|
y: -6,
|
|
338
353
|
},
|
|
354
|
+
touchCanvasOffset: {
|
|
355
|
+
x: 0,
|
|
356
|
+
y: -40,
|
|
357
|
+
},
|
|
339
358
|
},
|
|
340
359
|
};
|
|
341
360
|
ProbeTool.hydrate = (viewportId, points, options) => {
|
|
@@ -40,6 +40,9 @@ class RegionSegmentTool extends GrowCutBaseTool {
|
|
|
40
40
|
element.removeEventListener(Events.MOUSE_UP, this._endCallback);
|
|
41
41
|
element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
42
42
|
element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
43
|
+
element.removeEventListener(Events.TOUCH_END, this._endCallback);
|
|
44
|
+
element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
45
|
+
element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
async preMouseDownCallback(evt) {
|
|
@@ -84,6 +87,9 @@ class RegionSegmentTool extends GrowCutBaseTool {
|
|
|
84
87
|
element.addEventListener(Events.MOUSE_UP, this._endCallback);
|
|
85
88
|
element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
|
|
86
89
|
element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
|
|
90
|
+
element.addEventListener(Events.TOUCH_END, this._endCallback);
|
|
91
|
+
element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
|
|
92
|
+
element.addEventListener(Events.TOUCH_TAP, this._endCallback);
|
|
87
93
|
}
|
|
88
94
|
renderAnnotation(enabledElement, svgDrawingHelper) {
|
|
89
95
|
if (!this.growCutData) {
|
|
@@ -28,9 +28,11 @@ declare class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
28
28
|
newAnnotation?: boolean;
|
|
29
29
|
hasMoved?: boolean;
|
|
30
30
|
lastCanvasPoint?: Types.Point2;
|
|
31
|
+
closeCurveDistance?: number;
|
|
31
32
|
contourHoleProcessingEnabled?: boolean;
|
|
32
33
|
} | null;
|
|
33
34
|
isDrawing: boolean;
|
|
35
|
+
handlesMultiTouchGestures: boolean;
|
|
34
36
|
isHandleOutsideImage: boolean;
|
|
35
37
|
fireChangeOnUpdate: {
|
|
36
38
|
annotationUID: string;
|
|
@@ -52,6 +54,8 @@ declare class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
52
54
|
private _keyDownCallback;
|
|
53
55
|
private _mouseMoveCallback;
|
|
54
56
|
private _mouseDownCallback;
|
|
57
|
+
private _touchDragDuringDrawCallback;
|
|
58
|
+
private _touchEndDuringDrawCallback;
|
|
55
59
|
protected _dragCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
56
60
|
cancel(element: HTMLDivElement): string;
|
|
57
61
|
triggerAnnotationCompleted: (annotation: SplineROIAnnotation, contourHoleProcessingEnabled: boolean) => void;
|