diff --git a/demo2.html b/demo2.html new file mode 100644 index 0000000..fb8d073 --- /dev/null +++ b/demo2.html @@ -0,0 +1,43 @@ + + + + + + + + + + + diff --git a/springy.js b/springy.js index 8bf8d34..7960300 100644 --- a/springy.js +++ b/springy.js @@ -1,5 +1,5 @@ /** - * Springy v1.0.1 + * Springy v1.1.0 * * Copyright (c) 2010 Dennis Hotson * @@ -25,33 +25,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach -if ( !Array.prototype.forEach ) { - Array.prototype.forEach = function( callback, thisArg ) { - var T, k; - if ( this == null ) { - throw new TypeError( " this is null or not defined" ); - } - var O = Object(this); - var len = O.length >>> 0; // Hack to convert O.length to a UInt32 - if ( {}.toString.call(callback) != "[object Function]" ) { - throw new TypeError( callback + " is not a function" ); - } - if ( thisArg ) { - T = thisArg; - } - k = 0; - while( k < len ) { - var kValue; - if ( k in O ) { - kValue = O[ k ]; - callback.call( T, kValue, k, O ); - } - k++; - } - }; -} - var Graph = function() { this.nodeSet = {}; this.nodes = []; @@ -65,18 +38,28 @@ var Graph = function() { var Node = function(id, data) { this.id = id; - this.data = typeof(data) !== 'undefined' ? data : {}; + this.data = (data !== undefined) ? data : {}; + +// Data fields used by layout algorithm in this file: +// this.data.mass +// Data used by default renderer in springyui.js +// this.data.label }; var Edge = function(id, source, target, data) { this.id = id; + /** @type {Node} */ this.source = source; this.target = target; - this.data = typeof(data) !== 'undefined' ? data : {}; + this.data = (data !== undefined) ? data : {}; + +// Edge data field used by layout alorithm +// this.data.length +// this.data.type }; Graph.prototype.addNode = function(node) { - if (typeof(this.nodeSet[node.id]) === 'undefined') { + if (!(node.id in this.nodeSet)) { this.nodes.push(node); } @@ -86,6 +69,15 @@ Graph.prototype.addNode = function(node) { return node; }; +Graph.prototype.addNodes = function(list) { + if (typeof(list[0]) == "string") { + list.forEach(function(name) { + var node = new Node(name, data = {label:name}); + this.addNode(node); + }, this); + } +}; + Graph.prototype.addEdge = function(edge) { var exists = false; this.edges.forEach(function(e) { @@ -96,10 +88,10 @@ Graph.prototype.addEdge = function(edge) { this.edges.push(edge); } - if (typeof(this.adjacency[edge.source.id]) === 'undefined') { + if (!(edge.source.id in this.adjacency)) { this.adjacency[edge.source.id] = {}; } - if (typeof(this.adjacency[edge.source.id][edge.target.id]) === 'undefined') { + if (!(edge.target.id in this.adjacency[edge.source.id])) { this.adjacency[edge.source.id][edge.target.id] = []; } @@ -130,8 +122,8 @@ Graph.prototype.newEdge = function(source, target, data) { // find the edges from node1 to node2 Graph.prototype.getEdges = function(node1, node2) { - if (typeof(this.adjacency[node1.id]) !== 'undefined' - && typeof(this.adjacency[node1.id][node2.id]) !== 'undefined') { + if (node1.id in this.adjacency + && node2.id in this.adjacency[node1.id]) { return this.adjacency[node1.id][node2.id]; } @@ -140,7 +132,7 @@ Graph.prototype.getEdges = function(node1, node2) { // remove a node and it's associated edges from the graph Graph.prototype.removeNode = function(node) { - if (typeof(this.nodeSet[node.id]) !== 'undefined') { + if (node.id in this.nodeSet) { delete this.nodeSet[node.id]; } @@ -263,8 +255,8 @@ Layout.ForceDirected = function(graph, stiffness, repulsion, damping) { }; Layout.ForceDirected.prototype.point = function(node) { - if (typeof(this.nodePoints[node.id]) === 'undefined') { - var mass = typeof(node.data.mass) !== 'undefined' ? node.data.mass : 1.0; + if (!(node.id in this.nodePoints)) { + var mass = (node.data.mass !== undefined) ? node.data.mass : 1.0; this.nodePoints[node.id] = new Layout.ForceDirected.Point(Vector.random(), mass); } @@ -272,14 +264,14 @@ Layout.ForceDirected.prototype.point = function(node) { }; Layout.ForceDirected.prototype.spring = function(edge) { - if (typeof(this.edgeSprings[edge.id]) === 'undefined') { - var length = typeof(edge.data.length) !== 'undefined' ? edge.data.length : 1.0; + if (!(edge.id in this.edgeSprings)) { + var length = (edge.data.length !== undefined) ? edge.data.length : 1.0; var existingSpring = false; var from = this.graph.getEdges(edge.source, edge.target); from.forEach(function(e) { - if (existingSpring === false && typeof(this.edgeSprings[e.id]) !== 'undefined') { + if (existingSpring === false && e.id in this.edgeSprings) { existingSpring = this.edgeSprings[e.id]; } }, this); @@ -290,7 +282,7 @@ Layout.ForceDirected.prototype.spring = function(edge) { var to = this.graph.getEdges(edge.target, edge.source); from.forEach(function(e){ - if (existingSpring === false && typeof(this.edgeSprings[e.id]) !== 'undefined') { + if (existingSpring === false && e.id in this.edgeSprings) { existingSpring = this.edgeSprings[e.id]; } }, this); @@ -411,7 +403,7 @@ Layout.requestAnimationFrame = __bind(window.requestAnimationFrame || // start simulation -Layout.ForceDirected.prototype.start = function(interval, render, done) { +Layout.ForceDirected.prototype.start = function(render, done) { var t = this; if (this._started) return; @@ -424,13 +416,14 @@ Layout.ForceDirected.prototype.start = function(interval, render, done) { t.updateVelocity(0.03); t.updatePosition(0.03); - if (typeof(render) !== 'undefined') + if (render !== undefined) { render(); + } // stop simulation when energy of the system goes below a threshold if (t.totalEnergy() < 0.01) { t._started = false; - if (typeof(done) !== 'undefined') { done(); } + if (done !== undefined) { done(); } } else { Layout.requestAnimationFrame(step); } @@ -547,8 +540,7 @@ Layout.ForceDirected.Spring = function(point1, point2, length, k) { // }; // Renderer handles the layout rendering loop -function Renderer(interval, layout, clear, drawEdge, drawNode) { - this.interval = interval; +function Renderer(layout, clear, drawEdge, drawNode) { this.layout = layout; this.clear = clear; this.drawEdge = drawEdge; @@ -563,7 +555,7 @@ Renderer.prototype.graphChanged = function(e) { Renderer.prototype.start = function() { var t = this; - this.layout.start(50, function render() { + this.layout.start(function render() { t.clear(); t.layout.eachEdge(function(edge, spring) { @@ -576,3 +568,31 @@ Renderer.prototype.start = function() { }); }; +// Array.forEach implementation for IE support.. +//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach +if ( !Array.prototype.forEach ) { + Array.prototype.forEach = function( callback, thisArg ) { + var T, k; + if ( this == null ) { + throw new TypeError( " this is null or not defined" ); + } + var O = Object(this); + var len = O.length >>> 0; // Hack to convert O.length to a UInt32 + if ( {}.toString.call(callback) != "[object Function]" ) { + throw new TypeError( callback + " is not a function" ); + } + if ( thisArg ) { + T = thisArg; + } + k = 0; + while( k < len ) { + var kValue; + if ( k in O ) { + kValue = O[ k ]; + callback.call( T, kValue, k, O ); + } + k++; + } + }; +} + diff --git a/springyui.js b/springyui.js index ae94584..771dec9 100755 --- a/springyui.js +++ b/springyui.js @@ -112,7 +112,7 @@ jQuery.fn.springy = function(params) { }); Node.prototype.getWidth = function() { - var text = typeof(this.data.label) !== 'undefined' ? this.data.label : this.id; + var text = (this.data.label !== undefined) ? this.data.label : this.id; if (this._width && this._width[text]) return this._width[text]; @@ -131,7 +131,7 @@ jQuery.fn.springy = function(params) { return 20; }; - var renderer = new Renderer(1, layout, + var renderer = new Renderer(layout, function clear() { ctx.clearRect(0,0,canvas.width,canvas.height); }, @@ -174,18 +174,18 @@ jQuery.fn.springy = function(params) { intersection = s2; } - var stroke = typeof(edge.data.color) !== 'undefined' ? edge.data.color : '#000000'; + var stroke = (edge.data.color !== undefined) ? edge.data.color : '#000000'; var arrowWidth; var arrowLength; - var weight = typeof(edge.data.weight) !== 'undefined' ? edge.data.weight : 1.0; + var weight = (edge.data.weight !== undefined) ? edge.data.weight : 1.0; ctx.lineWidth = Math.max(weight * 2, 0.1); arrowWidth = 1 + ctx.lineWidth; arrowLength = 8; - var directional = typeof(edge.data.directional) !== 'undefined' ? edge.data.directional : true; + var directional = (edge.data.directional !== undefined) ? edge.data.directional : true; // line var lineEnd; @@ -218,7 +218,7 @@ jQuery.fn.springy = function(params) { } // label - if (typeof(edge.data.label) !== 'undefined') { + if (edge.data.label !== undefined) { text = edge.data.label ctx.save(); ctx.textAlign = "center"; @@ -256,7 +256,7 @@ jQuery.fn.springy = function(params) { ctx.font = "16px Verdana, sans-serif"; ctx.fillStyle = "#000000"; ctx.font = "16px Verdana, sans-serif"; - var text = typeof(node.data.label) !== 'undefined' ? node.data.label : node.id; + var text = (node.data.label !== undefined) ? node.data.label : node.id; ctx.fillText(text, s.x - boxWidth/2 + 5, s.y - 8); ctx.restore();