use super::funejson::Value; use super::charts_shape_line_path::svg_pair; /// A filled area as SVG path data, in d3.area's format: along the top edge /// (y1) left to right, back along the baseline (y0) right to left, closed. /// A null y1 ends one area and starts the next. pub fn area_path(points: &[AreaPoint]) -> String { let mut runs: Vec> = Vec::new(); let mut run: Vec<(f64, f64, f64)> = Vec::new(); for p in points { match p.y1 { None => { if !run.is_empty() { runs.push(std::mem::take(&mut run)); } } Some(y1) => run.push((p.x, p.y0, y1)), } } if !run.is_empty() { runs.push(run); } let mut out = String::new(); for run in runs { for (i, (x, _, y1)) in run.iter().enumerate() { out.push_str(if i == 0 { "M" } else { "L" }); out.push_str(&svg_pair(*x, *y1)); } for (x, y0, _) in run.iter().rev() { out.push('L'); out.push_str(&svg_pair(*x, *y0)); } out.push('Z'); } out } pub fn fune_vector(args: &[Value]) -> Value { let points: Vec = args[0] .as_arr() .iter() .map(|p| AreaPoint { x: p.get("x").as_f64(), y0: p.get("y0").as_f64(), y1: if p.get("y1").is_null() { None } else { Some(p.get("y1").as_f64()) }, }) .collect(); Value::str(&area_path(&points)) }