Source: og/control/MouseWheelZoomControl.js

/**
 * @module og/control/MouseWheelZoomControl
 */

"use strict";

import { Control } from "./Control.js";
import { Key } from "../Lock.js";
import { Quat } from "../math/Quat.js";
import { Sphere } from "../bv/Sphere.js";
import { Vec3 } from "../math/Vec3.js";
import { MouseNavigation } from "./MouseNavigation.js";

/**
 * Planet zoom buttons control.
 * @class
 * @extends {Control}
 * @params {Object} [options] - Control options.
 */
class MouseWheelZoomControl extends Control {
    constructor(options) {
        super(options);

        this._name = "MouseWheelZoomControl";

        options = options || {};

        this.grabbedPoint = new Vec3();
        this._eye0 = new Vec3();
        this.pointOnEarth = new Vec3();
        this.earthUp = new Vec3();
        this.inertia = 0.007;
        this.grabbedSpheroid = new Sphere();
        this.planet = null;
        this.qRot = new Quat();
        this.scaleRot = 0.0;

        this.distDiff = 0.3;
        this.stepsCount = 8;
        this.stepsForward = null;
        this.stepIndex = 0;

        this._lmbDoubleClickActive = true;

        this.minSlope = options.minSlope || 0.1;

        this._keyLock = new Key();
    }

    oninit() {
        var zoomDiv = document.createElement("div"),
            btnZoomIn = document.createElement("button"),
            btnZoomOut = document.createElement("button");

        zoomDiv.className = "ogZoomControl";
        btnZoomIn.className = "ogZoomButton ogZoomIn";
        btnZoomOut.className = "ogZoomButton ogZoomOut";

        zoomDiv.appendChild(btnZoomIn);
        zoomDiv.appendChild(btnZoomOut);

        this.renderer.div.appendChild(zoomDiv);

        btnZoomIn.addEventListener("mousedown", (e) => this.zoomIn());
        btnZoomIn.addEventListener("mouseup", (e) => this.stopZoom());

        btnZoomOut.addEventListener("mousedown", (e) => this.zoomOut());
        btnZoomOut.addEventListener("mouseup", (e) => this.stopZoom());

        btnZoomIn.addEventListener("touchstart", (e) => {
            e.preventDefault();
            this.zoomIn();
        });
        btnZoomIn.addEventListener("touchend", (e) => {
            e.preventDefault();
            this.stopZoom();
        });
        btnZoomIn.addEventListener("touchcancel", (e) => {
            e.preventDefault();
            this.stopZoom();
        });

        btnZoomOut.addEventListener("touchstart", (e) => {
            e.preventDefault();
            this.zoomOut();
        });
        btnZoomOut.addEventListener("touchend", (e) => {
            e.preventDefault();
            this.stopZoom();
        });
        btnZoomOut.addEventListener("touchcancel", (e) => {
            e.preventDefault();
            this.stopZoom();
        });

        this.renderer.events.on("draw", this._draw, this);
    }

    /**
     * Planet zoom in.
     * @public
     */
    zoomIn() {
        if (this.stepIndex) {
            return;
        }

        this.planet.stopFlying();

        this.stopRotation();

        this._deactivate = true;

        this.planet.layerLock.lock(this._keyLock);
        this.planet.terrainLock.lock(this._keyLock);
        this.planet._normalMapCreator.lock(this._keyLock);

        this.stepsForward = MouseNavigation.getMovePointsFromPixelTerrain(
            this.renderer.activeCamera,
            this.planet,
            this.stepsCount,
            this.distDiff,
            this.renderer.getCenter(),
            true,
           null
        );
        if (this.stepsForward) {
            this.stepIndex = this.stepsCount;
        }
    }

    /**
     * Planet zoom out.
     * @public
     */
    zoomOut() {
        if (this.stepIndex) {
            return;
        }

        this.planet.stopFlying();

        this.stopRotation();

        this._deactivate = true;

        this.planet.layerLock.lock(this._keyLock);
        this.planet.terrainLock.lock(this._keyLock);
        this.planet._normalMapCreator.lock(this._keyLock);
        
        this.stepsForward = MouseNavigation.getMovePointsFromPixelTerrain(
            this.renderer.activeCamera,
            this.planet,
            this.stepsCount,
            this.distDiff,
            this.renderer.getCenter(),
            false,
           null
        );
        if (this.stepsForward) {
            this.stepIndex = this.stepsCount;
        }
    }

    stopRotation() {
        this.qRot.clear();
        this.planet.layerLock.free(this._keyLock);
        this.planet.terrainLock.free(this._keyLock);
        this.planet._normalMapCreator.free(this._keyLock);
    }

    stopZoom() {
        this._move = 0;

        this.planet.layerLock.free(this._keyLock);
        this.planet.terrainLock.free(this._keyLock);
        this.planet._normalMapCreator.free(this._keyLock);
    }

    _draw(e) {
        if (this._active) {
            var r = this.renderer;
            var cam = r.activeCamera;
            var prevEye = cam.eye.clone();

            if (this.stepIndex) {
                r.controlsBag.scaleRot = 1.0;
                var sf = this.stepsForward[this.stepsCount - this.stepIndex--];

                let maxAlt = cam.maxAltitude + this.planet.ellipsoid._a;
                let minAlt = cam.minAltitude + this.planet.ellipsoid._a;
                const camAlt = sf.eye.length();
                if (camAlt > maxAlt || camAlt < minAlt) {
                    return;
                }

                cam.eye = sf.eye;
                cam._u = sf.v;
                cam._r = sf.u;
                cam._b = sf.n;

                cam.checkTerrainCollision();

                cam.update();
            } else {
                if (this._deactivate) {
                    this._deactivate = false;

                    this.planet.layerLock.free(this._keyLock);
                    this.planet.terrainLock.free(this._keyLock);
                    this.planet._normalMapCreator.free(this._keyLock);
                }
            }

            if (r.events.mouseState.leftButtonDown || !this.scaleRot) {
                return;
            }

            this.scaleRot -= this.inertia;
            if (this.scaleRot <= 0.0) {
                this.scaleRot = 0.0;
            } else {
                r.controlsBag.scaleRot = this.scaleRot;
                var rot = this.qRot
                    .slerp(Quat.IDENTITY, 1.0 - this.scaleRot * this.scaleRot * this.scaleRot)
                    .normalize();
                if (!(rot.x || rot.y || rot.z)) {
                    this.scaleRot = 0.0;
                }
                cam.eye = rot.mulVec3(cam.eye);
                cam._u = rot.mulVec3(cam._u);
                cam._r = rot.mulVec3(cam._r);
                cam._b = rot.mulVec3(cam._b);

                cam.checkTerrainCollision();

                cam.update();
            }

            if (cam.eye.distance(prevEye) / cam._terrainAltitude > 0.01) {
                this.planet.layerLock.lock(this._keyLock);
                this.planet.terrainLock.lock(this._keyLock);
                this.planet._normalMapCreator.lock(this._keyLock);
            } else {
                this.planet.layerLock.free(this._keyLock);
                this.planet.terrainLock.free(this._keyLock);
                this.planet._normalMapCreator.free(this._keyLock);
            }
        }
    }
}

export function mouseWheelZoomControl(options) {
    return new MouseWheelZoomControl(options);
}

export { MouseWheelZoomControl };