@cornerstonejs/tools 5.6.14 → 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.
Files changed (58) hide show
  1. package/dist/esm/eventDispatchers/shared/getTouchCallbackWithMouseFallback.d.ts +1 -0
  2. package/dist/esm/eventDispatchers/shared/getTouchCallbackWithMouseFallback.js +24 -0
  3. package/dist/esm/eventDispatchers/shared/releaseToolForMultiTouchGesture.d.ts +2 -0
  4. package/dist/esm/eventDispatchers/shared/releaseToolForMultiTouchGesture.js +30 -0
  5. package/dist/esm/eventDispatchers/touchEventHandlers/touchDrag.js +7 -4
  6. package/dist/esm/eventDispatchers/touchEventHandlers/touchStart.js +7 -4
  7. package/dist/esm/eventDispatchers/touchEventHandlers/touchStartActivate.js +7 -2
  8. package/dist/esm/eventDispatchers/touchEventHandlers/touchTap.d.ts +2 -2
  9. package/dist/esm/eventDispatchers/touchEventHandlers/touchTap.js +29 -3
  10. package/dist/esm/eventDispatchers/touchToolEventDispatcher.js +1 -0
  11. package/dist/esm/eventListeners/touch/touchStartListener.js +7 -2
  12. package/dist/esm/store/ToolGroupManager/ToolGroup.js +1 -1
  13. package/dist/esm/store/filterMoveableAnnotationTools.js +2 -1
  14. package/dist/esm/store/filterToolsWithMoveableHandles.js +2 -1
  15. package/dist/esm/tools/AdvancedMagnifyTool.d.ts +11 -4
  16. package/dist/esm/tools/AdvancedMagnifyTool.js +141 -7
  17. package/dist/esm/tools/CrosshairsTool.d.ts +1 -1
  18. package/dist/esm/tools/CrosshairsTool.js +9 -8
  19. package/dist/esm/tools/MagnifyTool.d.ts +2 -0
  20. package/dist/esm/tools/MagnifyTool.js +19 -4
  21. package/dist/esm/tools/TrackballRotateTool.js +7 -0
  22. package/dist/esm/tools/VolumeCroppingTool.js +8 -0
  23. package/dist/esm/tools/VolumeRotateTool.d.ts +5 -1
  24. package/dist/esm/tools/VolumeRotateTool.js +24 -3
  25. package/dist/esm/tools/annotation/ArrowAnnotateTool.d.ts +1 -1
  26. package/dist/esm/tools/annotation/ArrowAnnotateTool.js +3 -3
  27. package/dist/esm/tools/annotation/ClickSegmentTool.d.ts +1 -0
  28. package/dist/esm/tools/annotation/ClickSegmentTool.js +14 -0
  29. package/dist/esm/tools/annotation/DragProbeTool.js +3 -1
  30. package/dist/esm/tools/annotation/LivewireContourTool.d.ts +3 -0
  31. package/dist/esm/tools/annotation/LivewireContourTool.js +36 -2
  32. package/dist/esm/tools/annotation/ProbeTool.d.ts +10 -2
  33. package/dist/esm/tools/annotation/ProbeTool.js +22 -3
  34. package/dist/esm/tools/annotation/RegionSegmentTool.js +6 -0
  35. package/dist/esm/tools/annotation/SplineROITool.d.ts +4 -0
  36. package/dist/esm/tools/annotation/SplineROITool.js +41 -3
  37. package/dist/esm/tools/annotation/WholeBodySegmentTool.js +7 -1
  38. package/dist/esm/tools/base/BaseTool.d.ts +7 -1
  39. package/dist/esm/tools/base/BaseTool.js +16 -0
  40. package/dist/esm/tools/base/ContourSegmentationBaseTool.d.ts +4 -0
  41. package/dist/esm/tools/base/ContourSegmentationBaseTool.js +23 -0
  42. package/dist/esm/tools/segmentation/BrushTool.d.ts +3 -0
  43. package/dist/esm/tools/segmentation/BrushTool.js +62 -4
  44. package/dist/esm/tools/segmentation/CircleScissorsTool.js +6 -1
  45. package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +5 -0
  46. package/dist/esm/tools/segmentation/LabelmapBaseTool.js +15 -0
  47. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +1 -0
  48. package/dist/esm/tools/segmentation/RectangleScissorsTool.js +6 -1
  49. package/dist/esm/tools/segmentation/SegmentLabelTool.js +1 -1
  50. package/dist/esm/tools/segmentation/SegmentSelectTool.js +1 -1
  51. package/dist/esm/tools/segmentation/SphereScissorsTool.js +6 -1
  52. package/dist/esm/utilities/touch/constants.d.ts +4 -0
  53. package/dist/esm/utilities/touch/constants.js +4 -0
  54. package/dist/esm/utilities/touch/index.d.ts +3 -1
  55. package/dist/esm/utilities/touch/index.js +7 -1
  56. package/dist/esm/version.d.ts +1 -1
  57. package/dist/esm/version.js +1 -1
  58. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ export default function getTouchCallbackWithMouseFallback(tool: any, touchCallbackName: string, mouseCallbackName: string): ((evt: any) => unknown) | undefined;
