<template>
    <div id="container" :style="viewStyle">
        <slot name="path"></slot>
    </div>
</template>
<script>
import _progressbarjs from "progressbar.js";
const ProgressBar = _progressbarjs;
const ProgressBarType = ["Line", "Circle", "SemiCircle", "Customize"];
export default {
    name: "DoProgressBar",
    props: {
        //进度条类型
        type: {
            type: String,
            default: "Line",
            validator: value => ProgressBarType.indexOf(value) !== -1
        },
        //线条宽度
        strokeWidth: {
            type: Number,
            default: 4
        },
        //动画类型
        easing: {
            type: String,
            default: "easeInOut"
        },
        //动画持续时间（毫秒）
        duration: {
            type: Number,
            default: 1400
        },
        // 进度条颜色
        color: {
            type: String,
            default: "#ED6A5A"
        },
        // 中间线条颜色
        trailColor: {
            type: String,
            default: "#eee"
        },
        //中间线条宽度
        trailWidth: {
            type: Number,
            default: 1
        },
        //svg的内联样式
        svgStyle: {
            type: Object,
            default: () => {
                return {
                    width: "100%",
                    height: "100%"
                };
            }
        },
        // 文本元素的类名
        textClassName: {
            type: String,
            default: "ProgressBar_text"
        },
        // 文本元素样式
        textStyle: {
            type: Object,
            default: () => {
                return {};
            }
        },
        // 仅当text.style不为空时有效
        autoStyleContainer: {
            type: Boolean,
            default: () => {
                return false;
            }
        },
        // 仅当形状为半圆时有效,如果为true，则文本的基线与底部对齐;SVG画布。如果为false，SVG画布的底线,位于文本中心。
        alignToBottom: {
            type: Boolean,
            default: () => {
                return false;
            }
        },
        // 填充形状的颜色。如果为空，则不填充。默认值：空
        fill: {
            type: String,
            default: ""
        },
        // 起始
        from: {
            type: Object,
            default: () => {
                return {};
            }
        },
        // 终止
        to: {
            type: Object,
            default: () => {
                return {};
            }
        },
        //
        step: {
            type: Function,
            default: (state, bar) => {}
        },
        //错误报告
        warnings: {
            type: Boolean,
            default: () => {
                return false;
            }
        },
        // 动画执行完毕之后执行方法
        afterAnimate: {
            type: Function
        },
        // 执行进度
        rate: {
            type: Number,
            default: 1
        },
        // 是否显示数字
        isPercent: {
            type: Boolean,
            default: () => {
                return true;
            }
        },
        width: {
            type: String,
            default: "200px"
        },
        height: {
            type: String,
            default: "8px"
        }
    },
    data() {
        return {
            ProgressView: null
        };
    },
    computed: {
        Options() {
            return {
                strokeWidth: this.strokeWidth,
                easing: this.easing,
                duration: this.duration,
                color: this.color,
                trailColor: this.trailColor,
                trailWidth: this.trailWidth,
                svgStyle: this.svgStyle,
                text: {
                    className: this.textClassName,
                    style: this.textStyle,
                    autoStyleContainer: this.autoStyleContainer,
                    alignToBottom: this.alignToBottom
                },
                fill: this.fill,
                from: this.from,
                to: this.to,
                step: this.step,
                warnings: this.warnings
            };
        },
        viewStyle() {
            let height;
            switch (this.type) {
                case "Line":
                    if (this.height == "8px") height = this.height;
                    break;
                case "Circle":
                    if (this.height == "8px") height = this.width;
                    break;
                case "SemiCircle":
                    if (this.height == "8px") {
                        height = parseInt(this.width) / 2 + "px";
                    }
                    break;
                case "Customize":
                    if (this.height == "8px") height = this.width;
                    break;
            }
            return {
                width: this.width,
                height
            };
        }
    },
    mounted() {
        if (!this.ProgressView) {
            this.initialize();
        }
    },
    watch: {
        Options: {
            handler: function(val, oldVal) {
                var that = this;
                if (this.ProgressView && val) {
                    this.ProgressView.destroy();
                    this.initialize();
                }
            }
        },
        rate: {
            handler: function(val, oldVal) {
                var that = this;
                if (this.ProgressView && val) {
                    this.ProgressView.destroy();
                    this.initialize();
                }
            }
        },
        isPercent: {
            handler: function(val, oldVal) {
                var that = this;
                if (this.ProgressView && val) {
                    this.ProgressView.destroy();
                    this.initialize();
                }
            }
        },
        afterAnimate: {
            handler: function(val, oldVal) {
                var that = this;
                if (this.ProgressView && val) {
                    this.ProgressView.destroy();
                    this.initialize();
                }
            }
        },
        type: {
            handler: function(val, oldVal) {
                var that = this;
                if (this.ProgressView && val) {
                    this.ProgressView.destroy();
                    this.initialize();
                }
            }
        }
    },
    methods: {
        initialize() {
            switch (this.type) {
                case "Line":
                    this.lineInit();
                    break;
                case "Circle":
                    this.circleInit();
                    break;
                case "SemiCircle":
                    this.SemiCircleInit();
                    break;
                case "Customize":
                    this.CustomizeInit();
                    break;
            }
        },
        formatParams() {
            let Opt = this.Options;
            let funStr = Opt.step.toString();
            // eslint-disable-next-line
            var paramsReg = /[^\(\)]+(?=\))/g;
            // eslint-disable-next-line
            var paramsBodyReg = /[^\{\)]+(?=\})/g;
            let params = funStr.match(paramsReg)[0].split(",");
            if (params.length < 2) {
                throw "step 选项传入的参数必须为2个！";
            }
            let paramsStr = params.join(",");
            let paramsBody = funStr.match(
                /(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/
            )[1];
            Opt = this.formatFun(params, paramsBody, paramsStr, Opt);
            return Opt;
        },
        formatFun(params, paramsBody, paramsStr, Opt) {
            let newFunBody;
            if (this.isPercent) {
                let textStyle = this.textStyle;
                switch (this.type) {
                    case "Line":
                        textStyle = Object.assign(
                            {},
                            {
                                position: "absolute",
                                right: "-85%",
                                top: "0",
                                padding: 0,
                                margin: 0
                            },
                            textStyle
                        );
                        newFunBody = `${paramsBody};${
                            params[1]
                        }.setText(Math.round(${
                            params[1]
                        }.value() * 100) + " %");`;
                        break;
                    case "Circle":
                        textStyle = Object.assign(
                            {},
                            {
                                position: "absolute",
                                left: "50%",
                                top: "50%",
                                padding: 0,
                                margin: 0,
                                transform: "translate(-50%, -50%)"
                            },
                            textStyle
                        );
                        newFunBody = `
                        ${paramsBody};
                        var value = Math.round(${params[1]}.value() * 100);
                        if (value === 0) {
                            ${params[1]}.setText('');
                        } else {
                            ${params[1]}.setText(value+" %");
                        }`;
                        break;
                    case "SemiCircle":
                        textStyle = Object.assign(
                            {},
                            {
                                position: "absolute",
                                left: "50%",
                                top: "auto",
                                padding: 0,
                                margin: 0,
                                transform: "translate(-50%, 50%)",
                                color: "rgb(237, 106, 90)",
                                bottom: "14px"
                            },
                            textStyle
                        );
                        newFunBody = `
                        ${paramsBody};
                        var value = Math.round(${params[1]}.value() * 100);
                        if (value === 0) {
                            ${params[1]}.setText('');
                        } else {
                            ${params[1]}.setText(value+" %");
                        }`;
                        break;
                }
                Opt.text.style = textStyle;
                Opt.step = eval(`(false || function(${paramsStr}){
                        ${newFunBody}                    
                    })`);
            }
            if (
                this.to.hasOwnProperty("color") &&
                this.from.hasOwnProperty("color")
            ) {
                newFunBody = `${newFunBody};${
                    params[1]
                }.path.setAttribute("stroke", ${params[0]}.color);`;
                Opt.step = eval(`(false || function(${paramsStr}){
                        ${newFunBody}                    
                    })`);
            }

            return Opt;
        },
        lineInit() {
            let Opt = this.formatParams();
            this.ProgressView = new ProgressBar.Line("#container", Opt);
            this.ProgressView.animate(this.rate, {}, this.afterAnimate);
        },
        circleInit() {
            let Opt = this.formatParams();
            this.ProgressView = new ProgressBar.Circle("#container", Opt);
            this.ProgressView.animate(this.rate, {}, this.afterAnimate);
        },
        SemiCircleInit() {
            let Opt = this.formatParams();
            this.ProgressView = new ProgressBar.SemiCircle("#container", Opt);
            this.ProgressView.animate(this.rate, {}, this.afterAnimate);
        },
        CustomizeInit() {
            this.ProgressView  = new ProgressBar.Path("#customize-path", {
                easing: this.easing,
                duration: this.duration
            });          
            this.ProgressView.set(0);
            this.ProgressView.animate(this.rate, {}, this.afterAnimate);
        }
    }
};
</script>
<style lang="stylus" scoped>
#container
    position: relative
.progressbar-text-line
    color: #999
    position: absolute
    right: -50px
    top: 0
    padding: 0
    margin: 0
</style>