基於JS簡單甘特圖

筱筱醬發表於2019-02-28

基於JS簡單甘特圖

最近同事求助到一個小小的需求,寫一個時間甘特圖,主要想表現一個車在一天的不同的時間點裡,停靠的站點,

先來看一下效果吧,這裡的需求是從早上的5點為開始時間,到第二天到凌晨5點

基於JS簡單甘特圖

前期準備

其實網上有很多甘特圖的實現方式,但是他們都只能具象到天,不能具體到某個時間點,而且每一個具體的時間段中的描述是不能自定義的,所以準備自己寫一下了。

實現邏輯

我們可以先模擬一些demo資料,這裡面最為主要的資料為每個時間點,我們要實現上面的效果,需要對每個時間點進行拆分。

var demoData: [
    {   
        carNum: '川A09384',
        innerData: [
            {
                start: '2019/1/21 6:23',
                end: '2019/1/21 7:45',
                value: 'A站點',
                bg: 'green'
            },
            {
                start: '2019/1/21 12:23',
                end: '2019/1/21 16:45',
                value: 'B站點',
                bg: 'yellow'
            },
            {
                start: '2019/1/21 20:00',
                end: '2019/1/21 23:25',
                value: 'C站點',
                bg: 'blue'
            }
        ]
    },
    {   carNum: '川A04384',
        innerData: [
            {
                start: '2019/1/21 5:23',
                end: '2019/1/21 6:05',
                value: 'A站點',
                bg: 'blue'
            },
            {
                start: '2019/1/21 10:23',
                end: '2019/1/21 13:45',
                value: 'B站點',
                bg: 'green'
            },
            {
                start: '2019/1/21 21:00',
                end: '2019/1/22 3:35',
                value: 'C站點',
                bg: 'yellow'
            },
        ]
    }]
複製程式碼
首先建立時間
// 建立時間
createHours: function(){
    var startHour = 5;
    var endHour = 11;
    var html = '';
    for (let i = startHour; i< 24; i++) {
        html += `<div>${i < 10 ? `0${i}` : i}:00</div>`
    }
    for (let i = 0; i< endHour; i++) {
        html += `<div>${i < 10 ? `0${i}` : i}:00</div>`
    }
    document.getElementById('hour').innerHTML = html;
},
複製程式碼
根據資料繪製甘特圖

我們將 1H = 60px;這樣去定寬,即 1px = 1M;

繪製第一個時間段 start:'2019/1/21 6:23'; end: '2019/1/21 7:45';

var start = new Date('2019/1/21 6:23'),
    end = new Date('2019/1/21 7:45'),
    start_h = start.getHours(), // 開始時間
    start_m = start.getMinutes(), // 開始分鐘 
    end_h = end.getHours(), // 結束時間
    end_m = end.getMinutes(), // 結束分鐘
    left_offset = 0;
    _left_offset = 0;
    width = '';
    // 獲取時間段甘特圖的開始位置(我們從5點開始,所以-5);
    left_offset = (start_h - 5) * 60 + start_m;
    // 獲取每一段甘特圖的寬度,
    // 先計算出結束時間的位置,然後在減去開始時間的左邊距;
    width = ((end_h - 5) * 60 + end_m) - left_offset;
    // 使用現有的左邊距減去前一個時間的左邊距
    _left_offset = left_offset - allLeft;
    // 因為存在多個時間段,所以在繪製下一個時間斷時,left_offset
    // 使用allLeft儲存上一個時間斷距離左邊的距離。
    allLeft = left_offset + width;
    // 將其新增到DOM中
   html += `<span style="width:${width}px;margin-left:${_left_offset}px;">${innerData[i].value}</span>`;
複製程式碼
  1. 首先需要找到時間段中開始時間的開始位置,
  2. 計算出時間的width,遵循1px = 1M的規則。
  3. 在設定margin-left時,記得減去上一個時間段甘特圖的margin-left(重點)。
  4. 沒繪製一條後,儲存其margin-left,方便下一個時間段使用。
