stack_graphs/
visualization.rs1use serde_json::Error;
9
10use crate::arena::Handle;
11use crate::graph::File;
12use crate::graph::Node;
13use crate::graph::StackGraph;
14use crate::partial::PartialPath;
15use crate::partial::PartialPaths;
16use crate::serde::Filter;
17use crate::stitching::Database;
18
19static CSS: &'static str = include_str!("visualization/visualization.css");
20static D3: &'static str = include_str!("visualization/d3.min.js");
21static D3_DAG: &'static str = include_str!("visualization/d3-dag.min.js");
22static JS: &'static str = include_str!("visualization/visualization.js");
23
24static PKG: &'static str = env!("CARGO_PKG_NAME");
25static VERSION: &'static str = env!("CARGO_PKG_VERSION");
26
27impl StackGraph {
31 pub fn to_html_string(
32 &self,
33 title: &str,
34 partials: &mut PartialPaths,
35 db: &mut Database,
36 filter: &dyn Filter,
37 ) -> Result<String, Error> {
38 let filter = VisualizationFilter(filter);
39 let graph = serde_json::to_string(&self.to_serializable_filter(&filter))?;
40 let paths = serde_json::to_string(&db.to_serializable_filter(self, partials, &filter))?;
41 let html = format!(
42 r#"
43<!DOCTYPE html>
44<html lang="en">
45
46<head>
47
48<meta charset="utf-8">
49<title>{title}</title>
50
51<!-- <link href="visualization.css" type="text/css" rel="stylesheet"></link> -->
52<style>
53{CSS}
54</style>
55
56<!-- <script type="text/javascript" src="d3.v7.min.js"></script> -->
57<script type="text/javascript">
58{D3}
59</script>
60
61<!-- <script type="text/javascript" src="d3-dag.v0.10.0.min.js"></script> -->
62<script type="text/javascript">
63{D3_DAG}
64</script>
65
66<!-- <script type="text/javascript" src="visualization.js"></script> -->
67<script charset="utf-8">
68{JS}
69</script>
70
71<script type="text/javascript">
72 let graph = {graph};
73 let paths = {paths};
74</script>
75
76<style>
77 html, body, #container {{
78 width: 100%;
79 height: 100%;
80 margin: 0;
81 overflow: hidden;
82 }}
83</style>
84
85</head>
86
87<body>
88 <div id="container">
89 </div>
90 <script type="text/javascript">
91 const container = d3.select("\#container");
92 new StackGraph(container, graph, paths, {{ version: "{PKG} {VERSION}" }});
93 </script>
94</body>
95
96</html>
97"#
98 );
99 Ok(html)
100 }
101}
102
103struct VisualizationFilter<'a>(&'a dyn Filter);
104
105impl Filter for VisualizationFilter<'_> {
106 fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool {
107 self.0.include_file(graph, file)
108 }
109
110 fn include_node(&self, graph: &StackGraph, node: &Handle<Node>) -> bool {
111 self.0.include_node(graph, node)
112 }
113
114 fn include_edge(&self, graph: &StackGraph, source: &Handle<Node>, sink: &Handle<Node>) -> bool {
115 self.0.include_edge(graph, source, sink)
116 }
117
118 fn include_partial_path(
119 &self,
120 graph: &StackGraph,
121 paths: &PartialPaths,
122 path: &PartialPath,
123 ) -> bool {
124 self.0.include_partial_path(graph, paths, path)
125 && !path.edges.is_empty()
126 && path.starts_at_reference(graph)
127 && (path.ends_at_definition(graph) || path.ends_in_jump(graph))
128 }
129}