}
impl Area {
- fn default_cell_style(self) -> CellStyle {
+ pub fn default_cell_style(self) -> CellStyle {
use HorzAlign::*;
use VertAlign::*;
let (horz_align, vert_align, hmargins, vmargins) = match self {
}
}
- fn default_font_style(self) -> FontStyle {
+ pub fn default_font_style(self) -> FontStyle {
FontStyle::default().with_bold(self == Area::Title)
}
- fn default_area_style(self) -> AreaStyle {
+ pub fn default_area_style(self) -> AreaStyle {
AreaStyle {
cell_style: self.default_cell_style(),
font_style: self.default_font_style(),
}
}
+/// Can't convert `Axis3::Z` to `Axis2`.
+pub struct ZAxis;
+
+impl TryFrom<Axis3> for Axis2 {
+ type Error = ZAxis;
+
+ fn try_from(value: Axis3) -> Result<Self, Self::Error> {
+ match value {
+ Axis3::X => Ok(Axis2::X),
+ Axis3::Y => Ok(Axis2::Y),
+ Axis3::Z => Err(ZAxis),
+ }
+ }
+}
+
/// A 2-dimensional `(x,y)` pair.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Coord2(pub EnumMap<Axis2, usize>);
};
use enum_map::{Enum, EnumMap};
+use itertools::Itertools;
use ordered_float::OrderedFloat;
use serde::{Deserialize, de::Error as _};
format::{Decimal::Dot, F8_0, Type, UncheckedFormat},
output::{
pivot::{
- Area, AreaStyle, Color, HeadingRegion, HorzAlign, Look, PivotTable, RowParity, Value,
- VertAlign,
+ self, Area, AreaStyle, Axis2, Axis3, Color, HeadingRegion, HorzAlign, Look, PivotTable,
+ RowParity, Value, VertAlign,
},
spv::legacy_bin::DataValue,
},
+ variable,
};
#[derive(Debug)]
_phantom: PhantomData<T>,
}
+impl<T> Ref<T> {
+ fn get<'a>(&self, table: &HashMap<&str, &'a T>) -> Option<&'a T> {
+ table.get(self.references.as_str()).map(|v| &**v)
+ }
+}
+
impl<'de, T> Deserialize<'de> for Ref<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
todo!()
};
+ let mut axes = HashMap::new();
+ for child in &graph.facet_layout.children {
+ if let FacetLayoutChild::FacetLevel(facet_level) = child {
+ axes.insert(facet_level.level, &facet_level.axis);
+ }
+ }
+
// Footnotes.
//
// Any pivot_value might refer to footnotes, so it's important to
{
Style::decode(
Some(*style),
- styles
- .get(graph.cell_style.references.as_str())
- .map(|v| &**v),
+ graph.cell_style.get(&styles),
&mut look.areas[Area::Data(RowParity::Even)],
);
look.areas[Area::Data(RowParity::Odd)] =
}
}
+ fn decode_dimension(
+ variables: &[(&Series, usize)],
+ axes: &HashMap<usize, &Axis>,
+ styles: &HashMap<&str, &Style>,
+ a: Axis3,
+ look: &mut Look,
+ ) {
+ let base_level = variables[0].1;
+ if let Ok(a) = Axis2::try_from(a)
+ && let Some(axis) = axes.get(&(base_level + variables.len()))
+ && let Some(label) = &axis.label
+ {
+ let out = &mut look.areas[Area::Labels(a)];
+ *out = Area::Labels(a).default_area_style();
+ Style::decode(
+ label.style.get(&styles),
+ label.text_frame_style.as_ref().and_then(|r| r.get(styles)),
+ out,
+ );
+ }
+ if a == Axis3::Y
+ && let Some(axis) = axes.get(&(base_level + variables.len() - 1))
+ {}
+
+ todo!()
+ }
+
+ fn decode_dimensions(
+ variables: &[VariableReference],
+ series: &HashMap<&str, Series>,
+ axes: &HashMap<usize, &Axis>,
+ styles: &HashMap<&str, &Style>,
+ a: Axis3,
+ look: &mut Look,
+ level_ofs: usize,
+ ) -> Vec<pivot::Dimension> {
+ let variables = variables
+ .into_iter()
+ .zip(level_ofs..)
+ .map(|(vr, level)| {
+ series
+ .get(vr.reference.as_str())
+ .filter(|s| !s.values.is_empty())
+ .map(|s| (s, level))
+ })
+ .collect::<Vec<_>>();
+ let mut dim_vars = Vec::new();
+ for var in variables {
+ if let Some((var, level)) = var {
+ dim_vars.push((var, level));
+ } else if !dim_vars.is_empty() {
+ decode_dimension(&dim_vars, axes, styles, a, look);
+ dim_vars.clear();
+ }
+ }
+ if !dim_vars.is_empty() {
+ decode_dimension(&dim_vars, axes, styles, a, look);
+ }
+ todo!()
+ }
+
+ let cross = &graph.faceting.cross.children;
+ let columns = cross
+ .first()
+ .map(|child| child.variables())
+ .unwrap_or_default();
+ decode_dimensions(columns, &series, &axes, &styles, Axis3::X, &mut look, 1);
+ let rows = cross
+ .get(1)
+ .map(|child| child.variables())
+ .unwrap_or_default();
+ decode_dimensions(
+ rows,
+ &series,
+ &axes,
+ &styles,
+ Axis3::Y,
+ &mut look,
+ 1 + columns.len(),
+ );
+
todo!()
}
}
#[serde(rename_all = "camelCase")]
struct VariableReference {
#[serde(rename = "@ref")]
- reference: Option<String>,
+ reference: String,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
Nest(Nest),
}
+impl CrossChild {
+ fn variables(&self) -> &[VariableReference] {
+ match self {
+ CrossChild::Unity => &[],
+ CrossChild::Nest(nest) => &nest.variable_references,
+ }
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Nest {
}
fn decode_style(&self, area_style: &mut AreaStyle, styles: &HashMap<&str, &Style>) {
- let fg = styles.get(self.style.references.as_str()).map(|v| &**v);
- let bg = if let Some(text_frame_style) = &self.text_frame_style {
- styles
- .get(text_frame_style.references.as_str())
- .map(|v| &**v)
- } else {
- None
- };
+ let fg = self.style.get(styles);
+ let bg = self.text_frame_style.as_ref().and_then(|r| r.get(styles));
Style::decode(fg, bg, area_style);
}
}
}
impl LabelFrame {
- fn decode(&self, look: &mut Look, styles: &HashMap<&String, &Style>) {
+ fn decode(&self, look: &mut Look, styles: &HashMap<&str, &Style>) {
let Some(label) = &self.label else { return };
let Some(purpose) = label.purpose else { return };
let area = match purpose {
Purpose::Layer => Area::Layers,
Purpose::Footnote => Area::Footer,
};
- let fg = styles.get(&label.style.references).map(|v| &**v);
- let bg = if let Some(text_frame_style) = &label.text_frame_style {
- styles.get(&&text_frame_style.references).map(|v| &**v)
- } else {
- None
- };
- Style::decode(fg, bg, &mut look.areas[area]);
+ Style::decode(
+ label.style.get(styles),
+ label.text_frame_style.as_ref().and_then(|r| r.get(styles)),
+ &mut look.areas[area],
+ );
todo!()
}
}