# Dealing with circular definitions when zoom and pan are calling each other

**URL:** <https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194>\
**Category:** Help\
**Created:** [October 25, 2022, 10:25pm UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194 "2022-10-25T22:25:17Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![AbreezaSaleem](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/abreezasaleem/32/7084_2.png) [@AbreezaSaleem](https://talk.observablehq.com/u/AbreezaSaleem)\
**Post date:** [October 25, 2022, 10:25pm UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194/1 "2022-10-25T22:25:17Z")

</div>

I am following [this](https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172) example to recreate a zoomable bar chart in Javascript and it worked perfectly. I decided to add my graph to Observable but (unsurprisingly) it is not working in the Observable runtime environment. In the link I’ve shared it does say that we can’t copy-paste vanilla Javascript code into Observable and they have shared an example of how this should be rewritten in Observable but I am unable to understand it. Here is the new code: [Focus + Context / D3 / Observable](https://observablehq.com/@d3/focus-context).

Can anybody explain to me how they’re handling zoom-\>brush and brush-\>zoom events here? Any pointers will be appreciated! Thank you.

---

<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:** [October 26, 2022, 5:44am UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194/2 "2022-10-26T05:44:43Z")

</div>

Hi @AbreezaSaleem! Let’s go through those cells in order of data flow:

**1a. `chart`:**  
This cell produces a DOM element (the chart SVG), but also “sneakily” attaches an `.update()` method to it:

```javascript
  // ...
  return Object.assign(svg.node(), {
    update(focusX, focusY) {
      gx.call(xAxis, focusX, height);
      gy.call(yAxis, focusY, data.y);
      path.attr("d", area(focusX, focusY));
    }
  });

```

We can call `chart.update(fromDate, toDate)` from another cell to have the chart change its visible range. (As an aside, I think that `focusX` and `focusY` are legacy names from another implementation.)

**1b. `viewof focus`:**  
This cell is a `view`, a special Observable construct. Think of it as a custom form element with a `value` property that reflects its user input. When you brush, this value property is set to the selected range:

```javascript
  // ...
  function brushed({selection}) {
    if (selection) {
      svg.property("value", selection.map(x.invert, x).map(d3.utcDay.round));
      svg.dispatch("input");
    }
  }

```

Other cells can reference this value directly as `focus` (instead of `viewof focus`).

**2. `update`:**  
This cell ties the previous two together. Whenever we get a new value for `focus`, Observable will automatically rerun this cell. The important line here is this one:

```javascript
  // ...
  chart.update(x.copy().domain(focus), y.copy().domain([0, maxY]));

```

> [@AbreezaSaleem](#):
>
> Can anybody explain to me how they’re handling zoom-\>brush and brush-\>zoom events here?

Sadly, as per @Fil’s [comment](https://observablehq.com/@d3/focus-context#comment-2b6d37402102b4ce), this example does not yet seem to implement zoom.

To make it work for Observable, we’d likely implement chart as a viewof, too, and ensure that its value can be set from outside. We can then bind both `viewof focus` and `viewof chart` together so that they update each other: [Synchronized Inputs / Observable | Observable](https://observablehq.com/@observablehq/synchronized-inputs)

---

<div class="post-metadata">

**Author:** ![AbreezaSaleem](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/abreezasaleem/32/7084_2.png) [@AbreezaSaleem](https://talk.observablehq.com/u/AbreezaSaleem)\
**Post date:** [October 31, 2022, 7:44pm UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194/3 "2022-10-31T19:44:56Z")

</div>

Thank you for the prompt detailed response! I initially made my graph using vanilla Javascript and now I see I have quite a lot to learn about Observable as well. I will further look into the chart as a viewof approach. Thanks agian

---

<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:** [December 21, 2022, 6:05pm UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194/4 "2022-12-21T18:05:01Z")

</div>

We have just published an extension of this notebook: [Focus + context II / D3 | Observable](https://observablehq.com/@d3/focus-context/2)  
in which we use d3.dispatch to implement communication between the different cells.

Sorry for the belated answer; I hope this is still useful.

---

<div class="post-metadata">

**Author:** ![AbreezaSaleem](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/abreezasaleem/32/7084_2.png) [@AbreezaSaleem](https://talk.observablehq.com/u/AbreezaSaleem)\
**Post date:** [June 25, 2023, 3:48pm UTC](https://talk.observablehq.com/t/dealing-with-circular-definitions-when-zoom-and-pan-are-calling-each-other/7194/5 "2023-06-25T15:48:12Z")

</div>

Thank you for your answer! It was exactly what I needed. I got caught up in other things since I posted my question but I finally got back to this notebook and I’m very happy to report that I’ve successfully made it work using [d3.dispatch](https://github.com/d3/d3-dispatch). 🙂

Here’s a link to my notebook if you’d like to take a look: [D3 Scatterplot / Abreeza Saleem | Observable](https://observablehq.com/d/ed19f6d94f1eb95f)
