pub use crate::diagrams::util::esc;
pub fn build_style(id: &str, ff: &str) -> String {
use super::constants::{FONT_SIZE, SECTION_STYLES};
let mut s = format!(
"#{id}{{font-family:{ff};font-size:{fs}px;fill:#333;}}",
id = id,
ff = ff,
fs = FONT_SIZE,
);
for (i, st) in SECTION_STYLES.iter().enumerate() {
let idx: i64 = (i as i64) - 1;
s.push_str(&format!(
"#{id} .section-{idx} rect,#{id} .section-{idx} path,#{id} .section-{idx} circle,#{id} .section-{idx} path{{fill:{fill};}}",
id = id, idx = idx, fill = st.fill,
));
s.push_str(&format!(
"#{id} .section-{idx} text{{fill:{text};}}",
id = id,
idx = idx,
text = st.text,
));
s.push_str(&format!(
"#{id} .section-edge-{idx}{{stroke:{fill};}}",
id = id,
idx = idx,
fill = st.fill,
));
s.push_str(&format!(
"#{id} .section-{idx} line{{stroke:{line};stroke-width:3;}}",
id = id,
idx = idx,
line = st.line,
));
s.push_str(&format!(
"#{id} .node-line-{idx}{{stroke:{line};stroke-width:3;}}",
id = id,
idx = idx,
line = st.line,
));
}
s.push_str(&format!(
concat!(
"#{id} .edge{{stroke-width:3;}}",
"#{id} .timeline-node{{fill:none;}}",
"#{id} .node-bkg{{opacity:1;}}",
"#{id} p{{margin:0;}}",
"#{id} svg{{font-family:{ff};font-size:{fs}px;}}",
"#{id} text{{font-family:{ff};fill:#333;}}",
"#{id} .section-label{{text-anchor:middle;dominant-baseline:middle;}}",
"#{id} .title-text{{font-size:24px;font-weight:bold;fill:#333;text-anchor:middle;}}",
"#{id} .activity-line{{stroke:#333;stroke-width:4px;}}",
"#{id} .eventWrapper{{filter:brightness(120%);}}",
"#{id} .lineWrapper line{{stroke:#ffffff;}}",
),
id = id,
ff = ff,
fs = FONT_SIZE,
));
s
}
pub fn arrowhead_marker(id: &str) -> String {
format!(
"<defs>\n <marker id=\"{id}-arrowhead\" refX=\"5\" refY=\"2\" markerWidth=\"6\" markerHeight=\"4\" orient=\"auto\">\n <path d=\"M 0,0 V 4 L6,2 Z\"></path>\n </marker>\n</defs>",
id = id,
)
}
pub fn activity_line(x1: f64, y: f64, x2: f64, diagram_id: &str) -> String {
format!(
"<g class=\"lineWrapper\">\n <line x1=\"{x1}\" y1=\"{y}\" x2=\"{x2}\" y2=\"{y}\" style=\"stroke:black;stroke-width:4;\" marker-end=\"url(#{id}-arrowhead)\"></line>\n</g>",
x1 = x1,
y = y,
x2 = x2,
id = diagram_id,
)
}
pub fn title_text(x: f64, title: &str) -> String {
format!(
"<text x=\"{x}\" font-size=\"4ex\" font-weight=\"bold\" y=\"20\">{t}</text>",
x = x,
t = title,
)
}
pub fn svg_root(
id: &str,
max_w: f64,
vb_x: f64,
vb_y: f64,
vb_w: f64,
vb_h: f64,
style: &str,
) -> String {
format!(
"<svg id=\"{id}\" width=\"100%\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"max-width: {mw}px;\" viewBox=\"{vx} {vy} {vw} {vh}\" role=\"graphics-document document\" aria-roledescription=\"timeline\"><style>{style}</style><g></g><g></g>",
id = id,
mw = max_w,
vx = vb_x,
vy = vb_y,
vw = vb_w,
vh = vb_h,
style = style,
)
}
pub fn task_wrapper(x: f64, y: f64, svg: &str) -> String {
format!(
"<g class=\"taskWrapper\" transform=\"translate({x}, {y})\">{svg}</g>",
x = x,
y = y,
svg = svg,
)
}
pub fn event_wrapper(x: f64, y: f64, svg: &str) -> String {
format!(
"<g class=\"eventWrapper\" transform=\"translate({x}, {y})\">{svg}</g>",
x = x,
y = y,
svg = svg,
)
}
pub fn connector_line(x: f64, y1: f64, y2: f64, diagram_id: &str) -> String {
format!(
"<g class=\"lineWrapper\"><line x1=\"{x}\" y1=\"{y1}\" x2=\"{x}\" y2=\"{y2}\" style=\"stroke:black;stroke-width:2;stroke-dasharray:5,5;\" marker-end=\"url(#{id}-arrowhead)\"></line></g>",
x = x,
y1 = y1,
y2 = y2,
id = diagram_id,
)
}
pub fn node_group_open(section_class: i64) -> String {
format!(
"<g class=\"timeline-node section-{sc}\">\n",
sc = section_class,
)
}
pub fn node_bg_path(id_val: usize, path_d: &str) -> String {
format!(
" <path id=\"node-{id}\" class=\"node-bkg node-undefined\" d=\"{path}\"></path>\n",
id = id_val,
path = path_d,
)
}
pub fn node_separator_line(section_class: i64, height: f64, width: f64) -> String {
format!(
" <line class=\"node-line-{sc}\" x1=\"0\" y1=\"{h}\" x2=\"{w}\" y2=\"{h}\"></line>\n",
sc = section_class,
h = height,
w = width,
)
}
pub fn node_text_group(tx: f64, ty: f64, tspans: &str) -> String {
format!(
" <g transform=\"translate({tx}, {ty})\">{tspans}</g>\n",
tx = tx,
ty = ty,
tspans = tspans,
)
}
pub fn text_tspan(dy: &str, text: &str) -> String {
format!(
"<tspan x=\"0\" dy=\"{dy}\">{text}</tspan>",
dy = dy,
text = text,
)
}
#[allow(clippy::too_many_arguments)]
pub fn section_box(
x: f64,
y: f64,
path: &str,
color: &str,
line_class: i64,
height: f64,
width: f64,
line_color: &str,
text_x: f64,
text_y: f64,
text_color: &str,
label: &str,
) -> String {
let mut svg = String::new();
svg.push_str(&format!(
"<g transform=\"translate({x}, {y})\">\n",
x = x,
y = y,
));
svg.push_str(&format!(
" <path d=\"{path}\" style=\"fill:{color};stroke:{color};stroke-width:2px;\"/>\n",
path = path,
color = color,
));
svg.push_str(&format!(
" <line class=\"node-line-{cls}\" x1=\"0\" y1=\"{y}\" x2=\"{w}\" y2=\"{y}\" style=\"stroke:{lc};stroke-width:3;\"/>\n",
cls = line_class,
y = height,
w = width,
lc = line_color,
));
svg.push_str(&format!(
" <text x=\"{tx}\" y=\"{ty}\" class=\"section-label\" style=\"fill:{fc};\" text-anchor=\"middle\" dominant-baseline=\"middle\">{label}</text>\n",
tx = text_x,
ty = text_y,
fc = text_color,
label = label,
));
svg.push_str("</g>");
svg
}