use super::*;
pub const NUM_COLORS: usize = 8;
pub struct NamesStruct<A, B, C, D> {
title: A,
xname: B,
yname: C,
header: D,
}
impl<A: Display, B: Display, C: Display, D: Display> Names for NamesStruct<A, B, C, D> {
fn write_header(&self, fm: &mut fmt::Formatter) -> fmt::Result {
self.header.fmt(fm)
}
fn write_title(&self, fm: &mut fmt::Formatter) -> fmt::Result {
self.title.fmt(fm)
}
fn write_xname(&self, fm: &mut fmt::Formatter) -> fmt::Result {
self.xname.fmt(fm)
}
fn write_yname(&self, fm: &mut fmt::Formatter) -> fmt::Result {
self.yname.fmt(fm)
}
}
pub trait Names {
fn write_header(&self, fm: &mut fmt::Formatter) -> fmt::Result;
fn write_title(&self, fm: &mut fmt::Formatter) -> fmt::Result;
fn write_xname(&self, fm: &mut fmt::Formatter) -> fmt::Result;
fn write_yname(&self, fm: &mut fmt::Formatter) -> fmt::Result;
}
pub mod default_tags {
use core::fmt;
pub const CLASS: &str = "poloto";
pub const WIDTH: f64 = 800.0;
pub const HEIGHT: f64 = 500.0;
pub const XMLNS: &str = "http://www.w3.org/2000/svg";
pub fn default_svg_attrs<'a, 'b, T: fmt::Write>(
w: &'a mut tagger::AttributeWriter<'b, T>,
) -> Result<&'a mut tagger::AttributeWriter<'b, T>, fmt::Error> {
use tagger::prelude::*;
w.attr("class", CLASS)?
.attr("width", WIDTH)?
.attr("height", HEIGHT)?
.with_attr("viewBox", wr!("0 0 {} {}", WIDTH, HEIGHT))?
.attr("xmlns", XMLNS)
}
}
pub struct StyleBuilder<A, B, C> {
text_color: A,
back_color: B,
colors: [C; NUM_COLORS],
}
impl Default for StyleBuilder<&'static str, &'static str, &'static str> {
fn default() -> Self {
Self::new()
}
}
impl StyleBuilder<&'static str, &'static str, &'static str> {
pub fn new() -> Self {
StyleBuilder {
text_color: "black",
back_color: "aliceblue",
colors: [
"blue",
"red",
"green",
"gold",
"aqua",
"brown",
"lime",
"chocolate",
],
}
}
}
impl<A: Display, B: Display, C: Display> StyleBuilder<A, B, C> {
pub fn with_text_color<X: Display>(self, text_color: X) -> StyleBuilder<X, B, C> {
StyleBuilder {
text_color,
back_color: self.back_color,
colors: self.colors,
}
}
pub fn with_back_color<X: Display>(self, back_color: X) -> StyleBuilder<A, X, C> {
StyleBuilder {
text_color: self.text_color,
back_color,
colors: self.colors,
}
}
pub fn with_colors<X: Display>(self, colors: [X; NUM_COLORS]) -> StyleBuilder<A, B, X> {
StyleBuilder {
text_color: self.text_color,
back_color: self.back_color,
colors,
}
}
pub fn build_with_css_variables(self) -> impl Display {
let StyleBuilder {
text_color,
back_color,
colors,
} = self;
moveable_format(move |w| {
write!(
w,
r###"<style>.poloto {{
font-family: "Arial";
stroke-width:2;
}}
.poloto_text{{fill: var(--poloto_fg_color,{0}); }}
.poloto_axis_lines{{stroke: var(--poloto_fg_color,{0});stoke-width:3;fill:none}}
.poloto_background{{fill: var(--poloto_bg_color,{1}); }}
.poloto0stroke{{stroke: var(--poloto_color0,{2}); }}
.poloto1stroke{{stroke: var(--poloto_color1,{3}); }}
.poloto2stroke{{stroke: var(--poloto_color2,{4}); }}
.poloto3stroke{{stroke: var(--poloto_color3,{5}); }}
.poloto4stroke{{stroke: var(--poloto_color4,{6}); }}
.poloto5stroke{{stroke: var(--poloto_color5,{7}); }}
.poloto6stroke{{stroke: var(--poloto_color6,{8}); }}
.poloto7stroke{{stroke: var(--poloto_color7,{9}); }}
.poloto0fill{{fill:var(--poloto_color0,{2});}}
.poloto1fill{{fill:var(--poloto_color1,{3});}}
.poloto2fill{{fill:var(--poloto_color2,{4});}}
.poloto3fill{{fill:var(--poloto_color3,{5});}}
.poloto4fill{{fill:var(--poloto_color4,{6});}}
.poloto5fill{{fill:var(--poloto_color5,{7});}}
.poloto6fill{{fill:var(--poloto_color6,{8});}}
.poloto7fill{{fill:var(--poloto_color7,{9});}}</style>"###,
text_color,
back_color,
colors[0],
colors[1],
colors[2],
colors[3],
colors[4],
colors[5],
colors[6],
colors[7]
)
})
}
pub fn build(self) -> impl Display {
let StyleBuilder {
text_color,
back_color,
colors,
} = self;
moveable_format(move |w| {
write!(
w,
r###"<style>.poloto {{
font-family: "Arial";
stroke-width:2;
}}
.poloto_text{{fill: {0}; }}
.poloto_axis_lines{{stroke: {0};stoke-width:3;fill:none}}
.poloto_background{{fill: {1}; }}
.poloto0stroke{{stroke: {2}; }}
.poloto1stroke{{stroke: {3}; }}
.poloto2stroke{{stroke: {4}; }}
.poloto3stroke{{stroke: {5}; }}
.poloto4stroke{{stroke: {6}; }}
.poloto5stroke{{stroke: {7}; }}
.poloto6stroke{{stroke: {8}; }}
.poloto7stroke{{stroke: {9}; }}
.poloto0fill{{fill:{2};}}
.poloto1fill{{fill:{3};}}
.poloto2fill{{fill:{4};}}
.poloto3fill{{fill:{5};}}
.poloto4fill{{fill:{6};}}
.poloto5fill{{fill:{7};}}
.poloto6fill{{fill:{8};}}
.poloto7fill{{fill:{9};}}</style>"###,
text_color,
back_color,
colors[0],
colors[1],
colors[2],
colors[3],
colors[4],
colors[5],
colors[6],
colors[7],
)
})
}
}
pub struct HeaderBuilder<D: Display> {
header: D,
}
impl Default for HeaderBuilder<&'static str> {
fn default() -> Self {
Self::new()
}
}
impl HeaderBuilder<&'static str> {
pub fn new() -> Self {
HeaderBuilder { header: "" }
}
}
impl<D: Display> HeaderBuilder<D> {
pub fn push_css_default(self) -> HeaderBuilder<impl Display> {
HeaderBuilder {
header: concatenate_display("", self.header, StyleBuilder::new().build()),
}
}
pub fn push_default_css_with_variable(self) -> HeaderBuilder<impl Display> {
HeaderBuilder {
header: concatenate_display(
"",
self.header,
StyleBuilder::new().build_with_css_variables(),
),
}
}
pub fn push(self, a: impl fmt::Display) -> HeaderBuilder<impl Display> {
HeaderBuilder {
header: concatenate_display("", self.header, a),
}
}
pub fn build(self) -> D {
self.header
}
}
pub struct PlotterBuilder<D: fmt::Display> {
header: D,
svgtag: bool,
}
impl Default for PlotterBuilder<&'static str> {
fn default() -> Self {
Self::new()
}
}
impl PlotterBuilder<&'static str> {
pub fn new() -> Self {
PlotterBuilder {
header: "",
svgtag: true,
}
}
pub fn with_header<J: Display>(self, header: J) -> PlotterBuilder<J> {
PlotterBuilder {
header,
svgtag: self.svgtag,
}
}
pub fn with_svg(mut self, svg: bool) -> Self {
self.svgtag = svg;
self
}
}
impl<'a, D: Display + 'a> PlotterBuilder<D> {
pub fn build<A: Display + 'a, B: Display + 'a, C: Display + 'a>(
self,
title: A,
xname: B,
yname: C,
) -> Plotter<'a, NamesStruct<A, B, C, D>> {
let svgtag = if self.svgtag {
SvgTagOption::Svg
} else {
SvgTagOption::NoSvg
};
Plotter {
names: NamesStruct {
title,
xname,
yname,
header: self.header,
},
plots: Vec::new(),
svgtag,
}
}
}