/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { h, Host, } from "@stencil/core";
import { Line3, Point, Vector3 } from "@vertexvis/geometry";
import { MEASUREMENT_LINE_CAP_LENGTH, MEASUREMENT_SNAP_DISTANCE, } from "../../lib/constants";
import { measurementCursor } from "../../lib/cursors";
import { getMouseClientPosition } from "../../lib/dom";
import { makeMinimumDistanceResult, MeasurementModel, MeasurementOverlayManager, } from "../../lib/measurement";
import { DistanceUnits, Viewport, } from "../../lib/types";
import { getMeasurementBoundingClientRect } from "./dom";
import { PointToPointHitTester } from "./hitTest";
import { PointToPointInteractionController, PointToPointInteractionModel, } from "./interactions";
import { getViewingElementPositions, } from "./utils";
import { DistanceMeasurementRenderer } from "./viewer-measurement-distance-components";
const INTERACTION_THRESHOLD = 3;
/**
 * @slot start-anchor - An HTML element for the starting point anchor.
 *
 * @slot start-label - An HTML or text element that displays next to the start
 * anchor.
 *
 * @slot end-anchor - An HTML element for the ending point anchor.
 *
 * @slot end-label - An HTML or text element that displays next to the end
 * anchor.
 *
 * @slot indicator - An HTML element for the measurement indicator. The
 * indicator represents the position where a measurement will be placed while
 * editing.
 */
