spice up collections graph a little
authorTom Clegg <tom@clinicalfuture.com>
Fri, 1 Feb 2013 00:29:53 +0000 (16:29 -0800)
committerTom Clegg <tom@clinicalfuture.com>
Fri, 1 Feb 2013 00:29:53 +0000 (16:29 -0800)
app/views/collections/index.html.erb

index 677face1f802a93dbf4ea386151b7c736200f306..87f07eae1840ace6cf91e5c8e71712325332ae96 100644 (file)
@@ -9,11 +9,7 @@ path.link {
   stroke-width: 1.5px;
 }
 
-marker#can_read {
-  fill: green;
-}
-
-path.link.can_read {
+path.link.derived_from {
   stroke: green;
   stroke-dasharray: 0,4 1;
 }
@@ -31,7 +27,7 @@ path.link.created {
   stroke: red;
 }
 
-circle {
+circle.node {
   fill: #ccc;
   stroke: #333;
   stroke-width: 1.5px;
@@ -61,111 +57,125 @@ text.shadow {
 
 jQuery(function($){
 
-var links = <%= raw d3ify_links(@links).to_json %>;
-
-var nodes = {};
-
-// Compute the distinct nodes from the links.
-links.forEach(function(link) {
-  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
-  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
-});
-
-var w = 960,
+    var links = <%= raw d3ify_links(@links).to_json %>;
+
+    var nodes = {};
+
+    // Compute the distinct nodes from the links.
+    links.forEach(function(link) {
+       link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
+       link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
+    });
+
+    var fill_for = {'ldvyl': 'green',
+                   'j58dm': 'red',
+                   '4zz18': 'blue'};
+    jQuery.each(nodes, function(i, node) {
+       var m = node.name.match(/-([a-z0-9]{5})-/)
+       if (m)
+           node.fill = fill_for[m[1]] || '#ccc';
+       else if (node.name.match(/^[0-9a-f]{32}/))
+           node.fill = fill_for['4zz18'];
+       else
+           node.fill = '#ccc';
+    });
+
+    var w = 960,
     h = 600;
 
-var force = d3.layout.force()
-    .nodes(d3.values(nodes))
-    .links(links)
-    .size([w, h])
-    .linkDistance(250)
-    .charge(-300)
-    .on("tick", tick)
-    .start();
-
-var svg = d3.select("body").append("svg:svg")
-    .attr("width", w)
-    .attr("height", h);
-
-// Per-type markers, as they don't inherit styles.
-svg.append("svg:defs").selectAll("marker")
-    .data(["created", "member_of", "can_read", "can_write"])
-  .enter().append("svg:marker")
-    .attr("id", String)
-    .attr("viewBox", "0 -5 10 10")
-    .attr("refX", 15)
-    .attr("refY", -1.5)
-    .attr("markerWidth", 6)
-    .attr("markerHeight", 6)
-    .attr("orient", "auto")
-  .append("svg:path")
-    .attr("d", "M0,-5L10,0L0,5");
-
-var path = svg.append("svg:g").selectAll("path")
-    .data(force.links())
-  .enter().append("svg:path")
-    .attr("class", function(d) { return "link " + d.type; })
-    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
-
-var circle = svg.append("svg:g").selectAll("circle")
-    .data(force.nodes())
-  .enter().append("svg:circle")
-    .attr("r", 6)
-    .call(force.drag);
-
-var text = svg.append("svg:g").selectAll("g")
-    .data(force.nodes())
-  .enter().append("svg:g");
-
-// A copy of the text with a thick white stroke for legibility.
-text.append("svg:text")
-    .attr("x", 8)
-    .attr("y", ".31em")
-    .attr("class", "shadow")
-    .text(function(d) { return d.name; });
-
-text.append("svg:text")
-    .attr("x", 8)
-    .attr("y", ".31em")
-    .text(function(d) { return d.name; });
-
-var edgetext = svg.append("svg:g").selectAll("g")
-    .data(force.links())
-    .enter().append("svg:g");
-
-edgetext
-    .append("svg:text")
-    .attr("x",0)
-    .attr("y","-0.2em")
-    .text(function(d) { return d.type; });
-
-// Use elliptical arc path segments to doubly-encode directionality.
-function tick() {
-  path.attr("d", function(d) {
-    var dx = d.target.x - d.source.x,
-        dy = d.target.y - d.source.y,
-        // dr = Math.sqrt(dx * dx + dy * dy);
-        dr = 0;
-    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
-  });
-
-  circle.attr("transform", function(d) {
-    return "translate(" + d.x + "," + d.y + ")";
-  });
-
-  text.attr("transform", function(d) {
-    return "translate(" + d.x + "," + d.y + ")";
-  });
-
-  edgetext.attr("transform", function(d) {
-      return "translate(" +
-         (d.source.x + d.target.x)/2 + "," +
-         (d.source.y + d.target.y)/2 +
-         ")rotate(" +
-         (Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) * 180 / Math.PI) +
-         ")";
-  });
-}
+    var force = d3.layout.force()
+       .nodes(d3.values(nodes))
+       .links(links)
+       .size([w, h])
+       .linkDistance(150)
+       .charge(-300)
+       .on("tick", tick)
+       .start();
+
+    var svg = d3.select("body").append("svg:svg")
+       .attr("width", w)
+       .attr("height", h);
+
+    // Per-type markers, as they don't inherit styles.
+    svg.append("svg:defs").selectAll("marker")
+       .data(["member_of", "owner", "derived_from"])
+       .enter().append("svg:marker")
+       .attr("id", String)
+       .attr("viewBox", "0 -5 10 10")
+       .attr("refX", 15)
+       .attr("refY", -1.5)
+       .attr("markerWidth", 6)
+       .attr("markerHeight", 6)
+       .attr("orient", "auto")
+       .append("svg:path")
+       .attr("d", "M0,-5L10,0L0,5");
+
+    var path = svg.append("svg:g").selectAll("path")
+       .data(force.links())
+       .enter().append("svg:path")
+       .attr("class", function(d) { return "link " + d.type; })
+       .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
+
+    var circle = svg.append("svg:g").selectAll("circle")
+       .data(force.nodes())
+       .enter().append("svg:circle")
+       .attr("r", 6)
+       .style("fill", function(d) { return d.fill; })
+       .call(force.drag);
+
+    var text = svg.append("svg:g").selectAll("g")
+       .data(force.nodes())
+       .enter().append("svg:g");
+
+    // A copy of the text with a thick white stroke for legibility.
+    text.append("svg:text")
+       .attr("x", 8)
+       .attr("y", ".31em")
+       .attr("class", "shadow")
+       .text(function(d) { return d.name.replace(/^([0-9a-z]{5}-){2}/,''); });
+
+    text.append("svg:text")
+       .attr("x", 8)
+       .attr("y", ".31em")
+       .text(function(d) { return d.name.replace(/^([0-9a-z]{5}-){2}/,''); });
+
+    var edgetext = svg.append("svg:g").selectAll("g")
+       .data(force.links())
+       .enter().append("svg:g");
+
+    edgetext
+       .append("svg:text")
+       .attr("x","-5em")
+       .attr("y","-0.2em")
+       .text(function(d) { return d.type; });
+
+    // Use elliptical arc path segments to doubly-encode directionality.
+    function tick() {
+       path.attr("d", function(d) {
+           var dx = d.target.x - d.source.x,
+            dy = d.target.y - d.source.y,
+            // dr = Math.sqrt(dx * dx + dy * dy);
+            dr = 0;
+           return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
+       });
+
+       circle.attr("transform", function(d) {
+           return "translate(" + d.x + "," + d.y + ")";
+       });
+
+       text.attr("transform", function(d) {
+           return "translate(" + d.x + "," + d.y + ")";
+       });
+
+       edgetext.attr("transform", function(d) {
+           return "translate(" +
+               (d.source.x + d.target.x)/2 + "," +
+               (d.source.y + d.target.y)/2 +
+               ")rotate(" +
+               (Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) * 180 / Math.PI) +
+               ")";
+       });
+    }
 
 })(jQuery);
 <% end %>