You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chukwa.apache.org by ey...@apache.org on 2009/08/24 02:21:19 UTC

svn commit: r807034 - in /hadoop/chukwa/trunk: CHANGES.txt src/java/org/apache/hadoop/chukwa/hicc/Chart.java src/web/hicc/js/base64.js src/web/hicc/js/canvas2image.js src/web/hicc/js/flot.extend.js

Author: eyang
Date: Mon Aug 24 00:21:18 2009
New Revision: 807034

URL: http://svn.apache.org/viewvc?rev=807034&view=rev
Log:
CHUKWA-382. Added export button to export HICC graph as static image.  (Eric Yang)


Added:
    hadoop/chukwa/trunk/src/web/hicc/js/base64.js
    hadoop/chukwa/trunk/src/web/hicc/js/canvas2image.js
Modified:
    hadoop/chukwa/trunk/CHANGES.txt
    hadoop/chukwa/trunk/src/java/org/apache/hadoop/chukwa/hicc/Chart.java
    hadoop/chukwa/trunk/src/web/hicc/js/flot.extend.js

Modified: hadoop/chukwa/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/chukwa/trunk/CHANGES.txt?rev=807034&r1=807033&r2=807034&view=diff
==============================================================================
--- hadoop/chukwa/trunk/CHANGES.txt (original)
+++ hadoop/chukwa/trunk/CHANGES.txt Mon Aug 24 00:21:18 2009
@@ -4,6 +4,10 @@
 
   NEW FEATURES
 
+    CHUKWA-383. Added embed mode for HICC.  (Eric Yang)
+
+    CHUKWA-382. Added export button to export HICC graph as static image.  (Eric Yang)
+
     CHUKWA-366. Custom tags. (asrabkin)
 
     CHUKWA-358. Real-time monitoring at collector. (asrabkin)

Modified: hadoop/chukwa/trunk/src/java/org/apache/hadoop/chukwa/hicc/Chart.java
URL: http://svn.apache.org/viewvc/hadoop/chukwa/trunk/src/java/org/apache/hadoop/chukwa/hicc/Chart.java?rev=807034&r1=807033&r2=807034&view=diff
==============================================================================
--- hadoop/chukwa/trunk/src/java/org/apache/hadoop/chukwa/hicc/Chart.java (original)
+++ hadoop/chukwa/trunk/src/java/org/apache/hadoop/chukwa/hicc/Chart.java Mon Aug 24 00:21:18 2009
@@ -228,6 +228,10 @@
           .append("<script type=\"text/javascript\" src=\"/hicc/js/flexigrid.pack.js\"></script>\n");
       output
           .append("<script type=\"text/javascript\" src=\"/hicc/js/excanvas.pack.js\"></script>\n");
