PMA.UI Documentation by Pathomation

view/measure.js

import { ol } from "./definitionsOl";
import Overlay from "ol/Overlay";
import { addEvent } from "./viewportHelpers";
import * as olEventsCondition from 'ol/events/condition';
import { unByKey } from 'ol/Observable';

export function createMeasureTooltip() {
    var el = document.createElement('div');
    el.className = 'pma-ui-viewport-tooltip pma-ui-viewport-tooltip-measure';

    var measureTooltip = new Overlay({
        element: el,
        offset: [0, -15],
        positioning: 'bottom-center',
        stopEvent: false,
        insertFirst: false,
    });

    this.map.addOverlay(measureTooltip);
    measureTooltip.element = el;

    el.parentElement.style.display = 'block';
    let self = this;
    addEvent(el, 'click', function () {
        self.map.removeOverlay(measureTooltip);
        self.measureLayer.getSource().removeFeature(measureTooltip.sketch);
        
        if (el.parentNode) {
            el.parentNode.removeChild(el);
        }
        el = null;
    });

    return measureTooltip;
}

export function startMeasuring(type /* string (area, line) */) {
    if (this.measureDraw) {
        // prevent beginning measurement more than once
        return;
    }

    type = (type === 'area' ? 'Polygon' : 'LineString');

    this.measureDraw = new ol.interaction.Draw({
        source: this.measureLayer.getSource(),
        type: type,
        geometryFunction: null,
        style: new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 0.2)'
            }),
            stroke: new ol.style.Stroke({
                color: 'rgba(0, 0, 0, 0.5)',
                lineDash: [10, 10],
                width: 2
            }),
            image: new ol.style.Circle({
                radius: 5,
                stroke: new ol.style.Stroke({
                    color: 'rgba(0, 0, 0, 0.7)'
                }),
                fill: new ol.style.Fill({
                    color: 'rgba(255, 255, 255, 0.2)'
                })
            })
        }),
        condition: olEventsCondition.noModifierKeys,
        freehandCondition: olEventsCondition.never
    });

    this.map.addInteraction(this.measureDraw);

    let self = this;
    let tooltip = createMeasureTooltip.call(this);
    this.measureTooltips.push(tooltip);

    let listener, sketch;

    this.measureDraw.on('drawstart',
        function (evt) {
            // set sketch
            sketch = evt.feature;
            tooltip.sketch = sketch;

            /** @type {ol.Coordinate|undefined} */
            let tooltipCoord = evt.coordinate;

            listener = sketch.getGeometry().on('change', function (evt) {
                const geom = evt.target;
                let output;
                if (geom instanceof ol.geom.Polygon) {
                    output = formatArea.call(self, geom);
                    tooltipCoord = geom.getInteriorPoint().getCoordinates();
                }
                else if (geom instanceof ol.geom.LineString) {
                    output = formatLength.call(self, geom);
                    tooltipCoord = geom.getLastCoordinate();
                }

                tooltip.element.innerHTML = output;
                tooltip.setPosition(tooltipCoord);
            });
        }, this);

    this.measureDraw.on('drawend', function () {
        tooltip.element.className = 'pma-ui-viewport-tooltip pma-ui-viewport-tooltip-static';
        tooltip.setOffset([0, -7]);
        // unset sketch
        tooltip.sketch = sketch;
        sketch = null;
        // unset tooltip so that a new one can be created
        unByKey(listener);

        // remove the interaction with a delay, otherwise the last double click
        // will result in a zoom in
        setTimeout(function () {
            stopMeasuring.call(self);
        }, 100);
    }, this);
};

export function stopMeasuring(clear) {
    if (this.measureDraw) {
        this.map.removeInteraction(this.measureDraw);
        // this.measureTooltips = [];
        this.measureDraw = null;
    }

    if (clear == true) {
        while (this.measureTooltips.length > 0) {
            let mt = this.measureTooltips.pop();
            this.map.removeOverlay(mt);
            this.measureLayer.getSource().removeFeature(mt.sketch);
            if (mt.element.parentNode) {
                mt.element.parentNode.removeChild(mt.element);
            }
        }
    }
};

/**
 * Format length output.
 * @param {LineString} line The line.
 * @return {string} The formatted length.
 */
function formatLength(line) {
    if (this.imageInfo.MicrometresPerPixelX === 0) {
        return line.getLength() + ' px';
    }

    var length = line.getLength() * this.imageInfo.MicrometresPerPixelX;

    var output;
    if (length >= 1000) {
        output = Math.round(length * 10 / 1000) / 10 + ' mm';
    }
    else {
        output = Math.round(length * 10) / 10 + ' μm';
    }

    return output;
}

/**
 * Format area output.
 * @param {Polygon} polygon The polygon.
 * @return {string} Formatted area.
 */
function formatArea(polygon) {
    if (this.imageInfo.MicrometresPerPixelX === 0) {
        return polygon.getArea() + ' px<sup>2</sup>';
    }

    var area = polygon.getArea() * this.imageInfo.MicrometresPerPixelX * this.imageInfo.MicrometresPerPixelX;

    var output;
    if (area > 10000) {
        output = Math.round(area * 10 / 1000000) / 10 + ' mm<sup>2</sup>';
    }
    else {
        output = Math.round(area * 10) / 10 + ' μm<sup>2</sup>';
    }

    return output;
}