/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
'use strict';

var index = require('./index-C_J7n4Dv.js');
var bundle = require('./bundle-BhTmftd-.js');
var templates = require('./templates-DvjgjnlO.js');
var markup = require('./markup-BqWReWlC.js');
var utils = require('./utils-m4ihMvcS.js');
require('./bundle-96sYCpzz.js');
require('./_commonjsHelpers-CBbBosIU.js');

const viewerMarkupCss = () => `:host{display:block;position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:none}`;

const ViewerMarkup = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.markupAdded = index.createEvent(this, "markupAdded");
        this.markupChanged = index.createEvent(this, "markupChanged");
        this.markupRemoved = index.createEvent(this, "markupRemoved");
        this.markupSelectionChanged = index.createEvent(this, "markupSelectionChanged");
        /**
         * The type of markup to perform.
         */
        this.tool = 'arrow';
        /**
         * If `true`, disables adding or editing of markup through user
         * interaction.
         */
        this.disabled = false;
        /**
         * Indicates if new markup should be automatically selected.
         */
        this.selectNew = false;
        /**
         * The style of the starting anchor. This defaults to none.
         */
        this.startLineAnchorStyle = 'none';
        /**
         * The style of the ending anchor. This defaults to 'arrow-triangle.'
         */
        this.endLineAnchorStyle = 'arrow-triangle';
        /**
         * Defines the behavior of the provided markup when the originating viewport is smaller
         * than the current viewport, or is scaled to a size smaller than the current viewport
         * using the `scale` property.
         *
         * Options:
         * - `x-only`: Markup will be centered horizontally, but not vertically.
         * - `y-only`: Markup will be centered vertically, but not horizontally.
         * - `both`: Markup will be centered both horizontally and vertically.
         * - `none`: Markup will not be centered (default).
         */
        this.centeringBehavior = 'none';
        /**
         * The scale to render this markup at. This value is used to scale the element's bounds
         * along with any `offset` to determine the final computed coordinates.
         *
         * When provided, all computed coordinates will be scaled by this amount.
         */
        this.scale = 1;
        this.handleSlotChange = () => {
            this.updatePropsOnMarkupTool();
            this.updatePropsOnMarkups();
        };
        this.handlePointerMove = (event) => {
            if (this.pointerDownPosition != null &&
                bundle.point.distance(this.pointerDownPosition, bundle.point.create(event.clientX, event.clientY)) > 2) {
                this.toSelectMarkupId = undefined;
            }
        };
        this.handlePointerUp = async (event) => {
            if (!this.disabled) {
                const el = event.target;
                const markups = await this.getMarkupElements();
                const markup = markups.find((m) => m === el);
                if ((markup === null || markup === void 0 ? void 0 : markup.id) != null &&
                    markup.id !== '' &&
                    markup.id === this.toSelectMarkupId) {
                    this.selectedMarkupId = el.id;
                }
                else if (this.pointerDownPosition != null &&
                    bundle.point.distance(this.pointerDownPosition, bundle.point.create(event.clientX, event.clientY)) <= 2) {
                    this.selectedMarkupId = undefined;
                }
                this.toSelectMarkupId = undefined;
                this.pointerDownPosition = undefined;
            }
            window.removeEventListener('pointerup', this.handlePointerUp);
            window.removeEventListener('pointermove', this.handlePointerMove);
        };
    }
    disconnectedCallback() {
        window.removeEventListener('pointerup', this.handlePointerUp);
        window.removeEventListener('pointermove', this.handlePointerMove);
    }
    /**
     * Adds a new markup as a child to this component. A new markup
     * component will be created from the template specified by
     * `arrow-template-id`, `circle-template-id`, or if undefined
     * a default element will be created.
     *
     * @param markup The markup to add.
     * @returns The markup element that was created.
     * @see {@link arrowTemplateId}
     * @see {@link circleTemplateId}
     */
    async addMarkup(markup$1) {
        if (markup$1 instanceof markup.ArrowMarkup) {
            const { start, end, id } = markup$1;
            const el = this.createArrowMarkupElement();
            this.appendMarkupElement(el);
            el.id = id;
            el.start = start;
            el.end = end;
            el.startLineAnchorStyle = this.startLineAnchorStyle;
            el.endLineAnchorStyle = this.endLineAnchorStyle;
            return el;
        }
        else if (markup$1 instanceof markup.CircleMarkup) {
            const { bounds, id } = markup$1;
            const el = this.createCircleMarkupElement();
            this.appendMarkupElement(el);
            el.id = id;
            el.bounds = bounds;
            return el;
        }
        else if (markup$1 instanceof markup.FreeformMarkup) {
            const { bounds, points, id } = markup$1;
            const el = this.createFreeformMarkupElement();
            this.appendMarkupElement(el);
            el.id = id;
            el.points = points;
            el.bounds = bounds;
            return el;
        }
        else {
            throw new Error(`Cannot add markup. Unknown type '${markup$1}'.`);
        }
    }
    /**
     * Removes a markup with the given ID, and returns the HTML element
     * associated to the markup. Returns `undefined` if no markup is
     * found.
     *
     * @param id The ID of the markup to remove.
     * @returns The markup element, or undefined.
     */
    async removeMarkup(id) {
        const markup = await this.getMarkupElement(id);
        if (markup != null) {
            markup.remove();
            this.markupRemoved.emit(markup);
        }
        return markup;
    }
    /**
     * Returns a list of markup elements that are children of this component.
     *
     * @returns A list of all markups.
     * @see {@link getMarkupElement}
     */
    async getMarkupElements() {
        return Array.from(this.hostEl.children).filter((e) => utils.isVertexViewerArrowMarkup(e) ||
            utils.isVertexViewerCircleMarkup(e) ||
            utils.isVertexViewerFreeformMarkup(e));
    }
    /**
     * Returns the markup element associated to the given ID.
     *
     * @param id The ID of the markup element to return.
     * @returns A markup element, or `undefined`.
     * @see {@link getMarkupElements}
     */
    async getMarkupElement(id) {
        const markup = await this.getMarkupElements();
        return markup.find((el) => el.id === id);
    }
    /**
     * @ignore
     */
    async handleSelectedMarkupIdChanged() {
        const markup = await this.getMarkupElements();
        markup.forEach((m) => {
            if (m.id === this.selectedMarkupId) {
                m.mode = 'edit';
                this.markupSelectionChanged.emit(m);
            }
            else {
                m.mode = '';
            }
        });
        if (this.selectedMarkupId == null) {
            this.markupSelectionChanged.emit(undefined);
        }
    }
    /**
     * @ignore
     */
    handlePropertyChanged() {
        this.updatePropsOnMarkupTool();
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer) {
        this.updatePropsOnMarkupTool();
        this.updatePropsOnMarkups();
    }
    /**
     * @ignore
     */
    handleDisabledChanged() {
        this.updatePropsOnMarkupTool();
    }
    /**
     * @ignore
     */
    async handleStartLineAnchorStyleChanged() {
        this.updatePropsOnMarkupTool();
        // If a piece of arrow markup is currently selected, then update its anchor style
        const selectedArrow = await this.getSelectedArrowMarkup();
        if (selectedArrow != null) {
            selectedArrow.startLineAnchorStyle = this.startLineAnchorStyle;
            this.markupChanged.emit(selectedArrow);
        }
    }
    /**
     * @ignore
     */
    async handleEndLineAnchorStyleChanged() {
        this.updatePropsOnMarkupTool();
        // If a piece of arrow markup is currently selected, then update its anchor style
        const selectedArrow = await this.getSelectedArrowMarkup();
        if (selectedArrow != null) {
            selectedArrow.endLineAnchorStyle = this.endLineAnchorStyle;
            this.markupChanged.emit(selectedArrow);
        }
    }
    /**
     * @ignore
     */
    async handleMarkupEnd(event) {
        var _a;
        const e = event;
        const el = await this.addMarkup(e.detail);
        await new Promise((resolve) => {
            const handleRender = () => {
                el.removeEventListener('viewRendered', handleRender);
                resolve();
            };
            el.addEventListener('viewRendered', handleRender);
        });
        if (this.selectNew) {
            this.selectedMarkupId = e.detail.id;
        }
        (_a = this.getMarkupTool()) === null || _a === void 0 ? void 0 : _a.reset();
    }
    /**
     * @ignore
     */
    async handleMarkupUpdated(event) {
        const e = event;
        // Do not emit the markupChanged event if the markup was just created
        if (!e.detail.newlyCreatedMarkup) {
            this.markupChanged.emit(e.detail.markup);
        }
    }
    /**
     * @ignore
     */
    async handleMarkupPointerDown(event) {
        if (!this.disabled) {
            const el = event.target;
            const markups = await this.getMarkupElements();
            const markup = markups.find((m) => m === el);
            if ((markup === null || markup === void 0 ? void 0 : markup.id) != null && (markup === null || markup === void 0 ? void 0 : markup.id) !== '') {
                this.toSelectMarkupId = el.id;
            }
            this.pointerDownPosition = bundle.point.create(event.clientX, event.clientY);
            window.addEventListener('pointermove', this.handlePointerMove);
            window.addEventListener('pointerup', this.handlePointerUp);
        }
    }
    /**
     * @ignore
     */
    componentDidLoad() {
        this.updatePropsOnMarkupTool();
    }
    /**
     * @ignore
     */
    render() {
        return (index.h(index.Host, { key: 'a5620363230dcc56e335b0864eacf94ba8d8232c' }, index.h("slot", { key: '7fa77e410c679b183304f117e8c8e0a36a3ea14d', onSlotchange: this.handleSlotChange })));
    }
    appendMarkupElement(el) {
        this.updatePropsOnMarkup(el);
        this.hostEl.appendChild(el);
        this.markupAdded.emit(el);
        return el;
    }
    createArrowMarkupElement() {
        if (this.arrowTemplateId != null) {
            const element = templates.stampTemplateWithId(window.document.body, this.arrowTemplateId, utils.isVertexViewerArrowMarkup, () => console.warn(`Arrow template with ID ${this.arrowTemplateId} not found. Using default arrow element.`), () => console.warn(`Arrow template does not contain a vertex-viewer-markup-arrow. Using default arrow element.`));
            if (element != null) {
                return element;
            }
        }
        return document.createElement('vertex-viewer-markup-arrow');
    }
    createCircleMarkupElement() {
        if (this.circleTemplateId != null) {
            const element = templates.stampTemplateWithId(window.document.body, this.circleTemplateId, utils.isVertexViewerCircleMarkup, () => console.warn(`Circle template with ID ${this.circleTemplateId} not found. Using default circle element.`), () => console.warn(`Circle template does not contain a vertex-viewer-markup-circle. Using default circle element.`));
            if (element != null) {
                return element;
            }
        }
        return document.createElement('vertex-viewer-markup-circle');
    }
    createFreeformMarkupElement() {
        if (this.freeformTemplateId != null) {
            const element = templates.stampTemplateWithId(window.document.body, this.freeformTemplateId, utils.isVertexViewerFreeformMarkup, () => console.warn(`Freeform template with ID ${this.freeformTemplateId} not found. Using default freeform element.`), () => console.warn(`Freeform template does not contain a vertex-viewer-markup-freeform. Using default freeform element.`));
            if (element != null) {
                return element;
            }
        }
        return document.createElement('vertex-viewer-markup-freeform');
    }
    async updatePropsOnMarkups() {
        const markup = await this.getMarkupElements();
        markup.forEach((m) => this.updatePropsOnMarkup(m));
    }
    updatePropsOnMarkup(element) {
        element.viewer = this.viewer;
        element.originatingViewport = this.originatingViewport;
        element.centeringBehavior = this.centeringBehavior;
        element.offset = this.offset;
        element.scale = this.scale;
        element.classList.add('viewer-markup__markup');
    }
    updatePropsOnMarkupTool() {
        const tool = this.getMarkupTool();
        if (tool != null) {
            tool.disabled = this.disabled;
            tool.arrowTemplateId = this.arrowTemplateId;
            tool.circleTemplateId = this.circleTemplateId;
            tool.freeformTemplateId = this.freeformTemplateId;
            tool.tool = this.tool;
            tool.viewer = this.viewer;
            tool.startLineAnchorStyle = this.startLineAnchorStyle;
            tool.endLineAnchorStyle = this.endLineAnchorStyle;
            tool.originatingViewport = this.originatingViewport;
            tool.centeringBehavior = this.centeringBehavior;
            tool.offset = this.offset;
            tool.scale = this.scale;
        }
    }
    getMarkupTool() {
        return this.hostEl.querySelector('vertex-viewer-markup-tool');
    }
    async getSelectedArrowMarkup() {
        if (this.selectedMarkupId != null) {
            const selected = await this.getMarkupElement(this.selectedMarkupId);
            return utils.isVertexViewerArrowMarkup(selected) ? selected : undefined;
        }
    }
    get hostEl() { return index.getElement(this); }
    static get watchers() { return {
        "selectedMarkupId": [{
                "handleSelectedMarkupIdChanged": 0
            }],
        "arrowTemplateId": [{
                "handlePropertyChanged": 0
            }],
        "circleTemplateId": [{
                "handlePropertyChanged": 0
            }],
        "freeformTemplateId": [{
                "handlePropertyChanged": 0
            }],
        "tool": [{
                "handlePropertyChanged": 0
            }],
        "viewer": [{
                "handleViewerChanged": 0
            }],
        "originatingViewport": [{
                "handleViewerChanged": 0
            }],
        "centeringBehavior": [{
                "handleViewerChanged": 0
            }],
        "offset": [{
                "handleViewerChanged": 0
            }],
        "scale": [{
                "handleViewerChanged": 0
            }],
        "disabled": [{
                "handleDisabledChanged": 0
            }],
        "startLineAnchorStyle": [{
                "handleStartLineAnchorStyleChanged": 0
            }],
        "endLineAnchorStyle": [{
                "handleEndLineAnchorStyleChanged": 0
            }]
    }; }
};
ViewerMarkup.style = viewerMarkupCss();

exports.vertex_viewer_markup = ViewerMarkup;
//# sourceMappingURL=vertex-viewer-markup.entry.cjs.js.map

//# sourceMappingURL=vertex-viewer-markup.cjs.entry.js.map