小編有幸在之前使用過React + AntDesign 實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的時(shí)序圖,但是后來有了更復(fù)雜的需求就更換了一種思路,那么今天我們就對(duì)于:“如何制作原生時(shí)序圖?”這個(gè)問題做個(gè)講解吧!
經(jīng)過思索后決定使用原聲js+css+html去實(shí)現(xiàn),因?yàn)樵昷s下性能是最優(yōu)的。下面先來說說新版本的需求:
- 左側(cè)以樹形結(jié)構(gòu)展示任務(wù),可折疊
- 右側(cè)展示任務(wù)運(yùn)行所耗時(shí)間的長(zhǎng)度
- 需要用線條鏈接任務(wù)之間的關(guān)系
- 右側(cè)可縮放查看詳細(xì)的任務(wù)狀態(tài)
- 縮放時(shí)圖形保持以鼠標(biāo)為中心向兩端成一定比例放大,放大時(shí)里面的文字描述不受影響
- 圖形縮放時(shí)表示任務(wù)耗時(shí)的時(shí)間以及坐標(biāo)需要跟隨圖像放大的比例進(jìn)行相應(yīng)變化
- 鼠標(biāo)在時(shí)序圖上移動(dòng)時(shí)出現(xiàn)一根線條提示當(dāng)前的時(shí)間以及信息
效果圖
圖一:
圖二:
實(shí)現(xiàn)難點(diǎn)
鼠標(biāo)縮放,x軸的縮放方式
鼠標(biāo)縮放產(chǎn)生時(shí)序圖X軸的縮放。時(shí)序圖的縮放,在這里提供三種思路:
- 做數(shù)據(jù)截取,按照一定的算法截取前后的數(shù)據(jù),然后重新渲染整個(gè)頁(yè)面
- 利用css3的scaleX對(duì)時(shí)序圖的dom做縮放
- 實(shí)際改變時(shí)序圖dom的width,里面的任務(wù)運(yùn)行的長(zhǎng)度,連接線條的長(zhǎng)度,任務(wù)運(yùn)行預(yù)計(jì)需要的時(shí)長(zhǎng)都以百分比顯示。
三種思路的優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):不需要去操作dom的css屬性,之間重新渲染,比較方便。缺點(diǎn):對(duì)于使用dom重繪,耗費(fèi)性能嚴(yán)重,大量任務(wù)渲染時(shí)性能很慢。
- 優(yōu)點(diǎn):只需改變dom的css,加載快,較流程。缺點(diǎn):計(jì)算麻煩,使用過scaleX的小伙伴會(huì)發(fā)現(xiàn)當(dāng)我X軸放大時(shí)垂直連接線會(huì)變寬,字體會(huì)橫向拉伸,都需要去反向縮小。
- 優(yōu)點(diǎn):加載快,很流暢,一次計(jì)算好元素所占寬度的占百分比,后面的操作都不需要去計(jì)算。缺點(diǎn):使用百分比計(jì)算會(huì)有一定誤差,放大到一定程度會(huì)看的出來。(綜合考慮,本人采用的是第三種)
// 計(jì)算寬度百分比的函數(shù)
// endTime: 任務(wù)的結(jié)束時(shí)間
// startTime: 任務(wù)的開始時(shí)間
// maxTime: 所有任務(wù)結(jié)束時(shí)間最大的值
// minTime: 所有任務(wù)開始時(shí)間最小的值
// time: 所有任務(wù)開始時(shí)間與結(jié)束時(shí)間的排序 升序
// task_width: 任務(wù)的長(zhǎng)度、水平連接線的長(zhǎng)度、垂直連接線的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;
};
鼠標(biāo)縮放,保持以鼠標(biāo)為中心,往兩邊放大
先放推理過程圖:
// 上圖解釋
// dom = 時(shí)序圖的dom元素
// domL1, domeL2 = dom.scrollLeft;
// domeL1表示前一次的dom.scrollLeft;
// domeL2表示當(dāng)前的dom.scrollLeft;
// scale 表示當(dāng)前的放大的比例
// scale1 表示上一次的放大比例
// tree_dom.offsetWidth表示左側(cè)樹的寬度
// clientX1 表示上一次的鼠標(biāo)位置距離時(shí)序圖左側(cè)的距離 = e.clientX - tree_dom.offsetWidth
// clientX2 表示當(dāng)前鼠標(biāo)位置距離時(shí)序圖的距離
// 以鼠標(biāo)為中心的縮放,公式為:
domL2 = domeL1(scale/scale1) + clientX1(scale/scale1) - e.clientX + tree_dom.offsetWidth
// 公式講解:
// 1. scale/scale1表示本次的縮放比例除以上一次的縮放比例,表示當(dāng)前的縮放比例
// 左側(cè)卷去的寬度在第二次縮放時(shí)也會(huì)跟著縮放,所以左側(cè)的寬度需要乘以縮放比例
// 鼠標(biāo)位置距離時(shí)序圖左側(cè)的寬度在縮放時(shí)也會(huì)跟著縮放,所以也要乘以縮放比例
// 最后面減去鼠標(biāo)位置距離時(shí)序圖左側(cè)的實(shí)際距離就等于縮放時(shí)左側(cè)卷去的長(zhǎng)度
// 頁(yè)面代碼
time_box_parent.scrollLeft = (time_box_parent.scrollLeft + e.clientX - tree_box_dom.offsetWidth) * (scale_x / scale_x1) - e.clientX + tree_box_dom.offsetWidth;
使用連線表示任務(wù)之間的關(guān)系
方案:
- 采用的時(shí)css3 + js + html5,用偽元素繪制。
- 用dom包裹直角圖片,設(shè)置其位置及高度。
- 用標(biāo)簽繪制
優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):不會(huì)增加多余的標(biāo)簽,對(duì)渲染有利。缺點(diǎn):父任務(wù)產(chǎn)生了多個(gè)子任務(wù),不好添加偽類及設(shè)置偽類的高度及寬度。
- 優(yōu)點(diǎn):方便,只要計(jì)算子任務(wù)距父任務(wù)的高度即可。缺點(diǎn):任務(wù)過多時(shí)圖片會(huì)非常多,很影響性能
- 優(yōu)點(diǎn):?jiǎn)为?dú)控制每個(gè)元素的高度及位置,可控性高,可添加反饋色。缺點(diǎn):添加了較多的元素,對(duì)渲染產(chǎn)生影響(本人使用的是第三種,這是一個(gè)笨方法,有更好方法的大佬,可以提供建議,多謝)
實(shí)現(xiàn)思路:
用一個(gè)變量記錄每個(gè)任務(wù)的層級(jí)深度,層級(jí)深都以當(dāng)前任務(wù)的父任務(wù)為起點(diǎn),就是說是從哪個(gè)任務(wù)產(chǎn)生的當(dāng)前任務(wù),同級(jí)的子任務(wù)進(jìn)行累加操作。用累加的變量按照一定的比例獲取垂直連線的高度以及水平連線的top值,水平連線的長(zhǎng)度由任務(wù)的創(chuàng)建時(shí)間和開始時(shí)間決定。(使用上面的寬度百分比函數(shù))
時(shí)間單位:天、時(shí)、分、秒
這個(gè)比較簡(jiǎn)單,實(shí)現(xiàn)思路:
因?yàn)楸綿emo的時(shí)間4刻度是個(gè)刻度,判斷最小時(shí)間戳與最大時(shí)間戳之間的差除以4,是否還有一天的時(shí)間(60 * 60 * 24,換算成秒),從大到小的降序獲取時(shí)間單位。
總結(jié)
那么對(duì)于以上這些內(nèi)容就是有關(guān)于:“如何制作原生時(shí)序圖?”這個(gè)問題的全部?jī)?nèi)容,希望以上所述的內(nèi)容和做法對(duì)大家有所幫助,如果有喜歡前端的小伙伴可以在W3Cschool網(wǎng)站中進(jìn)行學(xué)習(xí)!