@cornerstonejs/tools 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -26,7 +26,7 @@
26
26
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
27
27
  },
28
28
  "dependencies": {
29
- "@cornerstonejs/core": "^1.1.4",
29
+ "@cornerstonejs/core": "^1.1.6",
30
30
  "lodash.clonedeep": "4.5.0",
31
31
  "lodash.get": "^4.4.2"
32
32
  },
@@ -49,5 +49,5 @@
49
49
  "type": "individual",
50
50
  "url": "https://ohif.org/donate"
51
51
  },
52
- "gitHead": "bd0b4c3bbbcf1646a9dffcbd6a26794dcd292cfb"
52
+ "gitHead": "cd4bc2f52ab0963cfa024eb975c5cac955067400"
53
53
  }
@@ -22,6 +22,9 @@ const { MOUSE_DOWN, MOUSE_DOWN_ACTIVATE, MOUSE_CLICK, MOUSE_UP, MOUSE_DRAG } =
22
22
  //
23
23
  const DOUBLE_CLICK_TOLERANCE_MS = 400;
24
24
 
25
+ // This tolerance is how long to accept a secondary button down
26
+ const MULTI_BUTTON_TOLERANCE_MS = 150;
27
+
25
28
  // A drag (projected distance) during the double click timeout that is greater than this
26
29
  // value will cancel the timeout and suppress any double click that might occur.
27
30
  // This tolerance is particularly important on touch devices where some movement
