Skip to content

Commit b878f25

Browse files
committed
Merge branch 'transform-null' of git://github.com/jasondavies/d3 into 2.9.7
Conflicts: examples/transform/test-rotate.html src/core/interpolate.js
2 parents 06deb8f + 20d38f8 commit b878f25

8 files changed

Lines changed: 177 additions & 70 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ d3.core.js: \
7575
src/core/formatPrefix.js \
7676
src/core/ease.js \
7777
src/core/event.js \
78+
src/core/transform.js \
7879
src/core/interpolate.js \
7980
src/core/uninterpolate.js \
8081
src/core/rgb.js \
@@ -118,7 +119,6 @@ d3.core.js: \
118119
src/core/transition-each.js \
119120
src/core/transition-transition.js \
120121
src/core/timer.js \
121-
src/core/transform.js \
122122
src/core/mouse.js \
123123
src/core/touches.js \
124124
src/core/noop.js

d3.v2.js

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,54 @@
732732
};
733733
return dispatch;
734734
}
735+
d3.transform = function(string) {
736+
var g = document.createElementNS(d3.ns.prefix.svg, "g");
737+
return (d3.transform = function(string) {
738+
g.setAttribute("transform", string);
739+
var t = g.transform.baseVal.consolidate();
740+
return new d3_transform(t ? t.matrix : d3_transformIdentity);
741+
})(string);
742+
};
743+
function d3_transform(m) {
744+
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)) || 0;
745+
if (r0[0] * r1[1] < r1[0] * r0[1]) {
746+
r0[0] *= -1;
747+
r0[1] *= -1;
748+
kx *= -1;
749+
kz *= -1;
750+
}
751+
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
752+
this.translate = [ m.e, m.f ];
753+
this.scale = [ kx, ky ];
754+
this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
755+
}
756+
d3_transform.prototype.toString = function() {
757+
return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
758+
};
759+
function d3_transformDot(a, b) {
760+
return a[0] * b[0] + a[1] * b[1];
761+
}
762+
function d3_transformNormalize(a) {
763+
var k = Math.sqrt(d3_transformDot(a, a));
764+
if (k) {
765+
a[0] /= k;
766+
a[1] /= k;
767+
}
768+
return k;
769+
}
770+
function d3_transformCombine(a, b, k) {
771+
a[0] += k * b[0];
772+
a[1] += k * b[1];
773+
return a;
774+
}
775+
var d3_transformDegrees = 180 / Math.PI, d3_transformIdentity = {
776+
a: 1,
777+
b: 0,
778+
c: 0,
779+
d: 1,
780+
e: 0,
781+
f: 0
782+
};
735783
d3.interpolate = function(a, b) {
736784
var i = d3.interpolators.length, f;
737785
while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
@@ -872,13 +920,22 @@
872920
gb.setAttribute("transform", b);
873921
a = ga.transform.baseVal;
874922
b = gb.transform.baseVal;
875-
var sa = [], sb = [], i = -1, n = a.numberOfItems, ta, tb, type;
876-
if (n !== b.numberOfItems) return;
923+
var sa = [], sb = [], i = -1, n = a.numberOfItems, m = b.numberOfItems, ta, tb, type;
924+
if (m !== n) {
925+
if (!m) b = d3_interpolateTransformIdentity(a); else if (!n) a = d3_interpolateTransformIdentity(b), n = m; else return;
926+
} else if (!m) return;
877927
while (++i < n) {
878928
ta = a.getItem(i);
879929
tb = b.getItem(i);
880-
if ((type = ta.type) !== tb.type || type <= 1) return;
930+
type = ta.type;
931+
if (type !== tb.type || !type) return;
881932
switch (type) {
933+
case 1:
934+
{
935+
sa.push(new d3_transform(ta.matrix));
936+
sb.push(new d3_transform(tb.matrix));
937+
continue;
938+
}
882939
case 2:
883940
{
884941
ra = ta.matrix.e + "," + ta.matrix.f;
@@ -895,7 +952,6 @@
895952
{
896953
ra = ta.angle;
897954
rb = tb.angle;
898-
break;
899955
}
900956
}
901957
sa.push(type = d3_interpolateTransformTypes[type], "(", ra, ")");
@@ -904,6 +960,17 @@
904960
return d3.interpolateString(sa.join(""), sb.join(""));
905961
})(a, b);
906962
};
963+
function d3_interpolateTransformIdentity(a) {
964+
return {
965+
getItem: function(i) {
966+
return {
967+
type: a.getItem(i).type,
968+
angle: 0,
969+
matrix: d3_transformIdentity
970+
};
971+
}
972+
};
973+
}
907974
d3.interpolateRgb = function(a, b) {
908975
a = d3.rgb(a);
909976
b = d3.rgb(b);
@@ -1990,54 +2057,6 @@
19902057
var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
19912058
setTimeout(callback, 17);
19922059
};
1993-
d3.transform = function(string) {
1994-
var g = document.createElementNS(d3.ns.prefix.svg, "g"), identity = {
1995-
a: 1,
1996-
b: 0,
1997-
c: 0,
1998-
d: 1,
1999-
e: 0,
2000-
f: 0
2001-
};
2002-
return (d3.transform = function(string) {
2003-
g.setAttribute("transform", string);
2004-
var t = g.transform.baseVal.consolidate();
2005-
return new d3_transform(t ? t.matrix : identity);
2006-
})(string);
2007-
};
2008-
function d3_transform(m) {
2009-
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)) || 0;
2010-
if (r0[0] * r1[1] < r1[0] * r0[1]) {
2011-
r0[0] *= -1;
2012-
r0[1] *= -1;
2013-
kx *= -1;
2014-
kz *= -1;
2015-
}
2016-
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
2017-
this.translate = [ m.e, m.f ];
2018-
this.scale = [ kx, ky ];
2019-
this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
2020-
}
2021-
d3_transform.prototype.toString = function() {
2022-
return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
2023-
};
2024-
function d3_transformDot(a, b) {
2025-
return a[0] * b[0] + a[1] * b[1];
2026-
}
2027-
function d3_transformNormalize(a) {
2028-
var k = Math.sqrt(d3_transformDot(a, a));
2029-
if (k) {
2030-
a[0] /= k;
2031-
a[1] /= k;
2032-
}
2033-
return k;
2034-
}
2035-
function d3_transformCombine(a, b, k) {
2036-
a[0] += k * b[0];
2037-
a[1] += k * b[1];
2038-
return a;
2039-
}
2040-
var d3_transformDegrees = 180 / Math.PI;
20412060
d3.mouse = function(container) {
20422061
return d3_mousePoint(container, d3_eventSource());
20432062
};

d3.v2.min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!DOCTYPE html>
2+
<body>
3+
<script src="../../d3.v2.js"></script>
4+
<script>
5+
var svg = d3.select("body").append("svg")
6+
.attr("width", 960)
7+
.attr("height", 500);
8+
9+
var g = svg.append("g")
10+
.attr("transform", "translate(100,100)")
11+
.append("g");
12+
13+
var rect = g.append("rect")
14+
.attr("x", -25)
15+
.attr("y", -50)
16+
.attr("width", 50)
17+
.attr("height", 100);
18+
19+
g.transition()
20+
.duration(3000)
21+
.attr("transform", "matrix(1 0 0 1 100 100)rotate(360)");
22+
</script>

examples/transform/null.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!DOCTYPE html>
2+
<body>
3+
<script src="../../d3.v2.js"></script>
4+
<script>
5+
var svg = d3.select("body").append("svg")
6+
.attr("width", 960)
7+
.attr("height", 500);
8+
9+
var g = svg.append("g")
10+
.attr("transform", "translate(100,100)")
11+
.append("g");
12+
13+
var rect = g.append("rect")
14+
.attr("x", -25)
15+
.attr("y", -50)
16+
.attr("width", 50)
17+
.attr("height", 100);
18+
19+
g.transition()
20+
.duration(3000)
21+
.attr("transform", "translate(100,100)rotate(360)");
22+
</script>

examples/transform/test-rotate.html

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,8 @@
118118
function animateExpected(d) {
119119
d3.select(this).transition()
120120
.duration(2500)
121-
.attrTween("transform", rotateTween)
121+
.attrTween("transform", function(d) { return d3.interpolateString("rotate(" + d.start + ")", "rotate(" + d.end + ")"); })
122122
.each("end", animateExpected);
123-
124-
function rotateTween(d) {
125-
return d3.interpolateString("rotate(" + d.start + ")", "rotate(" + d.end + ")");
126-
}
127123
}
128124

