Reference Source

src/plugins/AxisGizmoPlugin/AxisGizmoPlugin.js

import {Plugin} from "../../viewer/Plugin.js";
import {Scene} from "../../viewer/scene/scene/Scene.js";
import {AmbientLight} from "../../viewer/scene/lights/AmbientLight.js";
import {DirLight} from "../../viewer/scene/lights/DirLight.js";
import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
import {ReadableGeometry} from "../../viewer/scene/geometry/ReadableGeometry.js";
import {buildCylinderGeometry} from "../../viewer/scene/geometry/builders/buildCylinderGeometry.js";
import {buildSphereGeometry} from "../../viewer/scene/geometry/builders/buildSphereGeometry.js";
import {buildVectorTextGeometry} from "../../viewer/scene/geometry/builders/buildVectorTextGeometry.js";
import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js";
import {math} from "../../viewer/scene/math/math.js";

/**
 * {@link Viewer} plugin that shows the axii of the World-space coordinate system.
 *
 * ## Usage
 *
 * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_AxisGizmoPlugin)]
 *
 * ````JavaScript````
 * import {Viewer} from "../src/viewer/Viewer.js";
 * import {GLTFLoaderPlugin} from "../src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js";
 * import {AxisGizmoPlugin} from "../src/plugins/AxisGizmoPlugin/AxisGizmoPlugin.js";
 *
 * const viewer = new Viewer({
 *     canvasId: "myCanvas"
 * });
 *
 * const gltfLoader = new GLTFLoaderPlugin(viewer);
 *
 * new AxisGizmoPlugin(viewer, {size: [250, 250]});
 *
 * const model = gltfLoader.load({
 *     id: "myModel",
 *     src: "./models/gltf/schependomlaan/scene.gltf",
 *     metaModelSrc: "./metaModels/schependomlaan/metaModel.json",
 *     edges: true
 * });
 *
 * const scene = viewer.scene;
 * const camera = scene.camera;
 *
 * camera.orbitPitch(20);
 *
 * model.on("loaded", () => {
 *     viewer.cameraFlight.jumpTo(modelNode);
 *     scene.on("tick", () => {
 *        camera.orbitYaw(0.4);
 *     })
 * });
 * ````
 */
class AxisGizmoPlugin extends Plugin {

    /**
     * @constructor
     * @param {Viewer} viewer The Viewer.
     * @param {Object} cfg  Plugin configuration.
     * @param {String} [cfg.id="AxisGizmo"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
     * @param {Number[]} [cfg.size=[250,250]] Initial size in pixels.
     */
    constructor(viewer, cfg) {

        cfg = cfg || {};

        super("AxisGizmo", viewer, cfg);

        var camera = viewer.scene.camera;

        var size = cfg.size || [250, 250];

        var canvas = camera.scene.canvas;

        // Create canvas for this gizmo

        var canvasId = "xeokit-axisHelper-canvas-" + math.createUUID();
        var body = document.getElementsByTagName("body")[0];
        var div = document.createElement('div');
        var style = div.style;
        style.height = size[0] + "px";
        style.width = size[1] + "px";
        style.padding = "0";
        style.margin = "0";
        style.float = "left";
        style.left = "410px";
        style.bottom = "350px";
        style.position = "absolute";
        style["z-index"] = "1000000";
        // style["background-color"] = "rgba(0,0,0,0.3)";
        div.innerHTML += '<canvas id="' + canvasId + '" style="width: ' + size[0] + 'px; height: ' + size[1] + 'px; float: left; margin: 0; padding: 0;"></canvas>';
        body.appendChild(div);

        canvas.on("boundary",
            function (boundary) {
                style.left = boundary[0] + 10 + "px";
                style.bottom = (boundary[0] + 20) + "px";
            });

        // The scene containing this helper
        var scene = new Scene({
            canvasId: canvasId,
            transparent: true
        });

        // Custom lights
        scene.clearLights();

        new AmbientLight(scene, {
            color: [0.45, 0.45, 0.5],
            intensity: 0.9
        });

        new DirLight(scene, {
            dir: [-0.5, 0.5, -0.6],
            color: [0.8, 0.8, 0.7],
            intensity: 1.0,
            space: "view"
        });

        new DirLight(scene, {
            dir: [0.5, -0.5, -0.6],
            color: [0.8, 0.8, 0.8],
            intensity: 1.0,
            space: "view"
        });

        // Rotate helper in synch with target camera

        var helperCamera = scene.camera;

        camera.on("matrix", function () {

            var eye = camera.eye;
            var look = camera.look;
            var up = camera.up;

            var eyeLook = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, [])), 22);

