173 lines
5.5 KiB
Rust
173 lines
5.5 KiB
Rust
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 crate::{
|
|
probe::probe,
|
|
ui::{noise, 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))
|
|
}
|