Skip to content

Commit a5442ea

Browse files
authored
Button to Center view on visible objects (#452)
* Can't access camera * Use CustomEvent to emit and trigger correct method * Use CustomEvent to emit and trigger correct method * Use MainViewModel ID to only trigger correct model * Rename custom event to `jupytercadObjectSelection` * Return full `MainViewModel` with `get mainViewModel()`
1 parent 2a39e90 commit a5442ea

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

packages/base/src/3dview/mainview.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ export class MainView extends React.Component<IProps, IStates> {
117117
this.addContextMenu();
118118
this._mainViewModel.initWorker();
119119
this._mainViewModel.initSignal();
120+
window.addEventListener('jupytercadObjectSelection', (e: Event) => {
121+
const customEvent = e as CustomEvent;
122+
123+
if (customEvent.detail.mainViewModelId === this._mainViewModel.id) {
124+
this.lookAtPosition(customEvent.detail.objPosition);
125+
}
126+
});
120127
}
121128

122129
componentDidUpdate(oldProps: IProps, oldState: IStates): void {
@@ -435,6 +442,31 @@ export class MainView extends React.Component<IProps, IStates> {
435442
this.resizeCanvasToDisplaySize();
436443
};
437444

445+
private lookAtPosition(position: { x: number; y: number; z: number }) {
446+
const objPosition = new THREE.Vector3(
447+
position[0],
448+
position[1],
449+
position[2]
450+
);
451+
if (this._camera) {
452+
this._camera.lookAt(objPosition);
453+
const cameraToTargetDistance =
454+
this._camera.position.distanceTo(objPosition);
455+
456+
if (cameraToTargetDistance < 1) {
457+
// Move the camera back slightly to ensure visibility
458+
this._camera.position.add(
459+
this._camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-2)
460+
);
461+
}
462+
this._camera.updateProjectionMatrix();
463+
}
464+
if (this._controls) {
465+
this._controls.target.copy(objPosition);
466+
this._controls.update();
467+
}
468+
}
469+
438470
private _updateAnnotation() {
439471
Object.keys(this.state.annotations).forEach(key => {
440472
const el = document.getElementById(key);

packages/base/src/panelview/model.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { ISignal } from '@lumino/signaling';
33

44
import { IJupyterCadTracker, IJupyterCadWidget } from '@jupytercad/schema';
55
import { IControlPanelModel } from '../types';
6+
import { JupyterCadWidget } from '../widget';
7+
import { MainViewModel } from '../3dview/mainviewmodel';
68

79
export class ControlPanelModel implements IControlPanelModel {
810
constructor(options: ControlPanelModel.IOptions) {
@@ -26,6 +28,11 @@ export class ControlPanelModel implements IControlPanelModel {
2628
return this._tracker.currentWidget?.context.model.sharedModel;
2729
}
2830

31+
get mainViewModel(): MainViewModel | undefined {
32+
return (this._tracker.currentWidget as JupyterCadWidget | null)?.content
33+
.currentViewModel;
34+
}
35+
2936
disconnect(f: any): void {
3037
this._tracker.forEach(w => {
3138
w.context.model.sharedObjectsChanged.disconnect(f);

packages/base/src/panelview/objecttree.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,27 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {
237237
this.setState(old => ({ ...old, lightTheme }));
238238
};
239239

240+
handleNodeClick = (objectId: string) => {
241+
const object = this.getObjectFromName(objectId);
242+
243+
if (object && object.visible === true) {
244+
const objPosition = object?.parameters?.Placement?.Position || {
245+
x: 0,
246+
y: 0,
247+
z: 0
248+
};
249+
250+
const event = new CustomEvent('jupytercadObjectSelection', {
251+
detail: {
252+
objectId,
253+
objPosition,
254+
mainViewModelId: this.props.cpModel.mainViewModel?.id
255+
}
256+
});
257+
window.dispatchEvent(event);
258+
}
259+
};
260+
240261
private _sharedJcadModelChanged = (
241262
sender: IJupyterCadDoc,
242263
change: IJcadObjectDocChange
@@ -378,9 +399,8 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {
378399

379400
return (
380401
<div
381-
className={`jpcad-control-panel-tree ${
382-
opts.selected ? 'selected' : ''
383-
}`}
402+
className={`jpcad-control-panel-tree ${opts.selected ? 'selected' : ''}`}
403+
onClick={() => this.handleNodeClick(opts.node.id as string)}
384404
>
385405
<div
386406
style={{

packages/base/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ISignal } from '@lumino/signaling';
22
import { IJupyterCadModel, IJupyterCadDoc, IDict } from '@jupytercad/schema';
33
import { IJupyterCadTracker, IJupyterCadWidget } from '@jupytercad/schema';
4+
import { MainViewModel } from './3dview/mainviewmodel';
45

56
export { IDict };
67
export type ValueOf<T> = T[keyof T];
@@ -42,4 +43,5 @@ export interface IControlPanelModel {
4243
filePath: string | undefined;
4344
jcadModel: IJupyterCadModel | undefined;
4445
sharedModel: IJupyterCadDoc | undefined;
46+
mainViewModel: MainViewModel | undefined;
4547
}

0 commit comments

Comments
 (0)