Custom edge drawing function in vis.js - javascript

I'm using the vis.js library to draw a network but I need to customize the way the edges are drawn. For example, I would like to draw let's say 50% of the edge in red and the other 50% in blue.
Is there a way to do this?

Finally found a way to do it:
var nodes = new vis.DataSet
([
{id: 1, label: '1'},
{id: 2, label: '2'},
]);
var edges = new vis.DataSet
([
{from: 1, to: 2, color:'red'},
]);
var graph = {nodes: nodes, edges: edges};
var network = new vis.Network(container, graph, options);
var percent = 50;
network.on("afterDrawing", function (ctx)
{
var pos = network.getPositions([1, 2]);
ctx.strokeStyle = ctx.filStyle = 'green';
ctx.moveTo(pos[1].x, pos[1].y);
ctx.lineTo(pos[1].x + (pos[2].x-pos[1].x)*percent/100, pos[1].y + (pos[2].y - pos[1].y)*percent/100);
ctx.fill();
ctx.stroke();
});

You cannot directly customize parts of an edge but you can create two different edges (each with its own style) using a dummy invisible node serving as a connector. Since the dummy node is invisible, the two edges are going to look like two parts of the same edge.
For example, say you want to connect two nodes with a half-green-half-red edge:
var nodes = new vis.DataSet([
{id: 1, label: '1'},
{id: 2, label: '2'},
{id: 'dummy', hidden: true}
]);
var edges = new vis.DataSet([
{from: 1, to: 'dummy', color:'red'},
{from: 'dummy', to: 2, color:'green'}
]);
var graph = {nodes: nodes, edges: edges};

Related

Avoiding overlapping edges with minimal physics in vis.js

I'm using vis.js to build a story visualization tool, and a key feature is to allow authors to manually position nodes via dragging. There's also often several edges with the same origin and destination nodes. Without physics, these edges overlap.
Currently to avoid edge overlap, I enable physics for a small interval whenever a new edge is created to repel any overlapping edges from each other. Ideally I would have physics always disabled and edges would not overlap, but I don't think that is possible.
Are there any recommendations for how to apply vis physics so that it's disabled on node drag, stabilizes quickly also prevents edge overlap?
If anyone comes across this issue, the solution is to calculate the roundness for each edge, based on how many edges have the same origin and destination node.
example: http://jsbin.com/wojanuboxi/edit?html,js,output
var nodes = new vis.DataSet([
{id: 1, label: '1'},
{id: 2, label: '2'},
{id: 3, label: '3'}
]);
var edges = new vis.DataSet([
{id: 1, from: 1, to: 2, smooth: {type: 'curvedCW', roundness: 0.2}},
{id: 2, from: 1, to: 2, smooth: {type: 'curvedCW', roundness: -2.2}},
{id: 5, from: 1, to: 2, label: 5, smooth: {type: 'curvedCW', roundness: 0.4}},
{id: 6, from: 1, to: 2, label: 6, smooth: {type: 'curvedCW', roundness: -2.4}},
{id: 3, from: 1, to: 3, smooth: {type: 'curvedCW', roundness: -2.1}},
{id: 4, from: 1, to: 3, smooth: {type: 'curvedCW', roundness: 0.1}}
]);
var data = {
nodes: nodes,
edges: edges
};
var options = {
physics: false,
layout: {
hierarchical: {
direction: 'UD'
}
}
};
var networkContainer = document.getElementById('networkContainer');
var network = new vis.Network(networkContainer, data, options);
After disabling the physics variable, I couldn't find a useful solution for the overlap problem. for the edge. I have created a temporary solution for this.this can solve the overlap problem for a small number of edges. but for too many edges there will be overlap problem again. The roundness value sets the roundness of the edge. If we give it random values ​​in a negative and positive range, we may be out of luck. :)
getConnectedEdgesCountAndCreateRandomRoundness(toRouterId: number, fromRouterId: number): number {
var randomRoundness: number = 0;
var connectedEdgesCount = this.network.getConnectedEdges(toRouterId).filter(value => this.network.getConnectedEdges(fromRouterId).includes(value)).length;
if(connectedEdgesCount === 0){
randomRoundness = 0;
}
else if (connectedEdgesCount === 1){
randomRoundness = this.generateRandomNumber(-0.25,0.25);
}
else if (connectedEdgesCount === 2){
randomRoundness = this.generateRandomNumber(-0.5,0.5);
}
else {
randomRoundness = this.generateRandomNumber(-1.25,1.25);
}
return randomRoundness;
}
var randomRoundness = this.getConnectedEdgesCountAndCreateRandomRoundness(this.toRouterId,this.fromRouterId);
this.edges.add({
id: this.circuitEdge.id,
from: this.fromRouterNode.id,
to: this.toRouterNode.id,
label: this.circuitEdge.name,
type: this.circuitEdge.type,
color: visEdgeColor,
smooth: { enabled: true, type: "curvedCW", roundness: randomRoundness}
});

