Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferred vs. immediate transforms. #13

Closed
mbostock opened this issue Oct 22, 2010 · 1 comment
Closed

Deferred vs. immediate transforms. #13

mbostock opened this issue Oct 22, 2010 · 1 comment

Comments

@mbostock
Copy link
Member

Currently, d3 works purely in a "deferred" mode, where you define a transform and then apply it. Nothing gets done until the transform is applied. For example:

d3.selectAll("p").style("color", "red").apply();

One of the gotchas with this approach is that it's easy to forget to apply the transform. The following looks like it should do something, but has no effect:

d3.selectAll("p").style("color", "red");

Another gotcha is that when you apply a transform, you can (currently) only apply the root transform, since that's the only thing that makes sense from a global context. So, if you define a complicated sequence of nested-scope transforms, it only makes sense to apply the transform from the root...

var t0 = d3.select("body");
var t1 = t0.selectAll(...)...
var t2 = t0.select(...).selectAll(...)...
t0.apply();

Calling t1.apply() or t2.apply() currently has the same effect, but looks confusing! The reason we allow calling apply on a nested scope transform is that it avoids the need to pop back to the root transform. For example, this works:

d3.select("body")
    .style("background", "red")
  .selectAll("p")
    .style("color", "green")
    .apply();

The alternative would be something like this:

d3.select("body")
    .style("background", "red")
  .selectAll("p")
    .style("color", "green")
    .pop // and potentially more .pop.pop
    .apply();

Or like this:

d3.select("body")
    .style("background", "red")
  .selectAll("p")
    .style("color", "green")
    .root
    .apply();

Anyway, I feel like being able to call apply on a scoped transform and have it automagically perform the root transform is likely more confusing than its worth. On the other hand, it might be nice to take an arbitrary transform and apply it to a specific scope. And I suppose that scope could default to the single-element node list [document].

So, in addition to the semantics of apply, there's also the question of whether we should provide an immediate-mode form of transforms, where the actions are executed immediately as they are defined. With this approach, you might create a deferred transform explicitly:

var tx = d3.transform();

tx.select("body")
    .style("background", "red")
  .selectAll("p")
    .style("color", "green");

tx.apply();

It's a little bit more verbose for the deferred mode, but it does make things a bit more explicit. And it makes the immediate mode less verbose, since you can omit the apply:

d3.selectAll("p").style("color", "red");

Although, I also think you might want to specify a context in this case, such as:

d3([input]).style("color", "red");

Or possibly:

d3.select(input).style("color", "red");

(This would allow d3.selectAll to take an array, whilst d3.select would only take a single argument.)

This might would have the same effect as saying:

d3.transform().style("color", "red").apply([input]);
@mbostock
Copy link
Member Author

Oh, before I forget. I'm not sure it's possible for all actions to be supported in immediate-mode, which is an argument for not supporting it. (In addition to the parsimony argument.) Transitions, for example, presumably won't work. Although, it seems like in the case of transitions you don't need to perform the transition action immediately anyway, so it's fine to defer it. So maybe immediate-mode is okay.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant