Source: og/control/ScaleControl.js

/**
 * @module og/control/ZoomControl
 */

"use strict";

import { Control } from "./Control.js";
import { RADIANS } from "../math.js";
import { binarySearch, parseHTML } from "../utils/shared.js";

const scale = [
    1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1e3, 2e3, 3e3, 5e3, 10e3, 20e3, 30e3, 50e3,
    100e3, 200e3, 300e3, 500e3, 1000e3, 2000e3, 3000e3, 5000e3, 10000e3
];

const TEMPLATE = `<div class="og-scale-container">
      <div class="og-scale-label"></div>
      <div class="og-scale-ruler"></div>
    </div>`;

/**
 * Planet zoom buttons control.
 * @class
 * @extends {Control}
 * @params {Object} [options] - Control options.
 */
class ScaleControl extends Control {
    constructor(options = {}) {
        if (!options.name || options.name === "") {
            options.name = "scaleControl";
        }
        super(options);
        options = options || {};

        this._template = TEMPLATE;

        this.planet = null;

        this._minWidth = 100;
        this._maxWidth = 150;
    }

    _renderTemplate() {
        return parseHTML(this._template)[0];
    }

    oninit() {
        this.el = this._renderTemplate();

        this._scaleLabelEl = this.el.querySelector(".og-scale-label");

        this.renderer.div.appendChild(this.el);

        this.renderer.events.on("draw", (e) => {
            if (e.events.mouseState.anyEvent()) {
                this._draw();
            }
        });

        this.renderer.activeCamera.events.on("moveend", (e) => {
            this._draw(e);
        });
    }

    _draw(e) {
        let cam = this.renderer.activeCamera;
        let s0 = this.planet.renderer.handler.getCenter();
        let dist = this.planet.getDistanceFromPixel(s0);
        let p0 = cam.getForward().scaleTo(dist).addA(cam.eye);
        let tempSize = dist * Math.tan(cam._viewAngle * RADIANS);
        let p1 = p0.add(cam.getRight().scaleTo(tempSize));
        let s1 = cam.project(p1);
        this._mPx = tempSize / s1.distance(s0);

        let metersInMinSize = this._mPx * this._minWidth;

        let index = binarySearch(scale, metersInMinSize, (a, b) => a - b);
        if (index < 0) {
            index = ~index;
        }
        let minMeters = scale[index],
            maxMeters = scale[index + 1];

        let t = (minMeters - metersInMinSize) / (maxMeters - minMeters);
        this.currWidth = this._minWidth + t * (this._maxWidth - this._minWidth);

        if (minMeters > 1000) {
            this._scaleLabelEl.innerText = `${minMeters / 1000} km`;
        } else {
            this._scaleLabelEl.innerText = `${minMeters} m`;
        }

        this._metersInMinSize = metersInMinSize;

        this.el.style.width = this.currWidth + "px";
    }
}

export function scaleControl(options) {
    return new ScaleControl(options);
}

export { ScaleControl };