圖論中邊是重要元素,它鏈接各個頂點構成拓撲圖,有向圖中,邊具備方向性,在畫布中表現爲箭頭,在實際應用中,邊能夠表明鏈路,鏈路上不僅是有方向,還有流量,信號種類等信息,光用箭頭表現力就不夠了,可增長線條線型,以及流動效果來體現,這裏介紹 Qunee 1.6 中線條流動效果的實現 動畫
虛線流動效果在 連線示例中有演示,使用虛線偏移量樣式,不斷增大,實現線條的流動ui
var offset = 0; var index = 0; var timer = setInterval(function(){ offset += -1; // edge2.setStyle(Q.Styles.EDGE_LINE_DASH_OFFSET, offset); edge1.setStyle(Q.Styles.EDGE_LINE_DASH_OFFSET, offset); index++; index = index%20; edge2.setStyle(Q.Styles.ARROW_TO_OFFSET, -0.3 -0.02 * (20 - index)); edge1.setStyle(Q.Styles.ARROW_FROM_OFFSET, {x: 0.3 + 0.02 * (20 - index), y: -10}); }, 150);
對於更高級的流動需求,須要定製來實現,原理是在線條上掛載一個小圖標,讓這個圖標沿線移動,從而造成動畫效果this
下面的代碼實如今線條上移動小圖標spa
var line = graph.createShapeNode("Line"); line.moveTo(-100, 0); line.lineTo(200, 0); line.curveTo(300, 0, 300, 100, 200, 100); line.lineTo(0, 100); line.closePath(); line.setStyle(Q.Styles.SHAPE_STROKE_STYLE, "#2898E0"); line.setStyle(Q.Styles.SHAPE_LINE_DASH, [8, 5, 0.1, 6]); line.setStyle(Q.Styles.SHAPE_STROKE, 3); line.setStyle(Q.Styles.LINE_CAP, "round"); line.setStyle(Q.Styles.SHAPE_OUTLINE_STYLE, "#fcfb9b"); var ui = new Q.ImageUI("images/flow.png"); ui.position = {x: 0, y: 0}; ui.size = {width: 20}; ui.renderColor = "#F00"; line.addUI(ui); setTimeout(function A(){ var x = ui.position.x + 20; ui.position = {x: x % (ui.parent.length || 1), y: 0}; line.invalidate(); setTimeout(A, 300); }, 100)
上面的實現太隨意,實際使用不太方便,能夠進一步封裝成專門用於流動支持的類,這樣能夠經過一個定時器實現全部的流動支持,咱們建立一個FlowingSupport的類,詳細代碼以下.net
function FlowingSupport(graph) { this.flowMap = {}; this.graph = graph; } FlowingSupport.prototype = { flowMap: null, length: 0, gap: 40, graph: null, addFlowing: function (edgeOrLine, count, byPercent) { var flowList = this.flowMap[edgeOrLine.id]; if(!flowList){ flowList = this.flowMap[edgeOrLine.id] = []; this.length++; } count = count || 1; while(--count >= 0){ var ui = new Q.ImageUI("network/images/flow.png"); ui.position = {x: 0, y: 0}; ui.size = {width: 20}; ui.renderColor = "#F00"; flowList.push(ui); flowList.byPercent = byPercent; edgeOrLine.addUI(ui); } }, removeFlowing: function(id){ var flowList = this.flowMap[id]; if(!flowList){ return; } var edgeOrLine = this.graph.getElement(id); if(edgeOrLine){ flowList.forEach(function(ui){ edgeOrLine.removeUI(ui); }) } this._doRemove(id); }, _doRemove: function(id){ delete this.flowMap[id]; this.length--; }, timer: null, perStep: 10, stop: function(){ clearTimeout(this.timer); }, start: function(){ if(this.timer){ clearTimeout(this.timer); } var offset = 0; var scope = this; scope.timer = setTimeout(function A() { if (!scope.length) { scope.timer = setTimeout(A, 2000); offset = 0; return; } offset += 1; for(var id in scope.flowMap){ var ui = scope.graph.getUI(id); if(!ui){ scope._doRemove(id); continue; } var lineLength = ui.length; if(!lineLength){ continue; } var flowList = scope.flowMap[id]; if(flowList.byPercent){ //按百分比,0 - 1跑完整條線,線長度不一樣,速度也不一樣,跑完一圈的時間相同 var x = offset * 2; var gap = 15; scope.flowMap[id].forEach(function(ui){ ui.position = {x: (x % 100) / 100, y: 0}; x += gap; }); }else{ //按固定距離移動,速度相同,線條越長跑完一圈的時間越長 var x = offset * scope.perStep; scope.flowMap[id].forEach(function(ui){ ui.position = {x: x % lineLength, y: 0}; x += scope.gap; }); } scope.graph.invalidateUI(ui); //dashed line var data = ui.data; if(data instanceof Q.Edge){ if(data.getStyle(Q.Styles.EDGE_LINE_DASH)){ data.setStyle(Q.Styles.EDGE_LINE_DASH_OFFSET, -offset); } }else if(data instanceof Q.ShapeNode){ if(data.getStyle(Q.Styles.SHAPE_LINE_DASH)) { data.setStyle(Q.Styles.SHAPE_LINE_DASH_OFFSET, -offset); } } } scope.timer = setTimeout(A, 200); }, 200); } }
這裏的第二個參數爲圖標數量,第三個參數爲是否按百分比流動,若是按百分比流動,每次移動的距離爲線條長度的百分之二,這意味着不一樣長度的線條流動一圈,花費的時間相同prototype
var flowingSupport = new FlowingSupport(graph); flowingSupport.addFlowing(edge, 3); flowingSupport.addFlowing(edge2, 1); flowingSupport.addFlowing(line, 1, true); flowingSupport.addFlowing(line2, 2, true); graph.callLater(function(){ flowingSupport.start(); })