基于JS简单甘特图
基于JS简单甘特图
- 先来看一下效果吧,这里的需求是从早上的5点为开始时间,到第二天到凌晨5点
前期准备
- 其实网上有很多甘特图的实现方式,但是他们都只能具象到天,不能具体到某个时间点,而且每一个具体的时间段中的描述是不能自定义的,所以准备自己写一下了。
实现逻辑
-
我们可以先模拟一些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>`;
-
首先需要找到时间段中开始时间的开始位置,
-
计算出时间的width,遵循1px = 1M的规则。
-
在设置margin-left时,记得减去上一个时间段甘特图的margin-left(重点)。
-
没绘制一条后,存储其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>