+      output
+          .append("<script type=\"text/javascript\" src=\"/hicc/js/base64.js\"></script>\n");
+      output
+          .append("<script type=\"text/javascript\" src=\"/hicc/js/canvas2image.js\"></script>\n");
       output.append("<div id=\"placeholderTitle\"><center>" + title
           + "</center></div>\n");
       output.append("<div id=\"placeholder\" style=\"width:" + this.width
@@ -438,6 +442,7 @@
 	output.append("   $(window).resize(function() { wholePeriod(); });\n");
 	output.append("});\n");
 	output.append("</script>\n");
+        output.append("<input type=\"button\" value=\"Export\" onclick=\"javascript:saveReport();\">\n");
 	output.append("</body></html>\n");
     } else {
       output.append("chartTitle=\"<center>" + this.title + "</center>\";");

Added: hadoop/chukwa/trunk/src/web/hicc/js/base64.js
URL: http://svn.apache.org/viewvc/hadoop/chukwa/trunk/src/web/hicc/js/base64.js?rev=807034&view=auto
==============================================================================
--- hadoop/chukwa/trunk/src/web/hicc/js/base64.js (added)
+++ hadoop/chukwa/trunk/src/web/hicc/js/base64.js Mon Aug 24 00:21:18 2009
@@ -0,0 +1,113 @@
+/* Copyright (C) 1999 Masanao Izumo <iz...@onicos.co.jp>
+ * Version: 1.0
+ * LastModified: Dec 25 1999
+ * This library is free.  You can redistribute it and/or modify it.
+ */
+
+/*
+ * Interfaces:
+ * b64 = base64encode(data);
+ * data = base64decode(b64);
+ */
+
+(function() {
+
+var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var base64DecodeChars = new Array(
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
+
+function base64encode(str) {
+    var out, i, len;
+    var c1, c2, c3;
+
+    len = str.length;
+    i = 0;
+    out = "";
+    while(i < len) {
+	c1 = str.charCodeAt(i++) & 0xff;
+	if(i == len)
+	{
+	    out += base64EncodeChars.charAt(c1 >> 2);
+	    out += base64EncodeChars.charAt((c1 & 0x3) << 4);
+	    out += "==";
+	    break;
+	}
+	c2 = str.charCodeAt(i++);
+	if(i == len)
+	{
+	    out += base64EncodeChars.charAt(c1 >> 2);
+	    out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
+	    out += base64EncodeChars.charAt((c2 & 0xF) << 2);
+	    out += "=";
+	    break;
+	}
+	c3 = str.charCodeAt(i++);
+	out += base64EncodeChars.charAt(c1 >> 2);
+	out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
+	out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
+	out += base64EncodeChars.charAt(c3 & 0x3F);
+    }
+    return out;
+}
+
+function base64decode(str) {
+    var c1, c2, c3, c4;
+    var i, len, out;
+
+    len = str.length;
+    i = 0;
+    out = "";
+    while(i < len) {
+	/* c1 */
+	do {
+	    c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
+	} while(i < len && c1 == -1);
+	if(c1 == -1)
+	    break;
+
+	/* c2 */
+	do {
+	    c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
+	} while(i < len && c2 == -1);
+	if(c2 == -1)
+	    break;
+
+	out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
+
+	/* c3 */
+	do {
+	    c3 = str.charCodeAt(i++) & 0xff;
+	    if(c3 == 61)
+		return out;
+	    c3 = base64DecodeChars[c3];
+	} while(i < len && c3 == -1);
+	if(c3 == -1)
+	    break;
+
+	out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
+
+	/* c4 */
+	do {
+	    c4 = str.charCodeAt(i++) & 0xff;
+	    if(c4 == 61)
+		return out;
+	    c4 = base64DecodeChars[c4];
+	} while(i < len && c4 == -1);
+	if(c4 == -1)
+	    break;
+	out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
+    }
+    return out;
+}
+
+if (!window.btoa) window.btoa = base64encode;
+if (!window.atob) window.atob = base64decode;
+
+})();
\ No newline at end of file

Added: hadoop/chukwa/trunk/src/web/hicc/js/canvas2image.js
URL: http://svn.apache.org/viewvc/hadoop/chukwa/trunk/src/web/hicc/js/canvas2image.js?rev=807034&view=auto
==============================================================================
--- hadoop/chukwa/trunk/src/web/hicc/js/canvas2image.js (added)
+++ hadoop/chukwa/trunk/src/web/hicc/js/canvas2image.js Mon Aug 24 00:21:18 2009
@@ -0,0 +1,236 @@
+/*
+ * Canvas2Image v0.1
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+var Canvas2Image = (function() {
+
+	// check if we have canvas support
+	var bHasCanvas = false;
+	var oCanvas = document.createElement("canvas");
+	if (oCanvas.getContext("2d")) {
+		bHasCanvas = true;
+	}
+
+	// no canvas, bail out.
+	if (!bHasCanvas) {
+		return {
+			saveAsBMP : function(){},
+			saveAsPNG : function(){},
+			saveAsJPEG : function(){}
+		}
+	}
+
+	var bHasImageData = !!(oCanvas.getContext("2d").getImageData);
+	var bHasDataURL = !!(oCanvas.toDataURL);
+	var bHasBase64 = !!(window.btoa);
+
+	var strDownloadMime = "image/octet-stream";
+
+	// ok, we're good
+	var readCanvasData = function(oCanvas) {
+		var iWidth = parseInt(oCanvas.width);
+		var iHeight = parseInt(oCanvas.height);
+		return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
+	}
+
+	// base64 encodes either a string or an array of charcodes
+	var encodeData = function(data) {
+		var strData = "";
+		if (typeof data == "string") {
+			strData = data;
+		} else {
+			var aData = data;
+			for (var i=0;i<aData.length;i++) {
+				strData += String.fromCharCode(aData[i]);
+			}
+		}
+		return btoa(strData);
+	}
+
+	// creates a base64 encoded string containing BMP data
+	// takes an imagedata object as argument
+	var createBMP = function(oData) {
+		var aHeader = [];
+	
+		var iWidth = oData.width;
+		var iHeight = oData.height;
+
+		aHeader.push(0x42); // magic 1
+		aHeader.push(0x4D); 
+	
+		var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes
+		aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+		aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+		aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+		aHeader.push(iFileSize % 256);
+
+		aHeader.push(0); // reserved
+		aHeader.push(0);
+		aHeader.push(0); // reserved
+		aHeader.push(0);
+
+		aHeader.push(54); // dataoffset
+		aHeader.push(0);
+		aHeader.push(0);
+		aHeader.push(0);
+
+		var aInfoHeader = [];
+		aInfoHeader.push(40); // info header size
+		aInfoHeader.push(0);
+		aInfoHeader.push(0);
+		aInfoHeader.push(0);
+
+		var iImageWidth = iWidth;
+		aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+		aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+		aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+		aInfoHeader.push(iImageWidth % 256);
+	
+		var iImageHeight = iHeight;
+		aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+		aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+		aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+		aInfoHeader.push(iImageHeight % 256);
+	
+		aInfoHeader.push(1); // num of planes
+		aInfoHeader.push(0);
+	
+		aInfoHeader.push(24); // num of bits per pixel
+		aInfoHeader.push(0);
+	
+		aInfoHeader.push(0); // compression = none
+		aInfoHeader.push(0);
+		aInfoHeader.push(0);
+		aInfoHeader.push(0);
+	
+		var iDataSize = iWidth*iHeight*3; 
+		aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+		aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+		aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+		aInfoHeader.push(iDataSize % 256); 
+	
+		for (var i=0;i<16;i++) {
+			aInfoHeader.push(0);	// these bytes not used
+		}
+	
+		var iPadding = (4 - ((iWidth * 3) % 4)) % 4;
+
+		var aImgData = oData.data;
+
+		var strPixelData = "";
+		var y = iHeight;
+		do {
+			var iOffsetY = iWidth*(y-1)*4;
+			var strPixelRow = "";
+			for (var x=0;x<iWidth;x++) {
+				var iOffsetX = 4*x;
+
+				strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
+				strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
+				strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
+			}
+			for (var c=0;c<iPadding;c++) {
+				strPixelRow += String.fromCharCode(0);
+			}
+			strPixelData += strPixelRow;
+		} while (--y);
+
+		var strEncoded = encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);
+
+		return strEncoded;
+	}
+
+
+	// sends the generated file to the client
+	var saveFile = function(strData) {
+		document.location.href = strData;
+	}
+
+	var makeDataURI = function(strData, strMime) {
+		return "data:" + strMime + ";base64," + strData;
+	}
+
+	// generates a <img> object containing the imagedata
+	var makeImageObject = function(strSource) {
+		var oImgElement = document.createElement("img");
+		oImgElement.src = strSource;
+		return oImgElement;
+	}
+
+	var scaleCanvas = function(oCanvas, iWidth, iHeight) {
+		if (iWidth && iHeight) {
+			var oSaveCanvas = document.createElement("canvas");
+			oSaveCanvas.width = iWidth;
+			oSaveCanvas.height = iHeight;
+			oSaveCanvas.style.width = iWidth+"px";
+			oSaveCanvas.style.height = iHeight+"px";
+
+			var oSaveCtx = oSaveCanvas.getContext("2d");
+
+			oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
+			return oSaveCanvas;
+		}
+		return oCanvas;
+	}
+
+	return {
+
+		saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
+			if (!bHasDataURL) {
+				return false;
+			}
+			var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
+			var strData = oScaledCanvas.toDataURL("image/png");
+			if (bReturnImg) {
+				return makeImageObject(strData);
+			} else {
+				saveFile(strData.replace("image/png", strDownloadMime));
+			}
+			return true;
+		},
+
+		saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
+			if (!bHasDataURL) {
+				return false;
+			}
+
+			var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
+			var strMime = "image/jpeg";
+			var strData = oScaledCanvas.toDataURL(strMime);
+	
+			// check if browser actually supports jpeg by looking for the mime type in the data uri.
+			// if not, return false
+			if (strData.indexOf(strMime) != 5) {
+				return false;
+			}
+
+			if (bReturnImg) {
+				return makeImageObject(strData);
+			} else {
+				saveFile(strData.replace(strMime, strDownloadMime));
+			}
+			return true;
+		},
+
+		saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
+
+			if (!(bHasImageData && bHasBase64)) {
+				return false;
+			}
+
+			var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
+
+			var oData = readCanvasData(oScaledCanvas);
+			var strImgData = createBMP(oData);
+			if (bReturnImg) {
+				return makeImageObject(makeDataURI(strImgData, "image/bmp"));
+			} else {
+				saveFile(makeDataURI(strImgData, strDownloadMime));
+			}
+			return true;
+		}
+	};
+
+})();
\ No newline at end of file

Modified: hadoop/chukwa/trunk/src/web/hicc/js/flot.extend.js
URL: http://svn.apache.org/viewvc/hadoop/chukwa/trunk/src/web/hicc/js/flot.extend.js?rev=807034&r1=807033&r2=807034&view=diff
==============================================================================
--- hadoop/chukwa/trunk/src/web/hicc/js/flot.extend.js (original)
+++ hadoop/chukwa/trunk/src/web/hicc/js/flot.extend.js Mon Aug 24 00:21:18 2009
@@ -262,3 +262,30 @@
   }
   return true;
 }
+
+function saveReport() {
+  var pattern = /https?:\/\/(.*?)\//;
+  var baseUrl = pattern.exec(location.href)[0];
+  var chart = document.getElementById('placeholder').cloneNode(true);
+  var canvas = document.getElementById('placeholder').getElementsByTagName('canvas')[0];
+  chart.getElementsByTagName('canvas')[0].style.display="none";
+  chart.getElementsByTagName('canvas')[1].style.display="none";
+  var legend = document.getElementById('placeholderLegend');
+  var tableLegend = document.getElementById('statisLegend');
+  var data="data:text/html,";
+  data+="<!doctype html>";
+  data+="<link type=\"text/css\" rel=\"stylesheet\" href=\""+baseUrl+"hicc/css/default.css\" />";
+  data+="<link type=\"text/css\" rel=\"stylesheet\" href=\""+baseUrl+"hicc/css/iframe.css\" />";
+  data+="<link type=\"text/css\" rel=\"stylesheet\" href=\""+baseUrl+"hicc/css/flexigrid/flexigrid.css\" />";
+  data+="<center>";
+  data+="<div id=\"placeholder\" style=\"width:"+chart.style.width+"; height:"+chart.style.height+"; position: relative;\">";
+  data+="<img src=\""+canvas.toDataURL()+"\" style=\"position: absolute; left: 0px; top: 0px\">";
+  data+="<center>";
+  data+=chart.innerHTML;
+  data+="</center>";
+  data+="</div>";
+  data+=legend.innerHTML;
+  data+=tableLegend.innerHTML;
+  data+="</center>";
+  return window.open(data);
+}