mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-27 12:07:02 -06:00
Charts: draw, read and write value-axis minor gridlines
This commit is contained in:
@@ -159,6 +159,8 @@ pub struct Chart {
|
||||
pub title_size: Option<f64>,
|
||||
pub data_labels: bool,
|
||||
pub gridlines: bool,
|
||||
/// `c:minorGridlines` on the value axis: five to a major unit, between the major ones.
|
||||
pub minor_gridlines: bool,
|
||||
pub axis_titles: (Option<String>, Option<String>),
|
||||
/// Chart style number (1–48) and colour palette (`colorful1`, `monochrome3`…).
|
||||
pub style: u32,
|
||||
@@ -204,6 +206,7 @@ impl Default for Chart {
|
||||
title_size: None,
|
||||
data_labels: false,
|
||||
gridlines: true,
|
||||
minor_gridlines: false,
|
||||
axis_titles: (None, None),
|
||||
style: 2,
|
||||
palette: "colorful1".into(),
|
||||
|
||||
@@ -266,6 +266,7 @@ pub(crate) fn chart_from(root: &El) -> Option<Chart> {
|
||||
let cat_ax = pa.child("catAx").or_else(|| pa.child("dateAx")).or_else(|| pa.children_named("valAx").find(|a| !vertical(a)));
|
||||
if let Some(v) = val_ax {
|
||||
c.gridlines = v.child("majorGridlines").is_some();
|
||||
c.minor_gridlines = v.child("minorGridlines").is_some();
|
||||
let sc = v.child("scaling");
|
||||
c.y_min = sc.and_then(|s| s.child_val("min")).and_then(|v| v.parse().ok()).filter(|v: &f64| v.is_finite());
|
||||
c.y_max = sc.and_then(|s| s.child_val("max")).and_then(|v| v.parse().ok()).filter(|v: &f64| v.is_finite());
|
||||
@@ -310,6 +311,16 @@ fn text_size(e: Option<&El>) -> Option<f64> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn minor_gridlines_are_read_and_written_back() {
|
||||
let mut c = Chart::sample(ChartType::Line);
|
||||
c.minor_gridlines = true;
|
||||
let back = read_chart_xml(&crate::write::chart::chart_xml(&c)).unwrap();
|
||||
assert!(back.gridlines && back.minor_gridlines);
|
||||
c.minor_gridlines = false;
|
||||
assert!(!read_chart_xml(&crate::write::chart::chart_xml(&c)).unwrap().minor_gridlines);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legend_position_and_overlay_are_read() {
|
||||
let legend = r#"<c:legend><c:legendPos val="r"/><c:overlay val="1"/></c:legend>"#;
|
||||
|
||||
@@ -286,6 +286,9 @@ fn axes(w: &mut W, c: &Chart, g: Group) {
|
||||
if c.gridlines {
|
||||
w.empty0("c:majorGridlines");
|
||||
}
|
||||
if c.minor_gridlines {
|
||||
w.empty0("c:minorGridlines");
|
||||
}
|
||||
if let Some(t) = &c.axis_titles.1 {
|
||||
title(w, t);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! PPTX export: [`Presentation`] → package.
|
||||
|
||||
mod chart;
|
||||
pub(crate) mod chart;
|
||||
pub(crate) mod dml;
|
||||
mod shapes;
|
||||
mod theme;
|
||||
|
||||
@@ -282,6 +282,26 @@ pub fn draw(ctx: &mut RenderContext, rctx: &Ctx, c: &Chart, m: Affine, w: f64, h
|
||||
(true, Some((min2, max2, _))) => plot.y1 - (v - min2) / (max2 - min2).max(1e-9) * plot.height(),
|
||||
_ => to_v(v),
|
||||
};
|
||||
// Minor gridlines, under the major ones: five to a major unit.
|
||||
if c.minor_gridlines {
|
||||
let minor = step / 5.0;
|
||||
let n = (((max - min) / minor.max(1e-12)).round() as i64).clamp(1, 500);
|
||||
let mut g = BezPath::new();
|
||||
for k in (0..=n).filter(|k| k % 5 != 0) {
|
||||
let pos = to_v(min + k as f64 * minor);
|
||||
if horiz {
|
||||
g.move_to((pos, plot.y0));
|
||||
g.line_to((pos, plot.y1));
|
||||
} else {
|
||||
g.move_to((plot.x0, pos));
|
||||
g.line_to((plot.x1, pos));
|
||||
}
|
||||
}
|
||||
ctx.set_transform(m);
|
||||
ctx.set_paint(color(Rgba::rgb(0xF2, 0xF2, 0xF2), 1.0));
|
||||
ctx.set_stroke(kurbo::Stroke::new(0.75));
|
||||
ctx.stroke_path(&g);
|
||||
}
|
||||
// Gridlines and value labels.
|
||||
for v in ticks((min, max, step)) {
|
||||
let pos = to_v(v);
|
||||
|
||||
Reference in New Issue
Block a user