You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2013/10/30 10:50:53 UTC

svn commit: r1537021 [8/10] - in /incubator/sirona/trunk: ./ reporting/src/main/java/org/apache/sirona/reporting/web/ reporting/src/main/java/org/apache/sirona/reporting/web/handler/ reporting/src/main/java/org/apache/sirona/reporting/web/plugin/report...

Added: incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.pie.js
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.pie.js?rev=1537021&view=auto
==============================================================================
--- incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.pie.js (added)
+++ incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.pie.js Wed Oct 30 09:50:51 2013
@@ -0,0 +1,750 @@
+/*
+Flot plugin for rendering pie charts. The plugin assumes the data is 
+coming is as a single data value for each series, and each of those 
+values is a positive value or zero (negative numbers don't make 
+any sense and will cause strange effects). The data values do 
+NOT need to be passed in as percentage values because it 
+internally calculates the total and percentages.
+
+* Created by Brian Medendorp, June 2009
+* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
+
+* Changes:
+	2009-10-22: lineJoin set to round
+	2009-10-23: IE full circle fix, donut
+	2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
+	2009-11-17: Added IE hover capability submitted by Anthony Aragues
+	2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
+		
+
+Available options are:
+series: {
+	pie: {
+		show: true/false
+		radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
+		innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
+		startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
+		tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
+		offset: {
+			top: integer value to move the pie up or down
+			left: integer value to move the pie left or right, or 'auto'
+		},
+		stroke: {
+			color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
+			width: integer pixel width of the stroke
+		},
+		label: {
+			show: true/false, or 'auto'
+			formatter:  a user-defined function that modifies the text/style of the label text
+			radius: 0-1 for percentage of fullsize, or a specified pixel length
+			background: {
+				color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
+				opacity: 0-1
+			},
+			threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
+		},
+		combine: {
+			threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
+			color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
+			label: any text value of what the combined slice should be labeled
+		}
+		highlight: {
+			opacity: 0-1
+		}
+	}
+}
+
+More detail and specific examples can be found in the included HTML file.
+
+*/
+
+(function ($) 
+{
+	function init(plot) // this is the "body" of the plugin
+	{
+		var canvas = null;
+		var target = null;
+		var maxRadius = null;
+		var centerLeft = null;
+		var centerTop = null;
+		var total = 0;
+		var redraw = true;
+		var redrawAttempts = 10;
+		var shrink = 0.95;
+		var legendWidth = 0;
+		var processed = false;
+		var raw = false;
+		
+		// interactive variables	
+		var highlights = [];	
+	
+		// add hook to determine if pie plugin in enabled, and then perform necessary operations
+		plot.hooks.processOptions.push(checkPieEnabled);
+		plot.hooks.bindEvents.push(bindEvents);	
+
+		// check to see if the pie plugin is enabled
+		function checkPieEnabled(plot, options)
+		{
+			if (options.series.pie.show)
+			{
+				//disable grid
+				options.grid.show = false;
+				
+				// set labels.show
+				if (options.series.pie.label.show=='auto')
+					if (options.legend.show)
+						options.series.pie.label.show = false;
+					else
+						options.series.pie.label.show = true;
+				
+				// set radius
+				if (options.series.pie.radius=='auto')
+					if (options.series.pie.label.show)
+						options.series.pie.radius = 3/4;
+					else
+						options.series.pie.radius = 1;
+						
+				// ensure sane tilt
+				if (options.series.pie.tilt>1)
+					options.series.pie.tilt=1;
+				if (options.series.pie.tilt<0)
+					options.series.pie.tilt=0;
+			
+				// add processData hook to do transformations on the data
+				plot.hooks.processDatapoints.push(processDatapoints);
+				plot.hooks.drawOverlay.push(drawOverlay);	
+				
+				// add draw hook
+				plot.hooks.draw.push(draw);
+			}
+		}
+	
+		// bind hoverable events
+		function bindEvents(plot, eventHolder) 		
+		{		
+			var options = plot.getOptions();
+			
+			if (options.series.pie.show && options.grid.hoverable)
+				eventHolder.unbind('mousemove').mousemove(onMouseMove);
+				
+			if (options.series.pie.show && options.grid.clickable)
+				eventHolder.unbind('click').click(onClick);
+		}	
+		
+
+		// debugging function that prints out an object
+		function alertObject(obj)
+		{
+			var msg = '';
+			function traverse(obj, depth)
+			{
+				if (!depth)
+					depth = 0;
+				for (var i = 0; i < obj.length; ++i)
+				{
+					for (var j=0; j<depth; j++)
+						msg += '\t';
+				
+					if( typeof obj[i] == "object")
+					{	// its an object
+						msg += ''+i+':\n';
+						traverse(obj[i], depth+1);
+					}
+					else
+					{	// its a value
+						msg += ''+i+': '+obj[i]+'\n';
+					}
+				}
+			}
+			traverse(obj);
+			alert(msg);
+		}
+		
+		function calcTotal(data)
+		{
+			for (var i = 0; i < data.length; ++i)
+			{
+				var item = parseFloat(data[i].data[0][1]);
+				if (item)
+					total += item;
+			}
+		}	
+		
+		function processDatapoints(plot, series, data, datapoints) 
+		{	
+			if (!processed)
+			{
+				processed = true;
+			
+				canvas = plot.getCanvas();
+				target = $(canvas).parent();
+				options = plot.getOptions();
+			
+				plot.setData(combine(plot.getData()));
+			}
+		}
+		
+		function setupPie()
+		{
+			legendWidth = target.children().filter('.legend').children().width();
+		
+			// calculate maximum radius and center point
+			maxRadius =  Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
+			centerTop = (canvas.height/2)+options.series.pie.offset.top;
+			centerLeft = (canvas.width/2);
+			
+			if (options.series.pie.offset.left=='auto')
+				if (options.legend.position.match('w'))
+					centerLeft += legendWidth/2;
+				else
+					centerLeft -= legendWidth/2;
+			else
+				centerLeft += options.series.pie.offset.left;
+					
+			if (centerLeft<maxRadius)
+				centerLeft = maxRadius;
+			else if (centerLeft>canvas.width-maxRadius)
+				centerLeft = canvas.width-maxRadius;
+		}
+		
+		function fixData(data)
+		{
+			for (var i = 0; i < data.length; ++i)
+			{
+				if (typeof(data[i].data)=='number')
+					data[i].data = [[1,data[i].data]];
+				else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
+				{
+					if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
+						data[i].label = data[i].data.label; // fix weirdness coming from flot
+					data[i].data = [[1,0]];
+					
+				}
+			}
+			return data;
+		}
+		
+		function combine(data)
+		{
+			data = fixData(data);
+			calcTotal(data);
+			var combined = 0;
+			var numCombined = 0;
+			var color = options.series.pie.combine.color;
+			
+			var newdata = [];
+			for (var i = 0; i < data.length; ++i)
+			{
+				// make sure its a number
+				data[i].data[0][1] = parseFloat(data[i].data[0][1]);
+				if (!data[i].data[0][1])
+					data[i].data[0][1] = 0;
+					
+				if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
+				{
+					combined += data[i].data[0][1];
+					numCombined++;
+					if (!color)
+						color = data[i].color;
+				}				
+				else
+				{
+					newdata.push({
+						data: [[1,data[i].data[0][1]]], 
+						color: data[i].color, 
+						label: data[i].label,
+						angle: (data[i].data[0][1]*(Math.PI*2))/total,
+						percent: (data[i].data[0][1]/total*100)
+					});
+				}
+			}
+			if (numCombined>0)
+				newdata.push({
+					data: [[1,combined]], 
+					color: color, 
+					label: options.series.pie.combine.label,
+					angle: (combined*(Math.PI*2))/total,
+					percent: (combined/total*100)
+				});
+			return newdata;
+		}		
+		
+		function draw(plot, newCtx)
+		{
+			if (!target) return; // if no series were passed
+			ctx = newCtx;
+		
+			setupPie();
+			var slices = plot.getData();
+		
+			var attempts = 0;
+			while (redraw && attempts<redrawAttempts)
+			{
+				redraw = false;
+				if (attempts>0)
+					maxRadius *= shrink;
+				attempts += 1;
+				clear();
+				if (options.series.pie.tilt<=0.8)
+					drawShadow();
+				drawPie();
+			}
+			if (attempts >= redrawAttempts) {
+				clear();
+				target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
+			}
+			
+			if ( plot.setSeries && plot.insertLegend )
+			{
+				plot.setSeries(slices);
+				plot.insertLegend();
+			}
+			
+			// we're actually done at this point, just defining internal functions at this point
+			
+			function clear()
+			{
+				ctx.clearRect(0,0,canvas.width,canvas.height);
+				target.children().filter('.pieLabel, .pieLabelBackground').remove();
+			}
+			
+			function drawShadow()
+			{
+				var shadowLeft = 5;
+				var shadowTop = 15;
+				var edge = 10;
+				var alpha = 0.02;
+			
+				// set radius
+				if (options.series.pie.radius>1)
+					var radius = options.series.pie.radius;
+				else
+					var radius = maxRadius * options.series.pie.radius;
+					
+				if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
+					return;	// shadow would be outside canvas, so don't draw it
+			
+				ctx.save();
+				ctx.translate(shadowLeft,shadowTop);
+				ctx.globalAlpha = alpha;
+				ctx.fillStyle = '#000';
+
+				// center and rotate to starting position
+				ctx.translate(centerLeft,centerTop);
+				ctx.scale(1, options.series.pie.tilt);
+				
+				//radius -= edge;
+				for (var i=1; i<=edge; i++)
+				{
+					ctx.beginPath();
+					ctx.arc(0,0,radius,0,Math.PI*2,false);
+					ctx.fill();
+					radius -= i;
+				}	
+				
+				ctx.restore();
+			}
+			
+			function drawPie()
+			{
+				startAngle = Math.PI*options.series.pie.startAngle;
+				
+				// set radius
+				if (options.series.pie.radius>1)
+					var radius = options.series.pie.radius;
+				else
+					var radius = maxRadius * options.series.pie.radius;
+				
+				// center and rotate to starting position
+				ctx.save();
+				ctx.translate(centerLeft,centerTop);
+				ctx.scale(1, options.series.pie.tilt);
+				//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
+				
+				// draw slices
+				ctx.save();
+				var currentAngle = startAngle;
+				for (var i = 0; i < slices.length; ++i)
+				{
+					slices[i].startAngle = currentAngle;
+					drawSlice(slices[i].angle, slices[i].color, true);
+				}
+				ctx.restore();
+				
+				// draw slice outlines
+				ctx.save();
+				ctx.lineWidth = options.series.pie.stroke.width;
+				currentAngle = startAngle;
+				for (var i = 0; i < slices.length; ++i)
+					drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
+				ctx.restore();
+					
+				// draw donut hole
+				drawDonutHole(ctx);
+				
+				// draw labels
+				if (options.series.pie.label.show)
+					drawLabels();
+				
+				// restore to original state
+				ctx.restore();
+				
+				function drawSlice(angle, color, fill)
+				{	
+					if (angle<=0)
+						return;
+				
+					if (fill)
+						ctx.fillStyle = color;
+					else
+					{
+						ctx.strokeStyle = color;
+						ctx.lineJoin = 'round';
+					}
+						
+					ctx.beginPath();
+					if (Math.abs(angle - Math.PI*2) > 0.000000001)
+						ctx.moveTo(0,0); // Center of the pie
+					else if ($.browser.msie)
+						angle -= 0.0001;
+					//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
+					ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
+					ctx.closePath();
+					//ctx.rotate(angle); // This doesn't work properly in Opera
+					currentAngle += angle;
+					
+					if (fill)
+						ctx.fill();
+					else
+						ctx.stroke();
+				}
+				
+				function drawLabels()
+				{
+					var currentAngle = startAngle;
+					
+					// set radius
+					if (options.series.pie.label.radius>1)
+						var radius = options.series.pie.label.radius;
+					else
+						var radius = maxRadius * options.series.pie.label.radius;
+					
+					for (var i = 0; i < slices.length; ++i)
+					{
+						if (slices[i].percent >= options.series.pie.label.threshold*100)
+							drawLabel(slices[i], currentAngle, i);
+						currentAngle += slices[i].angle;
+					}
+					
+					function drawLabel(slice, startAngle, index)
+					{
+						if (slice.data[0][1]==0)
+							return;
+							
+						// format label text
+						var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
+						if (lf)
+							text = lf(slice.label, slice);
+						else
+							text = slice.label;
+						if (plf)
+							text = plf(text, slice);
+							
+						var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
+						var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
+						var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
+						
+						var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
+						target.append(html);
+						var label = target.children('#pieLabel'+index);
+						var labelTop = (y - label.height()/2);
+						var labelLeft = (x - label.width()/2);
+						label.css('top', labelTop);
+						label.css('left', labelLeft);
+						
+						// check to make sure that the label is not outside the canvas
+						if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
+							redraw = true;
+						
+						if (options.series.pie.label.background.opacity != 0) {
+							// put in the transparent background separately to avoid blended labels and label boxes
+							var c = options.series.pie.label.background.color;
+							if (c == null) {
+								c = slice.color;
+							}
+							var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
+							$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
+						}
+					} // end individual label function
+				} // end drawLabels function
+			} // end drawPie function
+		} // end draw function
+		
+		// Placed here because it needs to be accessed from multiple locations 
+		function drawDonutHole(layer)
+		{
+			// draw donut hole
+			if(options.series.pie.innerRadius > 0)
+			{
+				// subtract the center
+				layer.save();
+				innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
+				layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
+				layer.beginPath();
+				layer.fillStyle = options.series.pie.stroke.color;
+				layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+				layer.fill();
+				layer.closePath();
+				layer.restore();
+				
+				// add inner stroke
+				layer.save();
+				layer.beginPath();
+				layer.strokeStyle = options.series.pie.stroke.color;
+				layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+				layer.stroke();
+				layer.closePath();
+				layer.restore();
+				// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
+			}
+		}
+		
+		//-- Additional Interactive related functions --
+		
+		function isPointInPoly(poly, pt)
+		{
+			for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
+				((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
+				&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
+				&& (c = !c);
+			return c;
+		}
+		
+		function findNearbySlice(mouseX, mouseY)
+		{
+			var slices = plot.getData(),
+				options = plot.getOptions(),
+				radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+			
+			for (var i = 0; i < slices.length; ++i) 
+			{
+				var s = slices[i];	
+				
+				if(s.pie.show)
+				{
+					ctx.save();
+					ctx.beginPath();
+					ctx.moveTo(0,0); // Center of the pie
+					//ctx.scale(1, options.series.pie.tilt);	// this actually seems to break everything when here.
+					ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
+					ctx.closePath();
+					x = mouseX-centerLeft;
+					y = mouseY-centerTop;
+					if(ctx.isPointInPath)
+					{
+						if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
+						{
+							//alert('found slice!');
+							ctx.restore();
+							return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+						}
+					}
+					else
+					{
+						// excanvas for IE doesn;t support isPointInPath, this is a workaround. 
+						p1X = (radius * Math.cos(s.startAngle));
+						p1Y = (radius * Math.sin(s.startAngle));
+						p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
+						p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
+						p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
+						p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
+						p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
+						p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
+						p5X = (radius * Math.cos(s.startAngle+s.angle));
+						p5Y = (radius * Math.sin(s.startAngle+s.angle));
+						arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
+						arrPoint = [x,y];
+						// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
+						if(isPointInPoly(arrPoly, arrPoint))
+						{
+							ctx.restore();
+							return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+						}			
+					}
+					ctx.restore();
+				}
+			}
+			
+			return null;
+		}
+
+		function onMouseMove(e) 
+		{
+			triggerClickHoverEvent('plothover', e);
+		}
+		
+        function onClick(e) 
+		{
+			triggerClickHoverEvent('plotclick', e);
+        }
+
+		// trigger click or hover event (they send the same parameters so we share their code)
+		function triggerClickHoverEvent(eventname, e) 
+		{
+			var offset = plot.offset(),
+				canvasX = parseInt(e.pageX - offset.left),
+				canvasY =  parseInt(e.pageY - offset.top),
+				item = findNearbySlice(canvasX, canvasY);
+			
+			if (options.grid.autoHighlight) 
+			{
+				// clear auto-highlights
+				for (var i = 0; i < highlights.length; ++i) 
+				{
+					var h = highlights[i];
+					if (h.auto == eventname && !(item && h.series == item.series))
+						unhighlight(h.series);
+				}
+			}
+			
+			// highlight the slice
+			if (item) 
+			    highlight(item.series, eventname);
+				
+			// trigger any hover bind events
+			var pos = { pageX: e.pageX, pageY: e.pageY };
+			target.trigger(eventname, [ pos, item ]);	
+		}
+
+		function highlight(s, auto) 
+		{
+			if (typeof s == "number")
+				s = series[s];
+
+			var i = indexOfHighlight(s);
+			if (i == -1) 
+			{
+				highlights.push({ series: s, auto: auto });
+				plot.triggerRedrawOverlay();
+			}
+			else if (!auto)
+				highlights[i].auto = false;
+		}
+
+		function unhighlight(s) 
+		{
+			if (s == null) 
+			{
+				highlights = [];
+				plot.triggerRedrawOverlay();
+			}
+			
+			if (typeof s == "number")
+				s = series[s];
+
+			var i = indexOfHighlight(s);
+			if (i != -1) 
+			{
+				highlights.splice(i, 1);
+				plot.triggerRedrawOverlay();
+			}
+		}
+
+		function indexOfHighlight(s) 
+		{
+			for (var i = 0; i < highlights.length; ++i) 
+			{
+				var h = highlights[i];
+				if (h.series == s)
+					return i;
+			}
+			return -1;
+		}
+
+		function drawOverlay(plot, octx) 
+		{
+			//alert(options.series.pie.radius);
+			var options = plot.getOptions();
+			//alert(options.series.pie.radius);
+			
+			var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+
+			octx.save();
+			octx.translate(centerLeft, centerTop);
+			octx.scale(1, options.series.pie.tilt);
+			
+			for (i = 0; i < highlights.length; ++i) 
+				drawHighlight(highlights[i].series);
+			
+			drawDonutHole(octx);
+
+			octx.restore();
+
+			function drawHighlight(series) 
+			{
+				if (series.angle < 0) return;
+				
+				//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
+				octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
+				
+				octx.beginPath();
+				if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
+					octx.moveTo(0,0); // Center of the pie
+				octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
+				octx.closePath();
+				octx.fill();
+			}
+			
+		}	
+		
+	} // end init (plugin body)
+	
+	// define pie specific options and their default values
+	var options = {
+		series: {
+			pie: {
+				show: false,
+				radius: 'auto',	// actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
+				innerRadius:0, /* for donut */
+				startAngle: 3/2,
+				tilt: 1,
+				offset: {
+					top: 0,
+					left: 'auto'
+				},
+				stroke: {
+					color: '#FFF',
+					width: 1
+				},
+				label: {
+					show: 'auto',
+					formatter: function(label, slice){
+						return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
+					},	// formatter function
+					radius: 1,	// radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
+					background: {
+						color: null,
+						opacity: 0
+					},
+					threshold: 0	// percentage at which to hide the label (i.e. the slice is too narrow)
+				},
+				combine: {
+					threshold: -1,	// percentage at which to combine little slices into one larger slice
+					color: null,	// color to give the new slice (auto-generated if null)
+					label: 'Other'	// label to give the new slice
+				},
+				highlight: {
+					//color: '#FFF',		// will add this functionality once parseColor is available
+					opacity: 0.5
+				}
+			}
+		}
+	};
+    
+	$.plot.plugins.push({
+		init: init,
+		options: options,
+		name: "pie",
+		version: "1.0"
+	});
+})(jQuery);

Added: incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.resize.js
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.resize.js?rev=1537021&view=auto
==============================================================================
--- incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.resize.js (added)
+++ incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.resize.js Wed Oct 30 09:50:51 2013
@@ -0,0 +1,60 @@
+/* Flot plugin for automatically redrawing plots as the placeholder resizes.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+It works by listening for changes on the placeholder div (through the jQuery
+resize event plugin) - if the size changes, it will redraw the plot.
+
+There are no options. If you need to disable the plugin for some plots, you
+can just fix the size of their placeholders.
+
+*/
+
+/* Inline dependency:
+ * jQuery resize event - v1.1 - 3/14/2010
+ * http://benalman.com/projects/jquery-resize-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
+
+(function ($) {
+    var options = { }; // no options
+
+    function init(plot) {
+        function onResize() {
+            var placeholder = plot.getPlaceholder();
+
+            // somebody might have hidden us and we can't plot
+            // when we don't have the dimensions
+            if (placeholder.width() == 0 || placeholder.height() == 0)
+                return;
+
+            plot.resize();
+            plot.setupGrid();
+            plot.draw();
+        }
+        
+        function bindEvents(plot, eventHolder) {
+            plot.getPlaceholder().resize(onResize);
+        }
+
+        function shutdown(plot, eventHolder) {
+            plot.getPlaceholder().unbind("resize", onResize);
+        }
+        
+        plot.hooks.bindEvents.push(bindEvents);
+        plot.hooks.shutdown.push(shutdown);
+    }
+    
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'resize',
+        version: '1.0'
+    });
+})(jQuery);
\ No newline at end of file

Added: incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.tooltip.min.js
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.tooltip.min.js?rev=1537021&view=auto
==============================================================================
--- incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.tooltip.min.js (added)
+++ incubator/sirona/trunk/reporting/src/main/resources/resources/js/flot/jquery.flot.tooltip.min.js Wed Oct 30 09:50:51 2013
@@ -0,0 +1,12 @@
+/*
+ * jquery.flot.tooltip
+ * 
+ * description: easy-to-use tooltips for Flot charts
+ * version: 0.6.2
+ * author: Krzysztof Urbas @krzysu [myviews.pl]
+ * website: https://github.com/krzysu/flot.tooltip
+ * 
+ * build on 2013-09-30
+ * released under MIT License, 2012
+*/ 
+(function(t){var o={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},i=function(t){this.tipPosition={x:0,y:0},this.init(t)};i.prototype.init=function(o){function i(t){var o={};o.x=t.pageX,o.y=t.pageY,s.updateTooltipPosition(o)}function e(t,o,i){var e=s.getDomElement();if(i){var n;n=s.stringFormat(s.tooltipOptions.content,i),e.html(n),s.updateTooltipPosition({x:o.pageX,y:o.pageY}),e.css({left:s.tipPosition.x+s.tooltipOptions.shifts.x,top:s.tipPosition.y+s.tooltipOptions.shifts.y}).show(),"function"==typeof s.tooltipOptions.onHover&&s.tooltipOptions.onHover(i,e)}else e.hide().html("")}var s=this;o.hooks.bindEvents.push(function(o,n){s.plotOptions=o.getOptions(),s.plotOptions.tooltip!==!1&&void 0!==s.plotOptions.tooltip&&(s.tooltipOptions=s.plotOptions.tooltipOpts,s.getDomElement(),t(o.getPlaceholder()).bind("plothover",e),t(n).bind("mousemove",i))}),o.hooks.shutdown.push(function(o,s){t(o.g
 etPlaceholder()).unbind("plothover",e),t(s).unbind("mousemove",i)})},i.prototype.getDomElement=function(){var o;return t("#flotTip").length>0?o=t("#flotTip"):(o=t("<div />").attr("id","flotTip"),o.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&o.css({background:"#fff","z-index":"100",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),o},i.prototype.updateTooltipPosition=function(o){var i=t("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,e=t("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;o.x-t(window).scrollLeft()>t(window).innerWidth()-i&&(o.x-=i),o.y-t(window).scrollTop()>t(window).innerHeight()-e&&(o.y-=e),this.tipPosition.x=o.x,this.tipPosition.y=o.y},i.prototype.stringFormat=function(t,o){var i=/%p\.{0,1}(\d{0,})/,e=/%s/,s=/%x\.{0,1}(?:\d{0,})/,n=/%y\.{0,1}(?:\d{0,})/;return"function"==typeof t&&(t=t(o.series.label,o.series.data[o.dataIndex][0],o.se
 ries.data[o.dataIndex][1],o)),o.series.percent!==void 0&&(t=this.adjustValPrecision(i,t,o.series.percent)),o.series.label!==void 0&&(t=t.replace(e,o.series.label)),this.isTimeMode("xaxis",o)&&this.isXDateFormat(o)&&(t=t.replace(s,this.timestampToDate(o.series.data[o.dataIndex][0],this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",o)&&this.isYDateFormat(o)&&(t=t.replace(n,this.timestampToDate(o.series.data[o.dataIndex][1],this.tooltipOptions.yDateFormat))),"number"==typeof o.series.data[o.dataIndex][0]&&(t=this.adjustValPrecision(s,t,o.series.data[o.dataIndex][0])),"number"==typeof o.series.data[o.dataIndex][1]&&(t=this.adjustValPrecision(n,t,o.series.data[o.dataIndex][1])),o.series.xaxis.tickFormatter!==void 0&&(t=t.replace(s,o.series.xaxis.tickFormatter(o.series.data[o.dataIndex][0],o.series.xaxis))),o.series.yaxis.tickFormatter!==void 0&&(t=t.replace(n,o.series.yaxis.tickFormatter(o.series.data[o.dataIndex][1],o.series.yaxis))),t},i.prototype.isTimeMode=function(t,o){retur
 n o.series[t].options.mode!==void 0&&"time"===o.series[t].options.mode},i.prototype.isXDateFormat=function(){return this.tooltipOptions.xDateFormat!==void 0&&null!==this.tooltipOptions.xDateFormat},i.prototype.isYDateFormat=function(){return this.tooltipOptions.yDateFormat!==void 0&&null!==this.tooltipOptions.yDateFormat},i.prototype.timestampToDate=function(o,i){var e=new Date(o);return t.plot.formatDate(e,i)},i.prototype.adjustValPrecision=function(t,o,i){var e,s=o.match(t);return null!==s&&""!==RegExp.$1&&(e=RegExp.$1,i=i.toFixed(e),o=o.replace(t,i)),o};var e=function(t){new i(t)};t.plot.plugins.push({init:e,options:o,name:"tooltip",version:"0.6.1"})})(jQuery);
\ No newline at end of file