Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

VisJS Network - Have ability to select a group of nodes and edges by drawing a circle or rectangle that highlight a particular region #977

Closed
abcbaby opened this issue Jun 13, 2015 · 21 comments

Comments

@abcbaby
Copy link

abcbaby commented Jun 13, 2015

Do a quick highlight of nodes and edges by draw circle, rectangle, or free-hand on the network.

@josdejong
Copy link
Contributor

Thanks for your feature request.

@abcbaby
Copy link
Author

abcbaby commented Jun 26, 2015

I have created a sample page that have the ability to draw a rectangle using right-mouse click and selecting all the nodes/edges inside it. You can use it to incorporate into the main branch if you'd like. I have put it here: https://github.com/dragonzone/JsSamplerApp, go to "Link Analysis" to view it.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Jun 26, 2015

Hi,

Your code seems very much intertwined with other libraries or frameworks. I'm not sure we can merge this into vis.

Your application looks cool though :)

Regards,

Alex

@abcbaby
Copy link
Author

abcbaby commented Jun 26, 2015

Yes, I use a variety of JS apis, just for my own references and how to use it. But for the draw selection, it's just using HTML 5 Canvas. If I have time, I'll create another page with just the drawing.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Jun 26, 2015

Could you explain to me the basic outline of what it is you've done? Do you draw on another canvas on top of the network?

Regards

@abcbaby
Copy link
Author

abcbaby commented Jun 26, 2015

I just reuse the canvas context that is provided by vis.js. Then I added listeners on right-mouse down/move/up, which draws the rectangle outline. Once outline is draws, I grab all the nodes (x, y coord.) and check if they are inside my rectangle.

You can check the link-analysis.js to view the source code.

BTW, your library is being used on a project that I am working on, which is I am customizing. I add some powerful feature in the example of what is there so far.

@abcbaby
Copy link
Author

abcbaby commented Jun 26, 2015

I used one of your demo example and have expanded on it. You can check out the source code here. The only other JS lib. I am using is jQuery. I hope this helps.

https://github.com/dragonzone/JsSamplerApp/blob/master/src/main/webapp/network/draw.htm

@abcbaby
Copy link
Author

abcbaby commented Jul 10, 2015

I tried pasting into JS Bin, but something is buggy with it, so I'll paste the whole page here, on how to highlight with RIGHT mouse drag. But I think it's better to use the LEFT mouse drag instead. Since vis.js network already use the left-mouse drag to drag the view, I think it's best is to have an icon/button on the network, where user can toggle between the drag view or highlight icon.

Below is the working example of highlight nodes using right mouse drag. See if you can add it.

<!doctype html>
<html>
<head>
  <title>Network | Basic usage</title>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.4.0/vis.min.js"></script>

  <style type="text/css">
    #network {
      width: 600px;
      height: 400px;
      border: 1px solid lightgray;
    }

    p {
      max-width:600px;
    }
  </style>
</head>
<body>

<p>
  You can draw on the canvas using normal HTML5 canvas functions. The before drawing will be behind the network, the after drawing will be in front of the network.
</p>

<div id="network"></div>

<script type="text/javascript">
  // create an array with nodes
  var nodes = new vis.DataSet([
    {id: 1, label: 'Node 1'},
    {id: 2, label: 'Node 2'},
    {id: 3, label: 'Node 3'},
    {id: 4, label: 'Node 4'},
    {id: 5, label: 'Node 5'}
  ]);

  // create an array with edges
  var edges = new vis.DataSet([
    {from: 1, to: 3},
    {from: 1, to: 2},
    {from: 2, to: 4},
    {from: 2, to: 5}
  ]);

// create a network
var container = $("#network");
var data = {
    nodes: nodes,
    edges: edges
};
var options = {
    layout: {randomSeed: 2},
    interaction:{
        dragView: false,
        multiselect: true
    }
};
var network;

var canvas;
var ctx;
var rect = {}, drag = false;
var drawingSurfaceImageData;

function saveDrawingSurface() {
   drawingSurfaceImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
}

function restoreDrawingSurface() {
    ctx.putImageData(drawingSurfaceImageData, 0, 0);
}

function selectNodesFromHighlight() {
    var fromX, toX, fromY, toY;
    var nodesIdInDrawing = [];
    var xRange = getStartToEnd(rect.startX, rect.w);
    var yRange = getStartToEnd(rect.startY, rect.h);

    var allNodes = nodes.get();
    for (var i = 0; i < allNodes.length; i++) {
        var curNode = allNodes[i];
        var nodePosition = network.getPositions([curNode.id]);
        var nodeXY = network.canvasToDOM({x: nodePosition[curNode.id].x, y: nodePosition[curNode.id].y});
        if (xRange.start <= nodeXY.x && nodeXY.x <= xRange.end && yRange.start <= nodeXY.y && nodeXY.y <= yRange.end) {
            nodesIdInDrawing.push(curNode.id);
        }
    }
    network.selectNodes(nodesIdInDrawing);
}

function getStartToEnd(start, theLen) {
    return theLen > 0 ? {start: start, end: start + theLen} : {start: start + theLen, end: start};
}

$(document).ready(function() {
    container.on("mousemove", function(e) {
        if (drag) { 
            restoreDrawingSurface();
            rect.w = (e.pageX - this.offsetLeft) - rect.startX;
            rect.h = (e.pageY - this.offsetTop) - rect.startY ;

            ctx.setLineDash([5]);
            ctx.strokeStyle = "rgb(0, 102, 0)";
            ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
            ctx.setLineDash([]);
            ctx.fillStyle = "rgba(0, 255, 0, 0.2)";
            ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
        }
    });

    container.on("mousedown", function(e) {
        if (e.button == 2) { 
            selectedNodes = e.ctrlKey ? network.getSelectedNodes() : null;
            saveDrawingSurface();
            var that = this;
            rect.startX = e.pageX - this.offsetLeft;
            rect.startY = e.pageY - this.offsetTop;
            drag = true;
            container[0].style.cursor = "crosshair";
        }
    }); 

    container.on("mouseup", function(e) {
        if (e.button == 2) { 
            restoreDrawingSurface();
            drag = false;

            container[0].style.cursor = "default";
            selectNodesFromHighlight();
        }
    });

    document.body.oncontextmenu = function() {return false;};
    network = new vis.Network(container[0], data, options);
    canvas = network.canvas.frame.canvas;
    ctx = canvas.getContext('2d');

});
</script>

</body>
</html>

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

Here is the actual example, which I think you can add to part of the vis.js network.

http://jsfiddle.net/kbj54bas/

Do right mouse click & drag.

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

But I've changed this code in our app to handle the left-mouse clicked instead. But we use a toggle button to toggle between the drag view & highlighting.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 11, 2015

Hi Dragon,

Looks cool! I think the toggle is indeed the way to go. One thing, why are you not using the afterDrawing event for rendering? Currently your code does not work if the physics are running. Using the render event would solve that. You also do not need to restore the surface or use the internals: network.canvas.frame.canvas;

Regards

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

I didn't notice that event, I'll have to try it out. Here's a little teaser in case you want to know how our app look like.

link-analysis-sample

@abcbaby abcbaby closed this as completed Sep 11, 2015
@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 11, 2015

Looks cool!

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

But think vis.js is lacking the highlight feature, which I notice a few others have, so think about it.

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

This code is pretty old, I tweaked it to use your dragStart, dragging, and dragEnd. When dragStart, I disabled the physics, do my drawing. Then when done, dragEnd, puts back the physics. I just added it. ;)

@abcbaby
Copy link
Author

abcbaby commented Sep 11, 2015

BTW, We reserved the right-mouse click so we can use the bootstrap context-menu to view the properties & other features of each nodes not visible from the pix. :)

@baragona
Copy link

dragonzone, do you mind sharing your code which uses dragStart/end, and disables physics when selecting?

@abcbaby
Copy link
Author

abcbaby commented Sep 18, 2015

Sure, you can get full code at: https://github.com/dragonzone/JsSamplerApp and run it if you want. However, in there, there is a file that handles the logic to calculate and draw the shape (https://github.com/dragonzone/JsSamplerApp/blob/master/src/main/webapp/js/link-analysis-highlight.js). The listeners are register here, https://github.com/dragonzone/JsSamplerApp/blob/master/src/main/webapp/js/link-analysis-listeners.js, starting line 40.

I have to tweak the vis.js a little in order for that to work. Here is the modified vis.js (moving the dragging even), https://raw.githubusercontent.com/dragonzone/JsSamplerApp/master/src/main/webapp/js/vis/vis.js. Search for "Andy Do" (my name :)), of course. I had firing of the dragging out side of

if (this.options.dragView === true) {

Since i need to fire the event regardless. Enjoy!

@amullier
Copy link

Hi !
I want to create the same functionnality as this jsbin (http://jsfiddle.net/kbj54bas/) but with the left button.
The "mousemove" event seems to work only with the right button. And the "dragging" event does not work when the dragView is false.
Can you suggest me a solution ?

@wimrijnders
Copy link
Contributor

Currently your code does not work if the physics are running.

I had the chance to play around with the demo, after adjusting it to latest version of vis.js 4.20.0. It works well, and I sort of consider the fact that selection only works when the nodes are still a good thing.

OTOH, I am aware that there are networks that are never still. I'll think about it a bit.

@strblr
Copy link

strblr commented Oct 20, 2017

Hey there,

I had to implement this right-click selection too. After playing around with the previous JSFiddle, I made my own version, based on then afterDrawing event and DOMtoCanvas : https://jsfiddle.net/ostrebler/qzk6kmyk/

Since the first version presented here saves the canvas surface once and for all when the selection starts and restores it each time the selection box changes, this made zooming, dragging, animations, hovering (and actually any redraw) resulting in weird unexpected behaviours. With this new version, everything works fine.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants