fn fmt_tick(v: f64) -> String {
let a = v.abs();
if a == 0.0 {
"0".to_string()
} else if a >= 10.0 {
format!("{v:.0}")
} else if a >= 1.0 {
format!("{v:.1}")
} else {
format!("{v:.2}")
}
}
pub fn y_axis(ml: f64, mt: f64, pw: f64, ph: f64, y_max: f64, title: &str) -> String {
let mut s = String::new();
let ticks = 4;
for i in 0..=ticks {
let frac = i as f64 / ticks as f64;
let y = mt + ph - frac * ph;
let val = y_max * frac;
s.push_str(&format!(
"<line x1=\"{ml:.0}\" y1=\"{y:.1}\" x2=\"{:.0}\" y2=\"{y:.1}\" stroke=\"#262019\"/>",
ml + pw
));
s.push_str(&format!(
"<text x=\"{:.0}\" y=\"{:.1}\" text-anchor=\"end\" fill=\"#8c8273\" font-size=\"11\">{}</text>",
ml - 6.0,
y + 4.0,
fmt_tick(val)
));
}
let yc = mt + ph / 2.0;
s.push_str(&format!(
"<text x=\"16\" y=\"{yc:.1}\" text-anchor=\"middle\" fill=\"#8c8273\" font-size=\"12\" transform=\"rotate(-90 16 {yc:.1})\">{title}</text>"
));
s
}
pub fn frame_open(w: f64, h: f64, title: &str, subtitle: &str) -> String {
format!(
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{w:.0}\" height=\"{h:.0}\" \
font-family=\"sans-serif\" font-size=\"12\" fill=\"#bcb3a3\">\
<rect width=\"{w:.0}\" height=\"{h:.0}\" fill=\"#0c0b08\"/>\
<text x=\"24\" y=\"24\" font-size=\"15\" font-weight=\"bold\">{title}</text>\
<text x=\"24\" y=\"40\" font-size=\"11\" fill=\"#8a8172\">{subtitle}</text>"
)
}
pub fn panel_axes(x: f64, top: f64, width: f64, bottom: f64, caption: &str) -> String {
format!(
"<text x=\"{x:.0}\" y=\"{:.0}\" font-size=\"12\" fill=\"#8a8172\">{caption}</text>\
<line x1=\"{x:.0}\" y1=\"{top:.0}\" x2=\"{x:.0}\" y2=\"{bottom:.0}\" stroke=\"#342c21\"/>\
<line x1=\"{x:.0}\" y1=\"{bottom:.0}\" x2=\"{:.0}\" y2=\"{bottom:.0}\" stroke=\"#342c21\"/>",
top - 8.0,
x + width
)
}