///|
fn escape_xml(text : String) -> String {
let sb = StringBuilder::new()
for c in text {
match c {
'&' => sb.write_view("&")
'<' => sb.write_view("<")
'>' => sb.write_view(">")
'"' => sb.write_view(""")
'\'' => sb.write_view("'")
_ => sb.write_char(c)
}
}
sb.to_string()
}
///|
fn arrow_marker_defs(color : String) -> String {
"\n \n \n \n\n"
}
///|
fn to_px_x(x : Int) -> Double {
x.to_double() * cell_px
}
///|
fn to_px_y(y : Int) -> Double {
y.to_double() * cell_py
}
///|
fn svg_edge_path(start : Point, end_ : Point, direction : Direction) -> String {
let x1 = to_px_x(start.x)
let y1 = to_px_y(start.y)
let x2 = to_px_x(end_.x)
let y2 = to_px_y(end_.y)
if x1 == x2 || y1 == y2 {
"M \{x1} \{y1} L \{x2} \{y2}"
} else {
match direction {
Direction::TD | Direction::BT => {
let mid_y = (y1 + y2) / 2.0
"M \{x1} \{y1} C \{x1} \{mid_y}, \{x2} \{mid_y}, \{x2} \{y2}"
}
Direction::LR | Direction::RL => {
let mid_x = (x1 + x2) / 2.0
"M \{x1} \{y1} C \{mid_x} \{y1}, \{mid_x} \{y2}, \{x2} \{y2}"
}
}
}
}
///|
fn svg_open(
width_px : Double,
height_px : Double,
transparent : Bool,
bg : String,
) -> String {
let sb = StringBuilder::new()
sb.write_view(
"")
sb.to_string()
}
///|
fn render_sequence_svg(
diagram : SequenceDiagram,
options : SvgOptions,
) -> String {
let ascii_opts = default_ascii_options()
let layout = layout_sequence(diagram, ascii_opts)
let colors = build_colors(options)
let font = resolve_font(options)
let transparent = resolve_transparent(options)
let pad = 20.0
let width_px = to_px_x(layout.width) + pad * 2
let height_px = to_px_y(layout.height) + pad * 2
let font_size = cell_py * 0.8
let sb = StringBuilder::new()
sb.write_view(svg_open(width_px, height_px, transparent, colors.bg))
sb.write_view(arrow_marker_defs(colors.accent))
sb.write_view("\n")
sb.write_view("\n")
for actor in layout.actors {
let b = actor.box
let cx = to_px_x(b.x) + to_px_x(b.width) / 2.0
let y_start = to_px_y(b.y) + to_px_y(b.height)
let y_end = to_px_y(layout.height)
sb.write_view(
"\n",
)
}
sb.write_view("\n")
sb.write_view("\n")
for actor in layout.actors {
let b = actor.box
let x = to_px_x(b.x)
let y = to_px_y(b.y)
let w = to_px_x(b.width)
let h = to_px_y(b.height)
sb.write_view(
"\n",
)
let tx = x + w / 2.0
let ty = y + h / 2.0
sb.write_view(
"\{escape_xml(actor.actor.label)}\n",
)
}
sb.write_view("\n")
sb.write_view("\n")
for msg in layout.messages {
let x1 = to_px_x(msg.start.x)
let y1 = to_px_y(msg.start.y)
let x2 = to_px_x(msg.end.x)
let y2 = to_px_y(msg.end.y)
let dash = if msg.message.dashed { " stroke-dasharray=\"5,3\"" } else { "" }
sb.write_view(
"\n",
)
if msg.message.text.length() > 0 {
let tx = (x1 + x2) / 2.0
let ty = y1 - font_size * 0.5
let text_w = msg.message.text.length().to_double() * font_size * 0.55
sb.write_view(
"\n",
)
sb.write_view(
"\{escape_xml(msg.message.text)}\n",
)
}
}
sb.write_view("\n")
sb.write_view("\n")
sb.write_view("")
sb.to_string()
}