關於跨天怎麼計算

當我們的時間段是屬於跨天的怎麼計算他的開始和結束位置,以及他的寬度呢?直接貼程式碼了哈,

createData: function() {
var data = this.demoData;
var today = new Date().getDate(); // 今天的日期
for (let m = 0; m< data.length; m++) {
    var innerData = data[m].innerData;
    var html = '';
    var allLeft = 0;
    for (let i = 0; i< innerData.length; i++) {
        var start = new Date(innerData[i].start),
            end = new Date(innerData[i].end),
            start_d = start.getDate(),
            end_d = end.getDate(),
            start_h = start.getHours(),
            start_m = start.getMinutes(),
            end_h = end.getHours(),
            end_m = end.getMinutes(),
            left_offset = 0;
            _left_offset = 0;
            width = '';
        if (start_d === (today + 1)) {
            left_offset = ((23 - 5) * 60) + ((start_h + 1) * 60) + start_m;
            _left_offset = left_offset - allLeft;
            width = (((23 + (end_h + 1)) - 5) * 60 + end_m) - left_offset;
        } else if (end_d === (today + 1)) {
            left_offset = ((start_h - 5) * 60) + start_m;
            _left_offset = left_offset - allLeft;
            width = (((24 + end_h) - 5) * 60 + end_m) - left_offset;
        } else {
            left_offset = (start_h - 5) * 60 + start_m;
            _left_offset = left_offset - allLeft;
            width = ((end_h - 5) * 60 + end_m) - left_offset;
        }
        allLeft = left_offset + width;
        html += `<span style="width:${width}px;margin-left:${_left_offset}px;background:${innerData[i].bg}">${innerData[i].value}</span>`;
    }
    document.getElementById('container').innerHTML += `<div class="gantt-item" >${html}</div>`;
}
}
複製程式碼

這個地方就不詳細解說了,有什麼不懂的地方歡迎大家留言。程式碼很簡潔,主要用於實現一個比較簡單的甘特圖。不需要下載什麼外掛之類的。

這裡把程式碼貼出來哈,大家可以一起交流,或許你有更好的實現方式呢。

<html>
    <head>
        <title>測試demo</title>
        <style type="text/css">
            #container {
                width: 100%;
                overflow: scroll;
                height: calc(100vh - 0px);
                width: 1900px;
            }
            .carNum {
                float:left;
                width:100px;
                text-align: center;
            }
            #hour {
                width: 1800px;
                overflow: scroll;
            }
            #hour div{
                width: 60px;
                float: left;
                border-left: 1px solid #ddd;
                background: #ccc;
                text-align: center;
                box-sizing: border-box;
            }
            .gantt-item {
                width: 1800px;
            }
            .gantt-item:hover{
                background:rgba(0,0,0,.1);
            }
            .gantt-item span {
                height: 20px;;
                display: inline-block;
                margin: 5px 0px;
                font-size: 12px;
                text-align: center;
                color:#fff;
                background:green;
            }
            .nowTime {
                border: 1px solid green;
                display: inline-block;
                height: 500px;
                height: calc(100vh - 0px);
                position: absolute;
                top: 0px;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div class="carNum">
                <div style="background:#ccc;">車牌號</div>
                <div style="line-height:30px;">川A09384</div>
                <div style="line-height:30px;">川A09384</div>
                <div style="line-height:30px;">川A09384</div>
            </div>
            <div id="hour" style="float:righ">
            </div>
        </div>
    </body>
    <script type="text/javascript">
        var gantt = {
            demoData: [
                {   
                    innerData: [
                        {
                            start: '2019/1/21 6:23',
                            end: '2019/1/21 7:45',
                            value: 'A站點',
                            bg: 'green'
                        },
                        {
                            start: '2019/1/21 12:23',
                            end: '2019/1/21 16:45',
                            value: 'B站點',
                            bg: 'yellow'
                        },
                        {
                            start: '2019/1/21 20:00',
                            end: '2019/1/21 23:25',
                            value: 'C站點',
                            bg: 'blue'
                        }
                    ]
                },
                {   
                    innerData: [
                        {
                            start: '2019/1/21 5:23',
                            end: '2019/1/21 6:05',
                            value: 'A站點',
                            bg: 'blue'
                        },
                        {
                            start: '2019/1/21 10:23',
                            end: '2019/1/21 13:45',
                            value: 'B站點',
                            bg: 'green'
                        },
                        {
                            start: '2019/1/21 21:00',
                            end: '2019/1/22 3:35',
                            value: 'C站點',
                            bg: 'yellow'
                        },
                    ]
                },
                {  
                    innerData: [
                        {
                            start: '2019/1/21 8:23',
                            end: '2019/1/21 10:05',
                            value: 'A站點',
                            bg: 'blue'
                        },
                        {
                            start: '2019/1/21 13:23',
                            end: '2019/1/21 14:45',
                            value: 'B站點',
                            bg: 'green'
                        },
                        {
                            start: '2019/1/21 22:00',
                            end: '2019/1/22 3:35',
                            value: 'C站點',
                            bg: 'red'
                        },
                        {
                            start: '2019/1/22 4:00',
                            end: '2019/1/22 7:35',
                            value: 'D站點',
                            bg: 'green'
                        },
                    ]
                },
            ],
            // 初始化
            init: function() {
                this.showNowTime();
                this.createHours();
                this.createData();
            },
            // 建立時間
            createHours: function(){
                var startHour = 5;
                var endHour = 11;
                var html = '';
                for (let i = startHour; i< 24; i++) {
                    html += `<div>${i < 10 ? `0${i}` : i}:00</div>`
                }
                for (let i = 0; i< endHour; i++) {
                    html += `<div>${i < 10 ? `0${i}` : i}:00</div>`
                }
                document.getElementById('hour').innerHTML = html;
            },
            // 當前時間線
            showNowTime: function() {
                var date = new Date();
                var h = date.getHours(),
                    m = date.getMinutes();
                var offset = (h - 5) * 60 + m;
                var html = `<div class="nowTime" style="margin-left:${offset}px"></div>`;
                document.getElementById('container').innerHTML += `<div class="gantt-item">${html}</div>`;
            },
            createData: function() {
                var data = this.demoData;
                var today = new Date().getDate(); // 今天的日期
                for (let m = 0; m< data.length; m++) {
                    var innerData = data[m].innerData;
                    var html = '';
                    var allLeft = 0;
                    for (let i = 0; i< innerData.length; i++) {
                        var start = new Date(innerData[i].start),
                            end = new Date(innerData[i].end),
                            start_d = start.getDate(),
                            end_d = end.getDate(),
                            start_h = start.getHours(),
                            start_m = start.getMinutes(),
                            end_h = end.getHours(),
                            end_m = end.getMinutes(),
                            left_offset = 0;
                            _left_offset = 0;
                            width = '';
                        if (start_d === (today + 1)) {
                            left_offset = ((23 - 5) * 60) + ((start_h + 1) * 60) + start_m;
                            _left_offset = left_offset - allLeft;
                            width = (((23 + (end_h + 1)) - 5) * 60 + end_m) - left_offset;
                        } else if (end_d === (today + 1)) {
                            left_offset = ((start_h - 5) * 60) + start_m;
                            _left_offset = left_offset - allLeft;
                            width = (((24 + end_h) - 5) * 60 + end_m) - left_offset;
                        } else {
                            left_offset = (start_h - 5) * 60 + start_m;
                            _left_offset = left_offset - allLeft;
                            width = ((end_h - 5) * 60 + end_m) - left_offset;
                        }
                        allLeft = left_offset + width;
                        html += `<span style="width:${width}px;margin-left:${_left_offset}px;">${innerData[i].value}</span>`;
                    }
                    document.getElementById('container').innerHTML += `<div class="gantt-item" >${html}</div>`;
                }
            }
        }
        gantt.init();
    </script>
</html>
複製程式碼

相關文章