rguttersohn
rguttersohn

Reputation: 484

How do I resolve undefined errors when using d3.select(this) in a Vue methods hook?

I am porting some d3 graphs from another project over to a personal Vue-based project. Everything is working as expected except for attempting to center labels in the arcs of a pie chart using the arc.centroid(d) method. I keep getting two errors, which I'll explain below.

I have both my arc function and pie function in the computed hook.

My function for the labels, below, is in my methods hook:

pieLabel(width, height, margin) {
      d3.select(".pie-chart-wrapper svg")
        .append("g")
        .attr("class", "pie-chart-labels")
        .attr(
          "transform",
          `translate(${width / 2 + margin},${height / 2 + margin})`
        )
        .selectAll("text")
        .data(this.pie)
        .enter()
        .append("text")
        .style("fill", "black")
        .attr("text-anchor", "middle")
        .text(d => `${d3.format(",")(d.value)}`)
        .each(d => {
          const center = this.arc.centroid(d);

          d3.select(this)
            .attr("x", center[0])
            .attr("y", center[1]);
        });
    }

The errors I keep getting are this.arc is undefined and this.setAttribute is not a function.

How do I resolve these errors?

After moving some things around, I was able to get the error for this.arc to go away. I then logged 'this' and it returned a bunch of Vue prototypes, which leads me to believe that Vue thinks I am trying to reference a Vue element that isn't there and is thus causing the error.

Anyhow, I returned the code back to how it was when it was working outside of Vue but returning the two errors when inside the Vue hook.

This is not for a specific project. I am just trying to gain an understanding for how Vue and d3.js work together.

Upvotes: 0

Views: 784

Answers (1)

Ruben Helsloot
Ruben Helsloot

Reputation: 13129

What you're running into is the this scoping of arrow functions. In short: they use this from the outer scope, not their internal one. By contrast, the following should work:

        .each(function(d) {
          const center = this.arc.centroid(d);

          d3.select(this)
            .attr("x", center[0])
            .attr("y", center[1]);
        });

because now, this points to the text node, not the the Vue scope.

Upvotes: 1

Related Questions