Skip to content

Container: Add load / render / redraw lifecycle events - #782

Open
50rayn wants to merge 2 commits into
f5:mainfrom
50rayn:feat/container-render-events
Open

Container: Add load / render / redraw lifecycle events#782
50rayn wants to merge 2 commits into
f5:mainfrom
50rayn:feat/container-render-events

Conversation

@50rayn

@50rayn 50rayn commented May 3, 2026

Copy link
Copy Markdown
Contributor

Wanted a reliable way to know when a chart actually finished drawing — for logging first-paint times and reacting to renders downstream. The only existing hook was the onRenderComplete function-prop callback, which feels foreign in Vue/Svelte/Angular where events are the idiom. The usual workaround is await nextTick() + a couple of requestAnimationFrames, but that's a guess, not a real signal from unovis.

So I wired up load (first render), render (every render), redraw (every render except first) on VisXYContainer and VisSingleContainer — Highcharts-style. Vue gets @load, Svelte on:load, Angular (load). React/Solid keep onRenderComplete (function-prop callbacks are idiomatic there).

While at it, refactored the underlying XYContainer.onRenderComplete / SingleContainer.onRenderComplete from 7 positional args to a single payload object — that way XYContainerRenderPayload / SingleContainerRenderPayload live once in @unovis/ts and everyone imports them. This is a small breaking change for anyone passing onRenderComplete directly to the TS class or to React/Solid wrappers.

Verified pnpm check for Vue/Svelte, ng build for Angular, and the TS package rebuilds clean.

@rokotyan rokotyan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea! But there're a couple things I'm concerned about.

componentWidth: number,
componentHeight: number,
) => void;
onRenderComplete?: (payload: SingleContainerRenderPayload) => void;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to a payload object will be a breaking change, so we won't be able to do it till we release version 2.0. We'll need to stick to arguments

@50rayn 50rayn May 4, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted the TS-core onRenderComplete to positional args; wrappers build XYContainerRenderPayload / SingleContainerRenderPayload internally before emitting. No breaking change for existing TS / React / Solid users.


| Event | When it fires |
| -------- | --------------------------------------------------- |
| `load` | Once, after the chart's first render completes. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we really need three of these events instead of just one? I think the users can track whether it was the first render themselves if they need to. Could you give a couple of use cases to justify that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inspired by Highcharts (chart.events.load / render / redraw). Since I'm currently migrating from it, I have a couple of moments where I use these. Use cases I had in mind:

  • load — the big one. Fires once, perfect for prefetching chart settings, hydrating a "chart settings" panel, logging first-paint time, kicking off a fade-in, and hiding a skeleton. A userland boolean works, but every team ends up rewriting it and getting it subtly wrong (re-mounts, keyed components, hot reload, props that retrigger updates without a true "first paint").
  • redraw — react only to data/prop updates without the noisy first paint. e.g. block a "chart settings" toggle button while a redraw is in flight, refit an overlay, restore scroll, re-sync an external legend.
  • render — superset, blocks UI on every paint (first + redraw). Useful when you want a generic "chart is busy" gate around the whole lifecycle without branching on first vs subsequent.

Cost on our side is one boolean per container, so emitting all three is essentially free. Happy to drop redraw if it really feels redundant — but I'd push hard to keep load since it's the one consumers actually trip over. WDYT?

@50rayn
50rayn force-pushed the feat/container-render-events branch 2 times, most recently from 77e8c54 to 9fc7d32 Compare May 6, 2026 17:23
@50rayn
50rayn force-pushed the feat/container-render-events branch 2 times, most recently from e670bb6 to d296e97 Compare May 14, 2026 21:03
@50rayn
50rayn force-pushed the feat/container-render-events branch 2 times, most recently from e2cd852 to 90afba4 Compare July 3, 2026 08:02
@50rayn
50rayn force-pushed the feat/container-render-events branch 2 times, most recently from ab7c00b to d6f6b43 Compare July 17, 2026 06:31
@50rayn
50rayn force-pushed the feat/container-render-events branch 2 times, most recently from 697d19e to 814d70e Compare August 10, 2026 21:03
@50rayn
50rayn force-pushed the feat/container-render-events branch from 814d70e to e3b15c1 Compare August 12, 2026 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants