diff --git a/crates/story/src/chart_story.rs b/crates/story/src/chart_story.rs index 709ff5a7..e0c04f16 100644 --- a/crates/story/src/chart_story.rs +++ b/crates/story/src/chart_story.rs @@ -1,13 +1,14 @@ use gpui::{ - div, linear_color_stop, linear_gradient, prelude::FluentBuilder, px, App, AppContext, Context, - Entity, FocusHandle, Focusable, Hsla, IntoElement, ParentElement, Render, SharedString, Styled, - Window, + App, AppContext, Context, Entity, FocusHandle, Focusable, Hsla, IntoElement, ParentElement, + Render, SharedString, Styled, Window, div, linear_color_stop, linear_gradient, + prelude::FluentBuilder, px, }; use gpui_component::{ + ActiveTheme, StyledExt, chart::{AreaChart, BarChart, LineChart, PieChart}, divider::Divider, dock::PanelControl, - h_flex, v_flex, ActiveTheme, StyledExt, + h_flex, v_flex, }; use serde::Deserialize; @@ -174,8 +175,8 @@ impl Render for ChartStory { "Pie Chart - Donut", PieChart::new(self.monthly_devices.clone()) .value(|d| d.desktop as f32) - .outer_radius(100.) .inner_radius(60.) + .outer_radius_fn(|d| 100. - d.index as f32 * 4.) .color(move |d| d.color(color)), true, cx, @@ -184,8 +185,8 @@ impl Render for ChartStory { "Pie Chart - Pad Angle", PieChart::new(self.monthly_devices.clone()) .value(|d| d.desktop as f32) - .outer_radius(100.) .inner_radius(60.) + .outer_radius(100.) .pad_angle(4. / 100.) .color(move |d| d.color(color)), true, @@ -227,7 +228,7 @@ impl Render for ChartStory { .child(Divider::horizontal()) .child( h_flex() - .gap_x_8() + .gap_x_4() .h(px(400.)) .child(chart_container( "Line Chart", @@ -268,7 +269,7 @@ impl Render for ChartStory { .child(Divider::horizontal()) .child( h_flex() - .gap_x_8() + .gap_x_4() .h(px(400.)) .child(chart_container( "Area Chart", diff --git a/crates/ui/src/chart/pie_chart.rs b/crates/ui/src/chart/pie_chart.rs index a5b5dde2..1694f155 100644 --- a/crates/ui/src/chart/pie_chart.rs +++ b/crates/ui/src/chart/pie_chart.rs @@ -6,7 +6,7 @@ use num_traits::Zero; use crate::{ plot::{ - shape::{Arc, Pie}, + shape::{Arc, ArcData, Pie}, Plot, }, ActiveTheme, PixelsExt, @@ -16,7 +16,9 @@ use crate::{ pub struct PieChart { data: Vec, inner_radius: f32, + inner_radius_fn: Option) -> f32 + 'static>>, outer_radius: f32, + outer_radius_fn: Option) -> f32 + 'static>>, pad_angle: f32, value: Option f32>>, color: Option Hsla>>, @@ -30,23 +32,62 @@ impl PieChart { Self { data: data.into_iter().collect(), inner_radius: 0., + inner_radius_fn: None, outer_radius: 0., + outer_radius_fn: None, pad_angle: 0., value: None, color: None, } } + /// Set the inner radius of the pie chart. pub fn inner_radius(mut self, inner_radius: f32) -> Self { self.inner_radius = inner_radius; self } + /// Set the inner radius of the pie chart based on the arc data. + pub fn inner_radius_fn( + mut self, + inner_radius_fn: impl Fn(&ArcData) -> f32 + 'static, + ) -> Self { + self.inner_radius_fn = Some(Rc::new(inner_radius_fn)); + self + } + + fn get_inner_radius(&self, arc: &ArcData) -> f32 { + if let Some(inner_radius_fn) = self.inner_radius_fn.as_ref() { + inner_radius_fn(arc) + } else { + self.inner_radius + } + } + + /// Set the outer radius of the pie chart. pub fn outer_radius(mut self, outer_radius: f32) -> Self { self.outer_radius = outer_radius; self } + /// Set the outer radius of the pie chart based on the arc data. + pub fn outer_radius_fn( + mut self, + outer_radius_fn: impl Fn(&ArcData) -> f32 + 'static, + ) -> Self { + self.outer_radius_fn = Some(Rc::new(outer_radius_fn)); + self + } + + fn get_outer_radius(&self, arc: &ArcData) -> f32 { + if let Some(outer_radius_fn) = self.outer_radius_fn.as_ref() { + outer_radius_fn(arc) + } else { + self.outer_radius + } + } + + /// Set the pad angle of the pie chart. pub fn pad_angle(mut self, pad_angle: f32) -> Self { self.pad_angle = pad_angle; self @@ -57,6 +98,7 @@ impl PieChart { self } + /// Set the color of the pie chart. pub fn color(mut self, color: impl Fn(&T) -> H + 'static) -> Self where H: Into + 'static, @@ -87,6 +129,8 @@ impl Plot for PieChart { let arcs = pie.arcs(&self.data); for a in &arcs { + let inner_radius = self.get_inner_radius(a); + let outer_radius = self.get_outer_radius(a); arc.paint( a, if let Some(color_fn) = self.color.as_ref() { @@ -94,6 +138,8 @@ impl Plot for PieChart { } else { cx.theme().chart_2 }, + Some(inner_radius), + Some(outer_radius), &bounds, window, ); diff --git a/crates/ui/src/plot/shape.rs b/crates/ui/src/plot/shape.rs index 79917a86..1792b4f9 100644 --- a/crates/ui/src/plot/shape.rs +++ b/crates/ui/src/plot/shape.rs @@ -4,7 +4,7 @@ mod bar; mod line; mod pie; -pub use arc::Arc; +pub use arc::{Arc, ArcData}; pub use area::Area; pub use bar::Bar; pub use line::Line; diff --git a/crates/ui/src/plot/shape/arc.rs b/crates/ui/src/plot/shape/arc.rs index fb1b39a2..b52508c4 100644 --- a/crates/ui/src/plot/shape/arc.rs +++ b/crates/ui/src/plot/shape/arc.rs @@ -69,7 +69,13 @@ impl Arc { point(r * a.cos(), r * a.sin()) } - fn path(&self, arc: &ArcData, bounds: &Bounds) -> Option> { + fn path( + &self, + arc: &ArcData, + inner_radius: Option, + outer_radius: Option, + bounds: &Bounds, + ) -> Option> { let start_angle = arc.start_angle - HALF_PI; let end_angle = arc.end_angle - HALF_PI; let da = end_angle - start_angle; @@ -80,8 +86,8 @@ impl Arc { } else { arc.pad_angle }; - let r0 = self.inner_radius.max(0.); - let r1 = self.outer_radius.max(0.); + let r0 = inner_radius.unwrap_or(self.inner_radius).max(0.); + let r1 = outer_radius.unwrap_or(self.outer_radius).max(0.); // Calculate the center point. let center_x = bounds.origin.x.as_f32() + bounds.size.width.as_f32() / 2.; @@ -173,10 +179,12 @@ impl Arc { &self, arc: &ArcData, color: impl Into, + inner_radius: Option, + outer_radius: Option, bounds: &Bounds, window: &mut Window, ) { - let path = self.path(arc, bounds); + let path = self.path(arc, inner_radius, outer_radius, bounds); if let Some(path) = path { window.paint_path(path, color.into()); }