vis.js - Place node manually

How do I set a node's position in vis.js?
I want to initially position at least one node manually.
I know that a node has the options x and y. I set both, and also tried variations of layout options (randomSeed, improvedLayout, hierarchical), the node was never placed where I set it.
Here's the simple network I defined:
nodes = new vis.DataSet([
{id: 1, shape: 'circularImage', image: DIR + '1_circle', label:"1", x: 200, y: 100},
{id: 2, shape: 'circularImage', image: DIR + '2_circle', label:"2"},
{id: 3, shape: 'circularImage', image: DIR + '3_circle', label:"3"},
]);
edges = [
{id: "01-03", from: 1, to: 3, length: 300, label: '1 - 3'},
{id: "02-03", from: 2, to: 3},
];
var container = document.getElementById('graphcontainer');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
borderWidth: 4,
size: 30,
color: {
border: '#222222',
background: '#666666'
},
font:{
color:'#000000'
}
},
edges: {
color: 'lightgray'
},
//layout: {randomSeed:0}
//layout: {hierarchical: true}
layout: {
randomSeed: undefined,
improvedLayout:true,
hierarchical: {
enabled:false,
levelSeparation: 150,
direction: 'UD', // UD, DU, LR, RL
sortMethod: 'hubsize' // hubsize, directed
}
}
};
network = new vis.Network(container, data, options);
The node is placed, but not at the point I set (200,100), but at another position.
I haven't found an example for explicitly setting a node's position on the vis.js page. Could someone please provide one? Thanks!
You can indeed set a fixed position for a node by setting its x and y properties, and yes, this feature works and is not broken.
The x and y position of a node does not mean a position in pixels on the screen, but is a fixed position in the Networks coordinate system. When you move and zoom in the Network, the fixed items will move and zoom too, but they will always keep the same position relative to each other. It's like your home town has a fixed location (long, lat) on earth, but you can still zoom and move your town in Google Maps.
EDIT: To achieve what you want, you can fix zooming and moving, and adjust the viewport such that it matches the pixels of the HTML canvas, here is a demo:
// create an array with nodes
var nodes = new vis.DataSet([
{id: 1, label: 'x=200, y=200', x: 200, y: 200},
{id: 2, label: 'node 2', x: 0, y: 0},
{id: 3, label: 'node 3', x: 0, y: 400},
{id: 4, label: 'node 4', x: 400, y: 400},
{id: 5, label: 'node 5', x: 400, y: 0}
]);
// create an array with edges
var edges = new vis.DataSet([
{from: 1, to: 2, label: 'to x=0, y=0'},
{from: 1, to: 3, label: 'to x=0, y=400'},
{from: 1, to: 4, label: 'to x=400, y=400'},
{from: 1, to: 5, label: 'to x=400, y=0'}
]);
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var width = 400;
var height = 400;
var options = {
width: width + 'px',
height: height + 'px',
nodes: {
shape: 'dot'
},
edges: {
smooth: false
},
physics: false,
interaction: {
dragNodes: false,// do not allow dragging nodes
zoomView: false, // do not allow zooming
dragView: false // do not allow dragging
}
};
var network = new vis.Network(container, data, options);
// Set the coordinate system of Network such that it exactly
// matches the actual pixels of the HTML canvas on screen
// this must correspond with the width and height set for
// the networks container element.
network.moveTo({
position: {x: 0, y: 0},
offset: {x: -width/2, y: -height/2},
scale: 1,
})
#mynetwork {
border: 1px solid black;
background: white;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.9.0/vis.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.9.0/vis.min.css" rel="stylesheet" type="text/css" />
<p>The following network has a fixed scale and position, such that the networks viewport exactly matches the pixels of the HTML canvas.</p>
<div id="mynetwork"></div>
Documentation says that nodes positioned by the layout algorithm
When using the hierarchical layout, either the x or y position is set
by the layout engine depending on the type of view
You can put they in to explicit points but I would not recommend this - it's not the correct way for the work with the graphs - better review your task - maybe you do not need graphs (or your do not need to put points in to exactly position).
Anyway - if you really want to put in to some position then you need to use random layout with the fixed option set to true or physic option set to false
var DIR = 'http://cupofting.com/wp-content/uploads/2013/10/';
nodes = new vis.DataSet([
{id: 1, shape: 'circularImage', image: DIR + '1-circle.jpg', label:"1", x:0, y:0},
{id: 2, shape: 'circularImage', image: DIR + '2-circle.jpg', label:"2", x:100, y:0},
{id: 3, shape: 'circularImage', image: DIR + '3-circle.jpg', label:"3", x:0, y:100},
]);
edges = [
{id: "01-03", from: 1, to: 3, length: 300, label: '1 - 3'},
{id: "02-03", from: 2, to: 3},
];
var container = document.getElementById('graphcontainer');
var data = {
nodes: nodes,
edges: edges
};
var options = {
physics:{
stabilization: true,
},
nodes: {
borderWidth: 4,
size: 10,
//fixed:true,
physics:false,
color: {
border: '#222222',
background: '#666666'
},
font:{
color:'#000000'
}
},
edges: {
color: 'lightgray'
},
layout: {randomSeed:0}
};
network = new vis.Network(container, data, options);
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.9.0/vis.min.js"></script>
<div id="graphcontainer" style="border: 1px solid red; width:300px; height:300px; "> </div>
:) I just did this for the first time this morning. X = 0 and Y = 0 for a graph start centered, not at the top left of the canvas. There is a fixed attribute of the node that you can set to true for both x and y on a node with its x and y values set and have other nodes use physics in relation to it.
Look at the full options tab on page
http://visjs.org/docs/network/nodes.html#
and you'll see this piece:
fixed: {
x:false,
y:false
},

