From 143d2d4c41e800fcaba9448f235751cb240df6fd Mon Sep 17 00:00:00 2001 From: Fabian Kessler Date: Sat, 20 Apr 2013 23:38:12 +0300 Subject: [PATCH 1/4] updated copyright year The 2010 made me think that the project was abandoned. Also, arbor.js writes that it's based on springy. Only now that I take a closer look I see that there are recent commits. --- springy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/springy.js b/springy.js index ce3a9b5..ace5406 100644 --- a/springy.js +++ b/springy.js @@ -1,7 +1,7 @@ /** * Springy v2.0.1 * - * Copyright (c) 2010 Dennis Hotson + * Copyright (c) 2010-2013 Dennis Hotson * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation From 1b20da23e2acff576edf82fafb3c635202aef857 Mon Sep 17 00:00:00 2001 From: Fabian Kessler Date: Sat, 20 Apr 2013 23:43:28 +0300 Subject: [PATCH 2/4] added done callback to renderer start method. The done callback existed in the ForceDirected layout start method, but no one passed that in. Maybe I don't understand how it's meant to be used? Or something was lost on the way with refactorings in springy? Anyway, with this change it's possible to call the Springy.Renderer start() method with a done callback. Please accept it, or document how it's meant to be used. Thanks ;-) --- springy.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/springy.js b/springy.js index ace5406..e9fdfff 100644 --- a/springy.js +++ b/springy.js @@ -639,7 +639,11 @@ this.start(); }; - Renderer.prototype.start = function() { + /** + * @param done An optional callback function that gets executed when the springy algorithm stops, + * either because it ended or because stop() was called. + */ + Renderer.prototype.start = function(done) { var t = this; this.layout.start(function render() { t.clear(); @@ -651,7 +655,7 @@ t.layout.eachNode(function(node, point) { t.drawNode(node, point.p); }); - }); + }, done); }; Renderer.prototype.stop = function() { From ffca60dcabf2e3ad7e67b4e3c9e067e0600511d5 Mon Sep 17 00:00:00 2001 From: Fabian Kessler Date: Sat, 20 Apr 2013 23:48:58 +0300 Subject: [PATCH 3/4] Documented that start() is silently ignored if running. --- springy.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/springy.js b/springy.js index e9fdfff..fdda419 100644 --- a/springy.js +++ b/springy.js @@ -483,7 +483,10 @@ }), root); - // start simulation + /** + * Start simulation if it's not running already. + * In case it's running then the call is ignored, and none of the callbacks passed is ever executed. + */ Layout.ForceDirected.prototype.start = function(render, done) { var t = this; @@ -640,6 +643,12 @@ }; /** + * Starts the simulation of the layout in use. + * + * Note that in case the algorithm is still or already running then the layout that's in use + * might silently ignore the call, and your optional done callback is never executed. + * At least the built-in ForceDirected layout behaves in this way. + * * @param done An optional callback function that gets executed when the springy algorithm stops, * either because it ended or because stop() was called. */ From 81213595edeb5eee572956c0774b33053311759a Mon Sep 17 00:00:00 2001 From: Fabian Kessler Date: Sun, 21 Apr 2013 02:57:18 +0300 Subject: [PATCH 4/4] Render start and stop callbacks for all cases. Rendering can happen on demand (by calling start()) but also when adding/removing nodes and relations. I also need to be informed when rendering starts in my use case. I have a re-arrange button that needs to be toggled whenever rendering is in progress, and with these events it's nice and clean. When the event callbacks are passed in to the Springy.Renderer start() method only (as in my previous commit) then all the other cases are left out (adding/removing nodes/relations). --- springy.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/springy.js b/springy.js index fdda419..baf6e97 100644 --- a/springy.js +++ b/springy.js @@ -487,12 +487,14 @@ * Start simulation if it's not running already. * In case it's running then the call is ignored, and none of the callbacks passed is ever executed. */ - Layout.ForceDirected.prototype.start = function(render, done) { + Layout.ForceDirected.prototype.start = function(render, onRenderStart, onRenderStop) { var t = this; if (this._started) return; this._started = true; this._stop = false; + + if (onRenderStart !== undefined) { onRenderStart(); } Springy.requestAnimationFrame(function step() { t.applyCoulombsLaw(); @@ -508,7 +510,7 @@ // stop simulation when energy of the system goes below a threshold if (t._stop || t.totalEnergy() < 0.01) { t._started = false; - if (done !== undefined) { done(); } + if (onRenderStop !== undefined) { onRenderStop(); } } else { Springy.requestAnimationFrame(step); } @@ -628,12 +630,18 @@ // return Math.abs(ac.x * n.x + ac.y * n.y); // }; - // Renderer handles the layout rendering loop - var Renderer = Springy.Renderer = function(layout, clear, drawEdge, drawNode) { + /** + * Renderer handles the layout rendering loop + * @param onRenderStart optional callback function that gets executed whenever rendering starts. + * @param onRenderStop optional callback function that gets executed whenever rendering stops. + */ + var Renderer = Springy.Renderer = function(layout, clear, drawEdge, drawNode, onRenderStart, onRenderStop) { this.layout = layout; this.clear = clear; this.drawEdge = drawEdge; this.drawNode = drawNode; + this.onRenderStart = onRenderStart; + this.onRenderStop = onRenderStop; this.layout.graph.addGraphListener(this); } @@ -664,7 +672,7 @@ t.layout.eachNode(function(node, point) { t.drawNode(node, point.p); }); - }, done); + }, this.onRenderStart, this.onRenderStop); }; Renderer.prototype.stop = function() {