simple question on .call(function)

5,840 views
Skip to first unread message

Devang Mundhra

unread,
May 18, 2011, 3:27:26 AM5/18/11
to d3...@googlegroups.com
Hi,

I am trying to implement word wrap for svg text (since it seems it is not supported by default).

I want to call a function from svg text element itself. However, it seems the environment is not being saved when I use the .call operator.

In the example (http://bl.ocks.org/978123) for which I am using .call(aFunction), I should have got an alert of d.data.key variables for all the nodes. Instead, I get it as "undefined".

Simply put, I have


function aFunction(d,i) {
alert(d.data.key);
}
and a corresponding

cell.append("svg:text")
      .attr("x", function(d) { return d.dx / 2; })
      .attr("y", function(d) { return d.dy / 2; })
      .attr("dy", ".35em")
      .attr("text-anchor", "middle")
      .text(function(d) { return d.children ? null : d.data.key; })
.call(aFunction);
How should I call aFunction such that all the d.<> variables are also saved/passed.

Thanks,
Devang

PS: When the code works fine, you might want to remove the alert(d.data.key) or its a long way in getting rid of it!

Mike Bostock

unread,
May 18, 2011, 10:51:27 AM5/18/11
to d3...@googlegroups.com
You want to use `each` rather than `call`.

The `each` operator is the generic operator. It doesn't do anything by
default except call your function with the same arguments as other
operators. So, your `aFunction` will get called for each non-null
element in your selection, being passed the data `d` and index `i`.
The `this` context of your function will be the selected element (an
SVGTextElement).

The `call` operator is a way of grouping your code into reusable
blocks, in the same fashion as you calling a function yourself,
passing in the selection. The only difference is that you can use the
`call` operator with method chaining. Say for example I want to have a
reusable block of code which sets the "x" and "y" attributes:

function center(selection) {
selection


.attr("x", function(d) { return d.dx / 2; })
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")

.attr("text-anchor", "middle");
}

You can now call this function, passing in your selection:

cell.append("svg:text")
.call(center);

You can even pass in additional arguments to the `call` function (such
as `call(center, .5)`). And, you can use `call` with transitions as
well, which can be very convenient if you need to set a bunch of
attributes or styles on both selections and transitions.

Mike

Matthew Smillie

unread,
May 18, 2011, 11:14:21 AM5/18/11
to d3-js

I think you're just mixing up call(), which calls the function once
for the whole selection, with each(), which calls the function for
each element of the selection. They're described briefly in the docs:
http://mbostock.github.com/d3/api/

FWIW, the result using call is correct: the selection does have
a .data property (the data() function), but there is no .key property
on that, so d.data.key is undefined.

regards,
matt.

PS: console.log is a lot more useful for debugging, mostly because you
don't need to dismiss it. In the Chrome dev tools, it even gives you
an inline object inspector, which is very handy if you're being passed
something you don't expect. For example:

function aFunc(d, i) {
console.log(d, i)
}

With that you would have seen immediately that call() was passing the
entire selection to aFunc, and nothing in the 'i' param.

Matthew Smillie

unread,
May 18, 2011, 1:10:49 PM5/18/11
to d3-js
Sorry for doubling up - was on the move & neglected to hit 'refresh'
before posting.

Devang Mundhra

unread,
May 19, 2011, 12:41:24 AM5/19/11
to d3...@googlegroups.com
Mike, Matthew -

Thanks a lot for the detailed explanation and tips.

Regards,
Devang

Devang Mundhra

unread,
May 19, 2011, 12:51:12 AM5/19/11
to d3...@googlegroups.com
..and thanks for pointing me to the updated api documentation. Didn't realize there was new documentation on the website!
this is very helpful.

Cheers,
Devang
Reply all
Reply to author
Forward
0 new messages