From b2230df1d4d15501828e9b2ffce1356352f58c30 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Tue, 23 Feb 2016 08:50:32 -0800 Subject: [PATCH] Fix #37 - synchronous evaluation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can’t wait until the tweens are initialized in transition.{attr,style,text}; we must compute the target value synchronously. The resulting value is stored in a map on the transition schedule so that tweens can still be efficiently copied on write and shared across instances. --- src/transition/attr.js | 22 +++++++++++----------- src/transition/style.js | 12 ++++++------ src/transition/text.js | 15 ++++++++------- src/transition/tween.js | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/transition/attr.js b/src/transition/attr.js index 317a947..5d0d526 100644 --- a/src/transition/attr.js +++ b/src/transition/attr.js @@ -1,5 +1,6 @@ import {interpolate, interpolateTransform} from "d3-interpolate"; import {namespace, namespaces} from "d3-selection"; +import {tweenValue} from "./tween"; // TODO Assumes either ALL selected nodes are SVG, or none are. function attrInterpolate(node, name) { @@ -23,7 +24,7 @@ function attrRemoveNS(fullname) { function attrConstant(name, value1) { var value00, interpolate0; - return value1 += "", function() { + return function() { var value0 = this.getAttribute(name); return value0 === value1 ? null : value0 === value00 ? interpolate0 @@ -34,7 +35,7 @@ function attrConstant(name, value1) { function attrConstantNS(fullname, value1) { var value00, interpolate0; - return value1 += "", function() { + return function() { var value0 = this.getAttributeNS(fullname.space, fullname.local); return value0 === value1 ? null : value0 === value00 ? interpolate0 @@ -47,10 +48,9 @@ function attrFunction(name, value) { value10, interpolate0; return function() { - var value0, - value1 = value.apply(this, arguments); + var value0, value1 = value(this); if (value1 == null) return void this.removeAttribute(name); - value0 = this.getAttribute(name), value1 += ""; + value0 = this.getAttribute(name); return value0 === value1 ? null : value0 === value00 && value1 === value10 ? interpolate0 : interpolate0 = attrInterpolate(this, name)(value00 = value0, value10 = value1); @@ -62,9 +62,9 @@ function attrFunctionNS(fullname, value) { value10, interpolate0; return function() { - var value0, value1 = value.apply(this, arguments); + var value0, value1 = value(this); if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local); - value0 = this.getAttributeNS(fullname.space, fullname.local), value1 += ""; + value0 = this.getAttributeNS(fullname.space, fullname.local); return value0 === value1 ? null : value0 === value00 && value1 === value10 ? interpolate0 : interpolate0 = interpolate(value00 = value0, value10 = value1); @@ -73,8 +73,8 @@ function attrFunctionNS(fullname, value) { export default function(name, value) { var fullname = namespace(name); - return this.attrTween(name, (value == null - ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function" - ? (fullname.local ? attrFunctionNS : attrFunction) - : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value)); + return this.attrTween(name, typeof value === "function" + ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, tweenValue(this, "attr." + name, value)) + : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) + : (fullname.local ? attrConstantNS : attrConstant)(fullname, value + "")); } diff --git a/src/transition/style.js b/src/transition/style.js index 3b247e9..38e66ab 100644 --- a/src/transition/style.js +++ b/src/transition/style.js @@ -1,5 +1,6 @@ import {interpolate} from "d3-interpolate"; import {window} from "d3-selection"; +import {tweenValue} from "./tween"; function styleRemove(name) { var value00, @@ -24,7 +25,7 @@ function styleRemoveEnd(name) { function styleConstant(name, value1) { var value00, interpolate0; - return value1 += "", function() { + return function() { var value0 = window(this).getComputedStyle(this, null).getPropertyValue(name); return value0 === value1 ? null : value0 === value00 ? interpolate0 @@ -39,9 +40,8 @@ function styleFunction(name, value) { return function() { var style = window(this).getComputedStyle(this, null), value0 = style.getPropertyValue(name), - value1 = value.apply(this, arguments); + value1 = value(this); if (value1 == null) value1 = (this.style.removeProperty(name), style.getPropertyValue(name)); - else value1 += ""; return value0 === value1 ? null : value0 === value00 && value1 === value10 ? interpolate0 : interpolate0 = interpolate(value00 = value0, value10 = value1); @@ -52,7 +52,7 @@ export default function(name, value, priority) { return value == null ? this .styleTween(name, styleRemove(name)) .on("end.style." + name, styleRemoveEnd(name)) - : this.styleTween(name, (typeof value === "function" - ? styleFunction - : styleConstant)(name, value), priority); + : this.styleTween(name, typeof value === "function" + ? styleFunction(name, tweenValue(this, "style." + name, value)) + : styleConstant(name, value + ""), priority); } diff --git a/src/transition/text.js b/src/transition/text.js index 2f79a2b..4777252 100644 --- a/src/transition/text.js +++ b/src/transition/text.js @@ -1,19 +1,20 @@ +import {tweenValue} from "./tween"; + function textConstant(value) { - return value = value == null ? "" : value + "", function() { + return function() { this.textContent = value; }; } function textFunction(value) { return function() { - var v = value.apply(this, arguments); - if (v == null) v = ""; - this.textContent = v; + var value1 = value(this); + this.textContent = value1 == null ? "" : value1; }; } export default function(value) { - return this.tween("text", (typeof value === "function" - ? textFunction - : textConstant)(value)); + return this.tween("text", typeof value === "function" + ? textFunction(tweenValue(this, "text", value)) + : textConstant(value == null ? "" : value + "")); } diff --git a/src/transition/tween.js b/src/transition/tween.js index 9f8f1e8..a25cc8a 100644 --- a/src/transition/tween.js +++ b/src/transition/tween.js @@ -43,3 +43,17 @@ export default function(name, value) { if (typeof value !== "function") throw new Error; return this.each(tweenFunction(key, id, name, value)); } + +export function tweenValue(transition, name, value) { + var key = transition._key, + id = transition._id; + + transition.each(function() { + var schedule = set(this, key, id), v = value.apply(this, arguments); + (schedule.values || (schedule.values = {}))[name] = v == null ? null : v + ""; + }); + + return function(node) { + return get(node, key, id).values[name]; + }; +}