拓撲圖線條流動效果

圖論中邊是重要元素,它鏈接各個頂點構成拓撲圖,有向圖中,邊具備方向性,在畫布中表現爲箭頭,在實際應用中,邊能夠表明鏈路,鏈路上不僅是有方向,還有流量,信號種類等信息,光用箭頭表現力就不夠了,可增長線條線型,以及流動效果來體現,這裏介紹 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

FlowingSupport類代碼

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();
})

運行效果

在線演示

http://demo.qunee.com/#Flowing%20Demorem

相關文章
相關標籤/搜索