zabbix 拓扑图线缆标签 拓扑图中的线_有向图

图论中边是重要元素,它连接各个顶点构成拓扑图,有向图中,边具有方向性,在画布中表现为箭头,在实际应用中,边可以代表链路,链路上不只是有方向,还有流量,信号种类等信息,光用箭头表现力就不够了,可增加线条线型,以及流动效果来体现,这里介绍 Qunee 1.6 中线条流动效果的实现 


图论中边是重要元素,它连接各个顶点构成拓扑图,有向图中,边具有方向性,在画布中表现为箭头,在实际应用中,边可以代表链路,链路上不只是有方向,还有流量,信号种类等信息,光用箭头表现力就不够了,可增加线条线型,以及流动效果来体现,这里介绍 Qunee 1.6 中线条流动效果的实现 

zabbix 拓扑图线缆标签 拓扑图中的线_图论_02

 

虚线流动效果

虚线流动效果在 连线示例中有演示,使用虚线偏移量样式,不断增大,实现线条的流动

虚线流动代码

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

运行效果

定制流动效果

对于更高级的流动需求,需要定制来实现,原理是在线条上挂载一个小图标,让这个图标沿线移动,从而形成动画效果

实现代码

下面的代码实现在线条上移动小图标

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的类,详细代码如下

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

    }

}

使用如下

这里的第二个参数为图标数量,第三个参数为是否按百分比流动,如果按百分比流动,每次移动的距离为线条长度的百分之二,这意味着不同长度的线条流动一圈,花费的时间相同

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

})

运行效果

zabbix 拓扑图线缆标签 拓扑图中的线_链路_03