diff --git a/test/center-test.js b/test/center-test.js new file mode 100644 index 0000000..ef0c14a --- /dev/null +++ b/test/center-test.js @@ -0,0 +1,27 @@ +var tape = require("tape"), + force = require("../"); + +require("./nodeEqual.js"); + +tape("forceCenter repositions nodes", function(test) { + const center = force.forceCenter(0, 0); + const f = force.forceSimulation().force("center", center).stop(); + const a = { x: 100, y: 0 }, b = { x: 200, y: 0 }, c = { x: 300, y: 0 }; + f.nodes([a, b, c]); + f.tick(); + test.nodeEqual(a, { index: 0, x: -100, y: 0, vy: 0, vx: 0 }); + test.nodeEqual(b, { index: 1, x: 0, y: 0, vy: 0, vx: 0 }); + test.nodeEqual(c, { index: 2, x: 100, y: 0, vy: 0, vx: 0 }); + test.end(); +}); + + +tape("forceCenter respects fixed positions", function(test) { + const center = force.forceCenter(); + const f = force.forceSimulation().force("center", center).stop(); + const a = { fx: 0, fy:0 }, b = {}, c = {}; + f.nodes([a, b, c]); + f.tick(); + test.nodeEqual(a, { fx: 0, fy: 0, index: 0, x: 0, y: 0, vy: 0, vx: 0 }); + test.end(); +}); diff --git a/test/collide-test.js b/test/collide-test.js new file mode 100644 index 0000000..f9ed20f --- /dev/null +++ b/test/collide-test.js @@ -0,0 +1,48 @@ +var tape = require("tape"), + force = require("../"); + +require("./nodeEqual.js"); + +tape("forceCollide collides nodes", function(test) { + const collide = force.forceCollide(1); + const f = force.forceSimulation().force("collide", collide).stop(); + const a = {}, b = {}, c = {}; + f.nodes([a, b, c]); + f.tick(10); + test.nodeEqual(a, { index: 0, x: 7.0710678118654755, y: 0, vy: 0, vx: 0 }); + test.nodeEqual(b, { index: 1, x: -9.03088751750192, y: 8.27303273571596, vy: 0, vx: 0 }); + test.nodeEqual(c, { index: 2, x: 1.3823220809823638, y: -15.750847141167634, vy: 0, vx: 0 }); + collide.radius(100); + f.tick(10); + test.nodeEqual(a, { index: 0, x: 174.08616723117228, y: 66.51743051995625, vy: 0.26976816231064354, vx: 0.677346615710878 }); + test.nodeEqual(b, { index: 1, x: -139.73606544743998, y: 95.69860503079263, vy: 0.3545632444404687, vx: -0.5300880593105067 }); + test.nodeEqual(c, { index: 2, x: -34.9275994083864, y: -169.69384995620052, vy: -0.6243314067511122, vx: -0.1472585564003713 }); + test.end(); +}); + + +tape("forceCollide respects fixed positions", function(test) { + const collide = force.forceCollide(1); + const f = force.forceSimulation().force("collide", collide).stop(); + const a = { fx: 0, fy:0 }, b = {}, c = {}; + f.nodes([a, b, c]); + f.tick(10); + test.nodeEqual(a, { fx: 0, fy: 0, index: 0, x: 0, y: 0, vy: 0, vx: 0 }); + collide.radius(100); + f.tick(10); + test.nodeEqual(a, { fx: 0, fy: 0, index: 0, x: 0, y: 0, vy: 0, vx: 0 }); + test.end(); +}); + +tape("forceCollide jiggles equal positions", function(test) { + const collide = force.forceCollide(1); + const f = force.forceSimulation().force("collide", collide).stop(); + const a = { x: 0, y:0 }, b = { x:0, y: 0 }; + f.nodes([a, b]); + f.tick(); + test.assert(a.x !== b.x); + test.assert(a.y !== b.y); + test.equal(a.vx, -b.vx); + test.equal(a.vy, -b.vy); + test.end(); +}); diff --git a/test/find-test.js b/test/find-test.js new file mode 100644 index 0000000..e7c0dd2 --- /dev/null +++ b/test/find-test.js @@ -0,0 +1,24 @@ +var tape = require("tape"), + force = require("../"); + +require("./nodeEqual.js"); + +tape("simulation.find finds a node", function(test) { + const f = force.forceSimulation().stop(); + const a = { x: 5, y: 0 }, b = { x: 10, y: 16 }, c = { x: -10, y: -4}; + f.nodes([a, b, c]); + test.equal(f.find(0, 0), a); + test.equal(f.find(0, 20), b); + test.end(); +}); + +tape("simulation.find(x, y, radius) finds a node within radius", function(test) { + const f = force.forceSimulation().stop(); + const a = { x: 5, y: 0 }, b = { x: 10, y: 16 }, c = { x: -10, y: -4}; + f.nodes([a, b, c]); + test.equal(f.find(0, 0), a); + test.equal(f.find(0, 0, 1), undefined); + test.equal(f.find(0, 20), b); + test.end(); +}); + diff --git a/test/nodeEqual.js b/test/nodeEqual.js new file mode 100644 index 0000000..788f02e --- /dev/null +++ b/test/nodeEqual.js @@ -0,0 +1,23 @@ +var tape = require("tape"); + +tape.Test.prototype.nodeEqual = nodeEqual; + +function nodeEqual(actual, expected, delta) { + delta = delta || 1e-6; + this._assert(nodeEqual(actual, expected, delta), { + message: "should be similar", + operator: "nodeEqual", + actual: actual, + expected: expected + }); + + function nodeEqual(actual, expected, delta) { + return actual.index == expected.index + && Math.abs(actual.x - expected.x) < delta + && Math.abs(actual.vx - expected.vx) < delta + && Math.abs(actual.y - expected.y) < delta + && Math.abs(actual.vy - expected.vy) < delta + && !(Math.abs(actual.fx - expected.fx) > delta) + && !(Math.abs(actual.fy - expected.fy) > delta); + } +} \ No newline at end of file diff --git a/test/simulation-test.js b/test/simulation-test.js new file mode 100644 index 0000000..e4d09bd --- /dev/null +++ b/test/simulation-test.js @@ -0,0 +1,21 @@ +var tape = require("tape"), + force = require("../"); + +require("./nodeEqual.js"); + +tape("forceSimulation() returns a simulation", function(test) { + const f = force.forceSimulation().stop(); + test.deepEqual(Object.keys(f).sort(), [ 'alpha', 'alphaDecay', 'alphaMin', 'alphaTarget', 'find', 'force', 'nodes', 'on', 'restart', 'stop', 'tick', 'velocityDecay' ]); + test.end(); +}); + +tape("simulation.nodes(nodes) initializes a simulation with indices & phyllotaxis positions, 0 speed", function(test) { + const f = force.forceSimulation().stop(); + const a = {}, b = {}, c = {}; + f.nodes([a, b, c]); + test.nodeEqual(a, { index: 0, x: 7.0710678118654755, y: 0, vy: 0, vx: 0 }); + test.nodeEqual(b, { index: 1, x: -9.03088751750192, y: 8.27303273571596, vy: 0, vx: 0 }); + test.nodeEqual(c, { index: 2, x: 1.3823220809823638, y: -15.750847141167634, vy: 0, vx: 0 }); + test.end(); +}); + diff --git a/test/x-test.js b/test/x-test.js new file mode 100644 index 0000000..51a989f --- /dev/null +++ b/test/x-test.js @@ -0,0 +1,84 @@ +var tape = require("tape"), + force = require("../"); + +require("./nodeEqual.js"); + +tape("forceX centers nodes", function(test) { + const x = force.forceX(200); + const f = force.forceSimulation().force("x", x).stop(); + const a = { x: 100, y: 0 }, b = { x: 200, y: 0 }, c = { x: 300, y: 0 }; + f.nodes([a, b, c]); + f.tick(30); + test.assert(a.x > 190); + test.assert(a.vx > 0); + test.equal(b.x, 200); + test.equal(b.vx, 0); + test.assert(c.x < 210); + test.assert(c.vx < 0); + test.end(); +}); + +tape("forceY centers nodes", function(test) { + const y = force.forceY(200); + const f = force.forceSimulation().force("y", y).stop(); + const a = { y: 100, x: 0 }, b = { y: 200, x: 0 }, c = { y: 300, x: 0 }; + f.nodes([a, b, c]); + f.tick(30); + test.assert(a.y > 190); + test.assert(a.vy > 0); + test.equal(b.y, 200); + test.equal(b.vy, 0); + test.assert(c.y < 210); + test.assert(c.vy < 0); + test.end(); +}); + +tape("forceX respects fixed positions", function(test) { + const x = force.forceX(200); + const f = force.forceSimulation().force("x", x).stop(); + const a = { fx: 0, fy:0 }, b = {}, c = {}; + f.nodes([a, b, c]); + f.tick(); + test.nodeEqual(a, { fx: 0, fy: 0, index: 0, x: 0, y: 0, vy: 0, vx: 0 }); + test.end(); +}); + +tape("forceY respects fixed positions", function(test) { + const y = force.forceX(200); + const f = force.forceSimulation().force("y", y).stop(); + const a = { fx: 0, fy:0 }, b = {}, c = {}; + f.nodes([a, b, c]); + f.tick(); + test.nodeEqual(a, { fx: 0, fy: 0, index: 0, x: 0, y: 0, vy: 0, vx: 0 }); + test.end(); +}); + +tape("forceX.x() accessor", function(test) { + const x = force.forceX().x(d => d.x0); + const f = force.forceSimulation().force("x", x).stop(); + const a = { x: 100, y: 0, x0: 300 }, b = { x: 200, y: 0, x0: 200 }, c = { x: 300, y: 0, x0: 100 }; + f.nodes([a, b, c]); + f.tick(30); + test.assert(a.x > 290); + test.assert(a.vx > 0); + test.equal(b.x, 200); + test.equal(b.vx, 0); + test.assert(c.x < 110); + test.assert(c.vx < 0); + test.end(); +}); + +tape("forceY.y() accessor", function(test) { + const y = force.forceY().y(d => d.y0); + const f = force.forceSimulation().force("y", y).stop(); + const a = { y: 100, x: 0, y0: 300 }, b = { y: 200, x: 0, y0: 200 }, c = { y: 300, x: 0, y0: 100 }; + f.nodes([a, b, c]); + f.tick(30); + test.assert(a.y > 290); + test.assert(a.vy > 0); + test.equal(b.y, 200); + test.equal(b.vy, 0); + test.assert(c.y < 110); + test.assert(c.vy < 0); + test.end(); +});