use std::collections::HashMap;
use std::collections::HashSet;
use crate::scales::{Scale, ScaleType};
#[derive(Debug)]
pub struct ScaleBand {
domain: Vec<String>,
range: Vec<isize>,
offsets: Vec<f32>,
index: HashMap<String, usize>,
step: f32,
bandwidth: f32,
padding_inner: f32,
padding_outer: f32,
align: f32,
r0: f32,
r1: f32,
}
impl ScaleBand {
pub fn new() -> Self {
Self {
domain: Vec::new(),
range: vec![0, 1],
offsets: Vec::new(),
index: HashMap::new(),
step: 1f32,
bandwidth: 1f32,
padding_inner: 0.1,
padding_outer: 0.1,
align: 0.5,
r0: 0f32,
r1: 0f32,
}
}
pub fn set_inner_padding(mut self, padding: f32) -> Self {
self.padding_inner = padding;
self.rescale();
self
}
pub fn set_outer_padding(mut self, padding: f32) -> Self {
self.padding_outer = padding;
self.rescale();
self
}
pub fn set_domain(mut self, range: Vec<String>) -> Self {
let mut unique = Vec::new();
let mut set: HashSet<String> = HashSet::new();
for el in range.into_iter() {
let clone = el.clone();
if !set.contains(&clone) {
set.insert(clone);
unique.push(el);
}
}
self.domain = unique;
self.rescale();
self
}
pub fn domain(&self) -> &Vec<String> {
&self.domain
}
pub fn set_range(mut self, range: Vec<isize>) -> Self {
self.range = range;
self.rescale();
self
}
pub fn range(&self) -> &Vec<isize> {
&self.range
}
fn rescale(&mut self) {
let n = self.domain.len();
let r0 = self.range[0];
let r1 = self.range[1];
let reverse = r1 < r0;
let mut start = r0 as f32;
let mut stop = r1 as f32;
if reverse {
self.range = vec![r1, r0];
start = r1 as f32;
stop = r0 as f32;
}
let step_denominator = {
let computed_step = n as f32 - self.padding_inner + self.padding_outer * 2f32;
if computed_step > 1f32 {
computed_step
} else {
1f32
}
};
self.step = (stop - start) / step_denominator;
start += (stop - start - self.step * (n as f32 - self.padding_inner)) * self.align;
self.bandwidth = self.step * (1f32 - self.padding_inner);
self.offsets.clear();
for i in 0..n {
self.offsets.push(start + self.step * i as f32);
}
if reverse {
self.offsets.reverse();
}
self.index.clear();
let mut processed_domains = Vec::new();
for domain in self.domain.iter() {
if !self.index.contains_key(domain) {
self.index.insert(domain.clone(), processed_domains.len());
processed_domains.push(domain.clone());
}
}
self.domain.clear();
self.domain = processed_domains;
}
}
impl Scale<String> for ScaleBand {
fn get_type(&self) -> ScaleType {
ScaleType::Band
}
fn scale(&self, domain: &String) -> f32 {
self.offsets[*self.index.get(domain).unwrap()]
}
fn bandwidth(&self) -> Option<f32> {
Some(self.bandwidth)
}
fn range_start(&self) -> f32 {
self.range[0] as f32
}
fn range_end(&self) -> f32 {
self.range[1] as f32
}
fn get_ticks(&self) -> Vec<String> {
self.domain.clone()
}
}