0

I am currently working on an interactive UI in Jupyter Notebook based mainly on IPy Widgets to feature 3D interactive models created and exported previously using Blender. I used an HTML 3D model viewer to show the 3D model (see code below), which works perfectly fine but when I try to publish the Jupyter Notebook e.g. using Voíla it will show everything except for the 3D model (see images attached). Has anyone else encountered this issue or has an idea of how to solve it?

Any hint would be much appreciated, cheers!

JupyterNotebook before publishing with 3D model shown correctly

JupyterNotebook after publishing with Voila

The HTML model viewer code:

from IPython.display import HTML, Javascript, display

# Load the model-viewer script once
display(Javascript("""
if (!window.modelViewerLoaded) {
    const script = document.createElement('script');
    script.type = 'module';
    script.src = 'https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js';
    document.head.appendChild(script);
    window.modelViewerLoaded = true;
}
"""))

# Define the model viewer display function
def display_model_waterdepth(glb_path):
    return HTML(f"""
    <div class="mv-wrap" style="position: relative; width: 100%; height: 375px;">
      <model-viewer src="{glb_path}" alt="Waterdepth model"
        interaction-prompt="auto" interaction-prompt-threshold="8000"
        disable-default-lighting shadow-intensity="0" shadow-softness="0"
        exposure="0.003" environment-image="neutral" camera-controls 
        background-color="#FDF0F5" camera-orbit="0deg 0deg 7000m" 
        min-camera-orbit="auto auto 1m" max-camera-orbit="auto auto 10000m"
        field-of-view="45deg"
        style="width: 100%; height: 100%; filter: brightness(1.0) contrast(1.3);">
      </model-viewer>

      <div style="position: absolute; bottom: 10px; right: 10px; 
                  display: flex; flex-direction: column; align-items: flex-end; gap: 5px; z-index: 10;">
        <button data-zoomplus style="background-color: #f8f8f8; width: 25px; height: 25px;">+</button>
        <button data-zoomminus style="background-color: #f8f8f8; width: 25px; height: 25px;">-</button>
        <button data-reset style="background-color: #f8f8f8; width: 25px; height: 25px;">⟳</button>
        <button data-focus="1" style="background-color: #f8f8f8; width: 100px; height: 25px;">Neubacher Au</button>
        <button data-focus="2" style="background-color: #f8f8f8; width: 100px; height: 25px;">Ofenloch</button>
      </div>
    </div>

    <script>
    (function() {{
      const root = document.currentScript.previousElementSibling;
      const viewer = root.querySelector('model-viewer');

      root.querySelector('[data-zoomplus]').addEventListener('click', () => {{
        const o = viewer.getCameraOrbit();
        viewer.cameraOrbit = `${{o.theta}}rad ${{o.phi}}rad ${{o.radius * 0.9}}m`;
      }});
      root.querySelector('[data-zoomminus]').addEventListener('click', () => {{
        const o = viewer.getCameraOrbit();
        viewer.cameraOrbit = `${{o.theta}}rad ${{o.phi}}rad ${{o.radius * 1.1}}m`;
      }});
      root.querySelector('[data-reset]').addEventListener('click', () => {{
        viewer.cameraOrbit = "0deg 0deg 7000m";
        viewer.cameraTarget = "auto auto auto";
        viewer.fieldOfView = "45deg";
        viewer.jumpCameraToGoal();
      }});
      root.querySelectorAll('[data-focus]').forEach(btn => {{
        btn.addEventListener('click', () => {{
          const area = btn.getAttribute('data-focus');
          if (area === "1") {{
            viewer.cameraOrbit = "0deg 0deg 2300m";
            viewer.cameraTarget = "-850m 0m -450m";
          }} else {{
            viewer.cameraOrbit = "55deg 0deg 1800m";
            viewer.cameraTarget = "1000m 230m -250m";
          }}
          viewer.jumpCameraToGoal();
        }});
      }});
    }})();
    </script>
    """)
3
  • It is my understanding Voila is meant to work with ipywidgets or custom Jupyter widgets. I would recommend reading this page and read between the lines about the examples. Plus, read the part at the start here. Anyway, I think this is more of a simple solution than StackOverflow is meant to cover, plus you may get more guidance of experts by posting on the Jupyter Discoruse Forum, also where discussion is more encouraged. ... Commented Sep 4 at 14:32
  • <continued> Link to Jupyter Community Discourse Forum is here. Honestly, I am a little surprised your javascript works in the current versions of Jupyter. Can you say which specific version and interface you are using for that picture where it works? Although maybe you did it the correct way and I am not up-to-date on all the tricks. Or maybe a recent update restored more functionality. Commented Sep 4 at 14:36
  • Anyway, discussing it at the Discourse Forum may point you to alternatives, too, especially if you are willing to pivot away from Voila to make the app. ... I should have mentioned you may need to write an extension to do this if one doesn't already exist and you want to stick with Voila. Commented Sep 4 at 16:19

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.