Functional Weave
Code in Rust

charts.shape@1.0.0

impl/rust/area_path.rs

1,522 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::charts_shape_line_path::svg_pair;  ← linePath, another function of this group · built into the same file, even by a slim install

/// 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<(f64, f64, f64)>> = 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<AreaPoint> = 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))
}