use super::funejson::Value; use super::math_round_float::round_float; /// Rectangles for bars. Edges are rounded to 2 places and sizes are the /// differences of the rounded edges, so bars that share an edge share it /// exactly, and a negative bar's height is still positive. /// /// # Panics /// Panics on an unknown orientation or a negative thickness. pub fn bar_rects(bars: &[BarSpec], orientation: &str) -> Vec { if orientation != "vertical" && orientation != "horizontal" { panic!("orientation must be vertical or horizontal, received {}", orientation); } bars.iter() .map(|bar| { if !(bar.thickness >= 0.0) { panic!("bar thickness must not be negative, received {}", bar.thickness); } let a0 = round_float(bar.band, 2); let a1 = round_float(bar.band + bar.thickness, 2); let v0 = round_float(bar.base.min(bar.value), 2); let v1 = round_float(bar.base.max(bar.value), 2); let across = round_float(a1 - a0, 2); let along = round_float(v1 - v0, 2); if orientation == "vertical" { Rect { x: a0, y: v0, width: across, height: along } } else { Rect { x: v0, y: a0, width: along, height: across } } }) .collect() } pub fn rect_to_value(r: &Rect) -> Value { Value::obj(vec![ ("x", Value::Float(r.x)), ("y", Value::Float(r.y)), ("width", Value::Float(r.width)), ("height", Value::Float(r.height)), ]) } pub fn fune_vector(args: &[Value]) -> Value { let bars: Vec = args[0] .as_arr() .iter() .map(|b| BarSpec { band: b.get("band").as_f64(), thickness: b.get("thickness").as_f64(), base: b.get("base").as_f64(), value: b.get("value").as_f64(), }) .collect(); Value::Arr(bar_rects(&bars, args[1].as_str()).iter().map(rect_to_value).collect()) }