diff --git a/README.md b/README.md
index d4708f9..1c04150 100644
--- a/README.md
+++ b/README.md
@@ -245,6 +245,7 @@ You can also clone the repo and run `cargo run --bin gallery` to view the intera
+
diff --git a/charming/src/element/mod.rs b/charming/src/element/mod.rs
index 69819ab..e30c88d 100644
--- a/charming/src/element/mod.rs
+++ b/charming/src/element/mod.rs
@@ -40,6 +40,7 @@ pub mod smoothness;
pub mod sort;
pub mod split_area;
pub mod split_line;
+pub mod step;
pub mod symbol;
pub mod symbol_size;
pub mod text_align;
@@ -87,6 +88,7 @@ pub use shape::*;
pub use sort::*;
pub use split_area::*;
pub use split_line::*;
+pub use step::*;
pub use symbol::*;
pub use symbol_size::*;
pub use text_align::*;
diff --git a/charming/src/element/step.rs b/charming/src/element/step.rs
new file mode 100644
index 0000000..836fa5d
--- /dev/null
+++ b/charming/src/element/step.rs
@@ -0,0 +1,77 @@
+use serde::{de::Visitor, Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, PartialOrd, Clone)]
+pub enum Step {
+ True,
+ False,
+ Start,
+ Middle,
+ End,
+}
+
+impl From for Step {
+ fn from(value: bool) -> Self {
+ if value {
+ Step::True
+ } else {
+ Step::False
+ }
+ }
+}
+
+impl Serialize for Step {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: serde::Serializer,
+ {
+ match self {
+ Step::True => serializer.serialize_bool(true),
+ Step::False => serializer.serialize_bool(false),
+ Step::Start => serializer.serialize_str("start"),
+ Step::Middle => serializer.serialize_str("middle"),
+ Step::End => serializer.serialize_str("end"),
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for Step {
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct StepVisitor;
+
+ impl Visitor<'_> for StepVisitor {
+ type Value = Step;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ formatter.write_str(
+ "a boolean or a string containing either \"start\", \"middle\" or \"end\"",
+ )
+ }
+
+ fn visit_bool(self, v: bool) -> Result
+ where
+ E: serde::de::Error,
+ {
+ match v {
+ true => Ok(Step::True),
+ false => Ok(Step::False),
+ }
+ }
+
+ fn visit_str(self, v: &str) -> Result
+ where
+ E: serde::de::Error,
+ {
+ match v {
+ "start" => Ok(Step::Start),
+ "middle" => Ok(Step::Middle),
+ "end" => Ok(Step::End),
+ _ => Err(E::custom("unable to parse step type, invalid string")),
+ }
+ }
+ }
+ deserializer.deserialize_any(StepVisitor)
+ }
+}
diff --git a/charming/src/series/line.rs b/charming/src/series/line.rs
index 97131ec..ba12e4a 100644
--- a/charming/src/series/line.rs
+++ b/charming/src/series/line.rs
@@ -4,7 +4,7 @@ use crate::{
datatype::{DataFrame, DataPoint},
element::{
smoothness::Smoothness, AreaStyle, CoordinateSystem, DimensionEncode, Emphasis, ItemStyle,
- Label, LineStyle, MarkArea, MarkLine, MarkPoint, Symbol, SymbolSize, Tooltip,
+ Label, LineStyle, MarkArea, MarkLine, MarkPoint, Step, Symbol, SymbolSize, Tooltip,
},
};
@@ -53,6 +53,9 @@ pub struct Line {
#[serde(skip_serializing_if = "Option::is_none")]
smooth: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ step: Option,
+
#[serde(skip_serializing_if = "Option::is_none")]
connect_nulls: Option,
@@ -107,6 +110,7 @@ impl Line {
item_style: None,
emphasis: None,
smooth: None,
+ step: None,
connect_nulls: None,
mark_point: None,
mark_line: None,
@@ -187,6 +191,11 @@ impl Line {
self
}
+ pub fn step>(mut self, step: S) -> Self {
+ self.step = Some(step.into());
+ self
+ }
+
pub fn connect_nulls(mut self, connect_nulls: bool) -> Self {
self.connect_nulls = Some(connect_nulls);
self
diff --git a/gallery/src/lib.rs b/gallery/src/lib.rs
index 76b4f78..319224d 100644
--- a/gallery/src/lib.rs
+++ b/gallery/src/lib.rs
@@ -122,6 +122,7 @@ lazy_static! {
insert!(m, line, smoothed_line);
insert!(m, line, stacked_area);
insert!(m, line, stacked_line);
+ insert!(m, line, step_line);
insert!(m, line, temperature_change);
insert!(m, line, two_value_axes_in_polar);
m
diff --git a/gallery/src/line/mod.rs b/gallery/src/line/mod.rs
index 12d3bdd..e36751c 100644
--- a/gallery/src/line/mod.rs
+++ b/gallery/src/line/mod.rs
@@ -13,5 +13,6 @@ pub mod rainfall_vs_evaporation;
pub mod smoothed_line;
pub mod stacked_area;
pub mod stacked_line;
+pub mod step_line;
pub mod temperature_change;
pub mod two_value_axes_in_polar;
diff --git a/gallery/src/line/step_line.rs b/gallery/src/line/step_line.rs
new file mode 100644
index 0000000..df1727a
--- /dev/null
+++ b/gallery/src/line/step_line.rs
@@ -0,0 +1,46 @@
+use charming::{
+ component::{Axis, Feature, Grid, Legend, SaveAsImage, Title, Toolbox},
+ element::{AxisType, Step, Tooltip, Trigger},
+ series::Line,
+ Chart,
+};
+
+pub fn chart() -> Chart {
+ Chart::new()
+ .title(Title::new().text("Step Line"))
+ .tooltip(Tooltip::new().trigger(Trigger::Axis))
+ .legend(Legend::new())
+ .grid(
+ Grid::new()
+ .left("3%")
+ .right("4%")
+ .bottom("3%")
+ .contain_label(true),
+ )
+ .toolbox(Toolbox::new().feature(Feature::new().save_as_image(SaveAsImage::new())))
+ .x_axis(
+ Axis::new()
+ .type_(AxisType::Category)
+ .boundary_gap(false)
+ .data(vec!["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]),
+ )
+ .y_axis(Axis::new().type_(AxisType::Value))
+ .series(
+ Line::new()
+ .name("Step Start")
+ .step(Step::Start)
+ .data(vec![120, 132, 101, 134, 90, 230, 210]),
+ )
+ .series(
+ Line::new()
+ .name("Step Middle")
+ .step(Step::Middle)
+ .data(vec![220, 282, 201, 234, 290, 430, 410]),
+ )
+ .series(
+ Line::new()
+ .name("Step End")
+ .step(Step::End)
+ .data(vec![450, 432, 401, 454, 590, 530, 510]),
+ )
+}
diff --git a/img/line/step_line.svg b/img/line/step_line.svg
new file mode 100644
index 0000000..023f9a2
--- /dev/null
+++ b/img/line/step_line.svg
@@ -0,0 +1,117 @@
+
\ No newline at end of file