Improve viewer UI

This commit is contained in:
Tom 2025-02-13 08:04:51 +00:00
parent 3e3c325552
commit 6af7e0084e
4 changed files with 57 additions and 16 deletions

View File

@ -6,6 +6,7 @@ assets: /assets/blog/volume_rendering
thumbnail: /assets/blog/volume_rendering/thumbnail.png thumbnail: /assets/blog/volume_rendering/thumbnail.png
social_image: /assets/blog/volume_rendering/thumbnail.png social_image: /assets/blog/volume_rendering/thumbnail.png
image_class: invertable
alt: A volumetric render of a CT scan of my jaw. alt: A volumetric render of a CT scan of my jaw.

View File

@ -67,7 +67,7 @@ export class PointCloudViewer extends HTMLElement {
this.onWindowResize = () => { this.onWindowResize = () => {
this.camera.aspect = canvas.clientWidth / canvas.clientHeight; this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
this.camera.updateProjectionMatrix(); this.camera.updateProjectionMatrix();
renderer.setSize(canvas.clientWidth, canvas.clientHeight); renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
}; };
const timer = new Timer(); const timer = new Timer();

View File

@ -146,7 +146,8 @@ export class VolumeViewer extends HTMLElement {
} }
connectedCallback() { connectedCallback() {
const { container, canvas, scene, renderer, gui } = setupThreeJS(this); const { container, canvas, scene, renderer, gui, gui_buttons } =
setupThreeJS(this);
const model = this.getAttribute("model"); const model = this.getAttribute("model");
const model_metadata = this.getAttribute("model-metadata"); const model_metadata = this.getAttribute("model-metadata");
@ -215,7 +216,7 @@ export class VolumeViewer extends HTMLElement {
}; };
// Add a button to print the current settings to the console // Add a button to print the current settings to the console
gui gui_buttons
.add( .add(
{ {
printSettings: () => printSettings: () =>
@ -238,6 +239,7 @@ export class VolumeViewer extends HTMLElement {
}; };
gui gui
.add(renderProps, "preset", presets) .add(renderProps, "preset", presets)
.setValue("Default")
.onChange((preset) => { .onChange((preset) => {
Object.keys(preset).forEach((key) => { Object.keys(preset).forEach((key) => {
if (material.uniforms[key]) { if (material.uniforms[key]) {
@ -277,7 +279,7 @@ export class VolumeViewer extends HTMLElement {
this.onWindowResize = () => { this.onWindowResize = () => {
this.camera.aspect = canvas.clientWidth / canvas.clientHeight; this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
this.camera.updateProjectionMatrix(); this.camera.updateProjectionMatrix();
renderer.setSize(canvas.clientWidth, canvas.clientHeight); renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
}; };
this.onWindowResize(); this.onWindowResize();

View File

@ -117,9 +117,10 @@ function componentHTML(component_rect) {
color: var(--theme-subtle-outline); color: var(--theme-subtle-outline);
} }
.lil-gui .title {height: 2em;} .lil-gui .title {height: 2em;}
.lil-gui.root { .lil-gui.root {
margin-top: calc(${height}px - 2em); --height: 3em;
margin-top: calc(${height}px - var(--height));
width: 100%; width: 100%;
z-index: 1; z-index: 1;
--background-color: none; --background-color: none;
@ -132,6 +133,16 @@ function componentHTML(component_rect) {
--number-color: #2cc9ff; --number-color: #2cc9ff;
--string-color: #a2db3c; --string-color: #a2db3c;
} }
.lil-gui.root.closed {
height: var(--height);
}
#container.fullscreen > .lil-gui {
background-color: rgba(1,1,1, 0.5);
}
#container.fullscreen > .lil-gui.closed {
background-color: unset;
}
.lil-gui div.title { .lil-gui div.title {
margin: 0.5em; margin: 0.5em;
@ -161,15 +172,32 @@ function componentHTML(component_rect) {
height: 100%; height: 100%;
z-index: 1; z-index: 1;
background: var(--theme-bg-color); background: var(--theme-bg-color);
} }
#container.fullscreen canvas { #container.fullscreen canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%; height: 100%;
} }
#container.fullscreen .lil-gui.root { #container.fullscreen .lil-gui.root {
padding: 0.7em;
margin-top: 0; margin-top: 0;
width: 50%; }
#container.fullscreen .lil-gui.root > div.title {
margin: 0
}
.common-lil-gui-buttons .children {
display: flex;
flex-wrap: wrap;
justify-content: center;
button {
padding: 0.2em;
}
} }
</style> </style>
`; `;
@ -223,9 +251,14 @@ function setupThreeJS(component) {
}, },
}; };
component.gui.add(params, "printCamera").name("Print Viewport State"); let buttons = component.gui.addFolder("Actions");
component.gui.add(params, "screenshot").name("Take Screenshot"); buttons.open();
component.gui.add(params, "resetCamera").name("Reset Viewport"); buttons.$title.style.display = "none";
buttons.domElement.classList.add("common-lil-gui-buttons");
buttons.add(params, "printCamera").name("Print Viewport State");
buttons.add(params, "screenshot").name("Take Screenshot");
buttons.add(params, "resetCamera").name("Reset Viewport");
component.gui_buttons = buttons;
component.full_screen = false; component.full_screen = false;
// clone of original rect // clone of original rect
@ -235,16 +268,21 @@ function setupThreeJS(component) {
}; };
component.toggleFullScreen = () => { component.toggleFullScreen = () => {
if (!component.container.requestFullscreen) {
console.log("Fullscreen not supported");
return;
}
component.full_screen = !component.full_screen; component.full_screen = !component.full_screen;
if (component.full_screen) { if (component.full_screen) {
component.container.classList.add("fullscreen"); component.container.classList.add("fullscreen");
component.container.requestFullscreen();
} else { } else {
component.container.classList.remove("fullscreen"); component.container.classList.remove("fullscreen");
component.canvas.height = component.original_rect.height; component.canvas.style.height = component.original_rect.height + "px";
component.canvas.style.width = component.original_rect.width + "px";
document.exitFullscreen();
} }
component.canvas.removeAttribute("style");
component.canvas.removeAttribute("width");
component.canvas.removeAttribute("height");
component.onWindowResize(); component.onWindowResize();
}; };