            helperCamera.look = [0, 0, 0];
            helperCamera.eye = eyeLook;
            helperCamera.up = up;
        });

        // ----------------- Components that are shared among more than one mesh ---------------

        var arrowHead = new ReadableGeometry(scene, buildCylinderGeometry({
            radiusTop: 0.01,
            radiusBottom: 0.6,
            height: 1.7,
            radialSegments: 20,
            heightSegments: 1,
            openEnded: false
        }));

        var arrowShaft = new ReadableGeometry(scene, buildCylinderGeometry({
            radiusTop: 0.2,
            radiusBottom: 0.2,
            height: 4.5,
            radialSegments: 20,
            heightSegments: 1,
            openEnded: false
        }));

        var xAxisMaterial = new PhongMaterial(scene, { // Red by convention
            diffuse: [1, 0.3, 0.3],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });

        var xAxisLabelMaterial = new PhongMaterial(scene, { // Red by convention
            emissive: [1, 0.3, 0.3],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });

        var yAxisMaterial = new PhongMaterial(scene, { // Green by convention
            diffuse: [0.3, 1, 0.3],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });

        var yAxisLabelMaterial = new PhongMaterial(scene, { // Green by convention
            emissive: [0.3, 1, 0.3],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });


        var zAxisMaterial = new PhongMaterial(scene, { // Blue by convention
            diffuse: [0.3, 0.3, 1],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });

        var zAxisLabelMaterial = new PhongMaterial(scene, {
            emissive: [0.3, 0.3, 1],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });

        var ballMaterial = new PhongMaterial(scene, {
            diffuse: [0.5, 0.5, 0.5],
            ambient: [0.0, 0.0, 0.0],
            specular: [.6, .6, .3],
            shininess: 80,
            lineWidth: 2
        });


        // ----------------- Meshes ------------------------------

        this._meshes = [

            // Sphere behind gnomon

            new Mesh(scene, {
                geometry: new ReadableGeometry(scene, buildSphereGeometry({
                    radius: 9.0,
                    heightSegments: 60,
                    widthSegments: 60
                })),
                material: new PhongMaterial(scene, {
                    diffuse: [0.0, 0.0, 0.0],
                    emissive: [0.1, 0.1, 0.1],
                    ambient: [0.1, 0.1, 0.2],
                    specular: [0, 0, 0],
                    alpha: 0.4,
                    alphaMode: "blend",
                    frontface: "cw"
                }),
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false
            }),

            // Ball at center of axis

            new Mesh(scene, {  // Arrow
                geometry: new ReadableGeometry(scene, buildSphereGeometry({
                    radius: 1.0
                })),
                material: ballMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false
            }),

            // X-axis arrow, shaft and label

            new Mesh(scene, {  // Arrow
                geometry: arrowHead,
                material: xAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [-5, 0, 0],
                rotation: [0, 0, 90]
            }),

            new Mesh(scene, {  // Shaft
                geometry: arrowShaft,
                material: xAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [-2, 0, 0],
                rotation: [0, 0, 90]
            }),

            new Mesh(scene, {  // Label
                geometry: new ReadableGeometry(scene, buildVectorTextGeometry({text: "X", size: 1.5})),
                material: xAxisLabelMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [-7, 0, 0],
                billboard: "spherical"
            }),

            // Y-axis arrow, shaft and label

            new Mesh(scene, {  // Arrow
                geometry: arrowHead,
                material: yAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 5, 0]
            }),

            new Mesh(scene, {  // Shaft
                geometry: arrowShaft,
                material: yAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 2, 0]
            }),

            new Mesh(scene, {  // Label
                geometry: new ReadableGeometry(scene, buildVectorTextGeometry({text: "Y", size: 1.5})),
                material: yAxisLabelMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 7, 0],
                billboard: "spherical"
            }),

            // Z-axis arrow, shaft and label

            new Mesh(scene, {  // Arrow
                geometry: arrowHead,
                material: zAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 0, 5],
                rotation: [90, 0, 0]
            }),

            new Mesh(scene, {  // Shaft
                geometry: arrowShaft,
                material: zAxisMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 0, 2],
                rotation: [90, 0, 0]
            }),

            new Mesh(scene, {  // Label
                geometry: new ReadableGeometry(scene, buildVectorTextGeometry({text: "Z", size: 1.5})),
                material: zAxisLabelMaterial,
                pickable: false,
                collidable: false,
                visible: cfg.visible !== false,
                position: [0, 0, 7],
                billboard: "spherical"
            })
        ];
    }

    /** Shows or hides this helper
     *
     * @param visible
     */
    setVisible(visible) {
        for (var i = 0; i < this._meshes.length; i++) {
            this._meshes[i].visible = visible;
        }
    }

    /**
     * Destroys this AxisGizmoPlugin.
     */
    destroy() {
        super.destroy();
    }
}

export {AxisGizmoPlugin}