import { __assign, __extends, __read, __rest, __spreadArray } from "tslib";
import { Controller } from './base';
import { Scrollbar as ScrollbarComponent } from '../../dependents';
import { BBox } from '../../util/bbox';
import { directionToPosition } from '../../util/direction';
import { COMPONENT_TYPE, DIRECTION, LAYER, VIEW_LIFE_CIRCLE } from '../../constant';
import { isObject, clamp, size, throttle, noop, get, valuesOfKey, deepMix } from '@antv/util';
import { isBetween } from '../../util/helper';
var DEFAULT_PADDING = 0;
var DEFAULT_SIZE = 8;
var DEFAULT_CATEGORY_SIZE = 32;
var MIN_THUMB_LENGTH = 20;
var Scrollbar = /** @class */ (function (_super) {
    __extends(Scrollbar, _super);
    function Scrollbar(view) {
        var _this = _super.call(this, view) || this;
        _this.onChangeFn = noop;
        _this.resetMeasure = function () {
            _this.clear();
        };
        _this.onValueChange = function (_a) {
            var ratio = _a.ratio;
            var animate = _this.getValidScrollbarCfg().animate;
            _this.ratio = clamp(ratio, 0, 1);
            var originalAnimate = _this.view.getOptions().animate;
            if (!animate) {
                _this.view.animate(false);
            }
            _this.changeViewData(_this.getScrollRange(), true);
            _this.view.animate(originalAnimate);
        };
        _this.container = _this.view.getLayer(LAYER.FORE).addGroup();
        _this.onChangeFn = throttle(_this.onValueChange, 20, {
            leading: true,
        });
        _this.trackLen = 0;
        _this.thumbLen = 0;
        _this.ratio = 0;
        _this.view.on(VIEW_LIFE_CIRCLE.BEFORE_CHANGE_DATA, _this.resetMeasure);
        _this.view.on(VIEW_LIFE_CIRCLE.BEFORE_CHANGE_SIZE, _this.resetMeasure);
        return _this;
    }
    Object.defineProperty(Scrollbar.prototype, "name", {
        get: function () {
            return 'scrollbar';
        },
        enumerable: false,
        configurable: true
    });
    Scrollbar.prototype.destroy = function () {
        _super.prototype.destroy.call(this);
        this.view.off(VIEW_LIFE_CIRCLE.BEFORE_CHANGE_DATA, this.resetMeasure);
        this.view.off(VIEW_LIFE_CIRCLE.BEFORE_CHANGE_SIZE, this.resetMeasure);
    };
    Scrollbar.prototype.init = function () { };
    /**
     * 渲染
     */
    Scrollbar.prototype.render = function () {
        this.option = this.view.getOptions().scrollbar;
        if (this.option) {
            if (this.scrollbar) {
                // exist, update
                this.scrollbar = this.updateScrollbar();
            }
            else {
                // not exist, create
                this.scrollbar = this.createScrollbar();
                this.scrollbar.component.on('scrollchange', this.onChangeFn);
            }
        }
        else {
            if (this.scrollbar) {
                // exist, destroy
                this.scrollbar.component.destroy();
                this.scrollbar = undefined;
            }
        }
    };
    /**
     * 布局
     */
    Scrollbar.prototype.layout = function () {
        var _this = this;
        if (this.option && !this.trackLen) {
            this.measureScrollbar();
            setTimeout(function () {
                if (!_this.view.destroyed) {
                    _this.changeViewData(_this.getScrollRange(), true);
                }
            });
        }
        if (this.scrollbar) {
            var width = this.view.coordinateBBox.width;
            var padding = this.scrollbar.component.get('padding');
            var bboxObject = this.scrollbar.component.getLayoutBBox();
            var bbox = new BBox(bboxObject.x, bboxObject.y, Math.min(bboxObject.width, width), bboxObject.height).expand(padding);
            var cfg = this.getScrollbarComponentCfg();
            var x = void 0;
            var y = void 0;
            if (cfg.isHorizontal) {
                var _a = __read(directionToPosition(this.view.viewBBox, bbox, DIRECTION.BOTTOM), 2), x1 = _a[0], y1 = _a[1];
                var _b = __read(directionToPosition(this.view.coordinateBBox, bbox, DIRECTION.BOTTOM), 2), x2 = _b[0], y2 = _b[1];
                x = x2;
                y = y1;
            }
            else {
                var _c = __read(directionToPosition(this.view.viewBBox, bbox, DIRECTION.RIGHT), 2), x1 = _c[0], y1 = _c[1];
                var _d = __read(directionToPosition(this.view.viewBBox, bbox, DIRECTION.RIGHT), 2), x2 = _d[0], y2 = _d[1];
                x = x2;
                y = y1;
            }
            x += padding[3];
            y += padding[0];
            // 默认放在 bottom
            if (this.trackLen) {
                this.scrollbar.component.update(__assign(__assign({}, cfg), { x: x, y: y, trackLen: this.trackLen, thumbLen: this.thumbLen, thumbOffset: (this.trackLen - this.thumbLen) * this.ratio }));
            }
            else {
                this.scrollbar.component.update(__assign(__assign({}, cfg), { x: x, y: y }));
            }
            this.view.viewBBox = this.view.viewBBox.cut(bbox, cfg.isHorizontal ? DIRECTION.BOTTOM : DIRECTION.RIGHT);
        }
    };
    /**
     * 更新
     */
    Scrollbar.prototype.update = function () {
        // 逻辑和 render 保持一致
        this.render();
    };
    Scrollbar.prototype.getComponents = function () {
        return this.scrollbar ? [this.scrollbar] : [];
    };
    Scrollbar.prototype.clear = function () {
        if (this.scrollbar) {
            this.scrollbar.component.destroy();
            this.scrollbar = undefined;
        }
        this.trackLen = 0;
        this.thumbLen = 0;
        this.ratio = 0;
        this.cnt = 0;
        this.step = 0;
        this.data = undefined;
        this.xScaleCfg = undefined;
        this.yScalesCfg = [];
    };
    /** 设置滚动条位置  */
    Scrollbar.prototype.setValue = function (ratio) {
        this.onValueChange({ ratio: ratio });
    };
    /** 获得滚动条位置  */
    Scrollbar.prototype.getValue = function () {
        return this.ratio;
    };
    /**
     * 获取 scrollbar 的主题配置
     */
    Scrollbar.prototype.getThemeOptions = function () {
        var theme = this.view.getTheme();
        return get(theme, ['components', 'scrollbar', 'common'], {});
    };
    /**
     * 获取 scrollbar 组件的主题样式
     */
    Scrollbar.prototype.getScrollbarTheme = function (style) {
        var theme = get(this.view.getTheme(), ['components', 'scrollbar']);
        var _a = style || {}, thumbHighlightColor = _a.thumbHighlightColor, restStyles = __rest(_a, ["thumbHighlightColor"]);
        return {
            default: deepMix({}, get(theme, ['default', 'style'], {}), restStyles),
            hover: deepMix({}, get(theme, ['hover', 'style'], {}), { thumbColor: thumbHighlightColor }),
        };
    };
    Scrollbar.prototype.measureScrollbar = function () {
        var xScale = this.view.getXScale();
        var yScales = this.view.getYScales().slice();
        this.data = this.getScrollbarData();
        this.step = this.getStep();
        this.cnt = this.getCnt();
        var _a = this.getScrollbarComponentCfg(), trackLen = _a.trackLen, thumbLen = _a.thumbLen;
        this.trackLen = trackLen;
        this.thumbLen = thumbLen;
        this.xScaleCfg = {
            field: xScale.field,
            values: xScale.values || [],
        };
        this.yScalesCfg = yScales;
    };
    Scrollbar.prototype.getScrollRange = function () {
        var startIdx = Math.floor((this.cnt - this.step) * clamp(this.ratio, 0, 1));
        var endIdx = Math.min(startIdx + this.step - 1, this.cnt - 1);
        return [startIdx, endIdx];
    };
    Scrollbar.prototype.changeViewData = function (_a, render) {
        var _this = this;
        var _b = __read(_a, 2), startIdx = _b[0], endIdx = _b[1];
        var type = this.getValidScrollbarCfg().type;
        var isHorizontal = type !== 'vertical';
        var values = valuesOfKey(this.data, this.xScaleCfg.field);
        // 如果是 xScale 数值类型，则进行排序
        var xScaleValues = this.view.getXScale().isLinear ? values.sort(function (a, b) { return Number(a) - Number(b); }) : values;
        var xValues = isHorizontal ? xScaleValues : xScaleValues.reverse();
        this.yScalesCfg.forEach(function (cfg) {
            _this.view.scale(cfg.field, {
                formatter: cfg.formatter,
                type: cfg.type,
                min: cfg.min,
                max: cfg.max,
                tickMethod: cfg.tickMethod
            });
        });
        this.view.filter(this.xScaleCfg.field, function (val) {
            var idx = xValues.indexOf(val);
            return idx > -1 ? isBetween(idx, startIdx, endIdx) : true;
        });
        this.view.render(true);
    };
    Scrollbar.prototype.createScrollbar = function () {
        var type = this.getValidScrollbarCfg().type;
        var isHorizontal = type !== 'vertical';
        var component = new ScrollbarComponent(__assign(__assign({ container: this.container }, this.getScrollbarComponentCfg()), { x: 0, y: 0 }));
        component.init();
        return {
            component: component,
            layer: LAYER.FORE,
            direction: isHorizontal ? DIRECTION.BOTTOM : DIRECTION.RIGHT,
            type: COMPONENT_TYPE.SCROLLBAR,
        };
    };
    Scrollbar.prototype.updateScrollbar = function () {
        var config = this.getScrollbarComponentCfg();
        var realConfig = this.trackLen
            ? __assign(__assign({}, config), { trackLen: this.trackLen, thumbLen: this.thumbLen, thumbOffset: (this.trackLen - this.thumbLen) * this.ratio }) : __assign({}, config);
        this.scrollbar.component.update(realConfig);
        return this.scrollbar;
    };
    Scrollbar.prototype.getStep = function () {
        if (this.step) {
            return this.step;
        }
        var coordinateBBox = this.view.coordinateBBox;
        var _a = this.getValidScrollbarCfg(), type = _a.type, categorySize = _a.categorySize;
        var isHorizontal = type !== 'vertical';
        return Math.floor((isHorizontal ? coordinateBBox.width : coordinateBBox.height) / categorySize);
    };
    Scrollbar.prototype.getCnt = function () {
        if (this.cnt) {
            return this.cnt;
        }
        var xScale = this.view.getXScale();
        var data = this.getScrollbarData();
        var values = valuesOfKey(data, xScale.field);
        return size(values);
    };
    Scrollbar.prototype.getScrollbarComponentCfg = function () {
        var _a = this.view, coordinateBBox = _a.coordinateBBox, viewBBox = _a.viewBBox;
        var _b = this.getValidScrollbarCfg(), type = _b.type, padding = _b.padding, width = _b.width, height = _b.height, style = _b.style;
        var isHorizontal = type !== 'vertical';
        var _c = __read(padding, 4), paddingTop = _c[0], paddingRight = _c[1], paddingBottom = _c[2], paddingLeft = _c[3];
        var position = isHorizontal
            ? {
                x: coordinateBBox.minX + paddingLeft,
                y: viewBBox.maxY - height - paddingBottom,
            }
            : {
                x: viewBBox.maxX - width - paddingRight,
                y: coordinateBBox.minY + paddingTop,
            };
        var step = this.getStep();
        var cnt = this.getCnt();
        var trackLen = isHorizontal
            ? coordinateBBox.width - paddingLeft - paddingRight
            : coordinateBBox.height - paddingTop - paddingBottom;
        var thumbLen = Math.max(trackLen * clamp(step / cnt, 0, 1), MIN_THUMB_LENGTH);
        return __assign(__assign({}, this.getThemeOptions()), { x: position.x, y: position.y, size: isHorizontal ? height : width, isHorizontal: isHorizontal, trackLen: trackLen, thumbLen: thumbLen, thumbOffset: 0, theme: this.getScrollbarTheme(style) });
    };
    /**
     * 填充一些默认的配置项目
     */
    Scrollbar.prototype.getValidScrollbarCfg = function () {
        var cfg = {
            type: 'horizontal',
            categorySize: DEFAULT_CATEGORY_SIZE,
            width: DEFAULT_SIZE,
            height: DEFAULT_SIZE,
            padding: [0, 0, 0, 0],
            animate: true,
            style: {},
        };
        if (isObject(this.option)) {
            cfg = __assign(__assign({}, cfg), this.option);
        }
        if (!isObject(this.option) || !this.option.padding) {
            cfg.padding =
                cfg.type === 'horizontal' ? [DEFAULT_PADDING, 0, DEFAULT_PADDING, 0] : [0, DEFAULT_PADDING, 0, DEFAULT_PADDING];
        }
        return cfg;
    };
    /**
     * 获取数据
     */
    Scrollbar.prototype.getScrollbarData = function () {
        var coordinate = this.view.getCoordinate();
        var cfg = this.getValidScrollbarCfg();
        var data = this.view.getOptions().data || [];
        // 纵向做了 y 轴镜像之后，数据也需要镜像反转
        if (coordinate.isReflect('y') && cfg.type === 'vertical') {
            data = __spreadArray([], __read(data), false).reverse();
        }
        return data;
    };
    return Scrollbar;
}(Controller));
export default Scrollbar;
//# sourceMappingURL=scrollbar.js.map