Skip to content

Commit

Permalink
Use inline style value, if present.
Browse files Browse the repository at this point in the history
Rather than always returning the computed style value, selection.style now
favors the inline value, if present, and only falls back to the computed value
if an inline value is not present.

By not computing the style value in the common case where an inline style is
present, this is faster, but more importantly it is more predictable, since a
computed value can be surprisingly different from an inline value, such as when
the inline value is specified as a percentage.

This change is especially useful for transition.style, d3/d3-transition#47, so
that you can control the starting style value of a transition.
  • Loading branch information
mbostock committed May 15, 2017
1 parent 00b904b commit e7c72a6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ var div = selection.selectAll(d3.selectorAll("div"));

Returns the owner window for the specified *node*. If *node* is a node, returns the owner document’s default view; if *node* is a document, returns its default view; otherwise returns the *node*.

<a name="style" href="#style">#</a> d3.<b>style</b>(<i>node</i>, <i>name</i>) [<>](https://github.com/d3/d3-selection/blob/master/src/selection/style.js#L32 "Source")

Returns the value of the style property with the specified *name* for the specified *node*. If the *node* has an inline style with the specified *name*, its value is returned; otherwise, the [computed property value](https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value) is returned. See also [*selection*.style](#selection_style).

### Modifying Elements

After selecting elements, use the selection’s transformation methods to affect document content. For example, to set the name attribute and color style of an anchor element:
Expand Down Expand Up @@ -292,7 +296,7 @@ If a *value* is not specified, returns true if and only if the first (non-null)

If a *value* is specified, sets the style property with the specified *name* to the specified value on the selected elements and returns this selection. If the *value* is a constant, then all elements are given the same style property value; otherwise, if the *value* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element (*nodes*[*i*]). The function’s return value is then used to set each element’s style property. A null value will remove the style property. An optional *priority* may also be specified, either as null or the string `important` (without the exclamation point).

If a *value* is not specified, returns the current computed value of the specified style property for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element. The computed value **may be different than the previously-set value**, particularly if it was set using a shorthand property (such as the `font` style, which is shorthand for `font-size`, `font-face`, etc.).
If a *value* is not specified, returns the current value of the specified style property for the first (non-null) element in the selection. The current value is defined as the element’s inline value, if present, and otherwise its [computed value](https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value). Accessing the current style value is generally useful only if you know the selection contains exactly one element.

Caution: unlike many SVG attributes, CSS styles typically have associated units. For example, `3px` is a valid stroke-width property value, while `3` is not. Some browsers implicitly assign the `px` (pixel) unit to numeric values, but not all browsers do: IE, for example, throws an “invalid arguments” error!

Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {default as selectAll} from "./src/selectAll";
export {default as selection} from "./src/selection/index";
export {default as selector} from "./src/selector";
export {default as selectorAll} from "./src/selectorAll";
export {styleValue as style} from "./src/selection/style";
export {default as touch} from "./src/touch";
export {default as touches} from "./src/touches";
export {default as window} from "./src/window";
Expand Down
10 changes: 6 additions & 4 deletions src/selection/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ function styleFunction(name, value, priority) {
}

export default function(name, value, priority) {
var node;
return arguments.length > 1
? this.each((value == null
? styleRemove : typeof value === "function"
? styleFunction
: styleConstant)(name, value, priority == null ? "" : priority))
: defaultView(node = this.node())
.getComputedStyle(node, null)
.getPropertyValue(name);
: styleValue(this.node(), name);
}

export function styleValue(node, name) {
return node.style.getPropertyValue(name)
|| defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
}
24 changes: 22 additions & 2 deletions test/selection/style-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@ var tape = require("tape"),
jsdom = require("../jsdom"),
d3 = require("../../");

tape("selection.style(name) returns the computed value of the style property with the specified name on the first selected element", function(test) {
tape("d3.style(node, name) returns the inline value of the style property with the specified name on the first selected element, if present", function(test) {
var node = {style: {getPropertyValue: function(name) { return name === "color" ? "red" : ""}}};
test.equal(d3.style(node, "color"), "red");
test.end();
});

tape("d3.style(node, name) returns the computed value of the style property with the specified name on the first selected element, if there is no inline style", function(test) {
var style = {getPropertyValue: function(name) { return name === "color" ? "rgb(255, 0, 0)" : ""}},
node = {style: {getPropertyValue: function() { return ""; }}, ownerDocument: {defaultView: {getComputedStyle: function(n) { return n === node ? style : null; }}}};
test.equal(d3.style(node, "color"), "rgb(255, 0, 0)");
test.end();
});

tape("selection.style(name) returns the inline value of the style property with the specified name on the first selected element, if present", function(test) {
var node = {style: {getPropertyValue: function(name) { return name === "color" ? "red" : ""}}};
test.equal(d3.select(node).style("color"), "red");
test.equal(d3.selectAll([null, node]).style("color"), "red");
test.end();
});

tape("selection.style(name) returns the computed value of the style property with the specified name on the first selected element, if there is no inline style", function(test) {
var style = {getPropertyValue: function(name) { return name === "color" ? "rgb(255, 0, 0)" : ""}},
node = {ownerDocument: {defaultView: {getComputedStyle: function(n) { return n === node ? style : null; }}}};
node = {style: {getPropertyValue: function() { return ""; }}, ownerDocument: {defaultView: {getComputedStyle: function(n) { return n === node ? style : null; }}}};
test.equal(d3.select(node).style("color"), "rgb(255, 0, 0)");
test.equal(d3.selectAll([null, node]).style("color"), "rgb(255, 0, 0)");
test.end();
Expand Down

0 comments on commit e7c72a6

Please sign in to comment.