From 5fdfa2e1f224c822fb3a3252ee90884fcba60c5a Mon Sep 17 00:00:00 2001 From: LukaOber Date: Sat, 2 Nov 2024 13:28:09 +0100 Subject: [PATCH 1/3] added custom font_settings --- charming/src/element/font_settings.rs | 139 ++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 charming/src/element/font_settings.rs diff --git a/charming/src/element/font_settings.rs b/charming/src/element/font_settings.rs new file mode 100644 index 0000000..6deb55f --- /dev/null +++ b/charming/src/element/font_settings.rs @@ -0,0 +1,139 @@ +use serde::Serialize; + +#[derive(Serialize, Debug, PartialEq, PartialOrd, Clone)] +#[serde(rename_all = "camelCase")] +pub enum FontStyle { + Normal, + Italic, + Oblique, +} + +#[derive(Debug, PartialEq, PartialOrd, Clone)] +pub enum FontWeight { + Normal, + Bold, + Bolder, + Lighter, + Number(i32), + Custom(String), +} +impl From for FontWeight +where + S: Into, +{ + fn from(s: S) -> Self { + let s = s.into(); + match s.as_str() { + "normal" => FontWeight::Normal, + "bold" => FontWeight::Bold, + "bolder" => FontWeight::Bolder, + "lighter" => FontWeight::Lighter, + _ => FontWeight::Custom(s), + } + } +} + +impl Serialize for FontWeight { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + FontWeight::Normal => serializer.serialize_str("normal"), + FontWeight::Bold => serializer.serialize_str("bold"), + FontWeight::Bolder => serializer.serialize_str("bolder"), + FontWeight::Lighter => serializer.serialize_str("lighter"), + FontWeight::Number(num) => serializer.serialize_i32(*num), + FontWeight::Custom(val) => serializer.serialize_str(val), + } + } +} + +#[derive(Debug, PartialEq, PartialOrd, Clone)] +pub enum FontFamily { + Serif, + SansSerif, + MonoSpace, + Cursive, + Fantasy, + Custom(String), +} + +impl From for FontFamily +where + S: Into, +{ + fn from(s: S) -> Self { + let s = s.into(); + match s.as_str() { + "serif" => FontFamily::Serif, + "sans-serif" => FontFamily::SansSerif, + "monospace" => FontFamily::MonoSpace, + "cursive" => FontFamily::Cursive, + "fantasy" => FontFamily::Fantasy, + _ => FontFamily::Custom(s), + } + } +} + +impl Serialize for FontFamily { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + FontFamily::Serif => serializer.serialize_str("serif"), + FontFamily::SansSerif => serializer.serialize_str("sans-serif"), + FontFamily::MonoSpace => serializer.serialize_str("monospace"), + FontFamily::Cursive => serializer.serialize_str("cursive"), + FontFamily::Fantasy => serializer.serialize_str("fantasy"), + FontFamily::Custom(val) => serializer.serialize_str(val), + } + } +} + +#[cfg(test)] +#[test] +fn font_style() { + let normal = serde_json::to_string(&FontStyle::Normal).unwrap(); + let italic = serde_json::to_string(&FontStyle::Italic).unwrap(); + let oblique = serde_json::to_string(&FontStyle::Oblique).unwrap(); + + assert_eq!("\"normal\"", normal); + assert_eq!("\"italic\"", italic); + assert_eq!("\"oblique\"", oblique); +} + +#[test] +fn font_weight() { + let normal = serde_json::to_string(&FontWeight::Normal).unwrap(); + let bold = serde_json::to_string(&FontWeight::Bold).unwrap(); + let bolder = serde_json::to_string(&FontWeight::Bolder).unwrap(); + let lighter = serde_json::to_string(&FontWeight::Lighter).unwrap(); + let number = serde_json::to_string(&FontWeight::Number(100)).unwrap(); + let custom = serde_json::to_string(&FontWeight::Custom("test".to_string())).unwrap(); + + assert_eq!("\"normal\"", normal); + assert_eq!("\"bold\"", bold); + assert_eq!("\"bolder\"", bolder); + assert_eq!("\"lighter\"", lighter); + assert_eq!("100", number); + assert_eq!("\"test\"", custom); +} + +#[test] +fn font_family() { + let serif = serde_json::to_string(&FontFamily::Serif).unwrap(); + let sans_serif = serde_json::to_string(&FontFamily::SansSerif).unwrap(); + let monospace = serde_json::to_string(&FontFamily::MonoSpace).unwrap(); + let cursive = serde_json::to_string(&FontFamily::Cursive).unwrap(); + let fantasy = serde_json::to_string(&FontFamily::Fantasy).unwrap(); + let custom = serde_json::to_string(&FontFamily::Custom("test".to_string())).unwrap(); + + assert_eq!("\"serif\"", serif); + assert_eq!("\"sans-serif\"", sans_serif); + assert_eq!("\"monospace\"", monospace); + assert_eq!("\"cursive\"", cursive); + assert_eq!("\"fantasy\"", fantasy); + assert_eq!("\"test\"", custom); +} From 44448adb84a5f52a74d64d1b18de1506a3336634 Mon Sep 17 00:00:00 2001 From: LukaOber Date: Sat, 2 Nov 2024 13:29:15 +0100 Subject: [PATCH 2/3] added or switch to font_settings --- charming/src/component/radar_coordinate.rs | 13 ++++---- charming/src/element/axis_label.rs | 33 ++++++++++++++++++- charming/src/element/label.rs | 37 ++++++++++++++++++---- charming/src/element/mod.rs | 1 + charming/src/element/text_style.rs | 17 ++++++---- charming/src/series/gauge.rs | 13 ++++---- charming/src/series/graph.rs | 1 + 7 files changed, 88 insertions(+), 27 deletions(-) diff --git a/charming/src/component/radar_coordinate.rs b/charming/src/component/radar_coordinate.rs index 86ad5b9..8de63bd 100644 --- a/charming/src/component/radar_coordinate.rs +++ b/charming/src/component/radar_coordinate.rs @@ -3,6 +3,7 @@ use serde::Serialize; use crate::{ datatype::CompositeValue, element::{ + font_settings::{FontFamily, FontStyle, FontWeight}, AxisLabel, AxisLine, AxisTick, Color, Formatter, Padding, Shape, SplitArea, SplitLine, }, }; @@ -23,13 +24,13 @@ pub struct RadarAxisName { color: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_style: Option, + font_style: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_weight: Option, + font_weight: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_family: Option, + font_family: Option, #[serde(skip_serializing_if = "Option::is_none")] font_size: Option, @@ -161,17 +162,17 @@ impl RadarAxisName { self } - pub fn font_style>(mut self, font_style: S) -> Self { + pub fn font_style>(mut self, font_style: F) -> Self { self.font_style = Some(font_style.into()); self } - pub fn font_weight>(mut self, font_weight: S) -> Self { + pub fn font_weight>(mut self, font_weight: F) -> Self { self.font_weight = Some(font_weight.into()); self } - pub fn font_family>(mut self, font_family: S) -> Self { + pub fn font_family>(mut self, font_family: F) -> Self { self.font_family = Some(font_family.into()); self } diff --git a/charming/src/element/axis_label.rs b/charming/src/element/axis_label.rs index 5f2d4fd..cd32e01 100644 --- a/charming/src/element/axis_label.rs +++ b/charming/src/element/axis_label.rs @@ -1,6 +1,10 @@ use serde::Serialize; -use super::{color::Color, Formatter}; +use super::{ + color::Color, + font_settings::{FontFamily, FontStyle, FontWeight}, + Formatter, +}; #[derive(Serialize, Debug, PartialEq, PartialOrd, Clone)] #[serde(rename_all = "camelCase")] @@ -11,6 +15,15 @@ pub struct AxisLabel { #[serde(skip_serializing_if = "Option::is_none")] distance: Option, + #[serde(skip_serializing_if = "Option::is_none")] + font_style: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + font_weight: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + font_family: Option, + #[serde(skip_serializing_if = "Option::is_none")] font_size: Option, @@ -38,6 +51,9 @@ impl AxisLabel { Self { show: None, distance: None, + font_style: None, + font_weight: None, + font_family: None, font_size: None, color: None, formatter: None, @@ -56,6 +72,21 @@ impl AxisLabel { self } + pub fn font_style>(mut self, font_style: F) -> Self { + self.font_style = Some(font_style.into()); + self + } + + pub fn font_weight>(mut self, font_weight: F) -> Self { + self.font_weight = Some(font_weight.into()); + self + } + + pub fn font_family>(mut self, font_family: F) -> Self { + self.font_family = Some(font_family.into()); + self + } + pub fn font_size>(mut self, font_size: F) -> Self { self.font_size = Some(font_size.into()); self diff --git a/charming/src/element/label.rs b/charming/src/element/label.rs index fcfe63d..a847ee7 100644 --- a/charming/src/element/label.rs +++ b/charming/src/element/label.rs @@ -1,6 +1,11 @@ use serde::Serialize; -use super::{color::Color, line_style::LineStyle, Formatter}; +use super::{ + color::Color, + font_settings::{FontFamily, FontStyle, FontWeight}, + line_style::LineStyle, + Formatter, +}; #[derive(Serialize, Debug, PartialEq, PartialOrd, Clone)] #[serde(rename_all = "camelCase")] @@ -65,10 +70,16 @@ pub struct Label { color: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_size: Option, + font_style: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + font_weight: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_weight: Option, + font_family: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + font_size: Option, #[serde(skip_serializing_if = "Option::is_none")] padding: Option<(f64, f64, f64, f64)>, @@ -117,8 +128,10 @@ impl Label { offset: None, formatter: None, color: None, - font_size: None, + font_style: None, font_weight: None, + font_family: None, + font_size: None, padding: None, align: None, vertical_align: None, @@ -167,16 +180,26 @@ impl Label { self } - pub fn font_size>(mut self, font_size: F) -> Self { - self.font_size = Some(font_size.into()); + pub fn font_style>(mut self, font_style: F) -> Self { + self.font_style = Some(font_style.into()); self } - pub fn font_weight>(mut self, font_weight: S) -> Self { + pub fn font_weight>(mut self, font_weight: F) -> Self { self.font_weight = Some(font_weight.into()); self } + pub fn font_family>(mut self, font_family: F) -> Self { + self.font_family = Some(font_family.into()); + self + } + + pub fn font_size>(mut self, font_size: F) -> Self { + self.font_size = Some(font_size.into()); + self + } + pub fn padding>(mut self, padding: (F, F, F, F)) -> Self { self.padding = Some(( padding.0.into(), diff --git a/charming/src/element/mod.rs b/charming/src/element/mod.rs index 69819ab..dbc62e6 100644 --- a/charming/src/element/mod.rs +++ b/charming/src/element/mod.rs @@ -17,6 +17,7 @@ pub mod coordinate_tooltip; pub mod cursor; pub mod dimension_encode; pub mod emphasis; +pub mod font_settings; pub mod formatter; pub mod icon; pub mod item_style; diff --git a/charming/src/element/text_style.rs b/charming/src/element/text_style.rs index 974254c..9124737 100644 --- a/charming/src/element/text_style.rs +++ b/charming/src/element/text_style.rs @@ -1,6 +1,9 @@ use serde::Serialize; -use super::color::Color; +use super::{ + color::Color, + font_settings::{FontFamily, FontStyle, FontWeight}, +}; #[derive(Serialize, Debug, PartialEq, PartialOrd, Clone)] #[serde(rename_all = "camelCase")] @@ -9,13 +12,13 @@ pub struct TextStyle { color: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_style: Option, + font_style: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_weight: Option, + font_weight: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_family: Option, + font_family: Option, #[serde(skip_serializing_if = "Option::is_none")] font_size: Option, @@ -55,17 +58,17 @@ impl TextStyle { self } - pub fn font_style>(mut self, font_style: S) -> Self { + pub fn font_style>(mut self, font_style: F) -> Self { self.font_style = Some(font_style.into()); self } - pub fn font_weight>(mut self, font_weight: S) -> Self { + pub fn font_weight>(mut self, font_weight: F) -> Self { self.font_weight = Some(font_weight.into()); self } - pub fn font_family>(mut self, font_family: S) -> Self { + pub fn font_family>(mut self, font_family: F) -> Self { self.font_family = Some(font_family.into()); self } diff --git a/charming/src/series/gauge.rs b/charming/src/series/gauge.rs index c0c68b7..b822a2f 100644 --- a/charming/src/series/gauge.rs +++ b/charming/src/series/gauge.rs @@ -3,6 +3,7 @@ use serde::Serialize; use crate::{ datatype::{DataFrame, DataPoint}, element::{ + font_settings::{FontFamily, FontStyle, FontWeight}, Anchor, AxisLabel, AxisLine, AxisTick, Color, ColorBy, Formatter, ItemStyle, Pointer, SplitLine, Tooltip, }, @@ -18,13 +19,13 @@ pub struct GaugeDetail { color: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_style: Option, + font_style: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_weight: Option, + font_weight: Option, #[serde(skip_serializing_if = "Option::is_none")] - font_family: Option, + font_family: Option, #[serde(skip_serializing_if = "Option::is_none")] font_size: Option, @@ -70,17 +71,17 @@ impl GaugeDetail { self } - pub fn font_style>(mut self, font_style: S) -> Self { + pub fn font_style>(mut self, font_style: F) -> Self { self.font_style = Some(font_style.into()); self } - pub fn font_weight>(mut self, font_weight: S) -> Self { + pub fn font_weight>(mut self, font_weight: F) -> Self { self.font_weight = Some(font_weight.into()); self } - pub fn font_family>(mut self, font_family: S) -> Self { + pub fn font_family>(mut self, font_family: F) -> Self { self.font_family = Some(font_family.into()); self } diff --git a/charming/src/series/graph.rs b/charming/src/series/graph.rs index 7e5aac1..0212d39 100644 --- a/charming/src/series/graph.rs +++ b/charming/src/series/graph.rs @@ -122,6 +122,7 @@ pub struct GraphNodeLabel { #[serde(skip_serializing_if = "Option::is_none")] color: Option, + //TODO: I think this should be f64, would be a breaking change #[serde(skip_serializing_if = "Option::is_none")] font_size: Option, } From 3b117cc086b546fa3a1e9b975800eca66ecea316 Mon Sep 17 00:00:00 2001 From: LukaOber Date: Sat, 2 Nov 2024 13:34:32 +0100 Subject: [PATCH 3/3] switch to custom font_settings in gallery --- gallery/src/boxplot/basic_boxplot.rs | 6 +++--- gallery/src/boxplot/boxplot_light_velocity.rs | 5 +++-- .../src/pie/doughnut_chart_with_rounded_corner.rs | 12 +++++++++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/gallery/src/boxplot/basic_boxplot.rs b/gallery/src/boxplot/basic_boxplot.rs index 8e44fa0..8c457e1 100644 --- a/gallery/src/boxplot/basic_boxplot.rs +++ b/gallery/src/boxplot/basic_boxplot.rs @@ -2,8 +2,8 @@ use charming::{ component::{Axis, Grid, Title}, datatype::{DataFrame, DataPoint, DataPointItem}, element::{ - AxisPointer, AxisPointerType, AxisType, ItemStyle, SplitArea, SplitLine, TextStyle, - Tooltip, Trigger, + font_settings::FontWeight, AxisPointer, AxisPointerType, AxisType, ItemStyle, SplitArea, + SplitLine, TextStyle, Tooltip, Trigger, }, series::{Boxplot, Scatter}, Chart, @@ -34,7 +34,7 @@ pub fn chart() -> Chart { .border_width(1) .text_style( TextStyle::new() - .font_weight("normal") + .font_weight(FontWeight::Normal) .font_size(14) .line_height(20), ) diff --git a/gallery/src/boxplot/boxplot_light_velocity.rs b/gallery/src/boxplot/boxplot_light_velocity.rs index eb2505a..5e6d084 100644 --- a/gallery/src/boxplot/boxplot_light_velocity.rs +++ b/gallery/src/boxplot/boxplot_light_velocity.rs @@ -2,7 +2,8 @@ use charming::{ component::{Axis, Grid, Title}, datatype::{Dataset, Transform}, element::{ - AxisPointer, AxisPointerType, AxisType, SplitArea, SplitLine, TextStyle, Tooltip, Trigger, + font_settings::FontWeight, AxisPointer, AxisPointerType, AxisType, SplitArea, SplitLine, + TextStyle, Tooltip, Trigger, }, series::{Boxplot, Scatter}, Chart, @@ -54,7 +55,7 @@ pub fn chart() -> Chart { .border_width(1) .text_style( TextStyle::new() - .font_weight("normal") + .font_weight(FontWeight::Normal) .font_size(14) .line_height(20), ) diff --git a/gallery/src/pie/doughnut_chart_with_rounded_corner.rs b/gallery/src/pie/doughnut_chart_with_rounded_corner.rs index 0b5e401..20ba378 100644 --- a/gallery/src/pie/doughnut_chart_with_rounded_corner.rs +++ b/gallery/src/pie/doughnut_chart_with_rounded_corner.rs @@ -1,6 +1,8 @@ use charming::{ component::Legend, - element::{Emphasis, Label, LabelLine, LabelPosition, Tooltip, Trigger}, + element::{ + font_settings::FontWeight, Emphasis, Label, LabelLine, LabelPosition, Tooltip, Trigger, + }, series::Pie, Chart, }; @@ -16,8 +18,12 @@ pub fn chart() -> Chart { .avoid_label_overlap(false) .label(Label::new().show(false).position(LabelPosition::Center)) .emphasis( - Emphasis::new() - .label(Label::new().show(true).font_size(40).font_weight("bold")), + Emphasis::new().label( + Label::new() + .show(true) + .font_size(40) + .font_weight(FontWeight::Bold), + ), ) .label_line(LabelLine::new().show(false)) .data(vec![