Source: control2/hotspot/Rectangle.js

(function() {
    /**
     * @typedef {Help4.control2.hotspot.Hotspot.Params} Help4.control2.hotspot.Rectangle.Params
     * @property {Help4.control2.AreaXYWH} [rect = {x: 0, y: 0, w: 0, h: 0}] - the assigned elements rect
     * @property {Help4.control2.SizeWidthHeight} [delta = {width: 0, height: 0}] - in case the hotspot is moved
     */

    /**
     * Creates a rectangle hotspot.
     * @augments Help4.control2.hotspot.Hotspot
     * @property {Help4.control2.AreaXYWH} rect - the assigned elements rect
     * @property {Help4.control2.SizeWidthHeight} delta - in case the hotspot is moved
     */
    Help4.control2.hotspot.Rectangle = class extends Help4.control2.hotspot.Hotspot {
        /**
         * @override
         * @param {Help4.control2.hotspot.Rectangle.Params} [params]
         */
        constructor(params) {
            const T = Help4.jscore.ControlBase.TYPES;
            super(params, {
                params: {
                    rect:  {type: T.xywh},
                    delta: {type: T.widthHeight}
                },
                statics: {
                    _svg:  {destroy: false},
                    _rect: {destroy: false}
                },
                config: {
                    css: 'rectangle'
                }
            });
        }

        /**
         * @override
         * @param {Help4.control2.PositionXY} point
         */
        calcMeetingPoint({x, y}) {
            const {x: rx, y: ry, w: rw, h: rh} = this.rect;
            const {width: dw, height: dh} = this.delta;

            const rect = {
                x: rx - dw / 2,
                y: ry - dh / 2,
                w: Math.max(0, rw + dw),
                h: Math.max(0, rh + dh)
            };

            const line = {  // line from tile to the center of hotspot
                x1: rect.x + rect.w / 2,
                y1: rect.y + rect.h / 2,
                x2: x,
                y2: y
            };

            return Help4.getRectIntersect(rect, line, this.borderSize) || {x, y};
        }

        /**
         * @override
         * @param {HTMLElement} dom - control DOM
         */
        _onDomCreated(dom) {
            super._onDomCreated(dom);

            // svg elements need to be created createElementNS
            const svg = this._svg = this._createElement('svg', {id: '-svg', css: 'svg', dom: dom, isNS: true});
            const rect = this._rect = this._createElement('rect', {id: '-rect', css: 'rect', dom: svg, isNS: true});

            // XRAY-3384: rounded corners (border-radius) of SVG makes hotspot border not clickable in IE
            // so no rounded rect at all in IE
            if (!Help4.Browser.IE) {
                rect.setAttribute('rx', '1');
                rect.setAttribute('ry', '1');
            }

            // must be created after SVG to allow overlapping
            const cnt = this._content = this._createElement('div', {css: 'inner'});
            this._createElement('div', {id: '-arrow', css: 'arrow', dom: cnt});

            _apply.call(this);
        }

        /**
         * @override
         * @param {Help4.jscore.ControlBase.PropertyChangeEvent} event - the change event
         */
        _applyPropertyToDom(event) {
            ({rect: 1, delta: 1}[event.name])
                ? _apply.call(this)
                : super._applyPropertyToDom(event);
        }
    }

    /**
     * @memberof Help4.control2.hotspot.Rectangle#
     * @private
     */
    function _apply() {
        const dom = this.getDom();
        const {_svg, _rect} = this;
        if (!dom || !_svg || !_rect) return;

        const {x: rx, y: ry, w: rw, h: rh} = this.rect;
        const {width: dw, height: dh} = this.delta;
        const w = Math.max(0, rw + dw);
        const h = Math.max(0, rh + dh);

        // XRAY-3388: viewbox -0.5 -0.5 is for correct position of rect in SVG
        _svg.setAttribute('viewBox', `-0.5 -0.5 ${w} ${h}`);
        Help4.extendObject(_svg.style, {x: 0, y: 0, width: w + 'px', height: h + 'px'});

        const sw = parseInt(getComputedStyle(_rect).strokeWidth);
        Help4.Element.setAttribute(_rect, {
            x: sw >> 1,
            y: sw >> 1,
            width: Math.max(0, w - sw),
            height: Math.max(0, h - sw)
        });

        Help4.extendObject(dom.style, {
            left: rx - dw / 2 + 'px',
            top: ry - dh / 2 + 'px',
            width: w + 'px',
            height: h + 'px',
            lineHeight: h + 'px'
        });
    }
})();