@@ -124,17 +127,28 @@ const doubleClickState: IDoubleClickState = {
124
127
  * @private
125
128
  */
126
129
  function mouseDownListener(evt: MouseEvent) {
127
- // Ignore any mouse down during the double click timeout because only
128
- // the first mouse down has the potential of being handled.
129
130
  if (doubleClickState.doubleClickTimeout) {
131
+ // A second identical click will be a double click event, so ignore it
132
+ if (evt.buttons === doubleClickState.mouseDownEvent.buttons) return;
133
+
134
+ // Record the second button or the changed button event as the initial
135
+ // button down state so that the multi-button event can be detected
136
+ doubleClickState.mouseDownEvent = evt;
137
+
138
+ // If second button is added, then ensure double click timeout is terminated
139
+ // and do not handle three or more button gestures.
140
+ _doStateMouseDownAndUp();
130
141
  return;
131
142
  }
132
143
 
133
- // Only left single button click can be doubled up, so fire immediately
134
- // on anything except left double click.
144
+ // Handle multi-button clicks by adding a delay before handling them.
145
+ // Double clicks (left button only) physically take the user longer, so
146
+ // use a longer timeout, and for multi-button at the same time, the clicks
147
+ // are done at the same time by the user, just the system perceives them
148
+ // separately, so have a short timeout to allow catching both buttons.
135
149
  doubleClickState.doubleClickTimeout = setTimeout(
136
150
  _doStateMouseDownAndUp,
137
- evt.buttons === 1 ? DOUBLE_CLICK_TOLERANCE_MS : 0
151
+ evt.buttons === 1 ? DOUBLE_CLICK_TOLERANCE_MS : MULTI_BUTTON_TOLERANCE_MS
138
152
  );
139
153
 
140
154
  // First mouse down of a potential double click. So save it and start
@@ -1,3 +1,4 @@
1
+ import { vec3 } from 'gl-matrix';
1
2
  import { Events } from '../../enums';
2
3
  import {
3
4
  getEnabledElement,
@@ -381,6 +382,52 @@ class CobbAngleTool extends AnnotationTool {
381
382
  this.isDrawing = false;
382
383
  };
383
384
 
385
+ /**
386
+ * Handles the mouse down for all points that follow the very first mouse down.
387
+ * The very first mouse down is handled by addAnnotation.
388
+ * This method ensures that the state of the tool is correct for the drawing of the second line segment.
389
+ * In particular it ensures that the second segment can be created via a mouse down and drag.
390
+ */
391
+ _mouseDownCallback = (
392
+ evt: EventTypes.MouseUpEventType | EventTypes.MouseClickEventType
393
+ ) => {
394
+ const { annotation, handleIndex } = this.editData;
395
+ const eventDetail = evt.detail;
396
+ const { element, currentPoints } = eventDetail;
397
+ const worldPos = currentPoints.world;
398
+ const { data } = annotation;
399
+
400
+ if (handleIndex === 1) {
401
+ // This is the mouse down for the second point of the first segment.
402
+ // The mouse up takes care of adding the first point of the second segment.
403
+ data.handles.points[1] = worldPos;
404
+ this.editData.hasMoved =
405
+ data.handles.points[1][0] !== data.handles.points[0][0] ||
406
+ data.handles.points[1][1] !== data.handles.points[0][0];
407
+ return;
408
+ }
409
+
410
+ if (handleIndex === 3) {
411
+ // This is the mouse down for the second point of the second segment (i.e. the last point)
412
+ data.handles.points[3] = worldPos;
413
+ this.editData.hasMoved =
414
+ data.handles.points[3][0] !== data.handles.points[2][0] ||
415
+ data.handles.points[3][1] !== data.handles.points[2][0];
416
+
417
+ this.angleStartedNotYetCompleted = false;
418
+ return;
419
+ }
420
+
421
+ // This is the first mouse down of the first point of the second line segment.
422
+ // It is as if we have not moved yet because Cobb Angle has two, disjoint sections, each with its own move.
423
+ this.editData.hasMoved = false;
424
+ hideElementCursor(element);
425
+
426
+ // Add the last segment points for the subsequent drag/mouse move.
427
+ data.handles.points[2] = data.handles.points[3] = worldPos;
428
+ this.editData.handleIndex = data.handles.points.length - 1;
429
+ };
430
+
384
431
  _mouseDragCallback = (
385
432
  evt: EventTypes.MouseDragEventType | EventTypes.MouseMoveEventType
386
433
  ) => {
@@ -532,6 +579,10 @@ class CobbAngleTool extends AnnotationTool {
532
579
  Events.MOUSE_CLICK,
533
580
  this._mouseUpCallback as EventListener
534
581
  );
582
+ element.addEventListener(
583
+ Events.MOUSE_DOWN,
584
+ this._mouseDownCallback as EventListener
585
+ );
535
586
 
536
587
  // element.addEventListener(Events.TOUCH_END, this._mouseUpCallback)
537
588
  // element.addEventListener(Events.TOUCH_DRAG, this._mouseDragCallback)
@@ -556,6 +607,10 @@ class CobbAngleTool extends AnnotationTool {
556
607
  Events.MOUSE_CLICK,
557
608
  this._mouseUpCallback as EventListener
558
609
  );
610
+ element.removeEventListener(
611
+ Events.MOUSE_DOWN,
612
+ this._mouseDownCallback as EventListener
613
+ );
559
614
 
560
615
  // element.removeEventListener(Events.TOUCH_END, this._mouseUpCallback)
561
616
  // element.removeEventListener(Events.TOUCH_DRAG, this._mouseDragCallback)
@@ -775,20 +830,40 @@ class CobbAngleTool extends AnnotationTool {
775
830
  return;
776
831
  }
777
832
 
778
- const worldPos1 = data.handles.points[0];
779
- const worldPos2 = data.handles.points[1];
780
- const worldPos3 = data.handles.points[2];
781
- const worldPos4 = data.handles.points[3];
833
+ const seg1: [Types.Point3, Types.Point3] = [null, null];
834
+ const seg2: [Types.Point3, Types.Point3] = [null, null];
835
+ let minDist = Number.MAX_VALUE;
836
+
837
+ // Order the endpoints of each line segment such that seg1[1] and seg2[0]
838
+ // are the closest (Euclidean distance-wise) to each other. Thus
839
+ // the angle formed between the vectors seg1[1]->seg1[0] and seg2[0]->seg[1]
840
+ // is calculated.
841
+ // The assumption here is that the Cobb angle line segments are drawn
842
+ // such that the segments intersect nearest the segment endpoints
843
+ // that are closest AND those closest endpoints are the tails of the
844
+ // vectors used to calculate the angle between the vectors/line segments.
845
+ for (let i = 0; i < 2; i += 1) {
846
+ for (let j = 2; j < 4; j += 1) {
847
+ const dist = vec3.distance(
848
+ data.handles.points[i],
849
+ data.handles.points[j]
850
+ );
851
+ if (dist < minDist) {
852
+ minDist = dist;
853
+ seg1[1] = data.handles.points[i];
854
+ seg1[0] = data.handles.points[(i + 1) % 2];
855
+ seg2[0] = data.handles.points[j];
856
+ seg2[1] = data.handles.points[2 + ((j - 1) % 2)];
857
+ }
858
+ }
859
+ }
782
860
 
783
861
  const { cachedStats } = data;
784
862
  const targetIds = Object.keys(cachedStats);
785
863
 
786
864
  for (let i = 0; i < targetIds.length; i++) {
787
865
  const targetId = targetIds[i];
788
- const angle = angleBetweenLines(
789
- [worldPos1, worldPos2],
790
- [worldPos3, worldPos4]
791
- );
866
+ const angle = angleBetweenLines(seg1, seg2);
792
867
 
793
868
  cachedStats[targetId] = {
794
869
  angle,
@@ -5,6 +5,8 @@ type Line = [Types.Point3, Types.Point3];
5
5
 
6
6
  /**
7
7
  * It returns the angle between two lines in degrees.
8
+ * The angle measured is that between the vectors
9
+ * line1[1]->line1[0] AND line2[0]->line2[1].
8
10
  * @param line1 - Line = [p1, p2]
9
11
  * @param line2 - Line = [p3, p4]
10
12
  * @returns The angle between two lines in degrees.