Redraw when anything changes

Keep your custom viz current through every filter change, parameter move, data refresh, and window resize — with one event and one idempotent function.

intermediate6 min1 step

Why it matters

A native bar chart redraws itself when a filter changes; yours has to be told. The telling is one subscription: SummaryDataChanged fires whenever the data feeding your worksheet changes — filters, parameters, refreshes — and because it collapses every cause into one signal, your handler is just draw() again. Resize is the second, sneakier trigger: the author drags the window, your canvas changes size, and no Tableau event fires — that one belongs to the browser. Handle both and your extension is indistinguishable from a built-in mark type; miss one and it is a screenshot that lies.

Prompt Recipe

Extend my Tableau viz extension so it stays current: after initializeAsync, call draw(worksheet) once, subscribe worksheet.addEventListener(tableau.TableauEventType.SummaryDataChanged, ...) to call draw again whenever filters, parameters, or the data change, and keep the returned unregister function. Also handle window resize by calling draw, coalescing bursts of resize events into at most one redraw per animation frame using a requestAnimationFrame guard flag. draw() is already idempotent — it wipes and redraws. Explain why SummaryDataChanged replaces listening to FilterChanged and ParameterChanged separately in a viz extension.

SummaryDataChanged is the viz extension’s heartbeat: whatever changed the data — a filter on another sheet, a parameter, an extract refresh — it fires once, and your response is always the same draw(). No cause-by-cause handling, no diffing; that is what the idempotent contract from the last stop bought you.

Resize never touches Tableau’s event system — the browser owns it, and it fires in bursts of dozens while the author drags. The requestAnimationFrame guard collapses each burst into one redraw per frame: cheap, smooth, and no debounce timer to tune.

javascript
(async () => {
  await tableau.extensions.initializeAsync();
  const worksheet = tableau.extensions.worksheetContent.worksheet;

  await draw(worksheet);   // the idempotent draw() from the last stop

  // Filters, parameters, refreshes — every data change, one signal.
  const unregister = worksheet.addEventListener(
    tableau.TableauEventType.SummaryDataChanged,
    () => draw(worksheet));

  // Resize belongs to the browser. Coalesce bursts into one frame.
  let queued = false;
  window.addEventListener('resize', () => {
    if (queued) return;
    queued = true;
    requestAnimationFrame(() => {
      queued = false;
      draw(worksheet);
    });
  });
})();

Got what you came for? Mark the stop and the line fills in beneath you.