JoeBe
JoeBe

Reputation: 1290

How to create a conditional ease?

I have a d3.selectAll().each() function that animates each of the paths in my svg container. Now I would like that the first path has a d3.easePolyIn animation whereas the rest has a d3.easeLinear animation.

However, my following code does not work (no animation happens at all):

d3.selectAll(".myPaths").each(function(d,i) {

    d3.select(this)
        .attr("stroke-dasharray", d3.select(this).node().getTotalLength() + " " +  d3.select(this).node().getTotalLength())
        .attr("stroke-dashoffset", d3.select(this).node().getTotalLength())
        .transition()
            .duration(d3.select(this).node().getTotalLength())
            .ease(function(d) {if (i == 0) {return d3.easePolyIn} else {return d3.easeLinear}})
            .attr("stroke-dashoffset", 0)
})

How can I achieve my goal?

Upvotes: 1

Views: 64

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102219

Since you already have the index i from the outer function (selection.each), just use it in the ease method directly:

.ease(i ? d3.easeLinear : d3.easePolyIn)

Here, the ternary returns d3.easeLinear for all truthy values of i (that is, all indices except 0), and d3.easePolyIn for the falsy value (the first index, 0).

Here is a demo:

const svg = d3.select("svg")
const circles = svg.selectAll(null)
  .data([1, 1])
  .enter()
  .append("circle")
  .attr("r", 15)
  .attr("cx", 15)
  .attr("cy", (_, i) => i ? 100 : 50)
  .each(function(_, i) {
    d3.select(this)
      .transition()
      .ease(i ? d3.easeLinear : d3.easePolyIn)
      .duration(1000)
      .attr("cx", 280)
  });
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

The problem with your attempt is that transition.ease expects a function itself. So, when you just return d3.easeLinear or d3.easePolyIn, that's not going to work. For using your approach, you have to pass the normalised time, idiomatically named t:

.ease(function(t) {
    if (i == 0) {
        return d3.easePolyIn(t)
    } else {
        return d3.easeLinear(t)
    }
})

And here is the corresponding demo:

const svg = d3.select("svg")
const circles = svg.selectAll(null)
  .data([1, 1])
  .enter()
  .append("circle")
  .attr("r", 15)
  .attr("cx", 15)
  .attr("cy", (_, i) => i ? 100 : 50)
  .each(function(_, i) {
    d3.select(this)
      .transition()
      .ease(function(t) {
        if (i == 0) {
          return d3.easePolyIn(t)
        } else {
          return d3.easeLinear(t)
        }
      })
      .duration(1000)
      .attr("cx", 280)
  });
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

Upvotes: 1

Related Questions