stack_graphs/
visualization.rs

1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2022, stack-graphs authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8use 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
27//-----------------------------------------------------------------------------
28// StackGraph
29
30impl 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}