almende / vis

⚠️ This project is not maintained anymore! Please go to https://github.com/visjs
7.85k stars 1.48k forks source link

How to give traffic to my current network, which is having Nodes, Edges, Groups and Arrows #3419

Open Girish-Reddy opened 6 years ago

Girish-Reddy commented 6 years ago

capture

Here I am attching My network Image,, I wanted to implement the traffic for this, My current Json structure for Edges is like this {"arrows": "to", "to": 194, "from": 39}, Should i Add Anything additionally ??

I want my network arrows should show like this kind of animation https://cloud.githubusercontent.com/assets/4054499/8289887/041a53d8-18d4-11e5-9363-731673ea1c63.gif

wimrijnders commented 6 years ago

If you didn't add the link to the animation, I wouldn't have understood what you wanted. This is not part of vis.js itself, but some bright user managed to get it working.

Found it, #3300, scroll down to code block starting with:

// Purpose:  animate traffic from one node to another.

This code works! And it does exactly what happens in the animation. Special shoutout to @hackerxiaobai for figuring this out.

Girish-Reddy commented 6 years ago

I could not find proper solution for my question in #3300 , Please give me the lengthy answer, In addition to that, I have one more question, How to reduce the length of that node, For example: I wanted to reduce the height of grey color line? In what way i can do that?

wimrijnders commented 6 years ago

Then sorry I don't understand the question. Will you please explain it again?

The code block I passed does what the demo link in your first comment does. You can copy it over to your code and test it.

