Skip to content

Commit 7ae28f1

Browse files
committed
Merge branch 'transform' into 2.5.0
2 parents 8d68572 + 9460e7f commit 7ae28f1

File tree

9 files changed

+197
-18
lines changed

9 files changed

+197
-18
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ d3.core.js: \
120120
src/core/transition-each.js \
121121
src/core/transition-transition.js \
122122
src/core/timer.js \
123+
src/core/transform.js \
123124
src/core/noop.js
124125

125126
d3.scale.js: \

d3.js

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ d3.interpolateString = function(a, b) {
879879
};
880880
};
881881

882+
d3.interpolateTransform = function(a, b) {
883+
return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
884+
};
885+
882886
d3.interpolateRgb = function(a, b) {
883887
a = d3.rgb(a);
884888
b = d3.rgb(b);
@@ -933,7 +937,7 @@ d3.interpolateObject = function(a, b) {
933937
k;
934938
for (k in a) {
935939
if (k in b) {
936-
i[k] = d3.interpolate(a[k], b[k]);
940+
i[k] = d3_interpolateByName(k)(a[k], b[k]);
937941
} else {
938942
c[k] = a[k];
939943
}
@@ -951,11 +955,17 @@ d3.interpolateObject = function(a, b) {
951955

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

958+
function d3_interpolateByName(n) {
959+
return n == "transform"
960+
? d3.interpolateTransform
961+
: d3.interpolate;
962+
}
963+
954964
d3.interpolators = [
955965
d3.interpolateObject,
956966
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
957-
function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
958-
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); },
967+
function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
968+
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); },
959969
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
960970
];
961971
function d3_uninterpolateNumber(a, b) {
@@ -1985,17 +1995,18 @@ function d3_transitionNull(d, i, a) {
19851995
return a != "" && d3_transitionRemove;
19861996
}
19871997

1988-
function d3_transitionTween(b) {
1998+
function d3_transitionTween(name, b) {
1999+
var interpolate = d3_interpolateByName(name);
19892000

19902001
function transitionFunction(d, i, a) {
19912002
var v = b.call(this, d, i);
19922003
return v == null
19932004
? a != "" && d3_transitionRemove
1994-
: a != v && d3.interpolate(a, v);
2005+
: a != v && interpolate(a, v);
19952006
}
19962007

19972008
function transitionString(d, i, a) {
1998-
return a != b && d3.interpolate(a, b);
2009+
return a != b && interpolate(a, b);
19992010
}
20002011

20012012
return typeof b === "function" ? transitionFunction
@@ -2060,7 +2071,7 @@ d3_transitionPrototype.selectAll = function(selector) {
20602071
return d3_transition(subgroups, this.id, this.time).ease(this.ease());
20612072
};
20622073
d3_transitionPrototype.attr = function(name, value) {
2063-
return this.attrTween(name, d3_transitionTween(value));
2074+
return this.attrTween(name, d3_transitionTween(name, value));
20642075
};
20652076

20662077
d3_transitionPrototype.attrTween = function(nameNS, tween) {
@@ -2084,7 +2095,7 @@ d3_transitionPrototype.attrTween = function(nameNS, tween) {
20842095
};
20852096
d3_transitionPrototype.style = function(name, value, priority) {
20862097
if (arguments.length < 3) priority = "";
2087-
return this.styleTween(name, d3_transitionTween(value), priority);
2098+
return this.styleTween(name, d3_transitionTween(name, value), priority);
20882099
};
20892100

20902101
d3_transitionPrototype.styleTween = function(name, tween, priority) {
@@ -2237,6 +2248,54 @@ var d3_timer_frame = window.requestAnimationFrame
22372248
|| window.oRequestAnimationFrame
22382249
|| window.msRequestAnimationFrame
22392250
|| function(callback) { setTimeout(callback, 17); };
2251+
d3.transform = function(string) {
2252+
d3_transformG.setAttribute("transform", string);
2253+
return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
2254+
};
2255+
2256+
// Compute x-scale and normalize the first row.
2257+
// Compute shear and make second row orthogonal to first.
2258+
// Compute y-scale and normalize the second row.
2259+
// Finally, compute the rotation.
2260+
function d3_transform(m) {
2261+
var r0 = [m.a, m.b],
2262+
r1 = [m.c, m.d],
2263+
kx = d3_transformNormalize(r0),
2264+
kz = d3_transformDot(r0, r1),
2265+
ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
2266+
this.translate = [m.e, m.f];
2267+
this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
2268+
this.scale = [kx, ky || 0];
2269+
this.skew = ky ? kz / ky * d3_transformDegrees : 0;
2270+
};
2271+
2272+
d3_transform.prototype.toString = function() {
2273+
return "translate(" + this.translate
2274+
+ ")rotate(" + this.rotate
2275+
+ ")skewX(" + this.skew
2276+
+ ")scale(" + this.scale
2277+
+ ")";
2278+
};
2279+
2280+
function d3_transformDot(a, b) {
2281+
return a[0] * b[0] + a[1] * b[1];
2282+
}
2283+
2284+
function d3_transformNormalize(a) {
2285+
var k = Math.sqrt(d3_transformDot(a, a));
2286+
a[0] /= k;
2287+
a[1] /= k;
2288+
return k;
2289+
}
2290+
2291+
function d3_transformCombine(a, b, k) {
2292+
a[0] += k * b[0];
2293+
a[1] += k * b[1];
2294+
return a;
2295+
}
2296+
2297+
var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
2298+
d3_transformDegrees = 180 / Math.PI;
22402299
function d3_noop() {}
22412300
d3.scale = {};
22422301

d3.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/transform/transform.html

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
5+
<title>Transform Transitions</title>
6+
<script type="text/javascript" src="../../d3.js"></script>
7+
<style type="text/css">
8+
9+
body {
10+
margin: 0;
11+
}
12+
13+
rect {
14+
stroke: #fff;
15+
stroke-width: .05px;
16+
}
17+
18+
</style>
19+
</head>
20+
<body>
21+
<script type="text/javascript">
22+
23+
var w = 960,
24+
h = 500,
25+
z = 20,
26+
x = w / z,
27+
y = h / z;
28+
29+
var svg = d3.select("body").append("svg:svg")
30+
.attr("width", w)
31+
.attr("height", h);
32+
33+
svg.selectAll("rect")
34+
.data(d3.range(x * y))
35+
.enter().append("svg:rect")
36+
.attr("transform", translate)
37+
.attr("width", z)
38+
.attr("height", z)
39+
.style("fill", d3.scale.linear().domain([0, x * y]).range(["brown", "steelblue"]))
40+
.on("mouseover", mouseover);
41+
42+
function translate(d) {
43+
return "translate(" + (d % x) * z + "," + Math.floor(d / x) * z + ")";
44+
}
45+
46+
function mouseover(d) {
47+
this.parentNode.appendChild(this);
48+
d3.select(this).transition()
49+
.duration(750)
50+
.attr("transform", "translate(480,480)scale(23)rotate(180)")
51+
.transition()
52+
.delay(1500)
53+
.attr("transform", "translate(240,240)scale(0)rotate(180)")
54+
.style("fill-opacity", 0)
55+
.remove();
56+
}
57+
58+
</script>
59+
</body>
60+
</html>

src/core/interpolate.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ d3.interpolateString = function(a, b) {
9292
};
9393
};
9494

95+
d3.interpolateTransform = function(a, b) {
96+
return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
97+
};
98+
9599
d3.interpolateRgb = function(a, b) {
96100
a = d3.rgb(a);
97101
b = d3.rgb(b);
@@ -146,7 +150,7 @@ d3.interpolateObject = function(a, b) {
146150
k;
147151
for (k in a) {
148152
if (k in b) {
149-
i[k] = d3.interpolate(a[k], b[k]);
153+
i[k] = d3_interpolateByName(k)(a[k], b[k]);
150154
} else {
151155
c[k] = a[k];
152156
}
@@ -164,10 +168,16 @@ d3.interpolateObject = function(a, b) {
164168

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

171+
function d3_interpolateByName(n) {
172+
return n == "transform"
173+
? d3.interpolateTransform
174+
: d3.interpolate;
175+
}
176+
167177
d3.interpolators = [
168178
d3.interpolateObject,
169179
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
170-
function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
171-
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); },
180+
function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
181+
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); },
172182
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
173183
];

src/core/transform.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
d3.transform = function(string) {
2+
d3_transformG.setAttribute("transform", string);
3+
return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
4+
};
5+
6+
// Compute x-scale and normalize the first row.
7+
// Compute shear and make second row orthogonal to first.
8+
// Compute y-scale and normalize the second row.
9+
// Finally, compute the rotation.
10+
function d3_transform(m) {
11+
var r0 = [m.a, m.b],
12+
r1 = [m.c, m.d],
13+
kx = d3_transformNormalize(r0),
14+
kz = d3_transformDot(r0, r1),
15+
ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
16+
this.translate = [m.e, m.f];
17+
this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
18+
this.scale = [kx, ky || 0];
19+
this.skew = ky ? kz / ky * d3_transformDegrees : 0;
20+
};
21+
22+
d3_transform.prototype.toString = function() {
23+
return "translate(" + this.translate
24+
+ ")rotate(" + this.rotate
25+
+ ")skewX(" + this.skew
26+
+ ")scale(" + this.scale
27+
+ ")";
28+
};
29+
30+
function d3_transformDot(a, b) {
31+
return a[0] * b[0] + a[1] * b[1];
32+
}
33+
34+
function d3_transformNormalize(a) {
35+
var k = Math.sqrt(d3_transformDot(a, a));
36+
a[0] /= k;
37+
a[1] /= k;
38+
return k;
39+
}
40+
41+
function d3_transformCombine(a, b, k) {
42+
a[0] += k * b[0];
43+
a[1] += k * b[1];
44+
return a;
45+
}
46+
47+
var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
48+
d3_transformDegrees = 180 / Math.PI;

src/core/transition-attr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
d3_transitionPrototype.attr = function(name, value) {
2-
return this.attrTween(name, d3_transitionTween(value));
2+
return this.attrTween(name, d3_transitionTween(name, value));
33
};
44

55
d3_transitionPrototype.attrTween = function(nameNS, tween) {

src/core/transition-style.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
d3_transitionPrototype.style = function(name, value, priority) {
22
if (arguments.length < 3) priority = "";
3-
return this.styleTween(name, d3_transitionTween(value), priority);
3+
return this.styleTween(name, d3_transitionTween(name, value), priority);
44
};
55

66
d3_transitionPrototype.styleTween = function(name, tween, priority) {

src/core/transition.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,18 @@ function d3_transitionNull(d, i, a) {
9292
return a != "" && d3_transitionRemove;
9393
}
9494

95-
function d3_transitionTween(b) {
95+
function d3_transitionTween(name, b) {
96+
var interpolate = d3_interpolateByName(name);
9697

9798
function transitionFunction(d, i, a) {
9899
var v = b.call(this, d, i);
99100
return v == null
100101
? a != "" && d3_transitionRemove
101-
: a != v && d3.interpolate(a, v);
102+
: a != v && interpolate(a, v);
102103
}
103104

104105
function transitionString(d, i, a) {
105-
return a != b && d3.interpolate(a, b);
106+
return a != b && interpolate(a, b);
106107
}
107108

108109
return typeof b === "function" ? transitionFunction

0 commit comments

Comments
 (0)