added method to plot the blips
authorBruno Trecenti <btrecent@thoughtworks.com>
Wed, 26 Feb 2014 22:36:45 +0000 (19:36 -0300)
committerBruno Trecenti <btrecent@thoughtworks.com>
Wed, 26 Feb 2014 22:36:45 +0000 (19:36 -0300)
examples/default.html
src/graphing/radar.js

index e302073..c3f5843 100644 (file)
@@ -2,6 +2,7 @@
 <html lang="en">
 <head>
   <meta charset="utf-8">
+  <title>Thoughtworks Radar 2014</title>
   <script src="../bower_components/d3/d3.min.js"></script>
   <script src="../src/namespaces.js"></script>
   <script src="../src/util/fib.js"></script>
     svg {
       padding: 20px;
     }
-    svg circle {
-      stroke: #fff;
+    svg circle:nth-child(1) {
+      fill: #eaeaea;
+    }
+    svg circle:nth-child(2) {
+      fill: #dadada;
+    }
+    svg circle:nth-child(3) {
       fill: #cacaca;
     }
+    svg circle:nth-child(4) {
+      fill: #bababa;
+    }
     svg text {
       font: 11px 'Open Sans';
       font-variant: small-caps;
@@ -25,7 +34,7 @@
       fill: #000;
     }
     svg line {
-      stroke: #fff;
+      stroke: rgba(255, 255, 255, 0.3);
     }
 
   </style>
 
     var radar = new tr.models.Radar();
     var toolsQuadrant = new tr.models.Quadrant('Tools');
+    var techniquesQuadrant = new tr.models.Quadrant('Techniques');
+    var platformsQuadrant = new tr.models.Quadrant('Platforms');
+    var languageFramework = new tr.models.Quadrant('Languages & Frameworks');
+
     toolsQuadrant.add([
-        new tr.models.Blip('A', adopt),
-        new tr.models.Blip('B', trial),
-        new tr.models.Blip('C', assess),
-        new tr.models.Blip('D', hold)
+        new tr.models.Blip('D3', adopt),
+        new tr.models.Blip('Dependency Management for JavaScript', adopt, true),
+        new tr.models.Blip('Ansible', trial, true),
+        new tr.models.Blip('Calabash', trial, true),
+        new tr.models.Blip('Chaos Monkey', trial, true),
+        new tr.models.Blip('Gatling', trial),
+        new tr.models.Blip('Grunt.js', trial, true),
+        new tr.models.Blip('Hystrix', trial),
+        new tr.models.Blip('Icon fonts', trial),
+        new tr.models.Blip('Librarian-puppet and Librarian-Chef', trial),
+        new tr.models.Blip('Logstash & Graylog2', trial),
+        new tr.models.Blip('Moco', trial, true),
+        new tr.models.Blip('PhantomJS', trial),
+        new tr.models.Blip('Prototype On Paper', trial, true),
+        new tr.models.Blip('SnapCI', trial, true),
+        new tr.models.Blip('Snowplow Analytics & Piwik', trial),
+        new tr.models.Blip('Cloud-init', assess, true),
+        new tr.models.Blip('Docker', assess, true),
+        new tr.models.Blip('Octopus', assess),
+        new tr.models.Blip('Sensu', assess, true),
+        new tr.models.Blip('Travis for OSX/iOS', assess, true),
+        new tr.models.Blip('Visual regression testing tools', assess, true),
+        new tr.models.Blip('Xamarin', assess, true),
+        new tr.models.Blip('Ant', hold, true),
+        new tr.models.Blip('Heavyweight test tools', hold),
+        new tr.models.Blip('TFS', hold)
     ]);
+    techniquesQuadrant.add([
+        new tr.models.Blip('Capturing client-side JavaScript errors', adopt),
+        new tr.models.Blip('Continuous delivery for mobile devices', adopt),
+        new tr.models.Blip('Mobile testing on mobile networks', adopt),
+        new tr.models.Blip('Segregated DOM plus node for JS Testing', adopt, true),
+        new tr.models.Blip('Windows infrastructure automation', adopt),
+        new tr.models.Blip('Capture domain events explicitily', trial, true),
+        new tr.models.Blip('Client and server rendering with same code', trial, true),
+        new tr.models.Blip('HTML5 storage instead of cookies', trial),
+        new tr.models.Blip('Instrument all the things', trial, true),
+        new tr.models.Blip('Masterless Chef/Puppet', trial, true),
+        new tr.models.Blip('Micro-services', trial),
+        new tr.models.Blip('Perimeterless enterprise', trial),
+        new tr.models.Blip('Provisioning testing', trial, true),
+        new tr.models.Blip('Structured logging', trial, true),
+        new tr.models.Blip('Bridging physical and digital worlds with simple hardware', assess, true),
+        new tr.models.Blip('Collaborative analytics and data science', assess),
+        new tr.models.Blip('Datensparsamkeit', assess, true),
+        new tr.models.Blip('Development environments in the cloud', assess),
+        new tr.models.Blip('Focus on mean time to recovery', assess),
+        new tr.models.Blip('Machine image as a build artifact', assess),
+        new tr.models.Blip('Tangible interaction', assess, true),
+        new tr.models.Blip('Cloud lift and shift', hold, true),
+        new tr.models.Blip('Ignoring OWASP Top 10', hold, true),
+        new tr.models.Blip('Siloed metrics', hold, true),
+        new tr.models.Blip('Velocity as productivity', hold, true)
+    ]);
+    platformsQuadrant.add([
+        new tr.models.Blip('Elastic Search', adopt),
+        new tr.models.Blip('MongoDB', adopt),
+        new tr.models.Blip('Neo4J', adopt),
+        new tr.models.Blip('Node.js', adopt),
+        new tr.models.Blip('Redis', adopt),
+        new tr.models.Blip('SMS and USSD as UI', adopt),
+        new tr.models.Blip('Hadoop 2.0', trial),
+        new tr.models.Blip('Hadoop as a service', trial, true),
+        new tr.models.Blip('Open Stack', trial),
+        new tr.models.Blip('PostgreSQL for NoSql', trial),
+        new tr.models.Blip('Vumi', trial),
+        new tr.models.Blip('Akka', assess, true),
+        new tr.models.Blip('Backend as a service', assess, true),
+        new tr.models.Blip('Low-cost robotics', assess, true),
+        new tr.models.Blip('PhoneGap/Apache Cordova', assess),
+        new tr.models.Blip('Private Clouds', assess),
+        new tr.models.Blip('SPDY', assess, true),
+        new tr.models.Blip('Storm', assess, true),
+        new tr.models.Blip('Web Components standard', assess, true),
+        new tr.models.Blip('Big enterprise solutions', hold),
+        new tr.models.Blip('CMS as a platform', hold, true),
+        new tr.models.Blip('Enterprise Data Warehouse', hold, true)
+    ]);
+    languageFramework.add([
+        new tr.models.Blip('Clojure', adopt),
+        new tr.models.Blip('Dropwizard', adopt),
+        new tr.models.Blip('Scala, the good parts', adopt),
+        new tr.models.Blip('Sinatra', adopt),
+        new tr.models.Blip('CoffeeScript', trial),
+        new tr.models.Blip('Go language', trial, true),
+        new tr.models.Blip('Hive', trial, true),
+        new tr.models.Blip('Play Framework 2', trial),
+        new tr.models.Blip('Reactive Extensions across languages', trial, true),
+        new tr.models.Blip('Web API', trial, true),
+        new tr.models.Blip('Elixir', assess, true),
+        new tr.models.Blip('Julia', assess, true),
+        new tr.models.Blip('Nancy', assess),
+        new tr.models.Blip('OWIN', assess),
+        new tr.models.Blip('Pester', assess, true),
+        new tr.models.Blip('Pointer Events', assess, true),
+        new tr.models.Blip('Python 3', assess, true),
+        new tr.models.Blip('TypeScript', assess, true),
+        new tr.models.Blip('Yeoman', assess, true),
+        new tr.models.Blip('Handwritten CSS', hold),
+        new tr.models.Blip('JSF', hold, true)
+    ]);
+
     radar.setFirstQuadrant(toolsQuadrant);
+    radar.setSecondQuadrant(techniquesQuadrant);
+    radar.setThirdQuadrant(platformsQuadrant);
+    radar.setFourthQuadrant(languageFramework);
 
     var radarGraph = new tr.graphing.Radar(d3.select("body").append("svg"), 800, radar);
     radarGraph.plot();
index 704c572..10e2483 100644 (file)
@@ -63,12 +63,46 @@ tr.graphing.Radar = function (svg, size, radar) {
     });
   };
 