129125
function animateActual(d) {

src/core/interpolate.js

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ var d3_interpolateTransformTypes = [
156156
"skewY"
157157
];
158158

159+
// If both the ‘from’ and ‘to’ transforms have the same number of transform
160+
// functions and corresponding functions in each transform list are of the same
161+
// type, each transform function is animated with its corresponding destination
162+
// function in isolation using the rules described above. The individual values
163+
// are then applied as a list to produce resulting transform value.
159164
var d3_interpolateTransformSimilar = function(a, b) {
160165
var ga = document.createElementNS(d3.ns.prefix.svg, "g"),
161166
gb = document.createElementNS(d3.ns.prefix.svg, "g");
@@ -169,17 +174,49 @@ var d3_interpolateTransformSimilar = function(a, b) {
169174
sb = [],
170175
i = -1,
171176
n = a.numberOfItems,
177+
m = b.numberOfItems,
172178
ta,
173179
tb,
174180
type;
175181

176-
if (n !== b.numberOfItems) return;
182+
// If one of the ‘from’ or ‘to’ transforms is "none", the ‘none’ is replaced
183+
// by an equivalent identity function list for the corresponding transform
184+
// function list. Otherwise, if the transform function lists do not have the
185+
// same number of items, the transforms are each converted into the
186+
// equivalent matrix value and animation proceeds using the rule for a
187+
// single function above.
188+
if (m !== n) {
189+
if (!m) b = d3_interpolateTransformIdentity(a);
190+
else if (!n) a = d3_interpolateTransformIdentity(b), n = m;
191+
else return;
192+
}
193+
194+
// If both the ‘from’ and ‘to’ transforms are "none", there is no
195+
// interpolation necessary.
196+
else if (!m) return;
177197

178198
while (++i < n) {
179199
ta = a.getItem(i);
180200
tb = b.getItem(i);
181-
if ((type = ta.type) !== tb.type || type <= 1) return; // ignore unknown, matrix
201+
type = ta.type;
202+
203+
// If the transform functions are not the same type, or the type is
204+
// unknown, fallback to the decomposed transform transition.
205+
if (type !== tb.type || !type) return; // unknown
182206
switch (type) {
207+
208+
// For matrix, the matrix is decomposed using the method described by
209+
// unmatrix into separate translation, scale, rotation and skew
210+
// matrices, then each decomposed matrix is interpolated numerically,
211+
// and finally combined in order to produce a resulting 3x2 matrix.
212+
case 1: { // matrix
213+
sa.push(new d3_transform(ta.matrix));
214+
sb.push(new d3_transform(tb.matrix));
215+
continue;
216+
}
217+
218+
// For translate, scale, rotate and skew functions the individual
219+
// components of the function are interpolated numerically.
183220
case 2: { // translate
184221
ra = ta.matrix.e + "," + ta.matrix.f;
185222
rb = tb.matrix.e + "," + tb.matrix.f;
@@ -190,10 +227,9 @@ var d3_interpolateTransformSimilar = function(a, b) {
190227
rb = tb.matrix.a + "," + tb.matrix.d;
191228
break;
192229
}
193-
default: { // rotate, skewX, skewY
230+
default: { // rotate, skew
194231
ra = ta.angle;
195232
rb = tb.angle;
196-
break;
197233
}
198234
}
199235
sa.push(type = d3_interpolateTransformTypes[type], "(", ra, ")");
@@ -204,6 +240,18 @@ var d3_interpolateTransformSimilar = function(a, b) {
204240
})(a, b);
205241
};
206242

243+
function d3_interpolateTransformIdentity(a) {
244+
return {
245+
getItem: function(i) {
246+
return {
247+
type: a.getItem(i).type,
248+
angle: 0,
249+
matrix: d3_transformIdentity
250+
};
251+
}
252+
};
253+
}
254+
207255
d3.interpolateRgb = function(a, b) {
208256
a = d3.rgb(a);
209257
b = d3.rgb(b);

src/core/transform.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
d3.transform = function(string) {
2-
var g = document.createElementNS(d3.ns.prefix.svg, "g"),
3-
identity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
2+
var g = document.createElementNS(d3.ns.prefix.svg, "g");
43
return (d3.transform = function(string) {
54
g.setAttribute("transform", string);
65
var t = g.transform.baseVal.consolidate();
7-
return new d3_transform(t ? t.matrix : identity);
6+
return new d3_transform(t ? t.matrix : d3_transformIdentity);
87
})(string);
98
};
109

@@ -57,4 +56,5 @@ function d3_transformCombine(a, b, k) {
5756
return a;
5857
}
5958

60-
var d3_transformDegrees = 180 / Math.PI;
59+
var d3_transformDegrees = 180 / Math.PI,
60+
d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};

0 commit comments

Comments
 (0)