@@ -0,0 +1,24 @@
1
+ import { MouseBindings } from '../../enums/index.js';
2
+ function augmentTouchDetailForMouseCallback(detail) {
3
+ detail.mouseButton ??= MouseBindings.Primary;
4
+ detail.startPoints ??= detail.currentPoints;
5
+ detail.lastPoints ??= detail.currentPoints;
6
+ detail.deltaPoints ??= {
7
+ page: [0, 0],
8
+ client: [0, 0],
9
+ canvas: [0, 0],
10
+ world: [0, 0, 0],
11
+ };
12
+ }
13
+ export default function getTouchCallbackWithMouseFallback(tool, touchCallbackName, mouseCallbackName) {
14
+ if (typeof tool?.[touchCallbackName] === 'function') {
15
+ return (evt) => tool[touchCallbackName](evt);
16
+ }
17
+ if (tool?.supportedInteractionTypes?.includes('Touch') &&
18
+ typeof tool[mouseCallbackName] === 'function') {
19
+ return (evt) => {
20
+ augmentTouchDetailForMouseCallback(evt.detail);
21
+ return tool[mouseCallbackName](evt);
22
+ };
23
+ }
24
+ }
@@ -0,0 +1,2 @@
1
+ import type { EventTypes } from '../../types/index.js';
2
+ export default function releaseToolForMultiTouchGesture(evt: EventTypes.TouchDragEventType): boolean;
@@ -0,0 +1,30 @@
1
+ import { state } from '../../store/state.js';
2
+ import { getToolGroupForViewport } from '../../store/ToolGroupManager/index.js';
3
+ export default function releaseToolForMultiTouchGesture(evt) {
4
+ if (!state.isInteractingWithTool) {
5
+ return false;
6
+ }
7
+ if (!(evt.detail.currentPointsList?.length > 1)) {
8
+ return false;
9
+ }
10
+ const { renderingEngineId, viewportId, element } = evt.detail;
11
+ const toolGroup = getToolGroupForViewport(viewportId, renderingEngineId);
12
+ if (!toolGroup) {
13
+ return false;
14
+ }
15
+ let bypassInteractionGuard = false;
16
+ for (const toolName of Object.keys(toolGroup.toolOptions)) {
17
+ const tool = toolGroup.getToolInstance(toolName);
18
+ if (!tool) {
19
+ continue;
20
+ }
21
+ if (tool.handlesMultiTouchGestures) {
22
+ if (tool.isDrawing) {
23
+ bypassInteractionGuard = true;
24
+ }
25
+ continue;
26
+ }
27
+ tool.cancel?.(element);
28
+ }
29
+ return bypassInteractionGuard;
30
+ }
@@ -1,13 +1,16 @@
1
1
  import getActiveToolForTouchEvent from '../shared/getActiveToolForTouchEvent.js';
2
+ import getTouchCallbackWithMouseFallback from '../shared/getTouchCallbackWithMouseFallback.js';
3
+ import releaseToolForMultiTouchGesture from '../shared/releaseToolForMultiTouchGesture.js';
2
4
  import { state } from '../../store/state.js';
