Skip to content

Commit a938190

Browse files
committed
chore(InteractorStyleManipulatorRotateWorld): create example
closes #3309
1 parent 7ca74c6 commit a938190

File tree

1 file changed

+192
-0
lines changed
  • Sources/Interaction/Style/InteractorStyleManipulatorRotateWorld/example

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import '@kitware/vtk.js/favicon';
2+
3+
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
4+
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
5+
6+
import macro from '@kitware/vtk.js/macros';
7+
import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
8+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
9+
import vtkConeSource from '@kitware/vtk.js/Filters/Sources/ConeSource';
10+
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
11+
import vtkInteractorStyleManipulator from '@kitware/vtk.js/Interaction/Style/InteractorStyleManipulator';
12+
import vtkMouseCameraTrackballRotateManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballRotateManipulator';
13+
import vtkMouseCameraTrackballPanManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballPanManipulator';
14+
import vtkMouseCameraTrackballZoomManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballZoomManipulator';
15+
import vtkGestureCameraManipulator from '@kitware/vtk.js/Interaction/Manipulators/GestureCameraManipulator';
16+
17+
// No external HTML file needed - using inline controls
18+
19+
// ----------------------------------------------------------------------------
20+
// Custom InteractorStyle that Rotates Around World Center
21+
// ----------------------------------------------------------------------------
22+
23+
function vtkInteractorStyleRotateWorld(publicAPI, model) {
24+
model.classHierarchy.push('vtkInteractorStyleRotateWorld');
25+
26+
// For pre-v34.7.0 behavior: just prevent center update during pan
27+
28+
// Override handleMouseMove to NOT update center during pan
29+
publicAPI.handleMouseMove = (callData) => {
30+
model.cachedMousePosition = callData.position;
31+
if (model.currentManipulator && model.currentManipulator.onMouseMove) {
32+
model.currentManipulator.onMouseMove(
33+
model._interactor,
34+
model.getRenderer(callData),
35+
callData.position
36+
);
37+
// Don't update centerOfRotation here (v34.7.0+ does this)
38+
publicAPI.invokeInteractionEvent({ type: 'InteractionEvent' });
39+
}
40+
};
41+
42+
// Override handlePan for gesture-based panning
43+
publicAPI.handlePan = (callData) => {
44+
const renderer = model.getRenderer(callData);
45+
46+
let count = model.gestureManipulators.length;
47+
let actionCount = 0;
48+
while (count--) {
49+
const manipulator = model.gestureManipulators[count];
50+
if (manipulator && manipulator.isPanEnabled()) {
51+
manipulator.onPan(model._interactor, renderer, callData.translation);
52+
actionCount++;
53+
}
54+
}
55+
56+
if (actionCount) {
57+
// Don't update centerOfRotation here (v34.7.0+ does this)
58+
publicAPI.invokeInteractionEvent({ type: 'InteractionEvent' });
59+
}
60+
};
61+
}
62+
63+
// ----------------------------------------------------------------------------
64+
// Factory function for custom interactor style
65+
// ----------------------------------------------------------------------------
66+
67+
function extendInteractorStyle(publicAPI, model, initialValues = {}) {
68+
Object.assign(model, initialValues);
69+
70+
// Extend the base InteractorStyleManipulator
71+
vtkInteractorStyleManipulator.extend(publicAPI, model, initialValues);
72+
73+
// Add our custom methods
74+
vtkInteractorStyleRotateWorld(publicAPI, model);
75+
}
76+
77+
const newInteractorStyleRotateWorld = macro.newInstance(
78+
extendInteractorStyle,
79+
'vtkInteractorStyleRotateWorld'
80+
);
81+
82+
// ----------------------------------------------------------------------------
83+
// Standard rendering code setup
84+
// ----------------------------------------------------------------------------
85+
86+
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
87+
const renderer = fullScreenRenderer.getRenderer();
88+
const renderWindow = fullScreenRenderer.getRenderWindow();
89+
90+
// ----------------------------------------------------------------------------
91+
// Example code
92+
// ----------------------------------------------------------------------------
93+
94+
// Use our custom interactor style
95+
const interactorStyle = newInteractorStyleRotateWorld();
96+
fullScreenRenderer.getInteractor().setInteractorStyle(interactorStyle);
97+
98+
// ----------------------------------------------------------------------------
99+
// Create cone (main object)
100+
// ----------------------------------------------------------------------------
101+
102+
const coneSource = vtkConeSource.newInstance({ height: 1.0 });
103+
const coneMapper = vtkMapper.newInstance();
104+
coneMapper.setInputConnection(coneSource.getOutputPort());
105+
106+
const coneActor = vtkActor.newInstance();
107+
coneActor.setMapper(coneMapper);
108+
coneActor.getProperty().setColor(0.5, 0.5, 1.0);
109+
110+
// ----------------------------------------------------------------------------
111+
// Add actors and setup camera
112+
// ----------------------------------------------------------------------------
113+
114+
renderer.addActor(coneActor);
115+
renderer.resetCamera();
116+
117+
// Set the center of rotation (this will stay fixed due to our overrides)
118+
const coneCenter = [0, 0, 0];
119+
interactorStyle.setCenterOfRotation(coneCenter);
120+
121+
// ----------------------------------------------------------------------------
122+
// Setup manipulators
123+
// ----------------------------------------------------------------------------
124+
125+
// Rotate with left button
126+
const rotateManipulator =
127+
vtkMouseCameraTrackballRotateManipulator.newInstance();
128+
rotateManipulator.setButton(1); // Left button
129+
interactorStyle.addMouseManipulator(rotateManipulator);
130+
131+
// Zoom with middle button
132+
const middleZoomManipulator =
133+
vtkMouseCameraTrackballZoomManipulator.newInstance();
134+
middleZoomManipulator.setButton(2); // Middle button
135+
interactorStyle.addMouseManipulator(middleZoomManipulator);
136+
137+
// Also allow pan with shift + left button
138+
const shiftPanManipulator = vtkMouseCameraTrackballPanManipulator.newInstance();
139+
shiftPanManipulator.setButton(1);
140+
shiftPanManipulator.setShift(true);
141+
interactorStyle.addMouseManipulator(shiftPanManipulator);
142+
143+
// Pan with right button
144+
const rightPanManipulator = vtkMouseCameraTrackballPanManipulator.newInstance();
145+
rightPanManipulator.setButton(3); // Right button
146+
interactorStyle.addMouseManipulator(rightPanManipulator);
147+
148+
// Zoom with mouse wheel
149+
const wheelZoomManipulator =
150+
vtkMouseCameraTrackballZoomManipulator.newInstance();
151+
wheelZoomManipulator.setScrollEnabled(true);
152+
wheelZoomManipulator.setDragEnabled(false);
153+
interactorStyle.addMouseManipulator(wheelZoomManipulator);
154+
155+
// Add gesture manipulator for touch devices
156+
interactorStyle.addGestureManipulator(
157+
vtkGestureCameraManipulator.newInstance()
158+
);
159+
160+
renderWindow.render();
161+
162+
const infoDiv = document.createElement('div');
163+
infoDiv.style.position = 'absolute';
164+
infoDiv.style.top = '10px';
165+
infoDiv.style.left = '10px';
166+
infoDiv.style.padding = '10px';
167+
infoDiv.style.background = 'rgba(255, 255, 255, 0.9)';
168+
infoDiv.style.borderRadius = '5px';
169+
infoDiv.style.fontFamily = 'monospace';
170+
infoDiv.innerHTML = `
171+
<h3>Rotate Around World Center Example</h3>
172+
<p>This example demonstrates rotation around a fixed world point instead of the camera center.</p>
173+
<p><strong>Controls:</strong></p>
174+
<ul>
175+
<li>Left Mouse: Rotate around cone center (world center)</li>
176+
<li>Middle Mouse: Zoom</li>
177+
<li>Right Mouse or Shift+Left: Pan (rotation center stays fixed)</li>
178+
<li>Mouse Wheel: Zoom</li>
179+
</ul>
180+
<p>Notice: After panning, rotation still occurs around the same world point (cone center).</p>
181+
`;
182+
document.body.appendChild(infoDiv);
183+
184+
// -----------------------------------------------------------
185+
// Make some variables global for debugging
186+
// -----------------------------------------------------------
187+
188+
global.coneSource = coneSource;
189+
global.coneActor = coneActor;
190+
global.renderer = renderer;
191+
global.renderWindow = renderWindow;
192+
global.interactorStyle = interactorStyle;

0 commit comments

Comments
 (0)