sigma
Version:
A JavaScript library dedicated to graph drawing.
259 lines (229 loc) • 7.38 kB
JavaScript
;(function() {
'use strict';
sigma.utils.pkg('sigma.webgl.edges');
/**
* This edge renderer will display edges as lines going from the source node
* to the target node. To deal with edge thicknesses, the lines are made of
* two triangles forming rectangles, with the gl.TRIANGLES drawing mode.
*
* It is expensive, since drawing a single edge requires 6 points, each
* having 7 attributes (source position, target position, thickness, color
* and a flag indicating which vertice of the rectangle it is).
*/
sigma.webgl.edges.def = {
POINTS: 6,
ATTRIBUTES: 7,
addEdge: function(edge, source, target, data, i, prefix, settings) {
var w = (edge[prefix + 'size'] || 1) / 2,
x1 = source[prefix + 'x'],
y1 = source[prefix + 'y'],
x2 = target[prefix + 'x'],
y2 = target[prefix + 'y'],
color = edge.color;
if (!color)
switch (settings('edgeColor')) {
case 'source':
color = source.color || settings('defaultNodeColor');
break;
case 'target':
color = target.color || settings('defaultNodeColor');
break;
default:
color = settings('defaultEdgeColor');
break;
}
// Normalize color:
color = sigma.utils.floatColor(color);
data[i++] = x1;
data[i++] = y1;
data[i++] = x2;
data[i++] = y2;
data[i++] = w;
data[i++] = 0.0;
data[i++] = color;
data[i++] = x2;
data[i++] = y2;
data[i++] = x1;
data[i++] = y1;
data[i++] = w;
data[i++] = 1.0;
data[i++] = color;
data[i++] = x2;
data[i++] = y2;
data[i++] = x1;
data[i++] = y1;
data[i++] = w;
data[i++] = 0.0;
data[i++] = color;
data[i++] = x2;
data[i++] = y2;
data[i++] = x1;
data[i++] = y1;
data[i++] = w;
data[i++] = 0.0;
data[i++] = color;
data[i++] = x1;
data[i++] = y1;
data[i++] = x2;
data[i++] = y2;
data[i++] = w;
data[i++] = 1.0;
data[i++] = color;
data[i++] = x1;
data[i++] = y1;
data[i++] = x2;
data[i++] = y2;
data[i++] = w;
data[i++] = 0.0;
data[i++] = color;
},
render: function(gl, program, data, params) {
var buffer;
// Define attributes:
var colorLocation =
gl.getAttribLocation(program, 'a_color'),
positionLocation1 =
gl.getAttribLocation(program, 'a_position1'),
positionLocation2 =
gl.getAttribLocation(program, 'a_position2'),
thicknessLocation =
gl.getAttribLocation(program, 'a_thickness'),
minusLocation =
gl.getAttribLocation(program, 'a_minus'),
resolutionLocation =
gl.getUniformLocation(program, 'u_resolution'),
matrixLocation =
gl.getUniformLocation(program, 'u_matrix'),
matrixHalfPiLocation =
gl.getUniformLocation(program, 'u_matrixHalfPi'),
matrixHalfPiMinusLocation =
gl.getUniformLocation(program, 'u_matrixHalfPiMinus'),
ratioLocation =
gl.getUniformLocation(program, 'u_ratio'),
scaleLocation =
gl.getUniformLocation(program, 'u_scale');
buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.uniform2f(resolutionLocation, params.width, params.height);
gl.uniform1f(
ratioLocation,
params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio'))
);
gl.uniform1f(scaleLocation, params.scalingRatio);
gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
gl.uniformMatrix2fv(
matrixHalfPiLocation,
false,
sigma.utils.matrices.rotation(Math.PI / 2, true)
);
gl.uniformMatrix2fv(
matrixHalfPiMinusLocation,
false,
sigma.utils.matrices.rotation(-Math.PI / 2, true)
);
gl.enableVertexAttribArray(colorLocation);
gl.enableVertexAttribArray(positionLocation1);
gl.enableVertexAttribArray(positionLocation2);
gl.enableVertexAttribArray(thicknessLocation);
gl.enableVertexAttribArray(minusLocation);
gl.vertexAttribPointer(positionLocation1,
2,
gl.FLOAT,
false,
this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
0
);
gl.vertexAttribPointer(positionLocation2,
2,
gl.FLOAT,
false,
this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
8
);
gl.vertexAttribPointer(thicknessLocation,
1,
gl.FLOAT,
false,
this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
16
);
gl.vertexAttribPointer(minusLocation,
1,
gl.FLOAT,
false,
this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
20
);
gl.vertexAttribPointer(colorLocation,
1,
gl.FLOAT,
false,
this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
24
);
gl.drawArrays(
gl.TRIANGLES,
params.start || 0,
params.count || (data.length / this.ATTRIBUTES)
);
},
initProgram: function(gl) {
var vertexShader,
fragmentShader,
program;
vertexShader = sigma.utils.loadShader(
gl,
[
'attribute vec2 a_position1;',
'attribute vec2 a_position2;',
'attribute float a_thickness;',
'attribute float a_minus;',
'attribute float a_color;',
'uniform vec2 u_resolution;',
'uniform float u_ratio;',
'uniform float u_scale;',
'uniform mat3 u_matrix;',
'uniform mat2 u_matrixHalfPi;',
'uniform mat2 u_matrixHalfPiMinus;',
'varying vec4 color;',
'void main() {',
// Find the good point:
'vec2 position = a_thickness * u_ratio *',
'normalize(a_position2 - a_position1);',
'mat2 matrix = a_minus * u_matrixHalfPiMinus +',
'(1.0 - a_minus) * u_matrixHalfPi;',
'position = matrix * position + a_position1;',
// Scale from [[-1 1] [-1 1]] to the container:
'gl_Position = vec4(',
'((u_matrix * vec3(position, 1)).xy /',
'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
'0,',
'1',
');',
// Extract the color:
'float c = a_color;',
'color.b = mod(c, 256.0); c = floor(c / 256.0);',
'color.g = mod(c, 256.0); c = floor(c / 256.0);',
'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
'color.a = 1.0;',
'}'
].join('\n'),
gl.VERTEX_SHADER
);
fragmentShader = sigma.utils.loadShader(
gl,
[
'precision mediump float;',
'varying vec4 color;',
'void main(void) {',
'gl_FragColor = color;',
'}'
].join('\n'),
gl.FRAGMENT_SHADER
);
program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
return program;
}
};
})();