aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html')
-rw-r--r--framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html371
1 files changed, 371 insertions, 0 deletions
diff --git a/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html b/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html
new file mode 100644
index 00000000..be0b581c
--- /dev/null
+++ b/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html
@@ -0,0 +1,371 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>TITLE_PLACEHOLDER</title>
+ <style>
+
+ .node {
+ font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ fill: #bbb;
+ }
+
+ .link {
+ stroke: steelblue;
+ stroke-opacity: .4;
+ fill: none;
+ pointer-events: none;
+ }
+
+ .node--focus {
+ font-weight: 700;
+ fill: #000;
+ }
+
+ .node:hover {
+ fill: steelblue;
+ }
+
+ .node:hover,
+ .node--source,
+ .node--target {
+ font-weight: 700;
+ }
+
+ .node--source {
+ fill: #2ca02c;
+ }
+
+ .node--target {
+ fill: #d59800;
+ }
+
+ .link--source,
+ .link--target {
+ stroke-opacity: 1;
+ stroke-width: 3px;
+ }
+
+ .link--source {
+ stroke: #d59800;
+ }
+
+ .link--target {
+ stroke: #2ca02c;
+ }
+
+ .link--cycle {
+ stroke: #ff0000;
+ }
+
+ .summary {
+ font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ position: fixed;
+ top: 32px;
+ right: 32px;
+ width: 192px;
+ background-color: #ffffff;
+ box-shadow: 2px 2px 4px 2px #777777;
+ padding: 5px;
+ }
+
+ .details {
+ display: none;
+ font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ position: fixed;
+ top: 220px;
+ right: 32px;
+ width: 192px;
+ background-color: #ffffff;
+ box-shadow: 2px 2px 4px 2px #777777;
+ padding: 5px;
+ }
+
+ .shown {
+ display:block;
+ }
+
+ .stat {
+ text-align: right;
+ width: 64px;
+ }
+
+ .title {
+ font-size: 16px;
+ font-weight: bold;
+ }
+
+ #package {
+ font-size: 14px;
+ font-weight: bold;
+ }
+ </style>
+</head>
+<body>
+ <div class="summary">
+ <div class="title">Project TITLE_PLACEHOLDER</div>
+ <table>
+ <tr>
+ <td>Sources:</td>
+ <td id="sourceCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Packages:</td>
+ <td id="packageCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Cyclic Segments:</td>
+ <td id="segmentCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Cycles:</td>
+ <td id="cycleCount" class="stat"></td>
+ </tr>
+ </table>
+ <div><hr size="1"></div>
+ <div><input type="checkbox"> Highlight cycles</input></div>
+ <div><input style="width: 95%" type="range" min="0" max="100" value="75"></div>
+ </div>
+ <div class="details">
+ <div id="package">Package Details</div>
+ <table>
+ <tr>
+ <td>Sources:</td>
+ <td id="psourceCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Dependents:</td>
+ <td id="pdependentCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Cyclic Segments:</td>
+ <td id="psegmentCount" class="stat"></td>
+ </tr>
+ <tr>
+ <td>Cycles:</td>
+ <td id="pcycleCount" class="stat"></td>
+ </tr>
+ </table>
+ </div>
+<script>
+D3JS_PLACEHOLDER
+
+ var catalog =
+DATA_PLACEHOLDER
+ ;
+
+ var diameter = 1000,
+ radius = diameter / 2,
+ innerRadius = radius - 300;
+
+ var cluster = d3.layout.cluster()
+ .size([360, innerRadius])
+ .sort(null)
+ .value(function(d) { return d.size; });
+
+ var bundle = d3.layout.bundle();
+
+ var line = d3.svg.line.radial()
+ .interpolate("bundle")
+ .tension(.75)
+ .radius(function(d) { return d.y; })
+ .angle(function(d) { return d.x / 180 * Math.PI; });
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", diameter)
+ .attr("height", diameter)
+ .append("g")
+ .attr("transform", "translate(" + radius + "," + radius + ")");
+
+ var link = svg.append("g").selectAll(".link"),
+ node = svg.append("g").selectAll(".node"),
+ cycles = {}, highlightCycles, selectedNode;
+
+ function isCyclicLink(l) {
+ return highlightCycles &&
+ (cycles[l.source.key + "-" + l.target.key] || cycles[l.target.key + "-" + l.source.key]);
+ }
+
+ function isCyclicPackageLink(l, p) {
+ var key = l.source.key + "-" + l.target.key,
+ rKey = l.target.key + "-" + l.source.key;
+ return isCyclicLink(l) && (p.cycleSegments[key] || p.cycleSegments[rKey]);
+ }
+
+ function refreshPaths() {
+ svg.selectAll("path.link").classed("link--cycle", isCyclicLink);
+ }
+
+ function processCatalog() {
+ var nodes = cluster.nodes(packageHierarchy(catalog.packages)),
+ links = packageImports(nodes),
+ splines = bundle(links);
+ cycles = catalog.cycleSegments;
+
+ d3.select("input[type=checkbox]").on("change", function() {
+ highlightCycles = this.checked;
+ refreshPaths();
+ });
+
+ link = link
+ .data(splines)
+ .enter().append("path")
+ .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; })
+ .attr("class", "link")
+ .classed("link--cycle", isCyclicLink)
+ .attr("d", function(d, i) { return line(splines[i]); });
+
+
+ node = node
+ .data(nodes.filter(function(n) { return !n.children; }))
+ .enter().append("text")
+ .attr("class", "node")
+ .attr("dy", ".31em")
+ .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); })
+ .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
+ .text(function(d) { return d.key; })
+ .on("focus", processSelect)
+ .on("blur", processSelect);
+
+ d3.select("input[type=range]").on("change", function() {
+ line.tension(this.value / 100);
+ svg.selectAll("path.link")
+ .data(splines)
+ .attr("d", function(d, i) { return line(splines[i]); });
+ });
+
+ d3.select("#packageCount").text(catalog.summary.packages);
+ d3.select("#sourceCount").text(catalog.summary.sources);
+ d3.select("#segmentCount").text(catalog.summary.cycleSegments);
+ d3.select("#cycleCount").text(catalog.summary.cycles);
+ }
+
+ function processSelect(d) {
+ if (selectedNode === d) {
+ deselected(d);
+ selectedNode = null;
+
+ } else if (selectedNode) {
+ deselected(selectedNode);
+ selectedNode = null;
+ selected(d);
+
+ } else {
+ selected(d);
+ selectedNode = d;
+ }
+ }
+
+ function selected(d) {
+ node
+ .each(function(n) { n.target = n.source = false; })
+ .classed("node--focus", function(n) { return n === d; });
+
+ link
+ .classed("link--cycle", function(l) { return isCyclicPackageLink(l, d); })
+ .classed("link--target", function(l) { if (l.target === d) return l.source.source = true; })
+ .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; })
+ .filter(function(l) { return l.target === d || l.source === d; })
+ .each(function() { this.parentNode.appendChild(this); });
+
+ node
+ .classed("node--target", function(n) { return n.target; })
+ .classed("node--source", function(n) { return n.source; });
+
+ d3.select("#psourceCount").text(d.size);
+ d3.select("#pdependentCount").text(d.imports.length);
+ d3.select("#psegmentCount").text(d.cycleSegmentCount);
+ d3.select("#pcycleCount").text(d.cycleCount);
+ d3.select(".details").classed("shown", function() { return true; });
+ }
+
+ function deselected(d) {
+ link
+ .classed("link--cycle", isCyclicLink)
+ .classed("link--target", false)
+ .classed("link--source", false);
+
+ node
+ .classed("node--target", false)
+ .classed("node--source", false)
+ .classed("node--focus", false);
+ d3.select(".details").classed("shown", function() { return false; });
+ }
+
+ d3.select(self.frameElement).style("height", diameter + "px");
+
+ // Lazily construct the package hierarchy.
+ function packageHierarchy(packages) {
+ var map = {}, cnt = 0;
+
+ // Builds the structure top-down to the specified leaf or until
+ // another leaf in which case hook this leaf to the same parent
+ function buildHierarchy(leaf, i) {
+ var leafName = leaf.name,
+ node, name, parent = map[""], start = 0;
+ while (start < leafName.length) {
+ name = parentName(leafName, start);
+ node = map[name];
+ if (!node) {
+ node = map[name] = parentNode(name, parent);
+ parent.children.push(node);
+
+ } else if (node.imports) {
+ leaf.parent = parent;
+ parent.children.push(leaf);
+ break;
+ }
+ parent = node;
+ start = name.length + 1;
+ }
+ }
+
+ function parentNode(name, parent) {
+ return {name: name, parent: parent, key: name, children: []};
+ }
+
+ function parentName(leafName, start) {
+ var i = leafName.indexOf(".", start);
+ return i > 0 ? leafName.substring(0, i) : leafName;
+ }
+
+ // First populate all packages as leafs
+ packages.forEach(function(d) {
+ map[d.name] = d;
+ d.key = d.name;
+ });
+
+ // Next synthesize the intermediate structure, by-passing any leafs
+ map[""] = parentNode("", null);
+ var i = 0;
+ packages.forEach(function(d) {
+ buildHierarchy(d, i++);
+ });
+
+ return map[""];
+ }
+
+ // Return a list of imports for the given array of nodes.
+ function packageImports(nodes) {
+ var map = {},
+ imports = [];
+
+ // Compute a map from name to node.
+ nodes.forEach(function(d) {
+ map[d.name] = d;
+ });
+
+ // For each import, construct a link from the source to target node.
+ nodes.forEach(function(d) {
+ if (d.imports) d.imports.forEach(function(i) {
+ imports.push({source: map[d.name], target: map[i]});
+ });
+ });
+
+ return imports;
+ }
+
+ processCatalog();
+</script>
+</body>
+</html>