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::text_format_decimal::format_decimal; ← from text.format-decimal ^1.0.0 · built alongside by fune
/// A polyline as SVG path data, in d3.line's format ("M10,20L30,40").
/// A null y ends the current subpath; a run of one point is "Mx,yZ", as d3
/// closes it so a round line cap still shows a dot.
pub fn line_path(points: &[Point]) -> String {
let mut out = String::new();
for run in point_runs(points) {
for (i, (x, y)) in run.iter().enumerate() {
out.push_str(if i == 0 { "M" } else { "L" });
out.push_str(&svg_pair(*x, *y));
}
if run.len() == 1 {
out.push('Z');
}
}
out
}
// Shared with the other path functions of this group.
/// "x,y" with each number rounded to 2 places, trailing zeros dropped.
pub fn svg_pair(x: f64, y: f64) -> String {
format!("{},{}", format_decimal(x, 2, true, ""), format_decimal(y, 2, true, ""))
}
/// The unbroken runs of a series: a point with a null y separates them.
pub fn point_runs(points: &[Point]) -> Vec<Vec<(f64, f64)>> {
let mut runs = Vec::new();
let mut current: Vec<(f64, f64)> = Vec::new();
for p in points {
match p.y {
None => {
if !current.is_empty() {
runs.push(std::mem::take(&mut current));
}
}
Some(y) => current.push((p.x, y)),
}
}
if !current.is_empty() {
runs.push(current);
}
runs
}
/// Points from vector JSON, for the adapters.
pub fn points_from_value(v: &Value) -> Vec<Point> {
v.as_arr()
.iter()
.map(|p| Point {
x: p.get("x").as_f64(),
y: if p.get("y").is_null() { None } else { Some(p.get("y").as_f64()) },
})
.collect()
}
pub fn fune_vector(args: &[Value]) -> Value {
Value::str(&line_path(&points_from_value(&args[0])))
}