Skip to content

Commit

Permalink
Fix #16 - tension is cardinal-specific.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Nov 13, 2015
1 parent 9cdb143 commit 443978e
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 103 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ If you use NPM, `npm install d3-shape`. Otherwise, download the [latest release]

## Changes from D3 3.x:

* The default tension for cardinal interpolation is now 2 / 3, not 0.7.
* The behavior of the cardinal interpolation tension parameter has been standardized. The default tension is now 0, not 0.7.

8 changes: 6 additions & 2 deletions src/interpolate/basis-closed.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import {point} from "./basis";

function basisClosed(context) {
return new BasisClosed(context);
}

function BasisClosed(context) {
this._context = context;
};
}

basisClosed.prototype = {
BasisClosed.prototype = {
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = null;
Expand Down
8 changes: 6 additions & 2 deletions src/interpolate/basis-open.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import {point} from "./basis";

function basisOpen(context) {
return new BasisOpen(context);
}

function BasisOpen(context) {
this._context = context;
};
}

basisOpen.prototype = {
BasisOpen.prototype = {
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = null;
Expand Down
8 changes: 6 additions & 2 deletions src/interpolate/basis.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ export function point(basis, x, y) {
};

function basis(context) {
return new Basis(context);
}

function Basis(context) {
this._context = context;
};
}

basis.prototype = {
Basis.prototype = {
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = null;
Expand Down
10 changes: 8 additions & 2 deletions src/interpolate/cardinal-open.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
function cardinalOpen(context, tension) {
function cardinalOpen(tension) {
return function(context) {
return new CardinalOpen(context, tension);
};
}

function CardinalOpen(context, tension) {
this._context = context;
this._k = (tension == null ? 1 : 1 - tension) / 6;
}

cardinalOpen.prototype = {
CardinalOpen.prototype = {
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
Expand Down
10 changes: 8 additions & 2 deletions src/interpolate/cardinal.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
function cardinal(context, tension) {
function cardinal(tension) {
return function(context) {
return new Cardinal(context, tension);
};
}

function Cardinal(context, tension) {
this._context = context;
this._k = (tension == null ? 1 : 1 - tension) / 6;
}

cardinal.prototype = {
Cardinal.prototype = {
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
Expand Down
47 changes: 0 additions & 47 deletions src/interpolate/hermite.js

This file was deleted.

6 changes: 5 additions & 1 deletion src/interpolate/linear-closed.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function linearClosed(context) {
return new LinearClosed(context);
}

function LinearClosed(context) {
this._context = context;
}

linearClosed.prototype = {
LinearClosed.prototype = {
lineStart: function() {
this._state = 0;
},
Expand Down
6 changes: 5 additions & 1 deletion src/interpolate/linear.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function linear(context) {
return new Linear(context);
}

function Linear(context) {
this._context = context;
}

linear.prototype = {
Linear.prototype = {
lineStart: function() {
this._state = 0;
},
Expand Down
6 changes: 5 additions & 1 deletion src/interpolate/step-after.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function stepAfter(context) {
return new StepAfter(context);
}

function StepAfter(context) {
this._context = context;
}

stepAfter.prototype = {
StepAfter.prototype = {
lineStart: function() {
this._y = NaN;
this._state = 0;
Expand Down
6 changes: 5 additions & 1 deletion src/interpolate/step-before.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function stepBefore(context) {
return new StepBefore(context);
}

function StepBefore(context) {
this._context = context;
}

stepBefore.prototype = {
StepBefore.prototype = {
lineStart: function() {
this._x = NaN;
this._state = 0;
Expand Down
8 changes: 6 additions & 2 deletions src/interpolate/step.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function step(context) {
return new Step(context);
}

function Step(context) {
this._context = context;
};
}

step.prototype = {
Step.prototype = {
lineStart: function() {
this._x = this._y = NaN;
this._state = 0;
Expand Down
40 changes: 19 additions & 21 deletions src/line.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,11 @@ function _true() {
return true;
}

// TODO bundle, cardinal-closed, monotone, cubic
var interpolates = {
"linear": linear,
"linear-closed": linearClosed,
"step": step,
"step-before": stepBefore,
"step-after": stepAfter,
"basis": basis,
"basis-open": basisOpen,
"basis-closed": basisClosed,
"cardinal": cardinal,
"cardinal-open": cardinalOpen
};

export default function() {
var x = pointX, _x = x,
y = pointY, _y = y,
defined = true, _defined = _true,
interpolate = "linear", _interpolate = linear,
interpolate = linear,
tension = null,
context = null,
stream = null;
Expand All @@ -55,7 +41,7 @@ export default function() {
var defined = false,
buffer;

if (!context) stream = new _interpolate(buffer = path(), tension);
if (!context) stream = interpolate(buffer = path());

for (var i = 0, n = data.length, d; i < n; ++i) {
if (!_defined(d = data[i], i) === defined) {
Expand Down Expand Up @@ -87,24 +73,36 @@ export default function() {
return line;
};

line.interpolate = function(_) {
line.interpolate = function(_, tension) {
if (!arguments.length) return interpolate;
_interpolate = interpolates[interpolate = interpolates.hasOwnProperty(_ += "") ? _ : "linear"];
if (context != null) stream = new _interpolate(context, tension);
if (typeof _ === "function") interpolate = _;
else switch (_ + "") {
case "linear-closed": interpolate = linearClosed; break;
case "step": interpolate = step; break;
case "step-before": interpolate = stepBefore; break;
case "step-after": interpolate = stepAfter; break;
case "basis": interpolate = basis; break;
case "basis-open": interpolate = basisOpen; break;
case "basis-closed": interpolate = basisClosed; break;
case "cardinal": interpolate = cardinal(tension); break;
case "cardinal-open": interpolate = cardinalOpen(tension); break;
default: interpolate = linear; break;
}
if (context != null) stream = interpolate(context);
return line;
};

line.tension = function(_) {
if (!arguments.length) return tension;
tension = _ == null ? _ : +_;
if (context != null) stream = new _interpolate(context, tension);
if (context != null) stream = interpolate(context);
return line;
};

line.context = function(_) {
if (!arguments.length) return context;
if (_ == null) context = stream = null;
else stream = new _interpolate(context = _, tension);
else stream = interpolate(context = _);
return line;
};

Expand Down
58 changes: 40 additions & 18 deletions test/line-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ tape("line() returns a default line shape", function(test) {
test.equal(l.x()([42, 34]), 42);
test.equal(l.y()([42, 34]), 34);
test.equal(l.defined(), true);
test.equal(l.interpolate(), "linear");
test.equal(l.tension(), null);
test.equal(l.context(), null);
test.equal(l([[0, 1], [2, 3], [4, 5]]), "M0,1L2,3L4,5");
Expand Down Expand Up @@ -39,16 +38,13 @@ tape("line.y(y)(data) observes the specified constant", function(test) {

tape("line.interpolate(name) sets the interpolation method", function(test) {
var l = shape.line().interpolate("linear-closed");
test.equal(l.interpolate(), "linear-closed");
test.equal(l([]), null);
test.equal(l([[0, 1], [2, 3]]), "M0,1L2,3Z");
test.end();
});

tape("line.tension(value) sets the interpolation tension", function(test) {
var l = shape.line().interpolate("cardinal").tension(0.1);
test.equal(l.interpolate(), "cardinal");
test.equal(l.tension(), 0.1);
tape("line.interpolate(\"cardinal\", tension) sets the cardinal interpolation tension", function(test) {
var l = shape.line().interpolate("cardinal", 0.1);
test.equal(l([]), null);
test.equal(l([[0, 1]]), "M0,1Z");
test.equal(l([[0, 1], [1, 3]]), "M0,1L1,3");
Expand All @@ -57,29 +53,55 @@ tape("line.tension(value) sets the interpolation tension", function(test) {
test.end();
});

tape("line.tension(value) defaults to null", function(test) {
var l = shape.line().interpolate("cardinal");
test.equal(l.tension(), null);
tape("line.interpolate(\"cardinal\", tension) coerces the specified tension to a number", function(test) {
var l = shape.line().interpolate("cardinal", "0.1");
test.equal(l([]), null);
test.equal(l([[0, 1]]), "M0,1Z");
test.equal(l([[0, 1], [1, 3]]), "M0,1L1,3");
test.equal(l([[0, 1], [1, 3], [2, 1]]), "M0,1Q0.55,3,1,3Q1.45,3,2,1");
test.equal(l([[0, 1], [1, 3], [2, 1], [3, 3]]), "M0,1Q0.55,3,1,3C1.3,3,1.7,1,2,1Q2.45,1,3,3");
test.end();
});

tape("line.interpolate(\"cardinal\") implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal"),
l1 = shape.line().interpolate("cardinal", 0);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

tape("line.interpolate(\"cardinal\", null) implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal"),
l1 = shape.line().interpolate("cardinal", null);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

tape("line.tension(null) is equivalent to 0 for cardinal interpolation", function(test) {
var l0 = shape.line().interpolate("cardinal").tension(null),
l1 = shape.line().interpolate("cardinal").tension(0);
tape("line.interpolate(\"cardinal\", undefined) implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal"),
l1 = shape.line().interpolate("cardinal", undefined);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

tape("line.tension(null) is equivalent to 0 for cardinal-open interpolation", function(test) {
var l0 = shape.line().interpolate("cardinal-open").tension(null),
l1 = shape.line().interpolate("cardinal-open").tension(0);
tape("line.interpolate(\"cardinal-open\") implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal-open"),
l1 = shape.line().interpolate("cardinal-open", 0);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

tape("line.tension(value) coerces the specified value to a number", function(test) {
var l = shape.line().interpolate("cardinal").tension("0.1");
test.equal(l.tension(), 0.1);
tape("line.interpolate(\"cardinal-open\", null) implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal-open"),
l1 = shape.line().interpolate("cardinal-open", null);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

tape("line.interpolate(\"cardinal-open\", undefined) implicitly uses a tension of zero", function(test) {
var l0 = shape.line().interpolate("cardinal-open"),
l1 = shape.line().interpolate("cardinal-open", undefined);
test.equal(l1([[0, 1], [1, 3], [2, 1], [3, 3]]), l0([[0, 1], [1, 3], [2, 1], [3, 3]]));
test.end();
});

Expand Down

0 comments on commit 443978e

Please sign in to comment.