As for setting edge lengths (from #3217) {

 // Left out value fields for clarity
 var edges = [
        {from: 1, to: 2, length: 300},
        {from: 1, to: 3, length: 100},
        {from: 2, to: 4},
        {from: 2, to: 5}
    ];
Girish-Reddy commented 6 years ago

Hi, First of all, Thanks for the reply.

What I am saying is, If you see the above network image which I have given, In that i have one parent node called 231166, all nodes attached to that are child nodes. on hover of each child node , It is pointing towards the parent node with arrow mark. Now my requirement is in place of simply showing the arrow mark I wanted to do some animation like this https://cloud.githubusercontent.com/assets/4054499/8289887/041a53d8-18d4-11e5-9363-731673ea1c63.gif Hope You got it this time.

And for setting edges, is there any alternative way to set for all nodes as equal length in order to give for each and every node???

wimrijnders commented 6 years ago

OK, thanks. That explanation helped, I understand your request now.

Seeing that all the elements you require exist, this should be possible. I'll have to think about it a bit, will get back to this.

And for setting edges, is there any alternative way to set for all nodes as equal length in order to give for each and every node???

I gave you one way; namely setting the length. It should be possible to define this as a general option for all edges. Let me check that first.

Another way is to have fixed coordinates for all nodes, meaning you will have to set them yourself. I don't know if this is an option for you.

hackerxiaobai commented 6 years ago

yes, maybe i understand you. you want to Let the ball roll along the edge. is right? maybe this code is helpful fou you.

image

// Author: Edvin Eshagh
//
// Date: 6/22/2015
//
// Purpose:  animate traffic from one node to another.
//
// Usage: call *.animateTraffic method, passing array of edges to animate
//
// Example:
//
//       var myNodes = new vis.DataSet([  
//         {id: 1, label: 'Node 1'}, {id: 2, label: 'Node 2'}, {id: 3, label: 'Node 3'} ]);
//      
//       var myEdges = new vis.DataSet([
//           {id:1, from:1, to:2}, {id:2, from:2, to:1},
//           {id:3, from:2, to:3}, {id:4, from:3, to:1}]);
//       
//       var container = document.getElementById('mynetwork');
//       
//       var data = {nodes: myNodes, edges: myEdges};
//      
//       var options = {};
//      
//       var network = new vis.Network(container, data, options);
//      
//        function animate() {
//         network.animateTraffic([
//             {edge:1},
//             {edge:2, trafficSize:2}, 
//             {edge:3, trafficSize:5, isBackward: true}
//         ]);
//       }
 //
// Known issue: Does not render traffic animation "on top of" the edges in IE
//

vis.Network.prototype.animateTraffic =
    function(edgesTrafficList,
             onPreAnimationHandler, 
             onPreAnimateFrameHandler, 
             onPostAnimateFrameHandler, 
             onPostAnimationHandler) {

    var thisAnimator  = this;

    var trafficAnimator = {

        thisNetwork : this,    

        trafficCanvas : null,
        trafficCanvasCtx : null,
        trafficCanvasWidth : null,
        trafficCanvasHeight: null,

        reportedErrors : {},  // Helps to avoid reporting the same error in multiple setTimeout events

        edgesTrafficList : edgesTrafficList ,

        onPreAnimateFrame  : onPreAnimateFrameHandler,
        ontPostAnimateFrame: onPostAnimateFrameHandler,
        onPreAnimation : onPreAnimationHandler,
        onPostAnimation : onPostAnimationHandler,

        //////////////////////////////////////////////////////////////
        //
        // return object {edge, trafficSize, isBackward}
        parseEdgeTraffic : function (edgeTraffic) {
            var edge;
            if (edgeTraffic.edge) {
                edge =  edgeTraffic.edge.edgeType 
                    ? edgeTraffic.edge
                    : this.thisNetwork.body.edges[edgeTraffic.edge.id] 
                      || this.thisNetwork.body.edges[edgeTraffic.edge]
                    ;
            }
            else {
                edge = this.thisNetwork.body.edges[edgeTraffic];
            }

            return {
                edge: edge,
                trafficSize : edgeTraffic.trafficSize || 1,
                isBackward : edge && edgeTraffic.isBackward 
            };
        },

        //////////////////////////////////////////////////////////////
        //
        clearAnimationCanvas : function () {
            this.trafficCanvasCtx.save();
            this.trafficCanvasCtx.setTransform(1, 0, 0, 1, 0, 0);
            this.trafficCanvasCtx.clearRect(0,0, this.trafficCanvasWidth, this.trafficCanvasHeight);
            this.trafficCanvasCtx.restore();
        },

        //////////////////////////////////////////////////////////////
        //
        getNetworkTrafficCanvas : function() {

            this.trafficCanvas = this.thisNetwork.body
                .container.getElementsByClassName('networkTrafficCanvas')[0];

            if ( this.trafficCanvas == undefined) {

                var frame = this.thisNetwork.canvas.frame;
                this.trafficCanvas = document.createElement('canvas');
                this.trafficCanvas.className = 'networkTrafficCanvas';
                this.trafficCanvas.style.position = 'absolute';
                this.trafficCanvas.style.top = this.trafficCanvas.style.left = 0;
                this.trafficCanvas.style.zIndex = 1;
                this.trafficCanvas.style.pointerEvents='none';
                this.trafficCanvas.style.width = frame.style.width;
                this.trafficCanvas.style.height = frame.style.height;
                // ��������������
//              this.trafficCanvas.width = frame.canvas.width;
//              this.trafficCanvas.height = frame.canvas.height;

                //���������Լ��ӵģ��޸ĵ�bug
                this.trafficCanvas.width = frame.canvas.clientWidth;
                this.trafficCanvas.height = frame.canvas.clientHeight;

                frame.appendChild(this.trafficCanvas);
            }

            return this.trafficCanvas;
        },

        //////////////////////////////////////////////////////////////
        //
        animateFrame : function (offset, frameCounter) {

            this.clearAnimationCanvas();

            var maxOffset = .9;

            var reportedError = {};

            if (offset > maxOffset) {
                if (this.onPostAnimation) this.onPostAnimation(this.edgesTrafficList);
                return;
            }
            for(var i in this.edgesTrafficList) {

                var edgeTraffic = this.parseEdgeTraffic(this.edgesTrafficList[i]);

                if (!edgeTraffic.edge) {
                    if (!this.reportedErrors[this.edgesTrafficList[i]]) {
                        console.error ("No edge path defined: " , this.edgesTrafficList[i]);
                        this.reportedErrors[this.edgesTrafficList[i]] = true;
                    }
                    continue;
                }

                if (this.onPreAnimateFrameHandler 
                 && this.onPreAnimateFrameHandler(edgeTraffic,frameCounter) === false ) {
                    continue;
                }

  //              var s = edgeTraffic.edge.body.view.scale;
  //              var t = edgeTraffic.edge.body.view.translation;
                var p = edgeTraffic.edge.edgeType.getPoint(
                edgeTraffic.isBackward ? maxOffset - offset: offset);

//              this.trafficCanvasCtx.beginPath();
//                  this.trafficCanvasCtx.arc(p.x, p.y, parseInt(edgeTraffic.trafficSize)+1 || 2, 0, Math.PI*2, false);
//                  this.trafficCanvasCtx.lineWidth=1;
//                  this.trafficCanvasCtx.strokeStyle="#000";
//                  this.trafficCanvasCtx.fillStyle = "red";
//                  this.trafficCanvasCtx.fill();
//                  this.trafficCanvasCtx.stroke();
//              this.trafficCanvasCtx.closePath();

                this.trafficCanvasCtx.beginPath();
                    this.trafficCanvasCtx.arc(p.x, p.y, parseInt(edgeTraffic.trafficSize) || 1, 0, Math.PI*2, false);
                    this.trafficCanvasCtx.lineWidth=1;
                    this.trafficCanvasCtx.strokeWidth=4;
                    this.trafficCanvasCtx.strokeStyle="rgba(57,138,255,0.1)";
                    this.trafficCanvasCtx.fillStyle = "#1262e3";
                    this.trafficCanvasCtx.fill();
                    this.trafficCanvasCtx.stroke();
                this.trafficCanvasCtx.closePath();

                if (this.onPostAnimateFrame 
                 && this.onPostAnimateFrame(edgeTraffic,frameCounter) === false) {
                    if (this.onPostAnimation) this.onPostAnimation(this.edgesTrafficList);
                    return;
                }

            }

            setTimeout(this.animateFrame.bind(this), 10, offset+.01, frameCounter++);
        },

        //////////////////////////////////////////////////////////////
        //
        initalizeCanvasForEdgeAnimation : function () {

            this.reportedErrors = {};

            if (Object.prototype.toString.call( this.edgesTrafficList ) !== '[object Array]') {
                this.edgesTrafficList = [this.edgesTrafficList];
            }

            this.trafficCanvas = this.getNetworkTrafficCanvas();

            this.trafficCanvasCtx = this.trafficCanvas.getContext('2d');
            this.trafficCanvasWidth = this.trafficCanvasCtx.canvas.width;
            this.trafficCanvasHeight= this.trafficCanvasCtx.canvas.height;

            var edgeTraffic = this.parseEdgeTraffic(this.edgesTrafficList[0]);

            var s = this.thisNetwork.getScale();// edgeTraffic.edge.body.view.scale;
            var t = this.thisNetwork.body.view.translation; //edgeTraffic.edge.body.view.translation;

            this.trafficCanvasCtx.setTransform(1, 0, 0, 1, 0, 0);
            this.trafficCanvasCtx.translate(t.x, t.y);
            this.trafficCanvasCtx.scale(s, s);
/*
            if (!this.onPreAnimation)
            this.onPreAnimation = function(edgesTrafficList) {
                // remove the value from the source traffic
                for (var i in edgesTrafficList) {
                    edgeTraffic = this.parseEdgeTraffic(edgesTrafficList[i]);
                    if (!edgeTraffic.edge) {
                        continue;
                    }
                    var fromValue = edgeTraffic.edge.from.getValue()
                    if (parseFloat(fromValue)) {

                        var newValue = fromValue +
                            (edgeTraffic.isBackward ? -1 : 1) * -edgeTraffic.trafficSize;

                        this.thisNetwork.body.data.nodes
                            .update({id:edgeTraffic.edge.fromId, value:Math.max(0, newValue)});
                    }
                }
            };

            //////////////////////////////////////////////////////////////
            // 
            if (!this.onPostAnimation)
            this.onPostAnimation = function(edgesTrafficList) {
                // add the value from the source traffic to target
                for (var i in edgesTrafficList) {
                    edgeTraffic = this.parseEdgeTraffic(edgesTrafficList[i]);
                    if (!edgeTraffic.edge) {
                        continue;
                    }
                    var toValue = edgeTraffic.edge.to.getValue()
                    if (parseFloat(toValue)) {

                    var newValue = (toValue || 0) 
                        + (edgeTraffic.isBackward ? -1 : 1) * edgeTraffic.trafficSize;

                        this.thisNetwork.body.data.nodes
                            .update({id:edgeTraffic.edge.toId, value: newValue});
                    }
                }
            };
            */
        },

    };

    trafficAnimator.initalizeCanvasForEdgeAnimation();

    if (trafficAnimator.onPreAnimation 
     && trafficAnimator.onPreAnimation(trafficAnimator.edgesTrafficList) === false) return;

    trafficAnimator.animateFrame( 0.1 /*animationStartOffset*/, 0 /*frame*/);

};

vis.Network.prototype.animateTrafficOnPostAnimation = function(edgesTrafficList) {
    // add the value from the source traffic to target
    for (var i in edgesTrafficList) {
        edgeTraffic = this.parseEdgeTraffic(edgesTrafficList[i]);
        if (!edgeTraffic.edge) {
            continue;
        }
        var toValue = edgeTraffic.edge.to.getValue()
        if (parseFloat(toValue)) {

        var newValue = (toValue || 0) 
            + (edgeTraffic.isBackward ? -1 : 1) * edgeTraffic.trafficSize;

            this.thisNetwork.body.data.nodes
                .update({id:edgeTraffic.edge.toId, value: newValue});
        }
    }
};

vis.Network.prototype.animateTrafficOnPreAnimation = function(edgesTrafficList) {
    // remove the value from the source traffic
    for (var i in edgesTrafficList) {
        edgeTraffic = this.parseEdgeTraffic(edgesTrafficList[i]);
        if (!edgeTraffic.edge) {
            continue;
        }
        var fromValue = edgeTraffic.edge.from.getValue()
        if (parseFloat(fromValue)) {

            var newValue = fromValue +
                (edgeTraffic.isBackward ? -1 : 1) * -edgeTraffic.trafficSize;

            this.thisNetwork.body.data.nodes
                .update({id:edgeTraffic.edge.fromId, value:Math.max(0, newValue)});
        }
    }
};
wimrijnders commented 6 years ago

Demo for traffic on hover event, using @hackerxiaobai's code above.

Girish-Reddy commented 6 years ago

Hi Thank you so much for the solution.

I have one small issue, I couldn't find proper documentation for this also, so i am asking here.

arrowsize

If you see the above Image, There is an arrow showing from 231166 to 231196. I wanted that the arrowheads that point to a node should be smaller by 50%. Can you please help me in this?

hackerxiaobai commented 6 years ago

image

Do you would like use it? maybe it can help you.

wimrijnders commented 6 years ago

You can adjust it like this:

  var options = {
...
    edges: {
      arrows: {
        to: {
          scaleFactor: 0.5
        }
      }
    }
...
  };
Girish-Reddy commented 6 years ago

Thank you So much Its working perfectly

wimrijnders commented 6 years ago

Our pleasure. If you are done with this issue, please close it!