export class ViewerMeasurementDistance {
    constructor() {
        /**
         * Enables the display of axis reference lines between the start and end
         * point.
         */
        this.showAxisReferenceLines = false;
        /**
         * The distance, in pixels, between the mouse and nearest snappable edge. A
         * value of 0 disables snapping.
         */
        this.snapDistance = MEASUREMENT_SNAP_DISTANCE;
        /**
         * The unit of measurement.
         */
        this.units = 'millimeters';
        /**
         * The number of fraction digits to display.
         */
        this.fractionalDigits = 2;
        /**
         * The distance from an anchor to its label.
         */
        this.anchorLabelOffset = 20;
        /**
         * The length of the caps at each end of the distance measurement.
         */
        this.lineCapLength = MEASUREMENT_LINE_CAP_LENGTH;
        /**
         * A mode that specifies how the measurement component should behave.
         *
         * When unset, the component will not respond to interactions with the
         * handles.
         *
         * When `edit`, the measurement anchors are interactive and the user is able
         * to reposition them.
         *
         * When `replace`, anytime the user clicks on the canvas, a new measurement
         * will be created and replace any existing measurement. After a measurement
         * is created, the measurement will be editable.
         */
        this.mode = '';
        /**
         * A property that reflects which anchor is currently being interacted with.
         */
        this.interactingAnchor = 'none';
        /**
         * Indicates if the measurement is invalid. A measurement is invalid if either
         * the start or end position are not on the surface of the model.
         */
        this.invalid = false;
        /**
         * The measurement model that will be updated when this measurement changes.
         * You can pass this to a <vertex-viewer-measurement-details> component to
         * display measurement outcomes.
         */
        this.measurementModel = new MeasurementModel();
        this.viewport = new Viewport(0, 0);
        this.interactionCount = 0;
        this.invalidateStateCounter = 0;
        this.stateMap = {};
        this.measurementUnits = new DistanceUnits(this.units);
        this.model = PointToPointInteractionModel.empty();
        this.controller = new PointToPointInteractionController(this.model);
        this.overlays = new MeasurementOverlayManager();
        this.isUserInteractingWithModel = false;
        this.handleFrameDrawn = () => {
            this.invalidateState();
        };
        this.clearIndicator = () => {
            this.controller.clearIndicator();
        };
        this.updateStartAnchor = async (event) => {
            await this.getStencilBuffer();
            if (this.interactionCount === 0) {
                const pt = getMouseClientPosition(event, this.elementBounds);
                const snapPt = this.snapPoint(pt, event);
                await this.updateIndicator(snapPt);
            }
        };
        this.newMeasurement = (event) => {
            if (this.interactionCount === 0 && event.button === 0) {
                // Function that registers event listeners to perform a new measurement.
                const startMeasurement = (start) => {
                    const dispose = () => {
                        window.removeEventListener('pointerup', pointerUp);
                        window.removeEventListener('pointermove', pointerMove);
                    };
                    const pointerUp = async () => {
                        dispose();
                        start();
                    };
                    const pointerMove = (event) => {
                        if (event.buttons > 0) {
                            dispose();
                        }
                    };
                    window.addEventListener('pointermove', pointerMove);
                    window.addEventListener('pointerup', pointerUp);
                };
                // Function that registers event listeners to detect if a user is
                // interacting with the model. If so, we temporarily disable measurement
                // updates until the user finishes.
                const pointerDownAndMove = (callback) => {
                    let downPt = Point.create(0, 0);
                    const pointerMove = (event) => {
                        const dist = Point.distance(downPt, getMouseClientPosition(event, this.elementBounds));
                        if (dist >= INTERACTION_THRESHOLD) {
                            callback();
                        }
                    };
                    const dispose = () => {
                        window.removeEventListener('pointermove', pointerMove);
                        window.removeEventListener('pointerup', pointerUp);
                    };
                    const pointerUp = () => dispose();
                    const pointerDown = (event) => {
                        downPt = getMouseClientPosition(event, this.elementBounds);
                        window.addEventListener('pointermove', pointerMove);
                        window.addEventListener('pointerup', pointerUp);
                    };
                    window.addEventListener('pointerdown', pointerDown);
                    return {
                        dispose: () => window.removeEventListener('pointerdown', pointerDown),
                    };
                };
                // Function that registers event listeners to finish a measurement.
                const measureInteraction = () => {
                    const handleDownAndMove = pointerDownAndMove(() => {
                        var _a;
                        this.isUserInteractingWithModel = true;
                        (_a = this.stateMap.hoverCursor) === null || _a === void 0 ? void 0 : _a.dispose();
                    });
                    const dispose = () => {
                        window.removeEventListener('pointermove', pointerMove);
                        window.removeEventListener('pointerup', pointerUp);
                        handleDownAndMove.dispose();
                    };
                    const pointerMove = this.createInteractionMoveHandler();
                    const pointerUp = async (event) => {
                        var _a;
                        if (event.button === 0) {
                            if (this.isUserInteractingWithModel) {
                                this.isUserInteractingWithModel = false;
                            }
                            else {
                                const hits = this.getHitProvider();
                                if (hits != null) {
                                    const pt = getMouseClientPosition(event, this.elementBounds);
                                    const snapPt = this.snapPoint(pt, event);
                                    await ((_a = this.interaction) === null || _a === void 0 ? void 0 : _a.finish(snapPt, hits));
                                    dispose();
                                    this.updateMeasurementPropsFromModel();
                                    this.endEditing();
                                }
                            }
                        }
                    };
                    this.beginEditing('replace', 'end');
                    this.newInteractionHandler = { dispose };
                    window.addEventListener('pointermove', pointerMove);
                    window.addEventListener('pointerup', pointerUp);
                };
                const hits = this.getHitProvider();
                if (hits != null) {
                    const pt = getMouseClientPosition(event, this.elementBounds);
                    const snapPt = this.snapPoint(pt, event);
                    this.interaction = this.controller.newMeasurement(snapPt, hits);
                    if (this.interaction != null) {
                        startMeasurement(measureInteraction);
                    }
                }
            }
        };
    }
    /**
     * Computes the bounding boxes of the anchors and label. **Note:** invoking
     * this function uses `getBoundingClientRect` internally and will cause a
     * relayout of the DOM.
     */
    async computeElementMetrics() {
        var _a, _b, _c;
        const startAnchorEl = (_a = this.hostEl.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('start-anchor');
        const endAnchorEl = (_b = this.hostEl.shadowRoot) === null || _b === void 0 ? void 0 : _b.getElementById('end-anchor');
        const labelEl = (_c = this.hostEl.shadowRoot) === null || _c === void 0 ? void 0 : _c.getElementById('label');
        if (startAnchorEl != null && endAnchorEl != null && labelEl != null) {
            return {
                startAnchor: startAnchorEl.getBoundingClientRect(),
                endAnchor: endAnchorEl.getBoundingClientRect(),
                label: labelEl.getBoundingClientRect(),
            };
        }
        else {
            return undefined;
        }
    }
    /**
     * @ignore
     */
    connectedCallback() {
        this.setDepthBuffers();
    }
    /**
     * @ignore
     */
    disconnectedCallback() {
        var _a, _b;
        (_a = this.stateMap.hoverCursor) === null || _a === void 0 ? void 0 : _a.dispose();
        (_b = this.newInteractionHandler) === null || _b === void 0 ? void 0 : _b.dispose();
        this.resetDepthBuffers();
    }
    /**
     * @ignore
     */
    async componentWillLoad() {
        this.updatePropsFromJson();
        this.model.setMeasurementFromValues(this.start, this.end, !this.invalid);
        await this.getStencilBuffer();
        this.updateViewport();
        this.setDepthBuffers();
        await this.handleViewerChanged(this.viewer);
        await this.handleModeChanged();
        await this.computePropsAndState();
        this.model.onIndicatorChanged((pt) => {
            this.indicatorPt = pt;
        });
    }
    /**
     * @ignore
     */
    componentDidLoad() {
        const resize = new ResizeObserver(() => this.updateViewport());
        resize.observe(this.hostEl);
    }
    /**
     * @ignore
     */
    async componentWillUpdate() {
        await this.computePropsAndState();
    }
    /**
     * @ignore
     */
    render() {
        return (h(Host, { key: '58113224139c37a54bf9329ed27e6a8983d5cccd' }, this.showAxisReferenceLines && (h("vertex-viewer-measurement-overlays", { key: 'd2166c4a965761f472f5b3323844d82980baa29f', measurementOverlays: this.overlays, viewer: this.viewer })), this.renderMeasurement()));
    }
    renderMeasurement() {
        const positions = this.computeElementPositions();
        const { startPt, endPt, labelPt, indicatorPt, hideStart, hideEnd } = positions;
        const distance = this.formatDistance(this.distance);
        if (this.mode === 'edit' || this.mode === 'replace') {
            return (h(DistanceMeasurementRenderer, { startPt: startPt, endPt: endPt, centerPt: labelPt, indicatorPt: indicatorPt, distance: distance, anchorLabelOffset: this.anchorLabelOffset, lineCapLength: this.lineCapLength, hideStartAnchor: hideStart, hideEndAnchor: hideEnd, onStartAnchorPointerDown: this.handleEditAnchor('start'), onEndAnchorPointerDown: this.handleEditAnchor('end') }));
        }
        else {
            return (h(DistanceMeasurementRenderer, { startPt: startPt, endPt: endPt, centerPt: labelPt, indicatorPt: this.indicatorPt, distance: distance, hideStartAnchor: hideStart, hideEndAnchor: hideEnd, anchorLabelOffset: this.anchorLabelOffset, lineCapLength: this.lineCapLength, linePointerEvents: "painted" }));
        }
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer, oldViewer) {
        if (oldViewer != null) {
            oldViewer.removeEventListener('frameDrawn', this.handleFrameDrawn);
            await this.removeInteractionListeners(oldViewer);
        }
        if (newViewer != null) {
            newViewer.addEventListener('frameDrawn', this.handleFrameDrawn);
            await this.addInteractionListeners(newViewer);
        }
    }
    /**
     * @ignore
     */
    handleUnitsChanged() {
        this.measurementUnits = new DistanceUnits(this.units);
    }
    /**
     * @ignore
     */
    handleCameraChanged() {
        this.updateCamera();
    }
    /**
     * @ignore
     */
    async handleModeChanged() {
        var _a;
        // If we're not in edit or replace mode, ensure that the measurement
        // cursor is removed.
        if (this.mode === '') {
            (_a = this.stateMap.hoverCursor) === null || _a === void 0 ? void 0 : _a.dispose();
        }
        if (this.viewer != null) {
            await this.removeInteractionListeners(this.viewer);
            await this.addInteractionListeners(this.viewer);
        }
    }
    /**
     * @ignore
     */
    handleStartChanged() {
        this.updateInteractionModel();
    }
    /**
     * @ignore
     */
    handleEndChanged() {
        this.updateInteractionModel();
    }
    /**
     * @ignore
     */
    handleInvalidChanged() {
        this.updateInteractionModel();
    }
    async computePropsAndState() {
        this.updateCamera();
        await this.updateDepthBuffer();
        this.updateMeasurementPropsFromModel();
        this.updateOverlays();
    }
    updateOverlays() {
        var _a;
        (_a = this.overlay) === null || _a === void 0 ? void 0 : _a.dispose();
        if (this.showAxisReferenceLines &&
            this.interactionCount === 0 &&
            !this.invalid &&
            this.start != null &&
            this.end != null) {
            this.overlay = this.overlays.addDistanceVector(this.start, this.end);
        }
    }
    async setCursor(cursor) {
        var _a, _b;
        (_a = this.stateMap.hoverCursor) === null || _a === void 0 ? void 0 : _a.dispose();
        if (!this.isUserInteractingWithModel) {
            this.stateMap.hoverCursor = await ((_b = this.viewer) === null || _b === void 0 ? void 0 : _b.addCursor(cursor));
        }
    }
    computeElementPositions() {
        if (this.mode === 'replace') {
            return this.computeReplaceElementPositions();
        }
        else {
            return this.computeEditOrViewElementPositions();
        }
    }
    computeEditOrViewElementPositions() {
        const measurement = this.model.getMeasurement();
        if (this.internalCamera != null && measurement != null) {
            return this.computeLineElementPositions(Line3.create(measurement));
        }
        else {
            return {};
        }
    }
    computeReplaceElementPositions() {
        if (this.internalCamera != null) {
            const measurement = this.model.getMeasurement();
            const line = measurement != null
                ? this.computeLineElementPositions(Line3.create(measurement))
                : {};
            const indicator = this.indicatorPt != null
                ? {
                    indicatorPt: this.viewport.transformWorldToViewport(this.indicatorPt, this.internalCamera.projectionViewMatrix),
                }
                : {};
            return { ...line, ...indicator };
        }
        else {
            return {};
        }
    }
    computeLineElementPositions(line) {
        if (this.internalCamera != null) {
            return getViewingElementPositions(line, this.interactingAnchor, {
                viewport: this.viewport,
                camera: this.internalCamera,
            });
        }
        else {
            return {};
        }
    }
    updateCamera() {
        var _a, _b;
        this.internalCamera = this.camera || ((_b = (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.frame) === null || _b === void 0 ? void 0 : _b.scene.camera);
    }
    async updateDepthBuffer() {
        var _a, _b;
        this.stateMap.depthBuffer = await ((_b = (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.frame) === null || _b === void 0 ? void 0 : _b.depthBuffer());
    }
    updateViewport() {
        const rect = getMeasurementBoundingClientRect(this.hostEl);
        this.viewport = new Viewport(rect.width, rect.height);
        this.elementBounds = rect;
    }
    updatePropsFromJson() {
        var _a, _b;
        this.start = parseVector3((_a = this.startJson) !== null && _a !== void 0 ? _a : this.start);
        this.end = parseVector3((_b = this.endJson) !== null && _b !== void 0 ? _b : this.end);
    }
    updateInteractionModel() {
        this.model.setMeasurementFromValues(this.start, this.end, !this.invalid);
    }
    invalidateState() {
        this.invalidateStateCounter = this.invalidateStateCounter + 1;
    }
    async addInteractionListeners(viewer) {
        const interactionTarget = await viewer.getInteractionTarget_DEPRECATED();
        if (this.mode === 'replace') {
            interactionTarget.addEventListener('pointermove', this.updateStartAnchor);
            interactionTarget.addEventListener('pointerdown', this.newMeasurement);
            interactionTarget.addEventListener('pointerleave', this.clearIndicator);
        }
    }
    async removeInteractionListeners(viewer) {
        const interactionTarget = await viewer.getInteractionTarget_DEPRECATED();
        interactionTarget.removeEventListener('pointermove', this.updateStartAnchor);
        interactionTarget.removeEventListener('pointerdown', this.newMeasurement);
        interactionTarget.removeEventListener('pointerleave', this.clearIndicator);
    }
    handleEditAnchor(anchor) {
        if (this.mode === 'edit' || this.mode === 'replace') {
            const handlePointerMove = this.createInteractionMoveHandler();
            const handlePointerUp = async (event) => {
                var _a;
                const hits = this.getHitProvider();
                if (hits != null) {
                    window.removeEventListener('pointermove', handlePointerMove);
                    window.removeEventListener('pointerup', handlePointerUp);
                    const pt = getMouseClientPosition(event, this.elementBounds);
                    const snapPt = this.snapPoint(pt, event);
                    await ((_a = this.interaction) === null || _a === void 0 ? void 0 : _a.finish(snapPt, hits));
                    this.updateMeasurementPropsFromModel();
                    this.endEditing();
                }
            };
            return async (event) => {
                await this.getStencilBuffer();
                if (event.button === 0) {
                    this.beginEditing('edit', anchor);
                    this.interaction = this.controller.editMeasurement(anchor);
                    window.addEventListener('pointermove', handlePointerMove);
                    window.addEventListener('pointerup', handlePointerUp);
                }
            };
        }
    }
    createInteractionMoveHandler() {
        return async (event) => {
            var _a;
            const hits = this.getHitProvider();
            if (this.elementBounds != null && hits != null) {
                event.preventDefault();
                await this.getStencilBuffer();
                const pt = getMouseClientPosition(event, this.elementBounds);
                const snapPt = this.snapPoint(pt, event);
                (_a = this.interaction) === null || _a === void 0 ? void 0 : _a.update(snapPt, hits);
                this.updateMeasurementPropsFromModel();
            }
        };
    }
    async getStencilBuffer() {
        var _a;
        const stencil = await ((_a = this.viewer) === null || _a === void 0 ? void 0 : _a.stencilBuffer.latestAfterInteraction());
        this.stateMap.stencil = stencil;
    }
    snapPoint(pt, event) {
        const hits = this.getHitProvider();
        if (hits != null && !event.shiftKey) {
            const snapDistance = Math.max(0, this.snapDistance);
            return hits.hitTester().snapToNearestPixel(pt, snapDistance);
        }
        return pt;
    }
    formatDistance(distance) {
        const dist = distance != null
            ? this.measurementUnits.convertWorldValueToReal(distance)
            : undefined;
        if (this.labelFormatter != null) {
            return this.labelFormatter(dist);
        }
        else {
            const abbreviated = this.measurementUnits.unit.abbreviatedName;
            return dist == null
                ? '---'
                : `~${dist.toFixed(this.fractionalDigits)} ${abbreviated}`;
        }
    }
    beginEditing(type, anchor) {
        if (this.interactionCount === 0) {
            this.interactingAnchor = anchor;
            this.editBegin.emit({ type, anchor });
        }
        this.interactionCount = this.interactionCount + 1;
    }
    endEditing() {
        if (this.interactionCount === 1) {
            const measurement = this.model.getMeasurement();
            this.interactingAnchor = 'none';
            this.updateMeasurementModel();
            if (measurement != null) {
                this.editEnd.emit(measurement);
            }
        }
        this.interactionCount = this.interactionCount - 1;
    }
    updateMeasurementModel() {
        this.measurementModel.clearOutcome();
        if (!this.invalid && this.start != null && this.end != null) {
            this.measurementModel.setOutcome({
                isApproximate: true,
                results: [makeMinimumDistanceResult(this.start, this.end)],
            });
        }
    }
    getHitProvider() {
        if (this.hitProvider == null) {
            const hitTester = this.getHitTester();
            const viewer = this.viewer;
            if (viewer != null && hitTester != null) {
                return {
                    hitTester: () => hitTester,
                    raycaster: async () => (await viewer.scene()).raycaster(),
                };
            }
        }
        else
            return this.hitProvider;
    }
    getHitTester() {
        const { stencil, depthBuffer } = this.stateMap;
        if (depthBuffer != null) {
            return new PointToPointHitTester(stencil, depthBuffer, this.viewport, this.internalCamera);
        }
    }
    updateMeasurementPropsFromModel() {
        const measurement = this.model.getMeasurement();
        this.start = measurement === null || measurement === void 0 ? void 0 : measurement.start;
        this.end = measurement === null || measurement === void 0 ? void 0 : measurement.end;
        this.distance = measurement === null || measurement === void 0 ? void 0 : measurement.distance;
        this.invalid = measurement != null && !measurement.valid;
    }
    async updateIndicator(pt) {
        var _a;
        const hits = this.getHitProvider();
        const clearCursor = hits == null || !this.controller.moveIndicator(pt, hits);
        if (clearCursor) {
            (_a = this.stateMap.hoverCursor) === null || _a === void 0 ? void 0 : _a.dispose();
        }
        else {
            await this.setCursor(measurementCursor);
        }
    }
    setDepthBuffers() {
        if (this.mode != null &&
            this.viewer != null &&
            this.viewer.depthBuffers == null) {
            this.stateMap.shouldClearDepthBuffers = true;
            this.viewer.depthBuffers = 'final';
        }
    }
    resetDepthBuffers() {
        if (this.stateMap.shouldClearDepthBuffers && this.viewer != null) {
            this.viewer.depthBuffers = undefined;
            this.stateMap.shouldClearDepthBuffers = undefined;
        }
    }
    static get is() { return "vertex-viewer-measurement-distance"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["viewer-measurement-distance.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["viewer-measurement-distance.css"]
        };
    }
    static get properties() {
        return {
            "start": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Vector3.Vector3",
                    "resolved": "Vector3 | undefined",
                    "references": {
                        "Vector3": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/vector3\"",
                            "referenceLocation": "Vector3"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The world position of the starting anchor."
                },
                "getter": false,
                "setter": false
            },
            "startJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The world position of the starting anchor, as a JSON string. The JSON\nstring can be an array or object representation in the format of `[x, y,\nz]` or `{\"x\": 0, \"y\": 0, \"z\": 0}`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "start-json"
            },
            "end": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Vector3.Vector3",
                    "resolved": "Vector3 | undefined",
                    "references": {
                        "Vector3": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/vector3\"",
                            "referenceLocation": "Vector3"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The world position of the ending anchor."
                },
                "getter": false,
                "setter": false
            },
            "endJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The world position of the ending anchor, as a JSON string. The JSON string\ncan be an array or object representation in the format of `[x, y, z]` or\n`{\"x\": 0, \"y\": 0, \"z\": 0}`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "end-json"
            },
            "distance": {
                "type": "number",
                "mutable": true,
                "complexType": {
                    "original": "number",
                    "resolved": "number | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The distance between `start` and `end` in real world units. Value will be\nundefined if the start and end positions are undefined, or if the\nmeasurement is invalid."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "distance"
            },
            "showAxisReferenceLines": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Enables the display of axis reference lines between the start and end\npoint."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "show-axis-reference-lines",
                "defaultValue": "false"
            },
            "snapDistance": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The distance, in pixels, between the mouse and nearest snappable edge. A\nvalue of 0 disables snapping."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "snap-distance",
                "defaultValue": "MEASUREMENT_SNAP_DISTANCE"
            },
            "units": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "DistanceUnitType",
                    "resolved": "\"centimeters\" | \"feet\" | \"inches\" | \"meters\" | \"millimeters\" | \"yards\"",
                    "references": {
                        "DistanceUnitType": {
                            "location": "import",
                            "path": "../../lib/types",
                            "id": "src/lib/types/index.ts::DistanceUnitType",
                            "referenceLocation": "DistanceUnitType"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The unit of measurement."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "units",
                "defaultValue": "'millimeters'"
            },
            "fractionalDigits": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The number of fraction digits to display."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "fractional-digits",
                "defaultValue": "2"
            },
            "labelFormatter": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Formatter<number | undefined>",
                    "resolved": "number | undefined",
                    "references": {
                        "Formatter": {
                            "location": "import",
                            "path": "../../lib/formatter",
                            "id": "src/lib/formatter.ts::Formatter",
                            "referenceLocation": "Formatter"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "An optional formatter that can be used to format the display of a distance.\nThe formatting function is passed a calculated real-world distance and is\nexpected to return a string."
                },
                "getter": false,
                "setter": false
            },
            "anchorLabelOffset": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The distance from an anchor to its label."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "anchor-label-offset",
                "defaultValue": "20"
            },
            "lineCapLength": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The length of the caps at each end of the distance measurement."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "line-cap-length",
                "defaultValue": "MEASUREMENT_LINE_CAP_LENGTH"
            },
            "mode": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "ViewerMeasurementDistanceMode",
                    "resolved": "\"\" | \"edit\" | \"replace\"",
                    "references": {
                        "ViewerMeasurementDistanceMode": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-measurement-distance/viewer-measurement-distance.tsx",
                            "id": "src/components/viewer-measurement-distance/viewer-measurement-distance.tsx::ViewerMeasurementDistanceMode"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "A mode that specifies how the measurement component should behave.\n\nWhen unset, the component will not respond to interactions with the\nhandles.\n\nWhen `edit`, the measurement anchors are interactive and the user is able\nto reposition them.\n\nWhen `replace`, anytime the user clicks on the canvas, a new measurement\nwill be created and replace any existing measurement. After a measurement\nis created, the measurement will be editable."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "mode",
                "defaultValue": "''"
            },
            "interactingAnchor": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "Anchor | 'none'",
                    "resolved": "\"end\" | \"none\" | \"start\"",
                    "references": {
                        "Anchor": {
                            "location": "import",
                            "path": "./utils",
                            "id": "src/components/viewer-measurement-distance/utils.ts::Anchor",
                            "referenceLocation": "Anchor"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "A property that reflects which anchor is currently being interacted with."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "interacting-anchor",
                "defaultValue": "'none'"
            },
            "invalid": {
                "type": "boolean",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Indicates if the measurement is invalid. A measurement is invalid if either\nthe start or end position are not on the surface of the model."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "invalid",
                "defaultValue": "false"
            },
            "camera": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "FrameCameraBase",
                    "resolved": "FrameCameraBase | undefined",
                    "references": {
                        "FrameCameraBase": {
                            "location": "import",
                            "path": "../../lib/types",
                            "id": "src/lib/types/index.ts::FrameCameraBase",
                            "referenceLocation": "FrameCameraBase"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The camera used to position the anchors. If `viewer` is defined, then the\nprojection view matrix of the viewer will be used."
                },
                "getter": false,
                "setter": false
            },
            "hitProvider": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "PointToPointHitProvider",
                    "resolved": "PointToPointHitProvider | undefined",
                    "references": {
                        "PointToPointHitProvider": {
                            "location": "import",
                            "path": "./interactions",
                            "id": "src/components/viewer-measurement-distance/interactions.ts::PointToPointHitProvider",
                            "referenceLocation": "PointToPointHitProvider"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false
            },
            "indicatorPt": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Vector3.Vector3",
                    "resolved": "Vector3 | undefined",
                    "references": {
                        "Vector3": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/vector3\"",
                            "referenceLocation": "Vector3"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false
            },
            "viewer": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "HTMLVertexViewerElement",
                    "resolved": "HTMLVertexViewerElement | undefined",
                    "references": {
                        "HTMLVertexViewerElement": {
                            "location": "global",
                            "id": "global::HTMLVertexViewerElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The viewer to connect to this measurement. The measurement will redraw any\ntime the viewer redraws the scene."
                },
                "getter": false,
                "setter": false
            },
            "measurementModel": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "MeasurementModel",
                    "resolved": "MeasurementModel",
                    "references": {
                        "MeasurementModel": {
                            "location": "import",
                            "path": "../../lib/measurement",
                            "id": "src/lib/measurement/index.ts::MeasurementModel",
                            "referenceLocation": "MeasurementModel"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The measurement model that will be updated when this measurement changes.\nYou can pass this to a <vertex-viewer-measurement-details> component to\ndisplay measurement outcomes."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "new MeasurementModel()"
            }
        };
    }
    static get states() {
        return {
            "viewport": {},
            "elementBounds": {},
            "interactionCount": {},
            "internalCamera": {},
            "invalidateStateCounter": {},
            "stateMap": {},
            "measurementUnits": {}
        };
    }
    static get events() {
        return [{
                "method": "editBegin",
                "name": "editBegin",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "An event that is dispatched anytime the user begins editing the\nmeasurement."
                },
                "complexType": {
                    "original": "EditBeginEventDetails",
                    "resolved": "EditBeginEventDetails",
                    "references": {
                        "EditBeginEventDetails": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-measurement-distance/viewer-measurement-distance.tsx",
                            "id": "src/components/viewer-measurement-distance/viewer-measurement-distance.tsx::EditBeginEventDetails"
                        }
                    }
                }
            }, {
                "method": "editEnd",
                "name": "editEnd",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "An event that is dispatched when the user has finished editing the\nmeasurement."
                },
                "complexType": {
                    "original": "EditEndEventDetails",
                    "resolved": "EditEndEventDetails",
                    "references": {
                        "EditEndEventDetails": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-measurement-distance/viewer-measurement-distance.tsx",
                            "id": "src/components/viewer-measurement-distance/viewer-measurement-distance.tsx::EditEndEventDetails"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "computeElementMetrics": {
                "complexType": {
                    "signature": "() => Promise<ViewerMeasurementDistanceElementMetrics | undefined>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "ViewerMeasurementDistanceElementMetrics": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-measurement-distance/viewer-measurement-distance.tsx",
                            "id": "src/components/viewer-measurement-distance/viewer-measurement-distance.tsx::ViewerMeasurementDistanceElementMetrics"
                        }
                    },
                    "return": "Promise<ViewerMeasurementDistanceElementMetrics | undefined>"
                },
                "docs": {
                    "text": "Computes the bounding boxes of the anchors and label. **Note:** invoking\nthis function uses `getBoundingClientRect` internally and will cause a\nrelayout of the DOM.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "hostEl"; }
    static get watchers() {
        return [{
                "propName": "viewer",
                "methodName": "handleViewerChanged"
            }, {
                "propName": "units",
                "methodName": "handleUnitsChanged"
            }, {
                "propName": "camera",
                "methodName": "handleCameraChanged"
            }, {
                "propName": "mode",
                "methodName": "handleModeChanged"
            }, {
                "propName": "start",
                "methodName": "handleStartChanged"
            }, {
                "propName": "end",
                "methodName": "handleEndChanged"
            }, {
                "propName": "invalid",
                "methodName": "handleInvalidChanged"
            }];
    }
}
function parseVector3(value) {
    return typeof value === 'string' ? Vector3.fromJson(value) : value;
}
//# sourceMappingURL=viewer-measurement-distance.js.map
