import { __assign, __extends } from "tslib";
import { clamp, deepMix, each, get, isArray, isNil, size } from '@antv/util';
import GroupComponent from '../abstract/group-component';
import { Trend } from '../trend/trend';
import { DEFAULT_HANDLER_STYLE, Handler } from './handler';
import { BACKGROUND_STYLE, DEFAULT_HANDLER_WIDTH, FOREGROUND_STYLE, HANDLER_STYLE, SLIDER_CHANGE, TEXT_STYLE, } from './constant';
var Slider = /** @class */ (function (_super) {
    __extends(Slider, _super);
    function Slider() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.onMouseDown = function (target) { return function (e) {
            _this.currentTarget = target;
            // 取出原生事件
            var event = e.originalEvent;
            // 2. 存储当前点击位置
            event.stopPropagation();
            event.preventDefault();
            // 兼容移动端获取数据
            _this.prevX = get(event, 'touches.0.pageX', event.pageX);
            _this.prevY = get(event, 'touches.0.pageY', event.pageY);
            // 3. 开始滑动的时候，绑定 move 和 up 事件
            var containerDOM = _this.getContainerDOM();
            containerDOM.addEventListener('mousemove', _this.onMouseMove);
            containerDOM.addEventListener('mouseup', _this.onMouseUp);
            containerDOM.addEventListener('mouseleave', _this.onMouseUp);
            // 移动端事件
            containerDOM.addEventListener('touchmove', _this.onMouseMove);
            containerDOM.addEventListener('touchend', _this.onMouseUp);
            containerDOM.addEventListener('touchcancel', _this.onMouseUp);
        }; };
        _this.onMouseMove = function (event) {
            var width = _this.cfg.width;
            var originValue = [_this.get('start'), _this.get('end')];
            // 滑动过程中，计算偏移，更新滑块，然后 emit 数据出去
            event.stopPropagation();
            event.preventDefault();
            var x = get(event, 'touches.0.pageX', event.pageX);
            var y = get(event, 'touches.0.pageY', event.pageY);
            // 横向的 slider 只处理 x
            var offsetX = x - _this.prevX;
            var offsetXRange = _this.adjustOffsetRange(offsetX / width);
            // 更新 start end range 范围
            _this.updateStartEnd(offsetXRange);
            // 更新 ui
            _this.updateUI(_this.getElementByLocalId('foreground'), _this.getElementByLocalId('minText'), _this.getElementByLocalId('maxText'));
            _this.prevX = x;
            _this.prevY = y;
            _this.draw();
            // 因为存储的 start、end 可能不一定是按大小存储的，所以排序一下，对外是 end >= start
            _this.emit(SLIDER_CHANGE, [_this.get('start'), _this.get('end')].sort());
            _this.delegateEmit('valuechanged', {
                originValue: originValue,
                value: [_this.get('start'), _this.get('end')],
            });
        };
        _this.onMouseUp = function () {
            // 结束之后，取消绑定的事件
            if (_this.currentTarget) {
                _this.currentTarget = undefined;
            }
            var containerDOM = _this.getContainerDOM();
            if (containerDOM) {
                containerDOM.removeEventListener('mousemove', _this.onMouseMove);
                containerDOM.removeEventListener('mouseup', _this.onMouseUp);
                // 防止滑动到 canvas 外部之后，状态丢失
                containerDOM.removeEventListener('mouseleave', _this.onMouseUp);
                // 移动端事件
                containerDOM.removeEventListener('touchmove', _this.onMouseMove);
                containerDOM.removeEventListener('touchend', _this.onMouseUp);
                containerDOM.removeEventListener('touchcancel', _this.onMouseUp);
            }
        };
        return _this;
    }
    Slider.prototype.setRange = function (min, max) {
        this.set('minLimit', min);
        this.set('maxLimit', max);
        var oldStart = this.get('start');
        var oldEnd = this.get('end');
        var newStart = clamp(oldStart, min, max);
        var newEnd = clamp(oldEnd, min, max);
        if (!this.get('isInit') && (oldStart !== newStart || oldEnd !== newEnd)) {
            this.setValue([newStart, newEnd]);
        }
    };
    Slider.prototype.getRange = function () {
        return {
            min: this.get('minLimit') || 0,
            max: this.get('maxLimit') || 1,
        };
    };
    Slider.prototype.setValue = function (value) {
        var range = this.getRange();
        if (isArray(value) && value.length === 2) {
            var originValue = [this.get('start'), this.get('end')];
            this.update({
                start: clamp(value[0], range.min, range.max),
                end: clamp(value[1], range.min, range.max),
            });
            if (!this.get('updateAutoRender')) {
                this.render();
            }
            this.delegateEmit('valuechanged', {
                originValue: originValue,
                value: value,
            });
        }
    };
    Slider.prototype.getValue = function () {
        return [this.get('start'), this.get('end')];
    };
    Slider.prototype.getDefaultCfg = function () {
        var cfg = _super.prototype.getDefaultCfg.call(this);
        return __assign(__assign({}, cfg), { name: 'slider', x: 0, y: 0, width: 100, height: 16, backgroundStyle: {}, foregroundStyle: {}, handlerStyle: {}, textStyle: {}, defaultCfg: {
                backgroundStyle: BACKGROUND_STYLE,
                foregroundStyle: FOREGROUND_STYLE,
                handlerStyle: HANDLER_STYLE,
                textStyle: TEXT_STYLE,
            } });
    };
    Slider.prototype.update = function (cfg) {
        var start = cfg.start, end = cfg.end;
        var validCfg = __assign({}, cfg);
        if (!isNil(start)) {
            validCfg.start = clamp(start, 0, 1);
        }
        if (!isNil(end)) {
            validCfg.end = clamp(end, 0, 1);
        }
        _super.prototype.update.call(this, validCfg);
        this.minHandler = this.getChildComponentById(this.getElementId('minHandler'));
        this.maxHandler = this.getChildComponentById(this.getElementId('maxHandler'));
        this.trend = this.getChildComponentById(this.getElementId('trend'));
    };
    Slider.prototype.init = function () {
        this.set('start', clamp(this.get('start'), 0, 1));
        this.set('end', clamp(this.get('end'), 0, 1));
        _super.prototype.init.call(this);
    };
    Slider.prototype.render = function () {
        _super.prototype.render.call(this);
        this.updateUI(this.getElementByLocalId('foreground'), this.getElementByLocalId('minText'), this.getElementByLocalId('maxText'));
    };
    Slider.prototype.renderInner = function (group) {
        var _a = this.cfg, start = _a.start, end = _a.end, width = _a.width, height = _a.height, _b = _a.trendCfg, trendCfg = _b === void 0 ? {} : _b, minText = _a.minText, maxText = _a.maxText, _c = _a.backgroundStyle, backgroundStyle = _c === void 0 ? {} : _c, _d = _a.foregroundStyle, foregroundStyle = _d === void 0 ? {} : _d, _e = _a.textStyle, textStyle = _e === void 0 ? {} : _e;
        var handlerStyle = deepMix({}, DEFAULT_HANDLER_STYLE, this.cfg.handlerStyle);
        var min = start * width;
        var max = end * width;
        // 趋势图数据
        if (size(get(trendCfg, 'data'))) {
            this.trend = this.addComponent(group, __assign({ component: Trend, id: this.getElementId('trend'), x: 0, y: 0, width: width,
                height: height }, trendCfg));
        }
        // 1. 背景
        this.addShape(group, {
            id: this.getElementId('background'),
            type: 'rect',
            attrs: __assign({ x: 0, y: 0, width: width,
                height: height }, backgroundStyle),
        });
        // 2. 左右文字
        var minTextShape = this.addShape(group, {
            id: this.getElementId('minText'),
            type: 'text',
            attrs: __assign({ 
                // x: 0,
                y: height / 2, textAlign: 'right', text: minText, silent: false }, textStyle),
        });
        var maxTextShape = this.addShape(group, {
            id: this.getElementId('maxText'),
            type: 'text',
            attrs: __assign({ 
                // x: 0,
                y: height / 2, textAlign: 'left', text: maxText, silent: false }, textStyle),
        });
        // 3. 前景 选中背景框
        var foregroundShape = this.addShape(group, {
            id: this.getElementId('foreground'),
            name: 'foreground',
            type: 'rect',
            attrs: __assign({ 
                // x: 0,
                y: 0, 
                // width: 0,
                height: height }, foregroundStyle),
        });
        // 滑块相关的大小信息
        var handlerWidth = get(handlerStyle, 'width', DEFAULT_HANDLER_WIDTH);
        var handlerHeight = get(handlerStyle, 'height', 24);
        // 4. 左右滑块
        this.minHandler = this.addComponent(group, {
            component: Handler,
            id: this.getElementId('minHandler'),
            name: 'handler-min',
            x: 0,
            y: (height - handlerHeight) / 2,
            width: handlerWidth,
            height: handlerHeight,
            cursor: 'ew-resize',
            style: handlerStyle,
        });
        this.maxHandler = this.addComponent(group, {
            component: Handler,
            id: this.getElementId('maxHandler'),
            name: 'handler-max',
            x: 0,
            y: (height - handlerHeight) / 2,
            width: handlerWidth,
            height: handlerHeight,
            cursor: 'ew-resize',
            style: handlerStyle,
        });
    };
    Slider.prototype.applyOffset = function () {
        this.moveElementTo(this.get('group'), {
            x: this.get('x'),
            y: this.get('y'),
        });
    };
    Slider.prototype.initEvent = function () {
        this.bindEvents();
    };
    Slider.prototype.updateUI = function (foregroundShape, minTextShape, maxTextShape) {
        var _a = this.cfg, start = _a.start, end = _a.end, width = _a.width, minText = _a.minText, maxText = _a.maxText, handlerStyle = _a.handlerStyle, height = _a.height;
        var min = start * width;
        var max = end * width;
        if (this.trend) {
            this.trend.update({
                width: width,
                height: height,
            });
            if (!this.get('updateAutoRender')) {
                this.trend.render();
            }
        }
        // 1. foreground
        foregroundShape.attr('x', min);
        foregroundShape.attr('width', max - min);
        // 滑块相关的大小信息
        var handlerWidth = get(handlerStyle, 'width', DEFAULT_HANDLER_WIDTH);
        // 设置文本
        minTextShape.attr('text', minText);
        maxTextShape.attr('text', maxText);
        var _b = this._dodgeText([min, max], minTextShape, maxTextShape), minAttrs = _b[0], maxAttrs = _b[1];
        // 2. 左侧滑块和文字位置
        if (this.minHandler) {
            this.minHandler.update({
                x: min - handlerWidth / 2,
            });
            if (!this.get('updateAutoRender')) {
                this.minHandler.render();
            }
        }
        each(minAttrs, function (v, k) { return minTextShape.attr(k, v); });
        // 3. 右侧滑块和文字位置
        if (this.maxHandler) {
            this.maxHandler.update({
                x: max - handlerWidth / 2,
            });
            if (!this.get('updateAutoRender')) {
                this.maxHandler.render();
            }
        }
        each(maxAttrs, function (v, k) { return maxTextShape.attr(k, v); });
    };
    Slider.prototype.bindEvents = function () {
        var group = this.get('group');
        group.on('handler-min:mousedown', this.onMouseDown('minHandler'));
        group.on('handler-min:touchstart', this.onMouseDown('minHandler'));
        // 2. 右滑块的滑动
        group.on('handler-max:mousedown', this.onMouseDown('maxHandler'));
        group.on('handler-max:touchstart', this.onMouseDown('maxHandler'));
        // 3. 前景选中区域
        var foreground = group.findById(this.getElementId('foreground'));
        foreground.on('mousedown', this.onMouseDown('foreground'));
        foreground.on('touchstart', this.onMouseDown('foreground'));
    };
    /**
     * 调整 offsetRange，因为一些范围的限制
     * @param offsetRange
     */
    Slider.prototype.adjustOffsetRange = function (offsetRange) {
        var _a = this.cfg, start = _a.start, end = _a.end;
        // 针对不同的滑动组件，处理的方式不同
        switch (this.currentTarget) {
            case 'minHandler': {
                var min = 0 - start;
                var max = 1 - start;
                return Math.min(max, Math.max(min, offsetRange));
            }
            case 'maxHandler': {
                var min = 0 - end;
                var max = 1 - end;
                return Math.min(max, Math.max(min, offsetRange));
            }
            case 'foreground': {
                var min = 0 - start;
                var max = 1 - end;
                return Math.min(max, Math.max(min, offsetRange));
            }
        }
    };
    Slider.prototype.updateStartEnd = function (offsetRange) {
        var _a = this.cfg, start = _a.start, end = _a.end;
        // 操作不同的组件，反馈不一样
        switch (this.currentTarget) {
            case 'minHandler':
                start += offsetRange;
                break;
            case 'maxHandler':
                end += offsetRange;
                break;
            case 'foreground':
                start += offsetRange;
                end += offsetRange;
                break;
        }
        this.set('start', start);
        this.set('end', end);
    };
    /**
     * 调整 text 的位置，自动躲避
     * 根据位置，调整返回新的位置
     * @param range
     */
    Slider.prototype._dodgeText = function (range, minTextShape, maxTextShape) {
        var _a, _b;
        var _c = this.cfg, handlerStyle = _c.handlerStyle, width = _c.width;
        var PADDING = 2;
        var handlerWidth = get(handlerStyle, 'width', DEFAULT_HANDLER_WIDTH);
        var min = range[0], max = range[1];
        var sorted = false;
        // 如果交换了位置，则对应的 min max 也交互
        if (min > max) {
            _a = [max, min], min = _a[0], max = _a[1];
            _b = [maxTextShape, minTextShape], minTextShape = _b[0], maxTextShape = _b[1];
            sorted = true;
        }
        // 避让规则，优先显示在两侧，只有显示不下的时候，才显示在中间
        var minBBox = minTextShape.getBBox();
        var maxBBox = maxTextShape.getBBox();
        var minAttrs = minBBox.width > min - PADDING
            ? { x: min + handlerWidth / 2 + PADDING, textAlign: 'left' }
            : { x: min - handlerWidth / 2 - PADDING, textAlign: 'right' };
        var maxAttrs = maxBBox.width > width - max - PADDING
            ? { x: max - handlerWidth / 2 - PADDING, textAlign: 'right' }
            : { x: max + handlerWidth / 2 + PADDING, textAlign: 'left' };
        return !sorted ? [minAttrs, maxAttrs] : [maxAttrs, minAttrs];
    };
    Slider.prototype.draw = function () {
        var container = this.get('container');
        var canvas = container && container.get('canvas');
        if (canvas) {
            canvas.draw();
        }
    };
    Slider.prototype.getContainerDOM = function () {
        var container = this.get('container');
        var canvas = container && container.get('canvas');
        return canvas && canvas.get('container');
    };
    return Slider;
}(GroupComponent));
export { Slider };
export default Slider;
//# sourceMappingURL=slider.js.map