GUI -- [ONOS-89] Creating affinity colors for ONOS instances. (WIP)
- added d3utils.cat7() to provide color scales.
- added 'equals' and 'dash' ids for key binding.
- added theme() callback to let views know when the theme changed.
- re-bound test keys (0, dash, equals)

Change-Id: Ie6c6140451ddab567e26c2ea17d65395fa9cc829
diff --git a/web/gui/src/main/webapp/d3Utils.js b/web/gui/src/main/webapp/d3Utils.js
index 90b3032..c6d405c 100644
--- a/web/gui/src/main/webapp/d3Utils.js
+++ b/web/gui/src/main/webapp/d3Utils.js
@@ -119,10 +119,100 @@
             .attr('in', String);
     }
 
+    // --- Ordinal scales for 7 values.
+    // TODO: tune colors for light and dark themes
+
+    var lightNorm = ['#1f77b4', '#2ca02c', '#d62728', '#9467bd', '#e377c2', '#bcbd22', '#17becf'],
+        lightMute = ['#aec7e8', '#98df8a', '#ff9896', '#c5b0d5', '#f7b6d2', '#dbdb8d', '#9edae5'],
+        darkNorm = ['#1f77b4', '#2ca02c', '#d62728', '#9467bd', '#e377c2', '#bcbd22', '#17becf'],
+        darkMute = ['#aec7e8', '#98df8a', '#ff9896', '#c5b0d5', '#f7b6d2', '#dbdb8d', '#9edae5'];
+
+    function cat7() {
+        var colors = {
+                light: {
+                    norm: d3.scale.ordinal().range(lightNorm),
+                    mute: d3.scale.ordinal().range(lightMute)
+                },
+                dark: {
+                    norm: d3.scale.ordinal().range(darkNorm),
+                    mute: d3.scale.ordinal().range(darkMute)
+                }
+            },
+            tcid = 'd3utilTestCard';
+
+        function get(id, muted, theme) {
+            // NOTE: since we are lazily assigning domain ids, we need to
+            //       get the color from all 4 scales, to keep the domains
+            //       in sync.
+            var ln = colors.light.norm(id),
+                lm = colors.light.mute(id),
+                dn = colors.dark.norm(id),
+                dm = colors.dark.mute(id);
+            if (theme === 'dark') {
+                return muted ? dm : dn;
+            } else {
+                return muted ? lm : ln;
+            }
+        }
+
+        function testCard(svg) {
+            var g = svg.select('g#' + tcid),
+                dom = d3.range(7),
+                k, muted, theme, what;
+
+            if (!g.empty()) {
+                g.remove();
+
+            } else {
+                g = svg.append('g')
+                    .attr('id', tcid)
+                    .attr('transform', 'scale(4)translate(20,20)');
+
+                for (k=0; k<4; k++) {
+                    muted = k%2;
+                    what = muted ? ' muted' : ' normal';
+                    theme = k < 2 ? 'light' : 'dark';
+                    dom.forEach(function (id, i) {
+                        var x = i * 20,
+                            y = k * 20,
+                            f = get(id, muted, theme);
+                        g.append('circle').attr({
+                            cx: x,
+                            cy: y,
+                            r: 5,
+                            fill: f
+                        });
+                    });
+                    g.append('rect').attr({
+                        x: 140,
+                        y: k * 20 - 5,
+                        width: 32,
+                        height: 10,
+                        rx: 2,
+                        fill: '#888'
+                    });
+                    g.append('text').text(theme + what)
+                        .attr({
+                            x: 142,
+                            y: k * 20 + 2,
+                            fill: 'white'
+                        })
+                        .style('font-size', '4pt');
+                }
+            }
+        }
+
+        return {
+            testCard: testCard,
+            get: get
+        };
+    }
+
     // === register the functions as a library
     onos.ui.addLib('d3util', {
         createDragBehavior: createDragBehavior,
-        appendGlow: appendGlow
+        appendGlow: appendGlow,
+        cat7: cat7
     });
 
 }(ONOS));