Skip to content

Commit

Permalink
Merge pull request #163 from PaulHax/tf-3d
Browse files Browse the repository at this point in the history
Opacity and color range function editor for View 3D
  • Loading branch information
thewtex authored Jul 15, 2024
2 parents cf07f83 + dae0e89 commit 38f9201
Show file tree
Hide file tree
Showing 28 changed files with 757 additions and 282 deletions.
8 changes: 8 additions & 0 deletions .changeset/tall-cycles-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@itk-viewer/transfer-function-editor': minor
'@itk-viewer/element': minor
'@itk-viewer/viewer': minor
'@itk-viewer/vtkjs': minor
---

Add opacity function editor to View 3D.
23 changes: 13 additions & 10 deletions packages/element/examples/view-3d.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
<link rel="icon" type="image/svg+xml" href="itk-viewer-logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<script type="module" src="../src/itk-view-3d.ts"></script>

<script type="module" src="./view-3d.ts"></script>
<script type="module" src="../src/itk-viewer-3d.ts"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.13.1/cdn/themes/light.css"
/>
<script
type="module"
src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.13.1/cdn/shoelace.js"
></script>

<script type="module" src="view-3d.ts"></script>
<link rel="stylesheet" href="index.css" />
</head>

<body>
<itk-viewer class="fill">
<itk-viewport class="fill">
<itk-view-3d renderer="vtkjs" class="fill"></itk-view-3d>
</itk-viewport>
</itk-viewer>
<itk-viewer-3d id="viewer"></itk-viewer-3d>
</body>
</html>
12 changes: 6 additions & 6 deletions packages/element/examples/view-3d.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { ZarrMultiscaleSpatialImage } from '@itk-viewer/io/ZarrMultiscaleSpatialImage.js';
import { setPipelineWorkerUrl, setPipelinesBaseUrl } from 'itk-wasm';
import { ItkViewer3d } from '../src/itk-viewer-3d.js';

const pipelineWorkerUrl = '/itk/web-workers/itk-wasm-pipeline.min.worker.js';
setPipelineWorkerUrl(pipelineWorkerUrl);
const pipelineBaseUrl = '/itk/pipelines';
setPipelinesBaseUrl(pipelineBaseUrl);

document.addEventListener('DOMContentLoaded', async function () {
const viewerElement = document.querySelector('#viewer')! as ItkViewer3d;
const viewer = viewerElement.getActor();

const imagePath = '/ome-ngff-prototypes/single_image/v0.4/zyx.ome.zarr';
const url = new URL(imagePath, document.location.origin);
const image = await ZarrMultiscaleSpatialImage.fromUrl(url);

const viewerElement = document.querySelector('itk-viewer');
if (!viewerElement) throw new Error('Could not find element');
const viewer = viewerElement.getActor();
const zarrImage = await ZarrMultiscaleSpatialImage.fromUrl(url);

viewer.send({ type: 'setImage', image, name: 'image' });
viewer!.send({ type: 'setImage', image: zarrImage, name: 'image' });
});
4 changes: 2 additions & 2 deletions packages/element/src/itk-view-2d-controls-material.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { LitElement, css, html, nothing } from 'lit';
import { View2dActor } from '@itk-viewer/viewer/view-2d.js';
import { customElement } from 'lit/decorators.js';
import { View2dControls } from './view-2d-controls-controller.js';
import { ViewControls } from './view-controls-controller.js';
import '@material/web/slider/slider.js';
import '@material/web/select/outlined-select.js';
import '@material/web/select/select-option.js';