3
5
  export default function touchDrag(evt) {
4
- if (state.isInteractingWithTool) {
6
+ const bypassInteractionGuard = releaseToolForMultiTouchGesture(evt);
7
+ if (state.isInteractingWithTool && !bypassInteractionGuard) {
5
8
  return;
6
9
  }
7
10
  const activeTool = getActiveToolForTouchEvent(evt);
8
- const noFoundToolOrDoesNotHaveTouchDragCallback = !activeTool || typeof activeTool.touchDragCallback !== 'function';
9
- if (noFoundToolOrDoesNotHaveTouchDragCallback) {
11
+ const dragCallback = getTouchCallbackWithMouseFallback(activeTool, 'touchDragCallback', 'mouseDragCallback');
12
+ if (!dragCallback) {
10
13
  return;
11
14
  }
12
- activeTool.touchDragCallback(evt);
15
+ dragCallback(evt);
13
16
  }
@@ -7,6 +7,7 @@ import filterToolsWithMoveableHandles from '../../store/filterToolsWithMoveableH
7
7
  import filterToolsWithAnnotationsForElement from '../../store/filterToolsWithAnnotationsForElement.js';
8
8
  import filterMoveableAnnotationTools from '../../store/filterMoveableAnnotationTools.js';
9
9
  import getActiveToolForTouchEvent from '../shared/getActiveToolForTouchEvent.js';
10
+ import getTouchCallbackWithMouseFallback from '../shared/getTouchCallbackWithMouseFallback.js';
10
11
  import getToolsWithModesForTouchEvent from '../shared/getToolsWithModesForTouchEvent.js';
11
12
  const { Active, Passive } = ToolModes;
12
13
  export default function touchStart(evt) {
@@ -14,8 +15,9 @@ export default function touchStart(evt) {
14
15
  return;
15
16
  }
16
17
  const activeTool = getActiveToolForTouchEvent(evt);
17
- if (activeTool && typeof activeTool.preTouchStartCallback === 'function') {
18
- const consumedEvent = activeTool.preTouchStartCallback(evt);
18
+ const preCallback = getTouchCallbackWithMouseFallback(activeTool, 'preTouchStartCallback', 'preMouseDownCallback');
19
+ if (preCallback) {
20
+ const consumedEvent = preCallback(evt);
19
21
  if (consumedEvent) {
20
22
  return;
21
23
  }
@@ -45,8 +47,9 @@ export default function touchStart(evt) {
45
47
  tool.toolSelectedCallback(evt, annotation, 'Touch', canvasCoords);
46
48
  return;
47
49
  }
48
- if (activeTool && typeof activeTool.postTouchStartCallback === 'function') {
49
- const consumedEvent = activeTool.postTouchStartCallback(evt);
50
+ const postCallback = getTouchCallbackWithMouseFallback(activeTool, 'postTouchStartCallback', 'postMouseDownCallback');
51
+ if (postCallback) {
52
+ const consumedEvent = postCallback(evt);
50
53
  if (consumedEvent) {
51
54
  return;
52
55
  }
@@ -13,7 +13,12 @@ export default function touchStartActivate(evt) {
13
13
  return;
14
14
  }
15
15
  if (activeTool.addNewAnnotation) {
16
- const annotation = activeTool.addNewAnnotation(evt, 'touch');
17
- setAnnotationSelected(annotation.annotationUID);
16
+ try {
17
+ const annotation = activeTool.addNewAnnotation(evt, 'touch');
18
+ setAnnotationSelected(annotation.annotationUID);
19
+ }
20
+ catch (error) {
21
+ console.warn('Error adding new annotation, viewport not ready:', error);
22
+ }
18
23
  }
19
24
  }
@@ -1,2 +1,2 @@
1
- declare const touchTap: (evt: any) => boolean;
2
- export default touchTap;
1
+ import type { EventTypes } from '../../types/index.js';
2
+ export default function touchTap(evt: EventTypes.TouchTapEventType): void;
@@ -1,3 +1,29 @@
1
- import customCallbackHandler from '../shared/customCallbackHandler.js';
2
- const touchTap = customCallbackHandler.bind(null, 'Touch', 'touchTapCallback');
3
- export default touchTap;
1
+ import { state } from '../../store/state.js';
2
+ import ToolModes from '../../enums/ToolModes.js';
3
+ import { getToolGroupForViewport } from '../../store/ToolGroupManager/index.js';
4
+ import getTouchCallbackWithMouseFallback from '../shared/getTouchCallbackWithMouseFallback.js';
5
+ const { Active } = ToolModes;
6
+ export default function touchTap(evt) {
7
+ if (state.isInteractingWithTool) {
8
+ return;
9
+ }
10
+ const { renderingEngineId, viewportId } = evt.detail;
11
+ const toolGroup = getToolGroupForViewport(viewportId, renderingEngineId);
12
+ if (!toolGroup) {
13
+ return;
14
+ }
15
+ const toolGroupToolNames = Object.keys(toolGroup.toolOptions);
16
+ for (let j = 0; j < toolGroupToolNames.length; j++) {
17
+ const toolName = toolGroupToolNames[j];
18
+ const toolOptions = toolGroup.toolOptions[toolName];
19
+ if (toolOptions.mode !== Active) {
20
+ continue;
21
+ }
22
+ const toolInstance = toolGroup.getToolInstance(toolName);
23
+ const tapCallback = getTouchCallbackWithMouseFallback(toolInstance, 'touchTapCallback', 'mouseClickCallback');
24
+ if (tapCallback) {
25
+ tapCallback(evt);
26
+ return;
27
+ }
28
+ }
29
+ }
@@ -13,6 +13,7 @@ const disable = function (element) {
13
13
  element.removeEventListener(Events.TOUCH_START_ACTIVATE, touchStartActivate);
14
14
  element.removeEventListener(Events.TOUCH_DRAG, touchDrag);
15
15
  element.removeEventListener(Events.TOUCH_END, touchEnd);
16
+ element.removeEventListener(Events.TOUCH_TAP, touchTap);
16
17
  element.removeEventListener(Events.TOUCH_PRESS, touchPress);
17
18
  };
18
19
  const touchToolEventDispatcher = {
@@ -3,6 +3,7 @@ import Events from '../../enums/Events.js';
3
3
  import { Swipe } from '../../enums/Touch.js';
4
4
  import getTouchEventPoints from './getTouchEventPoints.js';
5
5
  import { copyPoints, copyPointsList, getDeltaDistanceBetweenIPoints, getDeltaDistance, getDeltaPoints, getMeanTouchPoints, } from '../../utilities/touch/index.js';
6
+ import { TOUCH_TAP_MAX_CANVAS_DISTANCE, TOUCH_TAP_TOLERANCE_MS, } from '../../utilities/touch/constants.js';
6
7
  import { Settings } from '@cornerstonejs/core';
7
8
  const runtimeSettings = Settings.getRuntimeSettings();
8
9
  const { TOUCH_START, TOUCH_START_ACTIVATE, TOUCH_PRESS, TOUCH_DRAG, TOUCH_END, TOUCH_TAP, TOUCH_SWIPE, } = Events;
@@ -56,8 +57,8 @@ const defaultTapState = {
56
57
  ],
57
58
  taps: 0,
58
59
  tapTimeout: null,
59
- tapMaxDistance: 24,
60
- tapToleranceMs: 300,
60
+ tapMaxDistance: TOUCH_TAP_MAX_CANVAS_DISTANCE,
61
+ tapToleranceMs: TOUCH_TAP_TOLERANCE_MS,
61
62
  };
62
63
  let state = utilities.deepClone(defaultState);
63
64
  let tapState = utilities.deepClone(defaultTapState);
@@ -224,6 +225,10 @@ function _checkTouchTap(evt) {
224
225
  clearTimeout(tapState.tapTimeout);
225
226
  tapState.taps += 1;
226
227
  tapState.tapTimeout = setTimeout(() => {
228
+ if (state.isTouchStart) {
229
+ tapState = utilities.deepClone(defaultTapState);
230
+ return;
231
+ }
227
232
  const eventDetail = {
228
233
  event: evt,
229
234
  eventName: TOUCH_TAP,
@@ -407,7 +407,7 @@ export default class ToolGroup {
407
407
  const sourceToolMode = sourceToolInstance.mode;
408
408
  toolGroup.addTool(toolName);
409
409
  toolGroup.setToolMode(toolName, sourceToolMode, {
410
- bindings: sourceToolOptions.bindings ?? [],
410
+ bindings: sourceToolOptions?.bindings ?? [],
411
411
  });
412
412
  });
413
413
  return toolGroup;
@@ -1,5 +1,6 @@
1
+ import { MOUSE_PROXIMITY, TOUCH_PROXIMITY } from '../utilities/touch/constants.js';
1
2
  export default function filterMoveableAnnotationTools(element, ToolAndAnnotations, canvasCoords, interactionType = 'mouse') {
2
- const proximity = interactionType === 'touch' ? 36 : 6;
3
+ const proximity = interactionType === 'touch' ? TOUCH_PROXIMITY : MOUSE_PROXIMITY;
3
4
  const moveableAnnotationTools = [];
4
5
  ToolAndAnnotations.forEach(({ tool, annotations }) => {
5
6
  for (const annotation of annotations) {
@@ -1,5 +1,6 @@
1
+ import { MOUSE_PROXIMITY, TOUCH_PROXIMITY } from '../utilities/touch/constants.js';
1
2
  export default function filterToolsWithMoveableHandles(element, ToolAndAnnotations, canvasCoords, interactionType = 'mouse') {
2
- const proximity = interactionType === 'touch' ? 36 : 6;
3
+ const proximity = interactionType === 'touch' ? TOUCH_PROXIMITY : MOUSE_PROXIMITY;
3
4
  const toolsWithMoveableHandles = [];
4
5
  ToolAndAnnotations.forEach(({ tool, annotations }) => {
5
6
  for (const annotation of annotations) {
@@ -55,18 +55,20 @@ declare class AdvancedMagnifyTool extends AnnotationTool {
55
55
  constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
56
56
  addNewAnnotation: (evt: EventTypes.InteractionEventType) => AdvancedMagnifyAnnotation;
57
57
  onSetToolDisabled: () => void;
58
- isPointNearTool: (element: HTMLDivElement, annotation: AdvancedMagnifyAnnotation, canvasCoords: Types.Point2, proximity: number) => boolean;
58
+ isPointNearTool: (element: HTMLDivElement, annotation: AdvancedMagnifyAnnotation, canvasCoords: Types.Point2, proximity: number, interactionType?: string) => boolean;
59
59
  toolSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: AdvancedMagnifyAnnotation) => void;
60
60
  handleSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: AdvancedMagnifyAnnotation, handle: ToolHandle) => void;
61
- _endCallback: (evt: EventTypes.InteractionEventType) => void;
61
+ _endCallback: (evt: EventTypes.InteractionEventType | EventTypes.TouchPressEventType) => void;
62
62
  _dragDrawCallback: (evt: EventTypes.InteractionEventType) => void;
63
63
  _dragModifyCallback: (evt: EventTypes.InteractionEventType) => void;
64
+ _pressModifyCallback: (evt: EventTypes.TouchPressEventType) => void;
64
65
  _dragHandle: (evt: EventTypes.InteractionEventType) => void;
65
66
  cancel: (element: HTMLDivElement) => string;
66
67
  _activateModify: (element: any) => void;
67
68
  _deactivateModify: (element: any) => void;
68
69
  renderAnnotation: (enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
69
- showZoomFactorsList(evt: EventTypes.InteractionEventType, annotation: AdvancedMagnifyAnnotation): void;
70
+ showZoomFactorsList(evt: EventTypes.InteractionEventType | EventTypes.TouchPressEventType, annotation: AdvancedMagnifyAnnotation): void;
71
+ touchPressCallback: (evt: EventTypes.TouchPressEventType) => void;
70
72
  private _getZoomFactorsListDropdown;
71
73
  private _getWorldHandlePoints;
72
74
  private _getCanvasCircleData;
@@ -85,11 +87,12 @@ declare class AdvancedMagnifyViewport {
85
87
  private _resized;
86
88
  private _resizeViewportAsync;
87
89
  private _canAutoPan;
90
+ private _annotation;
88
91
  private _autoPan;
89
92
  position: Types.Point2;
90
93
  zoomFactor: number;
91
94
  visible: boolean;
92
- constructor({ magnifyViewportId, sourceEnabledElement, radius, position, zoomFactor, autoPan, }: {
95
+ constructor({ magnifyViewportId, sourceEnabledElement, radius, position, zoomFactor, autoPan, annotation, }: {
93
96
  magnifyViewportId?: string;
94
97
  sourceEnabledElement: Types.IEnabledElement;
95
98
  radius?: number;
@@ -100,6 +103,7 @@ declare class AdvancedMagnifyViewport {
100
103
  padding: number;
101
104
  callback: AutoPanCallback;
102
105
  };
106
+ annotation?: AdvancedMagnifyAnnotation;
103
107
  });
104
108
  get sourceEnabledElement(): Types.IEnabledElement;
105
109
  get viewportId(): string;
@@ -120,7 +124,10 @@ declare class AdvancedMagnifyViewport {
120
124
  private _cancelMouseEventCallback;
121
125
  private _browserMouseUpCallback;
122
126
  private _browserMouseDownCallback;
127
+ private _browserTouchEndCallback;
128
+ private _browserTouchStartCallback;
123
129
  private _mouseDragCallback;
130
+ private _touchPressCallback;
124
131
  private _addBrowserEventListeners;
125
132
  private _removeBrowserEventListeners;
126
133
  private _addEventListeners;
@@ -135,7 +135,7 @@ class AdvancedMagnifyTool extends AnnotationTool {
135
135
  }
136
136
  });
137
137
  };
138
- this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
138
+ this.isPointNearTool = (element, annotation, canvasCoords, proximity, interactionType) => {
139
139
  const { viewport } = getEnabledElement(element);
140
140
  const { points } = annotation.data.handles;
141
141
  const { radius, center } = this._getCanvasCircleData(viewport, points);
@@ -143,6 +143,9 @@ class AdvancedMagnifyTool extends AnnotationTool {
143
143
  if (Math.abs(radiusPoint - radius) < proximity * 2) {
144
144
  return true;
145
145
  }
146
+ if (interactionType === 'touch' && radiusPoint < radius) {
147
+ return true;
148
+ }
146
149
  return false;
147
150
  };
148
151
  this.toolSelectedCallback = (evt, annotation) => {
@@ -227,6 +230,17 @@ class AdvancedMagnifyTool extends AnnotationTool {
227
230
  }
228
231
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
229
232
  };
233
+ this._pressModifyCallback = (evt) => {
234
+ const { element, startPoints } = evt.detail;
235
+ const annotation = this.editData.annotation;
236
+ const proximity = AdvancedMagnifyTool.TOUCH_PROXIMITY;
237
+ if (!this.isPointNearTool(element, annotation, startPoints.canvas, proximity)) {
238
+ return;
239
+ }
240
+ evt.stopImmediatePropagation();
241
+ this._endCallback(evt);
242
+ this.showZoomFactorsList(evt, annotation);
243
+ };
230
244
  this._dragHandle = (evt) => {
231
245
  const eventDetail = evt.detail;
232
246
  const { element } = eventDetail;
@@ -274,6 +288,7 @@ class AdvancedMagnifyTool extends AnnotationTool {
274
288
  element.addEventListener(Events.TOUCH_END, this._endCallback);
275
289
  element.addEventListener(Events.TOUCH_DRAG, this._dragModifyCallback);
276
290
  element.addEventListener(Events.TOUCH_TAP, this._endCallback);
291
+ element.addEventListener(Events.TOUCH_PRESS, this._pressModifyCallback);
277
292
  };
278
293
  this._deactivateModify = (element) => {
279
294
  state.isInteractingWithTool = false;
@@ -283,6 +298,7 @@ class AdvancedMagnifyTool extends AnnotationTool {
283
298
  element.removeEventListener(Events.TOUCH_END, this._endCallback);
284
299
  element.removeEventListener(Events.TOUCH_DRAG, this._dragModifyCallback);
285
300
  element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
301
+ element.removeEventListener(Events.TOUCH_PRESS, this._pressModifyCallback);
286
302
  };
287
303
  this.renderAnnotation = (enabledElement, svgDrawingHelper) => {
288
304
  let renderStatus = false;
@@ -350,6 +366,27 @@ class AdvancedMagnifyTool extends AnnotationTool {
350
366
  }
351
367
  return renderStatus;
352
368
  };
369
+ this.touchPressCallback = (evt) => {
370
+ const { element, startPoints } = evt.detail;
371
+ const enabledElement = getEnabledElement(element);
372
+ if (!enabledElement) {
373
+ return;
374
+ }
375
+ const { viewport } = enabledElement;
376
+ const canvasPoint = startPoints.canvas;
377
+ const proximity = AdvancedMagnifyTool.TOUCH_PROXIMITY;
378
+ const annotations = (getAnnotations(this.getToolName(), element) ??
379
+ []);
380
+ const annotation = annotations
381
+ .filter((a) => a.data.sourceViewportId === viewport.id)
382
+ .find((a) => isAnnotationVisible(a.annotationUID) &&
383
+ !isAnnotationLocked(a.annotationUID) &&
384
+ this.isPointNearTool(element, a, canvasPoint, proximity));
385
+ if (!annotation) {
386
+ return;
387
+ }
388
+ this.showZoomFactorsList(evt, annotation);
389
+ };
353
390
  this._getWorldHandlePoints = (viewport, canvasCenterPos, canvasRadius) => {
354
391
  const canvasHandlePoints = this._getCanvasHandlePoints(canvasCenterPos, canvasRadius);
355
392
  return canvasHandlePoints.map((handlePoint) => viewport.canvasToWorld(handlePoint));
@@ -377,13 +414,16 @@ class AdvancedMagnifyTool extends AnnotationTool {
377
414
  this.magnifyViewportManager = AdvancedMagnifyViewportManager.getInstance();
378
415
  }
379
416
  showZoomFactorsList(evt, annotation) {
380
- const { element, currentPoints } = evt.detail;
417
+ const { element } = evt.detail;
418
+ const currentPoints = 'currentPoints' in evt.detail
419
+ ? evt.detail.currentPoints
420
+ : evt.detail.startPoints;
381
421
  const enabledElement = getEnabledElement(element);
382
422
  const { viewport } = enabledElement;
383
423
  const { canvas: canvasPoint } = currentPoints;
384
424
  const viewportElement = element.querySelector(':scope .viewport-element');
385
425
  const currentZoomFactor = annotation.data.zoomFactor;
386
- const remove = () => dropdown.parentElement.removeChild(dropdown);
426
+ const remove = () => dropdown.remove();
387
427
  const dropdown = this._getZoomFactorsListDropdown(currentZoomFactor, (newZoomFactor) => {
388
428
  if (newZoomFactor !== undefined) {
389
429
  annotation.data.zoomFactor = Number.parseFloat(newZoomFactor);
@@ -407,19 +447,42 @@ class AdvancedMagnifyTool extends AnnotationTool {
407
447
  width: '50px',
408
448
  position: 'absolute',
409
449
  });
410
- ['mousedown', 'mouseup', 'mousemove', 'click'].forEach((eventName) => {
450
+ [
451
+ 'mousedown',
452
+ 'mouseup',
453
+ 'mousemove',
454
+ 'click',
455
+ 'touchstart',
456
+ 'touchend',
457
+ 'touchmove',
458
+ ].forEach((eventName) => {
411
459
  dropdown.addEventListener(eventName, (evt) => evt.stopPropagation());
412
460
  });
461
+ let committed = false;
462
+ const commit = (value) => {
463
+ if (committed) {
464
+ return;
465
+ }
466
+ committed = true;
467
+ onChangeCallback(value);
468
+ };
413
469
  dropdown.addEventListener('change', (evt) => {
414
470
  evt.stopPropagation();
415
- onChangeCallback(dropdown.value);
471
+ commit(dropdown.value);
416
472
  });
473
+ dropdown.addEventListener('click', (evt) => {
474
+ evt.stopPropagation();
475
+ if (evt.target?.tagName === 'OPTION') {
476
+ commit(dropdown.value);
477
+ }
478
+ });
479
+ dropdown.addEventListener('blur', () => commit(dropdown.value));
417
480
  dropdown.addEventListener('keydown', (evt) => {
418
481
  const shouldCancel = (evt.keyCode ?? evt.which === 27) ||
419
482
  evt.key?.toLowerCase() === 'escape';
420
483
  if (shouldCancel) {
421
484
  evt.stopPropagation();
422
- onChangeCallback();
485
+ commit();
423
486
  }
424
487
  });
425
488
  zoomFactorList.forEach((zoomFactor) => {
@@ -474,6 +537,7 @@ class AdvancedMagnifyViewportManager {
474
537
  position,
475
538
  zoomFactor,
476
539
  autoPan,
540
+ annotation,
477
541
  });
478
542
  this._addSourceElementEventListener(sourceElement);
479
543
  this._magnifyViewportsMap.set(magnifyViewport.viewportId, {
@@ -617,7 +681,7 @@ class AdvancedMagnifyViewportManager {
617
681
  }
618
682
  }
619
683
  class AdvancedMagnifyViewport {
620
- constructor({ magnifyViewportId, sourceEnabledElement, radius = MAGNIFY_VIEWPORT_INITIAL_RADIUS, position = [0, 0], zoomFactor, autoPan, }) {
684
+ constructor({ magnifyViewportId, sourceEnabledElement, radius = MAGNIFY_VIEWPORT_INITIAL_RADIUS, position = [0, 0], zoomFactor, autoPan, annotation, }) {
621
685
  this._enabledElement = null;
622
686
  this._sourceToolGroup = null;
623
687
  this._magnifyToolGroup = null;
@@ -628,12 +692,17 @@ class AdvancedMagnifyViewport {
628
692
  this._viewportId = magnifyViewportId ?? csUtils.uuidv4();
629
693
  this._sourceEnabledElement = sourceEnabledElement;
630
694
  this._autoPan = autoPan;
695
+ this._annotation = annotation;
631
696
  this.radius = radius;
632
697
  this.position = position;
633
698
  this.zoomFactor = zoomFactor;
634
699
  this.visible = true;
635
700
  this._browserMouseDownCallback = this._browserMouseDownCallback.bind(this);
636
701
  this._browserMouseUpCallback = this._browserMouseUpCallback.bind(this);
702
+ this._browserTouchStartCallback =
703
+ this._browserTouchStartCallback.bind(this);
704
+ this._browserTouchEndCallback = this._browserTouchEndCallback.bind(this);
705
+ this._touchPressCallback = this._touchPressCallback.bind(this);
637
706
  this._handleToolModeChanged = this._handleToolModeChanged.bind(this);
638
707
  this._mouseDragCallback = this._mouseDragCallback.bind(this);
639
708
  this._resizeViewportAsync = (debounce(this._resizeViewport.bind(this), 1));
@@ -837,6 +906,30 @@ class AdvancedMagnifyViewport {
837
906
  element.removeEventListener('mouseup', this._cancelMouseEventCallback);
838
907
  element.removeEventListener('mousemove', this._cancelMouseEventCallback);
839
908
  }
909
+ _browserTouchEndCallback(evt) {
910
+ if (evt.touches?.length > 0) {
911
+ return;
912
+ }
913
+ const { element } = this._enabledElement.viewport;
914
+ document.removeEventListener('touchend', this._browserTouchEndCallback);
915
+ document.removeEventListener('touchcancel', this._browserTouchEndCallback);
916
+ element.addEventListener('touchend', this._cancelMouseEventCallback, {
917
+ passive: false,
918
+ });
919
+ element.addEventListener('touchmove', this._cancelMouseEventCallback, {
920
+ passive: false,
921
+ });
922
+ }
923
+ _browserTouchStartCallback(evt) {
924
+ const { element } = this._enabledElement.viewport;
925
+ if (evt.touches?.length === 1) {
926
+ this._canAutoPan = !!evt.target?.closest('.advancedMagnifyTool');
927
+ }
928
+ document.addEventListener('touchend', this._browserTouchEndCallback);
929
+ document.addEventListener('touchcancel', this._browserTouchEndCallback);
930
+ element.removeEventListener('touchend', this._cancelMouseEventCallback);
931
+ element.removeEventListener('touchmove', this._cancelMouseEventCallback);
932
+ }
840
933
  _mouseDragCallback(evt) {
841
934
  if (!state.isInteractingWithTool) {
842
935
  return;
@@ -882,12 +975,43 @@ class AdvancedMagnifyViewport {
882
975
  };
883
976
  autoPan.callback(autoPanCallbackData);
884
977
  }
978
+ _touchPressCallback(evt) {
979
+ if (state.isInteractingWithTool) {
980
+ return;
981
+ }
982
+ const toolInstance = this._sourceToolGroup?.getToolInstance(ADVANCED_MAGNIFY_TOOL_NAME);
983
+ if (!toolInstance || !this._annotation) {
984
+ return;
985
+ }
986
+ const { viewport: sourceViewport } = this._sourceEnabledElement;
987
+ const pressCanvas = evt.detail.startPoints.canvas;
988
+ const sourceCanvasPoint = [
989
+ pressCanvas[0] + this.position[0] - this.radius,
990
+ pressCanvas[1] + this.position[1] - this.radius,
991
+ ];
992
+ toolInstance.showZoomFactorsList({
993
+ detail: {
994
+ element: sourceViewport.element,
995
+ startPoints: { canvas: sourceCanvasPoint },
996
+ },
997
+ }, this._annotation);
998
+ }
885
999
  _addBrowserEventListeners(element) {
886
1000
  document.addEventListener('mousedown', this._browserMouseDownCallback, true);
887
1001
  element.addEventListener('mousedown', this._cancelMouseEventCallback);
888
1002
  element.addEventListener('mouseup', this._cancelMouseEventCallback);
889
1003
  element.addEventListener('mousemove', this._cancelMouseEventCallback);
890
1004
  element.addEventListener('dblclick', this._cancelMouseEventCallback);
1005
+ document.addEventListener('touchstart', this._browserTouchStartCallback, true);
1006
+ element.addEventListener('touchstart', this._cancelMouseEventCallback, {
1007
+ passive: false,
1008
+ });
1009
+ element.addEventListener('touchend', this._cancelMouseEventCallback, {
1010
+ passive: false,
1011
+ });
1012
+ element.addEventListener('touchmove', this._cancelMouseEventCallback, {
1013
+ passive: false,
1014
+ });
891
1015
  }
892
1016
  _removeBrowserEventListeners(element) {
893
1017
  document.removeEventListener('mousedown', this._browserMouseDownCallback, true);
@@ -896,17 +1020,27 @@ class AdvancedMagnifyViewport {
896
1020
  element.removeEventListener('mouseup', this._cancelMouseEventCallback);
897
1021
  element.removeEventListener('mousemove', this._cancelMouseEventCallback);
898
1022
  element.removeEventListener('dblclick', this._cancelMouseEventCallback);
1023
+ document.removeEventListener('touchstart', this._browserTouchStartCallback, true);
1024
+ document.removeEventListener('touchend', this._browserTouchEndCallback);
1025
+ document.removeEventListener('touchcancel', this._browserTouchEndCallback);
1026
+ element.removeEventListener('touchstart', this._cancelMouseEventCallback);
1027
+ element.removeEventListener('touchend', this._cancelMouseEventCallback);
1028
+ element.removeEventListener('touchmove', this._cancelMouseEventCallback);
899
1029
  }
900
1030
  _addEventListeners(element) {
901
1031
  eventTarget.addEventListener(cstEvents.TOOL_MODE_CHANGED, this._handleToolModeChanged);
902
1032
  element.addEventListener(cstEvents.MOUSE_MOVE, this._mouseDragCallback);
903
1033
  element.addEventListener(cstEvents.MOUSE_DRAG, this._mouseDragCallback);
1034
+ element.addEventListener(cstEvents.TOUCH_DRAG, this._mouseDragCallback);
1035
+ element.addEventListener(cstEvents.TOUCH_PRESS, this._touchPressCallback);
904
1036
  this._addBrowserEventListeners(element);
905
1037
  }
906
1038
  _removeEventListeners(element) {
907
1039
  eventTarget.removeEventListener(cstEvents.TOOL_MODE_CHANGED, this._handleToolModeChanged);
908
1040
  element.addEventListener(cstEvents.MOUSE_MOVE, this._mouseDragCallback);
909
1041
  element.addEventListener(cstEvents.MOUSE_DRAG, this._mouseDragCallback);
1042
+ element.removeEventListener(cstEvents.TOUCH_DRAG, this._mouseDragCallback);
1043
+ element.removeEventListener(cstEvents.TOUCH_PRESS, this._touchPressCallback);
910
1044
  this._removeBrowserEventListeners(element);
911
1045
  }
912
1046
  _initialize() {
@@ -69,7 +69,7 @@ declare class CrosshairsTool extends AnnotationTool {
69
69
  _filterAnnotationsByUniqueViewportOrientations: (enabledElement: any, annotations: any) => any[];
70
70
  _checkIfViewportsRenderingSameScene: (viewport: any, otherViewport: any) => any;
71
71
  _jump: (enabledElement: any, jumpWorld: any) => boolean;
72
- _activateModify: (element: any) => void;
72
+ _activateModify: (element: any, evt?: EventTypes.InteractionEventType) => void;
73
73
  _deactivateModify: (element: any) => void;
74
74
  _endCallback: (evt: EventTypes.InteractionEventType) => void;
75
75
  _dragCallback: (evt: EventTypes.InteractionEventType) => void;