UNPKG

d3-jsnext

Version:
272 lines (262 loc) 9.85 kB
require( 'babel/register' ); var vows = require("vows"), _ = require("../d3"), load = require("../load"), assert = require("../assert"); var suite = vows.describe("d3.geom.voronoi"); suite.addBatch({ "voronoi": { topic: load("geom/voronoi").expression("d3.geom.voronoi"), "the default voronoi layout": { topic: function(voronoi) { return voronoi(); }, "has no defined clip extent": function(v) { assert.isNull(v.clipExtent()); }, "has no defined size": function(v) { assert.isNull(v.size()); }, "returns the configured clip extent": function(v) { try { assert.deepEqual(v.clipExtent([[1, 2], [3, 4]]).clipExtent(), [[1, 2], [3, 4]]); } finally { v.clipExtent(null); } }, "returns the configured size": function(v) { try { assert.deepEqual(v.size([1, 2]).size(), [1, 2]); } finally { v.size(null); } }, "size implies a clip extent from [0, 0]": function(v) { try { assert.deepEqual(v.size([1, 2]).clipExtent(), [[0, 0], [1, 2]]); } finally { v.size(null); } }, "clip extent implies a size, assuming [0, 0]": function(v) { try { assert.deepEqual(v.clipExtent([[1, 2], [3, 4]]).size(), [3, 4]); } finally { v.clipExtent(null); } }, "has the default x-accessor, d[0]": function(v) { assert.strictEqual(v.x()([42, 43]), 42); }, "has the default y-accessor, d[1]": function(v) { assert.strictEqual(v.y()([42, 43]), 43); }, "of two points": { topic: function(v) { return v([[200, 200], [760, 300]]); }, "returns two cells with the expected geometry": function(cells) { assert.inDelta(cells, [ [[-178046.7857142857, 1e6], [179096.07142857145, -1e6], [-1e6, -1e6], [-1e6, 1e6]], [[179096.07142857145, -1e6], [-178046.7857142857, 1e6], [1e6, 1e6], [1e6, -1e6]] ], 1e-6); }, "the returned cells are open polygons": function(cells) { cells.forEach(function(cell) { assert.greater(cell.length, 2); cell.forEach(function(point) { assert.equal(point.length, 2); assert.isNumber(point[0]); assert.isNumber(point[1]); }); assert.notDeepEqual(cell[0], cell[cell.length - 1]); }); }, "the returned cells are not clipped to the layout size": function(cells) { var x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity; cells.forEach(function(cell) { cell.forEach(function(point) { if (point[0] < x0) x0 = point[0]; if (point[0] > x1) x1 = point[0]; if (point[1] < y0) y0 = point[1]; if (point[1] > y1) y1 = point[1]; }); }); assert.strictEqual(x0, -1e6); assert.strictEqual(x1, 1e6); assert.strictEqual(y0, -1e6); assert.strictEqual(y1, 1e6); }, "the returned cells' point property points back to the input point": function(cells) { assert.deepEqual(cells.map(function(cell) { return cell.point; }), [[200, 200], [760, 300]]); }, "the returned cells’ have positive area": function(cells) { cells.forEach(function(cell) { assert.ok(_.geom.polygon(cell).area() > 0); }); } }, "links": { "for two points": function(v) { assert.deepEqual(v.links([[200, 200], [760, 300]]), [ {source: [200, 200], target: [760, 300]} ]); }, "for three points": function(v) { assert.deepEqual(v.links([[200, 200], [500, 250], [760, 300]]), [ {source: [200, 200], target: [500, 250]}, {source: [500, 250], target: [760, 300]}, {source: [760, 300], target: [200, 200]} ]); } }, "triangles": { "for three points": function(v) { assert.deepEqual(v.triangles([[200, 200], [500, 250], [760, 300]]), [ [[200, 200], [760, 300], [500, 250]] ]); } } }, "a voronoi layout with custom x- and y-accessors": { topic: function(voronoi) { return voronoi() .x(function(d) { return d.x; }) .y(43); }, "observes the specified x-accessor, a function": function(v) { assert.strictEqual(v.x()({x: 42, y: 43}), 42); }, "observes the specified y-accessor, a constant": function(v) { assert.strictEqual(v.y(), 43); }, "of two points": { topic: function(v) { return v([{x: 200}, {x: 760}]); }, "returns two cells with the expected geometry": function(cells) { assert.inDelta(cells, [ [[480, 1e6], [480, -1e6], [-1e6, -1e6], [-1e6, 1e6]], [[480, -1e6], [480, 1e6], [1e6, 1e6], [1e6, -1e6]] ], 1e-6); } }, "links": { topic: function(v) { return v.y(function(d) { return d.y; }); }, "for two points": function(v) { assert.deepEqual(v.links([{x: 200, y: 200}, {x: 760, y: 300}]), [ {source: {x: 200, y: 200}, target: {x: 760, y: 300}} ]); }, "for three points": function(v) { assert.deepEqual(v.links([{x: 200, y: 200}, {x: 500, y: 250}, {x: 760, y: 300}]), [ {source: {x: 200, y: 200}, target: {x: 500, y: 250}}, {source: {x: 500, y: 250}, target: {x: 760, y: 300}}, {source: {x: 760, y: 300}, target: {x: 200, y: 200}} ]); } } }, "a voronoi layout with clip extent [[0, 0], [960, 500]]": { topic: function(voronoi) { return voronoi() .x(function(d) { return d.x; }) .y(function(d) { return d.y; }) .clipExtent([[0, 0], [960, 500]]); }, "of two points": { topic: function(v) { return v([{x: 200, y: 200}, {x: 760, y: 300}]); }, "returns two cells with the expected geometry": function(cells) { assert.inDelta(cells, [ [[435.35714285715324, 500], [524.6428571428696, 0], [0, 0], [0, 500]], [[524.6428571428696, 0], [435.35714285715324, 500], [960, 500], [960, 0]] ], 1e-6); }, "the returned cells are clipped to the layout size": function(cells) { assert.isTrue(cells.every(function(cell) { return cell.every(function(point) { return point[0] >= 0 && point[0] <= 960 && point[1] >= 0 && point[1] <= 500; }); })); } } }, "the default voronoi layout applied directly": { "with zero points": { "returns the empty array": function(voronoi) { assert.deepEqual(polygons(voronoi([])), []); } }, "with one point": { topic: function(v) { return v([[50, 50]]); }, "returns the semi-infinite bounding box": function(cells) { assert.deepEqual(polygons(cells), [ [[-1e6, 1e6], [1e6, 1e6], [1e6, -1e6], [-1e6, -1e6]] ]); }, "the returned cell has positive area": function(cells) { assert.ok(_.geom.polygon(cells[0]).area() > 0); } }, "with two points": { "separated by a horizontal line": function(voronoi) { assert.deepEqual(polygons(voronoi([[0, -100], [0, 100]])), [ [[-1e6, 0], [1e6, 0], [1e6, -1e6], [-1e6, -1e6]], [[1e6, 0], [-1e6, 0], [-1e6, 1e6], [1e6, 1e6]], ]); assert.deepEqual(polygons(voronoi([[0, 100], [0, -100]])), [ [[1e6, 0], [-1e6, 0], [-1e6, 1e6], [1e6, 1e6]], [[-1e6, 0], [1e6, 0], [1e6, -1e6], [-1e6, -1e6]] ]); }, "separated by a vertical line": function(voronoi) { assert.deepEqual(polygons(voronoi([[100, 0], [-100, 0]])), [ [[0, -1e6], [0, 1e6], [1e6, 1e6], [1e6, -1e6]], [[0, 1e6], [0, -1e6], [-1e6, -1e6], [-1e6, 1e6]] ]); assert.deepEqual(polygons(voronoi([[-100, 0], [100, 0]])), [ [[0, 1e6], [0, -1e6], [-1e6, -1e6], [-1e6, 1e6]], [[0, -1e6], [0, 1e6], [1e6, 1e6], [1e6, -1e6]] ]); }, "separated by a diagonal line": function(voronoi) { assert.deepEqual(polygons(voronoi([[-100, -100], [100, 100]])), [ [[-1e6, 1e6], [1e6, -1e6], [-1e6, -1e6]], [[1e6, -1e6], [-1e6, 1e6], [1e6, 1e6]] ]); assert.deepEqual(polygons(voronoi([[100, 100], [-100, -100]])), [ [[1e6, -1e6], [-1e6, 1e6], [1e6, 1e6]], [[-1e6, 1e6], [1e6, -1e6], [-1e6, -1e6]] ]); }, "separated by an arbitrary diagonal": function(voronoi) { assert.deepEqual(polygons(voronoi([[-100, -100], [100, 0]])), [ [[-500025, 1e6], [499975, -1e6], [-1e6, -1e6], [-1e6, 1e6]], [ [499975, -1e6], [-500025, 1e6], [1e6, 1e6], [1e6, -1e6]] ]); } }, "with three points": { "collinear": function(voronoi) { assert.deepEqual(polygons(voronoi([[-100, -100], [0, 0], [100, 100]])), [ [[-1e6, 999900], [999900, -1e6], [-1e6, -1e6]], [[-999900, 1e6], [1e6, -999900], [1e6, -1e6], [999900, -1e6], [-1e6, 999900], [-1e6, 1e6]], [[1e6, -999900], [-999900, 1e6], [1e6, 1e6]] ]); } } } } }); function polygons(cells) { cells.forEach(function(cell) { delete cell.point; }); return cells; } suite.export(module);