先看效果一哈效果
铛铛,新的铁胆火车侠运行排班数据展示系统节目233 page1.png

点击Demo看效果
使用说明的Github地址
起因
刚刚毕业,初入新公司,就要求参与一个排班展示类的系统开发,前端系统方面的关键点就是排班数据的展示了。
- 在设计狮和甲方一顿疯狂的沟通
- 啪哒,给我了一份设计稿
- 偷偷瞄一眼,嗯哼,🧐这是啥子哦
- 诶哟,这不是和学校里学的甘特图很像嘛
- 一顿高兴就开始百度谷歌起来,毕竟看着挺复杂的,如果能有开源组件直接用就好啦,比自己写的靠谱又方便不是。
- 但是一顿搜索大概都是如下这些样子
都是类似如下的 这些


功能很多,但是都不是需要的,暴风哭泣😢。。。都是一行只有一条数据的甘特图表,都不符合要求啊摔

而且看github 上的相关代码很多都没有注释,或者看不懂啦(毕竟英语不好,太委屈😢)
既然找不到相关符合要求,所以只能自己动手了啊,打开vs code 准备一把梭了他。

但是想了一会没有梭出来,一丢丢思路都磨的。而上面的那些,功能都很多很杂看了头大,不知道那里看起。

翻了一会github 后,我在这里推荐一个代码 jquery.ganttView
这个是用jquery 写的,看了一哈代码也只有三百来行,相比其他看起来会轻松一点。推荐!!!

比较笨哈,不是很懂怎么看源码,看了半天才看懂他的原理,然后我就基于他的原理我就用vue 和react 抄了一个写了一个,地址,加了个拖拽。
嗯,自己根据的理解写了第一版本调研一哈,写的非常非常差劲,代码写的太少(我是去年1月转的开始写的前端,😂😂😂其实后端也没写多少,代码量太少了),长这个样子,表面看起来是很符合要求,但是里面的代码就很臭了呀。如果有兴趣看,大概就是前35次commit.

然后就commit 就停在那里很久了。因为公司要求的react的,所以我就跑去用react 写了。
跑题了。。。跑题了。。。
实现大致思路
看了上面基于jquery
的源码后,甘特图可以分成3块来写,加上自己的理解改造了一顿,上面的
时间轴区域,左侧的描述行名区域,右侧的甘特图表区域。
来看时间轴区域

时间轴的开始时间
。
比如Start
为10:10
分
- 刻度为
60
,时间轴的开始时间为10:00
分 - 刻度为
5
,时间轴的开始时间 为10:10
分 - 刻度为
3
,时间轴的开始时间为10:09
分
然后用你算出的开始时间一直加加加刻度,循环出刻度div 就可以啦,不难的,就是算起始时间可能有一点绕。
左侧的描述行名区域,

这个部分就比较简单啦,循环生成列表就ok 的啦。
右侧的甘特图表区域。

这边的思路是这样的,
-
先生成一行带有表格线的div,用一个
L形状
的png做背景重复background-repeat就好啦LLLLLLLLLL
这样是不是就是表格线啦。 上面的jq 版本的办法是生成一个个div 然后用border
来画线,大家最好不要学哦,因为这样会生成太多div了,性能会很差劲,除非你要订制每一个格子(但是也有其他方法订制哦) -
然后就要开始生成甘特条的容器了。
生成容器的关键点就定位他的位置了,定位的起点就是前面生成时间轴算出来的时间轴的开始时间
。方法就是
(容器时间-开始时间)/刻度值* 刻度的宽度,
这样就算出距离了,接着用绝对定位就可以了,很easy 哦。
- 还有滚动的同步需要处理,时间轴和甘特图表区 是
X轴
滚动关联,左侧的描述行名区域是和甘特图表区Y轴
关联。这里个纯Css的滚动方案,但是有缺陷,它Y轴
滚动条要滚动到末尾才可以看到。所以只能自己去实现滚动条啦,很简单哦。思路是一个父div
包裹一个子div
,其中父div
设置为一屏gantt 页面的高度,同时设置宽度为17px
(滚动条的宽度,但是不同浏览器滚动条宽度好像不一样),设置overflow:scroll
,子div
设置为gantt 图表行高度的总和。X轴同理,然后去同步滚动就好了。
交差时间
公司用的版本是用react 写的,当把测试数据带入时,10000条数据。。。

画面大概卡了十几秒才出来,漫长的白屏。滚动起来的效果还是可以看的。
给甲方看,甲方说可以接受这个渲染速度

甲方说他们旧系统也是要这样卡很久才出画面的,等习惯了没关系。。。而且称新的甘特图好看很多嘛,样式效果是比我目前这个Demo 差别很多哦,这个demo是猴版滑稽🙄。
不行,对自我的要求,我要改进它!!!
优化时间
👍点名表扬chrome ,虽然十多秒出来了,但是滚动还是很流畅的,页面大概占用600MB吧。
👿点名批评IE,可能有一分钟?出来后滚动也是一卡一卡像幻灯片一样。
没有思路就在zhihu 上逛了一会,机缘巧合遇到了曾建凯写了一个回答提到了大量数据的问题,遂请教了它,得知了react-virtualized,这里再次谢谢🙏。
于是查找了一些相关文章,需要的自查。

具体原理是很简单,简化版本大致说一下(注意,这里每一行高度固定哦):
根据滚动条滚动的距离除以行高算出渲染的第一行的firstIndex
scrollTop/cellHeight
再根据屏幕高度算出要渲染的最后一行的endIndex
screenHeight/cellHeight - scrollTop/cellHeight,
然后去原始数组中截取需要渲染定位
需要的部分就可以了(注意定位的问题哦)。
⌨️⌨️略去一番操作,就优化到了大概1.5秒左右就可以加载出页面啦 🎉 🎉 🎉
但是还不够,还可以再快一点,逮虾户~~~

上面的方案都只解决了Y轴
方向的动态渲染,说到这里你肯定明白了,X轴
我们同样可以做手脚的呀。思路很简单,就是算出当前的屏幕显示的时间范围
,然后渲染时判定甘特内容条容器的时间在不在这个范围之内就可以了,具体实现就留给大家了。
⌨️⌨️再略去一番操作,能有大概0.5秒的速度提升,现在1秒左右就可以加载出页面啦 🎉 🎉 🎉
通过以上相信大家也可以做出一个基本gantt图组件了
最后
就是我自己实现的玩具代码啦 v-gantt-chart 组件啦,demo 就是用他做的,支持多个甘特图组合哦。支持自定义渲染内容。

具体的使用 可以看Github 上的readme,欢迎大家提出意见,提issue👏👏👏