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_scale_linear_scale::{floats, pair}; ← linearScale, another function of this group · built into the same file, even by a slim install
use super::math_round_float::round_float; ← from math.round-float ^1.0.0 · built alongside by fune
/// The band a category occupies, as d3.scaleBand lays it out (without
/// rounding to whole pixels). A reversed range reverses the order of the
/// bands, not their direction, so `start` is always the lower coordinate.
///
/// # Panics
/// Panics on an empty or repeating domain, a value not in it, a range without
/// two values, or padding or align out of bounds.
pub fn band_scale(domain: &[String], range: &[f64], value: &str, padding_inner: f64, padding_outer: f64, align: f64) -> Band {
if !(padding_inner >= 0.0 && padding_inner <= 1.0) {
panic!("paddingInner must be between 0 and 1; got {}", padding_inner);
}
check_outer(padding_outer, "paddingOuter");
check_align(align);
let (start, width) = band_position(domain, range, value, padding_inner, padding_outer, align);
Band {
start: round_float(start, 6),
center: round_float(start + width / 2.0, 6),
width: round_float(width, 6),
}
}
// Exported for point_scale, which is a band scale whose bands have no width.
pub fn check_outer(padding: f64, what: &str) {
if !(padding >= 0.0) {
panic!("{} must be 0 or more; got {}", what, padding);
}
}
pub fn check_align(align: f64) {
if !(align >= 0.0 && align <= 1.0) {
panic!("align must be between 0 and 1; got {}", align);
}
}
/// The unrounded lower coordinate of value's band, and the band width.
pub fn band_position(domain: &[String], range: &[f64], value: &str, padding_inner: f64, padding_outer: f64, align: f64) -> (f64, f64) {
let (r0, r1) = pair(range, "range");
let n = domain.len();
if n == 0 {
panic!("domain must not be empty");
}
let mut index: Option<usize> = None;
for i in 0..n {
for j in 0..i {
if domain[j] == domain[i] {
panic!("domain has a repeated value: \"{}\"", domain[i]);
}
}
if domain[i] == value {
index = Some(i);
}
}
let index = match index {
Some(i) => i,
None => panic!("value is not in the domain: \"{}\"", value),
};
let reverse = r1 < r0;
let mut start = if reverse { r1 } else { r0 };
let stop = if reverse { r0 } else { r1 };
let nf = n as f64;
let step = (stop - start) / (nf - padding_inner + padding_outer * 2.0).max(1.0);
start += (stop - start - step * (nf - padding_inner)) * align;
let slot = if reverse { n - 1 - index } else { index };
(start + step * slot as f64, step * (1.0 - padding_inner))
}
pub fn band_to_value(band: &Band) -> Value {
Value::obj(vec![
("start", Value::Float(band.start)),
("center", Value::Float(band.center)),
("width", Value::Float(band.width)),
])
}
/// A JSON list of strings, for the vector adapters.
pub fn band_strings(value: &Value) -> Vec<String> {
value.as_arr().iter().map(|v| v.as_str().to_string()).collect()
}
pub fn fune_vector(args: &[Value]) -> Value {
band_to_value(&band_scale(
&band_strings(&args[0]),
&floats(&args[1]),
args[2].as_str(),
args[3].as_f64(),
args[4].as_f64(),
args[5].as_f64(),
))
}