vis.js - Place node manually - javascript

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
},

Related

How show a circular progress chart with Plotly Javascript

I am new to using the Plotly library and this time I find myself with the need to show in Vuejs 2 a circular progress graph like the following one.
I know that plotly is very complete but I have not seen an example with a similar aspect and that is also with javascript.
Thanks in advance for any information or help you can provide.
Greetings!
With plotly Derek Example, the graph looks like this
My English is not very good, but note that the line of the circle does not have a smooth curvature.
You can use plotly.js traces and text to recreate the components of this chart. If you use a scatter to place down an array of markers, you can create the grey arc, then place the red arc over it. To calculate the coordinates of each these markers, you can center your axes at (0,0) then use x=r*cos(theta) and y=r*sin(theta) where theta is your angle in radians. You can get an array of x and y values to trace out the desired portions of the red and grey arcs.
To get the circular chart to look like yours, I set the range of the x-axes and y-axes both to [-2,2], made the radius of the circular arcs 0.9 with [0,0] as the center, set the markers for these arcs to be size 10, and made the grey arc go from 210 to 85 degrees and red arc go from 90 to -200 degrees (using the function makeArr written by mhodges in his answer here),. Then to get the green marker to display in the legend, I created a trace with a green marker but with null values so it doesn't plot anything on the chart. Text traces can be used to add text around the center of the circular arcs.
Here is an example (codepen is here):
// credit goes to mhodges: https://stackoverflow.com/a/40475362/5327068
function makeArr(startValue, stopValue, cardinality) {
var arr = [];
var step = (stopValue - startValue) / (cardinality - 1);
for (var i = 0; i < cardinality; i++) {
arr.push(startValue + (step * i));
}
return arr;
}
// The function returns two arrays of circle coordinates
// for the outer points of a circle centered at some (x,y)
// and with a radius r with an arc of theta values
function getCircleCoords(r, center, degree_values) {
var center_x=center[0]
var center_y=center[1]
var x_coords = []
var y_coords = []
for (var i = 0; i < degree_values.length; i++) {
x_coords.push(center_x + (r * Math.cos(degree_values[i]*Math.PI/180)));
y_coords.push(center_y + (r * Math.sin(degree_values[i]*Math.PI/180)));
}
return [x_coords,y_coords]
}
var trace1 = {
x: [0],
y: [0.15],
text: ['1000'],
mode: 'text',
textfont: {
family: 'arial',
size: 28,
color: 'black'
},
showlegend: false
};
var trace2 = {
x: [0],
y: [-0.15],
text: ['kW/kg'],
mode: 'text',
textfont: {
family: 'arial',
size: 22,
color: 'grey'
},
showlegend: false
};
circleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(90,-200,1000))
backgroundCircleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(210,85,1000))
// display a marker in the legend without plotting it
var trace3 = {
x: [null],
y: [null],
mode: 'markers',
marker: {color: 'green', size: 10},
name: 'Correcto funcionamiento'
};
// grey background circle
var trace4 = {
x: backgroundCircleCoords[0],
y: backgroundCircleCoords[1],
mode: 'markers',
marker: {color: '#eeeeee', size: 10},
name: null,
showlegend: false
};
// red foreground circle
var trace5 = {
x: circleCoords[0],
y: circleCoords[1],
mode: 'markers',
marker: {color: 'red', size: 10},
name: 'Funcionamiento erroneo'
};
var layout = {
title:'Relacíon potencia peso',
xaxis: {
range: [-2, 2],
zeroline: false,
showgrid: false,
zeroline: false,
showline: false,
showticklabels: false
},
yaxis: {
range: [-2, 2],
showgrid: false,
zeroline: false,
showline: false,
showticklabels: false
},
width: 600,
height: 600,
legend: {
x: 0,
y: 0,
"orientation": "h"
}
};
var data = [trace1, trace2, trace3, trace4, trace5];
Plotly.newPlot('myDiv', data, layout);
EDIT: for a smoother circle, you can increase the number of markers used to draw the circle.
circleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(90,-200,5000))
backgroundCircleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(210,85,5000))

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

Custom edge drawing function in vis.js

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

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"
}]

Categories

Resources