use super::funejson::Value; use super::charts_shape_line_path::{point_runs, points_from_value, svg_pair}; /// A step line as SVG path data, as d3.curveStepBefore, d3.curveStep and /// d3.curveStepAfter draw it: horizontal then vertical moves only. /// /// # Panics /// Panics on a position other than before, middle or after. pub fn step_path(points: &[Point], position: &str) -> String { let t = match position { "before" => 0.0, "middle" => 0.5, "after" => 1.0, other => panic!("step position must be before, middle or after, received {}", other), }; let mut out = String::new(); for run in point_runs(points) { out.push('M'); out.push_str(&svg_pair(run[0].0, run[0].1)); for i in 1..run.len() { let (px, py) = run[i - 1]; let (x, y) = run[i]; if t <= 0.0 { out.push_str(&format!("L{}L{}", svg_pair(px, y), svg_pair(x, y))); } else { // d3's own expression, so the midpoint rounds as d3's does. let x1 = px * (1.0 - t) + x * t; out.push_str(&format!("L{}L{}", svg_pair(x1, py), svg_pair(x1, y))); } } if t > 0.0 && t < 1.0 && run.len() >= 2 { let (lx, ly) = run[run.len() - 1]; out.push('L'); out.push_str(&svg_pair(lx, ly)); } if run.len() == 1 { out.push('Z'); } } out } pub fn fune_vector(args: &[Value]) -> Value { Value::str(&step_path(&points_from_value(&args[0]), args[1].as_str())) }