+  function random(min, max) {
+    return Math.floor(Math.random() * (max - min + 1)) + min;
+  }
+
+  function plotBlips(cycles, blips, adjustX, adjustY) {
+    cycles.forEach(function (cycle, i) {
+      var maxRadius, minRadius, cycleBlips;
+
+      maxRadius = getRadius(cycles, i);
+      minRadius = (i == cycles.length - 1) ? 0: getRadius(cycles, i + 1);
+
+      var cycleBlips = blips.filter(function (blip) {
+        return blip.cycle() == cycle;
+      });
+
+      cycleBlips.forEach(function (blip) {
+        var angleInRad, radius;
+
+        angleInRad = Math.PI * random(5, 85) / 180;
+        radius = random(minRadius + 5, maxRadius - 5);
+
+        svg.append('circle')
+          .attr('cx', center() + radius * Math.cos(angleInRad) * adjustX)
+          .attr('cy', center() + radius * Math.sin(angleInRad) * adjustY)
+          .attr('r', 5)
+          .append('title').text(blip.name());
+      });
+    });
+  };
+
   self.plot = function () {
     var cycles = radar.cycles().reverse();
 
     plotCircles(cycles);
     plotLines();
     plotTexts(cycles);
+    plotBlips(cycles, radar.quadrants().I.blips(), 1, -1);
+    plotBlips(cycles, radar.quadrants().II.blips(), -1, -1);
+    plotBlips(cycles, radar.quadrants().III.blips(), -1, 1);
+    plotBlips(cycles, radar.quadrants().IV.blips(), 1, 1);
   };
 
   return self;