/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { h, r as registerInstance, c as createEvent, H as Host, a as getElement } from './index-EpnuuCxl.js';
import { b as getWindowDevicePixelRatio, g as getMouseClientPosition } from './dom-D6my8OyX.js';
import { w as writeDOM } from './stencil-CEl7wGvE.js';
import { g as getMarkupBoundingClientRect } from './dom-Bg-uS9BH.js';
import { p as point, e as dimensions, g as rectangle, a as angle } from './bundle-DfdVaPrt.js';
import { i as isVertexViewerArrowMarkup, a as isVertexViewerCircleMarkup, b as isVertexViewerFreeformMarkup, p as parsePoint, c as arrowheadPointsToPolygonPoints, d as arrowheadPointsToPathPoints, e as arrowheadPointsToHashPoints, f as arrowheadPointsToCirclePoints, g as createLineAnchorStylePoints, h as parseBounds, j as parsePoints } from './utils-DKzHYmwU.js';
import { c as classname } from './index-DI7z7TKn.js';
import './_commonjsHelpers-CG9AChtV.js';

function getBoundingBox2dAnchorPosition(rect, position) {
    switch (position) {
        case 'top-left':
            return point.create(rect.x, rect.y);
        case 'top':
            return point.create(rect.x + rect.width / 2, rect.y);
        case 'top-right':
            return point.create(rect.x + rect.width, rect.y);
        case 'right':
            return point.create(rect.x + rect.width, rect.y + rect.height / 2);
        case 'bottom-right':
            return point.create(rect.x + rect.width, rect.y + rect.height);
        case 'bottom':
            return point.create(rect.x + rect.width / 2, rect.y + rect.height);
        case 'bottom-left':
            return point.create(rect.x, rect.y + rect.height);
        case 'left':
            return point.create(rect.x, rect.y + rect.height / 2);
        case 'center':
            return rectangle.center(rect);
    }
}
function translatePointToScreen(pt, canvasDimensions, contentDimensions = canvasDimensions, centeringBehavior = 'none', scale = 1) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentRelativePoint = point.add(point.scale(pt, contentScaleFactor, contentScaleFactor), dimensions.center(contentDimensions));
    // Include an offset for width and height to account for cases where the
    // content dimensions are smaller than the canvas dimensions.
    const scaledContentWidth = contentDimensions.width * effectiveScalar;
    const scaledContentHeight = contentDimensions.height * effectiveScalar;
    const centerOffsetX = centeringBehavior === 'both' || centeringBehavior === 'x-only'
        ? Math.max(0, (canvasDimensions.width - scaledContentWidth) / 2)
        : 0;
    const centerOffsetY = centeringBehavior === 'both' || centeringBehavior === 'y-only'
        ? Math.max(0, (canvasDimensions.height - scaledContentHeight) / 2)
        : 0;
    return point.create(contentRelativePoint.x * effectiveScalar + centerOffsetX, contentRelativePoint.y * effectiveScalar + centerOffsetY);
}
function translateDimensionsToScreen(dimensions$1, canvasDimensions, contentDimensions = canvasDimensions, scale = 1) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentRelativeDimensions = dimensions.scale(contentScaleFactor, contentScaleFactor, dimensions$1);
    return dimensions.scale(effectiveScalar, effectiveScalar, contentRelativeDimensions);
}
/**
 * Translates a rectangle in relative units, to a rectangle in screen units.
 *
 * Shape coordinates are persisted in relative units, so they can be presented
 * at any size.
 */
function translateRectToScreen(rect, canvasDimensions, contentDimensions, centeringBehavior = 'none', scale = 1) {
    const position = translatePointToScreen(rect, canvasDimensions, contentDimensions, centeringBehavior, scale);
    const dimensions = translateDimensionsToScreen(rect, canvasDimensions, contentDimensions, scale);
    return rectangle.fromPointAndDimensions(position, dimensions);
}
/**
 * Translates a point in screen units, to a point in relative units.
 */
function translatePointToRelative(pt, canvasDimensions, contentDimensions = canvasDimensions, centeringBehavior = 'none', scale = 1, offset = point.create(0, 0)) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    // Include an offset for width and height to account for cases where the
    // content dimensions are smaller than the canvas dimensions.
    const scaledContentWidth = contentDimensions.width * effectiveScalar;
    const scaledContentHeight = contentDimensions.height * effectiveScalar;
    const centerOffsetX = centeringBehavior === 'both' || centeringBehavior === 'x-only'
        ? Math.max(0, (canvasDimensions.width - scaledContentWidth) / 2)
        : 0;
    const centerOffsetY = centeringBehavior === 'both' || centeringBehavior === 'y-only'
        ? Math.max(0, (canvasDimensions.height - scaledContentHeight) / 2)
        : 0;
    const pointWithoutOffset = point.subtract(pt, point.scale(offset, 1 / getWindowDevicePixelRatio(), 1 / getWindowDevicePixelRatio()));
    const centeredContentPoint = point.create((pointWithoutOffset.x - centerOffsetX) / effectiveScalar, (pointWithoutOffset.y - centerOffsetY) / effectiveScalar);
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentCenterRelativePoint = point.subtract(centeredContentPoint, dimensions.center(contentDimensions));
    return point.scale(contentCenterRelativePoint, 1 / contentScaleFactor, 1 / contentScaleFactor);
}
/**
 * Translates a set of points in relative `original` units to
 * points in relative `bounds` units.
 */
