@kitware/vtk.js 29.4.3 → 29.4.5

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.
@@ -33,6 +33,35 @@ function vtkPicker(publicAPI, model) {
33
33
  model.globalTMin = Number.MAX_VALUE;
34
34
  }
35
35
 
36
+ /**
37
+ * Compute the tolerance in world coordinates.
38
+ * Do this by determining the world coordinates of the diagonal points of the
39
+ * window, computing the width of the window in world coordinates, and
40
+ * multiplying by the tolerance.
41
+ * @param {Number} selectionZ
42
+ * @param {Number} aspect
43
+ * @param {vtkRenderer} renderer
44
+ * @returns {Number} the computed tolerance
45
+ */
46
+ function computeTolerance(selectionZ, aspect, renderer) {
47
+ let tolerance = 0.0;
48
+ const view = renderer.getRenderWindow().getViews()[0];
49
+ const viewport = renderer.getViewport();
50
+ const winSize = view.getSize();
51
+ let x = winSize[0] * viewport[0];
52
+ let y = winSize[1] * viewport[1];
53
+ const normalizedLeftDisplay = view.displayToNormalizedDisplay(x, y, selectionZ);
54
+ const windowLowerLeft = renderer.normalizedDisplayToWorld(normalizedLeftDisplay[0], normalizedLeftDisplay[1], normalizedLeftDisplay[2], aspect);
55
+ x = winSize[0] * viewport[2];
56
+ y = winSize[1] * viewport[3];
57
+ const normalizedRightDisplay = view.displayToNormalizedDisplay(x, y, selectionZ);
58
+ const windowUpperRight = renderer.normalizedDisplayToWorld(normalizedRightDisplay[0], normalizedRightDisplay[1], normalizedRightDisplay[2], aspect);
59
+ for (let i = 0; i < 3; i++) {
60
+ tolerance += (windowUpperRight[i] - windowLowerLeft[i]) * (windowUpperRight[i] - windowLowerLeft[i]);
61
+ }
62
+ return Math.sqrt(tolerance);
63
+ }
64
+
36
65
  // Intersect data with specified ray.
37
66
  // Project the center point of the mapper onto the ray and determine its parametric value
