You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@edgent.apache.org by qu...@apache.org on 2016/09/29 23:08:28 UTC

incubator-edgent git commit: [EDGENT-179] Console: Adjust oplet coloring

Repository: incubator-edgent
Updated Branches:
  refs/heads/master b0d44b587 -> f05ca87d4


[EDGENT-179] Console: Adjust oplet coloring


Project: http://git-wip-us.apache.org/repos/asf/incubator-edgent/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-edgent/commit/f05ca87d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-edgent/tree/f05ca87d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-edgent/diff/f05ca87d

Branch: refs/heads/master
Commit: f05ca87d40ac8b51dd931882b789dc4b824e5330
Parents: b0d44b5
Author: Queenie Ma <qu...@gmail.com>
Authored: Tue Sep 27 08:44:20 2016 -0700
Committer: Queenie Ma <qu...@gmail.com>
Committed: Thu Sep 29 08:51:47 2016 -0700

----------------------------------------------------------------------
 console/servlets/webapp_content/js/graph.js |  34 +++-
 console/servlets/webapp_content/js/index.js | 248 ++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-edgent/blob/f05ca87d/console/servlets/webapp_content/js/graph.js
----------------------------------------------------------------------
diff --git a/console/servlets/webapp_content/js/graph.js b/console/servlets/webapp_content/js/graph.js
index e279b91..538a892 100644
--- a/console/servlets/webapp_content/js/graph.js
+++ b/console/servlets/webapp_content/js/graph.js
@@ -16,15 +16,31 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-opletColor = {"org.apache.edgent.streamscope.oplets.StreamScope": "#c7c7c7",
-        "org.apache.edgent.metrics.oplets.CounterOp": "#c7c7c7", "org.apache.edgent.metrics.oplets.RateMeter": "#aec7e8", "org.apache.edgent.oplet.core.FanIn": "#ff7f0e",
-		"org.apache.edgent.oplet.core.FanOut": "#ffbb78", "org.apache.edgent.oplet.core.Peek": "#2ca02c", "org.apache.edgent.oplet.core.PeriodicSource": "#98df8a", 
-		"org.apache.edgent.oplet.core.Pipe": "#d62728", "org.apache.edgent.oplet.core.PipeWindow": "#ff9896", "org.apache.edgent.oplet.core.ProcessSource": "#9467bd", 
-		"org.apache.edgent.oplet.core.Sink": "#c5b0d5", "org.apache.edgent.oplet.core.Source": "#8c564b", "org.apache.edgent.oplet.core.Split": "#c49c94", "org.apache.edgent.oplet.core.Union" : "#1f77b4",
-		"org.apache.edgent.oplet.functional.ConsumerEventSource": "#e377c2", "org.apache.edgent.oplet.functional.ConsumerPeek": "#f7b6d2", "org.apache.edgent.oplet.functional.ConsumerSink": "#7f7f7f", 
-		"org.apache.edgent.oplet.functional.Filter": "#7F7F7F", "org.apache.edgent.oplet.functional.FlatMapper": "#bcbd22", "org.apache.edgent.oplet.functional.Isolate": "#dbdb8d", 
-		"org.apache.edgent.oplet.functional.Map": "#17becf", "org.apache.edgent.oplet.functional.SupplierPeriodicSource": "#9edae5", "org.apache.edgent.oplet.functional.SupplierSource": "#b5cf6b", 
-		"org.apache.edgent.oplet.plumbing.PressureReliever": "#e7cb94", "org.apache.edgent.oplet.plumbing.TextFileReader": "#ad494a", "org.apache.edgent.oplet.plumbing.UnorderedIsolate": "#de9ed6"};
+opletColor = {
+		"org.apache.edgent.metrics.oplets.CounterOp": "#c7c7c7",
+		"org.apache.edgent.metrics.oplets.RateMeter": "#1f77b4",
+		"org.apache.edgent.oplet.core.FanIn": "#aec7e8",
+		"org.apache.edgent.oplet.core.FanOut": "#ff7f0e",
+		"org.apache.edgent.oplet.core.Peek": "#ffbb78",
+		"org.apache.edgent.oplet.core.PeriodicSource": "#bcbd22",
+		"org.apache.edgent.oplet.core.Pipe": "#98df8a",
+		"org.apache.edgent.oplet.core.ProcessSource": "#d62728",
+		"org.apache.edgent.oplet.core.Sink": "#ff9896",
+		"org.apache.edgent.oplet.core.Source": "#9467bd",
+		"org.apache.edgent.oplet.core.Split": "#c5b0d5",
+		"org.apache.edgent.oplet.core.Union": "#c49c94",
+		"org.apache.edgent.oplet.functional.Filter": "#e377c2",
+		"org.apache.edgent.oplet.functional.Isolate": "#f7b6d2",
+		"org.apache.edgent.oplet.functional.Map": "#f2d979",
+		"org.apache.edgent.oplet.functional.Peek": "#dbdb8d",
+		"org.apache.edgent.oplet.functional.SupplierPeriodicSource": "#17becf",
+		"org.apache.edgent.oplet.functional.SupplierSource": "#9edae5",
+		"org.apache.edgent.oplet.plumbing.Isolate": "#79a7f2",
+		"org.apache.edgent.oplet.plumbing.PressureReliever": "#2ca02c",
+		"org.apache.edgent.oplet.plumbing.TextFileReader": "#c0f279",
+		"org.apache.edgent.oplet.plumbing.UnorderedIsolate": "#e279f2",
+		"org.apache.edgent.streamscope.oplets.StreamScope": "#c7c7c7"
+};
 colorMap = {};
 
 addValuesToEdges = function(graph, counterMetrics) {

http://git-wip-us.apache.org/repos/asf/incubator-edgent/blob/f05ca87d/console/servlets/webapp_content/js/index.js
----------------------------------------------------------------------
diff --git a/console/servlets/webapp_content/js/index.js b/console/servlets/webapp_content/js/index.js
index 1a4bb7d..5cc3565 100644
--- a/console/servlets/webapp_content/js/index.js
+++ b/console/servlets/webapp_content/js/index.js
@@ -766,6 +766,204 @@ var makeRows = function() {
 	return theRows;
 };
 
+// Convert HSV to RGB
+var hsvToRGB = function(h, s, v) {
+	var r, g, b, i, f, p, q, t;
+	if (arguments.length === 1) {
+		s = h.s, v = h.v, h = h.h;
+	}
+	i = Math.floor(h * 6);
+	f = h * 6 - i;
+	p = v * (1 - s);
+	q = v * (1 - f * s);
+	t = v * (1 - (1 - f) * s);
+	switch (i % 6) {
+		case 0:
+			r = v, g = t, b = p;
+			break;
+		case 1:
+			r = q, g = v, b = p;
+			break;
+		case 2:
+			r = p, g = v, b = t;
+			break;
+		case 3:
+			r = p, g = q, b = v;
+			break;
+		case 4:
+			r = t, g = p, b = v;
+			break;
+		case 5:
+			r = v, g = p, b = q;
+			break;
+	}
+	return {
+		r: Math.round(r * 255),
+		g: Math.round(g * 255),
+		b: Math.round(b * 255)
+	};
+};
+
+var componentToHex = function(c) {
+	var hex = c.toString(16);
+	return hex.length == 1 ? "0" + hex : hex;
+};
+
+// Convert RGB to Hex
+var rgbToHex = function(r, g, b) {
+	return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
+};
+
+// Convert Hex to RGB
+var hexToRGB = function(hex) {
+	var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+	return result ? {
+		r: parseInt(result[1], 16),
+		g: parseInt(result[2], 16),
+		b: parseInt(result[3], 16)
+	} : null;
+};
+
+// Convert RGB to XYZ
+var rgbToXYZ = function(r, g, b) {
+	var _r = (r / 255);
+	var _g = (g / 255);
+	var _b = (b / 255);
+
+	if (_r > 0.04045) {
+		_r = Math.pow(((_r + 0.055) / 1.055), 2.4);
+	} else {
+		_r = _r / 12.92;
+	}
+
+	if (_g > 0.04045) {
+		_g = Math.pow(((_g + 0.055) / 1.055), 2.4);
+	} else {
+		_g = _g / 12.92;
+	}
+
+	if (_b > 0.04045) {
+		_b = Math.pow(((_b + 0.055) / 1.055), 2.4);
+	} else {
+		_b = _b / 12.92;
+	}
+
+	_r = _r * 100;
+	_g = _g * 100;
+	_b = _b * 100;
+
+	var X = _r * 0.4124 + _g * 0.3576 + _b * 0.1805;
+	var Y = _r * 0.2126 + _g * 0.7152 + _b * 0.0722;
+	var Z = _r * 0.0193 + _g * 0.1192 + _b * 0.9505;
+
+	return [X, Y, Z];
+};
+
+// Convert XYZ to LAB
+var xyzToLAB = function(x, y, z) {
+	var ref_X = 95.047;
+	var ref_Y = 100.000;
+	var ref_Z = 108.883;
+
+	var _X = x / ref_X;
+	var _Y = y / ref_Y;
+	var _Z = z / ref_Z;
+
+	if (_X > 0.008856) {
+		_X = Math.pow(_X, (1 / 3));
+	} else {
+		_X = (7.787 * _X) + (16 / 116);
+	}
+
+	if (_Y > 0.008856) {
+		_Y = Math.pow(_Y, (1 / 3));
+	} else {
+		_Y = (7.787 * _Y) + (16 / 116);
+	}
+
+	if (_Z > 0.008856) {
+		_Z = Math.pow(_Z, (1 / 3));
+	} else {
+		_Z = (7.787 * _Z) + (16 / 116);
+	}
+
+	var CIE_L = (116 * _Y) - 16;
+	var CIE_a = 500 * (_X - _Y);
+	var CIE_b = 200 * (_Y - _Z);
+
+	return [CIE_L, CIE_a, CIE_b];
+};
+
+// Compute Delta E using CIE94
+var getDeltaE = function(x, y, isTextiles) {
+	var x = {
+		l: x[0],
+		a: x[1],
+		b: x[2]
+	};
+	var y = {
+		l: y[0],
+		a: y[1],
+		b: y[2]
+	};
+	labx = x;
+	laby = y;
+	var k2;
+	var k1;
+	var kl;
+	var kh = 1;
+	var kc = 1;
+	if (isTextiles) {
+		k2 = 0.014;
+		k1 = 0.048;
+		kl = 2;
+	} else {
+		k2 = 0.015;
+		k1 = 0.045;
+		kl = 1;
+	}
+
+	var c1 = Math.sqrt(x.a * x.a + x.b * x.b);
+	var c2 = Math.sqrt(y.a * y.a + y.b * y.b);
+
+	var sh = 1 + k2 * c1;
+	var sc = 1 + k1 * c1;
+	var sl = 1;
+
+	var da = x.a - y.a;
+	var db = x.b - y.b;
+	var dc = c1 - c2;
+
+	var dl = x.l - y.l;
+	var dh = Math.sqrt(da * da + db * db - dc * dc);
+
+	return Math.sqrt(Math.pow((dl / (kl * sl)), 2) + Math.pow((dc / (kc * sc)), 2) + Math.pow((dh / (kh * sh)), 2));
+};
+
+// Generate a random color using the golden ratio conjugate
+var genRandomColor = function(s, v) {
+	var goldenRatioConjugate = 0.618033988749895;
+	var h = Math.random();
+	h += goldenRatioConjugate;
+	h %= 1;
+	var hsv = {
+		h: h,
+		s: s,
+		v: v
+	};
+	var rgb = hsvToRGB(hsv.h, hsv.s, hsv.v);
+	var hex = rgbToHex(rgb.r, rgb.g, rgb.b);
+	return {
+		hsv: hsv,
+		rgb: rgb,
+		hex: hex
+	};
+};
+
+var checkDeltaE = function(deltaE) {
+    return deltaE >= 15;
+};
+
 vertexMap = {};
 
 var renderGraph = function(jobId, counterMetrics, bIsNewJob) {
@@ -937,7 +1135,9 @@ var renderGraph = function(jobId, counterMetrics, bIsNewJob) {
     			return document.createElementNS(d3.ns.prefix.svg, 'circle');
     		}
       });