How to set the image size in Vis.js network graph

I am building a network graph using vis.js
The problem is, how do I make all the images the same size?
(see live example here --> comparison of wordpress & drupal)
here's the graph code:
var nodes = [];
nodes.push({
id: 7,
shape: 'image',
image: '/static/windows8_icons/PNG/Industry/circuit/circuit-26.png',
label: 'sharepoint',
widthMin: 20,
widthMax: 20
});
edges.push({
from: 1,
to: 7,
length: 100
});
var data = {
nodes: nodes,
edges: edges
};
var options = {
smoothCurves: false,
stabilize: false,
nodes: {
shape: 'image',
radius: 24,
fontSize: 18,
widthMin: 20,
widthMax: 20
},
edges: {
width: 2
}
};
network = new vis.Network(container, data, options);
Go for size attribute of node.
Example
nodes:{shape:'image',size:20}
Reference: http://visjs.org/docs/network/nodes.html

jQuery Flot Chart add label per series

I am using http://www.flotcharts.org/ library to draw 2 connected series.
I can create Graph successfuly, you can see my JSFIDDLE below.
To do:
The problem is I want to add one label to the top-center of each series.
And I want to add label in such a way that if graph is resized it stays at top-center of series.
How can I do that ?
IMAGE:
JSFIDDLE:
http://jsfiddle.net/bababalcksheep/ktZ5X/2/
HTML/CSS:
html, body {height: 100%; }
JS:
var options = {
series: {
lines: { show: true,lineWidth: 2,fill: true},
points: { show: true,radius: 3,lineWidth: 1},
shadowSize: 2
},
legend: { show: false}
};
var DATA = [{
"label": "Group-1",
"data": [
[0.25, 0.25],
[0.5, 0.5],
[0.875, 0.875],
[1, 1]
]
}, {
"label": "Group-2",
"data": [
[1, 0.5],
[1.25, 0.25],
[1.5, 0.5],
[1.88, 0.875],
[2, 1]
]
}];
var plot = $.plot("#placeholder", DATA, options);
I agree with #iLikePrograms adding it in a hook event is the best approach. Here's an updated fiddle.
In your options add:
hooks: { drawSeries : [addLabel] }
Where the addLabel function is:
addLabel = function(plot, ctx, series){
var xaxis = series.xaxis;
var yaxis = series.yaxis;
// space midway on series
var x = (series.data[series.data.length-1][0] + series.data[0][0])/2;
// just below top of plot
var y = yaxis.max - (yaxis.tickSize / 2);
ctx.font = "16px 'Segoe UI'";
ctx.fillStyle = "black";
var text = series.label;
ctx.fillText(text, xaxis.p2c(x), yaxis.p2c(y)); // add the label
}
You can use the comments plugin for that. See this updated fiddle for a start.
New options:
comment: {
show: true
},
comments: [{
x: 0.625,
y: 1,
contents: "Group-1"
}, {
x: 1.5,
y: 1,
contents: "Group-2"
}]

