"use strict";

var __rest = this && this.__rest || function(s, e) {
    var t = {};
    for (var p in s) Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0 && (t[p] = s[p]);
    if (null != s && "function" == typeof Object.getOwnPropertySymbols) {
        var i = 0;
        for (p = Object.getOwnPropertySymbols(s); i < p.length; i++) e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]) && (t[p[i]] = s[p[i]]);
    }
    return t;
};

Object.defineProperty(exports, "__esModule", {
    value: !0
}), exports.BaseCrossHair = void 0;

const vrender_components_1 = require("@visactor/vrender-components"), vutils_1 = require("@visactor/vutils"), common_1 = require("../../typings/spec/common"), base_component_1 = require("../base/base-component"), math_1 = require("../../util/math"), event_1 = require("../../constant/event"), layout_1 = require("../../constant/layout"), config_1 = require("./config"), common_2 = require("./utils/common"), vscale_1 = require("@visactor/vscale"), ORIENT_MAP = {
    x: [ "top", "bottom" ],
    y: [ "left", "right" ],
    category: [ "angle" ],
    value: [ "radius" ]
};

class BaseCrossHair extends base_component_1.BaseComponent {
    get enableRemain() {
        return "none" === this.triggerOff;
    }
    constructor(spec, options) {
        super(spec, options), this.specKey = "crosshair", this.layoutType = "none", this.gridZIndex = layout_1.LayoutZIndex.CrossHair_Grid, 
        this.labelZIndex = layout_1.LayoutZIndex.CrossHair, this.trigger = "hover", this._handleIn = params => {
            if (!this._option) return;
            const {x: x, y: y} = this.calculateTriggerPoint(params);
            this.showDefault = !1, this._layoutCrosshair(x, y);
            const components = this._getNeedClearVRenderComponents();
            this._hasActive = components.some((comp => comp && !1 !== comp.attribute.visible));
        }, this._handleClickInEvent = params => {
            if (!this._hasActive || !this._spec.lockAfterClick || this._clickLock) return this._clickLock ? (this._clickLock = !1, 
            void this._handleOutEvent()) : void (this._onlyLockClick || (this._handleIn(params), 
            (0, vutils_1.isNumber)(this.triggerOff) && (this._timer && clearTimeout(this._timer), 
            this._timer = setTimeout((() => {
                this._handleOutEvent();
            }), this.triggerOff))));
            this._clickLock = !0;
        }, this._handleHoverInEvent = (0, vutils_1.throttle)((params => {
            this._clickLock || this._handleIn(params);
        }), 10), this._handleOutEvent = () => {
            this.enableRemain || this._clickLock || !this._hasActive || (this.clearOutEvent(), 
            this.hide());
        }, this._handleTooltipShow = params => {
            const tooltipData = params.tooltipData;
            if (params.isEmptyTooltip || !tooltipData || !tooltipData.length) return void this._handleTooltipHideOrRelease();
            if ((0, vutils_1.isObject)(this._spec.followTooltip) && !1 === this._spec.followTooltip[params.activeType]) return void this._handleTooltipHideOrRelease();
            const {x: x, y: y} = this.calculateTriggerPoint(params);
            this.showDefault = !1, this._layoutCrosshair(x, y, tooltipData, params.activeType);
            const components = this._getNeedClearVRenderComponents();
            this._hasActive = components.some((comp => comp && !1 !== comp.attribute.visible));
        }, this._handleTooltipHideOrRelease = () => {
            this.clearOutEvent(), this.hide();
        }, this.enable = !0, this.showDefault = !0;
    }
    _setAllAxisValues(axisMap, point, field) {
        let discrete = !1;
        if (axisMap.forEach((item => {
            (0, vscale_1.isDiscrete)(item.axis.getScale().type) && (discrete ? this.enable = !1 : discrete = !0);
        })), !this.enable) return !1;
        const {currentValue: currentValue} = this._stateByField[field];
        return axisMap.forEach(((item, id) => {
            const axis = item.axis;
            currentValue.set(id, {
                datum: this._getDatumAtPoint(axis, point),
                axis: axis
            });
        })), !0;
    }
    clearAxisValue() {
        Object.keys(this._stateByField).forEach((field => {
            this._stateByField[field].currentValue.clear();
        }));
    }
    hideCrosshair() {
        this.clearAxisValue(), this.hide();
    }
    showCrosshair(dimInfo) {
        dimInfo && dimInfo.length && (this.showDefault = !1, this.clearAxisValue(), dimInfo.forEach((d => {
            const {axis: axis, value: value} = d;
            this.setAxisValue(value, axis);
        })), this.layoutByValue(!1));
    }
    _getLimitBounds() {
        var _a, _b;
        if (!this._limitBounds) {
            const {width: width, height: height} = null !== (_b = null === (_a = this._option.globalInstance.getChart()) || void 0 === _a ? void 0 : _a.getViewRect()) && void 0 !== _b ? _b : {
                width: 0,
                height: 0
            };
            this._limitBounds = {
                x1: 0,
                y1: 0,
                x2: width,
                y2: height
            };
        }
        return this._limitBounds;
    }
    _showDefaultCrosshairBySpec() {
        Object.keys(this._stateByField).forEach((field => {
            const fieldSpec = this._spec[field];
            if (fieldSpec && fieldSpec.visible && fieldSpec.defaultSelect) {
                const {axisIndex: axisIndex = 0, datum: datum} = fieldSpec.defaultSelect, axis = this._option.getComponentsByKey("axes").find((c => c.getSpecIndex() === axisIndex));
                axis && (this._stateByField[field].currentValue.clear(), this._stateByField[field].currentValue.set(axisIndex, {
                    axis: axis,
                    datum: datum
                }));
            }
        }));
    }
    _updateVisibleCrosshair() {
        let hasVisible = !1;
        Object.keys(this._stateByField).forEach((field => {
            const fieldSpec = this._spec[field];
            fieldSpec && fieldSpec.visible && this._stateByField[field].currentValue.size ? hasVisible = !0 : this._hideByField(field);
        })), hasVisible && this.layoutByValue(!1);
    }
    _showDefaultCrosshair() {
        this.showDefault ? (this._showDefaultCrosshairBySpec(), this.layoutByValue(!1)) : this._updateVisibleCrosshair();
    }
    setAttrFromSpec() {
        super.setAttrFromSpec(), this._parseCrosshairSpec();
    }
    created() {
        super.created(), this._initEvent();
    }
    _compareSpec(spec, prevSpec) {
        const result = super._compareSpec(spec, prevSpec);
        return result.reMake || (0, vutils_1.isEqual)(prevSpec, spec) || (result.reRender = !0, 
        result.reMake = !0), result;
    }
    _initEvent() {
        if (!this._option.disableTriggerEvent) if (this._spec.followTooltip) this._registerTooltipEvent(); else {
            const triggerConfig = this._getTriggerEvent();
            triggerConfig && triggerConfig.forEach((cfg => {
                this._registerEvent(cfg.in, !1, cfg.click), cfg.out && this._registerEvent(cfg.out, !0);
            }));
        }
    }
    _registerEvent(eventName, isOut, click) {
        const handler = isOut ? this._handleOutEvent : click ? this._handleClickInEvent : this._handleHoverInEvent, cfg = isOut ? {
            level: event_1.Event_Bubble_Level.chart
        } : {
            source: event_1.Event_Source_Type.chart
        };
        (0, vutils_1.isArray)(eventName) ? eventName.forEach((evt => {
            this.event.on(evt, cfg, handler);
        })) : this.event.on(eventName, cfg, handler);
    }
    _eventOff(eventName, isOut, click) {
        const handler = isOut ? this._handleOutEvent : click ? this._handleClickInEvent : this._handleHoverInEvent;
        (0, vutils_1.isArray)(eventName) ? eventName.forEach((evt => {
            this.event.off(evt, handler);
        })) : this.event.off(eventName, handler);
    }
    onBeforeRender() {
        this._limitBounds = null, this._showDefaultCrosshair();
    }
    calculateTriggerPoint(params) {
        const {event: event} = params, layer = this._option.getCompiler().getStage().getLayer(void 0), point = {
            x: event.viewX,
            y: event.viewY
        };
        return layer.globalTransMatrix.transformPoint({
            x: event.viewX,
            y: event.viewY
        }, point), {
            x: point.x - this.getLayoutStartPoint().x,
            y: point.y - this.getLayoutStartPoint().y
        };
    }
    _getTriggerEvent() {
        const {mode: mode = common_1.RenderModeEnum["desktop-browser"]} = this._option, triggerConfig = (0, 
        config_1.getDefaultCrosshairTriggerEventByMode)(mode);
        if (triggerConfig) {
            const trigger = (0, vutils_1.array)(this.trigger || "hover"), outTrigger = inTrigger => "click" === inTrigger ? "none" === this.triggerOff ? null : triggerConfig.clickOut : triggerConfig.hoverOut;
            this._spec.lockAfterClick && !trigger.includes("click") ? (trigger.push("click"), 
            this._onlyLockClick = !0) : this._onlyLockClick = !1;
            const res = [];
            return trigger.forEach((item => {
                res.push({
                    click: "click" === item,
                    in: triggerConfig[item],
                    out: outTrigger(item)
                });
            })), res;
        }
        return null;
    }
    _registerTooltipEvent() {
        this.event.on(event_1.ChartEvent.tooltipHide, {
            source: event_1.Event_Source_Type.chart
        }, this._handleTooltipHideOrRelease), this.event.on(event_1.ChartEvent.tooltipShow, {
            source: event_1.Event_Source_Type.chart
        }, this._handleTooltipShow), this.event.on(event_1.ChartEvent.tooltipRelease, {
            source: event_1.Event_Source_Type.chart
        }, this._handleTooltipHideOrRelease);
    }
    _getAxisInfoByField(field) {
        var _a, _b;
        const axesComponents = null === (_b = (_a = this._option).getComponentsByKey) || void 0 === _b ? void 0 : _b.call(_a, "axes");
        if (!(null == axesComponents ? void 0 : axesComponents.length)) return null;
        let bindingAxesIndex = (0, vutils_1.get)(this._spec, `${field}Field.bindingAxesIndex`);
        if (bindingAxesIndex || (bindingAxesIndex = [], axesComponents.forEach(((item, index) => {
            ORIENT_MAP[field].includes(item.getOrient()) && bindingAxesIndex.push(index);
        }))), !bindingAxesIndex.length) return null;
        const map = new Map;
        let x1 = 1 / 0, y1 = 1 / 0, x2 = -1 / 0, y2 = -1 / 0;
        const {x: sx, y: sy} = this.getLayoutStartPoint();
        return bindingAxesIndex.forEach((idx => {
            x1 = 1 / 0, y1 = 1 / 0, x2 = -1 / 0, y2 = -1 / 0;
            const axis = axesComponents.find((axis => axis.getSpecIndex() === idx));
            if (!axis) return;
            axis.getRegions().forEach((r => {
                const {x: regionStartX, y: regionStartY} = r.getLayoutStartPoint();
                x1 = Math.min(x1, regionStartX - sx), y1 = Math.min(y1, regionStartY - sy), x2 = Math.max(x2, regionStartX + r.getLayoutRect().width - sx), 
                y2 = Math.max(y2, regionStartY + r.getLayoutRect().height - sy);
            })), map.set(idx, {
                x1: x1,
                y1: y1,
                x2: x2,
                y2: y2,
                axis: axis
            });
        })), map;
    }
    changeRegions(regions) {}
    onLayoutEnd(ctx) {
        const region = this._regions[0];
        this.setLayoutRect(region.getLayoutRect()), this.setLayoutStartPosition(region.getLayoutStartPoint()), 
        super.onLayoutEnd(ctx);
    }
    onRender(ctx) {}
    _releaseEvent() {
        this.clearOutEvent();
        const triggerConfig = this._getTriggerEvent();
        triggerConfig && triggerConfig.forEach((cfg => {
            this._eventOff(cfg.in, !1, cfg.click), cfg.out && this._eventOff(cfg.out, !0);
        }));
    }
    _parseFieldInfo() {
        Object.keys(this._stateByField).forEach((field => {
            const fieldSpec = this._spec[field], {crosshairComp: crosshairComp} = this._stateByField[field];
            if (fieldSpec && fieldSpec.visible) {
                if (this._stateByField[field].attributes = this._parseField(fieldSpec, field), crosshairComp) {
                    const {style: style, type: type} = this._stateByField[field].attributes, styleKey = "rect" === type ? "rectStyle" : "lineStyle";
                    crosshairComp.setAttributes({
                        [styleKey]: style
                    });
                }
            } else crosshairComp && crosshairComp.parent && crosshairComp.parent.removeChild(crosshairComp);
        }));
    }
    _parseCrosshairSpec() {
        this._parseFieldInfo();
        const {trigger: trigger, triggerOff: triggerOff, labelZIndex: labelZIndex, gridZIndex: gridZIndex} = this._spec;
        trigger && (this.trigger = trigger), ("none" === triggerOff || (0, vutils_1.isNumber)(triggerOff) && triggerOff > 0) && (this.triggerOff = triggerOff), 
        void 0 !== labelZIndex && (this.labelZIndex = labelZIndex), void 0 !== gridZIndex && (this.gridZIndex = gridZIndex);
    }
    _parseField(field, fieldName) {
        var _a, _b, _c;
        const hair = {}, {line: line = {}, label: label = {}, visible: visible} = field;
        if (hair.visible = visible, hair.type = line.type || "line", !1 === line.visible) hair.style = {
            visible: !1
        }; else {
            const style = line.style || {}, {stroke: stroke, fill: fill, lineWidth: lineWidth} = style, _d = style, {strokeOpacity: strokeOpacity, fillOpacity: fillOpacity, opacity: opacity} = _d, restStyle = __rest(_d, [ "strokeOpacity", "fillOpacity", "opacity" ]), isLineType = "line" === hair.type;
            let finalOpacity = isLineType ? strokeOpacity : fillOpacity;
            if ((0, vutils_1.isNumber)(opacity) && (finalOpacity = (null != finalOpacity ? finalOpacity : 1) * opacity), 
            hair.style = Object.assign({
                opacity: finalOpacity,
                pickable: !1,
                visible: !0
            }, restStyle), isLineType) hair.style.stroke = stroke || fill, hair.style.lineWidth = (0, 
            vutils_1.get)(line, "width", lineWidth || 2); else {
                hair.style.fill = fill || stroke, (null === (_b = null === (_a = null == field ? void 0 : field.line) || void 0 === _a ? void 0 : _a.style) || void 0 === _b ? void 0 : _b.stroke) && (hair.style.stroke = field.line.style.stroke);
                const rectSize = (0, vutils_1.get)(line, "width");
                if ("string" == typeof rectSize) {
                    const percent = parseInt(rectSize.substring(0, rectSize.length - 1), 10) / 100;
                    hair.style.sizePercent = percent;
                } else "number" != typeof rectSize && "function" != typeof rectSize || (hair.style.size = rectSize);
            }
        }
        if (label.visible) {
            const labelBackground = label.labelBackground || {}, syncAxisLabelAngle = null !== (_c = label.syncAxisLabelAngle) && void 0 !== _c && _c, labelStyle = label.style || {}, _e = labelBackground.style || {}, {fill: rectFill = "rgba(47, 59, 82, 0.9)", stroke: rectStroke, outerBorder: outerBorder} = _e, rectStyle = __rest(_e, [ "fill", "stroke", "outerBorder" ]);
            hair.label = {
                visible: !0,
                formatMethod: label.formatMethod,
                formatter: label.formatter,
                minWidth: labelBackground.minWidth,
                maxWidth: labelBackground.maxWidth,
                padding: labelBackground.padding,
                syncAxisLabelAngle: syncAxisLabelAngle,
                textStyle: Object.assign(Object.assign({
                    fontSize: 14,
                    pickable: !1
                }, labelStyle), {
                    fill: labelStyle.fill || "#fff",
                    stroke: (0, vutils_1.get)(labelStyle, "stroke")
                }),
                panel: ((0, vutils_1.isBoolean)(labelBackground.visible) ? labelBackground.visible : labelBackground) ? Object.assign({
                    visible: !0,
                    pickable: !1,
                    fill: rectFill,
                    stroke: rectStroke,
                    outerBorder: Object.assign({
                        stroke: rectFill,
                        distance: 0,
                        lineWidth: 3
                    }, outerBorder)
                }, rectStyle) : {
                    visible: !1
                },
                zIndex: this.labelZIndex,
                childrenPickable: !1,
                pickable: !1
            };
        } else hair.label = {
            visible: !1
        };
        return hair;
    }
    _filterAxisByPoint(axisMap, relativeX, relativeY) {
        return axisMap && axisMap.forEach((item => {
            const axis = item.axis;
            if ((0, math_1.outOfBounds)(item, relativeX, relativeY) && axisMap.delete(axis.getSpecIndex()), 
            axis.type.startsWith("polarAxis")) {
                const center = axis.getCenter(), innerRadius = axis.getInnerRadius(), outerRadius = axis.getOuterRadius(), distance = vutils_1.PointService.distancePP({
                    x: relativeX,
                    y: relativeY
                }, center);
                (distance > outerRadius || distance < innerRadius) && axisMap.delete(axis.getSpecIndex());
            }
        })), axisMap;
    }
    _updateCrosshairLabel(label, labelAttrs, callback) {
        const container = this.getContainer();
        label ? label.setAttributes(labelAttrs) : (label = new vrender_components_1.Tag(labelAttrs), 
        null == container || container.add(label), callback(label)), (0, common_2.limitTagInBounds)(label, this._getLimitBounds());
    }
    clearOutEvent() {
        this._timer && (clearTimeout(this._timer), this._timer = null), this._clickLock && (this._clickLock = null), 
        this._hasActive && (this._hasActive = null);
    }
    _hideByField(field) {
        const {crosshairComp: crosshairComp, labelsComp: labelsComp} = this._stateByField[field];
        crosshairComp && crosshairComp.hideAll(), labelsComp && Object.keys(labelsComp).forEach((key => {
            labelsComp[key] && labelsComp[key].hideAll();
        }));
    }
    hide() {
        Object.keys(this._stateByField).forEach((field => {
            this._hideByField(field);
        }));
    }
    _getNeedClearVRenderComponents() {
        return Object.keys(this._stateByField).reduce(((res, field) => {
            const {crosshairComp: crosshairComp, labelsComp: labelsComp} = this._stateByField[field];
            return crosshairComp && res.push(crosshairComp), labelsComp && Object.keys(labelsComp).forEach((key => {
                labelsComp[key] && res.push(labelsComp[key]);
            })), res;
        }), []);
    }
}

exports.BaseCrossHair = BaseCrossHair, BaseCrossHair.specKey = "crosshair";
//# sourceMappingURL=base.js.map