-      
+
+	var assignedOpletColors = [];
+
   	node.selectAll("circle")
   	.attr("cx", sankey.nodeWidth()/2)
   	.attr("cy", function(d){
@@ -950,11 +1150,53 @@ var renderGraph = function(jobId, counterMetrics, bIsNewJob) {
   		if (!colorMap[d.id.toString()]) {
   			colorMap[d.id.toString()] = color20(d.id.toString());
   		}
+
+  		// Generate a random color that is perceptually different than all assigned colors:
+  		// 1. Convert the assigned oplet colors from Hex to LAB
+  		// 2. Generate a random color in the RGB color space
+  		// 3. Convert RGB to XYZ
+  		// 4. Convert XYZ to LAB
+  		// 5. For each assigned oplet color, compute Delta E between the two LAB colors (new and assigned)
+  		// 6. If Delta E >= 15, consider the color to be different enough from the other colors
   		if (!opletColor[d.invocation.kind]) {
-  			opletColor[d.invocation.kind] = color20(d.invocation.kind);
+  	  		var assignedOpletColorsLAB = [];
+  	  		for (var i = 0; i < assignedOpletColors.length; i++) {
+  	  			var rgb = hexToRGB(assignedOpletColors[i]);
+  	  			var xyz = rgbToXYZ(rgb.r, rgb.g, rgb.b);
+  	  			var lab = xyzToLAB(xyz[0], xyz[1], xyz[2]);
+  	  			assignedOpletColorsLAB.push(lab);
+  	  		}
+
+  	  		var deltaEs = [];
+  	  		var c = null;
+  	  		var uniqueColor = false;
+
+  	  		while (!uniqueColor) {
+  	  			// Use a different color scheme for non-org.apache.edgent defined oplets
+  	  			if (d.invocation.kind.includes("org.apache.edgent")) {
+  	  				c = genRandomColor(0.5, 0.95);
+  	  			} else {
+  	  				c = genRandomColor(0.99, 0.99);
+  	  			}
+
+  	  			var xyz = rgbToXYZ(c.rgb.r, c.rgb.g, c.rgb.b);
+  	  			var lab = xyzToLAB(xyz[0], xyz[1], xyz[2]);
+
+  	  			// Compare color to assigned colors and check for similarity
+  	  			deltaEs = [];
+  	  			for (var m = 0; m < assignedOpletColorsLAB.length; m++) {
+  	  				deltaE = getDeltaE(lab, assignedOpletColorsLAB[m], false);
+  	  				deltaEs.push(deltaE);
+  	  			}
+  	  			uniqueColor = deltaEs.every(checkDeltaE);
+  	  		}
+
+  			opletColor[d.invocation.kind] = c.hex;
   		}
   		
-  		return getVertexFillColor(layer, d, counterMetrics);
+  		var color = getVertexFillColor(layer, d, counterMetrics);
+  		assignedOpletColors.push(color);
+  		return color;
   	
   	})
   	.attr("data-legend", function(d) {