T15 Charts: cartesian with axes, legend, crosshair, tooltip, zoom, annotations and export (T15a); pie, donut, radar, heatmaps, treemap, sunburst, waterfall and spreads (T15b); sankey, funnel, gantt, force graph, chord, parallel coordinates, bullet and progress (T15c)
This commit is contained in:
44 files changed
+8639
-35
No files matched your search
@@ -0,0 +1,170 @@
|
||||
use ely_gpui_component::charts::{
|
||||
Bullet, BulletChart, ChordDiagram, FunnelChart, GanttChart, NetworkGraph, ParallelCoordinates,
|
||||
ProgressChart, SankeyChart, Task,
|
||||
};
|
||||
use gpui::{App, IntoElement, ParentElement, Styled, div, px};
|
||||
use jiff::civil::date;
|
||||
|
||||
use super::cartesian::noise;
|
||||
use crate::{probe::probe, ui::section};
|
||||
|
||||
pub fn flows(cx: &mut App) -> impl IntoElement + use<> {
|
||||
let budget = SankeyChart::new(
|
||||
"budget",
|
||||
[
|
||||
"Salary",
|
||||
"Freelance",
|
||||
"Income",
|
||||
"Home",
|
||||
"Food",
|
||||
"Savings",
|
||||
"Travel",
|
||||
],
|
||||
)
|
||||
.link(0, 2, 5200.0)
|
||||
.link(1, 2, 1400.0)
|
||||
.link(2, 3, 2100.0)
|
||||
.link(2, 4, 900.0)
|
||||
.link(2, 5, 2600.0)
|
||||
.link(2, 6, 1000.0)
|
||||
.format(|value| format!("${value:.0}"));
|
||||
let signups = [
|
||||
("Visited", 48200.0),
|
||||
("Signed up", 9640.0),
|
||||
("Verified", 7420.0),
|
||||
("Invited a teammate", 3110.0),
|
||||
("Paid", 1260.0),
|
||||
]
|
||||
.iter()
|
||||
.fold(FunnelChart::new("signups"), |funnel, (name, value)| {
|
||||
funnel.stage(*name, *value)
|
||||
});
|
||||
section(
|
||||
"SankeyChart / FunnelChart",
|
||||
"A month's money from where it came to where it went, and how many of a month's visitors reached each step. Hover a node, a ribbon or a stage.",
|
||||
cx,
|
||||
)
|
||||
.child(probe("sankey", div().w(px(720.)).child(budget)))
|
||||
.child(probe("funnel", div().w(px(720.)).child(signups)))
|
||||
}
|
||||
|
||||
pub fn schedule(cx: &mut App) -> impl IntoElement + use<> {
|
||||
let plan = GanttChart::new("launch")
|
||||
.task(Task::new("Research", date(2026, 9, 1), date(2026, 9, 11)).done(1.0))
|
||||
.task(
|
||||
Task::new("Design", date(2026, 9, 9), date(2026, 9, 25))
|
||||
.done(0.8)
|
||||
.after(0),
|
||||
)
|
||||
.task(
|
||||
Task::new("Build", date(2026, 9, 21), date(2026, 10, 16))
|
||||
.done(0.35)
|
||||
.after(1),
|
||||
)
|
||||
.task(
|
||||
Task::new("Write the docs", date(2026, 10, 5), date(2026, 10, 20))
|
||||
.done(0.1)
|
||||
.after(1),
|
||||
)
|
||||
.task(
|
||||
Task::new("Beta", date(2026, 10, 19), date(2026, 10, 30))
|
||||
.after(2)
|
||||
.after(3),
|
||||
)
|
||||
.task(Task::new("Launch", date(2026, 11, 2), date(2026, 11, 3)).after(4))
|
||||
.today(date(2026, 9, 25));
|
||||
section(
|
||||
"GanttChart",
|
||||
"A launch plan: each bar filled as far as it is done, arrows from the work it waits for, and a line at today. Hover a row.",
|
||||
cx,
|
||||
)
|
||||
.child(probe("gantt", div().w(px(720.)).child(plan)))
|
||||
}
|
||||
|
||||
pub fn relations(cx: &mut App) -> impl IntoElement + use<> {
|
||||
let people = [
|
||||
"Ada", "Grace", "Alan", "Edsger", "Barbara", "Donald", "Ken", "Dennis", "Bjarne", "Guido",
|
||||
"Linus", "Margaret",
|
||||
];
|
||||
let graph = people
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(NetworkGraph::new("people"), |graph, (ix, name)| {
|
||||
graph.node(*name, ix % 3)
|
||||
});
|
||||
let graph = [
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 2),
|
||||
(2, 3),
|
||||
(3, 4),
|
||||
(4, 1),
|
||||
(5, 3),
|
||||
(6, 7),
|
||||
(7, 8),
|
||||
(6, 8),
|
||||
(8, 9),
|
||||
(9, 10),
|
||||
(10, 6),
|
||||
(11, 0),
|
||||
(11, 5),
|
||||
(5, 6),
|
||||
]
|
||||
.into_iter()
|
||||
.fold(graph, |graph, (a, b)| graph.edge(a, b));
|
||||
let regions = ["Europe", "Americas", "Asia", "Africa", "Oceania"];
|
||||
let trade = vec![
|
||||
vec![0.0, 42.0, 31.0, 12.0, 5.0],
|
||||
vec![38.0, 0.0, 44.0, 6.0, 7.0],
|
||||
vec![35.0, 50.0, 0.0, 14.0, 18.0],
|
||||
vec![15.0, 5.0, 11.0, 0.0, 2.0],
|
||||
vec![4.0, 6.0, 20.0, 1.0, 0.0],
|
||||
];
|
||||
let mut rng = noise(43);
|
||||
let axes = ["Price", "Weight", "Range", "Charge", "Seats"];
|
||||
let cars = ["Aria", "Bolt", "Crest", "Dune", "Echo", "Flux"]
|
||||
.iter()
|
||||
.fold(ParallelCoordinates::new("cars", axes), |chart, name| {
|
||||
chart.record(
|
||||
*name,
|
||||
[
|
||||
28.0 + rng() * 40.0,
|
||||
1.4 + rng() * 1.2,
|
||||
250.0 + rng() * 350.0,
|
||||
20.0 + rng() * 40.0,
|
||||
(4.0 + rng() * 3.0).floor(),
|
||||
],
|
||||
)
|
||||
});
|
||||
section(
|
||||
"NetworkGraph / ForceGraph / ChordDiagram / ParallelCoordinates",
|
||||
"People and who they work with, settling as forces pull and push: drag a node, hover one to light its ties. Trade between regions around a circle, and cars on five measures at once.",
|
||||
cx,
|
||||
)
|
||||
.child(probe("network", div().w(px(720.)).child(graph)))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.gap_6()
|
||||
.child(probe("chord", div().w(px(360.)).child(ChordDiagram::new("trade", regions, trade))))
|
||||
.child(probe("parallel", div().w(px(420.)).child(cars))),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn targets(cx: &mut App) -> impl IntoElement + use<> {
|
||||
let bullets = BulletChart::new("quarter")
|
||||
.bullet(Bullet::new("Revenue", 268.0, 250.0).bands([150.0, 225.0, 300.0]))
|
||||
.bullet(Bullet::new("Profit", 22.0, 27.0).bands([20.0, 25.0, 30.0]))
|
||||
.bullet(Bullet::new("New customers", 1680.0, 2000.0).bands([1000.0, 1500.0, 2500.0]));
|
||||
let rings = ProgressChart::new("goals")
|
||||
.goal("Move", 480.0, 600.0)
|
||||
.goal("Exercise", 27.0, 30.0)
|
||||
.goal("Stand", 9.0, 12.0);
|
||||
section(
|
||||
"Bullet Chart / ProgressChart",
|
||||
"A quarter's measures against their targets over bands from poor to good, and a day's goals as rings that fill toward them.",
|
||||
cx,
|
||||
)
|
||||
.child(probe("bullets", div().w(px(720.)).child(bullets)))
|
||||
.child(probe("rings", rings))
|
||||
}
|
||||
Reference in new issue
Block a user