参考:https://www.freecodecamp.org/news/create-gantt-chart-using-css-grid/
“甘特图是一种用于说明项目进度的条形图。该图表在纵轴上列出了要执行的任务,在横轴上列出了时间间隔。图中水平条的宽度显示了每项活动的持续时间。” – 维基百科
首先生成 7:00 - 6:00 24小时时间表头
generateTimeRange () { // let h1 = parseInt(start.substring(0, 2)) let timeRange = [] for (let i = 7; i < 24; i++) { timeRange.push((i < 10 ? '0' + i : i) + ':' + '00') this.timeRangeOrigin.push(i) } for (let i = 0; i < 7; i++) { timeRange.push((i < 10 ? '0' + i : i) + ':' + '00') this.timeRangeOrigin.push(i) } return timeRange },
如第一条Item,30和0这两个条状图像,时间范围分别是 7:40 - 8:12 和 7:30 - 8:30
如何让条状图形正好偏移到时间点呢?
首先需要一个存储所以时间的数组,为了方便查找,里面的数据大概为: [7,8,9,10,11 .... 6]
以第二条为例:
180 这一条的起始时间为 2021-06-03 08:22:46 - 2021-06-03 11:49:15
我们先来计算宽度,这个180该多长:
let width = ((endIdx - startIdx) === 0 ? 1 : (endIdx - startIdx)) * this.itemWidth
endIdx 和 startIdx 为结束时间的分钟在数组中的下标,itemWidth为每个单元格的宽度
那么上面的时间区间就是 (4 - 1) * 150 大约三个单元格的宽度
那么再进行时间偏移
180 的起始时间是8点,也就是需要跳跃7这个单元格到8,分钟时22分,那么算出偏移量
(单元格宽度 / 60) * 分钟数 = 偏移量
getOffset (minute) { return (this.itemWidth / 60) * minute },
那么最后还要处理一下宽度,这个时候的结束时间位置应该时不正确的。
let style = 'width:' + ((width - this.getOffset(parseInt(m1)) + this.getOffset(parseInt(m2))) - this.itemWidth) + 'px;'
最终宽度为: ((宽度 - 左偏移量 ) + 右偏移量) - 一个单元格宽度
完整计算如下:
getBarStyleVersion2 (flag, startTime, endTime) { let s = this.getMinutes(this.getTimestamp(startTime)) let h1 = parseInt(s.substring(0, 2)) let m1 = s.substring(s.indexOf(':') + 1, s.indexOf(':') + 3) let m2 let h2 if (endTime !== null) { let e = this.getMinutes(this.getTimestamp(endTime)) h2 = parseInt(e.substring(0, 2)) m2 = e.substring(s.indexOf(':') + 1, e.indexOf(':') + 3) } else { h2 = h1 m2 = m1 } let temp if (h1 > h2) { temp = h1 h1 = h2 h2 = temp } let startIdx = this.getTimeIdx(h1) let endIdx = this.getTimeIdx(h2) + 1 // 计算长度 // // console.log(startIdx) // // console.log(endIdx) // // console.log('w:' + ((endIdx - startIdx) === 0 ? 1 : (endIdx - startIdx)) * this.itemWidth) let width = ((endIdx - startIdx) === 0 ? 1 : (endIdx - startIdx)) * this.itemWidth // console.log('offset:' + this.getOffset(parseInt(m1))) let marginLeft = 0 if (startIdx > 0) { marginLeft = (this.itemWidth * startIdx) + this.getOffset(parseInt(m1)) } else { marginLeft = this.getOffset(parseInt(m1)) } let style = 'width:' + ((width - this.getOffset(parseInt(m1)) + this.getOffset(parseInt(m2))) - this.itemWidth) + 'px;' // 计算margin style += 'margin-left:' + marginLeft + 'px;' // 计算偏移 // console.log('m1: -> ' + m1) // console.log('w: -> ' + this.itemWidth) // // console.log('m2: -> ' + m2) // // console.log(s) if (flag === 0) { style += 'background-color:#4F97A3;' } else { style += 'background-color:#0E4D92;' } return style }, getOffset (minute) { return (this.itemWidth / 60) * minute },
就是图中的绿色竖线,代表当前时间。
首先一个DIV
然后生成样式:
getNowLine () { let styles = 'border:1px dashed green;height: 900px;width: 1px; position: fixed;z-index:999;' let now = this.getMinutes(Date.parse(new Date())) let m1 = parseInt(now.substring(0, 2)) let s1 = parseInt(now.substring(now.indexOf(':') + 1, now.indexOf(':') + 3)) let idx = this.getTimeIdx(m1) styles += 'margin-left:' + ((this.itemWidth * (idx + 1)) + (150 - (60 - this.getOffset(s1)))) + 'px' // console.log(idx) return styles }
偏移量计算为 (单元格长度 * (小时数下标 + 1)) + (左侧固定栏宽度 - (60分钟 - 分钟数下标偏移量))