diff --git a/.jshintrc b/.jshintrc index c59ae7c..604b7d3 100644 --- a/.jshintrc +++ b/.jshintrc @@ -8,7 +8,6 @@ "curly": true, "eqeqeq": true, "immed": true, - "indent": 4, "latedef": false, "newcap": true, "noarg": true, diff --git a/CHANGELOG b/CHANGELOG index 4d627dd..304614a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +v0.6.0 + date Dec 27, 2014 + - Migrated to gulp. First step towards commonjs. + - Fixed spelling, grammar. v0.5.8 date: Sep 28, 2014 - Graphics object no longer waits `init` method to create container. Fixes diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index c7cdb18..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,145 +0,0 @@ -// Generated on 2013-03-27 using generator-webapp 0.1.5 -"use strict"; - -module.exports = function (grunt) { - var libConfig = { - src: "src", - dist: "dist" - }; - // This needs to be changed. It"s just copies structure of - // my original builder, which was not really well organized: - var fileGroups = { - core: [ - "vivagraph.js", - "version.js", - "Utils/etc.js", - "Utils/browserInfo.js", - "Utils/indexOf.js", - "Utils/getDimensions.js", - "Utils/events.js", - "Input/dragndrop.js", - "Input/domInputManager.js", - "Input/spatialIndex.js", // TODO: Do I need this for SVG? - "Utils/timer.js", - "Utils/geom.js", - - "Core/primitives.js", - "Core/graph.js", - "Core/operations.js", - - "Physics/primitives.js", - "Physics/eulerIntegrator.js", - "Physics/Forces/nbodyForce.js", - "Physics/Forces/dragForce.js", - "Physics/Forces/springForce.js", - "Physics/forceSimulator.js", - "Layout/forceDirected.js", - "Layout/constant.js", - "View/renderer.js" - ], - extra: [ - "Core/serializer.js", - "Algorithms/centrality.js", - "Algorithms/Community/community.js", - "Algorithms/Community/slpa.js", - "Core/generator.js", - "View/cssGraphics.js" - ], - svg: [ - "Svg/svg.js", - "View/svgGraphics.js", - "View/svgNodeFactory.js", - ], - webgl: [ - "WebGL/webgl.js", - "WebGL/webglUIModels.js", - "WebGL/webglNodeProgram.js", - "WebGL/webglLinkProgram.js", - "WebGL/webglImageNodeProgram.js", - "View/webglGraphics.js", - "WebGL/webglInputEvents.js", - "Input/webglInputManager.js", - ] - }; - Object.keys(fileGroups).forEach(function (key) { - fileGroups[key] = fileGroups[key].map(function (path) { - return libConfig.src + "/" + path; - }); - }); - grunt.initConfig({ - lib: libConfig, - watch: { - js: { - files: "<%= lib.src %>/**/*.js", - tasks: ["build"], - spawn: true - } - }, - jshint: { - all: [ - "Gruntfile.js", - "<%= lib.src %>/{,*/}*.js" - ], - options: { - jshintrc: ".jshintrc" - } - }, - clean: { - dist: ["<%= lib.dist %>/*"], - }, - concat: { - options: { - separator: "" - }, - all: { - src: [ - fileGroups.core, - fileGroups.extra, - fileGroups.svg, - fileGroups.webgl - ], - dest: "<%= lib.dist %>/vivagraph.js" - }, - svg: { - src: [ - fileGroups.core, - fileGroups.svg - ], - dest: "<%= lib.dist %>/vivagraph.svg.js" - }, - webgl: { - src: [ - fileGroups.core, - fileGroups.webgl - ], - dest: "<%= lib.dist %>/vivagraph.webgl.js" - }, - }, - uglify: { - dist: { - files: { - "<%= lib.dist %>/vivagraph.min.js": ["<%= lib.dist %>/vivagraph.js"] - } - } - } - }); - - grunt.loadNpmTasks("grunt-contrib-clean"); - grunt.loadNpmTasks("grunt-contrib-jshint"); - grunt.loadNpmTasks("grunt-contrib-concat"); - grunt.loadNpmTasks("grunt-contrib-uglify"); - grunt.loadNpmTasks("grunt-regarde"); - - grunt.renameTask("regarde", "watch"); - - grunt.registerTask("build", [ - "clean:dist", - "concat:all", - "uglify" - ]); - grunt.registerTask("server", [ - "build", - "watch" - ]); - grunt.registerTask("default", ["jshint", "build"]); -}; diff --git a/dist/vivagraph.js b/dist/vivagraph.js index b566dff..c23fde4 100644 --- a/dist/vivagraph.js +++ b/dist/vivagraph.js @@ -1,5 +1,5 @@ /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ var Viva = Viva || {}; @@ -7,7 +7,9 @@ Viva.Graph = Viva.Graph || {}; if (typeof module !== 'undefined' && module.exports) { module.exports = Viva; } -Viva.Graph.version = '0.5.8'; + +Viva.Graph.version = '0.6.0'; + /** * Extends target object with given fields/values in the options object. * Unlike jQuery's extend this method does not override target object @@ -36,7 +38,7 @@ Viva.lazyExtend = function (target, options) { return target; }; /** - * Implenetation of seeded pseudo random number generator, based on Robert Jenkin's 32 bit integer hash function + * Implementation of seeded pseudo random number generator, based on Robert Jenkin's 32 bit integer hash function * * Usage example: * var random = Viva.random(seedNumber), @@ -68,7 +70,7 @@ Viva.random = function () { /** * Generates random integer number in the range from 0 (inclusive) to maxValue (exclusive) * - * @param maxValue is REQUIRED. Ommitit this numbe will result in NaN values from PRNG. + * @param maxValue is REQUIRED. Omitting this number will result in NaN values from PRNG. */ next : function (maxValue) { return Math.floor(randomFunc() * maxValue); @@ -92,7 +94,7 @@ Viva.random = function () { * * @param array to be shuffled * @param random - a [seeded] random number generator to produce same sequences. This parameter - * is optional. If you don't need determenistic randomness keep it blank. + * is optional. If you don't need deterministic randomness keep it blank. */ Viva.randomIterator = function (array, random) { random = random || Viva.random(); @@ -130,6 +132,7 @@ Viva.randomIterator = function (array, random) { } }; }; + Viva.BrowserInfo = (function () { if (typeof window === "undefined" || !window.hasOwnProperty("navigator")) { return { @@ -155,8 +158,9 @@ Viva.BrowserInfo = (function () { version: match[2] || "0" }; }()); + /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.Utils = Viva.Graph.Utils || {}; @@ -177,6 +181,7 @@ Viva.Graph.Utils.indexOfElementInArray = function (element, array) { return -1; }; + Viva.Graph.Utils = Viva.Graph.Utils || {}; Viva.Graph.Utils.getDimension = function (container) { @@ -212,8 +217,9 @@ Viva.Graph.Utils.findElementPosition = function (obj) { } return [curleft, curtop]; -};/** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com +}; +/** + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.Utils = Viva.Graph.Utils || {}; @@ -222,7 +228,7 @@ Viva.Graph.Utils = Viva.Graph.Utils || {}; // hard to understand. Refactor it. // TODO: This is really painful. Please don't use this class anymore, I will -// definitely depricate it or update its interface. +// definitely deprecate it or update its interface. /** * Allows to start/stop listen to element's events. An element can be arbitrary @@ -241,7 +247,7 @@ Viva.Graph.Utils.events = function (element) { * This behavior is based on Crockford's eventuality example, but with a minor changes: * - fire() method accepts parameters to pass to callbacks (instead of setting them in 'on' method) * - on() method is replaced with addEventListener(), to let objects be used as a DOM objects. - * - behavoir contract is simplified to "string as event name"/"function as callback" convention. + * - behavior contract is simplified to "string as event name"/"function as callback" convention. * - removeEventListener() method added to let unsubscribe from events. */ var eventuality = function (that) { @@ -327,10 +333,10 @@ Viva.Graph.Utils.events = function (element) { return { /** - * Registes callback to be called when element fires event with given event name. + * Registers callback to be called when element fires event with given event name. */ on : function (eventName, callback) { - if (element.addEventListener) {// W3C DOM and eventuality objecets. + if (element.addEventListener) {// W3C DOM and eventuality objects. element.addEventListener(eventName, callback, false); } else if (element.attachEvent) { // IE DOM element.attachEvent("on" + eventName, callback); @@ -361,8 +367,9 @@ Viva.Graph.Utils.events = function (element) { } }; }; + /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.Utils = Viva.Graph.Utils || {}; @@ -640,8 +647,9 @@ Viva.Graph.Utils.dragndrop = function (element) { } }; }; + /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Input = Viva.Input || {}; @@ -682,6 +690,7 @@ Viva.Input.domInputManager = function (graph, graphics) { } }; }; + /** * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com */ @@ -760,7 +769,8 @@ Viva.Graph.Utils = Viva.Graph.Utils || {}; } }; }; -}());Viva.Graph.geom = function () { +}()); +Viva.Graph.geom = function () { return { // function from Graphics GEM to determine lines intersection: @@ -789,7 +799,7 @@ Viva.Graph.Utils = Viva.Graph.Utils || {}; */ if (r3 !== 0 && r4 !== 0 && ((r3 >= 0) === (r4 >= 4))) { - return null; //no itersection. + return null; //no intersection. } /* Compute a2, b2, c2 */ @@ -854,7 +864,7 @@ Viva.Graph.Utils = Viva.Graph.Utils || {}; dy = p.y - basePoint.y, sign = dx > 0 ? 1 : -1; - // We use squared dx, to avoid Sqrt opertion and improve performance. + // We use squared dx, to avoid Sqrt operation and improve performance. // To avoid sign loss during dx * dx operation we precompute its sign: return sign * dx * dx / (dx * dx + dy * dy); }, @@ -945,8 +955,10 @@ Viva.Graph.Utils = Viva.Graph.Utils || {}; return s; } }; -};/** - * Very generic rectangle. +}; + +/** + * Very generic rectangle. */ Viva.Graph.Rect = function (x1, y1, x2, y2) { this.x1 = x1 || 0; @@ -981,10 +993,11 @@ Viva.Graph.Link = function (fromId, toId, data, id) { this.data = data; this.id = id; }; + /** * @fileOverview Contains definition of the core graph object. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ /** @@ -1003,7 +1016,7 @@ Viva.Graph.graph = function () { // hold all links related to that node. And general links // array is used to speed up all links enumeration. This is inefficient // in terms of memory, but simplifies coding. Furthermore, the graph structure - // is isolated from outter world, and can be changed to adjacency matrix later. + // is isolated from outer world, and can be changed to adjacency matrix later. var nodes = (typeof Object.create === 'function') ? Object.create(null) : {}, links = [], @@ -1012,7 +1025,7 @@ Viva.Graph.graph = function () { nodesCount = 0, suspendEvents = 0, - // Accumlates all changes made during graph updates. + // Accumulates all changes made during graph updates. // Each change element contains: // changeType - one of the strings: 'add', 'remove' or 'update'; // node - if change is related to node this property is set to changed graph's node; @@ -1024,7 +1037,7 @@ Viva.Graph.graph = function () { graph.fire('changed', changes); }, - // Enter, Exit Mofidication allows bulk graph updates without firing events. + // Enter, Exit modification allows bulk graph updates without firing events. enterModification = function () { suspendEvents += 1; }, @@ -1253,7 +1266,7 @@ Viva.Graph.graph = function () { // I.e. use array + 'for' iterator instead of dictionary + 'for .. in'? for (node in nodes) { if (callback(nodes[node])) { - return; // client doesn't want to proceed. return. + return; // client doesn't want to proceed. } } }, @@ -1273,7 +1286,7 @@ Viva.Graph.graph = function () { linkedNodeId; if (node && node.links && typeof callback === 'function') { - // Extraced orientation check out of the loop to increase performance + // Extracted orientation check out of the loop to increase performance if (oriented) { for (i = 0; i < node.links.length; ++i) { link = node.links[i]; @@ -1368,10 +1381,11 @@ Viva.Graph.graph = function () { return graphPart; }; + /** - * @fileOverview Contains collection of primitve operations under graph. + * @fileOverview Contains collection of primitive operations under graph. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.operations = function () { @@ -1400,6 +1414,7 @@ Viva.Graph.operations = function () { } }; }; + Viva.Graph.Physics = Viva.Graph.Physics || {}; Viva.Graph.Physics.Vector = function (x, y) { @@ -1473,6 +1488,7 @@ Viva.Graph.Physics.QuadTreeNode = function () { this.x2 = 0; this.y2 = 0; }; + Viva.Graph.Physics = Viva.Graph.Physics || {}; /** @@ -1524,10 +1540,11 @@ Viva.Graph.Physics.eulerIntegrator = function () { } }; }; + /** * This is Barnes Hut simulation algorithm. Implementation * is adopted to non-recursive solution, since certain browsers - * handle recursion extremly bad. + * handle recursion extremely bad. * * http://www.cs.princeton.edu/courses/archive/fall03/cs126/assignments/barnes-hut.html */ @@ -1685,7 +1702,7 @@ Viva.Graph.Physics.nbodyForce = function (options) { // To achieve this we have to convert current leaf into internal node // and continue adding two nodes. var oldBody = node.body; - node.body = null; // internal nodes do not cary bodies + node.body = null; // internal nodes do not carry bodies node.isInternal = true; if (isSamePosition(oldBody.location, body.location)) { @@ -1749,13 +1766,13 @@ Viva.Graph.Physics.nbodyForce = function (options) { r = Math.sqrt(dx * dx + dy * dy); if (r === 0) { - // Poor man's protection agains zero distance. + // Poor man's protection against zero distance. dx = (random.nextDouble() - 0.5) / 50; dy = (random.nextDouble() - 0.5) / 50; r = Math.sqrt(dx * dx + dy * dy); } - // This is standard gravition force calculation but we divide + // This is standard gravitation force calculation but we divide // by r^3 to save two operations when normalizing force vector. v = gravity * body.mass * sourceBody.mass / (r * r * r); sourceBody.force.x = sourceBody.force.x + v * dx; @@ -1769,7 +1786,7 @@ Viva.Graph.Physics.nbodyForce = function (options) { r = Math.sqrt(dx * dx + dy * dy); if (r === 0) { - // Sorry about code duplucation. I don't want to create many functions + // Sorry about code duplication. I don't want to create many functions // right away. Just want to see performance first. dx = (random.nextDouble() - 0.5) / 50; dy = (random.nextDouble() - 0.5) / 50; @@ -1851,6 +1868,7 @@ Viva.Graph.Physics.nbodyForce = function (options) { } }; }; + Viva.Graph.Physics.dragForce = function (options) { if (!options) { options = {}; @@ -1876,6 +1894,7 @@ Viva.Graph.Physics.dragForce = function (options) { } }; }; + Viva.Graph.Physics.springForce = function (currentOptions) { currentOptions = Viva.lazyExtend(currentOptions, { length : 50, @@ -1920,12 +1939,13 @@ Viva.Graph.Physics.springForce = function (currentOptions) { } }; }; + Viva.Graph.Physics = Viva.Graph.Physics || {}; /** * Manages a simulation of physical forces acting on bodies. * To create a custom force simulator register forces of the system - * via addForce() method, choos appropriate integrator and register + * via addForce() method, choose appropriate integrator and register * bodies. * * // TODO: Show example. @@ -2082,6 +2102,7 @@ Viva.Graph.Physics.forceSimulator = function (forceIntegrator) { } }; }; + // I don't like to suppress this, but I'm afraid 'force_directed_body' // could already be used by someone. Don't want to break it now. /* jshint camelcase:false */ @@ -2112,7 +2133,7 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { gravity: -1.2, /** - * Theta coeffiecient from Barnes Hut simulation. Ranged between (0, 1). + * Theta coefficient from Barnes Hut simulation. Ranged between (0, 1). * The closer it's to 1 the more nodes algorithm will have to go through. * Setting it to one makes Barnes Hut simulation no different from * brute-force forces calculation (each node is considered). @@ -2126,7 +2147,7 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { dragCoeff: 0.02, /** - * Allows to transfor physical spring associated with a link. this allows clients + * Allows to transform physical spring associated with a link. This allows clients * to specify custom length for a link. * * @param {Viva.Graph.Link} link actual link for which transform is performed @@ -2489,9 +2510,9 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { }, /** - * Gets or sets current spring coeffiсient. + * Gets or sets current spring coefficient. * - * @param coeff new spring coeffiсient. + * @param coeff new spring coefficient. * if this parameter is empty then its old value returned. */ springCoeff: function(coeff) { @@ -2525,7 +2546,7 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { /** * Gets or sets current theta value in the nbody simulation. * - * @param t new theta coeffiсient. + * @param t new theta coefficient. * if this parameter is empty then its old value returned. */ theta: function(t) { @@ -2542,7 +2563,7 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { /** * Gets or sets current theta value in the nbody simulation. * - * @param dragCoeff new drag coeffiсient. + * @param dragCoeff new drag coefficient. * if this parameter is empty then its old value returned. */ drag: function(dragCoeff) { @@ -2557,6 +2578,7 @@ Viva.Graph.Layout.forceDirected = function(graph, settings) { } }; }; + Viva.Graph.Layout = Viva.Graph.Layout || {}; /** @@ -2739,10 +2761,11 @@ Viva.Graph.Layout.constant = function (graph, userSettings) { }; }; + /** * @fileOverview Defines a graph renderer that uses CSS based drawings. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.View = Viva.Graph.View || {}; @@ -2779,14 +2802,14 @@ Viva.Graph.View = Viva.Graph.View || {}; * renderLinks : true, * * // Number of layout iterations to run before displaying the graph. The bigger you set this number - * // the closer to ideal position graph will apper first time. But be careful: for large graphs + * // the closer to ideal position graph will appear first time. But be careful: for large graphs * // it can freeze the browser. * prerender : 0 * } */ Viva.Graph.View.renderer = function (graph, settings) { // TODO: This class is getting hard to understand. Consider refactoring. - // TODO: I have a technical debt here: fix scaling/recentring! Currently it's total mess. + // TODO: I have a technical debt here: fix scaling/recentering! Currently it's a total mess. var FRAME_INTERVAL = 30; settings = settings || {}; @@ -3034,7 +3057,7 @@ Viva.Graph.View.renderer = function (graph, settings) { releaseGraphEvents = function () { if (graphEvents) { - // Interesting.. why is it not null? Anyway: + // Interesting.. Why is it not null? Anyway: graphEvents.stop('changed', onGraphChanged); graphEvents = null; } @@ -3198,6 +3221,7 @@ Viva.Graph.View.renderer = function (graph, settings) { } }; }; + Viva.Graph.serializer = function () { var checkJSON = function () { if (typeof JSON === 'undefined' || !JSON.stringify || !JSON.parse) { @@ -3297,19 +3321,20 @@ Viva.Graph.serializer = function () { } }; }; + /** - * @fileOverview Centrality calcuation algorithms. - * + * @fileOverview Centrality calculation algorithms. + * * @see http://en.wikipedia.org/wiki/Centrality * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.centrality = function () { var singleSourceShortestPath = function (graph, node, oriented) { // I'm using the same naming convention used in http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf // sorry about cryptic names. - var P = {}, // predcessors lists. + var P = {}, // predecessors lists. S = [], sigma = {}, d = {}, @@ -3400,26 +3425,26 @@ Viva.Graph.centrality = function () { /** * Compute the shortest-path betweenness centrality for all nodes in a graph. - * - * Betweenness centrality of a node `n` is the sum of the fraction of all-pairs + * + * Betweenness centrality of a node `n` is the sum of the fraction of all-pairs * shortest paths that pass through `n`. Runtime O(n * v) for non-weighted graphs. * * @see http://en.wikipedia.org/wiki/Centrality#Betweenness_centrality - * - * @see A Faster Algorithm for Betweenness Centrality. + * + * @see A Faster Algorithm for Betweenness Centrality. * Ulrik Brandes, Journal of Mathematical Sociology 25(2):163-177, 2001. * http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - * - * @see Ulrik Brandes: On Variants of Shortest-Path Betweenness + * + * @see Ulrik Brandes: On Variants of Shortest-Path Betweenness * Centrality and their Generic Computation. * Social Networks 30(2):136-145, 2008. * http://www.inf.uni-konstanz.de/algo/publications/b-vspbc-08.pdf - * + * * @see Ulrik Brandes and Christian Pich: Centrality Estimation in Large Networks. * International Journal of Bifurcation and Chaos 17(7):2303-2318, 2007. * http://www.inf.uni-konstanz.de/algo/publications/bp-celn-06.pdf - * - * @param graph for which we are calculating betweenness centrality. Non-weighted graphs are only supported + * + * @param graph for which we are calculating betweenness centrality. Non-weighted graphs are only supported */ betweennessCentrality : function (graph) { var betweennes = {}, @@ -3438,9 +3463,9 @@ Viva.Graph.centrality = function () { /** * Calculates graph nodes degree centrality (in/out or both). - * + * * @see http://en.wikipedia.org/wiki/Centrality#Degree_centrality - * + * * @param graph for which we are calculating centrality. * @param kind optional parameter. Valid values are * 'in' - calculate in-degree centrality @@ -3506,29 +3531,33 @@ Viva.Graph.centrality = function () { return result; } }; -};/** +}; + +/** * @fileOverview Community structure detection algorithms - * + * * @see http://en.wikipedia.org/wiki/Community_structure * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.community = function () { return { /** * Implementation of Speaker-listener Label Propagation Algorithm (SLPA) of - * Jierui Xie and Boleslaw K. Szymanski. - * + * Jierui Xie and Boleslaw K. Szymanski. + * * @see http://arxiv.org/pdf/1109.5720v3.pdf - * @see https://sites.google.com/site/communitydetectionslpa/ + * @see https://sites.google.com/site/communitydetectionslpa/ */ slpa : function (graph, T, r) { var algorithm = Viva.Graph._community.slpaAlgorithm(graph, T, r); return algorithm.run(); } }; -};Viva.Graph._community = {}; +}; + +Viva.Graph._community = {}; /** * Implementation of Speaker-listener Label Propagation Algorithm (SLPA) of @@ -3660,7 +3689,7 @@ Viva.Graph._community.slpaAlgorithm = function (graph, T, r) { * A data structure which serves as node memory during SLPA execution. The main idea is to * simplify operations on memory such as * - add word to memory, - * - get random word from memory, with probablity proportional to word occurrence in the memory + * - get random word from memory, with probability proportional to word occurrence in the memory * - get the most popular word in memory * * TODO: currently this structure is extremely inefficient in terms of memory. I think it could be @@ -3690,9 +3719,9 @@ Viva.Graph._community.occuranceMap = function (random) { return result; } - // Not only number of occurances matters but order of keys also does. + // Not only number of occurrences matters but order of keys also does. // for ... in implementation in different browsers results in different - // order, and if we want to have same categories accross all browsers + // order, and if we want to have same categories across all browsers // we should order words by key names too: if (x < y) { return -1; } if (x > y) { return 1; } @@ -3726,7 +3755,7 @@ Viva.Graph._community.occuranceMap = function (random) { }, /** - * Gets number of occurances for a given word. If word is not present in the dictionary + * Gets number of occurrences for a given word. If word is not present in the dictionary * zero is returned. */ getWordCount : function (word) { @@ -3735,7 +3764,7 @@ Viva.Graph._community.occuranceMap = function (random) { /** * Gets the most popular word in the map. If multiple words are at the same position - * random word among them is choosen. + * random word among them is chosen. * */ getMostPopularFair : function () { @@ -3750,7 +3779,7 @@ Viva.Graph._community.occuranceMap = function (random) { for (i = 1; i < uniqueWords.length; ++i) { if (wordsCount[uniqueWords[i - 1]] !== wordsCount[uniqueWords[i]]) { - break; // other words are less popular... not interested. + break; // other words are less popular... Not interested. } else { maxCount += 1; } @@ -3766,7 +3795,7 @@ Viva.Graph._community.occuranceMap = function (random) { */ getRandomWord : function () { if (allWords.length === 0) { - throw 'The occurance map is empty. Cannot get empty word'; + throw 'The occurrence map is empty. Cannot get empty word'; } return allWords[random.next(allWords.length)]; @@ -3774,7 +3803,7 @@ Viva.Graph._community.occuranceMap = function (random) { /** * Enumerates all unique words in the map, and calls - * callback(word, occuranceCount) function on each word. Callback + * callback(word, occurrenceCount) function on each word. Callback * can return true value to stop enumeration. * * Note: enumeration is guaranteed in to run in decreasing order. @@ -3798,10 +3827,12 @@ Viva.Graph._community.occuranceMap = function (random) { } } }; -};/** +}; + +/** * @fileOverview Contains collection of graph generators. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.generator = function () { @@ -3843,7 +3874,7 @@ Viva.Graph.generator = function () { */ completeBipartite : function (n, m) { if (!n || !m || n < 0 || m < 0) { - throw { message: "Graph dimensions are invalid. Number of nodes in each partition should be greate than 0" }; + throw { message: "Graph dimensions are invalid. Number of nodes in each partition should be greater than 0" }; } var g = Viva.Graph.graph(), @@ -4001,10 +4032,12 @@ Viva.Graph.generator = function () { } }; }; + /** * @fileOverview Defines a graph renderer that uses CSS based drawings. * * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * TODO: this should not be part of the library */ // The file tries to conform generic interface: /*jshint unused: false */ @@ -4013,10 +4046,10 @@ Viva.Graph.View = Viva.Graph.View || {}; /** * Performs css-based graph rendering. This module does not perform - * layout, but only visualizes nodes and edeges of the graph. + * layout, but only visualizes nodes and edges of the graph. * - * NOTE: Most likely I will remove this graphics engine due to superior svg support. - * In certain cases it doesn't work and require further imporvments: + * NOTE: Most likely I will remove this graphics engine due to superior SVG support. + * In certain cases it doesn't work and require further improvements: * * does not properly work for dragging. * * does not support scaling. * * does not support IE versions prior to IE9. @@ -4080,7 +4113,7 @@ Viva.Graph.View.cssGraphics = function () { // IE 6, 7 and 8 are screwed up when it comes to transforms; // I could not find justification for their choice of "floating" // matrix transform origin. The following ugly code was written - // out of complete dispair. + // out of complete despair. if (angleRad < 0) { angleRad = 2 * Math.PI + angleRad; } @@ -4160,7 +4193,7 @@ Viva.Graph.View.cssGraphics = function () { return { /** - * Sets the collback that creates node representation or creates a new node + * Sets the callback that creates node representation or creates a new node * presentation if builderCallbackOrNode is not a function. * * @param builderCallbackOrNode a callback function that accepts graph node @@ -4181,7 +4214,7 @@ Viva.Graph.View.cssGraphics = function () { }, /** - * Sets the collback that creates link representation or creates a new link + * Sets the callback that creates link representation or creates a new link * presentation if builderCallbackOrLink is not a function. * * @param builderCallbackOrLink a callback function that accepts graph link @@ -4324,8 +4357,9 @@ Viva.Graph.View.cssGraphics = function () { } }; }; + /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ /** @@ -4448,6 +4482,7 @@ Viva.Graph.svg = function (element) { return svgElement; }; + /** * @fileOverview Defines a graph renderer that uses SVG based drawings. * @@ -4458,7 +4493,7 @@ Viva.Graph.View = Viva.Graph.View || {}; /** * Performs svg-based graph rendering. This module does not perform - * layout, but only visualizes nodes and edeges of the graph. + * layout, but only visualizes nodes and edges of the graph. */ Viva.Graph.View.svgGraphics = function () { var svgContainer, @@ -4478,7 +4513,7 @@ Viva.Graph.View.svgGraphics = function () { }, nodePositionCallback = function (nodeUI, pos) { - // TODO: Remove magic 5. It should be halfo of the width or height of the node. + // TODO: Remove magic 5. It should be half of the width or height of the node. nodeUI.attr("x", pos.x - 5) .attr("y", pos.y - 5); }, @@ -4533,7 +4568,7 @@ Viva.Graph.View.svgGraphics = function () { */ node : function (builderCallback) { if (typeof builderCallback !== "function") { - return; // todo: throw? this is not compatible with old versions + return; // todo: throw? This is not compatible with old versions } nodeBuilder = builderCallback; @@ -4548,11 +4583,11 @@ Viva.Graph.View.svgGraphics = function () { * as a parameter and must return an element representing this link. * * @returns If builderCallback is a valid callback function, instance of this is returned; - * Otherwise undefined value is returend. + * Otherwise undefined value is returned. */ link : function (builderCallback) { if (typeof builderCallback !== "function") { - return; // todo: throw? this is not compatible with old versions + return; // todo: throw? This is not compatible with old versions } linkBuilder = builderCallback; @@ -4622,7 +4657,7 @@ Viva.Graph.View.svgGraphics = function () { p.x = scrollPoint.x; p.y = scrollPoint.y; - p = p.matrixTransform(svgContainer.getCTM().inverse()); // translate to svg coordinates + p = p.matrixTransform(svgContainer.getCTM().inverse()); // translate to SVG coordinates // Compute new scale matrix in current mouse position var k = svgRoot.createSVGMatrix().translate(p.x, p.y).scale(scaleFactor).translate(-p.x, -p.y), @@ -4653,7 +4688,7 @@ Viva.Graph.View.svgGraphics = function () { init : function (container) { container.appendChild(svgRoot); updateTransform(); - // Notify the world if someoen waited for update. TODO: should send an event + // Notify the world if someone waited for update. TODO: should send an event if (typeof initCallback === "function") { initCallback(svgRoot); } @@ -4776,7 +4811,7 @@ Viva.Graph.View.svgGraphics = function () { return svgRoot; }, /** - * Returns root svg element. + * Returns root SVG element. * * Note: This is internal method specific to this renderer */ @@ -4801,13 +4836,14 @@ Viva.Graph.View.svgGraphics = function () { return svgRoot; } }; + /** * @fileOverview I used this class to render links UI within * node. Lesser SVG elements is proven to improve performance * but I'm not happy with the code result here. Probably this class * will be removed from future versions. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.View.svgNodeFactory = function (graph) { @@ -4852,7 +4888,7 @@ Viva.Graph.View.svgNodeFactory = function (graph) { }, /** - * Sets a callback function for custom nodes contnet. + * Sets a callback function for custom nodes content. * @param conentCreator(nodeUI, node) - callback function which returns a node content UI. * Image, for example. * @param sizeProvider(nodeUI) - a callback function which accepts nodeUI returned by @@ -4924,6 +4960,7 @@ Viva.Graph.View.svgNodeFactory = function (graph) { }; }; + /** * @fileOverview Utility functions for webgl rendering. * @@ -5024,11 +5061,12 @@ Viva.Graph.webgl = function (gl) { context : gl }; }; + /** * @fileOverview Defines a model objects to represents graph rendering * primitives in webglGraphics. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.View.WebglUtils = function () { }; @@ -5086,7 +5124,7 @@ Viva.Graph.View.webglLine = function (color) { Viva.Graph.View.webglSquare = function (size, color) { return { /** - * Gets or sets size of the sqare side. + * Gets or sets size of the square side. */ size : typeof size === 'number' ? size : 10, @@ -5103,7 +5141,7 @@ Viva.Graph.View.webglSquare = function (size, color) { Viva.Graph.View.webglImage = function (size, src) { return { /** - * Gets texture index where current image is placed.s + * Gets texture index where current image is placed. */ _texture : 0, @@ -5118,17 +5156,19 @@ Viva.Graph.View.webglImage = function (size, src) { size : typeof size === 'number' ? size : 32, /** - * Source of the image. If image is comming not from your domain + * Source of the image. If image is coming not from your domain * certain origin restrictions applies. * See http://www.khronos.org/registry/webgl/specs/latest/#4.2 for more details. */ src : src }; -};/** +}; + +/** * @fileOverview Defines a naive form of nodes for webglGraphics class. * This form allows to change color of node. Shape of nodes is rectangular. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ /** @@ -5266,12 +5306,13 @@ Viva.Graph.View.webglNodeProgram = function () { } }; }; + /** * @fileOverview Defines a naive form of links for webglGraphics class. * This form allows to change color of links. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com - */ + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka + **/ /** * Defines UI for links in webgl renderer. @@ -5420,9 +5461,10 @@ Viva.Graph.View.webglLinkProgram = function () { } }; }; + /** * @fileOverview Defines an image nodes for webglGraphics class. - * Shape of nodes is sqare. + * Shape of nodes is square. * * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com */ @@ -5439,7 +5481,7 @@ Viva.Graph.View.Texture = function (size) { /** * My naive implementation of textures atlas. It allows clients to load - * multimple images into atlas and get canvas representing all of them. + * multiple images into atlas and get canvas representing all of them. * * @param tilesPerTexture - indicates how many images can be loaded to one * texture of the atlas. If number of loaded images exceeds this @@ -5544,7 +5586,7 @@ Viva.Graph.View.webglAtlas = function (tilesPerTexture) { }, /** - * Removes given url from colleciton of tiles in the atlas. + * Removes given url from collection of tiles in the atlas. */ remove : function (imgUrl) { var coordinates = loadedImages[imgUrl]; @@ -5838,17 +5880,19 @@ Viva.Graph.View.webglImageNodeProgram = function () { gl.drawArrays(gl.TRIANGLES, 0, nodesCount * 6); } }; -};/** +}; + +/** * @fileOverview Defines a graph renderer that uses WebGL based drawings. * - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Graph.View = Viva.Graph.View || {}; /** * Performs webgl-based graph rendering. This module does not perform - * layout, but only visualizes nodes and edeges of the graph. + * layout, but only visualizes nodes and edges of the graph. * * @param options - to customize graphics behavior. Currently supported parameter * enableBlending - true by default, allows to use transparency in node/links colors. @@ -5939,7 +5983,7 @@ Viva.Graph.View.webglGraphics = function (options) { }, /** - * Sets the collback that creates node representation. + * Sets the callback that creates node representation. * * @param builderCallback a callback function that accepts graph node * as a parameter and must return an element representing this node. @@ -5949,7 +5993,7 @@ Viva.Graph.View.webglGraphics = function (options) { */ node : function (builderCallback) { if (typeof builderCallback !== "function") { - return; // todo: throw? this is not compatible with old versions + return; // todo: throw? This is not compatible with old versions } nodeUIBuilder = builderCallback; @@ -5964,11 +6008,11 @@ Viva.Graph.View.webglGraphics = function (options) { * as a parameter and must return an element representing this link. * * @returns If builderCallback is a valid callback function, instance of this is returned; - * Otherwise undefined value is returend. + * Otherwise undefined value is returned. */ link : function (builderCallback) { if (typeof builderCallback !== "function") { - return; // todo: throw? this is not compatible with old versions + return; // todo: throw? This is not compatible with old versions } linkUIBuilder = builderCallback; @@ -6154,7 +6198,7 @@ Viva.Graph.View.webglGraphics = function (options) { var color = options.clearColorValue; gl.clearColor(color.r, color.g, color.b, color.a); // TODO: not the best way, really. Should come up with something better - // what if we need more updates inisde beginRender, like depth buffer? + // what if we need more updates inside beginRender, like depth buffer? this.beginRender = function () { gl.clear(gl.COLOR_BUFFER_BIT); }; @@ -6168,7 +6212,7 @@ Viva.Graph.View.webglGraphics = function (options) { updateTransformUniform(); - // Notify the world if someoen waited for update. TODO: should send an event + // Notify the world if someone waited for update. TODO: should send an event if (typeof initCallback === "function") { initCallback(graphicsRoot); } @@ -6243,7 +6287,7 @@ Viva.Graph.View.webglGraphics = function (options) { nodes[nodeIdToRemove] = lastNodeUI; lastNodeUI.id = nodeIdToRemove; - // Since concrete shaders may cache properties in the ui element + // Since concrete shaders may cache properties in the UI element // we are letting them to make this swap (e.g. image node shader // uses this approach to update node's offset in the atlas) nodeProgram.replaceProperties(nodeUI, lastNodeUI); @@ -6314,7 +6358,7 @@ Viva.Graph.View.webglGraphics = function (options) { // and let initialization logic take care about the rest. nodeProgram = newProgram; } else if (newProgram) { - throw "Not implemented. Cannot swap shader on the fly... yet."; + throw "Not implemented. Cannot swap shader on the fly... Yet."; // TODO: unload old shader and reinit. } }, @@ -6330,7 +6374,7 @@ Viva.Graph.View.webglGraphics = function (options) { // and let initialization logic take care about the rest. linkProgram = newProgram; } else if (newProgram) { - throw "Not implemented. Cannot swap shader on the fly... yet."; + throw "Not implemented. Cannot swap shader on the fly... Yet."; // TODO: unload old shader and reinit. } }, @@ -6376,6 +6420,7 @@ Viva.Graph.View.webglGraphics = function (options) { return graphics; }; + /** * Monitors graph-related mouse input in webgl graphics and notifies subscribers. * @@ -6593,8 +6638,9 @@ Viva.Graph.webglInputEvents = function (webglGraphics) { return webglGraphics.webglInputEvents; }; + /** - * @author Andrei Kashcha (aka anvaka) / http://anvaka.blogspot.com + * @author Andrei Kashcha (aka anvaka) / https://github.com/anvaka */ Viva.Input = Viva.Input || {}; diff --git a/dist/vivagraph.min.js b/dist/vivagraph.min.js index d2ea134..f11c7cb 100644 --- a/dist/vivagraph.min.js +++ b/dist/vivagraph.min.js @@ -1,2 +1,2 @@ -var Viva=Viva||{};Viva.Graph=Viva.Graph||{},"undefined"!=typeof module&&module.exports&&(module.exports=Viva),Viva.Graph.version="0.5.8",Viva.lazyExtend=function(e,t){var n;if(e||(e={}),t)for(n in t)if(t.hasOwnProperty(n)){var r=e.hasOwnProperty(n),i=typeof t[n],o=!r||typeof e[n]!==i;o?e[n]=t[n]:"object"===i&&(e[n]=Viva.lazyExtend(e[n],t[n]))}return e},Viva.random=function(){var e,t=arguments[0];e="number"==typeof t?t:"string"==typeof t?t.length:+new Date;var n=function(){return e=4294967295&e+2127912214+(e<<12),e=4294967295&(3345072700^e^e>>>19),e=4294967295&e+374761393+(e<<5),e=4294967295&(e+3550635116^e<<9),e=4294967295&e+4251993797+(e<<3),e=4294967295&(3042594569^e^e>>>16),(268435455&e)/268435456};return{next:function(e){return Math.floor(n()*e)},nextDouble:function(){return n()}}},Viva.randomIterator=function(e,t){return t=t||Viva.random(),{forEach:function(n){var r,i,o;for(r=e.length-1;r>0;--r)i=t.next(r+1),o=e[i],e[i]=e[r],e[r]=o,n(o);e.length&&n(e[0])},shuffle:function(){var n,r,i;for(n=e.length-1;n>0;--n)r=t.next(n+1),i=e[r],e[r]=e[n],e[n]=i;return e}}},Viva.BrowserInfo=function(){if("undefined"==typeof window||!window.hasOwnProperty("navigator"))return{browser:"",version:"0"};var e=window.navigator.userAgent.toLowerCase(),t=/(webkit)[ \/]([\w.]+)/,n=/(opera)(?:.*version)?[ \/]([\w.]+)/,r=/(msie) ([\w.]+)/,i=/(mozilla)(?:.*? rv:([\w.]+))?/,o=t.exec(e)||n.exec(e)||r.exec(e)||0>e.indexOf("compatible")&&i.exec(e)||[];return{browser:o[1]||"",version:o[2]||"0"}}(),Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.indexOfElementInArray=function(e,t){if(t.indexOf)return t.indexOf(e);var n,r=t.length;for(n=0;r>n;n+=1)if(t.hasOwnProperty(n)&&t[n]===e)return n;return-1},Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.getDimension=function(e){if(!e)throw{message:"Cannot get dimensions of undefined container"};var t=e.clientWidth,n=e.clientHeight;return{left:0,top:0,width:t,height:n}},Viva.Graph.Utils.findElementPosition=function(e){var t=0,n=0;if(e.offsetParent)do t+=e.offsetLeft,n+=e.offsetTop;while(null!==(e=e.offsetParent));return[t,n]},Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.events=function(e){var t=function(e){var t={};return e.fire=function(e,n){var r,i,o,a;if("string"!=typeof e)throw"Only strings can be used as even type";if(t.hasOwnProperty(e))for(r=t[e],a=0;r.length>a;++a)o=r[a],i=o.method,i(n);return this},e.addEventListener=function(e,n){if("function"!=typeof n)throw"Only functions allowed to be callbacks";var r={method:n};return t.hasOwnProperty(e)?t[e].push(r):t[e]=[r],this},e.removeEventListener=function(e,n){if("function"!=typeof n)throw"Only functions allowed to be callbacks";if(t.hasOwnProperty(e)){var r,i=t[e];for(r=0;i.length>r;++r)if(i[r].callback===n){i.splice(r);break}}return this},e.removeAllListeners=function(){var e;for(e in t)t.hasOwnProperty(e)&&delete t[e]},e};return{on:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),this},stop:function(t,n){e.removeEventListener?e.removeEventListener(t,n,!1):e.detachEvent&&e.detachEvent("on"+t,n)},extend:function(){return t(e)}}},Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.dragndrop=function(e){var t,n,r,i,o,a,u,s=Viva.Graph.Utils.events(window.document),f=Viva.Graph.Utils.events(e),c=Viva.Graph.Utils.findElementPosition,d=0,l=0,h=!1,v=0,p=function(e){var t=0,n=0;return e=e||window.event,e.pageX||e.pageY?(t=e.pageX,n=e.pageY):(e.clientX||e.clientY)&&(t=e.clientX+window.document.body.scrollLeft+window.document.documentElement.scrollLeft,n=e.clientY+window.document.body.scrollTop+window.document.documentElement.scrollTop),[t,n]},m=function(e,t,r){n&&n(e,{x:t-d,y:r-l}),d=t,l=r},g=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},y=function(e){e.preventDefault&&e.preventDefault()},x=function(e){return g(e),!1},w=function(e){e=e||window.event,m(e,e.clientX,e.clientY)},V=function(e){if(e=e||window.event,h)return g(e),!1;var n=1===e.button&&null!==window.event||0===e.button;return n?(d=e.clientX,l=e.clientY,u=e.target||e.srcElement,t&&t(e,{x:d,y:l}),s.on("mousemove",w),s.on("mouseup",b),g(e),o=window.document.onselectstart,a=window.document.ondragstart,window.document.onselectstart=x,u.ondragstart=x,!1):void 0},b=function(e){e=e||window.event,s.stop("mousemove",w),s.stop("mouseup",b),window.document.onselectstart=o,u.ondragstart=a,u=null,r&&r(e)},N=function(t){if("function"==typeof i){t=t||window.event,t.preventDefault&&t.preventDefault(),t.returnValue=!1;var n,r=p(t),o=c(e),a={x:r[0]-o[0],y:r[1]-o[1]};n=t.wheelDelta?t.wheelDelta/360:t.detail/-9,i(t,n,a)}},P=function(t){!i&&t?"webkit"===Viva.BrowserInfo.browser?e.addEventListener("mousewheel",N,!1):e.addEventListener("DOMMouseScroll",N,!1):i&&!t&&("webkit"===Viva.BrowserInfo.browser?e.removeEventListener("mousewheel",N,!1):e.removeEventListener("DOMMouseScroll",N,!1)),i=t},E=function(e,t){return(e.clientX-t.clientX)*(e.clientX-t.clientX)+(e.clientY-t.clientY)*(e.clientY-t.clientY)},G=function(e){if(1===e.touches.length){g(e);var t=e.touches[0];m(e,t.clientX,t.clientY)}else if(2===e.touches.length){var n=E(e.touches[0],e.touches[1]),r=0;v>n?r=-1:n>v&&(r=1),i(e,r,{x:e.touches[0].clientX,y:e.touches[0].clientY}),v=n,g(e),y(e)}},L=function(e){h=!1,s.stop("touchmove",G),s.stop("touchend",L),s.stop("touchcancel",L),u=null,r&&r(e)},_=function(e,n){g(e),y(e),d=n.clientX,l=n.clientY,u=e.target||e.srcElement,t&&t(e,{x:d,y:l}),h||(h=!0,s.on("touchmove",G),s.on("touchend",L),s.on("touchcancel",L))},A=function(t){return console.log("Touch start for ",e),1===t.touches.length?_(t,t.touches[0]):(2===t.touches.length&&(g(t),y(t),v=E(t.touches[0],t.touches[1])),void 0)};return f.on("mousedown",V),f.on("touchstart",A),{onStart:function(e){return t=e,this},onDrag:function(e){return n=e,this},onStop:function(e){return r=e,this},onScroll:function(e){return P(e),this},release:function(){s.stop("mousemove",w),s.stop("mousedown",V),s.stop("mouseup",b),s.stop("touchmove",G),s.stop("touchend",L),s.stop("touchcancel",L),P(null)}}},Viva.Input=Viva.Input||{},Viva.Input.domInputManager=function(e,t){var n={};return{bindDragNDrop:function(e,r){var i;if(r){var o=t.getNodeUI(e.id);i=Viva.Graph.Utils.dragndrop(o),"function"==typeof r.onStart&&i.onStart(r.onStart),"function"==typeof r.onDrag&&i.onDrag(r.onDrag),"function"==typeof r.onStop&&i.onStop(r.onStop),n[e.id]=i}else(i=n[e.id])&&(i.release(),delete n[e.id])}}},Viva.Graph.Utils=Viva.Graph.Utils||{},function(){var e,t,n=0,r=["ms","moz","webkit","o"];for(t="undefined"!=typeof window?window:"undefined"!=typeof global?global:{setTimeout:function(){},clearTimeout:function(){}},e=0;r.length>e&&!t.requestAnimationFrame;++e){var i=r[e];t.requestAnimationFrame=t[i+"RequestAnimationFrame"],t.cancelAnimationFrame=t[i+"CancelAnimationFrame"]||t[i+"CancelRequestAnimationFrame"]}t.requestAnimationFrame||(t.requestAnimationFrame=function(e){var r=(new Date).getTime(),i=Math.max(0,16-(r-n)),o=t.setTimeout(function(){e(r+i)},i);return n=r+i,o}),t.cancelAnimationFrame||(t.cancelAnimationFrame=function(e){t.clearTimeout(e)}),Viva.Graph.Utils.timer=function(e){var n,r=function(){t.cancelAnimationFrame(n),n=0},i=function(){n=t.requestAnimationFrame(i),e()||r()};return i(),{stop:r,restart:function(){n||i()}}}}(),Viva.Graph.geom=function(){return{intersect:function(e,t,n,r,i,o,a,u){var s,f,c,d,l,h,v,p,m,g,y,x,w,V={x:0,y:0};return s=r-t,c=e-n,l=n*t-e*r,m=s*i+c*o+l,g=s*a+c*u+l,0!==m&&0!==g&&m>=0==g>=4?null:(f=u-o,d=i-a,h=a*o-i*u,v=f*e+d*t+h,p=f*n+d*r+h,0!==v&&0!==p&&v>=0==p>=0?null:(y=s*d-f*c,0===y?null:(x=0>y?-y/2:y/2,x=0,w=c*h-d*l,V.x=(0>w?w-x:w+x)/y,w=f*l-s*h,V.y=(0>w?w-x:w+x)/y,V)))},intersectRect:function(e,t,n,r,i,o,a,u){return this.intersect(e,t,e,r,i,o,a,u)||this.intersect(e,r,n,r,i,o,a,u)||this.intersect(n,r,n,t,i,o,a,u)||this.intersect(n,t,e,t,i,o,a,u)},convexHull:function(e){var t=function(e,t){var n,r,i=function(t){var n=t.x-e.x,r=t.y-e.y,i=n>0?1:-1;return i*n*n/(n*n+r*r)},o=t.sort(function(e,t){return i(t)-i(e)}),a=o[0],u=i(a),s=a.x-e.x,f=a.y-e.y,c=s*s+f*f;for(r=1;o.length>r;++r){a=o[r];var d=i(a);d===u?(s=a.x-e.x,f=a.y-e.y,n=s*s+f*f,c>n?o.splice(r,1):o.splice(r-1,1)):u=d}return o},n=function(e,t,n){return 0>(n.x-e.x)*(t.y-e.y)-(n.y-e.y)*(t.x-e.x)};if(3>e.length)return e;var r,i=0;for(r=0;e.length>r;++r)e[r].ya.length)return a;var u=[];u.push(o),u.push(a[0]),u.push(a[1]);var s=u.length;for(r=2;a.length>r;++r){for(;!n(u[s-2],u[s-1],a[r]);)u.pop(),s-=1;u.push(a[r]),s+=1}return u}}},Viva.Graph.Rect=function(e,t,n,r){this.x1=e||0,this.y1=t||0,this.x2=n||0,this.y2=r||0},Viva.Graph.Point2d=function(e,t){this.x=e||0,this.y=t||0},Viva.Graph.Node=function(e){this.id=e,this.links=[],this.data=null},Viva.Graph.Link=function(e,t,n,r){this.fromId=e,this.toId=t,this.data=n,this.id=r},Viva.Graph.graph=function(){var e="function"==typeof Object.create?Object.create(null):{},t=[],n={},r=0,i=0,o=[],a=function(e){e.fire("changed",o)},u=function(){i+=1},s=function(e){i-=1,0===i&&o.length>0&&(a(e),o.length=0)},f=function(e,t){o.push({node:e,changeType:t})},c=function(e,t){o.push({link:e,changeType:t})},d={addNode:function(t,n){if(t===void 0)throw{message:"Invalid node identifier"};u();var i=this.getNode(t);return i?f(i,"update"):(i=new Viva.Graph.Node(t),r++,f(i,"add")),i.data=n,e[t]=i,s(this),i},addLink:function(e,r,i){u();var o=this.getNode(e)||this.addNode(e),a=this.getNode(r)||this.addNode(r),f=""+e+"👉 "+(""+r),d=n.hasOwnProperty(f);(d||this.hasLink(e,r))&&(d||(n[f]=0),f+="@"+ ++n[f]);var l=new Viva.Graph.Link(e,r,i,f);return t.push(l),o.links.push(l),a.links.push(l),c(l,"add"),s(this),l},removeLink:function(e){if(!e)return!1;var n=Viva.Graph.Utils.indexOfElementInArray(e,t);if(0>n)return!1;u(),t.splice(n,1);var r=this.getNode(e.fromId),i=this.getNode(e.toId);return r&&(n=Viva.Graph.Utils.indexOfElementInArray(e,r.links),n>=0&&r.links.splice(n,1)),i&&(n=Viva.Graph.Utils.indexOfElementInArray(e,i.links),n>=0&&i.links.splice(n,1)),c(e,"remove"),s(this),!0},removeNode:function(t){var n=this.getNode(t);if(!n)return!1;for(u();n.links.length;){var i=n.links[0];this.removeLink(i)}e[t]=null,delete e[t],r--,f(n,"remove"),s(this)},getNode:function(t){return e[t]},getNodesCount:function(){return r},getLinksCount:function(){return t.length},getLinks:function(e){var t=this.getNode(e);return t?t.links:null},forEachNode:function(t){if("function"==typeof t){var n;for(n in e)if(t(e[n]))return}},forEachLinkedNode:function(t,n,r){var i,o,a,u=this.getNode(t);if(u&&u.links&&"function"==typeof n)if(r)for(i=0;u.links.length>i;++i)o=u.links[i],o.fromId===t&&n(e[o.toId],o);else for(i=0;u.links.length>i;++i)o=u.links[i],a=o.fromId===t?o.toId:o.fromId,n(e[a],o)},forEachLink:function(e){var n,r;if("function"==typeof e)for(n=0,r=t.length;r>n;++n)e(t[n])},beginUpdate:function(){u()},endUpdate:function(){s(this)},clear:function(){var e=this;e.beginUpdate(),e.forEachNode(function(t){e.removeNode(t.id)}),e.endUpdate()},hasLink:function(e,t){var n,r=this.getNode(e);if(!r)return null;for(n=0;r.links.length>n;++n){var i=r.links[n];if(i.fromId===e&&i.toId===t)return i}return null}};return Viva.Graph.Utils.events(d).extend(),d},Viva.Graph.operations=function(){return{density:function(e,t){var n=e.getNodesCount();return 0===n?0/0:t?e.getLinksCount()/(n*(n-1)):2*e.getLinksCount()/(n*(n-1))}}},Viva.Graph.Physics=Viva.Graph.Physics||{},Viva.Graph.Physics.Vector=function(e,t){this.x=e||0,this.y=t||0},Viva.Graph.Physics.Vector.prototype={multiply:function(e){return new Viva.Graph.Physics.Vector(this.x*e,this.y*e)}},Viva.Graph.Physics.Point=function(e,t){this.x=e||0,this.y=t||0},Viva.Graph.Physics.Point.prototype={add:function(e){return new Viva.Graph.Physics.Point(this.x+e.x,this.y+e.y)}},Viva.Graph.Physics.Body=function(){this.mass=1,this.force=new Viva.Graph.Physics.Vector,this.velocity=new Viva.Graph.Physics.Vector,this.location=new Viva.Graph.Physics.Point,this.prevLocation=new Viva.Graph.Physics.Point},Viva.Graph.Physics.Body.prototype={loc:function(e){return e?(this.location.x=e.x,this.location.y=e.y,this):this.location},vel:function(e){return e?(this.velocity.x=e.x,this.velocity.y=e.y,this):this.velocity}},Viva.Graph.Physics.Spring=function(e,t,n,r,i){this.body1=e,this.body2=t,this.length=n,this.coeff=r,this.weight=i},Viva.Graph.Physics.QuadTreeNode=function(){this.centerOfMass=new Viva.Graph.Physics.Point,this.children=[],this.body=null,this.hasChildren=!1,this.x1=0,this.y1=0,this.x2=0,this.y2=0},Viva.Graph.Physics=Viva.Graph.Physics||{},Viva.Graph.Physics.eulerIntegrator=function(){return{integrate:function(e,t){var n,r=e.speedLimit,i=0,o=0,a=0,u=0,s=e.bodies.length;for(n=0;s>n;++n){var f=e.bodies[n],c=t/f.mass;f.velocity.x+=c*f.force.x,f.velocity.y+=c*f.force.y;var d=f.velocity.x,l=f.velocity.y,h=Math.sqrt(d*d+l*l);h>r&&(f.velocity.x=r*d/h,f.velocity.y=r*l/h),o=t*f.velocity.x,u=t*f.velocity.y,f.location.x+=o,f.location.y+=u,i+=Math.abs(o),a+=Math.abs(u)}return(i+a)/s}}},Viva.Graph.Physics.nbodyForce=function(e){function t(e,t){this.node=e,this.body=t}function n(){this.stack=[],this.popIdx=0}e=Viva.lazyExtend(e||{gravity:-1,theta:.8}),n.prototype={isEmpty:function(){return 0===this.popIdx},push:function(e,n){var r=this.stack[this.popIdx];r?(r.node=e,r.body=n):this.stack[this.popIdx]=new t(e,n),++this.popIdx},pop:function(){return this.popIdx>0?this.stack[--this.popIdx]:void 0},reset:function(){this.popIdx=0}};var r=e.gravity,i=[],o=new n,a=e.theta,u=Viva.random("5f4dcc3b5aa765d61d8327deb882cf99",75,20,63,108,65,76,65,72),s=function(){this.body=null,this.quads=[],this.mass=0,this.massX=0,this.massY=0,this.left=0,this.top=0,this.bottom=0,this.right=0,this.isInternal=!1},f=[],c=0,d=function(){var e;return f[c]?(e=f[c],e.quads[0]=null,e.quads[1]=null,e.quads[2]=null,e.quads[3]=null,e.body=null,e.mass=e.massX=e.massY=0,e.left=e.right=e.top=e.bottom=0,e.isInternal=!1):(e=new s,f[c]=e),++c,e},l=d(),h=function(e,t){var n=Math.abs(e.x-t.x),r=Math.abs(e.y-t.y);return 1e-8>n&&1e-8>r},v=function(e){for(o.reset(),o.push(l,e);!o.isEmpty();){var t=o.pop(),n=t.node,r=t.body;if(n.isInternal){var i=r.location.x,a=r.location.y;n.mass=n.mass+r.mass,n.massX=n.massX+r.mass*i,n.massY=n.massY+r.mass*a;var s=0,f=n.left,c=(n.right+f)/2,v=n.top,p=(n.bottom+v)/2;if(i>c){s+=1;var m=f;f=c,c+=c-m}if(a>p){s+=2;var g=v;v=p,p+=p-g}var y=n.quads[s];y||(y=d(),y.left=f,y.top=v,y.right=c,y.bottom=p,n.quads[s]=y),o.push(y,r)}else if(n.body){var x=n.body;if(n.body=null,n.isInternal=!0,h(x.location,r.location)){if(1e-8>n.right-n.left)return;do{var w=u.nextDouble(),V=(n.right-n.left)*w,b=(n.bottom-n.top)*w;x.location.x=n.left+V,x.location.y=n.top+b}while(h(x.location,r.location))}o.push(n,x),o.push(n,r)}else n.body=r}},p=function(e){var t,n,o,s,f=i,c=1,d=0,h=1;for(f[0]=l;c;){var v=f[d],p=v.body;c-=1,d+=1,p&&p!==e?(n=p.location.x-e.location.x,o=p.location.y-e.location.y,s=Math.sqrt(n*n+o*o),0===s&&(n=(u.nextDouble()-.5)/50,o=(u.nextDouble()-.5)/50,s=Math.sqrt(n*n+o*o)),t=r*p.mass*e.mass/(s*s*s),e.force.x=e.force.x+t*n,e.force.y=e.force.y+t*o):(n=v.massX/v.mass-e.location.x,o=v.massY/v.mass-e.location.y,s=Math.sqrt(n*n+o*o),0===s&&(n=(u.nextDouble()-.5)/50,o=(u.nextDouble()-.5)/50,s=Math.sqrt(n*n+o*o)),a>(v.right-v.left)/s?(t=r*v.mass*e.mass/(s*s*s),e.force.x=e.force.x+t*n,e.force.y=e.force.y+t*o):(v.quads[0]&&(f[h]=v.quads[0],c+=1,h+=1),v.quads[1]&&(f[h]=v.quads[1],c+=1,h+=1),v.quads[2]&&(f[h]=v.quads[2],c+=1,h+=1),v.quads[3]&&(f[h]=v.quads[3],c+=1,h+=1)))}},m=function(e){var t,n=Number.MAX_VALUE,r=Number.MAX_VALUE,i=Number.MIN_VALUE,o=Number.MIN_VALUE,a=e.bodies,u=a.length;for(t=u;t--;){var s=a[t].location.x,f=a[t].location.y;n>s&&(n=s),s>i&&(i=s),r>f&&(r=f),f>o&&(o=f)}var h=i-n,p=o-r;for(h>p?o=r+h:i=n+p,c=0,l=d(),l.left=n,l.right=i,l.top=r,l.bottom=o,t=u;t--;)v(a[t],l)};return{insert:v,init:m,update:p,options:function(e){return e?("number"==typeof e.gravity&&(r=e.gravity),"number"==typeof e.theta&&(a=e.theta),this):{gravity:r,theta:a}}}},Viva.Graph.Physics.dragForce=function(e){e||(e={});var t={coeff:e.coeff||.01};return{update:function(e){e.force.x-=t.coeff*e.velocity.x,e.force.y-=t.coeff*e.velocity.y},options:function(e){return e?("number"==typeof e.coeff&&(t.coeff=e.coeff),this):t}}},Viva.Graph.Physics.springForce=function(e){e=Viva.lazyExtend(e,{length:50,coeff:22e-5});var t=Viva.random("Random number 4.","Chosen by fair dice roll");return{update:function(n){var r=n.body1,i=n.body2,o=0>n.length?e.length:n.length,a=i.location.x-r.location.x,u=i.location.y-r.location.y,s=Math.sqrt(a*a+u*u);0===s&&(a=(t.nextDouble()-.5)/50,u=(t.nextDouble()-.5)/50,s=Math.sqrt(a*a+u*u));var f=s-o,c=(!n.coeff||0>n.coeff?e.coeff:n.coeff)*f/s*n.weight;r.force.x+=c*a,r.force.y+=c*u,i.force.x+=-c*a,i.force.y+=-c*u},options:function(t){return t?("number"==typeof t.length&&(e.length=t.length),"number"==typeof t.coeff&&(e.coeff=t.coeff),this):e}}},Viva.Graph.Physics=Viva.Graph.Physics||{},Viva.Graph.Physics.forceSimulator=function(e){var t,n,r,i=e,o=[],a=[];return{speedLimit:1,bodies:o,accumulate:function(){var e,i;for(n.init(this),e=o.length;e--;)i=o[e],i.force.x=0,i.force.y=0,n.update(i),r.update(i);for(e=a.length;e--;)t.update(a[e])},run:function(e){return this.accumulate(),i.integrate(this,e)},addBody:function(e){if(!e)throw{message:"Cannot add null body to force simulator"};return o.push(e),e},removeBody:function(e){if(!e)return!1;var t=Viva.Graph.Utils.indexOfElementInArray(e,o);return 0>t?!1:o.splice(t,1)},addSpring:function(e,t,n,r,i){if(!e||!t)throw{message:"Cannot add null spring to force simulator"};if("number"!=typeof n)throw{message:"Spring length should be a number"};r="number"==typeof r?r:1;var o=new Viva.Graph.Physics.Spring(e,t,n,i>=0?i:-1,r);return a.push(o),o},removeSpring:function(e){if(!e)return!1;var t=Viva.Graph.Utils.indexOfElementInArray(e,a);return 0>t?!1:a.splice(t,1)},setNbodyForce:function(e){if(!e)throw{message:"Cannot add mighty (unknown) force to the simulator"};n=e},setDragForce:function(e){if(!e)throw{message:"Cannot add mighty (unknown) force to the simulator"};r=e},setSpringForce:function(e){if(!e)throw{message:"Cannot add unknown force to the simulator"};t=e}}},Viva.Graph.Layout=Viva.Graph.Layout||{},Viva.Graph.Layout.forceDirected=function(e,t){if(!e)throw{message:"Graph structure cannot be undefined"};t=Viva.lazyExtend(t,{springLength:80,springCoeff:2e-4,gravity:-1.2,theta:.8,dragCoeff:.02,springTransform:function(){},timeStep:20,stableThreshold:.009});var n=Viva.Graph.Physics.forceSimulator(Viva.Graph.Physics.eulerIntegrator()),r=Viva.Graph.Physics.nbodyForce({gravity:t.gravity,theta:t.theta}),i=Viva.Graph.Physics.springForce({length:t.springLength,coeff:t.springCoeff}),o=Viva.Graph.Physics.dragForce({coeff:t.dragCoeff}),a=new Viva.Graph.Rect,u=Viva.random("ted.com",103,114,101,97,116),s={},f=function(e){if(e.position)return e.position;var n=(a.x1+a.x2)/2,r=(a.y1+a.y2)/2,i=t.springLength;if(e.links&&e.links.length>0){var o=e.links[0],f=o.fromId!==e.id?s[o.fromId]:s[o.toId];f&&f.location&&(n=f.location.x,r=f.location.y)}return{x:n+u.next(i)-i/2,y:r+u.next(i)-i/2}},c=function(e){return s[e]},d=function(e){s[e]=null,delete s[e]},l={},h=function(t){var n=c(t);n.mass=1+e.getLinks(t).length/3},v=function(e){return e&&(e.isPinned||e.data&&e.data.isPinned)},p=function(e){return e.isPinned},m=function(t){var r=c(t);if(!r){var i=e.getNode(t);if(!i)return;r=new Viva.Graph.Physics.Body,s[t]=r;var o=f(i);r.loc(o),h(t),v(i)&&(r.isPinned=!0),n.addBody(r)}},g=function(e){m(e.id)},y=function(t){var r=c(t.id);r&&(d(t.id),n.removeBody(r),0===e.getNodesCount()&&(a.x1=a.y1=0,a.x2=a.y2=0))},x=function(e){h(e.fromId),h(e.toId);var r=c(e.fromId),i=c(e.toId),o=n.addSpring(r,i,-1,e.weight);t.springTransform(e,o),l[e.id]=o},w=function(t){var r=l[t.id];if(r){var i=e.getNode(t.fromId),o=e.getNode(t.toId);i&&h(i.id),o&&h(o.id),delete l[t.id],n.removeSpring(r)}},V=function(e){for(var t=0;e.length>t;++t){var n=e[t];"add"===n.changeType?(n.node&&m(n.node.id),n.link&&x(n.link)):"remove"===n.changeType&&(n.node&&y(n.node),n.link&&w(n.link))}},b=function(){e.forEachNode(g),e.forEachLink(x),e.addEventListener("changed",V)},N=function(){var t=Number.MAX_VALUE,n=Number.MAX_VALUE,r=Number.MIN_VALUE,i=Number.MIN_VALUE;if(0!==e.getNodesCount()){for(var o in s)if(s.hasOwnProperty(o)){var u=s[o];p(u)?(u.location.x=u.prevLocation.x,u.location.y=u.prevLocation.y):(u.prevLocation.x=u.location.x,u.prevLocation.y=u.location.y),t>u.location.x&&(t=u.location.x),u.location.x>r&&(r=u.location.x),n>u.location.y&&(n=u.location.y),u.location.y>i&&(i=u.location.y)}a.x1=t,a.x2=r,a.y1=n,a.y2=i}};return n.setSpringForce(i),n.setNbodyForce(r),n.setDragForce(o),b(),{run:function(e){var t;for(e=e||50,t=0;e>t;++t)this.step()},step:function(){var e=n.run(t.timeStep);return N(),t.stableThreshold>e},isNodePinned:function(e){var t=c(e.id);return t?p(t):void 0},pinNode:function(e,t){var n=c(e.id);n.isPinned=!!t},getNodePosition:function(e){var t=c(e);return t||(m(e),t=c(e)),t&&t.location},getLinkPosition:function(e){var t=this.getNodePosition(e.fromId),n=this.getNodePosition(e.toId);return{from:t,to:n}},setNodePosition:function(e,t,n){var r=c(e.id);r&&(r.prevLocation.x=r.location.x=t,r.prevLocation.y=r.location.y=n)},getGraphRect:function(){return a},dispose:function(){e.removeEventListener("change",V)},springLength:function(e){return 1===arguments.length?(i.options({length:e}),this):i.options().length},springCoeff:function(e){return 1===arguments.length?(i.options({coeff:e}),this):i.options().coeff},gravity:function(e){return 1===arguments.length?(r.options({gravity:e}),this):r.options().gravity},theta:function(e){return 1===arguments.length?(r.options({theta:e}),this):r.options().theta},drag:function(e){return 1===arguments.length?(o.options({coeff:e}),this):o.options().coeff}}},Viva.Graph.Layout=Viva.Graph.Layout||{},Viva.Graph.Layout.constant=function(e,t){t=Viva.lazyExtend(t,{maxX:1024,maxY:1024,seed:"Deterministic randomness made me do this"});var n=Viva.random(t.seed),r=new Viva.Graph.Rect(Number.MAX_VALUE,Number.MAX_VALUE,Number.MIN_VALUE,Number.MIN_VALUE),i=function(){return new Viva.Graph.Point2d(n.next(t.maxX),n.next(t.maxY))},o=function(e,t){e.xt.x2&&(t.x2=e.x),e.yt.y2&&(t.y2=e.y)},a="function"==typeof Object.create?Object.create(null):{},u=function(e){e&&(a[e.id]=i(e),o(a[e.id],r))},s=function(){0!==e.getNodesCount()&&(r.x1=Number.MAX_VALUE,r.y1=Number.MAX_VALUE,r.x2=Number.MIN_VALUE,r.y2=Number.MIN_VALUE,e.forEachNode(u))},f=function(e){for(var t=0;e.length>t;++t){var n=e[t];n.node&&("add"===n.changeType?u(n.node):delete a[n.node.id])}};return e.addEventListener("changed",f),{run:function(){this.step()},step:function(){return s(),!0},getGraphRect:function(){return r},dispose:function(){e.removeEventListener("change",f)},isNodePinned:function(){return!0},pinNode:function(){},getNodePosition:function(t){var n=a[t];return n||u(e.getNode(t)),n},getLinkPosition:function(e){var t=this.getNodePosition(e.fromId),n=this.getNodePosition(e.toId);return{from:t,to:n}},setNodePosition:function(e,t,n){var r=a[e.id];r&&(r.x=t,r.y=n)},placeNode:function(e){return"function"==typeof e?(i=e,s(),this):i(e)}}},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.renderer=function(e,t){var n=30;t=t||{};var r,i,o,a,u=t.layout,s=t.graphics,f=t.container,c=void 0!==t.interactive?t.interactive:!0,d=!1,l=!0,h=0,v=0,p=!1,m=!1,g=!1,y={x:0,y:0},x={offsetX:0,offsetY:0,scale:1},w=function(){f=f||window.document.body,u=u||Viva.Graph.Layout.forceDirected(e),s=s||Viva.Graph.View.svgGraphics(e,{container:f}),t.hasOwnProperty("renderLinks")||(t.renderLinks=!0),t.prerender=t.prerender||0,r=(s.inputManager||Viva.Input.domInputManager)(e,s)},V=Viva.Graph.Utils.events(window),b=Viva.Graph.Utils.events({}).extend(),N=function(){s.beginRender(),t.renderLinks&&s.renderLinks(),s.renderNodes(),s.endRender()},P=function(){return p=u.step()&&!m,N(),!p},E=function(e){return i?(v+=e,void 0):(e?(v+=e,i=Viva.Graph.Utils.timer(function(){return P()},n)):(h=0,v=0,i=Viva.Graph.Utils.timer(P,n)),void 0)},G=function(){g||(p=!1,i.restart())},L=function(){var e;if("number"==typeof t.prerender&&t.prerender>0)for(e=0;t.prerender>e;e+=1)u.step()},_=function(){var e=u.getGraphRect(),t=Viva.Graph.Utils.getDimension(f);y.x=y.y=0,x.offsetX=t.width/2-(e.x2+e.x1)/2,x.offsetY=t.height/2-(e.y2+e.y1)/2,s.graphCenterChanged(x.offsetX,x.offsetY),l=!1},A=function(e){var t=u.getNodePosition(e.id);s.addNode(e,t)},I=function(e){s.releaseNode(e)},k=function(e){var t=u.getLinkPosition(e);s.addLink(e,t)},T=function(e){s.releaseLink(e)},C=function(e){var t=!1,n="string"==typeof c&&-1!==c.indexOf("node")||c;n&&r.bindDragNDrop(e,{onStart:function(){t=u.isNodePinned(e),u.pinNode(e,!0),m=!0,G()},onDrag:function(t,n){var r=u.getNodePosition(e.id);u.setNodePosition(e,r.x+n.x/x.scale,r.y+n.y/x.scale),m=!0,N()},onStop:function(){u.pinNode(e,t),m=!1}})},S=function(e){r.bindDragNDrop(e,null)},M=function(){s.init(f),e.forEachNode(A),t.renderLinks&&e.forEachLink(k)},U=function(){s.release(f)},D=function(t){var n=t.node;"add"===t.changeType?(A(n),C(n),l&&_()):"remove"===t.changeType?(S(n),I(n),0===e.getNodesCount()&&(l=!0)):"update"===t.changeType&&(S(n),I(n),A(n),C(n))},R=function(e){var n=e.link;if("add"===e.changeType)t.renderLinks&&k(n);else if("remove"===e.changeType)t.renderLinks&&T(n);else if("update"===e.changeType)throw"Update type is not implemented. TODO: Implement me!"},O=function(e){var t,n;for(t=0;e.length>t;t+=1)n=e[t],n.node?D(n):n.link&&R(n);G()},F=function(){_(),P()},z=function(){a&&(a.release(),a=null)},B=function(){o&&(o.stop("changed",O),o=null)},Y=function(e,t){if(!t){var n=Viva.Graph.Utils.getDimension(f);t={x:n.width/2,y:n.height/2}}var r=Math.pow(1.4,e?-.2:.2);return x.scale=s.scale(r,t),N(),b.fire("scale",x.scale),x.scale},X=function(){V.on("resize",F),z();var t="string"==typeof c&&-1!==c.indexOf("drag")||c;t&&(a=Viva.Graph.Utils.dragndrop(f),a.onDrag(function(e,t){y.x+=t.x,y.y+=t.y,s.translateRel(t.x,t.y),N()}));var n="string"==typeof c&&-1!==c.indexOf("scroll")||c;n&&a.onScroll(function(e,t,n){Y(0>t,n)}),e.forEachNode(C),B(),o=Viva.Graph.Utils.events(e),o.on("changed",O)},q=function(){d=!1,B(),z(),V.stop("resize",F),b.removeAllListeners(),i.stop(),e.forEachLink(function(e){t.renderLinks&&T(e)}),e.forEachNode(function(e){S(e),I(e)}),u.dispose(),U()};return{run:function(e){return d||(w(),L(),_(),M(),X(),d=!0),E(e),this},reset:function(){s.resetScale(),_(),x.scale=1},pause:function(){g=!0,i.stop()},resume:function(){g=!1,i.restart()},rerender:function(){return N(),this},zoomOut:function(){return Y(!0)},zoomIn:function(){return Y(!1)},moveTo:function(e,t){s.graphCenterChanged(x.offsetX-e*x.scale,x.offsetY-t*x.scale),N()},getGraphics:function(){return s},dispose:function(){q()},on:function(e,t){return b.addEventListener(e,t),this},off:function(e,t){return b.removeEventListener(e,t),this}}},Viva.Graph.serializer=function(){var e=function(){if("undefined"==typeof JSON||!JSON.stringify||!JSON.parse)throw"JSON serializer is not defined."},t=function(e){return{id:e.id,data:e.data}},n=function(e){return{fromId:e.fromId,toId:e.toId,data:e.data}},r=function(e){return e},i=function(e){return e};return{storeToJSON:function(r,i,o){if(!r)throw"Graph is not defined";e(),i=i||t,o=o||n;var a={nodes:[],links:[]};return r.forEachNode(function(e){a.nodes.push(i(e))}),r.forEachLink(function(e){a.links.push(o(e))}),JSON.stringify(a)},loadFromJSON:function(t,n,o){if("string"!=typeof t)throw"String expected in loadFromJSON() method";e(),n=n||r,o=o||i;var a,u=JSON.parse(t),s=Viva.Graph.graph();if(!u||!u.nodes||!u.links)throw"Passed json string does not represent valid graph";for(a=0;u.nodes.length>a;++a){var f=n(u.nodes[a]);if(!f.hasOwnProperty("id"))throw"Graph node format is invalid. Node.id is missing";s.addNode(f.id,f.data)}for(a=0;u.links.length>a;++a){var c=o(u.links[a]);if(!c.hasOwnProperty("fromId")||!c.hasOwnProperty("toId"))throw"Graph link format is invalid. Both fromId and toId are required";s.addLink(c.fromId,c.toId,c.data)}return s}}},Viva.Graph.centrality=function(){var e=function(e,t,n){var r,i,o,a={},u=[],s={},f={},c=[t.id],d=function(e){f.hasOwnProperty(e.id)||(c.push(e.id),f[e.id]=i+1),f[e.id]===i+1&&(s[e.id]+=o,a[e.id].push(r))};for(e.forEachNode(function(e){a[e.id]=[],s[e.id]=0}),f[t.id]=0,s[t.id]=1;c.length;)r=c.shift(),i=f[r],o=s[r],u.push(r),e.forEachLinkedNode(r,d,n);return{S:u,P:a,sigma:s}},t=function(e,t,n){var r,i,o,a,u,s={},f=t.S;for(r=0;f.length>r;r+=1)s[f[r]]=0;for(;f.length;){for(i=f.pop(),o=(1+s[i])/t.sigma[i],a=t.P[i],r=0;a.length>r;r+=1)u=a[r],s[u]+=t.sigma[u]*o;i!==n&&(e[i]+=s[i])}},n=function(e){var t,n=[];for(t in e)e.hasOwnProperty(t)&&n.push({key:t,value:e[t]});return n.sort(function(e,t){return t.value-e.value})};return{betweennessCentrality:function(r){var i,o={};return r.forEachNode(function(e){o[e.id]=0}),r.forEachNode(function(n){i=e(r,n),t(o,i,n)}),n(o)},degreeCentrality:function(e,t){var n,r,i=[],o=[];if(t=(t||"both").toLowerCase(),"in"===t)n=function(e,t){var n,r=0;for(n=0;e.length>n;n+=1)r+=e[n].toId===t?1:0;return r};else if("out"===t)n=function(e,t){var n,r=0;for(n=0;e.length>n;n+=1)r+=e[n].fromId===t?1:0;return r};else{if("both"!==t)throw"Expected centrality degree kind is: in, out or both";n=function(e){return e.length}}e.forEachNode(function(t){var r=e.getLinks(t.id),o=n(r,t.id);i.hasOwnProperty(o)?i[o].push(t.id):i[o]=[t.id]});for(r in i)if(i.hasOwnProperty(r)){var a,u=i[r];if(u)for(a=0;u.length>a;++a)o.unshift({key:u[a],value:parseInt(r,10)})}return o}}},Viva.Graph.community=function(){return{slpa:function(e,t,n){var r=Viva.Graph._community.slpaAlgorithm(e,t,n);return r.run()}}},Viva.Graph._community={},Viva.Graph._community.slpaAlgorithm=function(e,t,n){t=t||100,n=n||.3;var r=Viva.random(1331782216905),i=Viva.random("Greeting goes to you, ","dear reader"),o=function(e,n){var r=[];return e.forEachUniqueWord(function(e,i){return i>n?(r.push({name:e,probability:i/t}),void 0):!0}),r},a=function(e){var t=[];return e.forEachNode(function(e){var n=Viva.Graph._community.occuranceMap(r);n.add(e.id),e.slpa={memory:n},t.push(e.id)}),t},u=function(e,n){var o,a=Viva.randomIterator(n,i),u=function(t){var n=e.getNode(t),i=Viva.Graph._community.occuranceMap(r);e.forEachLinkedNode(t,function(e){var t=e.slpa.memory.getRandomWord();i.add(t)});var o=i.getMostPopularFair();n.slpa.memory.add(o)};for(o=0;t-1>o;++o)a.forEach(u)},s=function(e){var r={};return e.forEachNode(function(e){var i,a=o(e.slpa.memory,n*t);for(i=0;a.length>i;++i){var u=a[i].name;r.hasOwnProperty(u)?r[u].push(e.id):r[u]=[e.id]}e.communities=a,e.slpa=null,delete e.slpa}),r};return{run:function(){var t=a(e);return u(e,t),s(e)}}},Viva.Graph._community.occuranceMap=function(e){e=e||Viva.random();var t={},n=[],r=!1,i=[],o=function(){var e;i.length=0;for(e in t)t.hasOwnProperty(e)&&i.push(e);i.sort(function(e,n){var r=t[n]-t[e];return r?r:n>e?-1:e>n?1:0})},a=function(){r&&(o(),r=!1)};return{add:function(e){e+="",t.hasOwnProperty(e)?t[e]+=1:t[e]=1,n.push(e),r=!0},getWordCount:function(e){return t[e]||0},getMostPopularFair:function(){if(1===n.length)return n[0];a();var r,o=0;for(r=1;i.length>r&&t[i[r-1]]===t[i[r]];++r)o+=1;return o+=1,i[e.next(o)]},getRandomWord:function(){if(0===n.length)throw"The occurance map is empty. Cannot get empty word";return n[e.next(n.length)]},forEachUniqueWord:function(e){if("function"!=typeof e)throw"Function callback is expected to enumerate all words";var n;for(a(),n=0;i.length>n;++n){var r=i[n],o=t[r],u=e(r,o);if(u)break}}}},Viva.Graph.generator=function(){return{complete:function(e){if(!e||1>e)throw{message:"At least two nodes expected for complete graph"};var t,n,r=Viva.Graph.graph();for(r.Name="Complete K"+e,t=0;e>t;++t)for(n=t+1;e>n;++n)t!==n&&r.addLink(t,n);return r},completeBipartite:function(e,t){if(!e||!t||0>e||0>t)throw{message:"Graph dimensions are invalid. Number of nodes in each partition should be greate than 0"};var n,r,i=Viva.Graph.graph();for(i.Name="Complete K "+e+","+t,n=0;e>n;++n)for(r=e;e+t>r;++r)i.addLink(n,r); -return i},ladder:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Ladder graph "+e,t=0;e-1>t;++t)n.addLink(t,t+1),n.addLink(e+t,e+t+1),n.addLink(t,e+t);return n.addLink(e-1,2*e-1),n},circularLadder:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t=this.ladder(e);return t.Name="Circular ladder graph "+e,t.addLink(0,e-1),t.addLink(e,2*e-1),t},grid:function(e,t){var n,r,i=Viva.Graph.graph();for(i.Name="Grid graph "+e+"x"+t,n=0;e>n;++n)for(r=0;t>r;++r){var o=n+r*e;n>0&&i.addLink(o,n-1+r*e),r>0&&i.addLink(o,n+(r-1)*e)}return i},path:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Path graph "+e,n.addNode(0),t=1;e>t;++t)n.addLink(t-1,t);return n},lollipop:function(e,t){if(!t||0>t||!e||0>e)throw{message:"Invalid number of nodes"};var n,r=this.complete(e);for(r.Name="Lollipop graph. Head x Path "+e+"x"+t,n=0;t>n;++n)r.addLink(e+n-1,e+n);return r},balancedBinTree:function(e){var t,n=Viva.Graph.graph(),r=Math.pow(2,e);for(n.Name="Balanced bin tree graph "+e,t=1;r>t;++t){var i=t,o=2*i,a=2*i+1;n.addLink(i,o),n.addLink(i,a)}return n},randomNoLinks:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Random graph, no Links: "+e,t=0;e>t;++t)n.addNode(t);return n}}},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.cssGraphics=function(){var e,t,n,r="OLD_IE",i=1,o=1,a=function(){var e,t,n=Viva.BrowserInfo.browser;switch(n){case"mozilla":e="Moz";break;case"webkit":e="webkit";break;case"opera":e="O";break;case"msie":if(t=Viva.BrowserInfo.version.split(".")[0],!(t>8))return r;e="ms"}return e?e+"Transform":null}(),u=function(){return a===r?function(e,t,n,r){var i=Math.cos(r),o=Math.sin(r);0>r&&(r=2*Math.PI+r),Math.PI/2>r?(e.style.left=t+"px",e.style.top=n+"px"):Math.PI>r?(e.style.left=t-e.clientWidth*Math.cos(Math.PI-r),e.style.top=n):Math.PI+Math.PI/2>r?(e.style.left=t-e.clientWidth*Math.cos(Math.PI-r),e.style.top=n+e.clientWidth*Math.sin(Math.PI-r)):(e.style.left=t,e.style.top=n+e.clientWidth*Math.sin(Math.PI-r)),e.style.filter='progid:DXImageTransform.Microsoft.Matrix(sizingMethod="auto expand",M11='+i+", M12="+-o+","+"M21="+o+", M22="+i+");"}:a?function(e,t,n,r){e.style.left=t+"px",e.style.top=n+"px",e.style[a]="rotate("+r+"rad)",e.style[a+"Origin"]="left"}:function(){}}(),s=function(){var e=window.document.createElement("div");return e.setAttribute("class","node"),e},f=function(e,t){e.style.left=t.x-5+"px",e.style.top=t.y-5+"px"},c=function(e,t,n){var r=t.x-n.x,i=t.y-n.y,o=Math.sqrt(r*r+i*i);e.style.height="1px",e.style.width=o+"px",u(e,n.x,n.y,Math.atan2(i,r))},d=function(){var e=window.document.createElement("div");return e.setAttribute("class","link"),e},l=function(){if(e){if(!a||a===r)throw"Not implemented. TODO: Implement OLD_IE Filter based transform";var u="matrix("+i+", 0, 0,"+o+","+t+","+n+")";e.style[a]=u}};return{node:function(e){return e&&"function"!=typeof e?s(e):(s=e,this)},link:function(e){return e&&"function"!=typeof e?d(e):(d=e,this)},inputManager:Viva.Input.domInputManager,graphCenterChanged:function(e,r){t=e,n=r,l()},translateRel:function(e,r){t+=e,n+=r,l()},scale:function(){return 1},resetScale:function(){return this},beginRender:function(){},endRender:function(){},placeNode:function(e){return f=e,this},placeLink:function(e){return c=e,this},init:function(t){e=t,l()},initLink:function(t){e.childElementCount>0?e.insertBefore(t,e.firstChild):e.appendChild(t)},releaseLink:function(t){e.removeChild(t)},initNode:function(t){e.appendChild(t)},releaseNode:function(t){e.removeChild(t)},updateNodePosition:function(e,t){f(e,t)},updateLinkPosition:function(e,t,n){c(e,t,n)}}},Viva.Graph.svg=function(e){var t="http://www.w3.org/2000/svg",n="http://www.w3.org/1999/xlink",r=e;return"string"==typeof e&&(r=window.document.createElementNS(t,e)),r.vivagraphAugmented?r:(r.vivagraphAugmented=!0,r.attr=function(e,t){return 2===arguments.length?(null!==t?r.setAttributeNS(null,e,t):r.removeAttributeNS(null,e),r):r.getAttributeNS(null,e)},r.append=function(e){var t=Viva.Graph.svg(e);return r.appendChild(t),t},r.text=function(e){return e!==void 0?(r.textContent=e,r):r.textContent},r.link=function(e){return arguments.length?(r.setAttributeNS(n,"xlink:href",e),r):r.getAttributeNS(n,"xlink:href")},r.children=function(e){var t,n,i=[],o=r.childNodes.length;if(void 0===e&&r.hasChildNodes())for(t=0;o>t;t++)i.push(Viva.Graph.svg(r.childNodes[t]));else if("string"==typeof e){var a="."===e[0],u="#"===e[0],s=!a&&!u;for(t=0;o>t;t++){var f=r.childNodes[t];if(1===f.nodeType){var c=f.attr("class"),d=f.attr("id"),l=f.nodeName;if(a&&c){for(c=c.replace(/\s+/g," ").split(" "),n=0;c.length>n;n++)if(a&&c[n]===e.substr(1)){i.push(Viva.Graph.svg(f));break}}else{if(u&&d===e.substr(1)){i.push(Viva.Graph.svg(f));break}s&&l===e&&i.push(Viva.Graph.svg(f))}i=i.concat(Viva.Graph.svg(f).children(e))}}if(u&&1===i.length)return i[0]}return i},r)},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.svgGraphics=function(){function e(){var e=Viva.Graph.svg("svg");return t=Viva.Graph.svg("g").attr("buffered-rendering","dynamic"),e.appendChild(t),e}var t,n,r,i,o,a=1,u={},s={},f=function(){return Viva.Graph.svg("rect").attr("width",10).attr("height",10).attr("fill","#00a2e8")},c=function(e,t){e.attr("x",t.x-5).attr("y",t.y-5)},d=function(){return Viva.Graph.svg("line").attr("stroke","#999")},l=function(e,t,n){e.attr("x1",t.x).attr("y1",t.y).attr("x2",n.x).attr("y2",n.y)},h=function(e){e.fire("rescaled")},v={x:0,y:0},p={x:0,y:0},m={x:0,y:0},g=function(){if(t){var e="matrix("+a+", 0, 0,"+a+","+r+","+i+")";t.attr("transform",e)}};n=e();var y={getNodeUI:function(e){return u[e]},getLinkUI:function(e){return s[e]},node:function(e){return"function"==typeof e?(f=e,this):void 0},link:function(e){return"function"==typeof e?(d=e,this):void 0},placeNode:function(e){return c=e,this},placeLink:function(e){return l=e,this},beginRender:function(){},endRender:function(){},graphCenterChanged:function(e,t){r=e,i=t,g()},inputManager:Viva.Input.domInputManager,translateRel:function(e,r){var i=n.createSVGPoint(),o=t.getCTM(),a=n.createSVGPoint().matrixTransform(o.inverse());i.x=e,i.y=r,i=i.matrixTransform(o.inverse()),i.x=(i.x-a.x)*o.a,i.y=(i.y-a.y)*o.d,o.e+=i.x,o.f+=i.y;var u="matrix("+o.a+", 0, 0,"+o.d+","+o.e+","+o.f+")";t.attr("transform",u)},scale:function(e,o){var u=n.createSVGPoint();u.x=o.x,u.y=o.y,u=u.matrixTransform(t.getCTM().inverse());var s=n.createSVGMatrix().translate(u.x,u.y).scale(e).translate(-u.x,-u.y),f=t.getCTM().multiply(s);a=f.a,r=f.e,i=f.f;var c="matrix("+f.a+", 0, 0,"+f.d+","+f.e+","+f.f+")";return t.attr("transform",c),h(this),a},resetScale:function(){a=1;var e="matrix(1, 0, 0, 1, 0, 0)";return t.attr("transform",e),h(this),this},init:function(e){e.appendChild(n),g(),"function"==typeof o&&o(n)},release:function(e){n&&e&&e.removeChild(n)},addLink:function(e,n){var r=d(e);if(r)return r.position=n,r.link=e,s[e.id]=r,t.childElementCount>0?t.insertBefore(r,t.firstChild):t.appendChild(r),r},releaseLink:function(e){var n=s[e.id];n&&(t.removeChild(n),delete s[e.id])},addNode:function(e,n){var r=f(e);if(r)return r.position=n,r.node=e,u[e.id]=r,t.appendChild(r),r},releaseNode:function(e){var n=u[e.id];n&&(t.removeChild(n),delete u[e.id])},renderNodes:function(){for(var e in u)if(u.hasOwnProperty(e)){var t=u[e];v.x=t.position.x,v.y=t.position.y,c(t,v,t.node)}},renderLinks:function(){for(var e in s)if(s.hasOwnProperty(e)){var t=s[e];p.x=t.position.from.x,p.y=t.position.from.y,m.x=t.position.to.x,m.y=t.position.to.y,l(t,p,m,t.link)}},getGraphicsRoot:function(e){return"function"==typeof e&&(n?e(n):o=e),n},getSvgRoot:function(){return n}};return Viva.Graph.Utils.events(y).extend(),y},Viva.Graph.View.svgNodeFactory=function(e){var t="#999",n=Viva.Graph.geom(),r=function(e){e.size={w:10,h:10},e.append("rect").attr("width",e.size.w).attr("height",e.size.h).attr("stroke","orange").attr("fill","orange")},i=function(e){return e.size};return{node:function(e){var t=Viva.Graph.svg("g");return r(t,e),t.nodeId=e.id,t},link:function(n){var r=e.getNode(n.fromId),i=r&&r.ui;if(i&&!i.linksContainer){var o=Viva.Graph.svg("path").attr("stroke",t);return i.linksContainer=o,o}return null},customContent:function(e,t){if("function"!=typeof e||"function"!=typeof t)throw"Two functions expected: contentCreator(nodeUI, node) and size(nodeUI)";r=e,i=t},placeNode:function(t,r){var o="",a=i(t);e.forEachLinkedNode(t.nodeId,function(e,u){if(e.position&&e.ui&&e.ui!==t&&u.fromId===t.nodeId){var s=i(e.ui),f=e.position,c=n.intersectRect(r.x-a.w/2,r.y-a.h/2,r.x+a.w/2,r.y+a.h/2,r.x,r.y,f.x,f.y)||r,d=n.intersectRect(f.x-s.w/2,f.y-s.h/2,f.x+s.w/2,f.y+s.h/2,f.x,f.y,r.x,r.y)||f;o+="M"+Math.round(c.x)+" "+Math.round(c.y)+"L"+Math.round(d.x)+" "+Math.round(d.y)}}),t.attr("transform","translate("+(r.x-a.w/2)+", "+(r.y-a.h/2)+")"),""!==o&&t.linksContainer&&t.linksContainer.attr("d",o)}}},Viva.Graph.webgl=function(e){var t=function(t,n){var r=e.createShader(n);if(e.shaderSource(r,t),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS)){var i=e.getShaderInfoLog(r);throw window.alert(i),i}return r};return{createProgram:function(n,r){var i=e.createProgram(),o=t(n,e.VERTEX_SHADER),a=t(r,e.FRAGMENT_SHADER);if(e.attachShader(i,o),e.attachShader(i,a),e.linkProgram(i),!e.getProgramParameter(i,e.LINK_STATUS)){var u=e.getShaderInfoLog(i);throw window.alert(u),u}return i},extendArray:function(e,t,n){if((t+1)*n>e.length){var r=new Float32Array(2*e.length*n);return r.set(e),r}return e},copyArrayPart:function(e,t,n,r){var i;for(i=0;r>i;++i)e[t+i]=e[n+i]},swapArrayPart:function(e,t,n,r){var i;for(i=0;r>i;++i){var o=e[t+i];e[t+i]=e[n+i],e[n+i]=o}},getLocations:function(t,n){var r,i={};for(r=0;n.length>r;++r){var o=n[r],a=-1;if(0===o.indexOf("a_")){if(a=e.getAttribLocation(t,o),-1===a)throw"Program doesn't have required attribute: "+o;i[o.slice(2)]=a}else{if(0!==o.indexOf("u_"))throw"Couldn't figure out your intent. All uniforms should start with 'u_' prefix, and attributes with 'a_'";if(a=e.getUniformLocation(t,o),null===a)throw"Program doesn't have required uniform: "+o;i[o.slice(2)]=a}}return i},context:e}},Viva.Graph.View.WebglUtils=function(){},Viva.Graph.View.WebglUtils.prototype.parseColor=function(e){var t=10414335;if("string"==typeof e&&e)if(4===e.length&&(e=e.replace(/([^#])/g,"$1$1")),9===e.length)t=parseInt(e.substr(1),16);else{if(7!==e.length)throw'Color expected in hex format with preceding "#". E.g. #00ff00. Got value: '+e;t=255|parseInt(e.substr(1),16)<<8}else"number"==typeof e&&(t=e);return t},Viva.Graph.View._webglUtil=new Viva.Graph.View.WebglUtils,Viva.Graph.View.webglLine=function(e){return{color:Viva.Graph.View._webglUtil.parseColor(e)}},Viva.Graph.View.webglSquare=function(e,t){return{size:"number"==typeof e?e:10,color:Viva.Graph.View._webglUtil.parseColor(t)}},Viva.Graph.View.webglImage=function(e,t){return{_texture:0,_offset:0,size:"number"==typeof e?e:32,src:t}},Viva.Graph.View.webglNodeProgram=function(){var e,t,n,r,i,o,a,u,s,f=4,c=3*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT,d=["precision mediump float;","varying vec4 color;","void main(void) {"," gl_FragColor = color;","}"].join("\n"),l=["attribute vec3 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos.xy/u_screenSize, 0, 1);"," gl_PointSize = a_vertexPos.z * u_transform[0][0];"," color = a_color.abgr;","}"].join("\n"),h=new ArrayBuffer(16*c),v=new Float32Array(h),p=new Uint32Array(h),m=0,g=function(){if((m+1)*c>=h.byteLength){var e=new ArrayBuffer(2*h.byteLength),t=new Float32Array(e),n=new Uint32Array(e);n.set(p),v=t,p=n,h=e}};return{load:function(o){t=o,i=Viva.Graph.webgl(o),e=i.createProgram(l,d),t.useProgram(e),r=i.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),t.enableVertexAttribArray(r.vertexPos),t.enableVertexAttribArray(r.color),n=t.createBuffer()},position:function(e,t){var n=e.id;v[n*f]=t.x,v[n*f+1]=t.y,v[n*f+2]=e.size,p[n*f+3]=e.color},updateTransform:function(e){s=!0,u=e},updateSize:function(e,t){o=e,a=t,s=!0},removeNode:function(e){m>0&&(m-=1),m>e.id&&m>0&&i.copyArrayPart(p,e.id*f,m*f,f)},createNode:function(){g(),m+=1},replaceProperties:function(){},render:function(){t.useProgram(e),t.bindBuffer(t.ARRAY_BUFFER,n),t.bufferData(t.ARRAY_BUFFER,h,t.DYNAMIC_DRAW),s&&(s=!1,t.uniformMatrix4fv(r.transform,!1,u),t.uniform2f(r.screenSize,o,a)),t.vertexAttribPointer(r.vertexPos,3,t.FLOAT,!1,f*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(r.color,4,t.UNSIGNED_BYTE,!0,f*Float32Array.BYTES_PER_ELEMENT,12),t.drawArrays(t.POINTS,0,m)}}},Viva.Graph.View.webglLinkProgram=function(){var e,t,n,r,i,o,a,u,s,f,c=6,d=2*(2*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT),l=["precision mediump float;","varying vec4 color;","void main(void) {"," gl_FragColor = color;","}"].join("\n"),h=["attribute vec2 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0.0, 1.0);"," color = a_color.abgr;","}"].join("\n"),v=0,p=new ArrayBuffer(16*d),m=new Float32Array(p),g=new Uint32Array(p),y=function(){if((v+1)*d>p.byteLength){var e=new ArrayBuffer(2*p.byteLength),t=new Float32Array(e),n=new Uint32Array(e);n.set(g),m=t,g=n,p=e}};return{load:function(o){t=o,r=Viva.Graph.webgl(o),e=r.createProgram(h,l),t.useProgram(e),i=r.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),t.enableVertexAttribArray(i.vertexPos),t.enableVertexAttribArray(i.color),n=t.createBuffer()},position:function(e,t,n){var r=e.id,i=r*c;m[i]=t.x,m[i+1]=t.y,g[i+2]=e.color,m[i+3]=n.x,m[i+4]=n.y,g[i+5]=e.color},createLink:function(e){y(),v+=1,o=e.id},removeLink:function(e){v>0&&(v-=1),v>e.id&&v>0&&r.copyArrayPart(g,e.id*c,v*c,c)},updateTransform:function(e){f=!0,s=e},updateSize:function(e,t){a=e,u=t,f=!0},render:function(){t.useProgram(e),t.bindBuffer(t.ARRAY_BUFFER,n),t.bufferData(t.ARRAY_BUFFER,p,t.DYNAMIC_DRAW),f&&(f=!1,t.uniformMatrix4fv(i.transform,!1,s),t.uniform2f(i.screenSize,a,u)),t.vertexAttribPointer(i.vertexPos,2,t.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(i.color,4,t.UNSIGNED_BYTE,!0,3*Float32Array.BYTES_PER_ELEMENT,8),t.drawArrays(t.LINES,0,2*v),o=v-1},bringToFront:function(e){o>e.id&&r.swapArrayPart(m,e.id*c,o*c,c),o>0&&(o-=1)},getFrontLinkId:function(){return o}}},Viva.Graph.View.Texture=function(e){this.canvas=window.document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.isDirty=!1,this.canvas.width=this.canvas.height=e},Viva.Graph.View.webglAtlas=function(e){var t,n,r=Math.sqrt(e||1024)<<0,i=r,o=1,a={},u=0,s=[],f=[],c=function(e){return 0===(e&e-1)},d=function(){var e=new Viva.Graph.View.Texture(r*i);s.push(e)},l=function(t){var n=t/e<<0,i=t%e,o=i/r<<0,a=i%r;return{textureNumber:n,row:o,col:a}},h=function(){n.isDirty=!0,u=0,t=null},v=function(){t&&(window.clearTimeout(t),u+=1,t=null),u>10?h():t=window.setTimeout(h,400)},p=function(e,t){var n=s[e.textureNumber].canvas,r=s[t.textureNumber].ctx,o=t.col*i,a=t.row*i;r.drawImage(n,e.col*i,e.row*i,i,i,o,a,i,i),s[e.textureNumber].isDirty=!0,s[t.textureNumber].isDirty=!0},m=function(e,t,n){var r=l(e),o={offset:e};r.textureNumber>=s.length&&d();var u=s[r.textureNumber];u.ctx.drawImage(t,r.col*i,r.row*i,i,i),f[e]=t.src,a[t.src]=o,u.isDirty=!0,n(o)};if(!c(e))throw"Tiles per texture should be power of two.";return n={isDirty:!1,clearDirty:function(){var e;for(this.isDirty=!1,e=0;s.length>e;++e)s[e].isDirty=!1},remove:function(e){var t=a[e];if(!t)return!1;if(delete a[e],o-=1,o===t.offset)return!0;var n=l(t.offset),r=l(o);p(r,n);var i=a[f[o]];return i.offset=t.offset,f[t.offset]=f[o],v(),!0},getTextures:function(){return s},getCoordinates:function(e){return a[e]},load:function(e,t){if(a.hasOwnProperty(e))t(a[e]);else{var n=new window.Image,r=o;o+=1,n.crossOrigin="anonymous",n.onload=function(){v(),m(r,n,t)},n.src=e}}}},Viva.Graph.View.webglImageNodeProgram=function(){var e,t,n,r,i,o,a,u,s,f,c=18,d=["precision mediump float;","varying vec4 color;","varying vec3 vTextureCoord;","uniform sampler2D u_sampler0;","uniform sampler2D u_sampler1;","uniform sampler2D u_sampler2;","uniform sampler2D u_sampler3;","void main(void) {"," if (vTextureCoord.z == 0.) {"," gl_FragColor = texture2D(u_sampler0, vTextureCoord.xy);"," } else if (vTextureCoord.z == 1.) {"," gl_FragColor = texture2D(u_sampler1, vTextureCoord.xy);"," } else if (vTextureCoord.z == 2.) {"," gl_FragColor = texture2D(u_sampler2, vTextureCoord.xy);"," } else if (vTextureCoord.z == 3.) {"," gl_FragColor = texture2D(u_sampler3, vTextureCoord.xy);"," } else { gl_FragColor = vec4(0, 1, 0, 1); }","}"].join("\n"),l=["attribute vec2 a_vertexPos;","attribute float a_customAttributes;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","uniform float u_tilesPerTexture;","varying vec3 vTextureCoord;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0, 1);","float corner = mod(a_customAttributes, 4.);","float tileIndex = mod(floor(a_customAttributes / 4.), u_tilesPerTexture);","float tilesPerRow = sqrt(u_tilesPerTexture);","float tileSize = 1./tilesPerRow;","float tileColumn = mod(tileIndex, tilesPerRow);","float tileRow = floor(tileIndex/tilesPerRow);","if(corner == 0.0) {"," vTextureCoord.xy = vec2(0, 1);","} else if(corner == 1.0) {"," vTextureCoord.xy = vec2(1, 1);","} else if(corner == 2.0) {"," vTextureCoord.xy = vec2(0, 0);","} else {"," vTextureCoord.xy = vec2(1, 0);","}","vTextureCoord *= tileSize;","vTextureCoord.x += tileColumn * tileSize;","vTextureCoord.y += tileRow * tileSize;","vTextureCoord.z = floor(floor(a_customAttributes / 4.)/u_tilesPerTexture);","}"].join("\n"),h=1024,v=0,p=new Float32Array(64),m=function(e,t){e.nativeObject&&n.deleteTexture(e.nativeObject);var r=n.createTexture();n.activeTexture(n["TEXTURE"+t]),n.bindTexture(n.TEXTURE_2D,r),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,n.RGBA,n.UNSIGNED_BYTE,e.canvas),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR_MIPMAP_NEAREST),n.generateMipmap(n.TEXTURE_2D),n.uniform1i(o["sampler"+t],t),e.nativeObject=r},g=function(){if(e.isDirty){var t,n=e.getTextures();for(t=0;n.length>t;++t)(n[t].isDirty||!n[t].nativeObject)&&m(n[t],t);e.clearDirty()}};return{load:function(a){n=a,i=Viva.Graph.webgl(a),e=new Viva.Graph.View.webglAtlas(h),t=i.createProgram(l,d),n.useProgram(t),o=i.getLocations(t,["a_vertexPos","a_customAttributes","u_screenSize","u_transform","u_sampler0","u_sampler1","u_sampler2","u_sampler3","u_tilesPerTexture"]),n.uniform1f(o.tilesPerTexture,h),n.enableVertexAttribArray(o.vertexPos),n.enableVertexAttribArray(o.customAttributes),r=n.createBuffer()},position:function(e,t){var n=e.id*c;p[n]=t.x-e.size,p[n+1]=t.y-e.size,p[n+2]=4*e._offset,p[n+3]=t.x+e.size,p[n+4]=t.y-e.size,p[n+5]=4*e._offset+1,p[n+6]=t.x-e.size,p[n+7]=t.y+e.size,p[n+8]=4*e._offset+2,p[n+9]=t.x-e.size,p[n+10]=t.y+e.size,p[n+11]=4*e._offset+2,p[n+12]=t.x+e.size,p[n+13]=t.y-e.size,p[n+14]=4*e._offset+1,p[n+15]=t.x+e.size,p[n+16]=t.y+e.size,p[n+17]=4*e._offset+3},createNode:function(t){p=i.extendArray(p,v,c),v+=1;var n=e.getCoordinates(t.src);n?t._offset=n.offset:(t._offset=0,e.load(t.src,function(e){t._offset=e.offset}))},removeNode:function(t){v>0&&(v-=1),v>t.id&&v>0&&(t.src&&e.remove(t.src),i.copyArrayPart(p,t.id*c,v*c,c))},replaceProperties:function(e,t){t._offset=e._offset},updateTransform:function(e){f=!0,s=e},updateSize:function(e,t){a=e,u=t,f=!0},render:function(){n.useProgram(t),n.bindBuffer(n.ARRAY_BUFFER,r),n.bufferData(n.ARRAY_BUFFER,p,n.DYNAMIC_DRAW),f&&(f=!1,n.uniformMatrix4fv(o.transform,!1,s),n.uniform2f(o.screenSize,a,u)),n.vertexAttribPointer(o.vertexPos,2,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),n.vertexAttribPointer(o.customAttributes,1,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,8),g(),n.drawArrays(n.TRIANGLES,0,6*v)}}},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.webglGraphics=function(e){e=Viva.lazyExtend(e,{enableBlending:!0,preserveDrawingBuffer:!1,clearColor:!1,clearColorValue:{r:1,g:1,b:1,a:1}});var t,n,r,i,o,a,u,s,f=0,c=0,d=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],l=[],h=[],v={},p={},m=Viva.Graph.View.webglLinkProgram(),g=Viva.Graph.View.webglNodeProgram(),y=function(){return Viva.Graph.View.webglSquare()},x=function(){return Viva.Graph.View.webglLine(3014898687)},w=function(){m.updateTransform(d),g.updateTransform(d)},V=function(){d=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},b=function(){t&&n&&(i=n.width=Math.max(t.offsetWidth,1),o=n.height=Math.max(t.offsetHeight,1),r&&r.viewport(0,0,i,o),m&&m.updateSize(i/2,o/2),g&&g.updateSize(i/2,o/2))},N=function(e){e.fire("rescaled")};n=window.document.createElement("canvas");var P={getLinkUI:function(e){return p[e]},getNodeUI:function(e){return v[e]},node:function(e){return"function"==typeof e?(y=e,this):void 0},link:function(e){return"function"==typeof e?(x=e,this):void 0},placeNode:function(e){return a=e,this},placeLink:function(e){return u=e,this},inputManager:Viva.Input.webglInputManager,beginRender:function(){},endRender:function(){c>0&&m.render(),f>0&&g.render()},bringLinkToFront:function(e){var t,n,r=m.getFrontLinkId();m.bringToFront(e),r>e.id&&(t=e.id,n=h[r],h[r]=h[t],h[r].id=r,h[t]=n,h[t].id=t)},graphCenterChanged:function(e,t){d[12]=2*e/i-1,d[13]=1-2*t/o,w()},addLink:function(e,t){var n=c++,r=x(e);return r.id=n,r.pos=t,m.createLink(r),h[n]=r,p[e.id]=r,r},addNode:function(e,t){var n=f++,r=y(e);return r.id=n,r.position=t,r.node=e,g.createNode(r),l[n]=r,v[e.id]=r,r},translateRel:function(e,t){d[12]+=2*d[0]*e/i/d[0],d[13]-=2*d[5]*t/o/d[5],w()},scale:function(e,t){var n=2*t.x/i-1,r=1-2*t.y/o;return n-=d[12],r-=d[13],d[12]+=n*(1-e),d[13]+=r*(1-e),d[0]*=e,d[5]*=e,w(),N(this),d[0]},resetScale:function(){return V(),r&&(b(),w()),this},init:function(a){var u={};if(e.preserveDrawingBuffer&&(u.preserveDrawingBuffer=!0),t=a,b(),V(),t.appendChild(n),r=n.getContext("experimental-webgl",u),!r){var f="Could not initialize WebGL. Seems like the browser doesn't support it.";throw window.alert(f),f}if(e.enableBlending&&(r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA),r.enable(r.BLEND)),e.clearColor){var c=e.clearColorValue;r.clearColor(c.r,c.g,c.b,c.a),this.beginRender=function(){r.clear(r.COLOR_BUFFER_BIT)}}m.load(r),m.updateSize(i/2,o/2),g.load(r),g.updateSize(i/2,o/2),w(),"function"==typeof s&&s(n)},release:function(e){n&&e&&e.removeChild(n)},isSupported:function(){var e=window.document.createElement("canvas"),t=e&&e.getContext&&e.getContext("experimental-webgl");return t},releaseLink:function(e){c>0&&(c-=1);var t=p[e.id];delete p[e.id],m.removeLink(t);var n=t.id;if(c>n){if(0===c||c===n)return;var r=h[c];h[n]=r,r.id=n}},releaseNode:function(e){f>0&&(f-=1);var t=v[e.id];delete v[e.id],g.removeNode(t);var n=t.id;if(f>n){if(0===f||f===n)return;var r=l[f];l[n]=r,r.id=n,g.replaceProperties(t,r)}},renderNodes:function(){for(var e={x:0,y:0},t=0;f>t;++t){var n=l[t];e.x=n.position.x,e.y=-n.position.y,a&&a(n,e),g.position(n,e)}},renderLinks:function(){if(!this.omitLinksRendering)for(var e={x:0,y:0},t={x:0,y:0},n=0;c>n;++n){var r=h[n],i=r.pos.from;t.x=i.x,t.y=-i.y,i=r.pos.to,e.x=i.x,e.y=-i.y,u&&u(r,t,e),m.position(r,t,e)}},getGraphicsRoot:function(e){return"function"==typeof e&&(n?e(n):s=e),n},setNodeProgram:function(e){if(!r&&e)g=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... yet."},setLinkProgram:function(e){if(!r&&e)m=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... yet."},transformClientToGraphCoordinates:function(e){return e.x=2*e.x/i-1,e.y=1-2*e.y/o,e.x=(e.x-d[12])/d[0],e.y=(e.y-d[13])/d[5],e.x*=i/2,e.y*=-o/2,e},getNodeAtClientPos:function(e,t){if("function"!=typeof t)return null;this.transformClientToGraphCoordinates(e);for(var n=0;f>n;++n)if(t(l[n],e.x,e.y))return l[n].node;return null}};return Viva.Graph.Utils.events(P).extend(),P},Viva.Graph.webglInputEvents=function(e){if(e.webglInputEvents)return e.webglInputEvents;var t,n,r=function(e,t,n){if(e&&e.size){var r=e.position,i=e.size;return t>r.x-i&&r.x+i>t&&n>r.y-i&&r.y+i>n}return!0},i=function(t){return e.getNodeAtClientPos(t,r)},o=null,a=[],u=[],s=[],f=[],c=[],d=[],l=[],h=Viva.Graph.Utils.events(window.document),v=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},p=function(e){return v(e),!1},m=function(e,t){var n,r;for(n=0;e.length>n;n+=1)if(r=e[n].apply(void 0,t))return!0},g=function(e){var r={x:0,y:0},g=null,y=+new Date,x=function(e){m(c,[g,e]),r.x=e.clientX,r.y=e.clientY},w=function(){h.stop("mousemove",x),h.stop("mouseup",w)},V=function(){n=e.getBoundingClientRect()};window.addEventListener("resize",V),V(),e.addEventListener("mousemove",function(e){if(!o){var t,s=!1;r.x=e.clientX-n.left,r.y=e.clientY-n.top,t=i(r),t&&g!==t?(g=t,s=s||m(a,[g])):null===t&&g!==t&&(s=s||m(u,[g]),g=null),s&&v(e)}}),e.addEventListener("mousedown",function(e){var o,a=!1;r.x=e.clientX-n.left,r.y=e.clientY-n.top,o=[i(r),e],o[0]?(a=m(s,o),h.on("mousemove",x),h.on("mouseup",w),t=window.document.onselectstart,window.document.onselectstart=p,g=o[0]):g=null,a&&v(e)}),e.addEventListener("mouseup",function(e){var o,a=+new Date;r.x=e.clientX-n.left,r.y=e.clientY-n.top,o=[i(r),e],o[0]&&(window.document.onselectstart=t,400>a-y&&o[0]===g?m(l,o):m(d,o),y=a,m(f,o)&&v(e))})};return e.getGraphicsRoot(g),e.webglInputEvents={mouseEnter:function(e){return"function"==typeof e&&a.push(e),this},mouseLeave:function(e){return"function"==typeof e&&u.push(e),this},mouseDown:function(e){return"function"==typeof e&&s.push(e),this},mouseUp:function(e){return"function"==typeof e&&f.push(e),this},mouseMove:function(e){return"function"==typeof e&&c.push(e),this},click:function(e){return"function"==typeof e&&d.push(e),this},dblClick:function(e){return"function"==typeof e&&l.push(e),this},mouseCapture:function(e){o=e},releaseMouseCapture:function(){o=null}},e.webglInputEvents},Viva.Input=Viva.Input||{},Viva.Input.webglInputManager=function(e,t){var n=Viva.Graph.webglInputEvents(t),r=null,i={},o={x:0,y:0};return n.mouseDown(function(e,t){r=e,o.x=t.clientX,o.y=t.clientY,n.mouseCapture(r);var a=i[e.id];return a&&a.onStart&&a.onStart(t,o),!0}).mouseUp(function(e){n.releaseMouseCapture(r),r=null;var t=i[e.id];return t&&t.onStop&&t.onStop(),!0}).mouseMove(function(e,t){if(r){var n=i[r.id];return n&&n.onDrag&&n.onDrag(t,{x:t.clientX-o.x,y:t.clientY-o.y}),o.x=t.clientX,o.y=t.clientY,!0}}),{bindDragNDrop:function(e,t){i[e.id]=t,t||delete i[e.id]}}}; \ No newline at end of file +var Viva=Viva||{};Viva.Graph=Viva.Graph||{},"undefined"!=typeof module&&module.exports&&(module.exports=Viva),Viva.Graph.version="0.6.0",Viva.lazyExtend=function(e,t){var n;if(e||(e={}),t)for(n in t)if(t.hasOwnProperty(n)){var r=e.hasOwnProperty(n),i=typeof t[n],o=!r||typeof e[n]!==i;o?e[n]=t[n]:"object"===i&&(e[n]=Viva.lazyExtend(e[n],t[n]))}return e},Viva.random=function(){var e,t=arguments[0];e="number"==typeof t?t:"string"==typeof t?t.length:+new Date;var n=function(){return e=e+2127912214+(e<<12)&4294967295,e=4294967295&(3345072700^e^e>>>19),e=e+374761393+(e<<5)&4294967295,e=4294967295&(e+3550635116^e<<9),e=e+4251993797+(e<<3)&4294967295,e=4294967295&(3042594569^e^e>>>16),(268435455&e)/268435456};return{next:function(e){return Math.floor(n()*e)},nextDouble:function(){return n()}}},Viva.randomIterator=function(e,t){return t=t||Viva.random(),{forEach:function(n){var r,i,o;for(r=e.length-1;r>0;--r)i=t.next(r+1),o=e[i],e[i]=e[r],e[r]=o,n(o);e.length&&n(e[0])},shuffle:function(){var n,r,i;for(n=e.length-1;n>0;--n)r=t.next(n+1),i=e[r],e[r]=e[n],e[n]=i;return e}}},Viva.BrowserInfo=function(){if("undefined"==typeof window||!window.hasOwnProperty("navigator"))return{browser:"",version:"0"};var e=window.navigator.userAgent.toLowerCase(),t=/(webkit)[ \/]([\w.]+)/,n=/(opera)(?:.*version)?[ \/]([\w.]+)/,r=/(msie) ([\w.]+)/,i=/(mozilla)(?:.*? rv:([\w.]+))?/,o=t.exec(e)||n.exec(e)||r.exec(e)||e.indexOf("compatible")<0&&i.exec(e)||[];return{browser:o[1]||"",version:o[2]||"0"}}(),Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.indexOfElementInArray=function(e,t){if(t.indexOf)return t.indexOf(e);var n,r=t.length;for(n=0;r>n;n+=1)if(t.hasOwnProperty(n)&&t[n]===e)return n;return-1},Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.getDimension=function(e){if(!e)throw{message:"Cannot get dimensions of undefined container"};var t=e.clientWidth,n=e.clientHeight;return{left:0,top:0,width:t,height:n}},Viva.Graph.Utils.findElementPosition=function(e){var t=0,n=0;if(e.offsetParent)do t+=e.offsetLeft,n+=e.offsetTop;while(null!==(e=e.offsetParent));return[t,n]},Viva.Graph.Utils=Viva.Graph.Utils||{},Viva.Graph.Utils.events=function(e){var t=function(e){var t={};return e.fire=function(e,n){var r,i,o,a;if("string"!=typeof e)throw"Only strings can be used as even type";if(t.hasOwnProperty(e))for(r=t[e],a=0;an?r=-1:n>v&&(r=1),i(e,r,{x:e.touches[0].clientX,y:e.touches[0].clientY}),v=n,g(e),y(e)}},L=function(e){h=!1,s.stop("touchmove",G),s.stop("touchend",L),s.stop("touchcancel",L),u=null,r&&r(e)},_=function(e,n){g(e),y(e),d=n.clientX,l=n.clientY,u=e.target||e.srcElement,t&&t(e,{x:d,y:l}),h||(h=!0,s.on("touchmove",G),s.on("touchend",L),s.on("touchcancel",L))},A=function(t){return console.log("Touch start for ",e),1===t.touches.length?_(t,t.touches[0]):void(2===t.touches.length&&(g(t),y(t),v=E(t.touches[0],t.touches[1])))};return f.on("mousedown",V),f.on("touchstart",A),{onStart:function(e){return t=e,this},onDrag:function(e){return n=e,this},onStop:function(e){return r=e,this},onScroll:function(e){return P(e),this},release:function(){s.stop("mousemove",w),s.stop("mousedown",V),s.stop("mouseup",b),s.stop("touchmove",G),s.stop("touchend",L),s.stop("touchcancel",L),P(null)}}},Viva.Input=Viva.Input||{},Viva.Input.domInputManager=function(e,t){var n={};return{bindDragNDrop:function(e,r){var i;if(r){var o=t.getNodeUI(e.id);i=Viva.Graph.Utils.dragndrop(o),"function"==typeof r.onStart&&i.onStart(r.onStart),"function"==typeof r.onDrag&&i.onDrag(r.onDrag),"function"==typeof r.onStop&&i.onStop(r.onStop),n[e.id]=i}else(i=n[e.id])&&(i.release(),delete n[e.id])}}},Viva.Graph.Utils=Viva.Graph.Utils||{},function(){var e,t,n=0,r=["ms","moz","webkit","o"];for(t="undefined"!=typeof window?window:"undefined"!=typeof global?global:{setTimeout:function(){},clearTimeout:function(){}},e=0;e=0==g>=4?null:(f=u-o,d=i-a,h=a*o-i*u,v=f*e+d*t+h,p=f*n+d*r+h,0!==v&&0!==p&&v>=0==p>=0?null:(y=s*d-f*c,0===y?null:(x=0>y?-y/2:y/2,x=0,w=c*h-d*l,V.x=(0>w?w-x:w+x)/y,w=f*l-s*h,V.y=(0>w?w-x:w+x)/y,V)))},intersectRect:function(e,t,n,r,i,o,a,u){return this.intersect(e,t,e,r,i,o,a,u)||this.intersect(e,r,n,r,i,o,a,u)||this.intersect(n,r,n,t,i,o,a,u)||this.intersect(n,t,e,t,i,o,a,u)},convexHull:function(e){var t=function(e,t){var n,r,i=function(t){var n=t.x-e.x,r=t.y-e.y,i=n>0?1:-1;return i*n*n/(n*n+r*r)},o=t.sort(function(e,t){return i(t)-i(e)}),a=o[0],u=i(a),s=a.x-e.x,f=a.y-e.y,c=s*s+f*f;for(r=1;rn?o.splice(r,1):o.splice(r-1,1)):u=d}return o},n=function(e,t,n){return(n.x-e.x)*(t.y-e.y)-(n.y-e.y)*(t.x-e.x)<0};if(e.length<3)return e;var r,i=0;for(r=0;r0&&(a(e),o.length=0)},f=function(e,t){o.push({node:e,changeType:t})},c=function(e,t){o.push({link:e,changeType:t})},d={addNode:function(t,n){if("undefined"==typeof t)throw{message:"Invalid node identifier"};u();var i=this.getNode(t);return i?f(i,"update"):(i=new Viva.Graph.Node(t),r++,f(i,"add")),i.data=n,e[t]=i,s(this),i},addLink:function(e,r,i){u();var o=this.getNode(e)||this.addNode(e),a=this.getNode(r)||this.addNode(r),f=e.toString()+"👉 "+r.toString(),d=n.hasOwnProperty(f);(d||this.hasLink(e,r))&&(d||(n[f]=0),f+="@"+ ++n[f]);var l=new Viva.Graph.Link(e,r,i,f);return t.push(l),o.links.push(l),a.links.push(l),c(l,"add"),s(this),l},removeLink:function(e){if(!e)return!1;var n=Viva.Graph.Utils.indexOfElementInArray(e,t);if(0>n)return!1;u(),t.splice(n,1);var r=this.getNode(e.fromId),i=this.getNode(e.toId);return r&&(n=Viva.Graph.Utils.indexOfElementInArray(e,r.links),n>=0&&r.links.splice(n,1)),i&&(n=Viva.Graph.Utils.indexOfElementInArray(e,i.links),n>=0&&i.links.splice(n,1)),c(e,"remove"),s(this),!0},removeNode:function(t){var n=this.getNode(t);if(!n)return!1;for(u();n.links.length;){var i=n.links[0];this.removeLink(i)}e[t]=null,delete e[t],r--,f(n,"remove"),s(this)},getNode:function(t){return e[t]},getNodesCount:function(){return r},getLinksCount:function(){return t.length},getLinks:function(e){var t=this.getNode(e);return t?t.links:null},forEachNode:function(t){if("function"==typeof t){var n;for(n in e)if(t(e[n]))return}},forEachLinkedNode:function(t,n,r){var i,o,a,u=this.getNode(t);if(u&&u.links&&"function"==typeof n)if(r)for(i=0;in;++n)e(t[n])},beginUpdate:function(){u()},endUpdate:function(){s(this)},clear:function(){var e=this;e.beginUpdate(),e.forEachNode(function(t){e.removeNode(t.id)}),e.endUpdate()},hasLink:function(e,t){var n,r=this.getNode(e);if(!r)return null;for(n=0;nn;++n){var f=e.bodies[n],c=t/f.mass;f.velocity.x+=c*f.force.x,f.velocity.y+=c*f.force.y;var d=f.velocity.x,l=f.velocity.y,h=Math.sqrt(d*d+l*l);h>r&&(f.velocity.x=r*d/h,f.velocity.y=r*l/h),o=t*f.velocity.x,u=t*f.velocity.y,f.location.x+=o,f.location.y+=u,i+=Math.abs(o),a+=Math.abs(u)}return(i+a)/s}}},Viva.Graph.Physics.nbodyForce=function(e){function t(e,t){this.node=e,this.body=t}function n(){this.stack=[],this.popIdx=0}e=Viva.lazyExtend(e||{gravity:-1,theta:.8}),n.prototype={isEmpty:function(){return 0===this.popIdx},push:function(e,n){var r=this.stack[this.popIdx];r?(r.node=e,r.body=n):this.stack[this.popIdx]=new t(e,n),++this.popIdx},pop:function(){return this.popIdx>0?this.stack[--this.popIdx]:void 0},reset:function(){this.popIdx=0}};var r=e.gravity,i=[],o=new n,a=e.theta,u=Viva.random("5f4dcc3b5aa765d61d8327deb882cf99",75,20,63,108,65,76,65,72),s=function(){this.body=null,this.quads=[],this.mass=0,this.massX=0,this.massY=0,this.left=0,this.top=0,this.bottom=0,this.right=0,this.isInternal=!1},f=[],c=0,d=function(){var e;return f[c]?(e=f[c],e.quads[0]=null,e.quads[1]=null,e.quads[2]=null,e.quads[3]=null,e.body=null,e.mass=e.massX=e.massY=0,e.left=e.right=e.top=e.bottom=0,e.isInternal=!1):(e=new s,f[c]=e),++c,e},l=d(),h=function(e,t){var n=Math.abs(e.x-t.x),r=Math.abs(e.y-t.y);return 1e-8>n&&1e-8>r},v=function(e){for(o.reset(),o.push(l,e);!o.isEmpty();){var t=o.pop(),n=t.node,r=t.body;if(n.isInternal){var i=r.location.x,a=r.location.y;n.mass=n.mass+r.mass,n.massX=n.massX+r.mass*i,n.massY=n.massY+r.mass*a;var s=0,f=n.left,c=(n.right+f)/2,v=n.top,p=(n.bottom+v)/2;if(i>c){s+=1;var m=f;f=c,c+=c-m}if(a>p){s+=2;var g=v;v=p,p+=p-g}var y=n.quads[s];y||(y=d(),y.left=f,y.top=v,y.right=c,y.bottom=p,n.quads[s]=y),o.push(y,r)}else if(n.body){var x=n.body;if(n.body=null,n.isInternal=!0,h(x.location,r.location)){if(n.right-n.left<1e-8)return;do{var w=u.nextDouble(),V=(n.right-n.left)*w,b=(n.bottom-n.top)*w;x.location.x=n.left+V,x.location.y=n.top+b}while(h(x.location,r.location))}o.push(n,x),o.push(n,r)}else n.body=r}},p=function(e){var t,n,o,s,f=i,c=1,d=0,h=1;for(f[0]=l;c;){var v=f[d],p=v.body;c-=1,d+=1,p&&p!==e?(n=p.location.x-e.location.x,o=p.location.y-e.location.y,s=Math.sqrt(n*n+o*o),0===s&&(n=(u.nextDouble()-.5)/50,o=(u.nextDouble()-.5)/50,s=Math.sqrt(n*n+o*o)),t=r*p.mass*e.mass/(s*s*s),e.force.x=e.force.x+t*n,e.force.y=e.force.y+t*o):(n=v.massX/v.mass-e.location.x,o=v.massY/v.mass-e.location.y,s=Math.sqrt(n*n+o*o),0===s&&(n=(u.nextDouble()-.5)/50,o=(u.nextDouble()-.5)/50,s=Math.sqrt(n*n+o*o)),(v.right-v.left)/ss&&(n=s),s>i&&(i=s),r>f&&(r=f),f>o&&(o=f)}var h=i-n,p=o-r;for(h>p?o=r+h:i=n+p,c=0,l=d(),l.left=n,l.right=i,l.top=r,l.bottom=o,t=u;t--;)v(a[t],l)};return{insert:v,init:m,update:p,options:function(e){return e?("number"==typeof e.gravity&&(r=e.gravity),"number"==typeof e.theta&&(a=e.theta),this):{gravity:r,theta:a}}}},Viva.Graph.Physics.dragForce=function(e){e||(e={});var t={coeff:e.coeff||.01};return{update:function(e){e.force.x-=t.coeff*e.velocity.x,e.force.y-=t.coeff*e.velocity.y},options:function(e){return e?("number"==typeof e.coeff&&(t.coeff=e.coeff),this):t}}},Viva.Graph.Physics.springForce=function(e){e=Viva.lazyExtend(e,{length:50,coeff:22e-5});var t=Viva.random("Random number 4.","Chosen by fair dice roll");return{update:function(n){var r=n.body1,i=n.body2,o=n.length<0?e.length:n.length,a=i.location.x-r.location.x,u=i.location.y-r.location.y,s=Math.sqrt(a*a+u*u);0===s&&(a=(t.nextDouble()-.5)/50,u=(t.nextDouble()-.5)/50,s=Math.sqrt(a*a+u*u));var f=s-o,c=(!n.coeff||n.coeff<0?e.coeff:n.coeff)*f/s*n.weight;r.force.x+=c*a,r.force.y+=c*u,i.force.x+=-c*a,i.force.y+=-c*u},options:function(t){return t?("number"==typeof t.length&&(e.length=t.length),"number"==typeof t.coeff&&(e.coeff=t.coeff),this):e}}},Viva.Graph.Physics=Viva.Graph.Physics||{},Viva.Graph.Physics.forceSimulator=function(e){var t,n,r,i=e,o=[],a=[];return{speedLimit:1,bodies:o,accumulate:function(){var e,i;for(n.init(this),e=o.length;e--;)i=o[e],i.force.x=0,i.force.y=0,n.update(i),r.update(i);for(e=a.length;e--;)t.update(a[e])},run:function(e){return this.accumulate(),i.integrate(this,e)},addBody:function(e){if(!e)throw{message:"Cannot add null body to force simulator"};return o.push(e),e},removeBody:function(e){if(!e)return!1;var t=Viva.Graph.Utils.indexOfElementInArray(e,o);return 0>t?!1:o.splice(t,1)},addSpring:function(e,t,n,r,i){if(!e||!t)throw{message:"Cannot add null spring to force simulator"};if("number"!=typeof n)throw{message:"Spring length should be a number"};r="number"==typeof r?r:1;var o=new Viva.Graph.Physics.Spring(e,t,n,i>=0?i:-1,r);return a.push(o),o},removeSpring:function(e){if(!e)return!1;var t=Viva.Graph.Utils.indexOfElementInArray(e,a);return 0>t?!1:a.splice(t,1)},setNbodyForce:function(e){if(!e)throw{message:"Cannot add mighty (unknown) force to the simulator"};n=e},setDragForce:function(e){if(!e)throw{message:"Cannot add mighty (unknown) force to the simulator"};r=e},setSpringForce:function(e){if(!e)throw{message:"Cannot add unknown force to the simulator"};t=e}}},Viva.Graph.Layout=Viva.Graph.Layout||{},Viva.Graph.Layout.forceDirected=function(e,t){if(!e)throw{message:"Graph structure cannot be undefined"};t=Viva.lazyExtend(t,{springLength:80,springCoeff:2e-4,gravity:-1.2,theta:.8,dragCoeff:.02,springTransform:function(){},timeStep:20,stableThreshold:.009});var n=Viva.Graph.Physics.forceSimulator(Viva.Graph.Physics.eulerIntegrator()),r=Viva.Graph.Physics.nbodyForce({gravity:t.gravity,theta:t.theta}),i=Viva.Graph.Physics.springForce({length:t.springLength,coeff:t.springCoeff}),o=Viva.Graph.Physics.dragForce({coeff:t.dragCoeff}),a=new Viva.Graph.Rect,u=Viva.random("ted.com",103,114,101,97,116),s={},f=function(e){if(e.position)return e.position;var n=(a.x1+a.x2)/2,r=(a.y1+a.y2)/2,i=t.springLength;if(e.links&&e.links.length>0){var o=e.links[0],f=o.fromId!==e.id?s[o.fromId]:s[o.toId];f&&f.location&&(n=f.location.x,r=f.location.y)}return{x:n+u.next(i)-i/2,y:r+u.next(i)-i/2}},c=function(e){return s[e]},d=function(e){s[e]=null,delete s[e]},l={},h=function(t){var n=c(t);n.mass=1+e.getLinks(t).length/3},v=function(e){return e&&(e.isPinned||e.data&&e.data.isPinned)},p=function(e){return e.isPinned},m=function(t){var r=c(t);if(!r){var i=e.getNode(t);if(!i)return;r=new Viva.Graph.Physics.Body,s[t]=r;var o=f(i);r.loc(o),h(t),v(i)&&(r.isPinned=!0),n.addBody(r)}},g=function(e){m(e.id)},y=function(t){var r=c(t.id);r&&(d(t.id),n.removeBody(r),0===e.getNodesCount()&&(a.x1=a.y1=0,a.x2=a.y2=0))},x=function(e){h(e.fromId),h(e.toId);var r=c(e.fromId),i=c(e.toId),o=n.addSpring(r,i,-1,e.weight);t.springTransform(e,o),l[e.id]=o},w=function(t){var r=l[t.id];if(r){var i=e.getNode(t.fromId),o=e.getNode(t.toId);i&&h(i.id),o&&h(o.id),delete l[t.id],n.removeSpring(r)}},V=function(e){for(var t=0;tr&&(r=u.location.x),u.location.yi&&(i=u.location.y)}a.x1=t,a.x2=r,a.y1=n,a.y2=i}};return n.setSpringForce(i),n.setNbodyForce(r),n.setDragForce(o),b(),{run:function(e){var t;for(e=e||50,t=0;e>t;++t)this.step()},step:function(){var e=n.run(t.timeStep);return N(),et.x2&&(t.x2=e.x),e.yt.y2&&(t.y2=e.y)},a="function"==typeof Object.create?Object.create(null):{},u=function(e){e&&(a[e.id]=i(e),o(a[e.id],r))},s=function(){0!==e.getNodesCount()&&(r.x1=Number.MAX_VALUE,r.y1=Number.MAX_VALUE,r.x2=Number.MIN_VALUE,r.y2=Number.MIN_VALUE,e.forEachNode(u))},f=function(e){for(var t=0;t0)for(e=0;et,n)}),e.forEachNode(C),B(),o=Viva.Graph.Utils.events(e),o.on("changed",O)},q=function(){d=!1,B(),z(),V.stop("resize",F),b.removeAllListeners(),i.stop(),e.forEachLink(function(e){t.renderLinks&&T(e)}),e.forEachNode(function(e){S(e),I(e)}),u.dispose(),U()};return{run:function(e){return d||(w(),L(),_(),M(),X(),d=!0),E(e),this},reset:function(){s.resetScale(),_(),x.scale=1},pause:function(){g=!0,i.stop()},resume:function(){g=!1,i.restart()},rerender:function(){return N(),this},zoomOut:function(){return Y(!0)},zoomIn:function(){return Y(!1)},moveTo:function(e,t){s.graphCenterChanged(x.offsetX-e*x.scale,x.offsetY-t*x.scale),N()},getGraphics:function(){return s},dispose:function(){q()},on:function(e,t){return b.addEventListener(e,t),this},off:function(e,t){return b.removeEventListener(e,t),this}}},Viva.Graph.serializer=function(){var e=function(){if("undefined"==typeof JSON||!JSON.stringify||!JSON.parse)throw"JSON serializer is not defined."},t=function(e){return{id:e.id,data:e.data}},n=function(e){return{fromId:e.fromId,toId:e.toId,data:e.data}},r=function(e){return e},i=function(e){return e};return{storeToJSON:function(r,i,o){if(!r)throw"Graph is not defined";e(),i=i||t,o=o||n;var a={nodes:[],links:[]};return r.forEachNode(function(e){a.nodes.push(i(e))}),r.forEachLink(function(e){a.links.push(o(e))}),JSON.stringify(a)},loadFromJSON:function(t,n,o){if("string"!=typeof t)throw"String expected in loadFromJSON() method";e(),n=n||r,o=o||i;var a,u=JSON.parse(t),s=Viva.Graph.graph();if(!u||!u.nodes||!u.links)throw"Passed json string does not represent valid graph";for(a=0;an?void r.push({name:e,probability:i/t}):!0}),r},a=function(e){var t=[];return e.forEachNode(function(e){var n=Viva.Graph._community.occuranceMap(r);n.add(e.id),e.slpa={memory:n},t.push(e.id)}),t},u=function(e,n){var o,a=Viva.randomIterator(n,i),u=function(t){var n=e.getNode(t),i=Viva.Graph._community.occuranceMap(r);e.forEachLinkedNode(t,function(e){var t=e.slpa.memory.getRandomWord();i.add(t)});var o=i.getMostPopularFair();n.slpa.memory.add(o)};for(o=0;t-1>o;++o)a.forEach(u)},s=function(e){var r={};return e.forEachNode(function(e){var i,a=o(e.slpa.memory,n*t);for(i=0;ie?-1:e>n?1:0})},a=function(){r&&(o(),r=!1)};return{add:function(e){e=String(e),t.hasOwnProperty(e)?t[e]+=1:t[e]=1,n.push(e),r=!0},getWordCount:function(e){return t[e]||0},getMostPopularFair:function(){if(1===n.length)return n[0];a();var r,o=0;for(r=1;re)throw{message:"At least two nodes expected for complete graph"};var t,n,r=Viva.Graph.graph();for(r.Name="Complete K"+e,t=0;e>t;++t)for(n=t+1;e>n;++n)t!==n&&r.addLink(t,n);return r},completeBipartite:function(e,t){if(!e||!t||0>e||0>t)throw{message:"Graph dimensions are invalid. Number of nodes in each partition should be greater than 0"};var n,r,i=Viva.Graph.graph();for(i.Name="Complete K "+e+","+t,n=0;e>n;++n)for(r=e;e+t>r;++r)i.addLink(n,r); +return i},ladder:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Ladder graph "+e,t=0;e-1>t;++t)n.addLink(t,t+1),n.addLink(e+t,e+t+1),n.addLink(t,e+t);return n.addLink(e-1,2*e-1),n},circularLadder:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t=this.ladder(e);return t.Name="Circular ladder graph "+e,t.addLink(0,e-1),t.addLink(e,2*e-1),t},grid:function(e,t){var n,r,i=Viva.Graph.graph();for(i.Name="Grid graph "+e+"x"+t,n=0;e>n;++n)for(r=0;t>r;++r){var o=n+r*e;n>0&&i.addLink(o,n-1+r*e),r>0&&i.addLink(o,n+(r-1)*e)}return i},path:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Path graph "+e,n.addNode(0),t=1;e>t;++t)n.addLink(t-1,t);return n},lollipop:function(e,t){if(!t||0>t||!e||0>e)throw{message:"Invalid number of nodes"};var n,r=this.complete(e);for(r.Name="Lollipop graph. Head x Path "+e+"x"+t,n=0;t>n;++n)r.addLink(e+n-1,e+n);return r},balancedBinTree:function(e){var t,n=Viva.Graph.graph(),r=Math.pow(2,e);for(n.Name="Balanced bin tree graph "+e,t=1;r>t;++t){var i=t,o=2*i,a=2*i+1;n.addLink(i,o),n.addLink(i,a)}return n},randomNoLinks:function(e){if(!e||0>e)throw{message:"Invalid number of nodes"};var t,n=Viva.Graph.graph();for(n.Name="Random graph, no Links: "+e,t=0;e>t;++t)n.addNode(t);return n}}},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.cssGraphics=function(){var e,t,n,r="OLD_IE",i=1,o=1,a=function(){var e,t,n=Viva.BrowserInfo.browser;switch(n){case"mozilla":e="Moz";break;case"webkit":e="webkit";break;case"opera":e="O";break;case"msie":if(t=Viva.BrowserInfo.version.split(".")[0],!(t>8))return r;e="ms"}return e?e+"Transform":null}(),u=function(){return a===r?function(e,t,n,r){var i=Math.cos(r),o=Math.sin(r);0>r&&(r=2*Math.PI+r),r=h.byteLength){var e=new ArrayBuffer(2*h.byteLength),t=new Float32Array(e),n=new Uint32Array(e);n.set(p),v=t,p=n,h=e}};return{load:function(o){t=o,i=Viva.Graph.webgl(o),e=i.createProgram(l,d),t.useProgram(e),r=i.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),t.enableVertexAttribArray(r.vertexPos),t.enableVertexAttribArray(r.color),n=t.createBuffer()},position:function(e,t){var n=e.id;v[n*f]=t.x,v[n*f+1]=t.y,v[n*f+2]=e.size,p[n*f+3]=e.color},updateTransform:function(e){s=!0,u=e},updateSize:function(e,t){o=e,a=t,s=!0},removeNode:function(e){m>0&&(m-=1),e.id0&&i.copyArrayPart(p,e.id*f,m*f,f)},createNode:function(){g(),m+=1},replaceProperties:function(){},render:function(){t.useProgram(e),t.bindBuffer(t.ARRAY_BUFFER,n),t.bufferData(t.ARRAY_BUFFER,h,t.DYNAMIC_DRAW),s&&(s=!1,t.uniformMatrix4fv(r.transform,!1,u),t.uniform2f(r.screenSize,o,a)),t.vertexAttribPointer(r.vertexPos,3,t.FLOAT,!1,f*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(r.color,4,t.UNSIGNED_BYTE,!0,f*Float32Array.BYTES_PER_ELEMENT,12),t.drawArrays(t.POINTS,0,m)}}},Viva.Graph.View.webglLinkProgram=function(){var e,t,n,r,i,o,a,u,s,f,c=6,d=2*(2*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT),l=["precision mediump float;","varying vec4 color;","void main(void) {"," gl_FragColor = color;","}"].join("\n"),h=["attribute vec2 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0.0, 1.0);"," color = a_color.abgr;","}"].join("\n"),v=0,p=new ArrayBuffer(16*d),m=new Float32Array(p),g=new Uint32Array(p),y=function(){if((v+1)*d>p.byteLength){var e=new ArrayBuffer(2*p.byteLength),t=new Float32Array(e),n=new Uint32Array(e);n.set(g),m=t,g=n,p=e}};return{load:function(o){t=o,r=Viva.Graph.webgl(o),e=r.createProgram(h,l),t.useProgram(e),i=r.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),t.enableVertexAttribArray(i.vertexPos),t.enableVertexAttribArray(i.color),n=t.createBuffer()},position:function(e,t,n){var r=e.id,i=r*c;m[i]=t.x,m[i+1]=t.y,g[i+2]=e.color,m[i+3]=n.x,m[i+4]=n.y,g[i+5]=e.color},createLink:function(e){y(),v+=1,o=e.id},removeLink:function(e){v>0&&(v-=1),e.id0&&r.copyArrayPart(g,e.id*c,v*c,c)},updateTransform:function(e){f=!0,s=e},updateSize:function(e,t){a=e,u=t,f=!0},render:function(){t.useProgram(e),t.bindBuffer(t.ARRAY_BUFFER,n),t.bufferData(t.ARRAY_BUFFER,p,t.DYNAMIC_DRAW),f&&(f=!1,t.uniformMatrix4fv(i.transform,!1,s),t.uniform2f(i.screenSize,a,u)),t.vertexAttribPointer(i.vertexPos,2,t.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(i.color,4,t.UNSIGNED_BYTE,!0,3*Float32Array.BYTES_PER_ELEMENT,8),t.drawArrays(t.LINES,0,2*v),o=v-1},bringToFront:function(e){o>e.id&&r.swapArrayPart(m,e.id*c,o*c,c),o>0&&(o-=1)},getFrontLinkId:function(){return o}}},Viva.Graph.View.Texture=function(e){this.canvas=window.document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.isDirty=!1,this.canvas.width=this.canvas.height=e},Viva.Graph.View.webglAtlas=function(e){var t,n,r=Math.sqrt(e||1024)<<0,i=r,o=1,a={},u=0,s=[],f=[],c=function(e){return 0===(e&e-1)},d=function(){var e=new Viva.Graph.View.Texture(r*i);s.push(e)},l=function(t){var n=t/e<<0,i=t%e,o=i/r<<0,a=i%r;return{textureNumber:n,row:o,col:a}},h=function(){n.isDirty=!0,u=0,t=null},v=function(){t&&(window.clearTimeout(t),u+=1,t=null),u>10?h():t=window.setTimeout(h,400)},p=function(e,t){var n=s[e.textureNumber].canvas,r=s[t.textureNumber].ctx,o=t.col*i,a=t.row*i;r.drawImage(n,e.col*i,e.row*i,i,i,o,a,i,i),s[e.textureNumber].isDirty=!0,s[t.textureNumber].isDirty=!0},m=function(e,t,n){var r=l(e),o={offset:e};r.textureNumber>=s.length&&d();var u=s[r.textureNumber];u.ctx.drawImage(t,r.col*i,r.row*i,i,i),f[e]=t.src,a[t.src]=o,u.isDirty=!0,n(o)};if(!c(e))throw"Tiles per texture should be power of two.";return n={isDirty:!1,clearDirty:function(){var e;for(this.isDirty=!1,e=0;e0&&(v-=1),t.id0&&(t.src&&e.remove(t.src),i.copyArrayPart(p,t.id*c,v*c,c))},replaceProperties:function(e,t){t._offset=e._offset},updateTransform:function(e){f=!0,s=e},updateSize:function(e,t){a=e,u=t,f=!0},render:function(){n.useProgram(t),n.bindBuffer(n.ARRAY_BUFFER,r),n.bufferData(n.ARRAY_BUFFER,p,n.DYNAMIC_DRAW),f&&(f=!1,n.uniformMatrix4fv(o.transform,!1,s),n.uniform2f(o.screenSize,a,u)),n.vertexAttribPointer(o.vertexPos,2,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),n.vertexAttribPointer(o.customAttributes,1,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,8),g(),n.drawArrays(n.TRIANGLES,0,6*v)}}},Viva.Graph.View=Viva.Graph.View||{},Viva.Graph.View.webglGraphics=function(e){e=Viva.lazyExtend(e,{enableBlending:!0,preserveDrawingBuffer:!1,clearColor:!1,clearColorValue:{r:1,g:1,b:1,a:1}});var t,n,r,i,o,a,u,s,f=0,c=0,d=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],l=[],h=[],v={},p={},m=Viva.Graph.View.webglLinkProgram(),g=Viva.Graph.View.webglNodeProgram(),y=function(){return Viva.Graph.View.webglSquare()},x=function(){return Viva.Graph.View.webglLine(3014898687)},w=function(){m.updateTransform(d),g.updateTransform(d)},V=function(){d=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},b=function(){t&&n&&(i=n.width=Math.max(t.offsetWidth,1),o=n.height=Math.max(t.offsetHeight,1),r&&r.viewport(0,0,i,o),m&&m.updateSize(i/2,o/2),g&&g.updateSize(i/2,o/2))},N=function(e){e.fire("rescaled")};n=window.document.createElement("canvas");var P={getLinkUI:function(e){return p[e]},getNodeUI:function(e){return v[e]},node:function(e){return"function"==typeof e?(y=e,this):void 0},link:function(e){return"function"==typeof e?(x=e,this):void 0},placeNode:function(e){return a=e,this},placeLink:function(e){return u=e,this},inputManager:Viva.Input.webglInputManager,beginRender:function(){},endRender:function(){c>0&&m.render(),f>0&&g.render()},bringLinkToFront:function(e){var t,n,r=m.getFrontLinkId();m.bringToFront(e),r>e.id&&(t=e.id,n=h[r],h[r]=h[t],h[r].id=r,h[t]=n,h[t].id=t)},graphCenterChanged:function(e,t){d[12]=2*e/i-1,d[13]=1-2*t/o,w()},addLink:function(e,t){var n=c++,r=x(e);return r.id=n,r.pos=t,m.createLink(r),h[n]=r,p[e.id]=r,r},addNode:function(e,t){var n=f++,r=y(e);return r.id=n,r.position=t,r.node=e,g.createNode(r),l[n]=r,v[e.id]=r,r},translateRel:function(e,t){d[12]+=2*d[0]*e/i/d[0],d[13]-=2*d[5]*t/o/d[5],w()},scale:function(e,t){var n=2*t.x/i-1,r=1-2*t.y/o;return n-=d[12],r-=d[13],d[12]+=n*(1-e),d[13]+=r*(1-e),d[0]*=e,d[5]*=e,w(),N(this),d[0]},resetScale:function(){return V(),r&&(b(),w()),this},init:function(a){var u={};if(e.preserveDrawingBuffer&&(u.preserveDrawingBuffer=!0),t=a,b(),V(),t.appendChild(n),r=n.getContext("experimental-webgl",u),!r){var f="Could not initialize WebGL. Seems like the browser doesn't support it.";throw window.alert(f),f}if(e.enableBlending&&(r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA),r.enable(r.BLEND)),e.clearColor){var c=e.clearColorValue;r.clearColor(c.r,c.g,c.b,c.a),this.beginRender=function(){r.clear(r.COLOR_BUFFER_BIT)}}m.load(r),m.updateSize(i/2,o/2),g.load(r),g.updateSize(i/2,o/2),w(),"function"==typeof s&&s(n)},release:function(e){n&&e&&e.removeChild(n)},isSupported:function(){var e=window.document.createElement("canvas"),t=e&&e.getContext&&e.getContext("experimental-webgl");return t},releaseLink:function(e){c>0&&(c-=1);var t=p[e.id];delete p[e.id],m.removeLink(t);var n=t.id;if(c>n){if(0===c||c===n)return;var r=h[c];h[n]=r,r.id=n}},releaseNode:function(e){f>0&&(f-=1);var t=v[e.id];delete v[e.id],g.removeNode(t);var n=t.id;if(f>n){if(0===f||f===n)return;var r=l[f];l[n]=r,r.id=n,g.replaceProperties(t,r)}},renderNodes:function(){for(var e={x:0,y:0},t=0;f>t;++t){var n=l[t];e.x=n.position.x,e.y=-n.position.y,a&&a(n,e),g.position(n,e)}},renderLinks:function(){if(!this.omitLinksRendering)for(var e={x:0,y:0},t={x:0,y:0},n=0;c>n;++n){var r=h[n],i=r.pos.from;t.x=i.x,t.y=-i.y,i=r.pos.to,e.x=i.x,e.y=-i.y,u&&u(r,t,e),m.position(r,t,e)}},getGraphicsRoot:function(e){return"function"==typeof e&&(n?e(n):s=e),n},setNodeProgram:function(e){if(!r&&e)g=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... Yet."},setLinkProgram:function(e){if(!r&&e)m=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... Yet."},transformClientToGraphCoordinates:function(e){return e.x=2*e.x/i-1,e.y=1-2*e.y/o,e.x=(e.x-d[12])/d[0],e.y=(e.y-d[13])/d[5],e.x*=i/2,e.y*=-o/2,e},getNodeAtClientPos:function(e,t){if("function"!=typeof t)return null;this.transformClientToGraphCoordinates(e);for(var n=0;f>n;++n)if(t(l[n],e.x,e.y))return l[n].node;return null}};return Viva.Graph.Utils.events(P).extend(),P},Viva.Graph.webglInputEvents=function(e){if(e.webglInputEvents)return e.webglInputEvents;var t,n,r=function(e,t,n){if(e&&e.size){var r=e.position,i=e.size;return r.x-ia-y&&o[0]===g?m(l,o):m(d,o),y=a,m(f,o)&&v(e))})};return e.getGraphicsRoot(g),e.webglInputEvents={mouseEnter:function(e){return"function"==typeof e&&a.push(e),this},mouseLeave:function(e){return"function"==typeof e&&u.push(e),this},mouseDown:function(e){return"function"==typeof e&&s.push(e),this},mouseUp:function(e){return"function"==typeof e&&f.push(e),this},mouseMove:function(e){return"function"==typeof e&&c.push(e),this},click:function(e){return"function"==typeof e&&d.push(e),this},dblClick:function(e){return"function"==typeof e&&l.push(e),this},mouseCapture:function(e){o=e},releaseMouseCapture:function(){o=null}},e.webglInputEvents},Viva.Input=Viva.Input||{},Viva.Input.webglInputManager=function(e,t){var n=Viva.Graph.webglInputEvents(t),r=null,i={},o={x:0,y:0};return n.mouseDown(function(e,t){r=e,o.x=t.clientX,o.y=t.clientY,n.mouseCapture(r);var a=i[e.id];return a&&a.onStart&&a.onStart(t,o),!0}).mouseUp(function(e){n.releaseMouseCapture(r),r=null;var t=i[e.id];return t&&t.onStop&&t.onStop(),!0}).mouseMove(function(e,t){if(r){var n=i[r.id];return n&&n.onDrag&&n.onDrag(t,{x:t.clientX-o.x,y:t.clientY-o.y}),o.x=t.clientX,o.y=t.clientY,!0}}),{bindDragNDrop:function(e,t){i[e.id]=t,t||delete i[e.id]}}}; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..86d6be1 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,85 @@ +var gulp = require('gulp'); +var concat = require('gulp-concat'); +var path = require('path'); +var uglify = require('gulp-uglify'); +var rename = require('gulp-rename'); +var del = require('del'); + +var files = getFiles(); + +gulp.task('clean', clean); +gulp.task('build', concatenateFiles); +gulp.task('release', ['clean', 'build']); +gulp.task('default', watch); + +function watch() { + gulp.watch('src/**/*.js', ['build']); +} + +function clean(cb) { + del(['dist'], cb); +} + +function concatenateFiles() { + gulp.src(files) + .pipe(concat('vivagraph.js')) + .pipe(gulp.dest('./dist/')) + .pipe(rename('vivagraph.min.js')) + .pipe(uglify()) + .pipe(gulp.dest('./dist/')); +} + +function getFiles() { + // todo: this will be changed when we move to commonjs + return [ // core + "vivagraph.js", + "version.js", + "Utils/etc.js", + "Utils/browserInfo.js", + "Utils/indexOf.js", + "Utils/getDimensions.js", + "Utils/events.js", + "Input/dragndrop.js", + "Input/domInputManager.js", + "Input/spatialIndex.js", // TODO: Do I need this for SVG? + "Utils/timer.js", + "Utils/geom.js", + + "Core/primitives.js", + "Core/graph.js", + "Core/operations.js", + + "Physics/primitives.js", + "Physics/eulerIntegrator.js", + "Physics/Forces/nbodyForce.js", + "Physics/Forces/dragForce.js", + "Physics/Forces/springForce.js", + "Physics/forceSimulator.js", + "Layout/forceDirected.js", + "Layout/constant.js", + "View/renderer.js", + // extra + "Core/serializer.js", + "Algorithms/centrality.js", + "Algorithms/Community/community.js", + "Algorithms/Community/slpa.js", + "Core/generator.js", + "View/cssGraphics.js", + // svg + "Svg/svg.js", + "View/svgGraphics.js", + "View/svgNodeFactory.js", + // webgl + "WebGL/webgl.js", + "WebGL/webglUIModels.js", + "WebGL/webglNodeProgram.js", + "WebGL/webglLinkProgram.js", + "WebGL/webglImageNodeProgram.js", + "View/webglGraphics.js", + "WebGL/webglInputEvents.js", + "Input/webglInputManager.js"].map(toSrcFolder); +} + +function toSrcFolder(name) { + return path.join('src', name); +} diff --git a/package.json b/package.json index 83cd306..8d64254 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "doc": "docs" }, "scripts": { + "start": "gulp", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -19,11 +20,10 @@ "author": "Andrei Kashcha", "license": "BSD", "devDependencies": { - "grunt": "~0.4.1", - "grunt-contrib-uglify": "~0.2.0", - "grunt-contrib-jshint": "~0.4.1", - "grunt-contrib-clean": "~0.4.0", - "grunt-contrib-concat": "~0.1.3", - "grunt-regarde": "~0.1.1" + "del": "^1.1.1", + "gulp": "^3.8.10", + "gulp-concat": "^2.4.2", + "gulp-rename": "^1.2.0", + "gulp-uglify": "^1.0.2" } } diff --git a/src/version.js b/src/version.js index 67454a9..c756618 100644 --- a/src/version.js +++ b/src/version.js @@ -1 +1 @@ -Viva.Graph.version = '0.5.8'; +Viva.Graph.version = '0.6.0';