Skip to content

Conversation

@H4ad
Copy link

@H4ad H4ad commented Jan 10, 2026

This PR will contain these main changes:

  • using document fragment to avoid create elements directly in the dom
  • using requestFrameAnimation + insert the legends & cursor points last
  • remove ::after and ::before css to avoid costs of reflow

To test:

diff --git a/bench/uPlot-10M.html b/bench/uPlot-10M.html
index 5af53e2..ca855a6 100644
--- a/bench/uPlot-10M.html
+++ b/bench/uPlot-10M.html
@@ -109,7 +109,7 @@
 			let data1 = prepData(2e6);
 			let u1 = makeChart(data1, false);
 
-			let data2 = prepData(40_000, 50, 2);
+			let data2 = prepData(100, 10000, 2);
 			let u2 = makeChart(data2, true);
 
 			setTimeout(() => {
@@ -131,4 +131,4 @@
 			}, 2000);
 		</script>
 	</body>
-</html>
\ No newline at end of file
+</html>

Before:

image

After:

image

Maybe in the future introduce a feature to virtualize or just render top 20 legends and add button to load more.

I found this while trying to optimize the SigNoz/signoz#9784

This is breaking change since it could break people that expected legends to be on DOM after new uPlot.

This PR will contain these main changes:
- using document fragment to avoid create elements directly in the dom
- using requestFrameAnimation + insert the legends & cursor points last
- remove ::after and ::before css to avoid costs of reflow
@leeoniya
Copy link
Owner

leeoniya commented Jan 23, 2026

Maybe in the future introduce a feature to virtualize or just render top 20 legends and add button to load more.

that's actually an upcoming topic of discussion in Grafana. we have users with 2k+ series per panel, and the legend being in the dom becomes a performance issue, (even though Grafana uses its own React legend)

using requestFrameAnimation + insert the legends & cursor points last
This is breaking change since it could break people that expected legends to be on DOM after new uPlot.

that's my main concern with this approach, too.

@H4ad
Copy link
Author

H4ad commented Jan 25, 2026

that's my main concern with this approach, too.

Can't we just emit an new event and make this a breaking change release?

@leeoniya
Copy link
Owner

leeoniya commented Jan 26, 2026

imo, rendering an insane amount of legend items is fundamentally useless. since human eyes are unlikely to accurately distinguish more than 20-30 colors, trying to slightly optimize the legend for hundreds+ series use case is not a great approach to fix both a performance and a UX issue.

virtualization is not really possible with a non-table legend which flows/wraps unpredictably, so that solution would only help the table legend case, which is not the default.

since uPlot does not currently have a tooltip (it may get one in v2.0), it kinda has to render all items to make it possible to see the raw values on hover. i want to make sure that any solution still allows a live legend to display the hovered value(s). a couple new options to paginate/show-all the legend in addition to being able to live-sort it by hovered value may work well enough for all use cases and be much faster than trying to optimize css/dom for a thousand series. 🤔

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