Skip to content

Commit

Permalink
Merge pull request #112 from PaulHax/camera-2d
Browse files Browse the repository at this point in the history
2D View: Orthographic camera and zooming
  • Loading branch information
thewtex authored Jan 30, 2024
2 parents 7be12c5 + dd80a96 commit 1dc7a9b
Show file tree
Hide file tree
Showing 19 changed files with 682 additions and 532 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ types/

.npmrc
.pnpm-store

# temp transpiled TS files that don't always get cleaned up
vite.config.ts.timestamp-*.mjs
vite.config.ts.timestamp-*.mts
2 changes: 2 additions & 0 deletions packages/arcball/src/arcball.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ declare module '@itk-viewer/arcball' {
pan: (dpan: ReadonlyVec2 | ReadonlyVec3) => void;
zoom: (delta: number) => void;
lookAt: (eye: ReadonlyVec3, center: ReadonlyVec3, up: ReadonlyVec3) => void;
center: vec3;
rotation: quat;
distance: number;
};

Expand Down
2 changes: 1 addition & 1 deletion packages/element/examples/multi-views.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>itk-view-2d</title>
<title>Multiple Views</title>
<link rel="stylesheet" href="index.css" />
<script type="module" src="../src/itk-viewer-element.ts"></script>
<!-- avoid error: the name "itk-viewport" has already been used with this registry -->
Expand Down
2 changes: 1 addition & 1 deletion packages/element/examples/view-3d.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>itk-view-2d</title>
<title>itk-view-3d</title>
<link rel="stylesheet" href="index.css" />
<script type="module" src="../src/itk-viewer-element.ts"></script>
<script type="module" src="../src/itk-viewport.ts"></script>
Expand Down
4 changes: 2 additions & 2 deletions packages/element/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@
"vite-plugin-static-copy": "^0.17.0"
},
"dependencies": {
"@itk-viewer/arcball": "workspace:^",
"@itk-viewer/io": "workspace:^",
"@itk-viewer/remote-viewport": "workspace:^",
"@itk-viewer/viewer": "workspace:^",
"@itk-viewer/vtkjs": "workspace:^",
"@itk-viewer/arcball": "workspace:^",
"@lit/context": "^1.1.0",
"gl-matrix": "^3.4.3",
"itk-wasm": "1.0.0-b.160",
"lit": "^3.1.0",
"xstate": "5.5.1",
"xstate": "5.5.2",
"xstate-lit": "^2.0.4"
}
}
57 changes: 33 additions & 24 deletions packages/element/src/itk-camera.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { LitElement, PropertyValues, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { ReadonlyMat4, mat4 } from 'gl-matrix';
import { ReadonlyQuat, ReadonlyVec3, quat, vec3 } from 'gl-matrix';
import { createArcballCamera, ArcballCamera } from '@itk-viewer/arcball';

import { Camera, LookAtParams } from '@itk-viewer/viewer/camera.js';
import { Camera, Pose } from '@itk-viewer/viewer/camera.js';
import { SelectorController } from 'xstate-lit';

const PAN_SPEED = 1;
Expand All @@ -12,15 +12,17 @@ const ZOOM_SPEED = 0.001;
const bindCamera = (
camera: ArcballCamera,
viewport: HTMLElement,
onUpdate: (view: ReadonlyMat4) => unknown,
onUpdate: (
center: ReadonlyVec3,
rotation: ReadonlyQuat,
distance: number,
) => unknown,
) => {
let width = viewport.clientWidth;
let height = viewport.clientHeight;

const view = mat4.create();

const updateView = () => {
onUpdate(camera.view(view));
onUpdate(camera.center, camera.rotation, camera.distance);
};

const resizeObserver = new ResizeObserver((entries) => {
Expand Down Expand Up @@ -115,8 +117,6 @@ const bindCamera = (
viewport.removeEventListener('contextmenu', preventDefault);
};

updateView();

return unBind;
};

Expand All @@ -125,8 +125,8 @@ export class ItkCamera extends LitElement {
@property({ attribute: false })
actor: Camera | undefined;

oldLookAt: LookAtParams | undefined;
lookAt: SelectorController<Camera, LookAtParams> | undefined;
oldPose: Pose | undefined;
pose: SelectorController<Camera, Pose> | undefined;

cameraController: ArcballCamera;
unBind: (() => unknown) | undefined;
Expand All @@ -141,13 +141,21 @@ export class ItkCamera extends LitElement {
}

firstUpdated(): void {
this.unBind = bindCamera(this.cameraController, this, (pose) => {
if (!this.actor) return;
this.actor.send({
type: 'setPose',
pose,
});
});
this.unBind = bindCamera(
this.cameraController,
this,
(center, rotation, distance) => {
if (!this.actor) return;
this.actor.send({
type: 'setPose',
pose: {
center,
rotation,
distance,
},
});
},
);
}

disconnectedCallback(): void {
Expand All @@ -157,18 +165,19 @@ export class ItkCamera extends LitElement {

willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has('actor') && this.actor) {
this.lookAt = new SelectorController(
this.pose = new SelectorController(
this,
this.actor,
(state) => state?.context.lookAt,
(state) => state?.context.pose,
);
}

if (this.lookAt?.value !== this.oldLookAt) {
this.oldLookAt = this.lookAt?.value;
if (this.lookAt?.value) {
const { eye, center, up } = this.lookAt.value;
this.cameraController.lookAt(eye, center, up);
if (this.pose?.value !== this.oldPose) {
this.oldPose = this.pose?.value;
if (this.pose?.value) {
vec3.copy(this.cameraController.center, this.pose.value.center);
quat.copy(this.cameraController.rotation, this.pose.value.rotation);
this.cameraController.distance = this.pose.value.distance;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/remote-viewport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@
"@itk-wasm/htj2k": "2.1.0",
"gl-matrix": "^3.4.3",
"imjoy-rpc": "^0.5.46",
"xstate": "5.5.1"
"xstate": "5.5.2"
}
}
4 changes: 3 additions & 1 deletion packages/remote-viewport/src/remote-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
createBounds,
ensuredDims,
} from '@itk-viewer/io/dimensionUtils.js';
import { toMat4 } from '@itk-viewer/viewer/camera.js';

const MAX_IMAGE_BYTES_DEFAULT = 4000 * 1000 * 1000; // 4000 MB

Expand Down Expand Up @@ -192,10 +193,11 @@ export const remoteMachine = createMachine(
id: 'remote',
context: ({ spawn, self }) => {
const viewport = spawn(viewportMachine, { id: 'viewport' });
const tempMat = mat4.create();
viewport.getSnapshot().context.camera.subscribe((state) => {
self.send({
type: 'cameraPoseUpdated',
pose: state.context.pose,
pose: toMat4(tempMat, state.context.pose),
});
});
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@
"dependencies": {
"@itk-viewer/io": "workspace:^",
"gl-matrix": "^3.4.3",
"xstate": "5.5.1"
"xstate": "5.5.2"
}
}
Loading

0 comments on commit 1dc7a9b

Please sign in to comment.