Google charts API scatter chart with legend and other colors

I have this one example:
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart1);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart1() {
var data = new google.visualization.DataTable(
{
cols: [
{id: 'A', label: 'A', type: 'number'},
{id: 'B', label: 'B', type: 'number'},
{id: 'C', label: 'C', type:'tooltip', p:{role:'tooltip'}}
],
rows: [
{c:[{v: 2}, {v: 3}, {v:'Allen'}]},
{c:[{v: 4}, {v: 2}, {v:'Tom'}]},
{c:[{v: 1}, {v: 3}, {v:'Sim'}]}
]
})
var options = {
title: 'Age vs. Weight comparison',
hAxis: {title: 'Age', minValue: 1, maxValue: 5},
vAxis: {title: 'Weight', minValue: 1, maxValue: 5},
legend: ''
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart_scatter_container'));
chart.draw(data, options);
}
http://jsfiddle.net/eAWcC/1/
when i hover once data, tooltip will see me label for this data. That is good.
But I want to see all the values ​​are different color and placed in the legend.
How to do it?
The columns in the datatable of a scatterchart are the ones that are shown in the legend, and are colored differently. In order to display them separately you need to rearrange your data so that each person has their own column.
For instance, replace your data table variable with this:
var data = google.visualization.arrayToDataTable([
['x', 'Allen', 'Tom', 'Sim'],
[1, null, null, 3],
[2, 3, null, null],
[4, null, 2, null],
]);
Doing this will give you the desired output (I believe, check here).
However, the issue with this method is that you end up with a lot of 'null' values in each series (since you just have single points). In order to simplify this process, you could write a loop to go through your data and format it appropriately for the new table. The basic code would be:
Add a column for your X values to a new table
For each row in column 2 (tooltips) create a new column in the new table
For each row in column 1 (Y values) fill diagonally down/right
This would look something like this:
var newTable = new google.visualization.DataTable();
newTable.addColumn('number', 'Age');
for (var i = 0; i < data.getNumberOfRows(); ++i) {
newTable.addColumn('string', data.getValue(i, 2));
newTable.addRow();
}
for (var j = 0; j < data.getNumberOfRows(); ++j) {
newTable.setValue(j, j + 1, data.getValue(j, j + 1));
}
(Above code has been tested but doesn't like the second for() loop for reasons beyond my comprehension).

Categories

Resources