38
67
  publicAPI.intersectWithLine = (p1, p2, tol, mapper) => {
@@ -73,13 +102,6 @@ function vtkPicker(publicAPI, model) {
73
102
  let tB;
74
103
  const p1World = [];
75
104
  const p2World = [];
76
- let viewport = [];
77
- let winSize = [];
78
- let x;
79
- let y;
80
- let windowLowerLeft = [];
81
- let windowUpperRight = [];
82
- let tol = 0.0;
83
105
  let props = [];
84
106
  let pickable = false;
85
107
  const p1Mapper = new Float64Array(4);
@@ -108,6 +130,7 @@ function vtkPicker(publicAPI, model) {
108
130
  displayCoords = renderer.worldToNormalizedDisplay(cameraFP[0], cameraFP[1], cameraFP[2], aspect);
109
131
  displayCoords = view.normalizedDisplayToDisplay(displayCoords[0], displayCoords[1], displayCoords[2]);
110
132
  selectionZ = displayCoords[2];
133
+ const tolerance = computeTolerance(selectionZ, aspect, renderer) * model.tolerance;
111
134
 
112
135
  // Convert the selection point into world coordinates.
113
136
  const normalizedDisplay = view.displayToNormalizedDisplay(selectionX, selectionY, selectionZ);
@@ -150,27 +173,6 @@ function vtkPicker(publicAPI, model) {
150
173
  }
151
174
  p1World[3] = 1.0;
152
175
  p2World[3] = 1.0;
153
-
154
- // Compute the tolerance in world coordinates. Do this by
155
- // determining the world coordinates of the diagonal points of the
156
- // window, computing the width of the window in world coordinates, and
157
- // multiplying by the tolerance.
158
- viewport = renderer.getViewport();
159
- if (renderer.getRenderWindow()) {
160
- winSize = renderer.getRenderWindow().getViews()[0].getSize();
161
- }
162
- x = winSize[0] * viewport[0];
163
- y = winSize[1] * viewport[1];
164
- const normalizedLeftDisplay = view.displayToNormalizedDisplay(x, y, selectionZ);
165
- windowLowerLeft = renderer.normalizedDisplayToWorld(normalizedLeftDisplay[0], normalizedLeftDisplay[1], normalizedLeftDisplay[2], aspect);
166
- x = winSize[0] * viewport[2];
167
- y = winSize[1] * viewport[3];
168
- const normalizedRightDisplay = view.displayToNormalizedDisplay(x, y, selectionZ);
169
- windowUpperRight = renderer.normalizedDisplayToWorld(normalizedRightDisplay[0], normalizedRightDisplay[1], normalizedRightDisplay[2], aspect);
170
- for (let i = 0; i < 3; i++) {
171
- tol += (windowUpperRight[i] - windowLowerLeft[i]) * (windowUpperRight[i] - windowLowerLeft[i]);
172
- }
173
- tol = Math.sqrt(tol) * model.tolerance;
174
176
  if (model.pickFromList) {
175
177
  props = model.pickList;
176
178
  } else {
@@ -209,12 +211,12 @@ function vtkPicker(publicAPI, model) {
209
211
  }
210
212
  if (mapper) {
211
213
  bbox.setBounds(mapper.getBounds());
212
- bbox.inflate(tol);
214
+ bbox.inflate(tolerance);
213
215
  } else {
214
216
  bbox.reset();
215
217
  }
216
218
  if (bbox.intersectBox(p1Mapper, ray, hitPosition, t)) {
217
- t[0] = publicAPI.intersectWithLine(p1Mapper, p2Mapper, tol * 0.333 * (scale[0] + scale[1] + scale[2]), prop, mapper);
219
+ t[0] = publicAPI.intersectWithLine(p1Mapper, p2Mapper, tolerance * 0.333 * (scale[0] + scale[1] + scale[2]), prop, mapper);
218
220
  if (t[0] < Number.MAX_VALUE) {
219
221
  const p = [];
220
222
  p[0] = (1.0 - t[0]) * p1World[0] + t[0] * p2World[0];
@@ -93,7 +93,7 @@ export interface vtkRenderWindowInteractor extends vtkObject {
93
93
  *
94
94
  * @default null
95
95
  */
96
- getContainer(): HTMLElement;
96
+ getContainer(): Nullable<HTMLElement>;
97
97
 
98
98
  /**
99
99
  *
@@ -827,6 +827,13 @@ export interface vtkRenderWindowInteractor extends vtkObject {
827
827
  */
828
828
  rotateEvent(args: any): any;
829
829
 
830
+ /**
831
+ * Add an HTMLElement as the new container for the interactor.
832
+ * All events will be bound to this new container.
833
+ * Any old container will be removed along with its listeners.
834
+ */
835
+ setContainer(container: Nullable<HTMLElement>): boolean;
836
+
830
837
  /**
831
838
  * Turn on/off the automatic repositioning of lights as the camera moves.
832
839
  * @param lightFollowCamera
@@ -992,12 +999,15 @@ export interface vtkRenderWindowInteractor extends vtkObject {
992
999
 
993
1000
  /**
994
1001
  *
995
- * @param container
1002
+ * @param container kept for backward compatibility.
1003
+ * @deprecated please use vtkRenderWindowInteractor.setContainer(container: HTMLElement)
1004
+ * which will also bind events.
996
1005
  */
997
1006
  bindEvents(container: any): void;
998
1007
 
999
1008
  /**
1000
1009
  *
1010
+ * @deprecated please use vtkRenderWindowInteractor.setContainer(null) instead.
1001
1011
  */
1002
1012
  unbindEvents(): void;
1003
1013
 
@@ -51,6 +51,11 @@ function vtkRenderWindowInteractor(publicAPI, model) {
51
51
  // Set our className
52
52
  model.classHierarchy.push('vtkRenderWindowInteractor');
53
53
 
54
+ // Capture "parentClass" api for internal use
55
+ const superClass = {
56
+ ...publicAPI
57
+ };
58
+
54
59
  // Initialize list of requesters
55
60
  const animationRequesters = new Set();
56
61
 
@@ -161,8 +166,13 @@ function vtkRenderWindowInteractor(publicAPI, model) {
161
166
  function getDeviceTypeFor(event) {
162
167
  return event.pointerType || '';
163
168
  }
164
- publicAPI.bindEvents = container => {
165
- model.container = container;
169
+ const _bindEvents = () => {
170
+ if (model.container === null) {
171
+ return;
172
+ }
173
+ const {
174
+ container
175
+ } = model;
166
176
  container.addEventListener('contextmenu', preventDefault);
167
177
  container.addEventListener('wheel', publicAPI.handleWheel);
168
178
  container.addEventListener('DOMMouseScroll', publicAPI.handleWheel);
@@ -188,30 +198,53 @@ function vtkRenderWindowInteractor(publicAPI, model) {
188
198
  // disables tap highlight for when cursor is pointer
189
199
  container.style.webkitTapHighlightColor = 'rgba(0,0,0,0)';
190
200
  };
191
- publicAPI.unbindEvents = () => {
201
+
202
+ // For backward compatibility.
203
+ // Necessary for using unbind/bindEvent without calling setContainer.
204
+ publicAPI.bindEvents = container => {
205
+ if (container === null) {
206
+ return;
207
+ }
208
+ const res = superClass.setContainer(container);
209
+ if (res) {
210
+ _bindEvents();
211
+ }
212
+ };
213
+ const _unbindEvents = () => {
214
+ // Clear any previous timeouts and state variables that control mouse / touchpad behavior.
215
+ clearTimeout(model.moveTimeoutID);
216
+ clearTimeout(model.wheelTimeoutID);
217
+ model.moveTimeoutID = 0;
218
+ model.wheelTimeoutID = 0;
219
+ wheelCoefficient = 1.0;
192
220
  const {
193
221
  container
194
222
  } = model;
195
- container.removeEventListener('contextmenu', preventDefault);
196
- container.removeEventListener('wheel', publicAPI.handleWheel);
197
- container.removeEventListener('DOMMouseScroll', publicAPI.handleWheel);
198
- container.removeEventListener('pointerenter', publicAPI.handlePointerEnter);
199
- container.removeEventListener('pointerleave', publicAPI.handlePointerLeave);
200
- container.removeEventListener('pointermove', publicAPI.handlePointerMove, {
201
- passive: false
202
- });
203
- container.removeEventListener('pointerdown', publicAPI.handlePointerDown, {
204
- passive: false
205
- });
206
- container.removeEventListener('pointerup', publicAPI.handlePointerUp);
207
- container.removeEventListener('pointercancel', publicAPI.handlePointerCancel);
223
+ if (container) {
224
+ container.removeEventListener('contextmenu', preventDefault);
225
+ container.removeEventListener('wheel', publicAPI.handleWheel);
226
+ container.removeEventListener('DOMMouseScroll', publicAPI.handleWheel);
227
+ container.removeEventListener('pointerenter', publicAPI.handlePointerEnter);
228
+ container.removeEventListener('pointerleave', publicAPI.handlePointerLeave);
229
+ container.removeEventListener('pointermove', publicAPI.handlePointerMove, {
230
+ passive: false
231
+ });
232
+ container.removeEventListener('pointerdown', publicAPI.handlePointerDown, {
233
+ passive: false
234
+ });
235
+ container.removeEventListener('pointerup', publicAPI.handlePointerUp);
236
+ container.removeEventListener('pointercancel', publicAPI.handlePointerCancel);
237
+ }
208
238
  document.removeEventListener('keypress', publicAPI.handleKeyPress);
209
239
  document.removeEventListener('keydown', publicAPI.handleKeyDown);
210
240
  document.removeEventListener('keyup', publicAPI.handleKeyUp);
211
241
  document.removeEventListener('pointerlockchange', publicAPI.handlePointerLockChange);
212
- model.container = null;
213
242
  pointerCache.clear();
214
243
  };
244
+ publicAPI.unbindEvents = () => {
245
+ _unbindEvents();
246
+ superClass.setContainer(null);
247
+ };
215
248
  publicAPI.handleKeyPress = event => {
216
249
  const data = getKeysFor(event);
217
250
  publicAPI.keyPressEvent(data);
@@ -947,9 +980,16 @@ function vtkRenderWindowInteractor(publicAPI, model) {
947
980
  model._forcedRenderer = !!r;
948
981
  model.currentRenderer = r;
949
982
  };
983
+ publicAPI.setContainer = container => {
984
+ _unbindEvents();
985
+ const res = superClass.setContainer(container ?? null);
986
+ if (res) {
987
+ _bindEvents();
988
+ }
989
+ return res;
990
+ };
950
991
 
951
992
  // Stop animating if the renderWindowInteractor is deleted.
952
- const superDelete = publicAPI.delete;
953
993
  publicAPI.delete = () => {
954
994
  while (animationRequesters.size) {
955
995
  publicAPI.cancelAnimation(animationRequesters.values().next().value);
@@ -958,9 +998,9 @@ function vtkRenderWindowInteractor(publicAPI, model) {
958
998
  document.removeEventListener('visibilitychange', publicAPI.handleVisibilityChange);
959
999
  }
960
1000
  if (model.container) {
961
- publicAPI.unbindEvents();
1001
+ publicAPI.setContainer(null);
962
1002
  }
963
- superDelete();
1003
+ superClass.delete();
964
1004
  };
965
1005
 
966
1006
  // Use the Page Visibility API to detect when we switch away from or back to
@@ -1017,10 +1057,10 @@ function extend(publicAPI, model) {
1017
1057
  handledEvents.forEach(eventName => macro.event(publicAPI, model, eventName));
1018
1058
 
1019
1059
  // Create get-only macros
1020
- macro.get(publicAPI, model, ['initialized', 'container', 'interactorStyle', 'lastFrameTime', 'recentAnimationFrameRate', '_view']);
1060
+ macro.get(publicAPI, model, ['initialized', 'interactorStyle', 'lastFrameTime', 'recentAnimationFrameRate', '_view']);
1021
1061
 
1022
1062
  // Create get-set macros
1023
- macro.setGet(publicAPI, model, ['lightFollowCamera', 'enabled', 'enableRender', 'recognizeGestures', 'desiredUpdateRate', 'stillUpdateRate', 'picker', 'preventDefaultOnPointerDown', 'preventDefaultOnPointerUp', 'mouseScrollDebounceByPass']);
1063
+ macro.setGet(publicAPI, model, ['container', 'lightFollowCamera', 'enabled', 'enableRender', 'recognizeGestures', 'desiredUpdateRate', 'stillUpdateRate', 'picker', 'preventDefaultOnPointerDown', 'preventDefaultOnPointerUp', 'mouseScrollDebounceByPass']);
1024
1064
  macro.moveToProtected(publicAPI, model, ['view']);
1025
1065
 
1026
1066
  // For more macro methods, see "Sources/macros.js"
@@ -24,29 +24,30 @@ function widgetBehavior(publicAPI, model) {
24
24
  };
25
25
  publicAPI.handleEvent = callData => {
26
26
  const manipulator = model.activeState?.getManipulator?.() ?? model.manipulator;
27
- if (manipulator && model.activeState && model.activeState.getActive()) {
28
- const normal = model._camera.getDirectionOfProjection();
29
- const up = model._camera.getViewUp();
30
- const right = [];
31
- vec3.cross(right, up, normal);
32
- model.activeState.setUp(...up);
33
- model.activeState.setRight(...right);
34
- model.activeState.setDirection(...normal);
35
- const {
36
- worldCoords
37
- } = manipulator.handleEvent(callData, model._apiSpecificRenderWindow);
38
- if (worldCoords.length) {
39
- model.widgetState.setTrueOrigin(...worldCoords);
40
- model.activeState.setOrigin(...worldCoords);
41
- if (model.painting) {
42
- const trailCircle = model.widgetState.addTrail();
43
- trailCircle.set(model.activeState.get('origin', 'up', 'right', 'direction', 'scale1'));
44
- }
45
- }
46
- publicAPI.invokeInteractionEvent();
47
- return macro.EVENT_ABORT;
27
+ if (!(manipulator && model.activeState && model.activeState.getActive())) {
28
+ return macro.VOID;
29
+ }
30
+ const normal = model._camera.getDirectionOfProjection();
31
+ const up = model._camera.getViewUp();
32
+ const right = [];
33
+ vec3.cross(right, up, normal);
34
+ model.activeState.setUp(...up);
35
+ model.activeState.setRight(...right);
36
+ model.activeState.setDirection(...normal);
37
+ const {
38
+ worldCoords
39
+ } = manipulator.handleEvent(callData, model._apiSpecificRenderWindow);
40
+ if (!worldCoords?.length) {
41
+ return macro.VOID;
48
42
  }
49
- return macro.VOID;
43
+ model.widgetState.setTrueOrigin(...worldCoords);
44
+ model.activeState.setOrigin(...worldCoords);
45
+ if (model.painting) {
46
+ const trailCircle = model.widgetState.addTrail();
47
+ trailCircle.set(model.activeState.get('origin', 'up', 'right', 'direction', 'scale1'));
48
+ }
49
+ publicAPI.invokeInteractionEvent();
50
+ return macro.EVENT_ABORT;
50
51
  };
51
52
  publicAPI.grabFocus = () => {
52
53
  if (!model.hasFocus) {
@@ -75,7 +75,7 @@ export interface vtkResliceCursorWidget extends vtkAbstractWidgetFactory {
75
75
  * Return an array of the first and the last possible points of the plane
76
76
  * along its normal.
77
77
  * @param {ViewTypes} viewType
78
- * @returns {[Vector3, Vector3]} first and last points
78
+ * @returns {Array<Vector3>} two Vector3 arrays (first and last points)
79
79
  */
80
80
  getPlaneExtremities(viewType: ViewTypes): Array<Vector3>;
81
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "29.4.3",
3
+ "version": "29.4.5",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",
@@ -118,7 +118,6 @@
118
118
  "string-replace-loader": "3.1.0",
119
119
  "style-loader": "3.3.1",
120
120
  "tape": "5.5.3",
121
- "tape-catch": "1.0.6",
122
121
  "webpack": "5.76.0",
123
122
  "webpack-bundle-analyzer": "4.5.0",
124
123
  "webpack-cli": "4.9.2",