@customElement('itk-view-2d-controls-material')
export class View2dControlsMaterial extends LitElement {
actor: View2dActor | undefined;
private controls = new View2dControls(this);
private controls = new ViewControls(this);

setActor(actor: View2dActor) {
this.actor = actor;
Expand Down
40 changes: 9 additions & 31 deletions packages/element/src/itk-view-3d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { View3dActor, view3d } from '@itk-viewer/viewer/view-3d.js';
import { LitElement, css, html, nothing } from 'lit';
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { SelectorController } from 'xstate-lit';
import { dispatchSpawn, handleLogic } from './spawn-controller.js';
Expand Down Expand Up @@ -51,7 +51,7 @@ export class ItkView3d extends LitElement {
this.actor!.send({ type: 'setScale', scale });
}

getAttributeRenderer() {
getRenderer() {
if (this.renderer === 'vtkjs') {
return html`<itk-view-3d-vtkjs></itk-view-3d-vtkjs>`;
} else if (this.renderer === 'slot') {
Expand All @@ -67,40 +67,18 @@ export class ItkView3d extends LitElement {
this.dispatched = true;
}

const scale = this.scale?.value ?? 0;
const scaleCount = this.scaleCount?.value ?? 1;
const scaleOptions = Array.from(
{ length: scaleCount },
(_, i) => i,
).reverse();

return html`
<h1>View 3D</h1>
<div>
<label for="scale-select">Scale</label>
<select value=${scale} @change="${this.onScale}" type="choice">
${scaleOptions.map(
(option) =>
html`<option selected=${option === scale || nothing}>
${option}
</option>`,
)}
</select>
</div>
<div class="fill" @renderer=${handleLogic(this.actor)}>
<itk-camera .actor=${this.cameraActor?.value} class="fill">
${this.getAttributeRenderer()}
</itk-camera>
</div>
<itk-camera
class="fill"
.actor=${this.cameraActor?.value}
@renderer=${handleLogic(this.actor)}
>
${this.getRenderer()}
</itk-camera>
`;
}

static styles = css`
:host {
display: flex;
flex-direction: column;
}
.fill {
flex: 1;
min-height: 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { LitElement, html } from 'lit';
import { View2dActor } from '@itk-viewer/viewer/view-2d.js';
import { customElement } from 'lit/decorators.js';
import { View2dControls } from './view-2d-controls-controller.js';
import { LitElement, PropertyValues, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { ViewControls, ViewActor } from './view-controls-controller.js';
import { ref } from 'lit/directives/ref.js';

@customElement('itk-view-2d-controls-shoelace')
export class View2dControlsShoelace extends LitElement {
actor: View2dActor | undefined;
private controls = new View2dControls(this);
@customElement('itk-view-controls-shoelace')
export class ViewControlsShoelace extends LitElement {
@property({ type: String })
view: '2d' | '3d' = '2d';

setActor(actor: View2dActor) {
actor: ViewActor | undefined;
private controls = new ViewControls(this);

setActor(actor: ViewActor) {
this.actor = actor;
this.controls.setActor(actor);
}
Expand All @@ -18,6 +20,12 @@ export class View2dControlsShoelace extends LitElement {
this.controls.setTransferFunctionContainer(container);
}

willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has('view')) {
this.controls.setView(this.view);
}
}

render() {
const slice = this.controls.slice?.value;
const axis = this.controls.axis?.value;
Expand All @@ -31,12 +39,11 @@ export class View2dControlsShoelace extends LitElement {

const threeD = imageDimension >= 3;
const showScale = scaleCount >= 2;
if (!threeD && !showScale) {
return '';
}
const tfEditorHeight = this.view === '2d' ? '2rem' : '8rem';

return html`
<sl-card>
${threeD
${threeD && this.view === '2d'
? html`
<label>
<sl-range
Expand Down Expand Up @@ -79,7 +86,7 @@ export class View2dControlsShoelace extends LitElement {
<div style="padding-top: 0.4rem;">Color Range</div>
<div
${ref(this.transferFunctionContainerChanged)}
style="width: 14rem; height: 2rem;"
style=${`width: 14rem; height: ${tfEditorHeight};`}
></div>
</sl-card>
`;
Expand All @@ -88,6 +95,6 @@ export class View2dControlsShoelace extends LitElement {

declare global {
interface HTMLElementTagNameMap {
'itk-view-2d-controls-shoelace': View2dControlsShoelace;
'itk-view-2d-controls-shoelace': ViewControlsShoelace;
}
}
20 changes: 9 additions & 11 deletions packages/element/src/itk-viewer-2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import { Ref, createRef, ref } from 'lit/directives/ref.js';
import './itk-viewer-element.js';
import { ItkViewer } from './itk-viewer-element.js';
import './itk-viewport.js';
import './itk-view-2d.js';
import { ItkView2d } from './itk-view-2d.js';
import './itk-view-2d.js';
import './itk-view-2d-vtkjs.js';
import { View2dControlsShoelace } from './itk-view-2d-controls-shoelace.js';
import './itk-view-2d-controls-shoelace.js';
// import './itk-view-2d-controls-material.js';
import { ViewControlsShoelace } from './itk-view-controls-shoelace.js';
import './itk-view-controls-shoelace.js';

@customElement('itk-viewer-2d')
export class ItkViewer2d extends LitElement {
viewer: Ref<ItkViewer> = createRef();
view: Ref<ItkView2d> = createRef();
controls: Ref<View2dControlsShoelace> = createRef();
controls: Ref<ViewControlsShoelace> = createRef();

getActor() {
return this.viewer.value?.getActor();
Expand All @@ -27,12 +26,10 @@ export class ItkViewer2d extends LitElement {
<itk-viewport class="fill">
<div style="position: relative" class="fill">
<div style="position: absolute; top: 0.25rem; left: 0.25rem">
<itk-view-2d-controls-shoelace
${ref(this.controls)}
></itk-view-2d-controls-shoelace>
<!-- <itk-view-2d-controls-material
<itk-view-controls-shoelace
view="2d"
${ref(this.controls)}
></itk-view-2d-controls-material> -->
></itk-view-controls-shoelace>
</div>
<itk-view-2d ${ref(this.view)} class="fill">
<itk-view-2d-vtkjs></itk-view-2d-vtkjs>
Expand All @@ -44,7 +41,8 @@ export class ItkViewer2d extends LitElement {
}

protected async firstUpdated() {
await this.updateComplete; // Wait for view to render
// Wait for view to render so view actor is created
await this.updateComplete;
const viewActor = this.view.value!.getActor()!;
const controls = this.controls.value!;
controls.setActor(viewActor);
Expand Down
27 changes: 24 additions & 3 deletions packages/element/src/itk-viewer-3d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { LitElement, css, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { Ref, createRef, ref } from 'lit/directives/ref.js';
import './itk-viewer-element.js';
import { ItkViewer } from './itk-viewer-element.js';
import './itk-viewport.js';
import { ItkView3d } from './itk-view-3d.js';
import './itk-view-3d.js';
import './itk-view-3d-vtkjs.js';
import { ViewControlsShoelace } from './itk-view-controls-shoelace.js';
import './itk-view-controls-shoelace.js';

@customElement('itk-viewer-3d')
export class ItkViewer3d extends LitElement {
viewer: Ref<ItkViewer> = createRef();
view: Ref<ItkView3d> = createRef();
controls: Ref<ViewControlsShoelace> = createRef();

getActor() {
return this.viewer.value?.getActor();
Expand All @@ -18,14 +24,29 @@ export class ItkViewer3d extends LitElement {
return html`
<itk-viewer class="fill" ${ref(this.viewer)}>
<itk-viewport class="fill">
<itk-view-3d class="fill">
<itk-view-3d-vtkjs></itk-view-3d-vtkjs>
</itk-view-3d>
<div style="position: relative" class="fill">
<div style="position: absolute; top: 0.25rem; left: 0.25rem">
<itk-view-controls-shoelace
view="3d"
${ref(this.controls)}
></itk-view-controls-shoelace>
</div>
<itk-view-3d ${ref(this.view)} class="fill">
<itk-view-3d-vtkjs></itk-view-3d-vtkjs>
</itk-view-3d>
</div>
</itk-viewport>
</itk-viewer>
`;
}

protected async firstUpdated() {
await this.updateComplete; // Wait for view to render
const viewActor = this.view.value!.getActor()!;
const controls = this.controls.value!;
controls.setActor(viewActor);
}

static styles = css`
:host {
width: 100%;
Expand Down
Loading

0 comments on commit 38f9201

Please sign in to comment.