# Stagger issue

**URL:** https://talk.observablehq.com/t/stagger-issue/8147
**Category:** Help
**Created:** [August 2, 2023, 4:17pm UTC](https://talk.observablehq.com/t/stagger-issue/8147 "2023-08-02T16:17:51Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [August 2, 2023, 4:17pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/1 "2023-08-02T16:17:51Z")

</div>

I am trying to see if I can replicate CSS stager animation in d3. This is what I [tried](https://observablehq.com/d/3ce84934637b19d1).

The motion for blue and green circles was done through respectively CSS and d3. I was hoping to achieve the same animation for green circles as the blue ones. But they are not the same.

To make sure it is not due to easing, I have provided the exact same easing values in css as in d3. [d3.easeSinOut= cubic-bezier(0.37, 0, 0.63, 1)](https://easings.net/#easeInOutSine)

How can I achieve the exact same stagger motion in d3 as it is currently in d3.

My end goal is to use d3 for this motion and not CSS.

Thank you in advance.

@Fil

---

<div class="post-metadata">

### Author: ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)
#### Post date: [August 2, 2023, 4:48pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/2 "2023-08-02T16:48:25Z")

</div>

I don’t know… maybe a tiny bit of time is lost at the end of each loop?

---

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [August 2, 2023, 4:58pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/3 "2023-08-02T16:58:24Z")

</div>

Is there a way to fix it?

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [August 2, 2023, 5:26pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/4 "2023-08-02T17:26:33Z")

</div>

You’ll probably want to use a single transition for all elements and only change their easing offset?

---

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [August 2, 2023, 5:42pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/5 "2023-08-02T17:42:30Z")

</div>

@mootari can you please show what you are suggesting?

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [August 2, 2023, 5:50pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/6 "2023-08-02T17:50:54Z")

</div>

I don’t have the bandwidth right now, but the idea is that you animate all elements via the same transition instead of starting a separate one in .each(). If you specify a custom easing you can then offset `t` based on the element index, e.g. `(t + i / 3) % 1`.

---

<div class="post-metadata">

### Author: ![mcmcclur](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mcmcclur/32/2364_2.png) [@mcmcclur](https://talk.observablehq.com/u/mcmcclur)
#### Post date: [August 3, 2023, 3:25am UTC](https://talk.observablehq.com/t/stagger-issue/8147/7 "2023-08-03T03:25:21Z")

</div>

In seems very odd to me to attempt to generate this animation as an infinite sequence of transitions when it’s very easy to describe the motions exactly as three sinusoids that happen to be slightly out of phase. More generally, CSS is _not_ a programming language and I think it’s a mistake to try reproduce animations produced by CSS by emulating the code that you see there.

I would generate this motion using something like the techniques in [this notebook](https://observablehq.com/d/38108a6de6e969a4). The key step is to describe the displacement of the i^{\text{th}} particle as

```
-Math.cos((t - T0 - 100 * i) / 400)

```

where `t` is the current time, `T0` is the starting time, and `i` is the index of the particle. If you want to sync this with some other animation, of course, you’ll need to tweek the parameters.

Here it is in action:

https://observablehq.com/embed/38108a6de6e969a4@142?cells=viewof+run%2Canim

---

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [August 3, 2023, 12:51pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/8 "2023-08-03T12:51:43Z")

</div>

@mcmcclur many thanks for this. One follow up Q; in order for me to apply this in the prod item, I need to be generating the parameters programmatically. Hence, the question- how are you coming up with 100 and 400 in the following expression?

`-Math.cos((t - T0 - 100 * i) / 400)`

---

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [August 3, 2023, 12:53pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/9 "2023-08-03T12:53:16Z")

</div>

@mootari sounds like an interesting approach; however, I could not make that work. Whenever you have time and get a chance, if you can please demonstrate the idea you are proposing would be great.

Thanks again.

---

<div class="post-metadata">

### Author: ![mcmcclur](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mcmcclur/32/2364_2.png) [@mcmcclur](https://talk.observablehq.com/u/mcmcclur)
#### Post date: [August 3, 2023, 2:35pm UTC](https://talk.observablehq.com/t/stagger-issue/8147/10 "2023-08-03T14:35:23Z")

</div>

> [@smpa01](#):
>
> how are you coming up with 100 and 400 in the following expression?
> 
> `-Math.cos((t - T0 - 100 * i) / 400)`

I’m guessing you know that in an expression involving time T like

-\cos(\omega T - \varphi)

that \varphi controls the phase and that \omega controls the frequency, which the reciprocal of the period. In the formula you refer to,

- T = t-T\_0,
- \omega = 1/400 and
- \varphi = i/4.

These are really just parameters to speed up/slow down or shift the motion. I didn’t do anything technical to compute those values; I just fiddled with them until the animation looked something like what you want. I suppose it might be worth mentioning that, if we take

\omega = 2\pi/1000,

then the frequency should be 1s. That is, we should observe one complete back and forth motion every second.

If you can obtain whatever frequency and phase arises from the process you’re modelling, you should be able to fit the motion.

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [August 4, 2023, 11:13am UTC](https://talk.observablehq.com/t/stagger-issue/8147/11 "2023-08-04T11:13:37Z")

</div>

> [@smpa01](#):
>
> Whenever you have time and get a chance, if you can please demonstrate the idea you are proposing would be great.

Here is a working example:

```js
  const d3Circle = d3Grp
    .selectAll("circle")
    .data(rangeOne)
    .join("circle")
    .attr("cx", (d, i) => 100 + 30 * i)
    .attr("r", 10)
    .attr("fill", "green");

  const animate = selection => {
    selection
      .transition()
      .duration(2000)
      .ease(t => t) // linear
      .attrTween("cy", (d, i, arr) => {
        const offset = .15 * i / arr.length;
        const easeTri = t => t < .5 ? t * 2 : 2 - t * 2;
        return t => 50 + 600 * d3.easeQuadInOut(easeTri((offset + t) % 1));
      })
      .on("end", () => animate(selection));
  };
  animate(d3Circle);

```
