【无标题】

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>甘特图</title>
    <script type="text/javascript" src="echarts.min(1).js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="content" style="width: 900px;height: 300px"></div>
</body>
<script>
    /**
     * 存储阶段进度时间段的对象
     */
    var stageProgress = {

        // 方案 实际时间段
        fangAnTimeBucket: ['2017-11-23', '2017-11-28'],
        // 纲要 实际时间段
        gangYaoTimeBucket: ['2017-11-25', '2017-11-30'],
        // 成果 实际时间段
        chengGuoTimeBucket: ['2017-12-06', '2017-12-12'],
        // 计划开始时间
        scheduledStartTime: '2017-11-23',
        // 有效截止日期
        validTime: '2017-12-02'
    };

    /**
     * 横坐标轴时间刻度可选值
     * 这里 month和year 没有考虑平闰年之分
     */
    var timeInterval = {
        day: 3600 * 1000 * 24,
        month: 3600 * 1000 * 24 * 31,
        year: 3600 * 1000 * 24 * 31 * 12,
    };

    /**
     * 时间坐标轴标签单位应该精确到哪一位
     */
    var xAxisLabelUnit = {
        year: false,
        month: false,
        day: false
    }

    /**
     * 获取合适的横坐标时间刻度间隔
     */
    function getProperTimeAxisInterval() {
        xAxisLabelUnit.year = false;
        xAxisLabelUnit.month = false;
        xAxisLabelUnit.day = false;

        var timeDataArray = getXAxisData();
        var begin = getTimeMilliseconds(timeDataArray[timeDataArray.length - 1]);
        console.log("begin " + begin);
        var periodMillis = getTimeMilliseconds(timeDataArray[timeDataArray.length - 1]) - getTimeMilliseconds(timeDataArray[0]);
        console.log("periodMillis " + periodMillis);
        var years = periodMillis / timeInterval.year;
        console.log("years " + years);
        var months = periodMillis / timeInterval.month;
        console.log("months " + months);
        var days = periodMillis / timeInterval.day;
        console.log("days " + days);

        if (months <= 1) {
            xAxisLabelUnit.day = true;
            return timeInterval.day * 2;
        } else if (months <= 16) {
            xAxisLabelUnit.month = true;
            return timeInterval.month;
        } else if (months <= 24) {
            xAxisLabelUnit.month = true;
            return timeInterval.month * 2;
        } else if (years <= 16) {
            xAxisLabelUnit.year = true;
            return timeInterval.year;
        }
    }

    /**
     * 获取横轴坐标数据源,这里横坐标只显示年月
     * 最小值取传入数据最小的时间再减小一个月
     * 最大值取传入数据最小的时间再增加一个月
     */
    function getXAxisData() {
        var arr = new Array();
        arr = arr.concat(stageProgress.scheduledStartTime)
            .concat(stageProgress.fangAnTimeBucket)
            .concat(stageProgress.gangYaoTimeBucket)
            .concat(stageProgress.chengGuoTimeBucket)
            .concat(stageProgress.validTime).filter(function(item) {
                return item != "-";
            }).sort();
        console.log(arr);
        return arr;
    }

    /**
     * 更改日期字符串为相应月份的第一天
     * @param {Object} dateStr 日期字符串
     */
    function changeDateToMonthFirstDay(dateStr) {
        var inputDate = new Date(dateStr);
        inputDate.setDate(1);
        var result = inputDate.getFullYear() + "-" +
            (inputDate.getMonth() >= 9 ? inputDate.getMonth() + 1 : "0" +
                (inputDate.getMonth() + 1)) + "-" + ("0" + 1);
        return result;
    }

    /**
     * 获取格式化的日期 YYYY-MM-dd
     */
    function formatDateToStr(date) {
        var inputMonth = date.getMonth();
        var inputDate = date.getDate();
        var result = date.getFullYear() +
            "-" + (inputMonth >= 9 ? inputMonth + 1 : "0" + (inputMonth + 1)) +
            "-" + (inputDate >= 9 ? inputDate : "0" + (inputDate));
        return result;
    }

    var faOnTimeCompletionTime = getOnTimeCompletionTime('方案', stageProgress.fangAnTimeBucket[0], stageProgress.fangAnTimeBucket[
        1]);
    var gyOnTimeCompletionTime = getOnTimeCompletionTime('纲要', stageProgress.gangYaoTimeBucket[0], stageProgress.gangYaoTimeBucket[
        1]);
    var cgOnTimeCompletionTime = getOnTimeCompletionTime('成果', stageProgress.chengGuoTimeBucket[0], stageProgress.chengGuoTimeBucket[
        1]);

    var faOverTimeCompletionTime = getOverTimeCompletionTime('方案', stageProgress.fangAnTimeBucket[0], stageProgress.fangAnTimeBucket[
        1]);
    var gyOverTimeCompletionTime = getOverTimeCompletionTime('纲要', stageProgress.gangYaoTimeBucket[0], stageProgress.gangYaoTimeBucket[
        1]);
    var cgOverTimeCompletionTime = getOverTimeCompletionTime('成果', stageProgress.chengGuoTimeBucket[0], stageProgress.chengGuoTimeBucket[
        1]);

    /**
     * 时间数组
     */
    var timeArray = {
        // 开始时间
        beginTimeArr: [
            getTimeMilliseconds(stageProgress.fangAnTimeBucket[0]),
            getTimeMilliseconds(stageProgress.gangYaoTimeBucket[0]),
            getTimeMilliseconds(stageProgress.chengGuoTimeBucket[0]),
        ],
        // 按时完成时间
        onTimeCompletionTimeArr: [
            getTimeMilliseconds(faOnTimeCompletionTime),
            getTimeMilliseconds(gyOnTimeCompletionTime),
            getTimeMilliseconds(cgOnTimeCompletionTime),
        ],
        // 超时完成时间
        overTimeCompletionTimeArr: [
            getTimeMilliseconds(faOverTimeCompletionTime),
            getTimeMilliseconds(gyOverTimeCompletionTime),
            getTimeMilliseconds(cgOverTimeCompletionTime),
        ],
    };

    // 初始化图表
    var myChart = echarts.init(document.getElementById('content'));

    // 构建图表配置项
    option = {
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow',
            },

            /**
             * 也可以使用 formatter: '{b0}:<br />{a0}: {c0}<br />{a1}: {c1}<br />{a2}: {c2}',
             * 但是这样当鼠标指向纵坐标的三个阶段中的某一个时,即使该阶段 没有按时完成,或者 没有超时,
             * 也会显示 按时 或 超时 的 tooltip
             */
            formatter: function(params) {
// 			console.log("params[0]" + JSON.stringify(params[0]));
// 			console.log("params[1]" + JSON.stringify(params[1]));
                console.log("params[2]" + JSON.stringify(params[2]));
                var info = params[0].axisValue + ":<br />";
                info += params[0].seriesName + ":" + getSeriesDateStr(params[0].data) + "<br />";
                info += "结束时间:" + (params[2].data != "-" && params[2].data != undefined && params[2].data != null&&!isNaN(params[2].data) ?
                    getSeriesDateStr(params[2].data) :
                    (!isNaN(params[1].data)&&params[1].data != undefined && params[1].data != null ? getSeriesDateStr(params[1].data) : "-"));
                return info;
            },
        },

        /**
         * 右上角工具栏
         */
        toolbox: {
            right: '3%',
            show: false,
            feature: {
                /**
                 * 数据视图
                 */
                // 			dataView:{
                // 				show:true,
                // 			},
                saveAsImage: {
                    show: true
                }
            }
        },

        /**
         * 图例
         */
        legend: {
            data: ['按时完成', '超时完成'],
            tooltip: {
                show: true,
            },
            itemWidth: 15,
            itemHeight: 15,
            textStyle: {
                fontSize: 16,
                fontFamily: 'Microsoft YaHei',
            },
            itemGap: 120,
            padding: 10,
        },

        /**
         * 直角坐标系内绘图网格
         */
        grid: {
            left: '3%',
            right: '3%',
            bottom: '2%',
            /**
             * grid 区域是否包含坐标轴的刻度标签。
             */
            containLabel: true,
        },

        /**
         * 横坐标
         */
        xAxis: {
            // 		/**
            // 		 * 坐标轴指示器
            // 		 */
            // 		axisPointer: {
            // 			show: true,
            // 		},

            /**
             * 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,
             * 在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
             */
            type: 'time',

            /**
             * value 是一个包含 min 和 max 的对象,分别表示数据的最大最小值,这个函数应该返回坐标轴的最大值。
             *
             * 坐标轴刻度最小值。
             */
            min: function(value) {
                return value.min + (getTimeMilliseconds(getProperTimeAxisBeginAndEndTime()[0]) - value.min);
            },

            /**
             * value 是一个包含 min 和 max 的对象,分别表示数据的最大最小值,这个函数应该返回坐标轴的最大值。
             *
             * 坐标轴刻度最大值。
             */
            max: function(value) {
                return value.max + (getTimeMilliseconds(getProperTimeAxisBeginAndEndTime()[1]) - value.max);
            },
            //
            /**
             * 设置坐标轴分割间隔
             */
            interval: getProperTimeAxisInterval(),
            axisLine: {
                lineStyle: {
                    color: '#BDC8CD',
                    width: 1,
                },
            },

            /**
             * 坐标轴刻度标签的相关设置。
             */
            axisLabel: {
                showMinLabel: false,
                showMaxLabel: false,
                rotate: 35,
                margin: 12,
                fontSize: 16,
                color: '#1c2431',
                formatter: function(value, index) {
                    var date = new Date(value);
                    // var time = date.getFullYear() + "." + (date.getMonth() + 1) + "." + date.getDate();
                    var time = date.getFullYear();
                    if (xAxisLabelUnit.month) {
                        time += "." + (date.getMonth() + 1);
                    }
                    if (xAxisLabelUnit.day) {
                        time += "." + (date.getMonth() + 1) + '.' + date.getDate();
                    }
                    return time;
                },
            },

            /**
             * 坐标轴刻度分割线
             */
            splitLine: {
                show: false,
            },
        },

        /**
         * 纵坐标
         */
        yAxis: {
            type: 'category',
            data: ['方\n案', '纲\n要', '成\n果'],
            axisTick: {
                show: false,
            },
            axisLine: {
                lineStyle: {
                    color: '#e9e9ea',
                    width: 1,
                },
            },
            axisLabel: {
                fontWeight: 'bold',
                fontSize: 16,
                color: '#1c2431',
                fontFamily: 'Microsoft YaHei',
            },
            splitLine: {
                show: true,
                lineStyle: {
                    color: '#eaeae9',
                    width: 1,
                },
            },
        },

        /**
         * 系列
         */
        series: [{
            name: '开始时间',
            type: 'bar',
            stack: '时间',
            itemStyle: {
                normal: {
                    barBorderColor: 'rgba(0,0,0,0)',
                    color: 'rgba(0,0,0,0)'
                },
                emphasis: {
                    barBorderColor: 'rgba(0,0,0,0)',
                    color: 'rgba(0,0,0,0)'
                }
            },
            label: {
                normal: {
                    formatter: function(params) {
                        return getSeriesDateStr(params.value);
                    },
                    show: true,
                    position: 'insideRight',
                    fontSize: 16,
                    color: '#1c2431',
                    fontFamily: 'Microsoft YaHei',
                    offset: [40, -20],
                }
            },
            data: timeArray.beginTimeArr,

            /**
             * 标注线
             */
            markLine: {
                lineStyle: {
                    normal: {
                        color: '#0f77e9',
                    },
                },
                label: {
                    normal: {
                        fontWeight: 'bold',
                        padding: 2,
                        fontSize: 14,
                        fontFamily: 'Microsoft YaHei',
                        formatter: function(params) {
                            return '计划开始时间 ' + getSeriesDateStr(params.value);
                        },
                    },
                },
                data: [{
                    name: '计划开始时间',
                    xAxis: getTimeMilliseconds(stageProgress.scheduledStartTime),
                }, ]
            },
        }, {
            name: '按时完成',
            type: 'bar',
            stack: '时间',
            itemStyle: {
                normal: {
                    color: '#0f77e9'
                }
            },
            label: {
                normal: {
                    formatter: function(params) {
                        return getSeriesDateStr(params.value);
                    },
                    show: true,
                    fontSize: 16,
                    color: '#1c2431',
                    position: 'right',
                    fontFamily: 'Microsoft YaHei',
                    offset: [-45, -20],
                }
            },
            data: timeArray.onTimeCompletionTimeArr,
            markLine: {
                lineStyle: {
                    normal: {
                        color: '#ff4747',
                    },

                },
                label: {
                    normal: {
                        fontWeight: 'bold',
                        padding: 2,
                        fontSize: 14,
                        fontFamily: 'Microsoft YaHei',
                        formatter: function(params) {
                            return '计划完成时间 ' + getSeriesDateStr(params.value);
                        },
                    },
                },
                data: [{
                    name: '有效期',
                    xAxis: getTimeMilliseconds(stageProgress.validTime),
                }, ]
            },
        }, {
            name: '超时完成',
            type: 'bar',
            stack: '时间',
            itemStyle: {
                normal: {
                    color: '#ff4747'
                }
            },
            label: {
                normal: {
                    formatter: function(params) {
                        return getSeriesDateStr(params.value);
                    },
                    show: true,
                    fontSize: 16,
                    color: '#1c2431',
                    offset: [-45, -20],
                    position: 'right',
                    fontFamily: 'Microsoft YaHei',
                }
            },
            data: timeArray.overTimeCompletionTimeArr,
            /**
             * 柱状图宽度
             */
            barWidth: 20,
        }, ]
    };

    // 将构建好的配置项传入echarts
    myChart.setOption(option);

    /**
     * 时间对象转日期字符串 yyyy.MM.dd
     * @param {Object} timeObject 毫秒值或时间字符串
     */
    function getSeriesDateStr(timeObject) {
        if (timeObject == "-") {
            return timeObject;
        }
        var date = new Date(timeObject);
        var dateStr = '';
        dateStr += date.getFullYear() + '.';
        dateStr += date.getMonth() + 1 + '.';
        dateStr += date.getDate();
        return dateStr;
    };

    /**
     * 获取阶段的计划内完成时间(蓝色柱状图值)
     * @param {Object} stage 阶段
     * @param {Object} stateBeginTime
     * @param {Object} stateCompletionTime
     */
    function getOnTimeCompletionTime(stage, stageBeginTimeStr, stageCompletionTimeStr) {
        var validTimeMillis = getTimeMilliseconds(stageProgress.validTime);
        var stageBeginTimeMillis = getTimeMilliseconds(stageBeginTimeStr);
        var stageCompletionTimeMillis = getTimeMilliseconds(stageCompletionTimeStr);
        if (validTimeMillis <= stageBeginTimeMillis) {
            // 若阶段开始时间大于等于有效期,则项目超时完成,有效时间为'-'
            return '-';
        }
        if (validTimeMillis > stageBeginTimeMillis && validTimeMillis < stageCompletionTimeMillis) {
            // 若有效期介于阶段完成时间和阶段开始时间之间,则该阶段按时完后时间(实际该阶段是超时完成的)即蓝色柱状图的终值为有效期
            return stageProgress.validTime;
        }
        if (validTimeMillis >= stageCompletionTimeMillis) {
            // 若有效期大于等于阶段完成时间,则阶段按时完成
            return stageCompletionTimeStr;
        }
    }

    /**
     * 获取阶段内的超时完成时间(红色色柱状图值)
     * @param {Object} stage 阶段
     * @param {Object} stateBeginTime
     * @param {Object} stateCompletionTime
     */
    function getOverTimeCompletionTime(stage, stageBeginTimeStr, stageCompletionTimeStr) {
        var validTimeMillis = getTimeMilliseconds(stageProgress.validTime);
        var stageBeginTimeMillis = getTimeMilliseconds(stageBeginTimeStr);
        var stageCompletionTimeMillis = getTimeMilliseconds(stageCompletionTimeStr);

        if (validTimeMillis < stageCompletionTimeMillis) {
            // 阶段完成时间大于有效期,则将阶段完成时间作为超时时间返回
            return stageCompletionTimeStr;
        }

        if (validTimeMillis >= stageCompletionTimeMillis) {
            // 阶段完成时间小于等于有效期,则阶段按时完成,超时时间应为'-'
            return '-';
        }
    }

    /**
     * 根据时间字符串获取对应的毫秒值
     * @param {Object} timeStr 时间字符串
     */
    function getTimeMilliseconds(timeStr) {
        return (new Date(timeStr)).getTime();
    }

    /**
     *获取时间坐标轴的起始和结束值
     */
    function getProperTimeAxisBeginAndEndTime() {
        var xAxis = getXAxisData();
        var begin = xAxis[0];
        var end = xAxis[xAxis.length - 1];
        var beginDate = new Date(begin);
        var endDate = new Date(end);

        if (xAxisLabelUnit.month) {
            beginDate.setDate(1);
            endDate.setMonth(endDate.getMonth() + 1);
            endDate.setDate(1);
        } else {
            var daysCount = getProperTimeAxisInterval() / timeInterval.day;
            console.log("daysCount " + daysCount);
            beginDate.setDate(beginDate.getDate() - daysCount);
            endDate.setDate(endDate.getDate() + daysCount);
        }
        var beArr = [formatDateToStr(beginDate), formatDateToStr(endDate)];
        console.log("beArr " + beArr);
        return beArr;
    }
</script>
</html>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

i进击的攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值