summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/archweb.css12
-rw-r--r--media/visualize.js130
-rw-r--r--templates/visualize/index.html13
3 files changed, 148 insertions, 7 deletions
diff --git a/media/archweb.css b/media/archweb.css
index f4bb92fa..a354cb96 100644
--- a/media/archweb.css
+++ b/media/archweb.css
@@ -986,3 +986,15 @@ ul.signoff-list {
font-size: 0.85em;
line-height: 1em;
}
+
+#visualize-keys svg {
+ width: 100%;
+}
+
+ #visualize-keys circle {
+ stroke-width: 1.5px;
+ }
+
+ #visualize-keys line {
+ stroke: #888;
+ }
diff --git a/media/visualize.js b/media/visualize.js
index d9196d4d..e73171ea 100644
--- a/media/visualize.js
+++ b/media/visualize.js
@@ -1,5 +1,5 @@
function packages_treemap(chart_id, orderings, default_order) {
- var jq_div = $(chart_id),
+ var jq_div = jQuery(chart_id),
color = d3.scale.category20();
var key_func = function(d) { return d.key; };
var value_package_count = function(d) { return d.count; },
@@ -109,7 +109,7 @@ function packages_treemap(chart_id, orderings, default_order) {
});
};
- $.each(orderings, function(k, v) {
+ jQuery.each(orderings, function(k, v) {
make_group_button(k, v);
});
@@ -120,7 +120,131 @@ function packages_treemap(chart_id, orderings, default_order) {
.data(treemap.size([jq_div.width(), jq_div.height()]), key_func)
.call(cell);
};
- $(window).resize(function() {
+ jQuery(window).resize(function() {
+ if (resize_timeout) {
+ clearTimeout(resize_timeout);
+ }
+ resize_timeout = setTimeout(real_resize, 200);
+ });
+}
+
+function developer_keys(chart_id, data_url) {
+ var jq_div = jQuery(chart_id),
+ r = 10;
+
+ var force = d3.layout.force()
+ .gravity(0.1)
+ .charge(-200)
+ .linkStrength(0.2)
+ .size([jq_div.width(), jq_div.height()]);
+
+ var svg = d3.select(chart_id)
+ .append("svg");
+
+ d3.json(data_url, function(json) {
+ var fill = d3.scale.category20();
+
+ var index_for_key = function(key) {
+ var i;
+ key = key.slice(-8);
+ for (i = 0; i < json.nodes.length; i++) {
+ var node_key = json.nodes[i].key;
+ if (node_key && node_key.slice(-8) === key) {
+ return i;
+ }
+ }
+ };
+
+ /* filter edges to only include those that we have two nodes for */
+ var edges = jQuery.grep(json.edges, function(d, i) {
+ d.source = index_for_key(d.signer);
+ d.target = index_for_key(d.signee);
+ return d.source >= 0 && d.target >= 0;
+ });
+
+ jQuery.map(json.nodes, function(d, i) { d.master_sigs = 0; });
+ jQuery.map(edges, function(d, i) {
+ if (json.nodes[d.source].group === "master") {
+ json.nodes[d.target].master_sigs += 1;
+ }
+ });
+ jQuery.map(json.nodes, function(d, i) {
+ if (d.group === "dev" || d.group === "tu") {
+ d.approved = d.master_sigs >= 3;
+ } else {
+ d.approved = null;
+ }
+ });
+
+ var link = svg.selectAll("line")
+ .data(edges)
+ .enter()
+ .append("line");
+
+ var node = svg.selectAll("circle")
+ .data(json.nodes)
+ .enter().append("circle")
+ .attr("r", function(d) {
+ switch (d.group) {
+ case "master":
+ return r * 1.6 - 0.75;
+ case "cacert":
+ return r * 1.4 - 0.75;
+ case "dev":
+ case "tu":
+ default:
+ return r - 0.75;
+ }
+ })
+ .style("fill", function(d) { return fill(d.group); })
+ .style("stroke", function(d) {
+ if (d.approved === null) {
+ return d3.rgb(fill(d.group)).darker();
+ } else if (d.approved) {
+ return "green";
+ } else {
+ return "red";
+ }
+ })
+ .call(force.drag);
+ node.append("title").text(function(d) { return d.name; });
+
+ var distance = function(d, i) {
+ /* place a long line between all master keys and other keys.
+ * however, other connected clusters should be close together. */
+ if (d.source.group === "master" || d.target.group === "master") {
+ return 200;
+ } else {
+ return 50;
+ }
+ };
+
+ var tick = function() {
+ var offset = r * 2,
+ w = jq_div.width(),
+ h = jq_div.height();
+ node.attr("cx", function(d) { return (d.x = Math.max(offset, Math.min(w - offset, d.x))); })
+ .attr("cy", function(d) { return (d.y = Math.max(offset, Math.min(h - offset, d.y))); });
+
+ link.attr("x1", function(d) { return d.source.x; })
+ .attr("y1", function(d) { return d.source.y; })
+ .attr("x2", function(d) { return d.target.x; })
+ .attr("y2", function(d) { return d.target.y; });
+ };
+
+ force.nodes(json.nodes)
+ .links(edges)
+ .linkDistance(distance)
+ .on("tick", tick)
+ .start();
+ });
+
+ var resize_timeout = null;
+ var real_resize = function() {
+ resize_timeout = null;
+ force.size([jq_div.width(), jq_div.height()]);
+ };
+ jQuery(window).resize(function() {
if (resize_timeout) {
clearTimeout(resize_timeout);
}
diff --git a/templates/visualize/index.html b/templates/visualize/index.html
index 99525e69..b9459318 100644
--- a/templates/visualize/index.html
+++ b/templates/visualize/index.html
@@ -4,10 +4,7 @@
{% block content %}
<div class="box">
-
- <h2>Visualizations of Packaging Data</h2>
-
- <h3>Package Treemap</h3>
+ <h2>Visualization of Package Data</h2>
<div class="visualize-buttons">
<div>
@@ -25,9 +22,16 @@
</div>
<div id="visualize-archrepo" class="visualize-chart"></div>
</div>
+{% comment %}
+<div class="box">
+ <h2>Visualization of PGP Master and Signing Keys</h2>
+ <div id="visualize-keys" class="visualize-chart"></div>
+</div>
+{% endcomment %}
{% load cdn %}{% jquery %}
<script type="text/javascript" src="/media/d3.min.js"></script>
+<script type="text/javascript" src="/media/d3.geom.min.js"></script>
<script type="text/javascript" src="/media/d3.layout.min.js"></script>
<script type="text/javascript" src="/media/archweb.js"></script>
<script type="text/javascript" src="/media/visualize.js"></script>
@@ -38,6 +42,7 @@ $(document).ready(function() {
"arch": { url: "{% url visualize-byarch %}", color_attr: "arch" },
};
packages_treemap("#visualize-archrepo", orderings, "repo");
+ /*developer_keys("#visualize-keys", "{% url visualize-pgp_keys %}");*/
});
</script>
{% endblock %}