use super::funejson::Value; use super::charts_ticks_tick_step::tick_spec; use super::math_round_float::round_float; /// Ticks at round values between start and stop, as d3.ticks, each one exact /// operation on a whole number (i * step or i / divisor), so 0.1 steps give 0.3 /// and not 0.30000000000000004. /// /// # Panics /// Panics if start or stop is not finite or `count` is less than 1. pub fn nice_ticks(start: f64, stop: f64, count: i64) -> Vec { let (mut mul, mut div) = tick_spec(start, stop, count); if start == stop { return vec![start + 0.0]; } let reverse = stop < start; let (lo, hi) = if reverse { (stop, start) } else { (start, stop) }; let (mut i1, mut i2) = indexes(lo, hi, mul, div); if i2 < i1 && count == 1 { // No multiple of the step for one tick falls inside; d3 retries with two. let spec = tick_spec(start, stop, 2); mul = spec.0; div = spec.1; let idx = indexes(lo, hi, mul, div); i1 = idx.0; i2 = idx.1; } let mut ticks = Vec::new(); let mut i = i1; while i <= i2 { ticks.push((if div > 1.0 { i / div } else { i * mul }) + 0.0); i += 1.0; } if reverse { ticks.reverse(); } ticks } fn indexes(lo: f64, hi: f64, mul: f64, div: f64) -> (f64, f64) { if div > 1.0 { let mut i1 = round_float(lo * div, 0); let mut i2 = round_float(hi * div, 0); if i1 / div < lo { i1 += 1.0; } if i2 / div > hi { i2 -= 1.0; } return (i1, i2); } let mut i1 = round_float(lo / mul, 0); let mut i2 = round_float(hi / mul, 0); if i1 * mul < lo { i1 += 1.0; } if i2 * mul > hi { i2 -= 1.0; } (i1, i2) } pub fn fune_vector(args: &[Value]) -> Value { Value::Arr( nice_ticks(args[0].as_f64(), args[1].as_f64(), args[2].as_i64()) .into_iter() .map(Value::Float) .collect(), ) }