You are viewing a plain text version of this content. The canonical link for it is here.
Posted to adffaces-commits@incubator.apache.org by aw...@apache.org on 2006/09/28 18:07:59 UTC
svn commit: r450952 [3/6] - in /incubator/adffaces/trunk/trinidad:
src/site/xdoc/devguide/
trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/
trinidad-api/src/main/java/org/apache/myfaces/trinidad/event/
trinidad-api/src/main/j...
Added: incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/ApacheChart.js
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/ApacheChart.js?view=auto&rev=450952
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/ApacheChart.js (added)
+++ incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/ApacheChart.js Thu Sep 28 11:07:57 2006
@@ -0,0 +1,5315 @@
+/////////////////////////////////////////////
+// Some utility functions
+/////////////////////////////////////////////
+
+/**
+* Base Class that provides inheritence for charting subsystem
+* @constructor
+*/
+function ApacheChartObj()
+{
+ this.Init();
+}
+
+ApacheChartObj.prototype = new Object();
+ApacheChartObj.prototype.constructor = ApacheChartObj;
+ApacheChartObj._tempConstructor = function(){}
+
+ApacheChartObj.Inherit = function(baseClass, extendingClass)
+{
+ var tempConstructor = ApacheChartObj._tempConstructor;
+
+ tempConstructor.prototype = baseClass.prototype;
+ extendingClass.prototype = new tempConstructor();
+
+ extendingClass.prototype.constructor = extendingClass;
+ extendingClass.superclass = baseClass.prototype;
+}
+
+ApacheChartObj.prototype.createCallback = function(func)
+{
+ // create a function that sets up "this" and delegates all of the parameters
+ // to the passed in function
+ var proxyFunction = new Function(
+ "var f=arguments.callee; return f._func.apply(f._owner, arguments);");
+
+ // attach ourselves as "this" to the created function
+ proxyFunction._owner = this;
+
+ // attach function to delegate to
+ proxyFunction._func = func;
+
+ return proxyFunction;
+}
+
+/**
+* Asserts arg is true; else throws error with msg.
+*/
+ApacheChartObj.Assert = function(arg, msg)
+{
+ if (!arg)
+ {
+ throw new Error(msg);
+ }
+}
+
+
+/**
+* StringBuffer utility used by the charting
+*/
+function ApacheChartBuffer(size)
+{
+ this.maxStreamLength = document.all?5000:100000;
+ this.data = new Array(size?size:100);
+ this.iStr = 0;
+}
+
+ApacheChartBuffer.prototype.append = function(obj)
+{
+ this.data[this.iStr++] = obj;
+ if (this.data.length > this.maxStreamLength)
+ {
+ this.data = [this.data.join("")];
+ this.data.length = 100;
+ this.iStr = 1;
+ }
+ return this;
+}
+
+ApacheChartBuffer.prototype.toString = function()
+{
+ return this.data.join("");
+}
+
+////////////////////////////////////////////////////////////////////
+// Abstract Data Structure representing the model for drawing a chart control
+////////////////////////////////////////////////////////////////////
+function ApacheChartModel(seriesLabels, groupLabels, yValues, xValues, seriesColors)
+{
+ // An array representing series labels
+ this._seriesLabels = seriesLabels;
+ // An array representing Group labels
+ this._groupLabels = groupLabels;
+ // A 2D array representing values for Y axis
+ this._yValues = yValues;
+ // A 2D array representing values for X axis.
+ // The x axis values are used only for scatter plots/XYline
+ this._xValues = xValues;
+ // The array of strings with colors. Used for display of the series
+ this._seriesColors = seriesColors;
+
+ // the maximum value used to display the y-axis.
+ // Default is 20% of maximum of the yValues
+ //this._maxYValue = undefined;
+
+ // the minimum value used to display the y-axis. Default is 0
+ this._minYValue = 0;
+
+ // the maximum value used to display the X-axis.
+ // Default is 20% of maximum of the xValues
+ //this._maxXValue = undefined;
+
+ // the minimum value used to display the y-axis. Default is 0
+ this._minXValue = 0;
+
+ // The title for the graph
+ //this._title = undefined;
+
+ // The sub-title for the graph
+ //this._subTitle = undefined;
+
+ // The foot node for the graph
+ //this._footNote = undefined;
+}
+
+ApacheChartModel.prototype.getSeriesLabels = function()
+{
+ return this._seriesLabels;
+}
+
+ApacheChartModel.prototype.getGroupLabels = function()
+{
+ return this._groupLabels;
+}
+
+ApacheChartModel.prototype.getSeriesColors = function()
+{
+ return this._seriesColors;
+}
+
+ApacheChartModel.prototype.getXValues = function()
+{
+ return this._xValues;
+}
+
+ApacheChartModel.prototype.getYValues = function()
+{
+ return this._yValues;
+}
+
+ApacheChartModel.prototype.setMaxYValue = function(maxYValue)
+{
+ this._maxYValue = maxYValue;
+}
+
+ApacheChartModel.prototype.getMaxYValue = function()
+{
+ return this._maxYValue;
+}
+
+ApacheChartModel.prototype.setMinYValue = function(minYValue)
+{
+ this._minYValue = minYValue;
+}
+
+ApacheChartModel.prototype.getMinYValue = function()
+{
+ return this._minYValue;
+}
+
+ApacheChartModel.prototype.setMaxXValue = function(maxXValue)
+{
+ this._maxXValue = maxXValue;
+}
+
+ApacheChartModel.prototype.getMaxXValue = function()
+{
+ return this._maxXValue;
+}
+
+ApacheChartModel.prototype.setMinXValue = function(minXValue)
+{
+ this._minXValue = minXValue;
+}
+
+ApacheChartModel.prototype.getMinXValue = function()
+{
+ return this._minXValue;
+}
+
+ApacheChartModel.prototype.setTitle = function(title)
+{
+ this._title = title;
+}
+
+ApacheChartModel.prototype.getTitle = function()
+{
+ return this._title;
+}
+
+ApacheChartModel.prototype.setSubTitle = function(subTitle)
+{
+ this._subTitle = subTitle;
+}
+
+ApacheChartModel.prototype.getSubTitle = function()
+{
+ return this._subTitle;
+}
+
+ApacheChartModel.prototype.setFootNote = function(footNote)
+{
+ this._footNote = footNote;
+}
+
+ApacheChartModel.prototype.getFootNote = function()
+{
+ return this._footNote;
+}
+
+////////////////////////////////////////////////////////////////////
+// A Chart Event that is triggered in response to a user click
+// This event can be marshalled to the server if integration is done
+// with a J2EE platform platform
+////////////////////////////////////////////////////////////////////
+function ApacheChartEvent(seriesIndices, yValueIndices, yValues, xValues)
+{
+ this._seriesIndices = seriesIndices;
+ this._yValueIndices = yValueIndices;
+ this._yValues = yValues;
+ this._xValues = xValues;
+}
+
+ApacheChartEvent.prototype.getSeriesIndices = function()
+{
+ return this._seriesIndices;
+}
+
+ApacheChartEvent.prototype.getYValueIndices = function()
+{
+ return this._yValueIndices;
+}
+
+ApacheChartEvent.prototype.getYValues = function()
+{
+ return this._yValues;
+}
+
+ApacheChartEvent.prototype.getXValues = function()
+{
+ return this._xValues;
+}
+
+ApacheChartEvent.prototype.toString = function()
+{
+ var sb = new ApacheChartBuffer();
+ if(this._seriesIndices)
+ sb.append("seriesIndices = "+ this._seriesIndices.join(","));
+ if(this._yValueIndices)
+ sb.append("\yValueIndices = "+ this._yValueIndices.join(","));
+ sb.append("\nyValues = "+ this._yValues.join(","));
+ if(this._xValues)
+ sb.append("\nxValues = "+ this._xValues.join(","));
+
+ return sb.toString();
+}
+
+ApacheChartEvent.prototype.marshall = function()
+{
+ var value = new Array();
+ if(this._seriesIndices)
+ value.push("seriesIndices\t"+this._seriesIndices.join("\t"));
+ if(this._yValueIndices)
+ value.push("yValueIndices\t"+this._yValueIndices.join("\t"));
+ value.push("yValues\t"+this._yValues.join("\t"));
+ if(this._xValues)
+ value.push("xValues\t"+this._xValues.join("\t"));
+
+ return value.join("$adf$");
+}
+////////////////////////////////////////////////////////////////////
+// Abstract Base Class for rendering a Chart control
+////////////////////////////////////////////////////////////////////
+function ApacheChart(type, model, svgEmbedId, isPerspective, legendPosition)
+{
+ this.Init(type, model, svgEmbedId, isPerspective, legendPosition);
+}
+
+// Hack for IE. The SVG has to be loaded externally otherwise,
+// it needs to be activated by clicking
+ApacheChart.createSVG = function(containerId,
+ svgEmbedId, sourceUrl, inlineStyle, styleClass)
+{
+ var svgContainer = document.getElementById(containerId);
+ var embed = document.createElement("embed");
+ var agent = window._agent;
+ if(agent && agent.isIE)
+ {
+ var semiColIndex = sourceUrl.indexOf(";");
+ if(semiColIndex!=-1)
+ sourceUrl = sourceUrl.substr(0,semiColIndex);
+ }
+ embed.setAttribute("src",sourceUrl);
+ embed.setAttribute("id",svgEmbedId);
+ embed.setAttribute("wmode","transparent");
+ embed.setAttribute("type","image/svg+xml");
+
+ if(agent && agent.isOpera)
+ {
+ // opera does not like 100% width and 100% height.
+ var style = document.defaultView.getComputedStyle(svgContainer, null);
+ var embedStyle = embed.style;
+ embedStyle.width = style.width;
+ embedStyle.height = style.height;
+ }
+ else
+ {
+ embed.style.cssText = inlineStyle;
+ }
+ if(styleClass)
+ {
+ embed.className = styleClass;
+ }
+ svgContainer.appendChild(embed);
+}
+
+/**
+ * Method to detect if Adobe ActiveX controll is initialized on the machine
+ */
+ApacheChart.isASVInstalled = function()
+{
+ try{
+ var asv = new ActiveXObject("Adobe.SVGCtl");
+ return true;
+ }
+ catch(e){
+ }
+ return false;
+}
+ApacheChartObj.Inherit(ApacheChartObj, ApacheChart);
+
+ApacheChart.prototype.Init = function(type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ this._type = type;
+ this._model = model;
+ this._svgEmbedId = svgEmbedId;
+ this._margins = {left:2,right:2,top:2,bottom:2};
+ // By default the graphs are drawn with a perspective(2.5D)
+ this._isPerspective = isPerspective;
+ this._legendPosition = legendPosition;
+ //this._rootElement = undefined;
+ this._toolTip = null;
+ this._toolTipVisible = false;
+ //this._svgDoc = undefined;
+ //this._width = undefined;
+ //this._height = undefined;
+ //this._vLabelContainer = undefined;
+ //this._hLabelContainer = undefined;
+
+ // By default the graph animates for 1.5 s
+ this._animDuration = 1500;
+ this._dataElems = [];
+ this._labelElems = [];
+ this._gridElems = [];
+
+ // The group labels
+ this._groupLabelElems = [];
+
+ // The number of Major Line sections to draw on y axis
+ this._yMajorGridCount = 8;
+ // The number of Minor Line section to draw on y axis
+ this._yMinorGridCount = -1;
+
+ // The number of Major Line sections to draw on x axis
+ this._xMajorGridCount = -1;
+
+ // Controls if the tooltips are displayed or not
+ this._tooltipsVisible = true;
+
+ // By default we will use gradients
+ this._gradientsUsed = true;
+
+ // The maximum precision of the numbers displayed on yaxis/tooltips
+ this._maxPrecision = 0;
+
+ // The decimal separator
+ this._decimalSep = null;
+
+ // The form from which we will submit
+ this._formName = null;
+ this._partialSubmit = true;
+
+ this._svgCheckTotal = 0;
+ this._errorTextNode = null;
+ this._isIE = false;
+ if(window._agent) // use trinidad agent
+ this._isIE = _agent.isIE;
+
+ if(this._isIE)
+ this._errorHtml = "<H4>Unable to load SVG plugin. Please install the plugin from <a href='#' onclick=\"window.open('http://www.adobe.com/svg/viewer/install/main.html')\">Adobe</a><H4>";
+ else
+ this._errorHtml = "<H4>This component needs an SVG enabled browser like Internet Explorer, Firefox 1.5+ or Opera 9.0+<H4>";
+
+ this._statusHtml = "<H4>Please Wait. Attempting to load SVG document...</H4>";
+ this.ComputeMaxValues();
+}
+
+/**
+ * Error text to be displayed in the container of the embed,
+ * in case the svg document fails to load.
+ * NOTE: the error text can be customized by browser for e.g. in IE it can contain
+ * the link to SVG plugin download
+ */
+ApacheChart.prototype.setErrorHtml = function(errorHtml)
+{
+ this._errorHtml = errorHtml;
+}
+
+/**
+ * Status text that is displayed when the SVG document is taking a while to load
+ */
+ApacheChart.prototype.setStatusHtml = function(statusHtml)
+{
+ this._statusHtml = statusHtml;
+}
+
+ApacheChart.prototype.setYMajorGridLineCount = function(count)
+{
+ // number of sections is 1 greater than the lines
+ this._yMajorGridCount = count>0?count+1:count;
+}
+
+
+ApacheChart.prototype.setYMinorGridLineCount = function(count)
+{
+ // number of sections is 1 greater than the lines
+ this._yMinorGridCount = count>0?count+1:count;
+}
+
+ApacheChart.prototype.setXMajorGridLineCount = function(count)
+{
+ // number of sections is 1 greater than the lines
+ this._xMajorGridCount = count>0?count+1:count;
+}
+
+
+ApacheChart.prototype.setAnimationDuration = function(dur)
+{
+ this._animDuration = dur;
+}
+
+ApacheChart.prototype.setGradientsUsed = function(gradient)
+{
+ this._gradientsUsed = gradient;
+}
+
+ApacheChart.prototype.setMaxPrecision = function(precision)
+{
+ this._maxPrecision = precision;
+}
+
+ApacheChart.prototype.setFormName = function(formName)
+{
+ this._formName = formName;
+}
+
+ApacheChart.prototype.setPartialSubmit = function(partial)
+{
+ this._partialSubmit = partial;
+}
+
+ApacheChart.prototype.setTooltipsVisible = function(visible)
+{
+ this._tooltipsVisible = visible;
+}
+
+ApacheChart.prototype.getToolTip = function()
+{
+ return this._toolTip;
+}
+
+ApacheChart.prototype.setToolTip = function(tt)
+{
+ this._toolTip = tt;
+}
+
+ApacheChart.prototype.ComputeMaxValues = function()
+{
+ var model = this._model, yValues = model.getYValues(), xValues = model.getXValues(),
+ maxYValue = model.getMaxYValue(), maxXValue = model.getMaxXValue(),
+ seriesLabels = model.getSeriesLabels();
+ if(yValues != null && maxYValue == null)
+ model.setMaxYValue(this._computeAxisMaxValues(yValues, seriesLabels.length));
+
+ if(xValues != null && maxXValue == null)
+ model.setMaxXValue(this._computeAxisMaxValues(xValues, seriesLabels.length));
+}
+
+ApacheChart.prototype._computeAxisMaxValues = function(values, seriesSize)
+{
+ var stackedTotal, maxValue = 0, type = this._type,
+ isStacked = false, groupsCount = values.length;
+
+ if(type == ApacheChart.TYPE_VBAR_STACKED || type == ApacheChart.TYPE_HBAR_STACKED ||
+ type == ApacheChart.TYPE_AREA_STACKED)
+ {
+ isStacked = true;
+ }
+ for (var i = 0; i < groupsCount; ++i)
+ {
+ stackedTotal = 0;
+ for (var j = 0; j < seriesSize; ++j)
+ {
+ if (isStacked)
+ stackedTotal += values[i][j];
+ else
+ maxValue = Math.max(maxValue, values[i][j]);
+ }
+ if (isStacked)
+ maxValue = Math.max(maxValue, stackedTotal);
+ }
+ return maxValue*ApacheChart._MAX_MULTIPLIER;
+}
+
+ApacheChart.TYPE_VBAR = 1;
+ApacheChart.TYPE_HBAR = 2;
+ApacheChart.TYPE_VBAR_STACKED = 3;
+ApacheChart.TYPE_HBAR_STACKED = 4;
+ApacheChart.TYPE_PIE = 5;
+ApacheChart.TYPE_AREA = 6;
+ApacheChart.TYPE_AREA_STACKED = 7;
+ApacheChart.TYPE_LINE = 8;
+ApacheChart.TYPE_BAR_LINE_COMBO = 9;
+ApacheChart.TYPE_XYLINE = 10;
+ApacheChart.TYPE_SCATTER_PLOT = 11;
+ApacheChart.TYPE_RADAR = 12;
+ApacheChart.TYPE_RADAR_AREA = 13;
+ApacheChart.TYPE_FUNNEL = 14;
+ApacheChart.CIRCULAR_GAUGE = 15;
+ApacheChart.SEMI_CIRCULAR_GAUGE = 16;
+
+ApacheChart.LEGEND_LOCATION_NONE = "none";
+ApacheChart.LEGEND_LOCATION_TOP = "top";
+ApacheChart.LEGEND_LOCATION_END = "end";
+ApacheChart.LEGEND_LOCATION_BOTTOM = "bottom";
+ApacheChart.LEGEND_LOCATION_START = "start";
+
+ApacheChart._MAX_MULTIPLIER = 1.2;
+ApacheChart._XOFFSET_PERSPECTIVE = 10;
+ApacheChart._YOFFSET_PERSPECTIVE = 5;
+// margin generally used around text
+ApacheChart._TEXT_MARGIN = 4;
+ApacheChart._DEFAULT_STOP_OPACITY = .9;
+ApacheChart._BORDER_SIZE = 6;
+// Animate at 15 fps
+ApacheChart._ANIMATE_INTERVAL = 66;
+
+ApacheChart._SVGCHECK_INTERVAL = 100;
+ApacheChart._SVGCHECK_STATUS_LIMIT = 5000;
+ApacheChart._SVGCHECK_MAX_LIMIT = 20000;
+
+ApacheChart.createChart = function(
+ type,
+ model,
+ svgEmbedId,
+ isPerspective,
+ legendPosition)
+{
+ var chart = null;
+ if(type == this.TYPE_VBAR || type == this.TYPE_VBAR_STACKED || type == this.TYPE_BAR_LINE_COMBO)
+ {
+ chart = new ApacheBarChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_HBAR || type == this.TYPE_HBAR_STACKED)
+ {
+ chart = new ApacheHBarChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_PIE)
+ {
+ chart = new ApachePieChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_AREA || type == this.TYPE_AREA_STACKED)
+ {
+ chart = new ApacheAreaChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_LINE)
+ {
+ chart = new ApacheLineChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_SCATTER_PLOT)
+ {
+ chart = new ApacheScatterPlotChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_XYLINE)
+ {
+ chart = new ApacheXYLineChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_RADAR || type == this.TYPE_RADAR_AREA)
+ {
+ chart = new ApacheRadarChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.TYPE_FUNNEL)
+ {
+ chart = new ApacheFunnelChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.SEMI_CIRCULAR_GAUGE)
+ {
+ chart = new ApacheSemiGaugeChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ else if(type == this.CIRCULAR_GAUGE)
+ {
+ chart = new ApacheGaugeChart(type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ }
+ return chart;
+}
+
+ApacheChart.prototype.setPerspective = function(isPerpective)
+{
+ this._isPerspective = isPerpective;
+}
+
+ApacheChart.prototype.clear = function()
+{
+ var rootElem = this._rootElement;
+ var childNode = rootElem.firstChild;
+ while (childNode)
+ {
+ rootElem.removeChild(childNode);
+ childNode = rootElem.firstChild;
+ }
+}
+
+ApacheChart.prototype.draw = function()
+{
+ if(!this._initDocument())
+ return;
+
+ // Initialize our gradients if necessary
+ if (this._gradientsUsed && !this._gradientsInitialized)
+ {
+ this.InitializeGradients();
+ this._gradientsInitialized = true;
+ }
+ if(this._tooltipsVisible)
+ {
+ this.ShowToolTipCallback = this.createCallback(this.ShowToolTip);
+ this.HideToolTipCallback = this.createCallback(this.HideToolTip);
+ }
+ this.ClickCallback = this.createCallback(this.Click);
+
+ // Note the ordering is important. The grid takes the space after the title etc.
+ this.DrawBorder();
+ this.DrawTitles();
+ // First just draw the label elements so that we can estimate the space requirements
+ this.DrawGroupLabels();
+ this.DrawYValueLabels();
+ // Now adjust margins based on the labels
+ this.AdjustMarginsForGroupLabels();
+ this.AdjustMarginsForYLabels();
+ // Now start drawing the graph so that it gobbles the left over space
+ this.DrawLegend();
+ this.LayoutGroupLabels();
+ this.LayoutYValueLabels();
+ this.DrawGrid();
+ this.DrawChartData();
+ this.Animate();
+}
+
+ApacheChart.prototype._initDocument = function()
+{
+ // Get hold of the svgDocument
+ var svgEmbed = document.getElementById(this._svgEmbedId);
+
+ var isIE = this._isIE;
+ if(isIE && !ApacheChart.isASVInstalled())
+ {
+ this._displayErrorHtml(svgEmbed);
+ return false;
+ }
+ try
+ {
+ var svgDoc = svgEmbed.getSVGDocument();
+ this._rootElement = svgDoc.getElementById("chartRoot");
+ if(!this._rootElement) // make sure that the document is loaded
+ throw "not yet loaded";
+ this._svgDoc = svgDoc;
+ this._width = svgEmbed.clientWidth;
+ this._height = svgEmbed.clientHeight;
+ if(this._errorTextNode != null)
+ {
+ svgEmbed.parentNode.removeChild(this._errorTextNode);
+ svgEmbed.style.display = "";
+ }
+ }
+ catch(e)
+ {
+ this._svgCheckTotal += ApacheChart._SVGCHECK_INTERVAL;
+ if(this._svgCheckTotal > ApacheChart._SVGCHECK_MAX_LIMIT)
+ {
+ // We are out of our chances
+ this._displayErrorHtml(svgEmbed);
+ return false;
+ }
+ else if(null == this._errorTextNode &&
+ this._svgCheckTotal > ApacheChart._SVGCHECK_STATUS_LIMIT)
+ {
+ // display a status message
+ this._displayStatusHtml(svgEmbed);
+ }
+
+ if(!this._drawCallback)
+ this._drawCallback = this.createCallback(this.draw);
+ // Lets try again
+ window.setTimeout(this._drawCallback, ApacheChart._SVGCHECK_INTERVAL);
+ return false;
+ }
+ return true;
+}
+
+ApacheChart.prototype._displayStatusHtml = function(svgEmbed)
+{
+ var errorTextNode = this._errorTextNode = document.createElement("span");
+ errorTextNode.innerHTML = this._statusHtml;
+ svgEmbed.parentNode.insertBefore(errorTextNode, svgEmbed);
+ svgEmbed.style.display = "none";
+}
+
+ApacheChart.prototype._displayErrorHtml = function(svgEmbed)
+{
+ if(this._errorTextNode)
+ {
+ this._errorTextNode.innerHTML = this._errorHtml;
+ return;
+ }
+ else
+ {
+ var errorTextNode = this._errorTextNode = document.createElement("span");
+ errorTextNode.innerHTML = this._errorHtml;
+ svgEmbed.parentNode.insertBefore(errorTextNode, svgEmbed);
+ }
+ svgEmbed.style.display = "none";
+}
+
+ApacheChart.prototype.DrawChartData = function()
+{
+ // no default implementation. Subclasses have to override this
+}
+
+ApacheChart.prototype.Animate = function()
+{
+ var animateDuration = this._animDuration;
+ if(animateDuration > 0)
+ {
+ if(this._animCallback == null)
+ this._animCallback = this.createCallback(this.DoAnimation);
+ this._startTime = (new Date()).getTime();
+ this._intervalId = window.setInterval(this._animCallback, ApacheChart._ANIMATE_INTERVAL);
+ }
+}
+
+ApacheChart.prototype.DoAnimation = function()
+{
+ var animateDuration = this._animDuration;
+ var diffTime = (new Date()).getTime() - this._startTime;
+ if(diffTime >= animateDuration)
+ {
+ window.clearInterval(this._intervalId);
+ this.SetDataAnimStep(1);
+ this.SetLabelsAnimStep(1);
+ this.SetGridAnimStep(1);
+ // we do not need the elements any more.
+ delete this._dataElems;
+ delete this._labelElems;
+ delete this._gridElems;
+ }
+ else
+ {
+ var ratio = (diffTime)/animateDuration;
+ this.SetDataAnimStep(ratio);
+ this.SetLabelsAnimStep(ratio);
+ this.SetGridAnimStep(ratio);
+ }
+}
+
+ApacheChart.prototype.SetDataAnimStep = function(ratio)
+{
+ var animElems = this._dataElems, animCount = animElems.length;
+ var margins = this._margins, animHorizontal = this.AnimAlongXAxis();
+
+ // Default implementation is to make the elements appear from x axis or y axis
+ if(animHorizontal)
+ {
+ var marginLeft = margins.left;
+ for(var i = 0; i < animCount; ++i)
+ {
+ var tx = (1-ratio)*marginLeft;
+ animElems[i].setAttribute("transform", "translate("+tx+",0) scale("+ratio+",1)");
+ }
+ }
+ else
+ {
+ var marginBottom = margins.bottom, cy = (this._height - marginBottom);
+
+ for(var i = 0; i < animCount; ++i)
+ {
+ var ty = (1-ratio)*cy;
+ animElems[i].setAttribute("transform", "translate(0,"+ty+") scale(1,"+ratio+")");
+ }
+ }
+}
+
+ApacheChart.prototype.AnimAlongXAxis = function(ratio)
+{
+ return false;
+}
+
+ApacheChart.prototype.SetLabelsAnimStep = function(ratio)
+{
+ var animElems = this._labelElems, animCount = animElems.length;
+ // Default implementation is to make the elements fade in
+ for(var i = 0; i < animCount; ++i)
+ {
+ animElems[i].setAttribute("fill-opacity", ratio);
+ }
+}
+
+ApacheChart.prototype.SetGridAnimStep = function(ratio)
+{
+ var animElems = this._gridElems, animCount = animElems.length;
+ var margins = this._margins, animHorizontal = this.AnimAlongXAxis();
+
+ // Default implementation is to make the grid appear along the x axis or y axis
+ if(animHorizontal)
+ {
+ var marginBottom = margins.bottom, cy = (this._height - marginBottom);
+
+ // reverse the animation for horizontal chart
+ for(var i = 0; i < animCount; ++i)
+ {
+ var ty = (1-ratio)*cy;
+ animElems[i].setAttribute("transform", "translate(0,"+ty+") scale(1,"+ratio+")");
+ }
+ }
+ else
+ {
+ var marginLeft = margins.left;
+ for(var i = 0; i < animCount; ++i)
+ {
+ var tx = (1-ratio)*marginLeft;
+ animElems[i].setAttribute("transform", "translate("+tx+",0) scale("+ratio+",1)");
+ }
+ }
+}
+
+ApacheChart.prototype.InitializeGradients = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, seriesColors = model.getSeriesColors(),
+ seriesCount = model.getSeriesLabels().length;
+ var gradients = svgDoc.getElementById("gradients");
+
+ ApacheChartObj.Assert(gradients, "No Gradients element in the SVG document");
+ var gradientElements = gradients.childNodes;
+ ApacheChartObj.Assert(gradients.childNodes.length>1, "No Gradient Template in the SVG document");
+ var gradientTemplate = gradients.childNodes[0], gradientElement;
+
+ for (var i = 0; i< seriesCount; ++i)
+ {
+ gradientElement = svgDoc.getElementById("gradient"+i);
+ if(gradientElement == null)
+ {
+ gradientElement = gradientTemplate.cloneNode(true);
+ gradients.appendChild(gradientElement);
+ }
+ var childNode = gradientElement.firstChild;
+ var stopIndex = 0;
+ while (childNode)
+ {
+ if (childNode.nodeName == "stop")
+ {
+ var color = seriesColors[i];
+
+ color = (stopIndex == 0)?color:this._getLighterColor(color);
+
+ childNode.setAttribute("stop-color",color);
+ this.SetStopOpacity(childNode);
+
+ if(stopIndex>=1)
+ break;
+ stopIndex++;
+ }
+ childNode = childNode.nextSibling;
+ }
+ }
+}
+
+ApacheChart.prototype.SetStopOpacity = function(stopNode)
+{
+ // no default implementation
+ stopNode.setAttribute("stop-opacity", ApacheChart._DEFAULT_STOP_OPACITY);
+}
+
+ApacheChart.prototype._getLighterColor = function(color)
+{
+ if(color.indexOf("#") >=0 )
+ {
+ color = color.substr(1);
+ var rVal = color.substr(0,2), gVal = color.substr(2,2), bVal = color.substr(4);
+ color = "#"+this._getLighterNumberStr(rVal)+this._getLighterNumberStr(gVal)+
+ this._getLighterNumberStr(bVal);
+ }
+ else
+ {
+ color = color.toLowerCase().replace(" ", "");
+ color = color.substring(4, color.length-1);
+ var arr = color.split(",");
+ color = "#"+this._getLighterNumberStr(arr[0])+this._getLighterNumberStr(arr[1])+
+ this._getLighterNumberStr(arr[2]);
+ }
+ return color;
+}
+
+ApacheChart.prototype._getLighterNumberStr = function(valStr)
+{
+ var val = Math.round(parseInt(valStr, 16)*1.7);
+ if(val>255)
+ val = 255;
+
+ return this._to_hex(val);
+}
+
+ApacheChart.prototype._to_hex = function(n)
+{
+ var digit_array = ApacheChart._digit_array;
+ if(digit_array == null)
+ {
+ digit_array = ApacheChart._digit_array =
+ ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
+ }
+ var hex_result=''
+ var the_start=true;
+ for(var i=32;i>0;){
+ i-=4;
+ var one_digit=(n>>i)&0xf;
+ if(!the_start||one_digit!=0){
+ the_start=false;
+ hex_result+=digit_array[one_digit];
+ }
+ }
+ return ''+(hex_result==''?'0':hex_result);
+}
+
+ApacheChart.prototype.DrawBorder = function()
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement;
+ var rectElem = svgDoc.getElementById("borderPrototype").cloneNode(false);
+ var borderSize = ApacheChart._BORDER_SIZE, stroke = borderSize/2;
+ rectElem.setAttribute("x", 0);
+ rectElem.setAttribute("y", 0);
+ rectElem.setAttribute("rx", stroke);
+ rectElem.setAttribute("ry", stroke);
+ rectElem.setAttribute("width", this._width-stroke);
+ rectElem.setAttribute("height", this._height-stroke);
+ rectElem.setAttribute("stroke-width", stroke);
+ rootElem.appendChild(rectElem);
+
+ var margins = this._margins;
+ margins.left += borderSize;
+ margins.right += borderSize;
+ margins.top += borderSize;
+ margins.bottom += borderSize;
+}
+
+ApacheChart.prototype.DrawTitles = function()
+{
+ var model = this._model, title = model.getTitle(),
+ subTitle = model.getSubTitle(), footNote = model.getFootNote();
+ if(title)
+ this._drawTitleElem("titleTextPrototype", title, false);
+
+ if(subTitle)
+ this._drawTitleElem("subTitleTextPrototype", subTitle, false);
+
+ if(footNote)
+ this._drawTitleElem("footNoteTextPrototype", footNote, true);
+}
+
+ApacheChart.prototype._drawTitleElem = function(template, title, isFooter)
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement;
+ var margins = this._margins, gridWidth = (this._width - margins.left - margins.right);
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+
+ var textElem = svgDoc.getElementById(template).cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(textElem);
+ textElem.setAttribute("fill-opacity","0");
+ }
+ textElem.firstChild.data = title;
+ rootElem.appendChild(textElem);
+ var textBBox = textElem.getBBox(), textWidth = textBBox.width, dx=margins.left;
+
+ if(isFooter && this._width > textWidth + margins.right)
+ dx = (this._width-textWidth)-margins.right;
+
+ if(!isFooter && gridWidth > textWidth)
+ dx = (gridWidth-textWidth)/2+margins.left;
+
+ textElem.setAttribute("x",dx);
+ if(isFooter)
+ {
+ textElem.setAttribute("y",this._height-margins.bottom);
+ margins.bottom += textBBox.height+ApacheChart._TEXT_MARGIN;
+ }
+ else
+ {
+ margins.top += textBBox.height;
+ textElem.setAttribute("y",margins.top);
+ margins.top += ApacheChart._TEXT_MARGIN;
+ }
+}
+
+ApacheChart.prototype.DrawGroupLabels = function()
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement, model = this._model;
+ var container = svgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
+ this._hLabelContainer = container;
+ var groupLabels = model.getGroupLabels(), vLineCount = groupLabels.length;
+ var labelElem, labelElems = this._labelElems, animate = (this._animDuration>0);
+ var labelText, gLabelElems = this._groupLabelElems;
+
+ for (var i = 0; i< vLineCount; ++i)
+ {
+ // draw the horizontal label
+ if(i==0)
+ {
+ labelElem = svgDoc.getElementById("groupLabelPrototype");
+ }
+ labelText = groupLabels[i];
+ if(!labelText)
+ continue;
+
+ labelElem = labelElem.cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ labelElem.firstChild.data = labelText;
+ container.appendChild(labelElem);
+ gLabelElems[i] = labelElem;
+ }
+ rootElem.appendChild(container);
+}
+
+ApacheChart.prototype.LayoutGroupLabels = function()
+{
+ var model = this._model, margins = this._margins, marginLeft = margins.left;
+ var container = this._hLabelContainer, childNodes = container.childNodes;
+
+ if(childNodes.length == 0)
+ return;
+ if(this._isPerspective)
+ marginLeft += ApacheChart._XOFFSET_PERSPECTIVE;
+ var gridWidth = (this._width - marginLeft - margins.right);
+ var isCenterAligned = this.IsGroupLabelCentered();
+ var groupLabels = model.getGroupLabels(), vLineCount = groupLabels.length;
+ var labelElem, groupWidth = gridWidth/(isCenterAligned?vLineCount:vLineCount-1);
+ var dx = 0, dy = this._height - margins.bottom+container.getBBox().height+ApacheChart._TEXT_MARGIN;
+ var gLabelElems = this._groupLabelElems;
+ for (var i = 0; i< vLineCount; ++i)
+ {
+ labelElem = gLabelElems[i];
+ if(!labelElem)
+ continue;
+
+ labelElem.setAttribute("y", dy);
+ var textWidth = labelElem.getComputedTextLength();
+ if(isCenterAligned)
+ {
+ if(groupWidth > textWidth)
+ dx = (groupWidth-textWidth)/2;
+ else
+ dx = 2;
+ }
+ else
+ {
+ dx = (-textWidth)/2;
+ if(this._isPerspective)
+ dx -= ApacheChart._XOFFSET_PERSPECTIVE;
+ }
+ labelElem.setAttribute("x", marginLeft+dx+i*groupWidth);
+ }
+}
+
+/**
+ * Indicates if the group label should be center aligned or edge aligned
+ * @return true(String) indicates center aligned, false indicates it is edge aligned
+ */
+ApacheChart.prototype.IsGroupLabelCentered = function()
+{
+ return true;
+}
+
+ApacheChart.prototype.AdjustMarginsForGroupLabels = function()
+{
+ var container = this._hLabelContainer;
+ if(container && container.childNodes.length > 0)
+ {
+ this._margins.bottom += container.getBBox().height+ApacheChart._TEXT_MARGIN;
+ var isCentered = this.IsGroupLabelCentered();
+ if(!isCentered)
+ {
+ var textWidth = container.lastChild.getBBox().width;
+ if(textWidth/2> this._margins.right)
+ this._margins.right = textWidth/2;
+ }
+ }
+}
+
+ApacheChart.prototype.DrawLegend = function()
+{
+ var legendPosition = this._legendPosition;
+ if(legendPosition == ApacheChart.LEGEND_LOCATION_NONE)
+ {
+ return;
+ }
+
+ var svgDoc = this._svgDoc, rootElem = this._rootElement, model = this._model;
+ var gradientsUsed = this._gradientsUsed;
+ var seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length,
+ seriesColors = model.getSeriesColors();
+ var labelElem, rectElem, legendRectHeight,
+ legendGroup = svgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
+ var margins = this._margins, marginLeft = margins.left, marginTop = margins.top;
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+ rootElem.appendChild(legendGroup);
+
+ if(this._isPerspective)
+ {
+ marginLeft += ApacheChart._XOFFSET_PERSPECTIVE;
+ }
+ var gridWidth = (this._width - marginLeft - margins.right),
+ gridHeight = (this._height - marginTop - margins.bottom);
+
+ if(animate)
+ {
+ labelElems.push(legendGroup);
+ legendGroup.setAttribute("fill-opacity","0");
+ }
+
+ var dx = 0, dy = 0, tx = marginLeft, ty = this._height - margins.bottom;
+ var drawSideWays = (legendPosition == ApacheChart.LEGEND_LOCATION_START ||
+ legendPosition == ApacheChart.LEGEND_LOCATION_END)
+ for (var i = 0; i < seriesCount; ++i)
+ {
+ if(i == 0)
+ {
+ labelElem = svgDoc.getElementById("legendTextPrototype");
+ rectElem = svgDoc.getElementById("legendRectPrototype");
+ legendRectHeight = parseInt(rectElem.getAttribute("height"));
+ }
+
+ if(drawSideWays)
+ dx = 0;
+
+ rectElem = rectElem.cloneNode(false);
+ rectElem.setAttribute("x", dx);
+ rectElem.setAttribute("y", dy-legendRectHeight);
+ if(gradientsUsed)
+ rectElem.setAttribute("fill", "url(#gradient"+i+")");
+ else
+ rectElem.setAttribute("fill", seriesColors[i]);
+ rectElem.setAttribute("stroke", "#000000");
+ // TODO: Legend elements should fire on click event
+ //rectElem.setAttribute("onclick", "parent."+onclickStrings[i]);
+ legendGroup.appendChild(rectElem);
+
+ dx += 1.5*legendRectHeight;
+
+ labelElem = labelElem.cloneNode(true);
+ labelElem.setAttribute("x", dx);
+ labelElem.setAttribute("y", dy);
+ labelElem.firstChild.data = seriesLabels[i];
+ legendGroup.appendChild(labelElem);
+ // TODO: Legend elements should fire on click event
+ //labelElem.setAttribute("onclick", "parent."+onclickStrings[i]);
+
+ if(!drawSideWays)
+ dx += labelElem.getComputedTextLength()+legendRectHeight;
+ else
+ dy += 1.5*legendRectHeight;
+
+ if(i == 0 && !drawSideWays)
+ {
+ var rect = labelElem.getBBox();
+ if(legendPosition == ApacheChart.LEGEND_LOCATION_TOP)
+ {
+ ty = this.SetLegendTopAdjustment(margins.top+rect.height);
+ margins.top += rect.height+ApacheChart._TEXT_MARGIN;
+ }
+ else
+ {
+ ty = this.SetLegendBottomAdjustment(ty);
+ margins.bottom += rect.height+ApacheChart._TEXT_MARGIN;
+ }
+ }
+ }
+
+ if(!drawSideWays && gridWidth > dx)
+ tx = (gridWidth-dx)/2+marginLeft;
+
+ if(drawSideWays)
+ {
+ var lBBox = legendGroup.getBBox();
+ if(legendPosition == ApacheChart.LEGEND_LOCATION_START)
+ {
+ tx = this.SetLegendLeftAdjustment(margins.left);
+ margins.left += lBBox.width+ApacheChart._TEXT_MARGIN;
+ }
+ else
+ {
+ margins.right += lBBox.width+ApacheChart._TEXT_MARGIN;
+ tx = this._width - margins.right + ApacheChart._TEXT_MARGIN;
+ tx = this.SetLegendRightAdjustment(tx);
+ }
+ if(gridHeight > dy)
+ ty = (gridHeight-lBBox.height)/2+marginTop;
+ else
+ ty = gridHeight+marginTop-lBBox.height;
+ }
+
+ legendGroup.setAttribute("transform", "translate("+tx+","+ty+")");
+}
+
+/**
+ * Adjusts the legend location when it is at the top
+ * @param ty(int) the original y location of the legend
+ */
+ApacheChart.prototype.SetLegendTopAdjustment = function(ty)
+{
+ // By default we need not adjust anything
+ return ty;
+}
+
+/**
+ * Adjusts the legend location when it is at the bottom
+ * @param ty(int) the original y location of the legend
+ */
+ApacheChart.prototype.SetLegendBottomAdjustment = function(ty)
+{
+ var container = this._hLabelContainer;
+ if(container && container.childNodes.length > 0)
+ {
+ ty += container.getBBox().height+ApacheChart._TEXT_MARGIN;
+ }
+ return ty;
+}
+
+/**
+ * Adjusts the legend location when it is at the Left
+ * @param tx(int) the original x location of the legend
+ */
+ApacheChart.prototype.SetLegendLeftAdjustment = function(tx)
+{
+ var container = this._vLabelContainer;
+ if(container)
+ {
+ tx -= container.getBBox().width+ApacheChart._TEXT_MARGIN;
+ }
+ return tx;
+}
+
+/**
+ * Adjusts the legend location when it is at the Right
+ * @param tx{int} the original x location of the legend
+ */
+ApacheChart.prototype.SetLegendRightAdjustment = function(tx)
+{
+ // By default we need not adjust anything
+ return tx;
+}
+
+ApacheChart.prototype.DrawGrid = function()
+{
+ if(this._isPerspective)
+ this.DrawPerspectiveGrid();
+ else
+ this.Draw2DGrid();
+}
+
+ApacheChart.prototype.Draw2DGrid = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var gridElems = this._gridElems, animate = (this._animDuration>0);
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right);
+ var gridHeight = (this._height - marginTop - margins.bottom);
+ var gradientsUsed = this._gradientsUsed;
+ var rectElem = svgDoc.getElementById("gridRectPrototype").cloneNode(false);
+ rectElem.setAttribute("x", margins.left);
+ rectElem.setAttribute("y", (marginTop));
+ rectElem.setAttribute("width", gridWidth);
+ rectElem.setAttribute("height", gridHeight);
+ if(gradientsUsed)
+ rectElem.setAttribute("fill", "url(#gridGradient)");
+ this._rootElement.appendChild(rectElem);
+ var pathElem = svgDoc.getElementById("gridPathPrototype").cloneNode(false);
+ if(animate)
+ {
+ gridElems.push(pathElem);
+ pathElem.setAttribute("transform", "scale(0.00001,1)");
+ }
+ var sb = new ApacheChartBuffer(), vLineCount = this.GetVLineCount(), hLineCount = this.GetHLineCount();
+ // horizontal lines
+ for (var i = 0; i< hLineCount-1; ++i)
+ {
+ sb.append("M").append(marginLeft).append(",").append((i+1)*gridHeight/hLineCount+marginTop);
+ sb.append("h").append(gridWidth);
+ }
+
+ // vertical lines
+ for (var i = 0; i< vLineCount-1; ++i)
+ {
+ sb.append("M").append(marginLeft+((i+1)*gridWidth/vLineCount)).append(",").append(marginTop);
+ sb.append("v").append(gridHeight);
+ }
+ pathElem.setAttribute("d", sb.toString());
+ pathElem.removeAttribute("id");
+ this._rootElement.appendChild(pathElem);
+}
+
+ApacheChart.prototype.GetVLineCount = function()
+{
+ var xMajorCount = this._xMajorGridCount;
+ if(xMajorCount >= 0)
+ return xMajorCount;
+ else
+ return this._model.getGroupLabels().length;
+}
+
+ApacheChart.prototype.GetHLineCount = function()
+{
+ return this._yMajorGridCount;
+}
+
+ApacheChart.prototype.DrawPerspectiveGrid = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var gridElems = this._gridElems, animate = (this._animDuration>0);
+ var xOffset = ApacheChart._XOFFSET_PERSPECTIVE, yOffset = ApacheChart._YOFFSET_PERSPECTIVE;
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right - xOffset);
+ var gridHeight = (this._height - marginTop - margins.bottom - yOffset);
+ var rectElem = svgDoc.getElementById("gridRectPrototype").cloneNode(false);
+ var gradientsUsed = this._gradientsUsed;
+
+ rectElem.setAttribute("x", marginLeft+ApacheChart._XOFFSET_PERSPECTIVE);
+ rectElem.setAttribute("y", marginTop);
+ rectElem.setAttribute("width", (gridWidth));
+ rectElem.setAttribute("height", (gridHeight));
+ if(gradientsUsed)
+ rectElem.setAttribute("fill", "url(#gridGradient)");
+ rectElem.removeAttribute("id");
+ this._rootElement.appendChild(rectElem);
+ var sb = new ApacheChartBuffer();
+ var pathElem = svgDoc.getElementById("gridPath3dRectPrototype").cloneNode(false);
+ sb.append("M").append(marginLeft+xOffset).append(",").append(marginTop);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ sb.append("v").append(gridHeight);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("m").append(gridWidth).append(",").append(0);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ sb.append("h").append(-gridWidth);
+ if(gradientsUsed)
+ pathElem.setAttribute("fill", "url(#gridGradient)");
+ pathElem.setAttribute("d", sb.toString());
+ pathElem.removeAttribute("id");
+ this._rootElement.appendChild(pathElem);
+ pathElem = svgDoc.getElementById("gridPathPrototype").cloneNode(false);
+ if(animate)
+ {
+ pathElem.setAttribute("transform", "scale(0.00001,1)");
+ gridElems.push(pathElem);
+ }
+ var vLineCount = this.GetVLineCount(), hLineCount = this.GetHLineCount();
+ sb = new ApacheChartBuffer();
+ // horizontal lines
+ for (var i = 0; i< hLineCount-1; ++i)
+ {
+ sb.append("M").append(marginLeft).append(",").append((i+1)*gridHeight/hLineCount+marginTop+yOffset);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("h").append(gridWidth);
+ }
+
+ // vertical lines
+ for (var i = 0; i< vLineCount-1; ++i)
+ {
+ sb.append("M").append(marginLeft+xOffset+((i+1)*gridWidth/vLineCount)).append(",").append(marginTop);
+ sb.append("v").append(gridHeight);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ }
+ pathElem.setAttribute("d", sb.toString());
+ this._rootElement.appendChild(pathElem);
+}
+
+ApacheChart.prototype.DrawYValueLabels = function()
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement, model = this._model;
+ var container = svgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
+ this._vLabelContainer = container;
+
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+
+ var labelElem = svgDoc.getElementById("yLabelPrototype").cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ labelElem.firstChild.data = this._formatValue(minValue);
+ container.appendChild(labelElem);
+
+ labelElem = labelElem.cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ labelElem.firstChild.data = this._formatValue(maxValue);
+ container.appendChild(labelElem);
+
+ var hLineCount = this._yMajorGridCount;
+ // horizontal lines
+ for (var i = 0; i< hLineCount-1; ++i)
+ {
+ var value = ((maxValue-minValue)*(i+1)/hLineCount) + minValue;
+ labelElem = labelElem.cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ labelElem.firstChild.data = this._formatValue(value);
+ container.appendChild(labelElem);
+ }
+
+ rootElem.appendChild(container);
+}
+
+ApacheChart.prototype._formatValue = function(value)
+{
+ // Initialize the decimal separtor
+ var decimalSep = this._decimalSep;
+ if(decimalSep == null)
+ {
+ var symbols = window.getLocaleSymbols?getLocaleSymbols():null;
+ if (symbols)
+ {
+ this._decimalSep = symbols.getDecimalSeparator();
+ }
+ else
+ this._decimalSep = ".";
+ decimalSep = this._decimalSep;
+ }
+ value = value.toFixed(this._maxPrecision);
+ value = value.toString();
+ if(value.indexOf(decimalSep) == -1)
+ {
+ value = value.replace(".", decimalSep);
+ }
+ return value;
+}
+
+ApacheChart.prototype.AdjustMarginsForYLabels = function()
+{
+ var container = this._vLabelContainer;
+ if(container && container.childNodes.length > 0)
+ this._margins.left += container.getBBox().width+ApacheChart._TEXT_MARGIN;
+}
+
+ApacheChart.prototype.LayoutYValueLabels = function()
+{
+ var model = this._model, margins = this._margins;
+ var marginLeft = margins.left, marginTop = margins.top;
+ var container = this._vLabelContainer, childNodes = container.childNodes;
+ var gridHeight = (this._height - marginTop - margins.bottom);
+ if(this._isPerspective)
+ gridHeight -= ApacheChart._YOFFSET_PERSPECTIVE;
+
+ var bBox = container.getBBox(), textHeight = bBox.height;
+
+ this.SetVerticalLabelAt(childNodes.item(0), gridHeight+marginTop,
+ marginLeft, textHeight);
+
+ this.SetVerticalLabelAt(childNodes.item(1), marginTop,
+ marginLeft, textHeight);
+
+ var hLineCount = this._yMajorGridCount;
+ // horizontal lines
+ for (var i = 0; i< hLineCount-1; ++i)
+ {
+ this.SetVerticalLabelAt(childNodes.item(i+2),
+ (hLineCount -i -1)*gridHeight/hLineCount+marginTop,
+ marginLeft, textHeight);
+
+ }
+}
+
+ApacheChart.prototype.SetVerticalLabelAt = function(
+ labelElem, y, marginLeft, textHeight)
+{
+ if(this._isPerspective)
+ y += ApacheChart._YOFFSET_PERSPECTIVE;
+ // readjust to right align
+ var labelMargin = ApacheChart._TEXT_MARGIN,
+ textLength = labelElem.getComputedTextLength(), dx = labelMargin;
+ if(marginLeft>textLength+labelMargin)
+ dx = marginLeft-textLength-labelMargin;
+ labelElem.setAttribute("x", dx);
+ labelElem.setAttribute("y", y+textHeight/2);
+}
+
+ApacheChart.prototype.DrawGroupLabelTitle = function(
+ label, container, labelElem, dx, dy,
+ quadWidth, quadHeight)
+{
+ if(!label)
+ return quadHeight;
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+ labelElem.setAttribute("y", dy+quadHeight);
+ labelElem.firstChild.data = label;
+ container.appendChild(labelElem);
+ var textWidth = labelElem.getComputedTextLength();
+ if(quadWidth > textWidth)
+ dx += (quadWidth-textWidth)/2;
+ else
+ dx += 2;
+ labelElem.setAttribute("x", dx);
+
+ if(animate)
+ labelElems.push(labelElem);
+
+ var rect = labelElem.getBBox();
+ quadHeight -= rect.height+ApacheChart._TEXT_MARGIN;
+ return quadHeight;
+}
+
+ApacheChart.prototype.ShowToolTip = function(e)
+{
+ if (this._toolTipVisible)
+ return;
+
+ var model = this._model, seriesColors = model.getSeriesColors();
+ var toolTip = this.getToolTip();
+ if (toolTip == null)
+ {
+ toolTip = this._svgDoc.getElementById("toolTip").cloneNode(true);
+ this.setToolTip(toolTip);
+ this._rootElement.appendChild(toolTip);
+ }
+ toolTip.style.setProperty("visibility","visible","");
+
+ var circleElem = toolTip.firstChild.nextSibling;
+ var boundingRectElem = circleElem.nextSibling.nextSibling;
+ this.FillToolTipData(boundingRectElem, circleElem, e);
+
+ var ttBBox = toolTip.getBBox();
+ var pt = this.GetToolTipLocation(e, ttBBox);
+ var dx = pt.x, dy = pt.y;
+
+ if(dx + ttBBox.width > this._width)
+ {
+ dx -= ttBBox.width;
+ circleElem.setAttribute("cx",boundingRectElem.getBBox().width);
+ }
+ else
+ {
+ circleElem.setAttribute("cx",0);
+ }
+ if(dy - ttBBox.height < 0)
+ {
+ dy += ttBBox.height;
+ circleElem.setAttribute("cy",0);
+ }
+ else
+ {
+ circleElem.setAttribute("cy",boundingRectElem.getBBox().height);
+ }
+
+ if(this._isPerspective && this._type != ApacheChart.TYPE_PIE)
+ dy += ApacheChart._YOFFSET_PERSPECTIVE/2
+ toolTip.setAttribute("transform","translate("+dx+","+dy+")");
+ this._toolTipVisible = true;
+}
+
+ApacheChart.prototype.GetToolTipLocation = function(e, ttBBox)
+{
+ var targetBBox = e.target.getBBox();
+ return {x:(targetBBox.x+targetBBox.width/2), y:(targetBBox.y - ttBBox.height)};
+}
+
+ApacheChart.prototype.GetChartEvent = function(e)
+{
+ var evtTarget = e.target;
+
+ var i = parseInt(evtTarget.getAttribute("yValueIndex")),
+ j = parseInt(evtTarget.getAttribute("seriesIndex"));
+
+ var model = this._model, yValues = model.getYValues();
+ return new ApacheChartEvent([j],[i], [yValues[i][j]],null);
+}
+
+ApacheChart.prototype.FillToolTipData = function(boundingRectElem, circleElem, e)
+{
+ var chartEvent = this.GetChartEvent(e);
+
+ var j = chartEvent.getSeriesIndices()[0];
+
+ var model = this._model, groupLabels = model.getGroupLabels(),
+ seriesLabels = model.getSeriesLabels(),
+ yValues = chartEvent.getYValues();
+
+ //top label
+ var textElem = boundingRectElem.nextSibling.nextSibling;
+ textElem.firstChild.data = seriesLabels[j];
+
+ var labelWidth = textElem.getComputedTextLength();
+ //actual value
+ textElem = textElem.nextSibling.nextSibling;
+ textElem.firstChild.data = this._formatValue(yValues[0]);
+ var dataWidth = textElem.getComputedTextLength();
+ // leave a clearance on either end of the text
+ var xMargin = ApacheChart._TEXT_MARGIN, dx = xMargin;
+ if (labelWidth > dataWidth)
+ dx = (labelWidth-dataWidth)/2+xMargin;
+ textElem.setAttribute("dx",dx);
+ var rectWidth = Math.max(labelWidth,dataWidth)+2*xMargin;
+ boundingRectElem.setAttribute("width",rectWidth);
+ boundingRectElem.setAttribute("stroke", seriesColors[j]);
+ circleElem.setAttribute("stroke",seriesColors[j]);
+}
+
+ApacheChart.prototype.HideToolTip = function(e)
+{
+ var toolTip = this.getToolTip();
+ if(toolTip)
+ toolTip.style.setProperty("visibility","hidden","");
+ this._toolTipVisible = false;
+}
+
+ApacheChart.prototype.Click = function(e)
+{
+ var chartEvent = this.GetChartEvent(e);
+ var formName = this._formName;
+
+ if(formName !=null)
+ {
+ var svgEmbed = document.getElementById(this._svgEmbedId);
+ var sourceId = svgEmbed.parentNode.id;
+ var chartValue ={ 'event': 'chartDrillDown',
+ 'source':sourceId,
+ 'value':chartEvent.marshall()};
+ if(this._partialSubmit)
+ {
+ _submitPartialChange(formName,'0',chartValue);
+ }
+ else
+ {
+ submitForm(formName,'0',chartValue);
+ }
+ }
+ else
+ alert(chartEvent);
+}
+
+////////////////////////////////////////////////////////////////////
+// Bar Chart subclass
+////////////////////////////////////////////////////////////////////
+function ApacheBarChart(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ this.Init(type, model, svgEmbedId, isPerspective, legendPosition);
+}
+
+ApacheChartObj.Inherit(ApacheChart, ApacheBarChart);
+
+ApacheBarChart.prototype.DrawChartData = function()
+{
+ var isCombo = this._type == ApacheChart.TYPE_BAR_LINE_COMBO;
+ var isPerspective = this._isPerspective;
+ if(isPerspective)
+ this._drawPerspectiveBars(isCombo);
+ else
+ this._drawBars(isCombo);
+
+ // delegate to the line chart for combos
+ if(isCombo)
+ {
+ if(isPerspective)
+ this.__drawPerspectiveLines = ApacheLineChart.prototype.__drawPerspectiveLines;
+ else
+ this.__drawLines = ApacheLineChart.prototype.__drawLines;
+
+ ApacheLineChart.prototype.DrawChartData.call(this, isCombo);
+ }
+}
+
+ApacheBarChart.prototype._drawBars = function(isCombo)
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var rootElem = this._rootElement, dataElems = this._dataElems, animate = (this._animDuration>0);
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right);
+ var gridHeight = (this._height - marginTop - margins.bottom);
+ var rectElem = svgDoc.getElementById("barRectPrototype");
+ var barItemPadding = ApacheBarChart._BARITEM_PADDING;
+ var isStacked = (this._type == ApacheChart.TYPE_VBAR_STACKED);
+ var groupLabels = model.getGroupLabels(), groupCount = groupLabels.length,
+ seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length;
+ var seriesColors = model.getSeriesColors(), yValues = model.getYValues();
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var barDivider = isStacked?1:(isCombo?Math.ceil(seriesCount/2): seriesCount);
+ var yValueCount = yValues.length;
+ var barWidth = (gridWidth/Math.max(yValueCount,groupCount)-2*barItemPadding)/barDivider;
+ var dx = marginLeft, dy, barHeight, stackBase = minValue;
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "scale(1,0.00001)";
+ for (var i = 0; i< yValueCount; ++i)
+ {
+ dx += barItemPadding;
+ dy = gridHeight + marginTop;
+
+ for (var j = 0; j < seriesCount; ++j)
+ {
+ // for combo charts we draw every alternate(even) bar.
+ if(isCombo && j%2>0)
+ continue;
+
+ // If we use non zero min and it is a stacked graph, we need to remove the min for only
+ // the first series.
+ if(isStacked)
+ stackBase = (j==0?minValue:0);
+
+ rectElem = rectElem.cloneNode(false);
+ if(animate)
+ {
+ dataElems.push(rectElem);
+ rectElem.setAttribute("transform",defaultTransform);
+ }
+ rectElem.setAttribute("x", dx);
+ barHeight = gridHeight*(yValues[i][j]-stackBase)/(maxValue-minValue);
+ if(isStacked)
+ dy -= barHeight;
+ else
+ dy = gridHeight + marginTop - barHeight;
+ rectElem.setAttribute("y", dy);
+ rectElem.setAttribute("width", barWidth);
+ rectElem.setAttribute("height", barHeight);
+
+ if(gradientsUsed)
+ rectElem.setAttribute("fill", "url(#gradient"+j+")");
+ else
+ rectElem.setAttribute("fill", seriesColors[j]);
+
+ rectElem.setAttribute("stroke", seriesColors[j]);
+ rectElem.setAttribute("stroke-width", 1);
+ rectElem.setAttribute("yValueIndex", i);
+ rectElem.setAttribute("seriesIndex", j);
+ if(this._tooltipsVisible)
+ {
+ rectElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ rectElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ rectElem.addEventListener("click",this.ClickCallback,false);
+ rootElem.appendChild(rectElem);
+ if(!isStacked)
+ dx += barWidth;
+ }
+ if(isStacked)
+ dx += barWidth;
+ dx += barItemPadding;
+ }
+}
+
+ApacheBarChart.prototype._drawPerspectiveBars = function(isCombo)
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var rootElem = this._rootElement, dataElems = this._dataElems, animate = (this._animDuration>0);
+ var xOffset = ApacheChart._XOFFSET_PERSPECTIVE, yOffset = ApacheChart._YOFFSET_PERSPECTIVE;
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right - xOffset);
+ var gridHeight = (this._height - marginTop - margins.bottom - yOffset);
+ var pathElem = svgDoc.getElementById("barPathPrototype");
+ var barItemPadding = ApacheBarChart._BARITEM_PADDING;
+ var isStacked = (this._type == ApacheChart.TYPE_VBAR_STACKED);
+ var groupLabels = model.getGroupLabels(), groupCount = groupLabels.length,
+ seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length;
+ var seriesColors = model.getSeriesColors(), yValues = model.getYValues();
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var seriesBars = isCombo?Math.ceil(seriesCount/2): seriesCount, barWidth;
+ var yValueCount = yValues.length;
+ if(isStacked)
+ barWidth = gridWidth/Math.max(yValueCount,groupCount)-2*barItemPadding;
+ else
+ barWidth = (gridWidth/Math.max(yValueCount,groupCount) -2*barItemPadding - (seriesBars)*barItemPadding)/seriesBars;
+ var dx = marginLeft, dy, barHeight, stackBase = minValue;
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "scale(1, 0.00001)";
+ for (var i = 0; i< yValueCount; ++i)
+ {
+ dx += barItemPadding;
+ dy = gridHeight + marginTop+yOffset;
+ for (var j = 0; j < seriesCount; ++j)
+ {
+ // for combo charts we draw every alternate(even) bar.
+ if(isCombo && j%2>0)
+ continue;
+ // If we use non zero min and it is a stacked graph, we need to remove the min for only
+ // the first series.
+ if(isStacked)
+ stackBase = (j==0?minValue:0);
+
+ barHeight = gridHeight*(yValues[i][j]-stackBase)/(maxValue-minValue);
+ if(isStacked)
+ dy -= barHeight;
+ else
+ dy = gridHeight + yOffset + marginTop - barHeight;
+ pathElem = pathElem.cloneNode(false);
+ if(animate)
+ {
+ dataElems.push(pathElem);
+ pathElem.setAttribute("transform",defaultTransform);
+ }
+ var sb = new ApacheChartBuffer();
+ sb.append("M").append(dx).append(",").append(dy);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("h").append(barWidth);
+ sb.append("v").append(barHeight);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ sb.append("v").append(-barHeight);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ sb.append("h").append(-barWidth);
+ sb.append("v").append(barHeight);
+ sb.append("h").append(barWidth);
+ sb.append("v").append(-barHeight);
+ pathElem.setAttribute("stroke", seriesColors[j]);
+ pathElem.setAttribute("stroke-width", 1);
+ if(gradientsUsed)
+ pathElem.setAttribute("fill", "url(#gradient"+j+")");
+ else
+ pathElem.setAttribute("fill", seriesColors[j]);
+ pathElem.setAttribute("d", sb.toString());
+
+ pathElem.setAttribute("yValueIndex", i);
+ pathElem.setAttribute("seriesIndex", j);
+ if(this._tooltipsVisible)
+ {
+ pathElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ pathElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ pathElem.addEventListener("click",this.ClickCallback,false);
+ rootElem.appendChild(pathElem);
+ if(!isStacked)
+ {
+ dx += barWidth;
+ dx += barItemPadding;
+ }
+ }
+ if(isStacked)
+ dx += barWidth;
+ dx += barItemPadding;
+ }
+}
+
+ApacheBarChart.prototype.ShowToolTip = function(e)
+{
+ if(this._type == ApacheChart.TYPE_BAR_LINE_COMBO)
+ {
+ var i = parseInt(e.target.getAttribute("seriesIndex"));
+ if(i%2>0)
+ {
+ try
+ {
+ // Maybe we need a generic framework for combos so that we can delegate.
+ // Till that time...
+ this.GetToolTipLocation = ApacheLineChart.prototype.GetToolTipLocation;
+ this.FillToolTipData = ApacheLineChart.prototype.FillToolTipData;
+ this.GetChartEvent = ApacheLineChart.prototype.GetChartEvent;
+ ApacheLineChart.prototype.ShowToolTip.call(this, e);
+ }
+ finally
+ {
+ // restore
+ this.GetToolTipLocation = ApacheBarChart.prototype.GetToolTipLocation;
+ this.FillToolTipData = ApacheBarChart.prototype.FillToolTipData;
+ this.GetChartEvent = ApacheBarChart.prototype.GetChartEvent;
+ }
+ return;
+ }
+ }
+ ApacheBarChart.superclass.ShowToolTip.call(this, e);
+}
+
+// number of pixels on either side of the bar item
+ApacheBarChart._BARITEM_PADDING = 2;
+
+////////////////////////////////////////////////////////////////////
+// Bar chart subclass
+////////////////////////////////////////////////////////////////////
+function ApacheHBarChart(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ this.Init(type, model, svgEmbedId, isPerspective, legendPosition);
+}
+
+ApacheChartObj.Inherit(ApacheChart, ApacheHBarChart);
+
+ApacheHBarChart.prototype.DrawChartData = function()
+{
+ if(this._isPerspective)
+ this._drawPerspectiveBars();
+ else
+ this._drawBars();
+}
+
+ApacheHBarChart.prototype.AnimAlongXAxis = function()
+{
+ // horizontal bar animates around x axis
+ return true;
+}
+
+ApacheHBarChart.prototype.DrawYValueLabels = function()
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement, model = this._model;
+ var container = svgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
+ // Since the horizontal bar chart is flipped Y labels are horizontal
+ this._vLabelContainer = container;
+ var labelElem = svgDoc.getElementById("groupLabelPrototype");
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+ var groupLabels = model.getGroupLabels(), hLineCount = groupLabels.length;
+ var labelText, gLabelElems = this._groupLabelElems;
+
+ // horizontal lines
+ for (var i = 0; i< hLineCount; ++i)
+ {
+ labelText = groupLabels[i];
+ if(!labelText)
+ continue;
+ labelElem = labelElem.cloneNode(true);
+ labelElem.firstChild.data = labelText;
+ container.appendChild(labelElem);
+ gLabelElems[i] = labelElem;
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ }
+ rootElem.appendChild(container);
+}
+
+ApacheHBarChart.prototype.LayoutYValueLabels = function()
+{
+ var model = this._model, margins = this._margins,
+ marginLeft = margins.left, marginTop = margins.top;
+ var gridHeight = (this._height - marginTop - margins.bottom);
+ if(this._isPerspective)
+ gridHeight -= ApacheChart._YOFFSET_PERSPECTIVE;
+
+ var container = this._vLabelContainer, childNodes = container.childNodes;
+
+ if(childNodes.length == 0)
+ return;
+
+ var labelElem, bBox = container.getBBox(), textHeight = bBox.height;
+ var groupLabels = model.getGroupLabels(), hLineCount = groupLabels.length;
+ var gLabelElems = this._groupLabelElems;
+ // horizontal lines
+ for (var i = 0; i< hLineCount; ++i)
+ {
+ labelElem = gLabelElems[i];
+ if(!labelElem)
+ continue;
+
+ this.SetVerticalLabelAt(labelElem,
+ (hLineCount -i)*gridHeight/hLineCount+marginTop-(gridHeight/(2*hLineCount)),
+ marginLeft, textHeight);
+ }
+}
+
+ApacheHBarChart.prototype.IsGroupLabelCentered = function()
+{
+ return false;
+}
+
+ApacheHBarChart.prototype.DrawGroupLabels = function()
+{
+ var svgDoc = this._svgDoc, rootElem = this._rootElement, model = this._model;
+
+ var vLineCount = this._yMajorGridCount;
+ var container = svgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
+ // Since the horizontal bar chart is flipped group labels are vertical
+ this._hLabelContainer = container;
+
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var labelElem = svgDoc.getElementById("yLabelPrototype");
+
+ var value, labelElems = this._labelElems, animate = (this._animDuration>0);
+ for (var i = 0; i< vLineCount+1; ++i)
+ {
+ // draw the horizontal label
+ labelElem = labelElem.cloneNode(true);
+ if(animate)
+ {
+ labelElems.push(labelElem);
+ labelElem.setAttribute("fill-opacity","0");
+ }
+ if(i==0)
+ value = minValue;
+ else if(i==vLineCount)
+ value = maxValue;
+ else
+ value = (((maxValue-minValue)*(i)/vLineCount) + minValue);
+ labelElem.firstChild.data = this._formatValue(value);
+ container.appendChild(labelElem);
+ }
+ rootElem.appendChild(container);
+}
+
+ApacheHBarChart.prototype.LayoutGroupLabels = function()
+{
+ var model = this._model, margins = this._margins, marginLeft = margins.left;
+ var gridWidth = (this._width - marginLeft - margins.right);
+ var container = this._hLabelContainer, childNodes = container.childNodes;
+
+ if(this._isPerspective)
+ gridWidth -= ApacheChart._XOFFSET_PERSPECTIVE;
+
+ var vLineCount = this._yMajorGridCount;
+ var labelElem, yValWidth = gridWidth/vLineCount;
+
+ var bBox = container.getBBox();
+ var dx = 0, dy = this._height - margins.bottom + bBox.height+ApacheChart._TEXT_MARGIN;
+ var labelElems = this._labelElems, animate = (this._animDuration>0);
+ for (var i = 0; i< vLineCount+1; ++i)
+ {
+ // draw the horizontal label
+ labelElem = childNodes.item(i);
+ labelElem.setAttribute("y", dy);
+ var textWidth = labelElem.getComputedTextLength();
+ labelElem.setAttribute("x", marginLeft-textWidth/2+i*yValWidth);
+ }
+}
+
+ApacheHBarChart.prototype.GetVLineCount = function()
+{
+ return this._yMajorGridCount;
+}
+
+ApacheHBarChart.prototype.GetHLineCount = function()
+{
+ var xMajorCount = this._xMajorGridCount;
+ if(xMajorCount >= 0)
+ return xMajorCount;
+ else
+ return this._model.getGroupLabels().length;
+}
+
+ApacheHBarChart.prototype._drawBars = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var rootElem = this._rootElement, dataElems = this._dataElems, animate = (this._animDuration>0);
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right);
+ var gridHeight = (this._height - marginTop - margins.bottom);
+ var rectElem = svgDoc.getElementById("barRectPrototype");
+ var barItemPadding = ApacheBarChart._BARITEM_PADDING;
+ var isStacked = (this._type == ApacheChart.TYPE_HBAR_STACKED);
+ var groupLabels = model.getGroupLabels(), groupCount = groupLabels.length,
+ seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length;
+ var seriesColors = model.getSeriesColors(), yValues = model.getYValues();
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var barDivider = isStacked?1:seriesCount, stackBase = minValue;
+ var yValueCount = yValues.length;
+ var barHeight = (gridHeight/Math.max(yValueCount,groupCount)-2*barItemPadding)/barDivider;
+ var dx = marginLeft, dy=gridHeight+marginTop, barWidth;
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "scale(0.00001,1)";
+ for (var i = 0; i< yValueCount; ++i)
+ {
+ dy -= barItemPadding;
+ dx = marginLeft;
+ for (var j = 0; j < seriesCount; ++j)
+ {
+ // If we use non zero min and it is a stacked graph, we need to remove the min for only
+ // the first series.
+ if(isStacked)
+ stackBase = (j==0?minValue:0);
+
+ rectElem = rectElem.cloneNode(false);
+ if(animate)
+ {
+ dataElems.push(rectElem);
+ rectElem.setAttribute("transform",defaultTransform);
+ }
+ rectElem.setAttribute("x", dx);
+ barWidth = gridWidth*(yValues[i][j]-stackBase)/(maxValue-minValue);
+ if(isStacked)
+ dx += barWidth;
+ rectElem.setAttribute("y", dy-barHeight);
+ rectElem.setAttribute("width", barWidth);
+
+ rectElem.setAttribute("height", barHeight);
+ if(gradientsUsed)
+ rectElem.setAttribute("fill", "url(#gradient"+j+")");
+ else
+ rectElem.setAttribute("fill", seriesColors[j]);
+ rectElem.setAttribute("stroke", seriesColors[j]);
+ rectElem.setAttribute("stroke-width", 1);
+ rectElem.setAttribute("yValueIndex", i);
+ rectElem.setAttribute("seriesIndex", j);
+ if(this._tooltipsVisible)
+ {
+ rectElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ rectElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ rectElem.addEventListener("click",this.ClickCallback,false);
+ rootElem.appendChild(rectElem);
+ if(!isStacked)
+ dy -= barHeight;
+ }
+ if(isStacked)
+ dy -= barHeight;
+ dy -= barItemPadding;
+ }
+}
+
+ApacheHBarChart.prototype._drawPerspectiveBars = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var rootElem = this._rootElement, dataElems = this._dataElems, animate = (this._animDuration>0);
+ var xOffset = ApacheChart._XOFFSET_PERSPECTIVE, yOffset = ApacheChart._YOFFSET_PERSPECTIVE;
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right - xOffset);
+ var gridHeight = (this._height - marginTop - margins.bottom - yOffset);
+ var pathElem = svgDoc.getElementById("barPathPrototype");
+ var barItemPadding = ApacheBarChart._BARITEM_PADDING;
+ var isStacked = (this._type == ApacheChart.TYPE_HBAR_STACKED);
+ var groupLabels = model.getGroupLabels(), groupCount = groupLabels.length,
+ seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length;
+ var seriesColors = model.getSeriesColors(), yValues = model.getYValues();
+ var minValue = model.getMinYValue(), maxValue = model.getMaxYValue();
+ var yValueCount = yValues.length;
+ var barHeight, stackBase = minValue;
+ if(isStacked)
+ barHeight = gridHeight/Math.max(yValueCount,groupCount)-2*barItemPadding;
+ else
+ barHeight = (gridHeight/Math.max(yValueCount,groupCount)-2*barItemPadding - (seriesCount)*barItemPadding)/seriesCount;
+ var dx = marginLeft, dy=gridHeight+marginTop+yOffset, barWidth;
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "scale(0.00001,1)";
+
+ for (var i = 0; i< yValueCount; ++i)
+ {
+ dy -= barItemPadding;
+ dx = marginLeft;
+ for (var j = 0; j < seriesCount; ++j)
+ {
+ // If we use non zero min and it is a stacked graph, we need to remove the min for only
+ // the first series.
+ if(isStacked)
+ stackBase = (j==0?minValue:0);
+
+ barWidth = gridWidth*(yValues[i][j]-stackBase)/(maxValue-minValue);
+ pathElem = pathElem.cloneNode(false);
+ if(animate)
+ {
+ dataElems.push(pathElem);
+ pathElem.setAttribute("transform",defaultTransform);
+ }
+ var sb = new ApacheChartBuffer();
+ sb.append("M").append(dx).append(",").append(dy);
+ sb.append("h").append(barWidth);
+ sb.append("v").append(-barHeight);
+ sb.append("h").append(-barWidth);
+ sb.append("v").append(barHeight);
+
+ sb.append("M").append(dx).append(",").append(dy-barHeight);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("h").append(barWidth);
+ sb.append("l").append(-xOffset).append(",").append(yOffset);
+ sb.append("z");
+ sb.append("M").append(dx+barWidth).append(",").append(dy);
+ sb.append("v").append(-barHeight);
+ sb.append("l").append(xOffset).append(",").append(-yOffset);
+ sb.append("v").append(barHeight);
+ sb.append("z");
+ pathElem.setAttribute("stroke", seriesColors[j]);
+ pathElem.setAttribute("stroke-width", 1);
+ if(gradientsUsed)
+ pathElem.setAttribute("fill", "url(#gradient"+j+")");
+ else
+ pathElem.setAttribute("fill", seriesColors[j]);
+
+ pathElem.setAttribute("d", sb.toString());
+
+ pathElem.setAttribute("yValueIndex", i);
+ pathElem.setAttribute("seriesIndex", j);
+ if(this._tooltipsVisible)
+ {
+ pathElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ pathElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ pathElem.addEventListener("click",this.ClickCallback,false);
+ rootElem.appendChild(pathElem);
+ if(isStacked)
+ dx += barWidth;
+ else
+ {
+ dy -= barHeight;
+ dy -= barItemPadding;
+ }
+ }
+ if(isStacked)
+ dy -= barHeight;
+ dy -= barItemPadding;
+ }
+}
+
+////////////////////////////////////////////////////////////////////
+// Pie chart subclass
+////////////////////////////////////////////////////////////////////
+function ApachePieChart(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ this.Init(type, model, svgEmbedId, isPerspective, legendPosition);
+}
+
+ApacheChartObj.Inherit(ApacheChart, ApachePieChart);
+
+ApachePieChart.prototype.Init = function(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ ApachePieChart.superclass.Init.call(this, type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ //this._pieAnimAngles = undefined;
+ //this._pieAnimRadii = undefined;
+}
+
+ApachePieChart.prototype.DrawChartData = function()
+{
+ var rootElem = this._rootElement;
+
+ // calculate the number of rows and columns
+ var model = this._model, yValues = model.getYValues(), yValueCount = yValues.length;
+ var groupLabels = model.getGroupLabels(), groupCount = groupLabels?groupLabels.length:1;
+
+ var nCols = Math.ceil(Math.sqrt(yValueCount)), nRows = Math.round(Math.sqrt(yValueCount));
+ var labelElem = this._svgDoc.getElementById("groupLabelPrototype");
+ var margins = this._margins, dx=margins.left, dy=margins.top;
+ var quadWidth = (this._width - margins.left - margins.right)/nCols;
+ var animate = (this._animDuration>0), isPerspective = this._isPerspective;
+ var pieAnimRadii, vGap = 2*ApacheChart._TEXT_MARGIN;
+ var quadHeight = (this._height - margins.top - margins.bottom - (nRows-1)*vGap)/nRows;
+ if(animate)
+ {
+ this._pieAnimAngles = [];
+ pieAnimRadii = this._pieAnimRadii = [];
+ }
+ for(var i = 0; i<nRows; ++i)
+ {
+ for(var j = 0; j<nCols; ++j)
+ {
+ var iGroup = groupLabels?(i*nCols + j):(-1);
+ if(iGroup >= yValueCount)
+ break;
+
+ var groupLabel = (iGroup == -1)?null:groupLabels[iGroup];
+ var pieContainer = rootElem.cloneNode(false);
+ rootElem.appendChild(pieContainer);
+ var newHeight = this.DrawGroupLabelTitle(groupLabel, rootElem,
+ labelElem.cloneNode(true), dx, dy,
+ quadWidth, quadHeight);
+ var newWidth = quadWidth - 2*ApacheChart._TEXT_MARGIN;
+ var cx= dx+quadWidth/2+ApacheChart._TEXT_MARGIN, cy = dy+newHeight/2;
+
+ if(animate)
+ {
+ pieAnimRadii.push(Math.max(cx, cy));
+ }
+
+ if(isPerspective)
+ {
+ this._draw3DPies(pieContainer, newWidth, newHeight, iGroup);
+ // The chart is draw with the center at 0 so we need to compensate for it.
+ pieContainer.setAttribute("transform",
+ "translate("+cx+","+cy+") scale(1.0,0.707)");
+ }
+ else
+ {
+ this._drawPies(pieContainer, newWidth, newHeight, iGroup);
+ pieContainer.setAttribute("transform",
+ "translate("+cx+","+cy+")");
+ }
+ dx +=quadWidth;
+ }
+ dx=margins.left;
+ dy +=quadHeight+vGap;
+ }
+}
+
+ApachePieChart.prototype.ComputeMaxValues = function()
+{
+
+}
+
+ApachePieChart.prototype.DrawGroupLabels = function()
+{
+
+}
+
+ApachePieChart.prototype.LayoutGroupLabels = function()
+{
+
+}
+
+ApachePieChart.prototype.DrawGrid = function()
+{
+
+}
+
+ApachePieChart.prototype.DrawYValueLabels = function()
+{
+
+}
+
+ApachePieChart.prototype.LayoutYValueLabels = function()
+{
+
+}
+
+ApachePieChart.prototype.SetDataAnimStep = function(ratio)
+{
+ var pieAnimRadii = this._pieAnimRadii, pieAnimAngles = this._pieAnimAngles,
+ isPerspective = this._isPerspective, agleIndex = 0, elemIndex = 0;
+ var animElems = this._dataElems, chartCount = pieAnimRadii.length;
+ var model = this._model, yValues = model.getYValues();
+
+ // We are animating parependiculat to the tangent to the middle of the pie
+ for(var i = 0; i < chartCount; ++i)
+ {
+ var nPies = yValues[i].length;
+ var radius = pieAnimRadii[i]*(1-ratio);
+ for (var j = 0; j<nPies; ++j)
+ {
+ var angle = pieAnimAngles[agleIndex++]*2*Math.PI;
+ var tx = radius*Math.sin(angle), ty = radius*Math.cos(angle);
+ if(angle <= Math.PI/2)
+ {
+ ty = -ty;
+ tx = tx;
+ }
+ else if(angle <= Math.PI)
+ {
+ ;
+ }
+ else if(angle <= 3*Math.PI/2)
+ {
+ tx = -tx;
+ }
+ else
+ {
+ ty = -ty;
+ tx = -tx;
+ }
+ animElems[elemIndex++].setAttribute("transform", "translate("+tx+","+ty+")");
+ if(isPerspective)
+ {
+ animElems[elemIndex++].setAttribute("transform", "translate("+tx+","+ty+")");
+ animElems[elemIndex++].setAttribute("transform", "translate("+tx+","+ty+")");
+ }
+ }
+ }
+}
+
+ApachePieChart.prototype._drawPies = function(
+ pieContainer, quadWidth,
+ quadHeight, iGroup)
+{
+ var svgDoc = this._svgDoc, model = this._model, yValues = model.getYValues();
+ var groupLabels = model.getGroupLabels(), seriesColors = model.getSeriesColors();
+ var pieSize = Math.min(quadWidth/2, quadHeight/2);
+
+ if(iGroup == -1)
+ iGroup = 0;
+
+ var nPies = yValues[iGroup].length;
+ var pieTotal = 0;
+
+ for (var i = 0; i < nPies; ++i)
+ {
+ pieTotal += yValues[iGroup][i];
+ }
+
+ var pathElem = svgDoc.getElementById("piePathPrototype"), pieStart = 0, animAngleStart = 0;
+ var pieElems = new Array(nPies), dataElems = this._dataElems, animate = (this._animDuration>0);
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "translate(-10000, -10000)", pieAnimAngles = this._pieAnimAngles;
+ for (var i = 0; i<nPies; ++i)
+ {
+ pathElem = pathElem.cloneNode(false);
+ var valueRatio = 1 - (yValues[iGroup][i])/(pieTotal);
+ if(animate)
+ {
+ dataElems.push(pathElem);
+ pathElem.setAttribute("transform",defaultTransform);
+ var curAnimRatio = (yValues[iGroup][i])/(pieTotal);
+ pieAnimAngles.push(animAngleStart+curAnimRatio/2);
+ animAngleStart+=curAnimRatio;
+ }
+ var sb = new ApacheChartBuffer();
+ sb.append("M0,0L");
+ sb.append(pieSize*Math.cos(pieStart*Math.PI*2));
+ sb.append(",").append(pieSize*Math.sin(pieStart*Math.PI*2));
+
+ if (valueRatio >= .5) // major arc
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 0 0 ");
+ sb.append(pieSize* Math.cos((pieStart+valueRatio)*Math.PI*2));
+ sb.append(",").append(pieSize*Math.sin((pieStart+valueRatio)*Math.PI*2));
+ }
+ else
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 1 0 ");
+ sb.append(pieSize* Math.cos((pieStart+valueRatio)*Math.PI*2));
+ sb.append(",").append(pieSize*Math.sin((pieStart+valueRatio)*Math.PI*2));
+ }
+ sb.append("z");
+
+ pathElem.setAttribute("d", sb.toString());
+ if(gradientsUsed)
+ pathElem.setAttribute("fill", "url(#gradient"+i+")");
+ else
+ pathElem.setAttribute("fill", seriesColors[i]);
+ pathElem.setAttribute("stroke", seriesColors[i]);
+ pathElem.setAttribute("stroke-width", 1);
+ pathElem.setAttribute("yValueIndex", iGroup);
+ pathElem.setAttribute("seriesIndex", i);
+ if(this._tooltipsVisible)
+ {
+ pathElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ pathElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ pathElem.addEventListener("click",this.ClickCallback,false);
+ pieStart += valueRatio;
+ pieElems[i] = pathElem;
+ }
+
+
+ for (var i = 0; i< nPies; ++i)
+ {
+ // calculate the pie gradient:
+ pieContainer.appendChild(pieElems[i]);
+ }
+}
+
+ApachePieChart.prototype._draw3DPies = function(
+ pieContainer, quadWidth,
+ quadHeight, iGroup)
+{
+ var svgDoc = this._svgDoc, model = this._model, yValues = model.getYValues();
+ var groupLabels = model.getGroupLabels(), seriesColors = model.getSeriesColors();
+ var pieSize = Math.min(quadWidth/2, quadHeight/2);
+ var pieTotal = 0;
+
+ if(iGroup == -1)
+ iGroup = 0;
+
+ var nPies = yValues[iGroup].length;
+ for (var i = 0; i < nPies; ++i)
+ {
+ pieTotal += yValues[iGroup][i];
+ }
+
+ var perspectiveHeight = pieSize/4, pieElems = new Array(nPies),
+ ringElems = new Array(nPies), edgeElems = new Array(nPies);
+ var dataElems = this._dataElems, animate = (this._animDuration>0);
+ if( perspectiveHeight> ApachePieChart._MAX_PERSPECTIVE_HEIGHT )
+ perspectiveHeight = ApachePieChart._MAX_PERSPECTIVE_HEIGHT;
+
+ var pathElem = svgDoc.getElementById("piePathPrototype"), pieStart = 0;
+ var gradientsUsed = this._gradientsUsed;
+ var defaultTransform = "translate(-10000, -10000)", pieAnimAngles = this._pieAnimAngles;
+ for (var i = 0; i < nPies; ++i)
+ {
+ pathElem = pathElem.cloneNode(false);
+ var valueRatio = 1 - (yValues[iGroup][i])/(pieTotal);
+ if(animate)
+ {
+ dataElems.push(pathElem);
+ pathElem.setAttribute("transform",defaultTransform);
+ pieAnimAngles.push(pieStart+valueRatio/2);
+ }
+ var arcBeginX, arcBeginY, arcEndX, arcEndY;
+
+ arcBeginX = pieSize*Math.cos(pieStart*Math.PI*2);
+ arcBeginY = pieSize*Math.sin(pieStart*Math.PI*2);
+ var sb = new ApacheChartBuffer();
+ sb.append("M0,0L").append(arcBeginX).append(",").append(arcBeginY);
+
+ arcEndX = pieSize*Math.cos((pieStart+valueRatio)*Math.PI*2);
+ arcEndY = pieSize*Math.sin((pieStart+valueRatio)*Math.PI*2);
+
+ if (valueRatio >= .5)
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 0 0 ");
+ sb.append(arcEndX).append(",").append(arcEndY);
+ }
+ else
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 1 0 ");
+ sb.append(arcEndX).append(",").append(arcEndY);
+ }
+ sb.append("z");
+ if(gradientsUsed)
+ pathElem.setAttribute("fill", "url(#gradient"+i+")");
+ else
+ pathElem.setAttribute("fill", seriesColors[i]);
+ pathElem.setAttribute("stroke", seriesColors[i]);
+ pathElem.setAttribute("stroke-width", 1);
+ pathElem.setAttribute("yValueIndex", iGroup);
+ pathElem.setAttribute("seriesIndex", i);
+ if(this._tooltipsVisible)
+ {
+ pathElem.addEventListener("mouseover",this.ShowToolTipCallback,false);
+ pathElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+ pathElem.addEventListener("click",this.ClickCallback,false);
+
+ var pathRingElem = pathElem.cloneNode(false);
+ var pathEdgeElem = pathElem.cloneNode(false);
+ if(animate)
+ {
+ dataElems.push(pathRingElem);
+ pathRingElem.setAttribute("transform",defaultTransform);
+ dataElems.push(pathEdgeElem);
+ pathEdgeElem.setAttribute("transform",defaultTransform);
+ }
+ pathElem.setAttribute("d", sb.toString());
+
+ sb = new ApacheChartBuffer();
+ sb.append("M").append(arcBeginX).append(",").append(arcBeginY);
+ if (valueRatio >= .5) // major arc
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 0 0 ");
+ sb.append(arcEndX).append(",").append(arcEndY);
+ }
+ else
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 1 0 ");
+ sb.append(arcEndX).append(",").append(arcEndY);
+ }
+
+ sb.append("v").append(perspectiveHeight);
+ if (valueRatio >= .5) // major arc
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 0 1 ");
+ sb.append(arcBeginX).append(",").append(arcBeginY+perspectiveHeight);
+ }
+ else
+ {
+ sb.append("A").append(pieSize).append(" ").append(pieSize).append(" 1 1 1 ");
+ sb.append(arcBeginX).append(",").append(arcBeginY+perspectiveHeight);
+ }
+
+ sb.append("z");
+ pathRingElem.setAttribute("d", sb.toString());
+
+ sb = new ApacheChartBuffer();
+ sb.append("M0,0L");
+ sb.append(arcBeginX).append(",").append(arcBeginY);
+ sb.append("v").append(perspectiveHeight);
+ sb.append("L").append(0).append(",").append(perspectiveHeight);
+ sb.append("z");
+ sb.append("M0,0L");
+ sb.append(arcEndX).append(",").append(arcEndY);
+ sb.append("v").append(perspectiveHeight);
+ sb.append("L").append(0).append(",").append(perspectiveHeight);
+ sb.append("z");
+ pathEdgeElem.setAttribute("d", sb.toString());
+
+ pieStart += valueRatio;
+ pieElems[i] = pathElem;
+ ringElems[i] = pathRingElem;
+ edgeElems[i] = pathEdgeElem;
+ }
+
+ // For the top half, edges have preference over rings
+ var totalRatio = 0;
+ for (var i = 0; i< nPies; ++i)
+ {
+ if(totalRatio <= .5)
+ pieContainer.appendChild(ringElems[i]);
+ totalRatio += (yValues[iGroup][i])/(pieTotal);
+ }
+ totalRatio = 0;
+ for (var i = 0; i< nPies; ++i)
+ {
+ if(totalRatio <= .5)
+ pieContainer.appendChild(edgeElems[i]);
+ totalRatio += (yValues[iGroup][i])/(pieTotal);
+ }
+
+ // For the bottom half, rings have preference over edges
+ totalRatio = 0;
+ for (var i = 0; i< nPies; ++i)
+ {
+ if(totalRatio > .5)
+ pieContainer.appendChild(edgeElems[i]);
+ totalRatio += (yValues[iGroup][i])/(pieTotal);
+ }
+
+ totalRatio = 0;
+ for (var i = 0; i< nPies; ++i)
+ {
+ if(totalRatio > .5)
+ pieContainer.appendChild(ringElems[i]);
+ totalRatio += (yValues[iGroup][i])/(pieTotal);
+ }
+
+ for (var i = 0; i< nPies; ++i)
+ {
+ pieContainer.appendChild(pieElems[i]);
+ }
+}
+
+ApachePieChart.prototype.GetToolTipLocation = function(e, ttBBox)
+{
+ var evtTarget = e.target;
+ var targetBBox = evtTarget.getBBox();
+ var ctm = evtTarget.parentNode.getCTM();
+ return {x:(ctm.e+targetBBox.x+targetBBox.width/2),
+ y:(ctm.f+targetBBox.y+targetBBox.height/2 - ttBBox.height)};
+}
+
+ApachePieChart._MAX_PERSPECTIVE_HEIGHT = 30;
+////////////////////////////////////////////////////////////////////
+// Area chart subclass
+////////////////////////////////////////////////////////////////////
+function ApacheAreaChart(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ this.Init(type, model, svgEmbedId, isPerspective, legendPosition);
+}
+
+ApacheChartObj.Inherit(ApacheChart, ApacheAreaChart);
+
+ApacheAreaChart.prototype.Init = function(
+ type, model, svgEmbedId,
+ isPerspective, legendPosition)
+{
+ ApacheAreaChart.superclass.Init.call(this, type, model, svgEmbedId,
+ isPerspective, legendPosition);
+ this._toolTips = [];
+}
+
+ApacheAreaChart.prototype.SetStopOpacity = function(stopNode)
+{
+ // In gecko opacity does not mix with stop-opacity, so use a lower value
+ stopNode.setAttribute("stop-opacity", ApacheChart._DEFAULT_STOP_OPACITY/2);
+}
+
+ApacheAreaChart.prototype.DrawChartData = function()
+{
+ var rootElem = this._rootElement;
+
+ if(this._tooltipsVisible)
+ {
+ rootElem.addEventListener("mousemove",this.ShowToolTipCallback,false);
+ rootElem.addEventListener("mouseout",this.HideToolTipCallback,false);
+ }
+
+ if(this._isPerspective)
+ this._drawPerspectiveAreas();
+ else
+ this._drawAreas();
+}
+
+ApacheAreaChart.prototype.SetDataAnimStep = function(ratio)
+{
+ var model = this._model,
+ seriesLabels = model.getSeriesLabels(), seriesCount = seriesLabels.length;
+ var yValues = model.getYValues(), yValueCount = yValues.length;
+ var animElems = this._dataElems, animPathCount = (this._isPerspective)? (yValueCount-1):1;
+ var margins = this._margins, marginBottom = margins.bottom;
+ var cy = (this._height - marginBottom);
+ var newRatio = ratio*seriesCount, animSeriesIndex = 0;
+ if(newRatio > 1)
+ {
+ animSeriesIndex = Math.floor(newRatio);
+ if(animSeriesIndex >= seriesCount)
+ animSeriesIndex = seriesCount - 1;
+ newRatio = newRatio - Math.floor(newRatio);
+ }
+
+ // We will make each series appear separately
+ var i = animSeriesIndex;
+ for (var j = 0; j < animPathCount; ++j)
+ {
+ var ty = (1-newRatio)*cy;
+ animElems[i*animPathCount+j].setAttribute("transform", "translate(0,"+ty+") scale(1,"+newRatio+")");
+ if(i>0)
+ {
+ animElems[(i-1)*animPathCount+j].setAttribute("transform", "scale(1,1)");
+ }
+ }
+ // make sure that everything is scaled properly at the end
+ if(ratio == 1)
+ {
+ for(var i = 0; i < seriesCount; ++i)
+ {
+ for (var j = 0; j < animPathCount; ++j)
+ {
+ animElems[i*animPathCount+j].setAttribute("transform", "scale(1,1)");
+ }
+ }
+ }
+}
+
+/**
+ * Overridden to indicate that the group label is edge aligned instead of center aligned
+ */
+ApacheAreaChart.prototype.IsGroupLabelCentered = function()
+{
+ return false;
+}
+
+ApacheAreaChart.prototype.GetVLineCount = function()
+{
+ var xMajorCount = this._xMajorGridCount;
+ if(xMajorCount >= 0)
+ return xMajorCount;
+ else
+ {
+ // Area Chart has one vertical line less since the
+ // first line represents a value
+ return this._model.getGroupLabels().length-1;
+ }
+}
+
+ApacheAreaChart.prototype._drawAreas = function()
+{
+ var svgDoc = this._svgDoc, model = this._model, margins = this._margins;
+ var rootElem = this._rootElement, dataElems = this._dataElems, animate = (this._animDuration>0);
+ var marginLeft = margins.left, marginTop = margins.top;
+ var gridWidth = (this._width - marginLeft - margins.right);
[... 2542 lines stripped ...]