--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Tech Radar Example</title>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,700italic,400,300,700' rel='stylesheet' type='text/css'>
+ <script src="chance.js"></script>
+ <script src="d3.min.js"></script>
+ <script src="d3-queue.js"></script>
+ <script src="tech-radar.min.js"></script>
+ <link href="base.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+ <div id="radar">
+ </div>
+ <div id="ref-table"></div>
+</body>
+<script>
+// var adopt = new tr.models.Cycle('Adopt', 0);
+// var trial = new tr.models.Cycle('Trial', 1);
+// var assess = new tr.models.Cycle('Assess', 2);
+// var hold = new tr.models.Cycle('Hold', 3);
+
+
+ function processRows(data) {
+
+ var adopt = new tr.models.Cycle('Adopt', 0);
+ var trial = new tr.models.Cycle('Trial', 1);
+ var assess = new tr.models.Cycle('Assess', 2);
+ var hold = new tr.models.Cycle('Hold', 3);
+ var cycles = [adopt, trial, assess, hold];
+
+ error = "";
+ var blips = {};
+ blips["tool"] = [];
+ blips["technique"] = [];
+ blips["platform"] = [];
+ blips["language"] = [];
+ for (var i=0; i < data.length; i++) {
+ row = data[i];
+
+ idx_cycle = ["adapt", "trial", "assess", "hold"].indexOf(row.cycle)
+
+ if (idx_cycle === -1) {
+ error += "Unexpected cycle: " + row.cycle + " in row " + i.toString() + "<br />";
+ } else if (["tool", "technique", "platform", "language"].indexOf(row.quadrant) === -1) {
+ error += "Unexpected quadrant: " + row.quadrant + " in row " + i.toString() + "<br />";
+ } else if (["true","false"].indexOf(row.is_new) === -1) {
+ error += "Unboolean is_new: " + row.is_new + " in row " + i.toString() + "<br />";
+ } else {
+ if (row.is_new === "true") {
+ b_IsNew = true
+ } else {
+ b_IsNew = false
+ }
+ a_cycle = cycles[idx_cycle];
+ a_blip = new tr.models.Blip(row.name, a_cycle, b_IsNew, row.description);
+ blips[row.quadrant].push(a_blip);
+ }
+ }
+ if (error !== "") {
+ throw error
+ }
+ return blips;
+ }
+
+ function showRadar(error,rows) {
+
+ 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');
+
+ var radarGraph;
+
+ blips = processRows(rows);
+ toolsQuadrant.add(blips.tool);
+ techniquesQuadrant.add(blips.technique);
+ platformsQuadrant.add(blips.platform);
+ languageFramework.add(blips.language);
+
+ radar.setFirstQuadrant(toolsQuadrant);
+ radar.setSecondQuadrant(techniquesQuadrant);
+ radar.setThirdQuadrant(platformsQuadrant);
+ radar.setFourthQuadrant(languageFramework);
+
+ radarGraph = new tr.graphing.Radar(1080, radar);
+ radarGraph.init("#radar").plot();
+ var refTable = new tr.graphing.RefTable(radar);
+ refTable.init('#ref-table').render();
+ }
+
+ // CSV file:
+ // first line is a header: it should be "quadrant,cycle,is_new,name,description"
+ // quadrant values should be one of [tool,technique,platform,language]
+ // cycle should be one of [asses,hold,adapt,trial]
+ // is_new : true if new to the radar since the last version
+ // name:
+ d3.queue()
+ .defer(d3.csv, "./tech-radar.csv")
+ .await(showRadar); //only function name is needed
+
+</script>
+</html>
--- /dev/null
+// https://d3js.org/d3-queue/ Version 3.0.5. Copyright 2017 Mike Bostock.
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
+ (factory((global.d3 = global.d3 || {})));
+}(this, (function (exports) { 'use strict';
+
+var slice = [].slice;
+
+var noabort = {};
+
+function Queue(size) {
+ if (!(size >= 1)) throw new Error;
+ this._size = size;
+ this._call =
+ this._error = null;
+ this._tasks = [];
+ this._data = [];
+ this._waiting =
+ this._active =
+ this._ended =
+ this._start = 0; // inside a synchronous task callback?
+}
+
+Queue.prototype = queue.prototype = {
+ constructor: Queue,
+ defer: function(callback) {
+ if (typeof callback !== "function" || this._call) throw new Error;
+ if (this._error != null) return this;
+ var t = slice.call(arguments, 1);
+ t.push(callback);
+ ++this._waiting, this._tasks.push(t);
+ poke(this);
+ return this;
+ },
+ abort: function() {
+ if (this._error == null) abort(this, new Error("abort"));
+ return this;
+ },
+ await: function(callback) {
+ if (typeof callback !== "function" || this._call) throw new Error;
+ this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
+ maybeNotify(this);
+ return this;
+ },
+ awaitAll: function(callback) {
+ if (typeof callback !== "function" || this._call) throw new Error;
+ this._call = callback;
+ maybeNotify(this);
+ return this;
+ }
+};
+
+function poke(q) {
+ if (!q._start) {
+ try { start(q); } // let the current task complete
+ catch (e) {
+ if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
+ else if (!q._data) throw e; // await callback errored synchronously
+ }
+ }
+}
+
+function start(q) {
+ while (q._start = q._waiting && q._active < q._size) {
+ var i = q._ended + q._active,
+ t = q._tasks[i],
+ j = t.length - 1,
+ c = t[j];
+ t[j] = end(q, i);
+ --q._waiting, ++q._active;
+ t = c.apply(null, t);
+ if (!q._tasks[i]) continue; // task finished synchronously
+ q._tasks[i] = t || noabort;
+ }
+}
+
+function end(q, i) {
+ return function(e, r) {
+ if (!q._tasks[i]) return; // ignore multiple callbacks
+ --q._active, ++q._ended;
+ q._tasks[i] = null;
+ if (q._error != null) return; // ignore secondary errors
+ if (e != null) {
+ abort(q, e);
+ } else {
+ q._data[i] = r;
+ if (q._waiting) poke(q);
+ else maybeNotify(q);
+ }
+ };
+}
+
+function abort(q, e) {
+ var i = q._tasks.length, t;
+ q._error = e; // ignore active callbacks
+ q._data = undefined; // allow gc
+ q._waiting = NaN; // prevent starting
+
+ while (--i >= 0) {
+ if (t = q._tasks[i]) {
+ q._tasks[i] = null;
+ if (t.abort) {
+ try { t.abort(); }
+ catch (e) { /* ignore */ }
+ }
+ }
+ }
+
+ q._active = NaN; // allow notification
+ maybeNotify(q);
+}
+
+function maybeNotify(q) {
+ if (!q._active && q._call) {
+ var d = q._data;
+ q._data = undefined; // allow gc
+ q._call(q._error, d);
+ }
+}
+
+function queue(concurrency) {
+ return new Queue(arguments.length ? +concurrency : Infinity);
+}
+
+exports.queue = queue;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
--- /dev/null
+quadrant,cycle,is_new,name,description
+tool,adapt,false,D3,Charting Library,
+tool,adapt,false,Dependenct Management for Javascript, <a href="https://pwan.org">pwan</a>
+tool,trial,false,Ansible,Bah,
+tool,trial,false,Calabash,???
+tool,assess,false,Xamarin,???
+tool,hold,true,TFS,???
+technique,trial,false,Microservices,
+technique,adapt,false,Continuous delivery,
+technique,assess,false,Development environments in the cloud,
+platform,adapt,false,Elastic Search,
+platform,assess,false,PhoneGap,
+platform,hold,false,Big enterprise solutions,
+language,adapt,false,Clojure,
+language,trial,false,CoffeeScript,
+language,assess,false,Elixir,
+language,hold,true,JSF,