UNPKG

react-sigma-conglei

Version:

Lightweight but powerful library for drawing network graphs built on top of dunnock/react-sigma

1,707 lines (1,484 loc) 63.4 kB
var Sigma = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 84); /******/ }) /************************************************************************/ /******/ ({ /***/ 62: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(global) { 'use strict'; if (typeof sigma === 'undefined') throw 'sigma is not declared'; // Initialize packages: sigma.utils.pkg('sigma.renderers'); // Check if WebGL is enabled: var canvas, webgl = !!global.WebGLRenderingContext; if (webgl) { canvas = document.createElement('canvas'); try { webgl = !!( canvas.getContext('webgl') || canvas.getContext('experimental-webgl') ); } catch (e) { webgl = false; } } // Copy the good renderer: sigma.renderers.def = webgl ? sigma.renderers.webgl : sigma.renderers.canvas; })(this); }.call(window)); /***/ }), /***/ 64: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(undefined) { 'use strict'; if (typeof sigma === 'undefined') throw 'sigma is not declared'; // Initialize packages: sigma.utils.pkg('sigma.renderers'); /** * This function is the constructor of the canvas sigma's renderer. * * @param {sigma.classes.graph} graph The graph to render. * @param {sigma.classes.camera} camera The camera. * @param {configurable} settings The sigma instance settings * function. * @param {object} object The options object. * @return {sigma.renderers.canvas} The renderer instance. */ sigma.renderers.webgl = function(graph, camera, settings, options) { if (typeof options !== 'object') throw 'sigma.renderers.webgl: Wrong arguments.'; if (!(options.container instanceof HTMLElement)) throw 'Container not found.'; var k, i, l, a, fn, _self = this; sigma.classes.dispatcher.extend(this); // Conrad related attributes: this.jobs = {}; Object.defineProperty(this, 'conradId', { value: sigma.utils.id() }); // Initialize main attributes: this.graph = graph; this.camera = camera; this.contexts = {}; this.domElements = {}; this.options = options; this.container = this.options.container; this.settings = ( typeof options.settings === 'object' && options.settings ) ? settings.embedObjects(options.settings) : settings; // Find the prefix: this.options.prefix = this.camera.readPrefix; // Initialize programs hash Object.defineProperty(this, 'nodePrograms', { value: {} }); Object.defineProperty(this, 'edgePrograms', { value: {} }); Object.defineProperty(this, 'nodeFloatArrays', { value: {} }); Object.defineProperty(this, 'edgeFloatArrays', { value: {} }); Object.defineProperty(this, 'edgeIndicesArrays', { value: {} }); // Initialize the DOM elements: if (this.settings(options, 'batchEdgesDrawing')) { this.initDOM('canvas', 'edges', true); this.initDOM('canvas', 'nodes', true); } else { this.initDOM('canvas', 'scene', true); this.contexts.nodes = this.contexts.scene; this.contexts.edges = this.contexts.scene; } this.initDOM('canvas', 'labels'); this.initDOM('canvas', 'mouse'); this.contexts.hover = this.contexts.mouse; // Initialize captors: this.captors = []; a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch]; for (i = 0, l = a.length; i < l; i++) { fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]]; this.captors.push( new fn( this.domElements.mouse, this.camera, this.settings ) ); } // Deal with sigma events: sigma.misc.bindEvents.call(this, this.camera.prefix); sigma.misc.drawHovers.call(this, this.camera.prefix); this.resize(); }; /** * This method will generate the nodes and edges float arrays. This step is * separated from the "render" method, because to keep WebGL efficient, since * all the camera and middlewares are modelised as matrices and they do not * require the float arrays to be regenerated. * * Basically, when the user moves the camera or applies some specific linear * transformations, this process step will be skipped, and the "render" * method will efficiently refresh the rendering. * * And when the user modifies the graph colors or positions (applying a new * layout or filtering the colors, for instance), this "process" step will be * required to regenerate the float arrays. * * @return {sigma.renderers.webgl} Returns the instance itself. */ sigma.renderers.webgl.prototype.process = function() { var a, i, l, k, type, renderer, graph = this.graph, options = sigma.utils.extend(options, this.options), defaultEdgeType = this.settings(options, 'defaultEdgeType'), defaultNodeType = this.settings(options, 'defaultNodeType'); // Empty float arrays: for (k in this.nodeFloatArrays) delete this.nodeFloatArrays[k]; for (k in this.edgeFloatArrays) delete this.edgeFloatArrays[k]; for (k in this.edgeIndicesArrays) delete this.edgeIndicesArrays[k]; // Sort edges and nodes per types: for (a = graph.edges(), i = 0, l = a.length; i < l; i++) { type = a[i].type || defaultEdgeType; k = (type && sigma.webgl.edges[type]) ? type : 'def'; if (!this.edgeFloatArrays[k]) this.edgeFloatArrays[k] = { edges: [] }; this.edgeFloatArrays[k].edges.push(a[i]); } for (a = graph.nodes(), i = 0, l = a.length; i < l; i++) { type = a[i].type || defaultNodeType; k = (type && sigma.webgl.nodes[type]) ? type : 'def'; if (!this.nodeFloatArrays[k]) this.nodeFloatArrays[k] = { nodes: [] }; this.nodeFloatArrays[k].nodes.push(a[i]); } // Push edges: for (k in this.edgeFloatArrays) { renderer = sigma.webgl.edges[k]; a = this.edgeFloatArrays[k].edges; // Creating the necessary arrays this.edgeFloatArrays[k].array = new Float32Array( a.length * renderer.POINTS * renderer.ATTRIBUTES ); for (i = 0, l = a.length; i < l; i++) { // Just check that the edge and both its extremities are visible: if ( !a[i].hidden && !graph.nodes(a[i].source).hidden && !graph.nodes(a[i].target).hidden ) renderer.addEdge( a[i], graph.nodes(a[i].source), graph.nodes(a[i].target), this.edgeFloatArrays[k].array, i * renderer.POINTS * renderer.ATTRIBUTES, options.prefix, this.settings ); } if (typeof renderer.computeIndices === 'function') this.edgeIndicesArrays[k] = renderer.computeIndices( this.edgeFloatArrays[k].array ); } // Push nodes: for (k in this.nodeFloatArrays) { renderer = sigma.webgl.nodes[k]; a = this.nodeFloatArrays[k].nodes; // Creating the necessary arrays this.nodeFloatArrays[k].array = new Float32Array( a.length * renderer.POINTS * renderer.ATTRIBUTES ); for (i = 0, l = a.length; i < l; i++) { if (!this.nodeFloatArrays[k].array) this.nodeFloatArrays[k].array = new Float32Array( a.length * renderer.POINTS * renderer.ATTRIBUTES ); // Just check that the edge and both its extremities are visible: if ( !a[i].hidden ) renderer.addNode( a[i], this.nodeFloatArrays[k].array, i * renderer.POINTS * renderer.ATTRIBUTES, options.prefix, this.settings ); } } return this; }; /** * This method renders the graph. It basically calls each program (and * generate them if they do not exist yet) to render nodes and edges, batched * per renderer. * * As in the canvas renderer, it is possible to display edges, nodes and / or * labels in batches, to make the whole thing way more scalable. * * @param {?object} params Eventually an object of options. * @return {sigma.renderers.webgl} Returns the instance itself. */ sigma.renderers.webgl.prototype.render = function(params) { var a, i, l, k, o, program, renderer, self = this, graph = this.graph, nodesGl = this.contexts.nodes, edgesGl = this.contexts.edges, matrix = this.camera.getMatrix(), options = sigma.utils.extend(params, this.options), drawLabels = this.settings(options, 'drawLabels'), drawEdges = this.settings(options, 'drawEdges'), drawNodes = this.settings(options, 'drawNodes'); // Call the resize function: this.resize(false); // Check the 'hideEdgesOnMove' setting: if (this.settings(options, 'hideEdgesOnMove')) if (this.camera.isAnimated || this.camera.isMoving) drawEdges = false; // Clear canvases: this.clear(); // Translate matrix to [width/2, height/2]: matrix = sigma.utils.matrices.multiply( matrix, sigma.utils.matrices.translation(this.width / 2, this.height / 2) ); // Kill running jobs: for (k in this.jobs) if (conrad.hasJob(k)) conrad.killJob(k); if (drawEdges) { if (this.settings(options, 'batchEdgesDrawing')) (function() { var a, k, i, id, job, arr, end, start, indices, renderer, batchSize, currentProgram; id = 'edges_' + this.conradId; batchSize = this.settings(options, 'webglEdgesBatchSize'); a = Object.keys(this.edgeFloatArrays); if (!a.length) return; i = 0; renderer = sigma.webgl.edges[a[i]]; arr = this.edgeFloatArrays[a[i]].array; indices = this.edgeIndicesArrays[a[i]]; start = 0; end = Math.min( start + batchSize * renderer.POINTS, arr.length / renderer.ATTRIBUTES ); job = function() { // Check program: if (!this.edgePrograms[a[i]]) this.edgePrograms[a[i]] = renderer.initProgram(edgesGl); if (start < end) { edgesGl.useProgram(this.edgePrograms[a[i]]); renderer.render( edgesGl, this.edgePrograms[a[i]], arr, { settings: this.settings, matrix: matrix, width: this.width, height: this.height, ratio: this.camera.ratio, scalingRatio: this.settings( options, 'webglOversamplingRatio' ), start: start, count: end - start, indicesData: indices } ); } // Catch job's end: if ( end >= arr.length / renderer.ATTRIBUTES && i === a.length - 1 ) { delete this.jobs[id]; return false; } if (end >= arr.length / renderer.ATTRIBUTES) { i++; arr = this.edgeFloatArrays[a[i]].array; renderer = sigma.webgl.edges[a[i]]; start = 0; end = Math.min( start + batchSize * renderer.POINTS, arr.length / renderer.ATTRIBUTES ); } else { start = end; end = Math.min( start + batchSize * renderer.POINTS, arr.length / renderer.ATTRIBUTES ); } return true; }; this.jobs[id] = job; conrad.addJob(id, job.bind(this)); }).call(this); else { for (k in this.edgeFloatArrays) { renderer = sigma.webgl.edges[k]; // Check program: if (!this.edgePrograms[k]) this.edgePrograms[k] = renderer.initProgram(edgesGl); // Render if (this.edgeFloatArrays[k]) { edgesGl.useProgram(this.edgePrograms[k]); renderer.render( edgesGl, this.edgePrograms[k], this.edgeFloatArrays[k].array, { settings: this.settings, matrix: matrix, width: this.width, height: this.height, ratio: this.camera.ratio, scalingRatio: this.settings(options, 'webglOversamplingRatio'), indicesData: this.edgeIndicesArrays[k] } ); } } } } if (drawNodes) { // Enable blending: nodesGl.blendFunc(nodesGl.SRC_ALPHA, nodesGl.ONE_MINUS_SRC_ALPHA); nodesGl.enable(nodesGl.BLEND); for (k in this.nodeFloatArrays) { renderer = sigma.webgl.nodes[k]; // Check program: if (!this.nodePrograms[k]) this.nodePrograms[k] = renderer.initProgram(nodesGl); // Render if (this.nodeFloatArrays[k]) { nodesGl.useProgram(this.nodePrograms[k]); renderer.render( nodesGl, this.nodePrograms[k], this.nodeFloatArrays[k].array, { settings: this.settings, matrix: matrix, width: this.width, height: this.height, ratio: this.camera.ratio, scalingRatio: this.settings(options, 'webglOversamplingRatio') } ); } } } if (drawLabels) { a = this.camera.quadtree.area( this.camera.getRectangle(this.width, this.height) ); // Apply camera view to these nodes: this.camera.applyView( undefined, undefined, { nodes: a, edges: [], width: this.width, height: this.height } ); o = function(key) { return self.settings({ prefix: self.camera.prefix }, key); }; for (i = 0, l = a.length; i < l; i++) if (!a[i].hidden) ( sigma.canvas.labels[ a[i].type || this.settings(options, 'defaultNodeType') ] || sigma.canvas.labels.def )(a[i], this.contexts.labels, o); } this.dispatchEvent('render'); return this; }; /** * This method creates a DOM element of the specified type, switches its * position to "absolute", references it to the domElements attribute, and * finally appends it to the container. * * @param {string} tag The label tag. * @param {string} id The id of the element (to store it in * "domElements"). * @param {?boolean} webgl Will init the WebGL context if true. */ sigma.renderers.webgl.prototype.initDOM = function(tag, id, webgl) { var gl, dom = document.createElement(tag), self = this; dom.style.position = 'absolute'; dom.setAttribute('class', 'sigma-' + id); this.domElements[id] = dom; this.container.appendChild(dom); if (tag.toLowerCase() === 'canvas') { this.contexts[id] = dom.getContext(webgl ? 'experimental-webgl' : '2d', { preserveDrawingBuffer: true }); // Adding webgl context loss listeners if (webgl) { dom.addEventListener('webglcontextlost', function(e) { e.preventDefault(); }, false); dom.addEventListener('webglcontextrestored', function(e) { self.render(); }, false); } } }; /** * This method resizes each DOM elements in the container and stores the new * dimensions. Then, it renders the graph. * * @param {?number} width The new width of the container. * @param {?number} height The new height of the container. * @return {sigma.renderers.webgl} Returns the instance itself. */ sigma.renderers.webgl.prototype.resize = function(w, h) { var k, oldWidth = this.width, oldHeight = this.height, pixelRatio = sigma.utils.getPixelRatio(); if (w !== undefined && h !== undefined) { this.width = w; this.height = h; } else { this.width = this.container.offsetWidth; this.height = this.container.offsetHeight; w = this.width; h = this.height; } if (oldWidth !== this.width || oldHeight !== this.height) { for (k in this.domElements) { this.domElements[k].style.width = w + 'px'; this.domElements[k].style.height = h + 'px'; if (this.domElements[k].tagName.toLowerCase() === 'canvas') { // If simple 2D canvas: if (this.contexts[k] && this.contexts[k].scale) { this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px'); this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px'); if (pixelRatio !== 1) this.contexts[k].scale(pixelRatio, pixelRatio); } else { this.domElements[k].setAttribute( 'width', (w * this.settings('webglOversamplingRatio')) + 'px' ); this.domElements[k].setAttribute( 'height', (h * this.settings('webglOversamplingRatio')) + 'px' ); } } } } // Scale: for (k in this.contexts) if (this.contexts[k] && this.contexts[k].viewport) this.contexts[k].viewport( 0, 0, this.width * this.settings('webglOversamplingRatio'), this.height * this.settings('webglOversamplingRatio') ); return this; }; /** * This method clears each canvas. * * @return {sigma.renderers.webgl} Returns the instance itself. */ sigma.renderers.webgl.prototype.clear = function() { this.contexts.labels.clearRect(0, 0, this.width, this.height); this.contexts.nodes.clear(this.contexts.nodes.COLOR_BUFFER_BIT); this.contexts.edges.clear(this.contexts.edges.COLOR_BUFFER_BIT); return this; }; /** * This method kills contexts and other attributes. */ sigma.renderers.webgl.prototype.kill = function() { var k, captor; // Kill captors: while ((captor = this.captors.pop())) captor.kill(); delete this.captors; // Kill contexts: for (k in this.domElements) { this.domElements[k].parentNode.removeChild(this.domElements[k]); delete this.domElements[k]; delete this.contexts[k]; } delete this.domElements; delete this.contexts; }; /** * The object "sigma.webgl.nodes" contains the different WebGL node * renderers. The default one draw nodes as discs. Here are the attributes * any node renderer must have: * * {number} POINTS The number of points required to draw a node. * {number} ATTRIBUTES The number of attributes needed to draw one point. * {function} addNode A function that adds a node to the data stack that * will be given to the buffer. Here is the arguments: * > {object} node * > {number} index The node index in the * nodes array. * > {Float32Array} data The stack. * > {object} options Some options. * {function} render The function that will effectively render the nodes * into the buffer. * > {WebGLRenderingContext} gl * > {WebGLProgram} program * > {Float32Array} data The stack to give to the * buffer. * > {object} params An object containing some * options, like width, * height, the camera ratio. * {function} initProgram The function that will initiate the program, with * the relevant shaders and parameters. It must return * the newly created program. * * Check sigma.webgl.nodes.def or sigma.webgl.nodes.fast to see how it * works more precisely. */ sigma.utils.pkg('sigma.webgl.nodes'); /** * The object "sigma.webgl.edges" contains the different WebGL edge * renderers. The default one draw edges as direct lines. Here are the * attributes any edge renderer must have: * * {number} POINTS The number of points required to draw an edge. * {number} ATTRIBUTES The number of attributes needed to draw one point. * {function} addEdge A function that adds an edge to the data stack that * will be given to the buffer. Here is the arguments: * > {object} edge * > {object} source * > {object} target * > {Float32Array} data The stack. * > {object} options Some options. * {function} render The function that will effectively render the edges * into the buffer. * > {WebGLRenderingContext} gl * > {WebGLProgram} program * > {Float32Array} data The stack to give to the * buffer. * > {object} params An object containing some * options, like width, * height, the camera ratio. * {function} initProgram The function that will initiate the program, with * the relevant shaders and parameters. It must return * the newly created program. * * Check sigma.webgl.edges.def or sigma.webgl.edges.fast to see how it * works more precisely. */ sigma.utils.pkg('sigma.webgl.edges'); /** * The object "sigma.canvas.labels" contains the different * label renderers for the WebGL renderer. Since displaying texts in WebGL is * definitely painful and since there a way less labels to display than nodes * or edges, the default renderer simply renders them in a canvas. * * A labels renderer is a simple function, taking as arguments the related * node, the renderer and a settings function. */ sigma.utils.pkg('sigma.canvas.labels'); }).call(this); }.call(window)); /***/ }), /***/ 71: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function() { 'use strict'; sigma.utils.pkg('sigma.webgl.edges'); /** * This edge renderer will display edges as arrows going from the source node * to the target node. To deal with edge thicknesses, the lines are made of * three triangles: two forming rectangles, with the gl.TRIANGLES drawing * mode. * * It is expensive, since drawing a single edge requires 9 points, each * having a lot of attributes. */ sigma.webgl.edges.arrow = { POINTS: 9, ATTRIBUTES: 11, 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'], targetSize = target[prefix + 'size'], 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++] = targetSize; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; data[i++] = x1; data[i++] = y1; data[i++] = x2; data[i++] = y2; data[i++] = w; data[i++] = targetSize; data[i++] = 0.0; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; data[i++] = x1; data[i++] = y1; data[i++] = x2; data[i++] = y2; data[i++] = w; data[i++] = targetSize; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = 0.0; data[i++] = color; // Arrow head: data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 1.0; data[i++] = -1.0; data[i++] = color; data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 1.0; data[i++] = 0.0; data[i++] = color; data[i++] = x2; data[i++] = y2; data[i++] = x1; data[i++] = y1; data[i++] = w; data[i++] = targetSize; data[i++] = 1.0; data[i++] = 0.0; data[i++] = 1.0; data[i++] = 1.0; data[i++] = color; }, render: function(gl, program, data, params) { var buffer; // Define attributes: var positionLocation1 = gl.getAttribLocation(program, 'a_pos1'), positionLocation2 = gl.getAttribLocation(program, 'a_pos2'), thicknessLocation = gl.getAttribLocation(program, 'a_thickness'), targetSizeLocation = gl.getAttribLocation(program, 'a_tSize'), delayLocation = gl.getAttribLocation(program, 'a_delay'), minusLocation = gl.getAttribLocation(program, 'a_minus'), headLocation = gl.getAttribLocation(program, 'a_head'), headPositionLocation = gl.getAttribLocation(program, 'a_headPosition'), colorLocation = gl.getAttribLocation(program, 'a_color'), 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'), nodeRatioLocation = gl.getUniformLocation(program, 'u_nodeRatio'), arrowHeadLocation = gl.getUniformLocation(program, 'u_arrowHead'), 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( nodeRatioLocation, Math.pow(params.ratio, params.settings('nodesPowRatio')) / params.ratio ); gl.uniform1f(arrowHeadLocation, 5.0); 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(positionLocation1); gl.enableVertexAttribArray(positionLocation2); gl.enableVertexAttribArray(thicknessLocation); gl.enableVertexAttribArray(targetSizeLocation); gl.enableVertexAttribArray(delayLocation); gl.enableVertexAttribArray(minusLocation); gl.enableVertexAttribArray(headLocation); gl.enableVertexAttribArray(headPositionLocation); gl.enableVertexAttribArray(colorLocation); 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(targetSizeLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 20 ); gl.vertexAttribPointer(delayLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 24 ); gl.vertexAttribPointer(minusLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 28 ); gl.vertexAttribPointer(headLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 32 ); gl.vertexAttribPointer(headPositionLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 36 ); gl.vertexAttribPointer(colorLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 40 ); 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_pos1;', 'attribute vec2 a_pos2;', 'attribute float a_thickness;', 'attribute float a_tSize;', 'attribute float a_delay;', 'attribute float a_minus;', 'attribute float a_head;', 'attribute float a_headPosition;', 'attribute float a_color;', 'uniform vec2 u_resolution;', 'uniform float u_ratio;', 'uniform float u_nodeRatio;', 'uniform float u_arrowHead;', '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 pos = normalize(a_pos2 - a_pos1);', 'mat2 matrix = (1.0 - a_head) *', '(', 'a_minus * u_matrixHalfPiMinus +', '(1.0 - a_minus) * u_matrixHalfPi', ') + a_head * (', 'a_headPosition * u_matrixHalfPiMinus * 0.6 +', '(a_headPosition * a_headPosition - 1.0) * mat2(1.0)', ');', 'pos = a_pos1 + (', // Deal with body: '(1.0 - a_head) * a_thickness * u_ratio * matrix * pos +', // Deal with head: 'a_head * u_arrowHead * a_thickness * u_ratio * matrix * pos +', // Deal with delay: 'a_delay * pos * (', 'a_tSize / u_nodeRatio +', 'u_arrowHead * a_thickness * u_ratio', ')', ');', // Scale from [[-1 1] [-1 1]] to the container: 'gl_Position = vec4(', '((u_matrix * vec3(pos, 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; } }; })(); }.call(window)); /***/ }), /***/ 72: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(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; } }; })(); }.call(window)); /***/ }), /***/ 73: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function() { 'use strict'; sigma.utils.pkg('sigma.webgl.edges'); /** * This edge renderer will display edges as lines with the gl.LINES display * mode. Since this mode does not support well thickness, edges are all drawn * with the same thickness (3px), independantly of the edge attributes or the * zooming ratio. */ sigma.webgl.edges.fast = { POINTS: 2, ATTRIBUTES: 3, 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++] = color; data[i++] = x2; data[i++] = y2; data[i++] = color; }, render: function(gl, program, data, params) { var buffer; // Define attributes: var colorLocation = gl.getAttribLocation(program, 'a_color'), positionLocation = gl.getAttribLocation(program, 'a_position'), resolutionLocation = gl.getUniformLocation(program, 'u_resolution'), matrixLocation = gl.getUniformLocation(program, 'u_matrix'); buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW); gl.uniform2f(resolutionLocation, params.width, params.height); gl.uniformMatrix3fv(matrixLocation, false, params.matrix); gl.enableVertexAttribArray(positionLocation); gl.enableVertexAttribArray(colorLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0 ); gl.vertexAttribPointer(colorLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 8 ); gl.lineWidth(3); gl.drawArrays( gl.LINES, params.start || 0, params.count || (data.length / this.ATTRIBUTES) ); }, initProgram: function(gl) { var vertexShader, fragmentShader, program; vertexShader = sigma.utils.loadShader( gl, [ 'attribute vec2 a_position;', 'attribute float a_color;', 'uniform vec2 u_resolution;', 'uniform mat3 u_matrix;', 'varying vec4 color;', 'void main() {', // Scale from [[-1 1] [-1 1]] to the container: 'gl_Position = vec4(', '((u_matrix * vec3(a_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; } }; })(); }.call(window)); /***/ }), /***/ 74: /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function() { 'use strict'; sigma.utils.pkg('sigma.webgl.nodes'); /** * This node renderer will display nodes as discs, shaped in triangles with * the gl.TRIANGLES display mode. So, to be more precise, to draw one node, * it will store three times the center of node, with the color and the size, * and an angle indicating which "corner" of the triangle to draw. * * The fragment shader does not deal with anti-aliasing, so make sure that * you deal with it somewhere else in the code (by default, the WebGL * renderer will oversample the rendering through the webglOversamplingRatio * value). */ sigma.webgl.nodes.def = { POINTS: 3, ATTRIBUTES: 5, addNode: function(node, data, i, prefix, settings) { var color = sigma.utils.floatColor( node.color || settings('defaultNodeColor') ); data[i++] = node[prefix + 'x']; data[i++] = node[prefix + 'y']; data[i++] = node[prefix + 'size']; data[i++] = color; data[i++] = 0; data[i++] = node[prefix + 'x']; data[i++] = node[prefix + 'y'];