原生 JS+CSS+HTML 实现时序图的方法


Posted in HTML / CSS onJuly 31, 2019

之前本人使用React + AntDesign 实现了一个简单的时序图,但是后来有了更复杂的需求,并且要求同时展示2000个任务的展示,这就涉及到了性能问题,本人先使用React+antd+ts实现了一个基本满足下面需求的demo,但是react的渲染机制造成了较大的性能问题,利用chrome自带的Performance,测试发现demo的首次渲染高达10s以上,并且后续的操作也会使整个页面非常卡。经过思索后决定使用原声js+css+html去实现,因为原声js下性能是最优的。下面先来说说新版本的需求:

  • 左侧以树形结构展示任务,可折叠
  • 右侧展示任务运行所耗时间的长度
  • 需要用线条链接任务之间的关系
  • 右侧可缩放查看详细的任务状态
  • 缩放时图形保持以鼠标为中心向两端成一定比例放大,放大时里面的文字描述不受影响
  • 图形缩放时表示任务耗时的时间以及坐标需要跟随图像放大的比例进行相应变化
  • 鼠标在时序图上移动时出现一根线条提示当前的时间以及信息

效果图

图一:

原生 JS+CSS+HTML 实现时序图的方法
 

图二:

原生 JS+CSS+HTML 实现时序图的方法

实现难点

鼠标缩放,x轴的缩放方式

鼠标缩放产生时序图X轴的缩放。时序图的缩放,在这里提供三种思路:

  1. 做数据截取,按照一定的算法截取前后的数据,然后重新渲染整个页面
  2. 利用css3的scaleX对时序图的dom做缩放
  3. 实际改变时序图dom的width,里面的任务运行的长度,连接线条的长度,任务运行预计需要的时长都以百分比显示。

三种思路的优缺点:

  1. 优点:不需要去操作dom的css属性,之间重新渲染,比较方便。缺点:对于使用dom重绘,耗费性能严重,大量任务渲染时性能很慢。
  2. 优点:只需改变dom的css,加载快,较流程。缺点:计算麻烦,使用过scaleX的小伙伴会发现当我X轴放大时垂直连接线会变宽,字体会横向拉伸,都需要去反向缩小。
  3. 优点:加载快,很流畅,一次计算好元素所占宽度的占百分比,后面的操作都不需要去计算。缺点:使用百分比计算会有一定误差,放大到一定程度会看的出来。(综合考虑,本人采用的是第三种)
// 计算宽度百分比的函数
// endTime: 任务的结束时间
// startTime: 任务的开始时间
// maxTime: 所有任务结束时间最大的值
// minTime: 所有任务开始时间最小的值
// time: 所有任务开始时间与结束时间的排序 升序
// task_width: 任务的长度、水平连接线的长度、垂直连接线的left值
const widthFun = function (endTime, startTime, maxTime, minTime) {
    const task_width =
    (((Number (endTime) - Number (startTime)) /
    ((maxTime || time[time.length - 1]) - (minTime || time[0])) *
    (body_width - tree_box_dom.offsetWidth)) / dom.offsetWidth)*100;
    return task_width> 100 ? 100 : task_width;
  };

鼠标缩放,保持以鼠标为中心,往两边放大

先放推理过程图:

原生 JS+CSS+HTML 实现时序图的方法

// 上图解释
// dom = 时序图的dom元素
// domL1, domeL2 = dom.scrollLeft;
// domeL1表示前一次的dom.scrollLeft;
// domeL2表示当前的dom.scrollLeft;
// scale 表示当前的放大的比例
// scale1 表示上一次的放大比例
// tree_dom.offsetWidth表示左侧树的宽度
// clientX1 表示上一次的鼠标位置距离时序图左侧的距离 = e.clientX - tree_dom.offsetWidth
// clientX2 表示当前鼠标位置距离时序图的距离

// 以鼠标为中心的缩放,公式为:
domL2 = domeL1(scale/scale1) + clientX1(scale/scale1) - e.clientX + tree_dom.offsetWidth
// 公式讲解:
// 1. scale/scale1表示本次的缩放比例除以上一次的缩放比例,表示当前的缩放比例
// 左侧卷去的宽度在第二次缩放时也会跟着缩放,所以左侧的宽度需要乘以缩放比例
// 鼠标位置距离时序图左侧的宽度在缩放时也会跟着缩放,所以也要乘以缩放比例
// 最后面减去鼠标位置距离时序图左侧的实际距离就等于缩放时左侧卷去的长度

// 页面代码
time_box_parent.scrollLeft = (time_box_parent.scrollLeft + e.clientX - tree_box_dom.offsetWidth) * (scale_x / scale_x1) - e.clientX + tree_box_dom.offsetWidth;

使用连线表示任务之间的关系

方案:

  1. 采用的时css3 + js + html5,用伪元素绘制。
  2. 用dom包裹直角图片,设置其位置及高度。
  3. 用标签绘制
     

优缺点:

  1. 优点:不会增加多余的标签,对渲染有利。缺点:父任务产生了多个子任务,不好添加伪类及设置伪类的高度及宽度。
  2. 优点:方便,只要计算子任务距父任务的高度即可。缺点:任务过多时图片会非常多,很影响性能
  3. 优点:单独控制每个元素的高度及位置,可控性高,可添加反馈色。缺点:添加了较多的元素,对渲染产生影响(本人使用的是第三种,这是一个笨方法,有更好方法的大佬,可以提供建议,多谢)

实现思路:

用一个变量记录每个任务的层级深度,层级深都以当前任务的父任务为起点,就是说是从哪个任务产生的当前任务,同级的子任务进行累加操作。用累加的变量按照一定的比例获取垂直连线的高度以及水平连线的top值,水平连线的长度由任务的创建时间和开始时间决定。(使用上面的宽度百分比函数)

时间单位:天、时、分、秒

这个比较简单,实现思路:

因为本demo的时间4刻度是个刻度,判断最小时间戳与最大时间戳之间的差除以4,是否还有一天的时间(60 * 60 * 24,换算成秒),从大到小的降序获取时间单位。

总结

以上所述是小编给大家介绍的原生 JS+CSS+HTML 实现时序图的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

HTML / CSS 相关文章推荐
纯CSS3实现圆角效果(含IE兼容解决方法)
May 07 HTML / CSS
详解css3 Transition属性(平滑过渡菜单栏案例)
Sep 05 HTML / CSS
CSS 说明横向进度条最后显示文字的实现代码
Nov 10 HTML / CSS
socket.io 和canvas 实现的共享画板功能
May 22 HTML / CSS
带你认识HTML5中的WebSocket
May 22 HTML / CSS
html5 实现客户端验证上传文件的大小(简单实例)
May 15 HTML / CSS
深入浅析HTML5中的article和section的区别
May 15 HTML / CSS
详解window.open被浏览器拦截的解决方案
Jul 18 HTML / CSS
canvas实现滑动验证的实现示例
Aug 11 HTML / CSS
老生常谈 使用 CSS 实现三角形的技巧(多种方法)
Apr 13 HTML / CSS
CSS完成视差滚动效果
Apr 27 HTML / CSS
详解使用 CSS prefers-* 规范提升网站的可访问性与健壮性
May 25 HTML / CSS
Canvas图片分割效果的实现
Jul 29 #HTML / CSS
HTML5中的Web Notification桌面通知功能的实现方法
Jul 29 #HTML / CSS
HTML5 播放 RTSP 视频的实例代码
Jul 29 #HTML / CSS
利用 Canvas实现绘画一个未闭合的带进度条的圆环
Jul 26 #HTML / CSS
使用Html5多媒体实现微信语音功能
Jul 26 #HTML / CSS
使用canvas来完成线性渐变和径向渐变的功能的方法示例
Jul 25 #HTML / CSS
浅析canvas元素的html尺寸和css尺寸对元素视觉的影响
Jul 22 #HTML / CSS
You might like
模板引擎Smarty深入浅出介绍
2006/12/06 PHP
php 过滤器实现代码
2010/08/09 PHP
对比PHP对MySQL的缓冲查询和无缓冲查询
2016/07/01 PHP
yii2 在控制器中验证请求参数的使用方法
2019/06/19 PHP
js表格分页实现代码
2009/09/18 Javascript
js模拟类继承小例子
2010/07/17 Javascript
js String对象中常用方法小结(字符串操作)
2012/01/27 Javascript
js中top的作用深入剖析
2014/03/04 Javascript
JavaScript对象数组如何按指定属性和排序方向进行排序
2016/06/15 Javascript
JS关闭窗口时产生的事件及用法示例
2016/08/20 Javascript
AngularJS表单和输入验证实例
2016/11/02 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
2016/11/29 Javascript
将鼠标焦点定位到文本框最后(代码分享)
2017/01/11 Javascript
JS图片压缩(pc端和移动端都适用)
2017/01/12 Javascript
javascript 缓冲运动框架的实现
2017/09/29 Javascript
vue组件表单数据回显验证及提交的实例代码
2018/08/30 Javascript
微信小程序使用map组件实现路线规划功能示例
2019/01/22 Javascript
微信小程序实现商品属性联动选择
2019/02/15 Javascript
深入浅析Vue中mixin和extend的区别和使用场景
2019/08/01 Javascript
JS防抖和节流实例解析
2019/09/24 Javascript
JavaScript常用进制转换及位运算实例解析
2020/10/14 Javascript
你不知道的SpringBoot与Vue部署解决方案
2020/11/09 Javascript
Handtrack.js库实现实时监测手部运动(推荐)
2021/02/08 Javascript
vue打开新窗口并实现传参的图文实例
2021/03/04 Vue.js
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
在Windows服务器下用Apache和mod_wsgi配置Python应用的教程
2015/05/06 Python
python邮件发送smtplib使用详解
2020/06/16 Python
Python如何实现转换URL详解
2019/07/02 Python
Python unittest工作原理和使用过程解析
2020/02/24 Python
20行Python代码实现视频字符化功能
2020/04/13 Python
CSS3 旋转立方体问题详解
2020/01/09 HTML / CSS
css3实现小箭头各种图形效果
2020/07/08 HTML / CSS
应用化学专业职业生涯规划书
2013/12/31 职场文书
总账会计岗位职责
2015/04/02 职场文书
Windows server 2012 R2 安装IIS服务器
2022/04/29 Servers
Django数据库(SQlite)基本入门使用教程
2022/07/07 Python