Passing a function to .attr('d')?

て烟熏妆下的殇ゞ 提交于 2020-01-24 21:56:12

问题


I am attempting to use two different area generators inside one .data() selection, so that one set of points can have an area rendered from top to bottom while the second set's area can be rendered from left to right. I can pass fat arrow functions to every .attr() except 'd', which produces the following error:

Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "function area(da…".

I need to access the selection index in order to set the area from an array of booleans. Please see the jsfiddle I've set up with the relevant code. I've commented two of my attempts to pass a function to the .attr('d').


回答1:


if you inspect your generated code, you'll see this:

So, you are not geting values. Instead call the function.

Add (d) to the return value so that the area generator function is executed:

  .attr('d', function(d, i){
    if (horizontalNotVertical[i]) {
        return horizontalArea(d);
    } else {
        return verticalArea(d);
    }
  })



回答2:


The issue in your code is simply the famous first argument in D3.

Your comment:

I was wondering why D3 executes the area generator automatically if it's passed by itself (.attr('d', myArea)) but doesn't automatically execute if the area generator is returned by an anonymous function...

Is not correct. D3 has no problems executing functions returned by functions.

When you do...

.attr('d', myArea)

... the datum is automatically passed as the first argument to myArea. Let's see a basic demo:

var data = ["foo", "bar", "baz"];
var sel = d3.select("body").selectAll(null)
  .data(data)
  .enter()
  .append("whatever")

sel.attr("whatever", callback)

function callback(d) {
  console.log("The datum is " + d)
}
<script src="https://d3js.org/d3.v5.min.js"></script>

So, if you want to put your myArea function inside an anonymous function, you have to specify the first argument, because the datum is passed to the outer function, not to myArea:

.attr('d', function(d){
//1st arg here------^
    myArea(d);
//and here-^
});

Let's see it:

var data = ["foo", "bar", "baz"];
var sel = d3.select("body").selectAll(null)
  .data(data)
  .enter()
  .append("whatever")

sel.attr("whatever", function(d) {
  callback(d);
})

function callback(d) {
  console.log("The datum is " + d)
}
<script src="https://d3js.org/d3.v5.min.js"></script>

Therefore, in your case, you just need:

.attr('d', (d, i) => (horizontalNotVertical[i]) ? horizontalArea(d) : verticalArea(d));

Just to show that D3 has no problems executing a function returned by another function, have a look at this last snippet:

var data = ["foo", "bar", "baz"];
var sel = d3.select("body").selectAll(null)
  .data(data)
  .enter()
  .append("whatever")

sel.attr("whatever", function() {
  callback();
})

function callback() {
  console.log("I don't have the datum!")
}
<script src="https://d3js.org/d3.v5.min.js"></script>

Here is the updated jsfiddle: https://jsfiddle.net/zt5vxbm6/



来源:https://stackoverflow.com/questions/49520535/passing-a-function-to-attrd

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!