Display Giro3D scenes in with different layouts (flex, sticky, fixed, etc.).

Sticky position
Nested flex layouts
Custom WebGL Renderer
Overflow
Fixed position
100% Map style by Stamen Design, © OpenStreetMap contributors
index.js
import { WebGLRenderer } from 'three';
import { MapControls } from 'three/examples/jsm/controls/MapControls.js';

import StadiaMaps from 'ol/source/StadiaMaps.js';

import Extent from '@giro3d/giro3d/core/geographic/Extent.js';
import Instance from '@giro3d/giro3d/core/Instance.js';
import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer.js';
import Map from '@giro3d/giro3d/entities/Map.js';
import TiledImageSource from '@giro3d/giro3d/sources/TiledImageSource.js';

const extent = new Extent(
    'EPSG:3857',
    -20037508.342789244,
    20037508.342789244,
    -20037508.342789244,
    20037508.342789244,
);

const source = new TiledImageSource({
    source: new StadiaMaps({ layer: 'stamen_watercolor', wrapX: false }),
});

function buildViewer(viewerDiv, defaultRenderer = true) {
    const renderer = { clearColor: false };
    if (!defaultRenderer) {
        renderer.renderer = new WebGLRenderer({ antialias: true, alpha: true });
    }
    const instance = new Instance(viewerDiv, { renderer, crs: extent.crs() });
    // Creates a map that will contain the layer
    const map = new Map('planar', { extent, maxSubdivisionLevel: 10 });

    instance.add(map);

    // Adds an TMS imagery layer
    map.addLayer(
        new ColorLayer({
            name: 'osm',
            source,
        }),
    ).catch(e => console.error(e));

    instance.camera.camera3D.position.set(0, 0, 25000000);

    const controls = new MapControls(instance.camera.camera3D, instance.domElement);

    instance.useTHREEControls(controls);

    // Disable zoom so it doesn't capture scrolling
    controls.enableZoom = false;
}

// Remove the pre-generated default HTML elements for this example
document.getElementById('viewerDiv').remove();
document.getElementById('panelDiv').remove();

// Dynamically find all viewers we have to build
const viewerDivs = document.getElementsByClassName('viewer');
for (let i = 0; i < viewerDivs.length; i += 1) {
    buildViewer(viewerDivs[i]);
}

// Dynamically find all viewers we have to build with custom WebGLRenderers
const viewerCustomRendererDivs = document.getElementsByClassName('viewer-custom-renderer');
for (let i = 0; i < viewerCustomRendererDivs.length; i += 1) {
    buildViewer(viewerCustomRendererDivs[i], false);
}
index.html
<!doctype html>
<html lang="en">
    <head>
        <title>Multiple instances in different layouts</title>
        <meta charset="UTF-8" />
        <meta name="name" content="layouts" />
        <meta name="description" content="Display Giro3D scenes in with different layouts (flex, sticky, fixed, etc.)." />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />

        <link rel="icon" href="https://giro3d.org/images/favicon.svg" />
        <link href="https://giro3d.org/assets/bootstrap-custom.css" rel="stylesheet" />
        <script src="https://giro3d.org/assets/bootstrap.bundle.min.js"></script>
        <link
            rel="stylesheet"
            type="text/css"
            href="https://giro3d.org/latest/css/example.css"
        />

        <style>
        /* Reset page height so we can scroll */
        html {
          height: auto;
        }
        body {
          height: auto;
        }

        #legendSticky,
        #viewerDivSticky {
          background: linear-gradient(to right, rgb(125, 199, 144), rgb(11, 59, 23));
        }

        #legendNestedFlex {
          writing-mode: vertical-rl;
        }
        #containerFlex {
          background: linear-gradient(to right, rgb(251, 165, 116), rgb(216, 245, 251));
        }

        #legendOverflow,
        #viewerDivOverflow {
          background: linear-gradient(to right, rgb(251, 251, 255), rgb(215, 223, 252));
        }

        #viewerDivFixed {
          background: linear-gradient(to right, rgb(65, 80, 95), rgb(36, 37, 38));
        }
        #legendFixed {
          color: #fff;
        }

        #source {
          margin-bottom: 250px !important;
        }
        </style>
    </head>

    <body>
        <div id="viewerDiv" class="m-0 p-0 w-100 h-100"></div>
        <div id="panelDiv" class="position-absolute top-0 start-0 mh-100 overflow-auto"></div>

        <!--
            In all examples we are using Bootstrap classes for styling.
            Here, we are using:
            - plain-old styles to show how to use different layouts,
            - Bootstrap classes and embedded <style> for pure styling (borders, padding, margin, backgrounds, etc.).
        -->

        <div id="legendSticky" style="position: sticky; z-index: 1021; top: 0" class="ps-2">
            Sticky position
        </div>
        <!-- A container must have a size (height+width), and can have any style applied-->
        <div
            id="viewerDivSticky"
            style="position: sticky; z-index: 1020; top: 0; height: 300px; width: 100%"
            class="viewer p-2 border-bottom border-5 border-dark"
        ></div>

        <div id="containerFlex" style="display: flex; align-items: stretch; height: 50vh" class="mt-5">
            <div id="legendNestedFlex" class="pt-2">Nested flex layouts</div>
            <!-- In flex display, a container can have a flex property instead of a size -->
            <div id="viewerDivNestedFlex1" style="flex: 1 1 auto" class="viewer ps-2 pe-2"></div>

            <!--
                In case you are using your own renderer, you are responsible for the layout, for instance:
                - a parent div to set the element size - this is were you would want to apply borders, padding, backgrounds, etc.
                - a viewport div that fills it parent and has "position: relative" and "overflow: hidden"
                    - this is to ensure a correct sizing of the renderer when the parent div is resized
                - the div that will hold your renderer, that fills its parent
            -->
            <div style="min-width: 20vw; height: 100%" class="p-5 border border-3 border-dark">
                <div
                    id="customViewDivContainer"
                    style="position: relative; overflow: hidden; width: 100%; height: 100%"
                >
                    <div
                        id="customViewerDiv"
                        style="width: 100%; height: 100%"
                        class="viewer-custom-renderer"
                    ></div>
                </div>
                <span class="position-absolute">Custom WebGL Renderer</span>
            </div>
        </div>

        <div id="legendOverflow" class="mt-5 ps-2">Overflow</div>
        <!-- You can also have containers that are larger than the viewport -->
        <div id="viewerDivOverflow" style="width: 100%; height: 200vh" class="viewer p-2"></div>

        <!-- You can also have containers that are at fixed positions -->
        <div
            id="viewerDivFixed"
            style="position: fixed; left: 0; bottom: 0; height: 200px; width: 50vw"
            class="viewer p-2 border border-3 border-dark"
        ></div>
        <!-- Any Giro3D container can have overlays, as long as they are after in the DOM (or using z-index) -->
        <span id="legendFixed" style="position: fixed; left: 0; bottom: 0" class="ps-2">
            Fixed position
        </span>

        <script type="module" src="index.js"></script>
        <script>
            /* activate popovers */
            const popoverTriggerList = [].slice.call(
                document.querySelectorAll('[data-bs-toggle="popover"]'),
            );
            popoverTriggerList.map(
                // bootstrap is used as script in the template, disable warning about undef
                // eslint-disable-next-line no-undef
                popoverTriggerEl =>
                    new bootstrap.Popover(popoverTriggerEl, {
                        trigger: 'hover',
                        placement: 'left',
                        content: document.getElementById(
                            popoverTriggerEl.getAttribute('data-bs-content'),
                        ).innerHTML,
                        html: true,
                    }),
            );
        </script>
    </body>
</html>
package.json
{
    "name": "layouts",
    "dependencies": {
        "@giro3d/giro3d": "0.37.3"
    },
    "devDependencies": {
        "vite": "^3.2.3"
    },
    "scripts": {
        "start": "vite",
        "build": "vite build"
    }
}