binary_search_tree_visualizer/visualizer/
svg.rs1use crate::tree::{BinarySearchTree, Node};
2use crate::Result;
3use crate::visualizer::TreeVisualizer;
4use svg::node::element::{Circle, Line, Text};
5use svg::Document;
6
7pub struct SvgVisualizer {
9 pub node_radius: f64,
10 pub level_height: f64,
11 pub horizontal_spacing: f64,
12}
13
14impl Default for SvgVisualizer {
15 fn default() -> Self {
16 Self {
17 node_radius: 20.0,
18 level_height: 60.0,
19 horizontal_spacing: 40.0,
20 }
21 }
22}
23
24impl<T: std::fmt::Display> TreeVisualizer<T> for SvgVisualizer {
25 fn visualize(&self, tree: &BinarySearchTree<T>) -> Result<String> {
26 let mut document = Document::new()
27 .set("width", "800")
28 .set("height", "600")
29 .set("viewBox", "0 0 800 600");
30
31 if let Some(root) = &tree.root {
32 let width = self.calculate_width(root);
33 let start_x = 400.0 - (width * self.horizontal_spacing) / 2.0;
34 self.draw_node(root, start_x, 50.0, &mut document);
35 }
36
37 Ok(document.to_string())
38 }
39}
40
41impl SvgVisualizer {
42 fn calculate_width<T>(&self, node: &Node<T>) -> f64 {
43 let left_width = if let Some(left) = &node.left {
44 self.calculate_width(left)
45 } else {
46 0.0
47 };
48 let right_width = if let Some(right) = &node.right {
49 self.calculate_width(right)
50 } else {
51 0.0
52 };
53 1.0 + left_width + right_width
54 }
55
56 fn draw_node<T: std::fmt::Display>(
57 &self,
58 node: &Node<T>,
59 x: f64,
60 y: f64,
61 document: &mut Document,
62 ) {
63 let circle = Circle::new()
65 .set("cx", x)
66 .set("cy", y)
67 .set("r", self.node_radius)
68 .set("fill", "white")
69 .set("stroke", "black")
70 .set("stroke-width", 2);
71
72 let text = Text::new()
74 .set("x", x)
75 .set("y", y + 5.0)
76 .set("text-anchor", "middle")
77 .set("font-size", "14")
78 .add(svg::node::Text::new(format!("{}", node.value)));
79
80 *document = document.clone().add(circle).add(text);
81
82 if let Some(left) = &node.left {
84 let left_x = x - self.horizontal_spacing;
85 let left_y = y + self.level_height;
86
87 let line = Line::new()
88 .set("x1", x)
89 .set("y1", y + self.node_radius)
90 .set("x2", left_x)
91 .set("y2", left_y - self.node_radius)
92 .set("stroke", "black")
93 .set("stroke-width", 2);
94
95 *document = document.clone().add(line);
96 self.draw_node(left, left_x, left_y, document);
97 }
98
99 if let Some(right) = &node.right {
100 let right_x = x + self.horizontal_spacing;
101 let right_y = y + self.level_height;
102
103 let line = Line::new()
104 .set("x1", x)
105 .set("y1", y + self.node_radius)
106 .set("x2", right_x)
107 .set("y2", right_y - self.node_radius)
108 .set("stroke", "black")
109 .set("stroke-width", 2);
110
111 *document = document.clone().add(line);
112 self.draw_node(right, right_x, right_y, document);
113 }
114 }
115}