Skip to content

Commit

Permalink
Merge branch 'transform' into 2.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Nov 5, 2011
2 parents 8d68572 + 9460e7f commit 7ae28f1
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 18 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ d3.core.js: \
src/core/transition-each.js \
src/core/transition-transition.js \
src/core/timer.js \
src/core/transform.js \
src/core/noop.js

d3.scale.js: \
Expand Down
75 changes: 67 additions & 8 deletions d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,10 @@ d3.interpolateString = function(a, b) {
};
};

d3.interpolateTransform = function(a, b) {
return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
};

d3.interpolateRgb = function(a, b) {
a = d3.rgb(a);
b = d3.rgb(b);
Expand Down Expand Up @@ -933,7 +937,7 @@ d3.interpolateObject = function(a, b) {
k;
for (k in a) {
if (k in b) {
i[k] = d3.interpolate(a[k], b[k]);
i[k] = d3_interpolateByName(k)(a[k], b[k]);
} else {
c[k] = a[k];
}
Expand All @@ -951,11 +955,17 @@ d3.interpolateObject = function(a, b) {

var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;

function d3_interpolateByName(n) {
return n == "transform"
? d3.interpolateTransform
: d3.interpolate;
}

d3.interpolators = [
d3.interpolateObject,
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(String(a), b); },
function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
];
function d3_uninterpolateNumber(a, b) {
Expand Down Expand Up @@ -1985,17 +1995,18 @@ function d3_transitionNull(d, i, a) {
return a != "" && d3_transitionRemove;
}

function d3_transitionTween(b) {
function d3_transitionTween(name, b) {
var interpolate = d3_interpolateByName(name);

function transitionFunction(d, i, a) {
var v = b.call(this, d, i);
return v == null
? a != "" && d3_transitionRemove
: a != v && d3.interpolate(a, v);
: a != v && interpolate(a, v);
}

function transitionString(d, i, a) {
return a != b && d3.interpolate(a, b);
return a != b && interpolate(a, b);
}

return typeof b === "function" ? transitionFunction
Expand Down Expand Up @@ -2060,7 +2071,7 @@ d3_transitionPrototype.selectAll = function(selector) {
return d3_transition(subgroups, this.id, this.time).ease(this.ease());
};
d3_transitionPrototype.attr = function(name, value) {
return this.attrTween(name, d3_transitionTween(value));
return this.attrTween(name, d3_transitionTween(name, value));
};

d3_transitionPrototype.attrTween = function(nameNS, tween) {
Expand All @@ -2084,7 +2095,7 @@ d3_transitionPrototype.attrTween = function(nameNS, tween) {
};
d3_transitionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = "";
return this.styleTween(name, d3_transitionTween(value), priority);
return this.styleTween(name, d3_transitionTween(name, value), priority);
};

d3_transitionPrototype.styleTween = function(name, tween, priority) {
Expand Down Expand Up @@ -2237,6 +2248,54 @@ var d3_timer_frame = window.requestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { setTimeout(callback, 17); };
d3.transform = function(string) {
d3_transformG.setAttribute("transform", string);
return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
};

// Compute x-scale and normalize the first row.
// Compute shear and make second row orthogonal to first.
// Compute y-scale and normalize the second row.
// Finally, compute the rotation.
function d3_transform(m) {
var r0 = [m.a, m.b],
r1 = [m.c, m.d],
kx = d3_transformNormalize(r0),
kz = d3_transformDot(r0, r1),
ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
this.translate = [m.e, m.f];
this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
this.scale = [kx, ky || 0];
this.skew = ky ? kz / ky * d3_transformDegrees : 0;
};

d3_transform.prototype.toString = function() {
return "translate(" + this.translate
+ ")rotate(" + this.rotate
+ ")skewX(" + this.skew
+ ")scale(" + this.scale
+ ")";
};

function d3_transformDot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}

function d3_transformNormalize(a) {
var k = Math.sqrt(d3_transformDot(a, a));
a[0] /= k;
a[1] /= k;
return k;
}

function d3_transformCombine(a, b, k) {
a[0] += k * b[0];
a[1] += k * b[1];
return a;
}

var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
d3_transformDegrees = 180 / Math.PI;
function d3_noop() {}
d3.scale = {};

Expand Down
4 changes: 2 additions & 2 deletions d3.min.js

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions examples/transform/transform.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Transform Transitions</title>
<script type="text/javascript" src="../../d3.js"></script>
<style type="text/css">

body {
margin: 0;
}

rect {
stroke: #fff;
stroke-width: .05px;
}

</style>
</head>
<body>
<script type="text/javascript">

var w = 960,
h = 500,
z = 20,
x = w / z,
y = h / z;

var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);

svg.selectAll("rect")
.data(d3.range(x * y))
.enter().append("svg:rect")
.attr("transform", translate)
.attr("width", z)
.attr("height", z)
.style("fill", d3.scale.linear().domain([0, x * y]).range(["brown", "steelblue"]))
.on("mouseover", mouseover);

function translate(d) {
return "translate(" + (d % x) * z + "," + Math.floor(d / x) * z + ")";
}

function mouseover(d) {
this.parentNode.appendChild(this);
d3.select(this).transition()
.duration(750)
.attr("transform", "translate(480,480)scale(23)rotate(180)")
.transition()
.delay(1500)
.attr("transform", "translate(240,240)scale(0)rotate(180)")
.style("fill-opacity", 0)
.remove();
}

</script>
</body>
</html>
16 changes: 13 additions & 3 deletions src/core/interpolate.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ d3.interpolateString = function(a, b) {
};
};

d3.interpolateTransform = function(a, b) {
return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
};

d3.interpolateRgb = function(a, b) {
a = d3.rgb(a);
b = d3.rgb(b);
Expand Down Expand Up @@ -146,7 +150,7 @@ d3.interpolateObject = function(a, b) {
k;
for (k in a) {
if (k in b) {
i[k] = d3.interpolate(a[k], b[k]);
i[k] = d3_interpolateByName(k)(a[k], b[k]);
} else {
c[k] = a[k];
}
Expand All @@ -164,10 +168,16 @@ d3.interpolateObject = function(a, b) {

var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;

function d3_interpolateByName(n) {
return n == "transform"
? d3.interpolateTransform
: d3.interpolate;
}

d3.interpolators = [
d3.interpolateObject,
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(String(a), b); },
function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
];
48 changes: 48 additions & 0 deletions src/core/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
d3.transform = function(string) {
d3_transformG.setAttribute("transform", string);
return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
};

// Compute x-scale and normalize the first row.
// Compute shear and make second row orthogonal to first.
// Compute y-scale and normalize the second row.
// Finally, compute the rotation.
function d3_transform(m) {
var r0 = [m.a, m.b],
r1 = [m.c, m.d],
kx = d3_transformNormalize(r0),
kz = d3_transformDot(r0, r1),
ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
this.translate = [m.e, m.f];
this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
this.scale = [kx, ky || 0];
this.skew = ky ? kz / ky * d3_transformDegrees : 0;
};

d3_transform.prototype.toString = function() {
return "translate(" + this.translate
+ ")rotate(" + this.rotate
+ ")skewX(" + this.skew
+ ")scale(" + this.scale
+ ")";
};

function d3_transformDot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}

function d3_transformNormalize(a) {
var k = Math.sqrt(d3_transformDot(a, a));
a[0] /= k;
a[1] /= k;
return k;
}

function d3_transformCombine(a, b, k) {
a[0] += k * b[0];
a[1] += k * b[1];
return a;
}

var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
d3_transformDegrees = 180 / Math.PI;
2 changes: 1 addition & 1 deletion src/core/transition-attr.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
d3_transitionPrototype.attr = function(name, value) {
return this.attrTween(name, d3_transitionTween(value));
return this.attrTween(name, d3_transitionTween(name, value));
};

d3_transitionPrototype.attrTween = function(nameNS, tween) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/transition-style.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
d3_transitionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = "";
return this.styleTween(name, d3_transitionTween(value), priority);
return this.styleTween(name, d3_transitionTween(name, value), priority);
};

d3_transitionPrototype.styleTween = function(name, tween, priority) {
Expand Down
7 changes: 4 additions & 3 deletions src/core/transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,18 @@ function d3_transitionNull(d, i, a) {
return a != "" && d3_transitionRemove;
}

function d3_transitionTween(b) {
function d3_transitionTween(name, b) {
var interpolate = d3_interpolateByName(name);

function transitionFunction(d, i, a) {
var v = b.call(this, d, i);
return v == null
? a != "" && d3_transitionRemove
: a != v && d3.interpolate(a, v);
: a != v && interpolate(a, v);
}

function transitionString(d, i, a) {
return a != b && d3.interpolate(a, b);
return a != b && interpolate(a, b);
}

return typeof b === "function" ? transitionFunction
Expand Down

0 comments on commit 7ae28f1

Please sign in to comment.