Open Matthi0uw opened 10 years ago
That would be really a nice add... vivagraph has very rudimentary webgl support, adding bezier curve is feasible but is not straightforward.
Thanks for the quick answer, I can give it a try. But can you tell me where I can access the vertices positions (x,y) coordinates ?
Sure, webgl graphics receives a link position when link is added, this happens in webglGraphics.js.
By default links in webgl are rendered by a program
: a combination of vertex and fragment shaders. In vivagraph program implements position() method, which accepts position for a link.
Example of how to create custom node program is available in webglCustomNode.html. Link program could be implemented in a similar way
Okay, so the method position() returns a table with the coordinates of each node ?
1st element is x of 1st node 2nd element is y of 1st node 3rd element is z of 1st node 4th element is x of 2nd node 5th element is y of 2nd node 6nd element is z of 2nd node 7nd element is x of 3rd node ...
I found an example of webGL with circles : on this site and try to use their function on your code. There is a function arc() to calculate the path of the curve approximation between 2 nodes:
function arc(cx, cy, r, a, b, n) {
var angle = a * Math.PI / 180;
var dA = (b * Math.PI / 180) / n;
var points = [];
for (var i = 0; i <= n; i++) {
var x = cx + r * Math.cos(angle + i * dA);
var y = cy + r * Math.sin(angle + i * dA);
points.push(x, y, 0);
}
return points;
}
I've made a fiddlejs to try a example with 1 node on the curve. I display in console the coordinates of nodes : there is a bug in my function because coordinates of start are not good. It should represent my link (even if position is false), but I do not see it. Maybe I do not use the render () function in the right way
The reason you're not seeing the lines is due to your points.push- the third argument is color, and you've specified 0. Swap that with positions[2] and I think you should get the color of the from position.
Having done that, though, all I'm seeing is a straight line, positioned incorrectly. Since I'm a complete amateur with glsl / webgl in general, I'm guessing it has to do with some sort of mismatch in array buffer size, perhaps?
Found the other problem, yet another silly mistake- instead of
gl.drawArrays(gl.LINES, 0, ap.length/3)
you should be doing
gl.drawArrays(gl.LINE_STRIP, 0, ap.length/3)
. That'll draw a line between each vertex, rather than drawing one line per vertex pairs. From there, it's just a matter of getting the maths right so that the curve starts and stops at the two points.
Thank you for your anwser @dzdrazil ! I have update my fiddle with your advice : this is an early response to my initial problem. I can draw a circle arc for the 1st link, but not for all... Have you any idea to draw all links ?
Here is my new fiddle update with Bezier quadratic curves and cubic curves with 2 control points (see on wikipedia). I wrote the function arc() called in render of Viva.Graph.View.webglLinkProgram :
/* function to draw links:
positions : position of all nodes in the graph
n : 1 = line / 2 = quadratic curve / 3 = cubic curve
m : number of point on the curve
*/
function arc(positions, n, m) {
for (var j = 0; j < positions.length; j++){
if (positions[j] != positions[j+3] || positions[j+1] != positions[j+4]){
points = [];
pointsMid = [];
var dx = positions[j] - positions[j+3],
dy = positions[j+1] - positions[j+4],
cx = (positions[j]+positions[j+3])/2,
cy = (positions[j+1]+positions[j+4])/2,
a = Math.atan2(dy, dx) * 180 / Math.PI,
r = Math.sqrt(dx * dx + dy * dy)/2,
angle = a * Math.PI / 180,
dA = Math.PI / n;
for (var i = 0; i <= n; i++) {
var x = cx + r * Math.cos(angle + i * dA);
var y = cy + r * Math.sin(angle + i * dA);
pointsMid.push(x, y,0.2);
}
if (n == 1){
points = pointsMid;
}else if (n == 2){
for (var k = 0; k <= m; k++){
t = k / m;
Ax = ( (1 - t) * pointsMid[0] ) + (t * pointsMid[3]);
Ay = ( (1 - t) * pointsMid[1] ) + (t * pointsMid[4]);
Bx = ( (1 - t) * pointsMid[3] ) + (t * pointsMid[6]);
By = ( (1 - t) * pointsMid[4] ) + (t * pointsMid[7]);
x = ( (1 - t) * Ax ) + (t * Bx);
y = ( (1 - t) * Ay ) + (t * By);
points.push(x, y,0.2);
}
} else if (n == 3){
for (var k = 0; k <= m; k++){
t = k / m;
Px0 = pointsMid[0];
Px1 = pointsMid[3];
Px2 = pointsMid[6];
Px3 = pointsMid[9];
Py0 = pointsMid[1];
Py1 = pointsMid[4];
Py2 = pointsMid[7];
Py3 = pointsMid[10];
x = Px0*(1-t)*(1-t)*(1-t) + 3*Px1*t*(1-t)*(1-t) + 3*Px2*t*t*(1-t) + Px3*t*t*t;
y = Py0*(1-t)*(1-t)*(1-t) + 3*Py1*t*(1-t)*(1-t) + 3*Py2*t*t*(1-t) + Py3*t*t*t;
points.push(x, y,0.2);
}
}
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.DYNAMIC_DRAW);
if (sizeDirty) {
sizeDirty = false;
gl.uniformMatrix4fv(locations.transform, false, transform);
gl.uniform2f(locations.screenSize, width, height);
}
gl.vertexAttribPointer(locations.vertexPos, 2, gl.FLOAT, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0);
gl.vertexAttribPointer(locations.color, 4, gl.UNSIGNED_BYTE, true, 3 * Float32Array.BYTES_PER_ELEMENT, 2 * 4);
// param : mode , 0, numItems
gl.drawArrays(gl.LINE_STRIP, 0, points.length/3)
}
j += 5;
}
}
In pointsMid array, I put 3 nodes :
In points array, I put m
nodes (m
defined in parameters) that are in the path of the curve.
Then I simply display these nodes.
Currently I have 3 problems:
points.push(x, y,0.15);
. The third value is used to add colors, but I don’t really understand how it works, for instance 0.1 = cyan / blue = 0.2 / 0 and 0.5 hide the links, is there a way to have some RGB colors in there? m
links (m
corresponding to the parameter value of the arc function. Regarding performance, the rendering becomes very slow with m
times fewer nodes on the screen... Do you have any idea on how to improve it?n
parameter? (at the moment, I've put it in "Viva.Graph.View.webglLinkProgram" but I am not sure it is the correct location for this part of the code)Can you do straight dynamic ribbons, like Almende does?
I would like to have a visualization with bezier curves instead of line between the links. In the example "07 - Dual Show Links", there is an implementation of a curve between two nodes with svg render.
My graph can be up to 15k nodes, so I have to use webGL part of your code.
Have you an idea to have curve on webGL render ?