function translatePointsToBounds(points, original, bounds) {
    return points.map((pt) => point.add(point.scale(point.subtract(pt, original), bounds.width / (original.width || 1), bounds.height / (original.height || 1)), bounds));
}
function createRectangle(initialPoint, currentPoint, maintainAspectRatio) {
    const bounds = rectangle.fromPoints(initialPoint, currentPoint);
    if (maintainAspectRatio) {
        const fitBoundsSize = Math.max(bounds.width, bounds.height);
        const isPortrait = bounds.height > bounds.width;
        const currentIsLeftOfInitial = currentPoint.x <= initialPoint.x;
        const currentIsAboveInitial = currentPoint.y <= initialPoint.y;
        const fitBoundsX = currentIsLeftOfInitial
            ? isPortrait
                ? initialPoint.x - fitBoundsSize
                : currentPoint.x
            : initialPoint.x;
        const fitBoundsY = currentIsAboveInitial
            ? isPortrait
                ? currentPoint.y
                : initialPoint.y - fitBoundsSize
            : initialPoint.y;
        return rectangle.create(fitBoundsX, fitBoundsY, fitBoundsSize, fitBoundsSize);
    }
    else {
        return bounds;
    }
}
function transformRectangle(bounds, start, current, anchor, maintainAspectRatio) {
    const delta = point.subtract(current, start);
    const { x: left, y: top, width: w, height: h } = bounds;
    const right = left + w;
    const bottom = top + h;
    const topLeft = point.create(left, top);
    const bottomLeft = point.create(left, bottom);
    const topRight = point.create(right, top);
    const bottomRight = point.create(right, bottom);
    switch (anchor) {
        case 'top-left':
            return createRectangle(bottomRight, current, !!maintainAspectRatio);
        case 'top':
            return createRectangle(bottomRight, point.create(left, current.y), !!maintainAspectRatio);
        case 'top-right':
            return createRectangle(bottomLeft, current, !!maintainAspectRatio);
        case 'right':
            return createRectangle(bottomLeft, point.create(current.x, top), !!maintainAspectRatio);
        case 'bottom-right':
            return createRectangle(topLeft, current, !!maintainAspectRatio);
        case 'bottom':
            return createRectangle(topLeft, point.create(right, current.y), !!maintainAspectRatio);
        case 'bottom-left':
            return createRectangle(topRight, current, !!maintainAspectRatio);
        case 'left':
            return createRectangle(bottomRight, point.create(current.x, top), !!maintainAspectRatio);
        case 'center':
            return rectangle.create(bounds.x + delta.x, bounds.y + delta.y, bounds.width, bounds.height);
    }
}
function isVertexViewerMarkupElement(el) {
    return (isVertexViewerArrowMarkup(el) ||
        isVertexViewerCircleMarkup(el) ||
        isVertexViewerFreeformMarkup(el));
}
function isValidPointData(...points) {
    return points.every((pt) => !isNaN(pt.x) && !isNaN(pt.y));
}
function isValidStartEvent(event) {
    const el = event.target;
    return isVertexViewerMarkupElement(el) && el.mode !== 'edit';
}
function getScaleFactor(dimensions) {
    // We intentionally use the content's height when scaling to maintain a consistent coordinate
    // space for markup. This is to ensure the markup will be displayed in the same position
    // on the canvas regardless of the aspect ratio at the time the markup was created.
    // See https://github.com/Vertexvis/vertex-web-sdk/pull/429 for more details.
    return dimensions.height;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const RelativeAnchor = ({ id, transform, rotation, name, point, onPointerDown }, children) => {
    return (h("div", { id: id, class: "bounds-anchor-position", style: {
            top: `${point.y}px`,
            left: `${point.x}px`,
        }, onTouchStart: (event) => event.preventDefault(), onPointerDown: onPointerDown }, h("div", { style: { transform } }, h("div", { class: "bounds-anchor", style: {
            transform: `rotateZ(${rotation !== null && rotation !== void 0 ? rotation : 0}deg)`,
        } }, h("slot", { name: name }, children)))));
};
const SvgShadow = ({ id, scale, }) => {
    // Scale default values for a `<filter>` element by the provided scale.
    // This prevents the filter area from being too small when scale is greater than 1,
    // and uses the default values for a scale less than 1 to prevent the same issue.
    // See https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/filter
    // for more details on the default values used here.
    const effectiveScale = scale !== null && scale !== void 0 ? scale : 1;
    const xOffset = Math.max(10, 10 * effectiveScale);
    const yOffset = Math.max(10, 10 * effectiveScale);
    const width = Math.max(120, 110 * effectiveScale + xOffset);
    const height = Math.max(120, 110 * effectiveScale + yOffset);
    return (h("filter", { id: id, filterUnits: "userSpaceOnUse", x: `${-xOffset}%`, y: `${-yOffset}%`, width: `${width}%`, height: `${height}%` }, h("feGaussianBlur", { in: "SourceAlpha", stdDeviation: "2" }), h("feOffset", { dx: "0", dy: "1", result: "offsetblur" }), h("feFlood", { "flood-color": "#000000", "flood-opacity": "0.25" }), h("feComposite", { in2: "offsetblur", operator: "in" }), h("feMerge", null, h("feMergeNode", null), h("feMergeNode", { in: "SourceGraphic" }))));
};

class MarkupInteractionHandler {
    constructor(scalingOptions) {
        this.handlePointerDown = (event) => {
            this.handleInteractionAttempt(event);
        };
        this.handlePointerMove = (event) => {
            this.handleInteractionMove(event);
        };
        this.handlePointerUp = (event) => {
            window.removeEventListener('pointermove', this.handlePointerMove);
            window.removeEventListener('pointerup', this.handlePointerUp);
            this.handleInteractionEnd(event);
        };
        this.resizeObserver = new ResizeObserver(([entry]) => {
            this.elementBounds = this.computeBoundingRect();
        });
        this.scalingOptions = scalingOptions !== null && scalingOptions !== void 0 ? scalingOptions : {};
    }
    initialize(element) {
        this.element = element;
        this.elementBounds = this.computeBoundingRect();
        this.resizeObserver.observe(this.element);
        this.element.addEventListener('pointerdown', this.handlePointerDown);
    }
    dispose() {
        var _a;
        this.resizeObserver.disconnect();
        (_a = this.element) === null || _a === void 0 ? void 0 : _a.removeEventListener('pointerdown', this.handlePointerDown);
        this.element = undefined;
    }
    updateScalingOptions(scalingOptions) {
        this.scalingOptions = {
            ...this.scalingOptions,
            ...scalingOptions,
        };
    }
    getScalingOptions() {
        return this.scalingOptions;
    }
    acceptInteraction() {
        window.addEventListener('pointermove', this.handlePointerMove);
        window.addEventListener('pointerup', this.handlePointerUp);
    }
}

class ArrowMarkupInteractionHandler extends MarkupInteractionHandler {
    constructor(markupEl, interactionBegin, interactionEnd, scalingOptions) {
        super(scalingOptions);
        this.markupEl = markupEl;
        this.interactionBegin = interactionBegin;
        this.interactionEnd = interactionEnd;
        this.anchor = 'end';
    }
    editAnchor(anchor, event) {
        if (this.markupEl.mode === 'edit') {
            this.anchor = anchor;
            this.startInteraction(event);
        }
    }
    startInteraction(event) {
        this.handleInteractionAttempt(event);
    }
    computeBoundingRect() {
        return getMarkupBoundingClientRect(this.markupEl);
    }
    handleInteractionAttempt(event) {
        var _a;
        if (this.markupEl.mode !== '' &&
            this.pointerId == null &&
            this.elementBounds != null) {
            this.pointerId = event.pointerId;
            this.markupEl.start =
                (_a = this.markupEl.start) !== null && _a !== void 0 ? _a : translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            this.interactionBegin.emit();
            this.acceptInteraction();
        }
    }
    handleInteractionMove(event) {
        if (this.elementBounds != null && this.pointerId === event.pointerId) {
            const position = translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            if (this.anchor === 'start') {
                this.markupEl.start = position;
            }
            else if (this.anchor === 'end') {
                this.markupEl.end = position;
            }
            else if (this.markupEl.start != null && this.markupEl.end != null) {
                const center = point.create((this.markupEl.start.x + this.markupEl.end.x) / 2, (this.markupEl.start.y + this.markupEl.end.y) / 2);
                const xDifference = center.x - position.x;
                const yDifference = center.y - position.y;
                this.markupEl.start = point.create(this.markupEl.start.x - xDifference, this.markupEl.start.y - yDifference);
                this.markupEl.end = point.create(this.markupEl.end.x - xDifference, this.markupEl.end.y - yDifference);
            }
        }
    }
    handleInteractionEnd(event) {
        if (this.pointerId === event.pointerId) {
            const screenStart = this.markupEl.start != null && this.elementBounds != null
                ? translatePointToScreen(this.markupEl.start, this.elementBounds)
                : undefined;
            const screenEnd = this.markupEl.end != null && this.elementBounds != null
                ? translatePointToScreen(this.markupEl.end, this.elementBounds)
                : undefined;
            if (this.markupEl.mode !== '' &&
                screenStart != null &&
                screenEnd != null &&
                point.distance(screenStart, screenEnd) >= 2) {
                const newlyCreatedMarkup = this.markupEl.mode !== 'edit';
                this.interactionEnd.emit({ markup: this.markupEl, newlyCreatedMarkup });
            }
            else {
                this.markupEl.start = undefined;
                this.markupEl.end = undefined;
            }
            this.pointerId = undefined;
        }
    }
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const BoundingBox1d = ({ start, end, offset, onStartAnchorPointerDown, onCenterAnchorPointerDown, onEndAnchorPointerDown, }) => {
    const angle$1 = angle.normalize(angle.toDegrees(angle.fromPoints(start, end)) - 270);
    const center = point.create((start.x + end.x) / 2, (start.y + end.y) / 2);
    const transform = offset != null ? `translate(${offset.x}px, ${offset.y}px)` : undefined;
    return (h("div", { class: "bounds-container" }, h(RelativeAnchor, { transform: transform, id: "bounding-box-1d-start-anchor", name: "start-anchor", rotation: angle$1, point: start, onPointerDown: onStartAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-cap-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-1d-end-anchor", name: "end-anchor", rotation: angle$1, point: end, onPointerDown: onEndAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-cap-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-1d-center-anchor", name: "center-anchor", point: center, onPointerDown: onCenterAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-center-anchor') }))));
};

const viewerMarkupArrowCss = () => `:host{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;--viewer-markup-arrow-line-stroke-color:var(--red-800);--viewer-markup-arrow-line-stroke-width:4px;--viewer-markup-arrow-head-stroke-color:var(--red-800);--viewer-markup-arrow-head-stroke-width:4px;--viewer-markup-arrow-head-fill-color:var(--red-800);--viewer-markup-arrow-head-fill-opacity:1;--viewer-markup-arrow-bounds-cap-border-color:var(--blue-400);--viewer-markup-arrow-bounds-cap-border-width:1px;--viewer-markup-arrow-bounds-cap-background-color:white;--viewer-markup-arrow-bounds-center-anchor-border-color:white;--viewer-markup-arrow-bounds-center-anchor-border-width:1px;--viewer-markup-arrow-bounds-center-anchor-background-color:var(--blue-400);--viewer-markup-arrow-bounds-outline-width:1px;--viewer-markup-arrow-bounds-outline-color:var(--blue-400);--viewer-markup-arrow-bounds-anchor-width:9px;--viewer-markup-arrow-bounds-anchor-height:9px;--viewer-markup-arrow-scale:1}.svg{pointer-events:none;width:100%;height:100%}.create-overlay{pointer-events:auto;position:absolute;left:0;top:0;width:100%;height:100%;cursor:crosshair}.line{pointer-events:auto;stroke:var(--viewer-markup-arrow-line-stroke-color);stroke-width:calc(     var(--viewer-markup-arrow-line-stroke-width) *       var(--viewer-markup-arrow-scale)   );cursor:default}.head{pointer-events:auto;stroke:var(--viewer-markup-arrow-head-stroke-color);stroke-width:calc(     var(--viewer-markup-arrow-head-stroke-width) *       var(--viewer-markup-arrow-scale)   );fill:var(--viewer-markup-arrow-head-fill-color);fill-opacity:var(--viewer-markup-arrow-head-fill-opacity);cursor:default}.bounds-line{pointer-events:auto;stroke:var(--viewer-markup-arrow-bounds-outline-color);stroke-width:var(--viewer-markup-arrow-bounds-outline-width)}.bounds-container{pointer-events:none;position:absolute;width:100%;height:100%;top:0;left:0;overflow:hidden}.bounds-anchor-position{position:absolute;transform:translate(-50%, -50%)}.bounds-anchor{pointer-events:auto;cursor:default;user-select:none}.bounds-default-anchor{width:var(--viewer-markup-arrow-bounds-anchor-width);height:var(--viewer-markup-arrow-bounds-anchor-height);box-sizing:border-box;box-shadow:0 0 2px rgba(0, 0, 0, 0.3)}.bounds-center-anchor{border-radius:100%;border-width:var(--viewer-markup-arrow-bounds-center-anchor-border-width);border-color:var(--viewer-markup-arrow-bounds-center-anchor-border-color);border-style:solid;background-color:var(     --viewer-markup-arrow-bounds-center-anchor-background-color   )}.bounds-cap-anchor{border-width:var(--viewer-markup-arrow-bounds-cap-border-width);border-color:var(--viewer-markup-arrow-bounds-cap-border-color);border-style:solid;background-color:var(--viewer-markup-arrow-bounds-cap-background-color)}`;

const ViewerMarkupArrow = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.interactionBegin = createEvent(this, "interactionBegin");
        this.interactionEnd = createEvent(this, "interactionEnd");
        this.viewRendered = createEvent(this, "viewRendered");
        /**
         * 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;
        /**
         * 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';
        /**
         * A mode that specifies how the markup component should behave. When
         * unset, the component will not respond to interactions with the handles.
         * When `edit`, the markup anchors are interactive and the user is able
         * to reposition them. When `create`, anytime the user clicks on the canvas,
         * a new markup will be performed.
         */
        this.mode = '';
        this.interactionHandler = new ArrowMarkupInteractionHandler(this.hostEl, this.interactionBegin, this.interactionEnd, {
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
        this.handleWindowPointerDown = (event) => {
            if (isValidStartEvent(event)) {
                this.interactionHandler.startInteraction(event);
            }
        };
        this.handleTouchStart = (event) => {
            event.preventDefault();
        };
    }
    /**
     * @ignore
     */
    componentWillLoad() {
        this.updateViewport();
        this.handleViewerChanged(this.viewer);
        this.handleScaleChange();
        this.handleScalingConfigurationChange();
        this.updatePointsFromProps();
    }
    componentDidLoad() {
        this.updatePointsFromProps();
        const resize = new ResizeObserver(() => this.updateViewport());
        resize.observe(this.hostEl);
        if (this.mode === 'create') {
            window.addEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    componentDidRender() {
        if (this.mode === '') {
            this.viewRendered.emit();
        }
    }
    disconnectedCallback() {
        this.dispose();
    }
    async dispose() {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        window.removeEventListener('pointerdown', this.handleWindowPointerDown);
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer) {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        if (newViewer != null) {
            this.registeredInteraction =
                await newViewer.registerBasicInteractionHandler(this.interactionHandler);
        }
    }
    handleStartJsonChange() {
        this.updatePointsFromProps();
    }
    handleEndJsonChange() {
        this.updatePointsFromProps();
    }
    handleModeChange() {
        if (this.mode !== 'create') {
            window.removeEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    handleScalingConfigurationChange() {
        this.interactionHandler.updateScalingOptions({
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
    }
    handleScaleChange() {
        writeDOM(() => {
            var _a, _b;
            this.hostEl.style.setProperty('--viewer-markup-arrow-scale', (_b = (_a = this.scale) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '1');
        });
    }
    updateViewport() {
        const rect = getMarkupBoundingClientRect(this.hostEl);
        this.elementBounds = rect;
    }
    updatePointsFromProps() {
        this.start = this.start || parsePoint(this.startJson);
        this.end = this.end || parsePoint(this.endJson);
    }
    renderLineAnchorStyle(anchorStyle, arrowheadPoints) {
        if (anchorStyle === 'arrow-triangle') {
            return (h("polygon", { id: "line-anchor-arrow-triangle", class: "head", points: arrowheadPointsToPolygonPoints(arrowheadPoints, this.scale) }));
        }
        else if (anchorStyle === 'arrow-line') {
            return (h("path", { id: "line-anchor-arrow-line", class: "head", d: arrowheadPointsToPathPoints(arrowheadPoints, this.scale) }));
        }
        else if (anchorStyle === 'hash') {
            const hashPoints = arrowheadPointsToHashPoints(arrowheadPoints, this.scale);
            return h("line", { id: "line-anchor-hash", class: "head", ...hashPoints });
        }
        else if (anchorStyle === 'dot') {
            const circlePoints = arrowheadPointsToCirclePoints(arrowheadPoints, this.scale);
            return h("circle", { id: "line-anchor-circle", class: "head", ...circlePoints });
        }
        else {
            return h("div", null);
        }
    }
    render() {
        var _a, _b, _c, _d;
        if (this.start != null && this.end != null && this.elementBounds != null) {
            const elementBounds = this.elementBounds;
            const offsetX = ((_b = (_a = this.offset) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0) / getWindowDevicePixelRatio();
            const offsetY = ((_d = (_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0) / getWindowDevicePixelRatio();
            const screenStart = translatePointToScreen(this.start, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale);
            const screenEnd = translatePointToScreen(this.end, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale);
            if (isValidPointData(screenStart, screenEnd)) {
                const arrowheadStartPoints = createLineAnchorStylePoints(screenEnd, screenStart);
                const arrowheadEndPoints = createLineAnchorStylePoints(screenStart, screenEnd);
                return (h(Host, null, h("svg", { class: "svg", onTouchStart: this.handleTouchStart }, h("defs", null, h(SvgShadow, { id: "arrow-shadow", scale: this.scale })), h("g", { transform: `translate(${offsetX} ${offsetY})`, filter: "url(#arrow-shadow)" }, this.renderLineAnchorStyle(this.startLineAnchorStyle, arrowheadStartPoints), h("line", { id: "arrow-line", class: "line", x1: arrowheadEndPoints.tip.x, y1: arrowheadEndPoints.tip.y, x2: arrowheadStartPoints.tip.x, y2: arrowheadStartPoints.tip.y }), this.renderLineAnchorStyle(this.endLineAnchorStyle, arrowheadEndPoints)), this.mode === 'edit' && (h("g", { transform: `translate(${offsetX} ${offsetY})` }, h("line", { id: "bounding-box-1d-line", class: "bounds-line", x1: screenStart.x, y1: screenStart.y, x2: screenEnd.x, y2: screenEnd.y })))), this.mode === 'edit' && (h(BoundingBox1d, { start: screenStart, end: screenEnd, offset: { x: offsetX, y: offsetY }, onStartAnchorPointerDown: (event) => this.interactionHandler.editAnchor('start', event), onCenterAnchorPointerDown: (event) => this.interactionHandler.editAnchor('center', event), onEndAnchorPointerDown: (event) => this.interactionHandler.editAnchor('end', event) })), this.mode === 'create' && (h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart }))));
            }
            else {
                return h(Host, null);
            }
        }
        else {
            return (h(Host, null, h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart })));
        }
    }
    get hostEl() { return getElement(this); }
    static get watchers() { return {
        "viewer": [{
                "handleViewerChanged": 0
            }],
        "start": [{
                "handleStartJsonChange": 0
            }],
        "end": [{
                "handleEndJsonChange": 0
            }],
        "mode": [{
                "handleModeChange": 0
            }],
        "offset": [{
                "handleScalingConfigurationChange": 0
            }],
        "originatingViewport": [{
                "handleScalingConfigurationChange": 0
            }],
        "centeringBehavior": [{
                "handleScalingConfigurationChange": 0
            }],
        "scale": [{
                "handleScalingConfigurationChange": 0
            }, {
                "handleScaleChange": 0
            }]
    }; }
};
ViewerMarkupArrow.style = viewerMarkupArrowCss();

class CircleMarkupInteractionHandler extends MarkupInteractionHandler {
    constructor(markupEl, interactionBegin, interactionEnd, scalingOptions) {
        super(scalingOptions);
        this.markupEl = markupEl;
        this.interactionBegin = interactionBegin;
        this.interactionEnd = interactionEnd;
        this.anchor = 'bottom-right';
    }
    editAnchor(anchor, event) {
        if (this.markupEl.mode === 'edit') {
            this.anchor = anchor;
            this.resizeBounds = this.markupEl.bounds;
            this.startInteraction(event);
        }
    }
    startInteraction(event) {
        this.handleInteractionAttempt(event);
    }
    computeBoundingRect() {
        return getMarkupBoundingClientRect(this.markupEl);
    }
    handleInteractionAttempt(event) {
        var _a;
        if (this.markupEl.mode !== '' &&
            this.pointerId == null &&
            this.elementBounds != null) {
            const position = translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            this.pointerId = event.pointerId;
            this.startPosition = position;
            this.markupEl.bounds =
                (_a = this.markupEl.bounds) !== null && _a !== void 0 ? _a : rectangle.create(position.x, position.y, 0, 0);
            this.resizeBounds = this.markupEl.bounds;
            this.interactionBegin.emit();
            this.acceptInteraction();
        }
    }
    handleInteractionMove(event) {
        var _a;
        if (this.markupEl.bounds != null &&
            this.startPosition != null &&
            this.elementBounds != null &&
            this.pointerId === event.pointerId) {
            const position = translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            this.markupEl.bounds = transformRectangle((_a = this.resizeBounds) !== null && _a !== void 0 ? _a : this.markupEl.bounds, this.startPosition, position, this.anchor, event.shiftKey);
        }
    }
    handleInteractionEnd(event) {
        var _a, _b;
        if (this.pointerId === event.pointerId) {
            if (this.markupEl.mode !== '' &&
                this.markupEl.bounds != null &&
                ((_a = this.markupEl.bounds) === null || _a === void 0 ? void 0 : _a.width) > 0 &&
                ((_b = this.markupEl.bounds) === null || _b === void 0 ? void 0 : _b.height) > 0) {
                this.anchor = 'bottom-right';
                const newlyCreatedMarkup = this.markupEl.mode !== 'edit';
                this.interactionEnd.emit({ markup: this.markupEl, newlyCreatedMarkup });
            }
            else {
                this.markupEl.bounds = undefined;
            }
            this.pointerId = undefined;
        }
    }
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const BoundingBox2d = ({ bounds, offset, onTopLeftAnchorPointerDown, onLeftAnchorPointerDown, onTopRightAnchorPointerDown, onRightAnchorPointerDown, onBottomLeftAnchorPointerDown, onBottomAnchorPointerDown, onBottomRightAnchorPointerDown, onTopAnchorPointerDown, onCenterAnchorPointerDown, }) => {
    const padded = rectangle.pad(bounds, 6);
    const center = rectangle.center(padded);
    const transform = offset != null ? `translate(${offset.x}px, ${offset.y}px)` : undefined;
    return (h("div", { class: "bounds-container" }, h("div", { class: "bounds-outline", style: {
            top: `${padded.y}px`,
            left: `${padded.x}px`,
            width: `${padded.width}px`,
            height: `${padded.height}px`,
            transform,
        } }), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-top-left-anchor", name: "top-left-anchor", point: getBoundingBox2dAnchorPosition(padded, 'top-left'), onPointerDown: onTopLeftAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-left-anchor", name: "left-anchor", point: getBoundingBox2dAnchorPosition(padded, 'left'), onPointerDown: onLeftAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-top-right-anchor", name: "top-right-anchor", point: getBoundingBox2dAnchorPosition(padded, 'top-right'), onPointerDown: onTopRightAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-right-anchor", name: "right-anchor", point: getBoundingBox2dAnchorPosition(padded, 'right'), onPointerDown: onRightAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-bottom-left-anchor", name: "bottom-left-anchor", point: getBoundingBox2dAnchorPosition(padded, 'bottom-left'), onPointerDown: onBottomLeftAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-bottom-anchor", name: "bottom-anchor", point: getBoundingBox2dAnchorPosition(padded, 'bottom'), onPointerDown: onBottomAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-bottom-right-anchor", name: "bottom-right-anchor", point: getBoundingBox2dAnchorPosition(padded, 'bottom-right'), onPointerDown: onBottomRightAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-top-anchor", name: "top-anchor", point: getBoundingBox2dAnchorPosition(padded, 'top'), onPointerDown: onTopAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-edge-anchor') })), h(RelativeAnchor, { transform: transform, id: "bounding-box-2d-center-anchor", name: "center-anchor", point: center, onPointerDown: onCenterAnchorPointerDown }, h("div", { class: classname('bounds-default-anchor', 'bounds-center-anchor') }))));
};

const viewerMarkupCircleCss = () => `:host{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;--viewer-markup-circle-ellipse-stroke-color:var(--red-700);--viewer-markup-circle-ellipse-stroke-width:4px;--viewer-markup-circle-ellipse-fill-color:none;--viewer-markup-circle-ellipse-fill-opacity:0;--viewer-markup-circle-bounds-outline-border-color:var(--blue-400);--viewer-markup-circle-bounds-outline-border-width:1px;--viewer-markup-circle-bounds-edge-anchor-border-color:var(--blue-400);--viewer-markup-circle-bounds-edge-anchor-border-width:1px;--viewer-markup-circle-bounds-edge-anchor-background-color:white;--viewer-markup-circle-bounds-center-anchor-border-color:white;--viewer-markup-circle-bounds-center-anchor-border-width:1px;--viewer-markup-circle-bounds-center-anchor-background-color:var(--blue-400);--viewer-markup-circle-bounds-anchor-width:9px;--viewer-markup-circle-bounds-anchor-height:9px;--viewer-markup-circle-scale:1}.svg{pointer-events:none;width:100%;height:100%}.create-overlay{pointer-events:auto;position:absolute;left:0;top:0;width:100%;height:100%;cursor:crosshair}.ellipse{pointer-events:auto;stroke:var(--viewer-markup-circle-ellipse-stroke-color);stroke-width:calc(     var(--viewer-markup-circle-ellipse-stroke-width) *       var(--viewer-markup-circle-scale)   );fill:var(--viewer-markup-circle-ellipse-fill-color);fill-opacity:var(--viewer-markup-circle-ellipse-fill-opacity);cursor:default}.bounds-container{pointer-events:none;position:absolute;width:100%;height:100%;top:0;left:0;overflow:hidden}.bounds-outline{position:absolute;border-width:var(--viewer-markup-circle-bounds-outline-border-width);border-color:var(--viewer-markup-circle-bounds-outline-border-color);border-style:solid;box-shadow:0 0 3px rgba(0, 0, 0, 0.3)}.bounds-anchor-position{position:absolute;transform:translate(-50%, -50%)}.bounds-anchor{pointer-events:auto;cursor:default;user-select:none}.bounds-default-anchor{width:var(--viewer-markup-circle-bounds-anchor-width);height:var(--viewer-markup-circle-bounds-anchor-height);box-sizing:border-box;box-shadow:0 0 2px rgba(0, 0, 0, 0.3)}.bounds-center-anchor{border-radius:100%;border-width:var(--viewer-markup-circle-bounds-center-anchor-border-width);border-color:var(--viewer-markup-circle-bounds-center-anchor-border-color);border-style:solid;background-color:var(     --viewer-markup-circle-bounds-center-anchor-background-color   )}.bounds-edge-anchor{border-width:var(--viewer-markup-circle-bounds-edge-anchor-border-width);border-color:var(--viewer-markup-circle-bounds-edge-anchor-border-color);border-style:solid;background-color:var(     --viewer-markup-circle-bounds-edge-anchor-background-color   )}`;

const ViewerMarkupCircle = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.interactionBegin = createEvent(this, "interactionBegin");
        this.interactionEnd = createEvent(this, "interactionEnd");
        this.viewRendered = createEvent(this, "viewRendered");
        /**
         * A mode that specifies how the markup component should behave. When
         * unset, the component will not respond to interactions with the handles.
         * When `edit`, the markup anchors are interactive and the user is able
         * to reposition them. When `create`, anytime the user clicks on the canvas,
         * a new markup will be performed.
         */
        this.mode = '';
        /**
         * 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.interactionHandler = new CircleMarkupInteractionHandler(this.hostEl, this.interactionBegin, this.interactionEnd, {
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
        this.handleWindowPointerDown = (event) => {
            if (isValidStartEvent(event)) {
                this.interactionHandler.startInteraction(event);
            }
        };
        this.handleTouchStart = (event) => {
            event.preventDefault();
        };
    }
    /**
     * @ignore
     */
    componentWillLoad() {
        this.updateViewport();
        this.handleViewerChanged(this.viewer);
        this.handleScaleChange();
        this.handleScalingConfigurationChange();
        this.updateBoundsFromProps();
    }
    componentDidLoad() {
        this.updateBoundsFromProps();
        const resize = new ResizeObserver(() => this.updateViewport());
        resize.observe(this.hostEl);
        if (this.mode === 'create') {
            window.addEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    componentDidRender() {
        if (this.mode === '') {
            this.viewRendered.emit();
        }
    }
    disconnectedCallback() {
        this.dispose();
    }
    async dispose() {
        var _a;
        (_a = this.registeredHandler) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredHandler = undefined;
        window.removeEventListener('pointerdown', this.handleWindowPointerDown);
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer) {
        var _a;
        (_a = this.registeredHandler) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredHandler = undefined;
        if (newViewer != null) {
            this.registeredHandler = await newViewer.registerBasicInteractionHandler(this.interactionHandler);
        }
    }
    handleBoundsJsonChange() {
        this.updateBoundsFromProps();
    }
    handleModeChange() {
        if (this.mode !== 'create') {
            window.removeEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    handleScalingConfigurationChange() {
        this.interactionHandler.updateScalingOptions({
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
    }
    handleScaleChange() {
        writeDOM(() => {
            this.hostEl.style.setProperty('--viewer-markup-circle-scale', this.scale.toString());
        });
    }
    updateViewport() {
        const rect = getMarkupBoundingClientRect(this.hostEl);
        this.elementBounds = rect;
    }
    updateBoundsFromProps() {
        var _a;
        this.bounds = (_a = this.bounds) !== null && _a !== void 0 ? _a : parseBounds(this.boundsJson);
    }
    render() {
        var _a, _b, _c, _d;
        if (this.bounds != null && this.elementBounds != null) {
            const relativeBounds = translateRectToScreen(this.bounds, this.elementBounds, this.originatingViewport, this.centeringBehavior, this.scale);
            const center = rectangle.center(relativeBounds);
            const offsetX = ((_b = (_a = this.offset) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0) / getWindowDevicePixelRatio();
            const offsetY = ((_d = (_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0) / getWindowDevicePixelRatio();
            return (h(Host, null, h("svg", { class: "svg", onTouchStart: this.handleTouchStart }, h("defs", null, h(SvgShadow, { id: "circle-shadow", scale: this.scale })), h("g", { transform: `translate(${offsetX} ${offsetY})`, filter: "url(#circle-shadow)" }, h("ellipse", { class: "ellipse", cx: center.x, cy: center.y, rx: relativeBounds.width / 2, ry: relativeBounds.height / 2, stroke: '#000ff0', "stroke-width": 4, fill: 'none' }))), this.mode === 'edit' && (h(BoundingBox2d, { bounds: relativeBounds, offset: { x: offsetX, y: offsetY }, onTopLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-left', e), onTopRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-right', e), onTopAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top', e), onBottomLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-left', e), onBottomRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-right', e), onBottomAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom', e), onLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('left', e), onRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('right', e), onCenterAnchorPointerDown: (e) => this.interactionHandler.editAnchor('center', e) })), this.mode === 'create' && (h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart }))));
        }
        else {
            return (h(Host, null, h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart })));
        }
    }
    get hostEl() { return getElement(this); }
    static get watchers() { return {
        "viewer": [{
                "handleViewerChanged": 0
            }],
        "bounds": [{
                "handleBoundsJsonChange": 0
            }],
        "mode": [{
                "handleModeChange": 0
            }],
        "offset": [{
                "handleScalingConfigurationChange": 0
            }],
        "originatingViewport": [{
                "handleScalingConfigurationChange": 0
            }],
        "centeringBehavior": [{
                "handleScalingConfigurationChange": 0
            }],
        "scale": [{
                "handleScalingConfigurationChange": 0
            }, {
                "handleScaleChange": 0
            }]
    }; }
};
ViewerMarkupCircle.style = viewerMarkupCircleCss();

class FreeformMarkupInteractionHandler extends MarkupInteractionHandler {
    constructor(markupEl, interactionBegin, interactionEnd, scalingOptions) {
        super(scalingOptions);
        this.markupEl = markupEl;
        this.interactionBegin = interactionBegin;
        this.interactionEnd = interactionEnd;
        this.anchor = 'bottom-right';
        this.handleResizeInteractionMove = (event) => {
            if (this.resizeStartPosition != null &&
                this.elementBounds != null &&
                this.resizeBounds != null &&
                this.resizePoints != null) {
                const position = translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
                const updatedBounds = transformRectangle(this.resizeBounds, this.resizeStartPosition, position, this.anchor, event.shiftKey);
                this.markupEl.points = translatePointsToBounds(this.resizePoints, this.resizeBounds, updatedBounds);
                this.markupEl.bounds = updatedBounds;
            }
        };
        this.handleResizeInteractionEnd = (event) => {
            window.removeEventListener('pointermove', this.handleResizeInteractionMove);
            window.removeEventListener('pointerup', this.handleResizeInteractionEnd);
            this.resizeBounds = undefined;
            const newlyCreatedMarkup = this.markupEl.mode !== 'edit';
            this.interactionEnd.emit({ markup: this.markupEl, newlyCreatedMarkup });
        };
    }
    editAnchor(anchor, event) {
        if (this.markupEl.mode === 'edit' && this.elementBounds != null) {
            this.resizeBounds = this.markupEl.bounds;
            this.resizePoints = this.markupEl.points;
            this.anchor = anchor;
            this.resizeStartPosition = translatePointToRelative(getMouseClientPosition(event, this.elementBounds), this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            window.addEventListener('pointermove', this.handleResizeInteractionMove);
            window.addEventListener('pointerup', this.handleResizeInteractionEnd);
        }
    }
    startInteraction(event) {
        this.handleInteractionAttempt(event);
    }
    computeBoundingRect() {
        return getMarkupBoundingClientRect(this.markupEl);
    }
    handleInteractionAttempt(event) {
        var _a;
        if (this.markupEl.mode !== '' &&
            this.pointerId == null &&
            this.elementBounds != null) {
            this.pointerId = event.pointerId;
            const screenPosition = getMouseClientPosition(event, this.elementBounds);
            const position = translatePointToRelative(screenPosition, this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            this.updateMinAndMax(position);
            this.markupEl.points = (_a = this.markupEl.points) !== null && _a !== void 0 ? _a : [position];
            this.interactionBegin.emit();
            this.acceptInteraction();
        }
    }
    handleInteractionMove(event) {
        if (this.pointerId === event.pointerId &&
            this.markupEl.points != null &&
            this.elementBounds != null) {
            const screenPosition = getMouseClientPosition(event, this.elementBounds);
            const position = translatePointToRelative(screenPosition, this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
            this.updateMinAndMax(position);
            this.markupEl.points = [...this.markupEl.points, position];
        }
    }
    handleInteractionEnd(event) {
        if (this.pointerId === event.pointerId) {
            if (this.markupEl.mode !== '' &&
                this.markupEl.points != null &&
                this.markupEl.points.length > 2 &&
                this.elementBounds != null) {
                const screenPosition = getMouseClientPosition(event, this.elementBounds);
                const position = translatePointToRelative(screenPosition, this.elementBounds, this.scalingOptions.originatingViewport, this.scalingOptions.centeringBehavior, this.scalingOptions.scale, this.scalingOptions.offset);
                this.updateMinAndMax(position);
                this.markupEl.points = [...this.markupEl.points, position];
                const newlyCreatedMarkup = this.markupEl.mode !== 'edit';
                this.interactionEnd.emit({ markup: this.markupEl, newlyCreatedMarkup });
            }
            else {
                this.markupEl.points = undefined;
            }
            this.min = undefined;
            this.max = undefined;
            this.pointerId = undefined;
        }
    }
    updateMinAndMax(position) {
        this.min =
            this.min != null
                ? point.create(Math.min(this.min.x, position.x), Math.min(this.min.y, position.y))
                : position;
        this.max =
            this.max != null
                ? point.create(Math.max(this.max.x, position.x), Math.max(this.max.y, position.y))
                : position;
        this.markupEl.bounds = rectangle.create(this.min.x, this.min.y, this.max.x - this.min.x, this.max.y - this.min.y);
    }
}

const viewerMarkupFreeformCss = () => `:host{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;--viewer-markup-freeform-stroke-color:var(--red-800);--viewer-markup-freeform-stroke-width:4px;--viewer-markup-freeform-line-join:round;--viewer-markup-freeform-line-cap:round;--viewer-markup-freeform-bounds-outline-border-color:var(--blue-400);--viewer-markup-freeform-bounds-outline-border-width:1px;--viewer-markup-freeform-bounds-edge-anchor-border-color:var(--blue-400);--viewer-markup-freeform-bounds-edge-anchor-border-width:1px;--viewer-markup-freeform-bounds-edge-anchor-background-color:white;--viewer-markup-freeform-bounds-center-anchor-border-color:white;--viewer-markup-freeform-bounds-center-anchor-border-width:1px;--viewer-markup-freeform-bounds-center-anchor-background-color:var(     --blue-400   );--viewer-markup-freeform-bounds-anchor-width:9px;--viewer-markup-freeform-bounds-anchor-height:9px;--viewer-markup-freeform-scale:1}.svg{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0}.path{pointer-events:auto;cursor:default;stroke:var(--viewer-markup-freeform-stroke-color);stroke-width:calc(     var(--viewer-markup-freeform-stroke-width) *       var(--viewer-markup-freeform-scale)   );stroke-linejoin:var(--viewer-markup-freeform-line-join);stroke-linecap:var(--viewer-markup-freeform-line-cap)}.create-overlay{pointer-events:auto;position:absolute;left:0;top:0;width:100%;height:100%;cursor:crosshair}.bounds-container{pointer-events:none;position:absolute;width:100%;height:100%;top:0;left:0;overflow:hidden}.bounds-outline{position:absolute;border-width:var(--viewer-markup-freeform-bounds-outline-border-width);border-color:var(--viewer-markup-freeform-bounds-outline-border-color);border-style:solid;box-shadow:0 0 3px rgba(0, 0, 0, 0.3)}.bounds-anchor-position{position:absolute;transform:translate(-50%, -50%)}.bounds-anchor{pointer-events:auto;cursor:default;user-select:none}.bounds-default-anchor{width:var(--viewer-markup-freeform-bounds-anchor-width);height:var(--viewer-markup-freeform-bounds-anchor-height);box-sizing:border-box;box-shadow:0 0 2px rgba(0, 0, 0, 0.3)}.bounds-center-anchor{border-radius:100%;border-width:var(--viewer-markup-freeform-bounds-center-anchor-border-width);border-color:var(--viewer-markup-freeform-bounds-center-anchor-border-color);border-style:solid;background-color:var(     --viewer-markup-freeform-bounds-center-anchor-background-color   )}.bounds-edge-anchor{border-width:var(--viewer-markup-freeform-bounds-edge-anchor-border-width);border-color:var(--viewer-markup-freeform-bounds-edge-anchor-border-color);border-style:solid;background-color:var(     --viewer-markup-freeform-bounds-edge-anchor-background-color   )}`;

const ViewerMarkupFreeform = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.interactionBegin = createEvent(this, "interactionBegin");
        this.interactionEnd = createEvent(this, "interactionEnd");
        this.viewRendered = createEvent(this, "viewRendered");
        /**
         * A mode that specifies how the markup component should behave. When
         * unset, the component will not respond to interactions with the handles.
         * When `edit`, the markup anchors are interactive and the user is able
         * to reposition them. When `create`, anytime the user clicks on the canvas,
         * a new markup will be performed.
         */
        this.mode = '';
        /**
         * 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.screenPoints = [];
        this.interactionHandler = new FreeformMarkupInteractionHandler(this.hostEl, this.interactionBegin, this.interactionEnd, {
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
        this.handleWindowPointerDown = (event) => {
            if (isValidStartEvent(event)) {
                this.interactionHandler.startInteraction(event);
            }
        };
        this.handleTouchStart = (event) => {
            event.preventDefault();
        };
    }
    /**
     * @ignore
     */
    componentWillLoad() {
        this.updateViewport();
        this.handleViewerChanged(this.viewer);
        this.handleScaleChange();
        this.handleScalingConfigurationChange();
        this.updatePointsFromProps();
    }
    componentDidLoad() {
        const resize = new ResizeObserver(() => this.updateViewport());
        resize.observe(this.hostEl);
        if (this.mode === 'create') {
            window.addEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    componentDidRender() {
        if (this.mode === '') {
            this.viewRendered.emit();
        }
    }
    disconnectedCallback() {
        this.dispose();
    }
    async dispose() {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        window.removeEventListener('pointerdown', this.handleWindowPointerDown);
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer) {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        if (newViewer != null) {
            this.registeredInteraction =
                await newViewer.registerBasicInteractionHandler(this.interactionHandler);
        }
    }
    recomputePointsFromProps() {
        this.updatePointsFromProps();
    }
    handleScalingConfigurationChange() {
        this.interactionHandler.updateScalingOptions({
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
    }
    handleScaleChange() {
        writeDOM(() => {
            this.hostEl.style.setProperty('--viewer-markup-freeform-scale', this.scale.toString());
        });
    }
    handleModeChange() {
        if (this.mode !== 'create') {
            window.removeEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    updateViewport() {
        var _a;
        const rect = getMarkupBoundingClientRect(this.hostEl);
        this.elementBounds = rect;
        this.screenPoints = (_a = this.convertPointsToScreen()) !== null && _a !== void 0 ? _a : this.screenPoints;
    }
    updatePointsFromProps() {
        var _a, _b, _c;
        this.points = (_a = this.points) !== null && _a !== void 0 ? _a : parsePoints(this.pointsJson);
        this.screenPoints = (_b = this.convertPointsToScreen()) !== null && _b !== void 0 ? _b : [];
        this.bounds = (_c = this.bounds) !== null && _c !== void 0 ? _c : parseBounds(this.boundsJson);
    }
    render() {
        var _a, _b, _c, _d;
        if (this.screenPoints.length > 0 && this.elementBounds != null) {
            const offsetX = ((_b = (_a = this.offset) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0) / getWindowDevicePixelRatio();
            const offsetY = ((_d = (_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0) / getWindowDevicePixelRatio();
            return (h(Host, null, h("svg", { class: "svg", onTouchStart: this.handleTouchStart }, h("defs", null, h(SvgShadow, { id: "freeform-markup-shadow", scale: this.scale })), h("g", { transform: `translate(${offsetX} ${offsetY})`, filter: "url(#freeform-markup-shadow)" }, h("path", { class: "path", d: this.screenPoints.reduce((d, pt) => `${d}L${pt.x},${pt.y}`, `M${this.screenPoints[0].x},${this.screenPoints[0].y}`), fill: "none" }))), this.mode === 'edit' && this.bounds != null && (h(BoundingBox2d, { bounds: translateRectToScreen(this.bounds, this.elementBounds, this.originatingViewport, this.centeringBehavior, this.scale), offset: { x: offsetX, y: offsetY }, onTopLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-left', e), onTopRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-right', e), onTopAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top', e), onBottomLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-left', e), onBottomRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-right', e), onBottomAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom', e), onLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('left', e), onRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('right', e), onCenterAnchorPointerDown: (e) => this.interactionHandler.editAnchor('center', e) })), this.mode === 'create' && (h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart }))));
        }
        else {
            return (h(Host, null, h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart })));
        }
    }
    convertPointsToScreen() {
        var _a;
        const elementBounds = this.elementBounds;
        if (elementBounds != null) {
            return (_a = this.points) === null || _a === void 0 ? void 0 : _a.map((pt) => translatePointToScreen(pt, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale));
        }
    }
    get hostEl() { return getElement(this); }
    static get watchers() { return {
        "viewer": [{
                "handleViewerChanged": 0
            }],
        "originatingViewport": [{
                "recomputePointsFromProps": 0
            }, {
                "handleScalingConfigurationChange": 0
            }],
        "offset": [{
                "recomputePointsFromProps": 0
            }, {
                "handleScalingConfigurationChange": 0
            }],
        "scale": [{
                "recomputePointsFromProps": 0
            }, {
                "handleScalingConfigurationChange": 0
            }, {
                "handleScaleChange": 0
            }],
        "bounds": [{
                "recomputePointsFromProps": 0
            }],
        "points": [{
                "recomputePointsFromProps": 0
            }],
        "centeringBehavior": [{
                "handleScalingConfigurationChange": 0
            }],
        "mode": [{
                "handleModeChange": 0
            }]
    }; }
};
ViewerMarkupFreeform.style = viewerMarkupFreeformCss();

export { ViewerMarkupArrow as vertex_viewer_markup_arrow, ViewerMarkupCircle as vertex_viewer_markup_circle, ViewerMarkupFreeform as vertex_viewer_markup_freeform };
//# sourceMappingURL=vertex-viewer-markup-arrow.vertex-viewer-markup-circle.vertex-viewer-markup-freeform.entry.js.map

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