diff options
author | mattpiwik <matthieu.aubry@gmail.com> | 2011-05-20 05:29:42 +0400 |
---|---|---|
committer | mattpiwik <matthieu.aubry@gmail.com> | 2011-05-20 05:29:42 +0400 |
commit | cf8fb7a3b537f0affa37417cdb4355a1150f9763 (patch) | |
tree | 182ec257f4e4299b993d3934c11103701f55cc01 /libs/jqplot | |
parent | 54aa61a0c6328134d280b9b60080c82252aa8bb1 (diff) |
one more try, native EOL
git-svn-id: http://dev.piwik.org/svn/trunk@4729 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'libs/jqplot')
-rwxr-xr-x | libs/jqplot/plugins/jqplot.cursor.js | 2038 | ||||
-rw-r--r-- | libs/jqplot/plugins/jqplot.highlighter.js | 824 | ||||
-rwxr-xr-x | libs/jqplot/plugins/jqplot.pieRenderer.js | 1606 |
3 files changed, 2234 insertions, 2234 deletions
diff --git a/libs/jqplot/plugins/jqplot.cursor.js b/libs/jqplot/plugins/jqplot.cursor.js index 6251531fbd..a8deb9fb83 100755 --- a/libs/jqplot/plugins/jqplot.cursor.js +++ b/libs/jqplot/plugins/jqplot.cursor.js @@ -1,1020 +1,1020 @@ -/** - * jqPlot - * Pure JavaScript plotting plugin using jQuery - * - * Version: @VERSION - * - * Copyright (c) 2009-2011 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. - * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: - * chris at jqplot dot com or see http://www.jqplot.com/info.php . - * - * If you are feeling kind and generous, consider supporting the project by - * making a donation at: http://www.jqplot.com/donate.php . - * - * sprintf functions contained in jqplot.sprintf.js by Ash Searle: - * - * version 2007.04.27 - * author Ash Searle - * http://hexmen.com/blog/2007/03/printf-sprintf/ - * http://hexmen.com/js/sprintf.js - * The author (Ash Searle) has placed this code in the public domain: - * "This code is unrestricted: you are free to use it however you like." - * - */ -(function($) { - - /** - * Class: $.jqplot.Cursor - * Plugin class representing the cursor as displayed on the plot. - */ - $.jqplot.Cursor = function(options) { - // Group: Properties - // - // prop: style - // CSS spec for cursor style - this.style = 'crosshair'; - this.previousCursor = 'auto'; - // prop: show - // wether to show the cursor or not. - this.show = $.jqplot.config.enablePlugins; - // prop: showTooltip - // show a cursor position tooltip. Location of the tooltip - // will be controlled by followMouse and tooltipLocation. - this.showTooltip = true; - // prop: followMouse - // Tooltip follows the mouse, it is not at a fixed location. - // Tooltip will show on the grid at the location given by - // tooltipLocation, offset from the grid edge by tooltipOffset. - this.followMouse = false; - // prop: tooltipLocation - // Where to position tooltip. If followMouse is true, this is - // relative to the cursor, otherwise, it is relative to the grid. - // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' - this.tooltipLocation = 'se'; - // prop: tooltipOffset - // Pixel offset of tooltip from the grid boudaries or cursor center. - this.tooltipOffset = 6; - // prop: showTooltipGridPosition - // show the grid pixel coordinates of the mouse. - this.showTooltipGridPosition = false; - // prop: showTooltipUnitPosition - // show the unit (data) coordinates of the mouse. - this.showTooltipUnitPosition = true; - // prop: showTooltipDataPosition - // Used with showVerticalLine to show intersecting data points in the tooltip. - this.showTooltipDataPosition = false; - // prop: tooltipFormatString - // sprintf format string for the tooltip. - // Uses Ash Searle's javascript sprintf implementation - // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ - // See http://perldoc.perl.org/functions/sprintf.html for reference - // Note, if showTooltipDataPosition is true, the default tooltipFormatString - // will be set to the cursorLegendFormatString, not the default given here. - this.tooltipFormatString = '%.4P, %.4P'; - // prop: useAxesFormatters - // Use the x and y axes formatters to format the text in the tooltip. - this.useAxesFormatters = true; - // prop: tooltipAxisGroups - // Show position for the specified axes. - // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']] - // Default is to compute automatically for all visible axes. - this.tooltipAxisGroups = []; - // prop: zoom - // Enable plot zooming. - this.zoom = false; - // zoomProxy and zoomTarget properties are not directly set by user. - // They Will be set through call to zoomProxy method. - this.zoomProxy = false; - this.zoomTarget = false; - // prop: looseZoom - // Will expand zoom range to provide more rounded tick values. - // Works only with linear axes and date axes. - this.looseZoom = false; - // prop: clickReset - // Will reset plot zoom if single click on plot without drag. - this.clickReset = false; - // prop: dblClickReset - // Will reset plot zoom if double click on plot without drag. - this.dblClickReset = true; - // prop: showVerticalLine - // draw a vertical line across the plot which follows the cursor. - // When the line is near a data point, a special legend and/or tooltip can - // be updated with the data values. - this.showVerticalLine = false; - // prop: showHorizontalLine - // draw a horizontal line across the plot which follows the cursor. - this.showHorizontalLine = false; - // prop: constrainZoomTo - // 'none', 'x' or 'y' - this.constrainZoomTo = 'none'; - // // prop: autoscaleConstraint - // // when a constrained axis is specified, true will - // // auatoscale the adjacent axis. - // this.autoscaleConstraint = true; - this.shapeRenderer = new $.jqplot.ShapeRenderer(); - this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}}; - this._tooltipElem; - this.zoomCanvas; - this.cursorCanvas; - // prop: intersectionThreshold - // pixel distance from data point or marker to consider cursor lines intersecting with point. - // If data point markers are not shown, this should be >= 1 or will often miss point intersections. - this.intersectionThreshold = 2; - // prop: showCursorLegend - // Replace the plot legend with an enhanced legend displaying intersection information. - this.showCursorLegend = false; - // prop: cursorLegendFormatString - // Format string used in the cursor legend. If showTooltipDataPosition is true, - // this will also be the default format string used by tooltipFormatString. - this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString; - // whether the cursor is over the grid or not. - this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null}; - // prop: constrainOutsideZoom - // True to limit actual zoom area to edges of grid, even when zooming - // outside of plot area. That is, can't zoom out by mousing outside plot. - this.constrainOutsideZoom = true; - // prop: showTooltipOutsideZoom - // True will keep updating the tooltip when zooming of the grid. - this.showTooltipOutsideZoom = false; - // true if mouse is over grid, false if not. - this.onGrid = false; - $.extend(true, this, options); - }; - - $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s'; - - // called with scope of plot - $.jqplot.Cursor.init = function (target, data, opts){ - // add a cursor attribute to the plot - var options = opts || {}; - this.plugins.cursor = new $.jqplot.Cursor(options.cursor); - var c = this.plugins.cursor; - - if (c.show) { - $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]); - $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]); - $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]); - - if (c.showCursorLegend) { - opts.legend = opts.legend || {}; - opts.legend.renderer = $.jqplot.CursorLegendRenderer; - opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString; - opts.legend.show = true; - } - - if (c.zoom) { - $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]); - - if (c.clickReset) { - $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]); - } - - if (c.dblClickReset) { - $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]); - } - } - - this.resetZoom = function() { - var axes = this.axes; - if (!c.zoomProxy) { - for (var ax in axes) { - axes[ax].reset(); - } - this.redraw(); - } - else { - var ctx = this.plugins.cursor.zoomCanvas._ctx; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx = null; - } - this.plugins.cursor._zoom.isZoomed = false; - this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]); - }; - - - if (c.showTooltipDataPosition) { - c.showTooltipUnitPosition = false; - c.showTooltipGridPosition = false; - if (options.cursor.tooltipFormatString == undefined) { - c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString; - } - } - } - }; - - // called with context of plot - $.jqplot.Cursor.postDraw = function() { - var c = this.plugins.cursor; - - // Memory Leaks patch - if (c.zoomCanvas) { - c.zoomCanvas.resetCanvas(); - c.zoomCanvas = null; - } - - if (c.cursorCanvas) { - c.cursorCanvas.resetCanvas(); - c.cursorCanvas = null; - } - - if (c._tooltipElem) { - c._tooltipElem.emptyForce(); - c._tooltipElem = null; - } - - - // if (c.zoom) { - c.zoomCanvas = new $.jqplot.GenericCanvas(); - this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions)); - c.zoomCanvas.setContext(); - // } - c._tooltipElem = $('<div class="jqplot-cursor-tooltip" style="position:absolute;display:none"></div>'); - c.zoomCanvas._elem.before(c._tooltipElem); - if (c.showVerticalLine || c.showHorizontalLine) { - c.cursorCanvas = new $.jqplot.GenericCanvas(); - this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions)); - c.cursorCanvas.setContext(); - } - - // if we are showing the positions in unit coordinates, and no axes groups - // were specified, create a default set. - if (c.showTooltipUnitPosition){ - if (c.tooltipAxisGroups.length === 0) { - var series = this.series; - var s; - var temp = []; - for (var i=0; i<series.length; i++) { - s = series[i]; - var ax = s.xaxis+','+s.yaxis; - if ($.inArray(ax, temp) == -1) { - temp.push(ax); - } - } - for (var i=0; i<temp.length; i++) { - c.tooltipAxisGroups.push(temp[i].split(',')); - } - } - } - }; - - // Group: methods - // - // method: $.jqplot.Cursor.zoomProxy - // links targetPlot to controllerPlot so that plot zooming of - // targetPlot will be controlled by zooming on the controllerPlot. - // controllerPlot will not actually zoom, but acts as an - // overview plot. Note, the zoom options must be set to true for - // zoomProxy to work. - $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) { - var tc = targetPlot.plugins.cursor; - var cc = controllerPlot.plugins.cursor; - tc.zoomTarget = true; - tc.zoom = true; - tc.style = 'auto'; - tc.dblClickReset = false; - cc.zoom = true; - cc.zoomProxy = true; - - controllerPlot.target.bind('jqplotZoom', plotZoom); - controllerPlot.target.bind('jqplotResetZoom', plotReset); - - function plotZoom(ev, gridpos, datapos, plot, cursor) { - tc.doZoom(gridpos, datapos, targetPlot, cursor); - } - - function plotReset(ev, plot, cursor) { - targetPlot.resetZoom(); - } - }; - - $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) { - var axes = plot.axes; - var cax = cursor._zoom.axes; - if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) { - for (var ax in axes) { - axes[ax]._ticks = []; - axes[ax].min = cax[ax].min; - axes[ax].max = cax[ax].max; - axes[ax].numberTicks = cax[ax].numberTicks; - axes[ax].tickInterval = cax[ax].tickInterval; - // for date axes - axes[ax].daTickInterval = cax[ax].daTickInterval; - } - plot.redraw(); - cursor._zoom.isZoomed = false; - } - else { - var ctx = cursor.zoomCanvas._ctx; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx = null; - } - plot.target.trigger('jqplotResetZoom', [plot, cursor]); - }; - - $.jqplot.Cursor.resetZoom = function(plot) { - plot.resetZoom(); - }; - - $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) { - var c = cursor; - var axes = plot.axes; - var zaxes = c._zoom.axes; - var start = zaxes.start; - var end = zaxes.end; - var min, max, dp, span; - var ctx = plot.plugins.cursor.zoomCanvas._ctx; - // don't zoom if zoom area is too small (in pixels) - if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) { - if (!plot.plugins.cursor.zoomProxy) { - for (var ax in datapos) { - // make a copy of the original axes to revert back. - if (c._zoom.axes[ax] == undefined) { - c._zoom.axes[ax] = {}; - c._zoom.axes[ax].numberTicks = axes[ax].numberTicks; - c._zoom.axes[ax].tickInterval = axes[ax].tickInterval; - // for date axes... - c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval; - c._zoom.axes[ax].min = axes[ax].min; - c._zoom.axes[ax].max = axes[ax].max; - } - - - if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) { - dp = datapos[ax]; - if (dp != null) { - var newmin, newmax; - if (dp > start[ax]) { - newmin = start[ax]; - newmax = dp; - } - else { - span = start[ax] - dp; - newmin = dp; - newmax = start[ax]; - } - - if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) { - var ret = $.jqplot.LinearTickGenerator(newmin, newmax); - axes[ax].min = ret[0]; - axes[ax].max = ret[1]; - axes[ax].numberTicks = ret[2]; - axes[ax].tickInterval = ret[4]; - // for date axes... - axes[ax].daTickInterval = [ret[4]/1000, 'seconds']; - } - else { - axes[ax].min = newmin; - axes[ax].max = newmax; - axes[ax].tickInterval = null; - // for date axes... - axes[ax].daTickInterval = null; - } - - axes[ax]._ticks = []; - } - } - - // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) { - // dp = datapos[ax]; - // if (dp != null) { - // axes[ax].max == null; - // axes[ax].min = null; - // } - // } - } - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - plot.redraw(); - c._zoom.isZoomed = true; - ctx = null; - } - plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]); - } - }; - - $.jqplot.preInitHooks.push($.jqplot.Cursor.init); - $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw); - - function updateTooltip(gridpos, datapos, plot) { - var c = plot.plugins.cursor; - var s = ''; - var addbr = false; - if (c.showTooltipGridPosition) { - s = gridpos.x+', '+gridpos.y; - addbr = true; - } - if (c.showTooltipUnitPosition) { - var g; - for (var i=0; i<c.tooltipAxisGroups.length; i++) { - g = c.tooltipAxisGroups[i]; - if (addbr) { - s += '<br />'; - } - if (c.useAxesFormatters) { - var xf = plot.axes[g[0]]._ticks[0].formatter; - var yf = plot.axes[g[1]]._ticks[0].formatter; - var xfstr = plot.axes[g[0]]._ticks[0].formatString; - var yfstr = plot.axes[g[1]]._ticks[0].formatString; - s += xf(xfstr, datapos[g[0]]) + ', '+ yf(yfstr, datapos[g[1]]); - } - else { - s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]); - } - addbr = true; - } - } - - if (c.showTooltipDataPosition) { - var series = plot.series; - var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); - var addbr = false; - - for (var i = 0; i< series.length; i++) { - if (series[i].show) { - var idx = series[i].index; - var label = series[i].label.toString(); - var cellid = $.inArray(idx, ret.indices); - var sx = undefined; - var sy = undefined; - if (cellid != -1) { - var data = ret.data[cellid].data; - if (c.useAxesFormatters) { - var xf = series[i]._xaxis._ticks[0].formatter; - var yf = series[i]._yaxis._ticks[0].formatter; - var xfstr = series[i]._xaxis._ticks[0].formatString; - var yfstr = series[i]._yaxis._ticks[0].formatString; - sx = xf(xfstr, data[0]); - sy = yf(yfstr, data[1]); - } - else { - sx = data[0]; - sy = data[1]; - } - if (addbr) { - s += '<br />'; - } - s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy); - addbr = true; - } - } - } - - } - c._tooltipElem.html(s); - } - - function moveLine(gridpos, plot) { - var c = plot.plugins.cursor; - var ctx = c.cursorCanvas._ctx; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - if (c.showVerticalLine) { - c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]); - } - if (c.showHorizontalLine) { - c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]); - } - var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); - if (c.showCursorLegend) { - var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); - for (var i=0; i<cells.length; i++) { - var idx = $(cells[i]).data('seriesIndex'); - var series = plot.series[idx]; - var label = series.label.toString(); - var cellid = $.inArray(idx, ret.indices); - var sx = undefined; - var sy = undefined; - if (cellid != -1) { - var data = ret.data[cellid].data; - if (c.useAxesFormatters) { - var xf = series._xaxis._ticks[0].formatter; - var yf = series._yaxis._ticks[0].formatter; - var xfstr = series._xaxis._ticks[0].formatString; - var yfstr = series._yaxis._ticks[0].formatString; - sx = xf(xfstr, data[0]); - sy = yf(yfstr, data[1]); - } - else { - sx = data[0]; - sy = data[1]; - } - } - if (plot.legend.escapeHtml) { - $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); - } - else { - $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); - } - } - } - ctx = null; - } - - function getIntersectingPoints(plot, x, y) { - var ret = {indices:[], data:[]}; - var s, i, d0, d, j, r, p; - var threshold; - var c = plot.plugins.cursor; - for (var i=0; i<plot.series.length; i++) { - s = plot.series[i]; - r = s.renderer; - if (s.show) { - threshold = c.intersectionThreshold; - if (s.showMarker) { - threshold += s.markerRenderer.size/2; - } - for (var j=0; j<s.gridData.length; j++) { - p = s.gridData[j]; - // check vertical line - if (c.showVerticalLine) { - if (Math.abs(x-p[0]) <= threshold) { - ret.indices.push(i); - ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}); - } - } - } - } - } - return ret; - } - - function moveTooltip(gridpos, plot) { - var c = plot.plugins.cursor; - var elem = c._tooltipElem; - switch (c.tooltipLocation) { - case 'nw': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); - break; - case 'n': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; - var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); - break; - case 'ne': - var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); - break; - case 'e': - var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; - break; - case 'se': - var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; - break; - case 's': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; - var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; - break; - case 'sw': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; - break; - case 'w': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; - break; - default: - var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; - var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; - break; - } - - elem.css('left', x); - elem.css('top', y); - elem = null; - } - - function positionTooltip(plot) { - // fake a grid for positioning - var grid = plot._gridPadding; - var c = plot.plugins.cursor; - var elem = c._tooltipElem; - switch (c.tooltipLocation) { - case 'nw': - var a = grid.left + c.tooltipOffset; - var b = grid.top + c.tooltipOffset; - elem.css('left', a); - elem.css('top', b); - break; - case 'n': - var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; - var b = grid.top + c.tooltipOffset; - elem.css('left', a); - elem.css('top', b); - break; - case 'ne': - var a = grid.right + c.tooltipOffset; - var b = grid.top + c.tooltipOffset; - elem.css({right:a, top:b}); - break; - case 'e': - var a = grid.right + c.tooltipOffset; - var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; - elem.css({right:a, top:b}); - break; - case 'se': - var a = grid.right + c.tooltipOffset; - var b = grid.bottom + c.tooltipOffset; - elem.css({right:a, bottom:b}); - break; - case 's': - var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; - var b = grid.bottom + c.tooltipOffset; - elem.css({left:a, bottom:b}); - break; - case 'sw': - var a = grid.left + c.tooltipOffset; - var b = grid.bottom + c.tooltipOffset; - elem.css({left:a, bottom:b}); - break; - case 'w': - var a = grid.left + c.tooltipOffset; - var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; - elem.css({left:a, top:b}); - break; - default: // same as 'se' - var a = grid.right - c.tooltipOffset; - var b = grid.bottom + c.tooltipOffset; - elem.css({right:a, bottom:b}); - break; - } - elem = null; - } - - function handleClick (ev, gridpos, datapos, neighbor, plot) { - ev.preventDefault(); - ev.stopImmediatePropagation(); - var c = plot.plugins.cursor; - if (c.clickReset) { - c.resetZoom(plot, c); - } - var sel = window.getSelection; - if (document.selection && document.selection.empty) - { - document.selection.empty(); - } - else if (sel && !sel().isCollapsed) { - sel().collapse(); - } - return false; - } - - function handleDblClick (ev, gridpos, datapos, neighbor, plot) { - ev.preventDefault(); - ev.stopImmediatePropagation(); - var c = plot.plugins.cursor; - if (c.dblClickReset) { - c.resetZoom(plot, c); - } - var sel = window.getSelection; - if (document.selection && document.selection.empty) - { - document.selection.empty(); - } - else if (sel && !sel().isCollapsed) { - sel().collapse(); - } - return false; - } - - function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) { - var c = plot.plugins.cursor; - c.onGrid = false; - if (c.show) { - $(ev.target).css('cursor', c.previousCursor); - if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) { - c._tooltipElem.hide(); - } - if (c.zoom) { - c._zoom.gridpos = gridpos; - c._zoom.datapos = datapos; - } - if (c.showVerticalLine || c.showHorizontalLine) { - var ctx = c.cursorCanvas._ctx; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx = null; - } - if (c.showCursorLegend) { - var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); - for (var i=0; i<cells.length; i++) { - var idx = $(cells[i]).data('seriesIndex'); - var series = plot.series[idx]; - var label = series.label.toString(); - if (plot.legend.escapeHtml) { - $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); - } - else { - $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); - } - - } - } - } - } - - function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) { - var c = plot.plugins.cursor; - c.onGrid = true; - if (c.show) { - c.previousCursor = ev.target.style.cursor; - ev.target.style.cursor = c.style; - if (c.showTooltip) { - updateTooltip(gridpos, datapos, plot); - if (c.followMouse) { - moveTooltip(gridpos, plot); - } - else { - positionTooltip(plot); - } - c._tooltipElem.show(); - } - if (c.showVerticalLine || c.showHorizontalLine) { - moveLine(gridpos, plot); - } - } - - } - - function handleMouseMove(ev, gridpos, datapos, neighbor, plot) { - var c = plot.plugins.cursor; - var ctx = c.zoomCanvas._ctx; - if (c.show) { - if (c.showTooltip) { - updateTooltip(gridpos, datapos, plot); - if (c.followMouse) { - moveTooltip(gridpos, plot); - } - } - if (c.showVerticalLine || c.showHorizontalLine) { - moveLine(gridpos, plot); - } - } - ctx = null; - } - - function getEventPosition(ev) { - var plot = ev.data.plot; - var go = plot.eventCanvas._elem.offset(); - var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; - var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null}; - var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; - var ax = plot.axes; - var n, axis; - for (n=11; n>0; n--) { - axis = an[n-1]; - if (ax[axis].show) { - dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); - } - } - - return {offsets:go, gridPos:gridPos, dataPos:dataPos}; - } - - function handleZoomMove(ev) { - var plot = ev.data.plot; - var c = plot.plugins.cursor; - // don't do anything if not on grid. - if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) { - var ctx = c.zoomCanvas._ctx; - var positions = getEventPosition(ev); - var gridpos = positions.gridPos; - var datapos = positions.dataPos; - c._zoom.gridpos = gridpos; - c._zoom.datapos = datapos; - c._zoom.zooming = true; - var xpos = gridpos.x; - var ypos = gridpos.y; - var height = ctx.canvas.height; - var width = ctx.canvas.width; - if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) { - updateTooltip(gridpos, datapos, plot); - if (c.followMouse) { - moveTooltip(gridpos, plot); - } - } - if (c.constrainZoomTo == 'x') { - c._zoom.end = [xpos, height]; - } - else if (c.constrainZoomTo == 'y') { - c._zoom.end = [width, ypos]; - } - else { - c._zoom.end = [xpos, ypos]; - } - var sel = window.getSelection; - if (document.selection && document.selection.empty) - { - document.selection.empty(); - } - else if (sel && !sel().isCollapsed) { - sel().collapse(); - } - drawZoomBox.call(c); - ctx = null; - } - } - - function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { - var c = plot.plugins.cursor; - $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp); - var axes = plot.axes; - if (document.onselectstart != undefined) { - c._oldHandlers.onselectstart = document.onselectstart; - document.onselectstart = function () { return false; }; - } - if (document.ondrag != undefined) { - c._oldHandlers.ondrag = document.ondrag; - document.ondrag = function () { return false; }; - } - if (document.onmousedown != undefined) { - c._oldHandlers.onmousedown = document.onmousedown; - document.onmousedown = function () { return false; }; - } - if (c.zoom) { - if (!c.zoomProxy) { - var ctx = c.zoomCanvas._ctx; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx = null; - } - if (c.constrainZoomTo == 'x') { - c._zoom.start = [gridpos.x, 0]; - } - else if (c.constrainZoomTo == 'y') { - c._zoom.start = [0, gridpos.y]; - } - else { - c._zoom.start = [gridpos.x, gridpos.y]; - } - c._zoom.started = true; - for (var ax in datapos) { - // get zoom starting position. - c._zoom.axes.start[ax] = datapos[ax]; - } - $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove); - } - } - - function handleMouseUp(ev) { - var plot = ev.data.plot; - var c = plot.plugins.cursor; - if (c.zoom && c._zoom.zooming && !c.zoomTarget) { - var xpos = c._zoom.gridpos.x; - var ypos = c._zoom.gridpos.y; - var datapos = c._zoom.datapos; - var height = c.zoomCanvas._ctx.canvas.height; - var width = c.zoomCanvas._ctx.canvas.width; - var axes = plot.axes; - - if (c.constrainOutsideZoom && !c.onGrid) { - if (xpos < 0) { xpos = 0; } - else if (xpos > width) { xpos = width; } - if (ypos < 0) { ypos = 0; } - else if (ypos > height) { ypos = height; } - - for (var axis in datapos) { - if (datapos[axis]) { - if (axis.charAt(0) == 'x') { - datapos[axis] = axes[axis].series_p2u(xpos); - } - else { - datapos[axis] = axes[axis].series_p2u(ypos); - } - } - } - } - - if (c.constrainZoomTo == 'x') { - ypos = height; - } - else if (c.constrainZoomTo == 'y') { - xpos = width; - } - c._zoom.end = [xpos, ypos]; - c._zoom.gridpos = {x:xpos, y:ypos}; - - c.doZoom(c._zoom.gridpos, datapos, plot, c); - } - c._zoom.started = false; - c._zoom.zooming = false; - - $(document).unbind('mousemove.jqplotCursor', handleZoomMove); - - if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){ - document.onselectstart = c._oldHandlers.onselectstart; - c._oldHandlers.onselectstart = null; - } - if (document.ondrag != undefined && c._oldHandlers.ondrag != null){ - document.ondrag = c._oldHandlers.ondrag; - c._oldHandlers.ondrag = null; - } - if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){ - document.onmousedown = c._oldHandlers.onmousedown; - c._oldHandlers.onmousedown = null; - } - - } - - function drawZoomBox() { - var start = this._zoom.start; - var end = this._zoom.end; - var ctx = this.zoomCanvas._ctx; - var l, t, h, w; - if (end[0] > start[0]) { - l = start[0]; - w = end[0] - start[0]; - } - else { - l = end[0]; - w = start[0] - end[0]; - } - if (end[1] > start[1]) { - t = start[1]; - h = end[1] - start[1]; - } - else { - t = end[1]; - h = start[1] - end[1]; - } - ctx.fillStyle = 'rgba(0,0,0,0.2)'; - ctx.strokeStyle = '#999999'; - ctx.lineWidth = 1.0; - ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height); - ctx.clearRect(l, t, w, h); - // IE won't show transparent fill rect, so stroke a rect also. - ctx.strokeRect(l,t,w,h); - ctx = null; - } - - $.jqplot.CursorLegendRenderer = function(options) { - $.jqplot.TableLegendRenderer.call(this, options); - this.formatString = '%s'; - }; - - $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); - $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer; - - // called in context of a Legend - $.jqplot.CursorLegendRenderer.prototype.draw = function() { - if (this.show) { - var series = this._series, s; - // make a table. one line label per row. - this._elem = $('<table class="jqplot-legend jqplot-cursor-legend" style="position:absolute"></table>'); - - var pad = false; - for (var i = 0; i< series.length; i++) { - s = series[i]; - if (s.show && s.showLabel) { - var lt = $.jqplot.sprintf(this.formatString, s.label.toString()); - if (lt) { - var color = s.color; - if (s._stack && !s.fill) { - color = ''; - } - addrow.call(this, lt, color, pad, i); - pad = true; - } - // let plugins add more rows to legend. Used by trend line plugin. - for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { - var item = $.jqplot.addLegendRowHooks[j].call(this, s); - if (item) { - addrow.call(this, item.label, item.color, pad); - pad = true; - } - } - } - } - series = s = null; - delete series; - delete s; - } - - function addrow(label, color, pad, idx) { - var rs = (pad) ? this.rowSpacing : '0'; - var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem); - tr.data('seriesIndex', idx); - $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+ - '<div style="border:1px solid #cccccc;padding:0.2em;">'+ - '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+ - '</div></td>').appendTo(tr); - var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>'); - td.appendTo(tr); - td.data('seriesIndex', idx); - if (this.escapeHtml) { - td.text(label); - } - else { - td.html(label); - } - tr = null; - td = null; - } - return this._elem; - }; - +/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Cursor
+ * Plugin class representing the cursor as displayed on the plot.
+ */
+ $.jqplot.Cursor = function(options) {
+ // Group: Properties
+ //
+ // prop: style
+ // CSS spec for cursor style
+ this.style = 'crosshair';
+ this.previousCursor = 'auto';
+ // prop: show
+ // wether to show the cursor or not.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: showTooltip
+ // show a cursor position tooltip. Location of the tooltip
+ // will be controlled by followMouse and tooltipLocation.
+ this.showTooltip = true;
+ // prop: followMouse
+ // Tooltip follows the mouse, it is not at a fixed location.
+ // Tooltip will show on the grid at the location given by
+ // tooltipLocation, offset from the grid edge by tooltipOffset.
+ this.followMouse = false;
+ // prop: tooltipLocation
+ // Where to position tooltip. If followMouse is true, this is
+ // relative to the cursor, otherwise, it is relative to the grid.
+ // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'se';
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the grid boudaries or cursor center.
+ this.tooltipOffset = 6;
+ // prop: showTooltipGridPosition
+ // show the grid pixel coordinates of the mouse.
+ this.showTooltipGridPosition = false;
+ // prop: showTooltipUnitPosition
+ // show the unit (data) coordinates of the mouse.
+ this.showTooltipUnitPosition = true;
+ // prop: showTooltipDataPosition
+ // Used with showVerticalLine to show intersecting data points in the tooltip.
+ this.showTooltipDataPosition = false;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference
+ // Note, if showTooltipDataPosition is true, the default tooltipFormatString
+ // will be set to the cursorLegendFormatString, not the default given here.
+ this.tooltipFormatString = '%.4P, %.4P';
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipAxisGroups
+ // Show position for the specified axes.
+ // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']]
+ // Default is to compute automatically for all visible axes.
+ this.tooltipAxisGroups = [];
+ // prop: zoom
+ // Enable plot zooming.
+ this.zoom = false;
+ // zoomProxy and zoomTarget properties are not directly set by user.
+ // They Will be set through call to zoomProxy method.
+ this.zoomProxy = false;
+ this.zoomTarget = false;
+ // prop: looseZoom
+ // Will expand zoom range to provide more rounded tick values.
+ // Works only with linear axes and date axes.
+ this.looseZoom = false;
+ // prop: clickReset
+ // Will reset plot zoom if single click on plot without drag.
+ this.clickReset = false;
+ // prop: dblClickReset
+ // Will reset plot zoom if double click on plot without drag.
+ this.dblClickReset = true;
+ // prop: showVerticalLine
+ // draw a vertical line across the plot which follows the cursor.
+ // When the line is near a data point, a special legend and/or tooltip can
+ // be updated with the data values.
+ this.showVerticalLine = false;
+ // prop: showHorizontalLine
+ // draw a horizontal line across the plot which follows the cursor.
+ this.showHorizontalLine = false;
+ // prop: constrainZoomTo
+ // 'none', 'x' or 'y'
+ this.constrainZoomTo = 'none';
+ // // prop: autoscaleConstraint
+ // // when a constrained axis is specified, true will
+ // // auatoscale the adjacent axis.
+ // this.autoscaleConstraint = true;
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}};
+ this._tooltipElem;
+ this.zoomCanvas;
+ this.cursorCanvas;
+ // prop: intersectionThreshold
+ // pixel distance from data point or marker to consider cursor lines intersecting with point.
+ // If data point markers are not shown, this should be >= 1 or will often miss point intersections.
+ this.intersectionThreshold = 2;
+ // prop: showCursorLegend
+ // Replace the plot legend with an enhanced legend displaying intersection information.
+ this.showCursorLegend = false;
+ // prop: cursorLegendFormatString
+ // Format string used in the cursor legend. If showTooltipDataPosition is true,
+ // this will also be the default format string used by tooltipFormatString.
+ this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ // whether the cursor is over the grid or not.
+ this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null};
+ // prop: constrainOutsideZoom
+ // True to limit actual zoom area to edges of grid, even when zooming
+ // outside of plot area. That is, can't zoom out by mousing outside plot.
+ this.constrainOutsideZoom = true;
+ // prop: showTooltipOutsideZoom
+ // True will keep updating the tooltip when zooming of the grid.
+ this.showTooltipOutsideZoom = false;
+ // true if mouse is over grid, false if not.
+ this.onGrid = false;
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s';
+
+ // called with scope of plot
+ $.jqplot.Cursor.init = function (target, data, opts){
+ // add a cursor attribute to the plot
+ var options = opts || {};
+ this.plugins.cursor = new $.jqplot.Cursor(options.cursor);
+ var c = this.plugins.cursor;
+
+ if (c.show) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]);
+
+ if (c.showCursorLegend) {
+ opts.legend = opts.legend || {};
+ opts.legend.renderer = $.jqplot.CursorLegendRenderer;
+ opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString;
+ opts.legend.show = true;
+ }
+
+ if (c.zoom) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]);
+
+ if (c.clickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]);
+ }
+
+ if (c.dblClickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]);
+ }
+ }
+
+ this.resetZoom = function() {
+ var axes = this.axes;
+ if (!c.zoomProxy) {
+ for (var ax in axes) {
+ axes[ax].reset();
+ }
+ this.redraw();
+ }
+ else {
+ var ctx = this.plugins.cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ this.plugins.cursor._zoom.isZoomed = false;
+ this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]);
+ };
+
+
+ if (c.showTooltipDataPosition) {
+ c.showTooltipUnitPosition = false;
+ c.showTooltipGridPosition = false;
+ if (options.cursor.tooltipFormatString == undefined) {
+ c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ }
+ }
+ }
+ };
+
+ // called with context of plot
+ $.jqplot.Cursor.postDraw = function() {
+ var c = this.plugins.cursor;
+
+ // Memory Leaks patch
+ if (c.zoomCanvas) {
+ c.zoomCanvas.resetCanvas();
+ c.zoomCanvas = null;
+ }
+
+ if (c.cursorCanvas) {
+ c.cursorCanvas.resetCanvas();
+ c.cursorCanvas = null;
+ }
+
+ if (c._tooltipElem) {
+ c._tooltipElem.emptyForce();
+ c._tooltipElem = null;
+ }
+
+
+ // if (c.zoom) {
+ c.zoomCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions));
+ c.zoomCanvas.setContext();
+ // }
+ c._tooltipElem = $('<div class="jqplot-cursor-tooltip" style="position:absolute;display:none"></div>');
+ c.zoomCanvas._elem.before(c._tooltipElem);
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ c.cursorCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions));
+ c.cursorCanvas.setContext();
+ }
+
+ // if we are showing the positions in unit coordinates, and no axes groups
+ // were specified, create a default set.
+ if (c.showTooltipUnitPosition){
+ if (c.tooltipAxisGroups.length === 0) {
+ var series = this.series;
+ var s;
+ var temp = [];
+ for (var i=0; i<series.length; i++) {
+ s = series[i];
+ var ax = s.xaxis+','+s.yaxis;
+ if ($.inArray(ax, temp) == -1) {
+ temp.push(ax);
+ }
+ }
+ for (var i=0; i<temp.length; i++) {
+ c.tooltipAxisGroups.push(temp[i].split(','));
+ }
+ }
+ }
+ };
+
+ // Group: methods
+ //
+ // method: $.jqplot.Cursor.zoomProxy
+ // links targetPlot to controllerPlot so that plot zooming of
+ // targetPlot will be controlled by zooming on the controllerPlot.
+ // controllerPlot will not actually zoom, but acts as an
+ // overview plot. Note, the zoom options must be set to true for
+ // zoomProxy to work.
+ $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) {
+ var tc = targetPlot.plugins.cursor;
+ var cc = controllerPlot.plugins.cursor;
+ tc.zoomTarget = true;
+ tc.zoom = true;
+ tc.style = 'auto';
+ tc.dblClickReset = false;
+ cc.zoom = true;
+ cc.zoomProxy = true;
+
+ controllerPlot.target.bind('jqplotZoom', plotZoom);
+ controllerPlot.target.bind('jqplotResetZoom', plotReset);
+
+ function plotZoom(ev, gridpos, datapos, plot, cursor) {
+ tc.doZoom(gridpos, datapos, targetPlot, cursor);
+ }
+
+ function plotReset(ev, plot, cursor) {
+ targetPlot.resetZoom();
+ }
+ };
+
+ $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) {
+ var axes = plot.axes;
+ var cax = cursor._zoom.axes;
+ if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) {
+ for (var ax in axes) {
+ axes[ax]._ticks = [];
+ axes[ax].min = cax[ax].min;
+ axes[ax].max = cax[ax].max;
+ axes[ax].numberTicks = cax[ax].numberTicks;
+ axes[ax].tickInterval = cax[ax].tickInterval;
+ // for date axes
+ axes[ax].daTickInterval = cax[ax].daTickInterval;
+ }
+ plot.redraw();
+ cursor._zoom.isZoomed = false;
+ }
+ else {
+ var ctx = cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ plot.target.trigger('jqplotResetZoom', [plot, cursor]);
+ };
+
+ $.jqplot.Cursor.resetZoom = function(plot) {
+ plot.resetZoom();
+ };
+
+ $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) {
+ var c = cursor;
+ var axes = plot.axes;
+ var zaxes = c._zoom.axes;
+ var start = zaxes.start;
+ var end = zaxes.end;
+ var min, max, dp, span;
+ var ctx = plot.plugins.cursor.zoomCanvas._ctx;
+ // don't zoom if zoom area is too small (in pixels)
+ if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) {
+ if (!plot.plugins.cursor.zoomProxy) {
+ for (var ax in datapos) {
+ // make a copy of the original axes to revert back.
+ if (c._zoom.axes[ax] == undefined) {
+ c._zoom.axes[ax] = {};
+ c._zoom.axes[ax].numberTicks = axes[ax].numberTicks;
+ c._zoom.axes[ax].tickInterval = axes[ax].tickInterval;
+ // for date axes...
+ c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval;
+ c._zoom.axes[ax].min = axes[ax].min;
+ c._zoom.axes[ax].max = axes[ax].max;
+ }
+
+
+ if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) {
+ dp = datapos[ax];
+ if (dp != null) {
+ var newmin, newmax;
+ if (dp > start[ax]) {
+ newmin = start[ax];
+ newmax = dp;
+ }
+ else {
+ span = start[ax] - dp;
+ newmin = dp;
+ newmax = start[ax];
+ }
+
+ if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) {
+ var ret = $.jqplot.LinearTickGenerator(newmin, newmax);
+ axes[ax].min = ret[0];
+ axes[ax].max = ret[1];
+ axes[ax].numberTicks = ret[2];
+ axes[ax].tickInterval = ret[4];
+ // for date axes...
+ axes[ax].daTickInterval = [ret[4]/1000, 'seconds'];
+ }
+ else {
+ axes[ax].min = newmin;
+ axes[ax].max = newmax;
+ axes[ax].tickInterval = null;
+ // for date axes...
+ axes[ax].daTickInterval = null;
+ }
+
+ axes[ax]._ticks = [];
+ }
+ }
+
+ // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) {
+ // dp = datapos[ax];
+ // if (dp != null) {
+ // axes[ax].max == null;
+ // axes[ax].min = null;
+ // }
+ // }
+ }
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ plot.redraw();
+ c._zoom.isZoomed = true;
+ ctx = null;
+ }
+ plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]);
+ }
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Cursor.init);
+ $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw);
+
+ function updateTooltip(gridpos, datapos, plot) {
+ var c = plot.plugins.cursor;
+ var s = '';
+ var addbr = false;
+ if (c.showTooltipGridPosition) {
+ s = gridpos.x+', '+gridpos.y;
+ addbr = true;
+ }
+ if (c.showTooltipUnitPosition) {
+ var g;
+ for (var i=0; i<c.tooltipAxisGroups.length; i++) {
+ g = c.tooltipAxisGroups[i];
+ if (addbr) {
+ s += '<br />';
+ }
+ if (c.useAxesFormatters) {
+ var xf = plot.axes[g[0]]._ticks[0].formatter;
+ var yf = plot.axes[g[1]]._ticks[0].formatter;
+ var xfstr = plot.axes[g[0]]._ticks[0].formatString;
+ var yfstr = plot.axes[g[1]]._ticks[0].formatString;
+ s += xf(xfstr, datapos[g[0]]) + ', '+ yf(yfstr, datapos[g[1]]);
+ }
+ else {
+ s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]);
+ }
+ addbr = true;
+ }
+ }
+
+ if (c.showTooltipDataPosition) {
+ var series = plot.series;
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ var addbr = false;
+
+ for (var i = 0; i< series.length; i++) {
+ if (series[i].show) {
+ var idx = series[i].index;
+ var label = series[i].label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series[i]._xaxis._ticks[0].formatter;
+ var yf = series[i]._yaxis._ticks[0].formatter;
+ var xfstr = series[i]._xaxis._ticks[0].formatString;
+ var yfstr = series[i]._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ if (addbr) {
+ s += '<br />';
+ }
+ s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy);
+ addbr = true;
+ }
+ }
+ }
+
+ }
+ c._tooltipElem.html(s);
+ }
+
+ function moveLine(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ if (c.showVerticalLine) {
+ c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
+ }
+ if (c.showHorizontalLine) {
+ c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
+ }
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ }
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ }
+ }
+ ctx = null;
+ }
+
+ function getIntersectingPoints(plot, x, y) {
+ var ret = {indices:[], data:[]};
+ var s, i, d0, d, j, r, p;
+ var threshold;
+ var c = plot.plugins.cursor;
+ for (var i=0; i<plot.series.length; i++) {
+ s = plot.series[i];
+ r = s.renderer;
+ if (s.show) {
+ threshold = c.intersectionThreshold;
+ if (s.showMarker) {
+ threshold += s.markerRenderer.size/2;
+ }
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // check vertical line
+ if (c.showVerticalLine) {
+ if (Math.abs(x-p[0]) <= threshold) {
+ ret.indices.push(i);
+ ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]});
+ }
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ function moveTooltip(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default:
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ }
+
+ elem.css('left', x);
+ elem.css('top', y);
+ elem = null;
+ }
+
+ function positionTooltip(plot) {
+ // fake a grid for positioning
+ var grid = plot._gridPadding;
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'n':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'ne':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = grid.right + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = grid.left + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid.right - c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ }
+ elem = null;
+ }
+
+ function handleClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.clickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleDblClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.dblClickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = false;
+ if (c.show) {
+ $(ev.target).css('cursor', c.previousCursor);
+ if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) {
+ c._tooltipElem.hide();
+ }
+ if (c.zoom) {
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+
+ }
+ }
+ }
+ }
+
+ function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = true;
+ if (c.show) {
+ c.previousCursor = ev.target.style.cursor;
+ ev.target.style.cursor = c.style;
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ else {
+ positionTooltip(plot);
+ }
+ c._tooltipElem.show();
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+
+ }
+
+ function handleMouseMove(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ var ctx = c.zoomCanvas._ctx;
+ if (c.show) {
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+ ctx = null;
+ }
+
+ function getEventPosition(ev) {
+ var plot = ev.data.plot;
+ var go = plot.eventCanvas._elem.offset();
+ var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
+ var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null};
+ var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
+ var ax = plot.axes;
+ var n, axis;
+ for (n=11; n>0; n--) {
+ axis = an[n-1];
+ if (ax[axis].show) {
+ dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
+ }
+ }
+
+ return {offsets:go, gridPos:gridPos, dataPos:dataPos};
+ }
+
+ function handleZoomMove(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ // don't do anything if not on grid.
+ if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) {
+ var ctx = c.zoomCanvas._ctx;
+ var positions = getEventPosition(ev);
+ var gridpos = positions.gridPos;
+ var datapos = positions.dataPos;
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ c._zoom.zooming = true;
+ var xpos = gridpos.x;
+ var ypos = gridpos.y;
+ var height = ctx.canvas.height;
+ var width = ctx.canvas.width;
+ if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.end = [xpos, height];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.end = [width, ypos];
+ }
+ else {
+ c._zoom.end = [xpos, ypos];
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ drawZoomBox.call(c);
+ ctx = null;
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
+ var axes = plot.axes;
+ if (document.onselectstart != undefined) {
+ c._oldHandlers.onselectstart = document.onselectstart;
+ document.onselectstart = function () { return false; };
+ }
+ if (document.ondrag != undefined) {
+ c._oldHandlers.ondrag = document.ondrag;
+ document.ondrag = function () { return false; };
+ }
+ if (document.onmousedown != undefined) {
+ c._oldHandlers.onmousedown = document.onmousedown;
+ document.onmousedown = function () { return false; };
+ }
+ if (c.zoom) {
+ if (!c.zoomProxy) {
+ var ctx = c.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.start = [gridpos.x, 0];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.start = [0, gridpos.y];
+ }
+ else {
+ c._zoom.start = [gridpos.x, gridpos.y];
+ }
+ c._zoom.started = true;
+ for (var ax in datapos) {
+ // get zoom starting position.
+ c._zoom.axes.start[ax] = datapos[ax];
+ }
+ $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove);
+ }
+ }
+
+ function handleMouseUp(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ if (c.zoom && c._zoom.zooming && !c.zoomTarget) {
+ var xpos = c._zoom.gridpos.x;
+ var ypos = c._zoom.gridpos.y;
+ var datapos = c._zoom.datapos;
+ var height = c.zoomCanvas._ctx.canvas.height;
+ var width = c.zoomCanvas._ctx.canvas.width;
+ var axes = plot.axes;
+
+ if (c.constrainOutsideZoom && !c.onGrid) {
+ if (xpos < 0) { xpos = 0; }
+ else if (xpos > width) { xpos = width; }
+ if (ypos < 0) { ypos = 0; }
+ else if (ypos > height) { ypos = height; }
+
+ for (var axis in datapos) {
+ if (datapos[axis]) {
+ if (axis.charAt(0) == 'x') {
+ datapos[axis] = axes[axis].series_p2u(xpos);
+ }
+ else {
+ datapos[axis] = axes[axis].series_p2u(ypos);
+ }
+ }
+ }
+ }
+
+ if (c.constrainZoomTo == 'x') {
+ ypos = height;
+ }
+ else if (c.constrainZoomTo == 'y') {
+ xpos = width;
+ }
+ c._zoom.end = [xpos, ypos];
+ c._zoom.gridpos = {x:xpos, y:ypos};
+
+ c.doZoom(c._zoom.gridpos, datapos, plot, c);
+ }
+ c._zoom.started = false;
+ c._zoom.zooming = false;
+
+ $(document).unbind('mousemove.jqplotCursor', handleZoomMove);
+
+ if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){
+ document.onselectstart = c._oldHandlers.onselectstart;
+ c._oldHandlers.onselectstart = null;
+ }
+ if (document.ondrag != undefined && c._oldHandlers.ondrag != null){
+ document.ondrag = c._oldHandlers.ondrag;
+ c._oldHandlers.ondrag = null;
+ }
+ if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){
+ document.onmousedown = c._oldHandlers.onmousedown;
+ c._oldHandlers.onmousedown = null;
+ }
+
+ }
+
+ function drawZoomBox() {
+ var start = this._zoom.start;
+ var end = this._zoom.end;
+ var ctx = this.zoomCanvas._ctx;
+ var l, t, h, w;
+ if (end[0] > start[0]) {
+ l = start[0];
+ w = end[0] - start[0];
+ }
+ else {
+ l = end[0];
+ w = start[0] - end[0];
+ }
+ if (end[1] > start[1]) {
+ t = start[1];
+ h = end[1] - start[1];
+ }
+ else {
+ t = end[1];
+ h = start[1] - end[1];
+ }
+ ctx.fillStyle = 'rgba(0,0,0,0.2)';
+ ctx.strokeStyle = '#999999';
+ ctx.lineWidth = 1.0;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.clearRect(l, t, w, h);
+ // IE won't show transparent fill rect, so stroke a rect also.
+ ctx.strokeRect(l,t,w,h);
+ ctx = null;
+ }
+
+ $.jqplot.CursorLegendRenderer = function(options) {
+ $.jqplot.TableLegendRenderer.call(this, options);
+ this.formatString = '%s';
+ };
+
+ $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer;
+
+ // called in context of a Legend
+ $.jqplot.CursorLegendRenderer.prototype.draw = function() {
+ if (this.show) {
+ var series = this._series, s;
+ // make a table. one line label per row.
+ this._elem = $('<table class="jqplot-legend jqplot-cursor-legend" style="position:absolute"></table>');
+
+ var pad = false;
+ for (var i = 0; i< series.length; i++) {
+ s = series[i];
+ if (s.show && s.showLabel) {
+ var lt = $.jqplot.sprintf(this.formatString, s.label.toString());
+ if (lt) {
+ var color = s.color;
+ if (s._stack && !s.fill) {
+ color = '';
+ }
+ addrow.call(this, lt, color, pad, i);
+ pad = true;
+ }
+ // let plugins add more rows to legend. Used by trend line plugin.
+ for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
+ var item = $.jqplot.addLegendRowHooks[j].call(this, s);
+ if (item) {
+ addrow.call(this, item.label, item.color, pad);
+ pad = true;
+ }
+ }
+ }
+ }
+ series = s = null;
+ delete series;
+ delete s;
+ }
+
+ function addrow(label, color, pad, idx) {
+ var rs = (pad) ? this.rowSpacing : '0';
+ var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem);
+ tr.data('seriesIndex', idx);
+ $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+
+ '<div style="border:1px solid #cccccc;padding:0.2em;">'+
+ '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+
+ '</div></td>').appendTo(tr);
+ var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>');
+ td.appendTo(tr);
+ td.data('seriesIndex', idx);
+ if (this.escapeHtml) {
+ td.text(label);
+ }
+ else {
+ td.html(label);
+ }
+ tr = null;
+ td = null;
+ }
+ return this._elem;
+ };
+
})(jQuery);
\ No newline at end of file diff --git a/libs/jqplot/plugins/jqplot.highlighter.js b/libs/jqplot/plugins/jqplot.highlighter.js index 59a5b8faee..26e3a2f6bc 100644 --- a/libs/jqplot/plugins/jqplot.highlighter.js +++ b/libs/jqplot/plugins/jqplot.highlighter.js @@ -1,413 +1,413 @@ -/** - * jqPlot - * Pure JavaScript plotting plugin using jQuery - * - * Version: @VERSION - * - * Copyright (c) 2009-2011 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. - * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: - * chris at jqplot dot com or see http://www.jqplot.com/info.php . - * - * If you are feeling kind and generous, consider supporting the project by - * making a donation at: http://www.jqplot.com/donate.php . - * - * sprintf functions contained in jqplot.sprintf.js by Ash Searle: - * - * version 2007.04.27 - * author Ash Searle - * http://hexmen.com/blog/2007/03/printf-sprintf/ - * http://hexmen.com/js/sprintf.js - * The author (Ash Searle) has placed this code in the public domain: - * "This code is unrestricted: you are free to use it however you like." - * - */ -(function($) { - $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]); - - /** - * Class: $.jqplot.Highlighter - * Plugin which will highlight data points when they are moused over. - * - * To use this plugin, include the js - * file in your source: - * - * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script> - * - * A tooltip providing information about the data point is enabled by default. - * To disable the tooltip, set "showTooltip" to false. - * - * You can control what data is displayed in the tooltip with various - * options. The "tooltipAxes" option controls wether the x, y or both - * data values are displayed. - * - * Some chart types (e.g. hi-low-close) have more than one y value per - * data point. To display the additional values in the tooltip, set the - * "yvalues" option to the desired number of y values present (3 for a hlc chart). - * - * By default, data values will be formatted with the same formatting - * specifiers as used to format the axis ticks. A custom format code - * can be supplied with the tooltipFormatString option. This will apply - * to all values in the tooltip. - * - * For more complete control, the "formatString" option can be set. This - * Allows conplete control over tooltip formatting. Values are passed to - * the format string in an order determined by the "tooltipAxes" and "yvalues" - * options. So, if you have a hi-low-close chart and you just want to display - * the hi-low-close values in the tooltip, you could set a formatString like: - * - * > highlighter: { - * > tooltipAxes: 'y', - * > yvalues: 3, - * > formatString:'<table class="jqplot-highlighter"> - * > <tr><td>hi:</td><td>%s</td></tr> - * > <tr><td>low:</td><td>%s</td></tr> - * > <tr><td>close:</td><td>%s</td></tr></table>' - * > } - * - */ - $.jqplot.Highlighter = function(options) { - // Group: Properties - // - //prop: show - // true to show the highlight. - this.show = $.jqplot.config.enablePlugins; - // prop: markerRenderer - // Renderer used to draw the marker of the highlighted point. - // Renderer will assimilate attributes from the data point being highlighted, - // so no attributes need set on the renderer directly. - // Default is to turn off shadow drawing on the highlighted point. - this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false}); - // prop: showMarker - // true to show the marker - this.showMarker = true; - // prop: lineWidthAdjust - // Pixels to add to the lineWidth of the highlight. - this.lineWidthAdjust = 2.5; - // prop: sizeAdjust - // Pixels to add to the overall size of the highlight. - this.sizeAdjust = 5; - // prop: showTooltip - // Show a tooltip with data point values. - this.showTooltip = true; - // prop: tooltipLocation - // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' - this.tooltipLocation = 'nw'; - // prop: fadeTooltip - // true = fade in/out tooltip, flase = show/hide tooltip - this.fadeTooltip = true; - // prop: tooltipFadeSpeed - // 'slow', 'def', 'fast', or number of milliseconds. - this.tooltipFadeSpeed = "fast"; - // prop: tooltipOffset - // Pixel offset of tooltip from the highlight. - this.tooltipOffset = 2; - // prop: tooltipAxes - // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx' - // 'both' and 'xy' are equivalent, 'yx' reverses order of labels. - this.tooltipAxes = 'both'; - // prop; tooltipSeparator - // String to use to separate x and y axes in tooltip. - this.tooltipSeparator = ', '; - // prop; tooltipContentEditor - // Function used to edit/augment/replace the formatted tooltip contents. - // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex) - // where str is the generated tooltip html and seriesIndex and pointIndex identify - // the data point being highlighted. Should return the html for the tooltip contents. - this.tooltipContentEditor = null; - // prop: useAxesFormatters - // Use the x and y axes formatters to format the text in the tooltip. - this.useAxesFormatters = true; - // prop: tooltipFormatString - // sprintf format string for the tooltip. - // Uses Ash Searle's javascript sprintf implementation - // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ - // See http://perldoc.perl.org/functions/sprintf.html for reference. - // Additional "p" and "P" format specifiers added by Chris Leonello. - this.tooltipFormatString = '%.5P'; - // prop: formatString - // alternative to tooltipFormatString - // will format the whole tooltip text, populating with x, y values as - // indicated by tooltipAxes option. So, you could have a tooltip like: - // 'Date: %s, number of cats: %d' to format the whole tooltip at one go. - // If useAxesFormatters is true, values will be formatted according to - // Axes formatters and you can populate your tooltip string with - // %s placeholders. - this.formatString = null; - // prop: yvalues - // Number of y values to expect in the data point array. - // Typically this is 1. Certain plots, like OHLC, will - // have more y values in each data point array. - this.yvalues = 1; - // prop: bringSeriesToFront - // This option requires jQuery 1.4+ - // True to bring the series of the highlighted point to the front - // of other series. - this.bringSeriesToFront = false; - this._tooltipElem; - this.isHighlighting = false; - - $.extend(true, this, options); - }; - - var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; - var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; - var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; - - // axis.renderer.tickrenderer.formatter - - // called with scope of plot - $.jqplot.Highlighter.init = function (target, data, opts){ - var options = opts || {}; - // add a highlighter attribute to the plot - this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter); - }; - - // called within scope of series - $.jqplot.Highlighter.parseOptions = function (defaults, options) { - // Add a showHighlight option to the series - // and set it to true by default. - this.showHighlight = true; - }; - - // called within context of plot - // create a canvas which we can draw on. - // insert it before the eventCanvas, so eventCanvas will still capture events. - $.jqplot.Highlighter.postPlotDraw = function() { - // Memory Leaks patch - if (this.plugins.highlighter && - this.plugins.highlighter.highlightCanvas) { - this.plugins.highlighter.highlightCanvas.resetCanvas(); - this.plugins.highlighter.highlightCanvas = null; - } - - this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas(); - - this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions)); - this.plugins.highlighter.highlightCanvas.setContext(); - - var p = this.plugins.highlighter; - p._tooltipElem = $('<div class="jqplot-highlighter-tooltip" style="position:absolute;display:none"></div>'); - this.eventCanvas._elem.before(p._tooltipElem); - }; - - $.jqplot.preInitHooks.push($.jqplot.Highlighter.init); - $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions); - $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw); - - function draw(plot, neighbor) { - var hl = plot.plugins.highlighter; - var s = plot.series[neighbor.seriesIndex]; - var smr = s.markerRenderer; - var mr = hl.markerRenderer; - mr.style = smr.style; - mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust; - mr.size = smr.size + hl.sizeAdjust; - var rgba = $.jqplot.getColorComponents(smr.color); - var newrgb = [rgba[0], rgba[1], rgba[2]]; - var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]); - mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')'; - mr.init(); - mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx); - } - - function showTooltip(plot, series, neighbor) { - // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]} - // gridData should be x,y pixel coords on the grid. - // add the plot._gridPadding to that to get x,y in the target. - var hl = plot.plugins.highlighter; - var elem = hl._tooltipElem; - if (hl.useAxesFormatters) { - var xf = series._xaxis._ticks[0].formatter; - var yf = series._yaxis._ticks[0].formatter; - var xfstr = series._xaxis._ticks[0].formatString; - var yfstr = series._yaxis._ticks[0].formatString; - var str; - var xstr = xf(xfstr, neighbor.data[0]); - var ystrs = []; - for (var i=1; i<hl.yvalues+1; i++) { - ystrs.push(yf(yfstr, neighbor.data[i])); - } - if (hl.formatString) { - switch (hl.tooltipAxes) { - case 'both': - case 'xy': - ystrs.unshift(xstr); - ystrs.unshift(hl.formatString); - str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); - break; - case 'yx': - ystrs.push(xstr); - ystrs.unshift(hl.formatString); - str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); - break; - case 'x': - str = $.jqplot.sprintf.apply($.jqplot.sprintf, [hl.formatString, xstr]); - break; - case 'y': - ystrs.unshift(hl.formatString); - str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); - break; - default: // same as xy - ystrs.unshift(xstr); - ystrs.unshift(hl.formatString); - str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); - break; - } - } - else { - switch (hl.tooltipAxes) { - case 'both': - case 'xy': - str = xstr; - for (var i=0; i<ystrs.length; i++) { - str += hl.tooltipSeparator + ystrs[i]; - } - break; - case 'yx': - str = ''; - for (var i=0; i<ystrs.length; i++) { - str += ystrs[i] + hl.tooltipSeparator; - } - str += xstr; - break; - case 'x': - str = xstr; - break; - case 'y': - str = ystrs.join(hl.tooltipSeparator); - break; - default: // same as 'xy' - str = xstr; - for (var i=0; i<ystrs.length; i++) { - str += hl.tooltipSeparator + ystrs[i]; - } - break; - - } - } - } - else { - var str; - if (hl.tooltipAxes == 'both' || hl.tooltipAxes == 'xy') { - str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]) + hl.tooltipSeparator + $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]); - } - else if (hl.tooltipAxes == 'yx') { - str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]) + hl.tooltipSeparator + $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]); - } - else if (hl.tooltipAxes == 'x') { - str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]); - } - else if (hl.tooltipAxes == 'y') { - str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]); - } - } - if ($.isFunction(hl.tooltipContentEditor)) { - // args str, seriesIndex, pointIndex are essential so the hook can look up - // extra data for the point. - str = hl.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot); - } - elem.html(str); - var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]}; - var ms = 0; - var fact = 0.707; - if (series.markerRenderer.show == true) { - ms = (series.markerRenderer.size + hl.sizeAdjust)/2; - } - - var loc = locations; - if (series.fillToZero && series.fill && neighbor.data[1] < 0) { - loc = oppositeLocations; - } - - switch (loc[locationIndicies[hl.tooltipLocation]]) { - case 'nw': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms; - var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms; - break; - case 'n': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; - var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - ms; - break; - case 'ne': - var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + fact * ms; - var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms; - break; - case 'e': - var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + ms; - var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; - break; - case 'se': - var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + fact * ms; - var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + fact * ms; - break; - case 's': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; - var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + ms; - break; - case 'sw': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms; - var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + fact * ms; - break; - case 'w': - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - ms; - var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; - break; - default: // same as 'nw' - var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms; - var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms; - break; - } - elem.css('left', x); - elem.css('top', y); - if (hl.fadeTooltip) { - // Fix for stacked up animations. Thnanks Trevor! - elem.stop(true,true).fadeIn(hl.tooltipFadeSpeed); - } - else { - elem.show(); - } - elem = null; - - } - - function handleMove(ev, gridpos, datapos, neighbor, plot) { - var hl = plot.plugins.highlighter; - var c = plot.plugins.cursor; - if (hl.show) { - if (neighbor == null && hl.isHighlighting) { - var ctx = hl.highlightCanvas._ctx; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - if (hl.fadeTooltip) { - hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed); - } - else { - hl._tooltipElem.hide(); - } - if (hl.bringSeriesToFront) { - plot.restorePreviousSeriesOrder(); - } - hl.isHighlighting = false; - ctx = null; - - } - else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) { - hl.isHighlighting = true; - if (hl.showMarker) { - draw(plot, neighbor); - } - if (hl.showTooltip && (!c || !c._zoom.started)) { - showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor); - } - if (hl.bringSeriesToFront) { - plot.moveSeriesToFront(neighbor.seriesIndex); - } - } - } - } +/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+
+ /**
+ * Class: $.jqplot.Highlighter
+ * Plugin which will highlight data points when they are moused over.
+ *
+ * To use this plugin, include the js
+ * file in your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
+ *
+ * A tooltip providing information about the data point is enabled by default.
+ * To disable the tooltip, set "showTooltip" to false.
+ *
+ * You can control what data is displayed in the tooltip with various
+ * options. The "tooltipAxes" option controls wether the x, y or both
+ * data values are displayed.
+ *
+ * Some chart types (e.g. hi-low-close) have more than one y value per
+ * data point. To display the additional values in the tooltip, set the
+ * "yvalues" option to the desired number of y values present (3 for a hlc chart).
+ *
+ * By default, data values will be formatted with the same formatting
+ * specifiers as used to format the axis ticks. A custom format code
+ * can be supplied with the tooltipFormatString option. This will apply
+ * to all values in the tooltip.
+ *
+ * For more complete control, the "formatString" option can be set. This
+ * Allows conplete control over tooltip formatting. Values are passed to
+ * the format string in an order determined by the "tooltipAxes" and "yvalues"
+ * options. So, if you have a hi-low-close chart and you just want to display
+ * the hi-low-close values in the tooltip, you could set a formatString like:
+ *
+ * > highlighter: {
+ * > tooltipAxes: 'y',
+ * > yvalues: 3,
+ * > formatString:'<table class="jqplot-highlighter">
+ * > <tr><td>hi:</td><td>%s</td></tr>
+ * > <tr><td>low:</td><td>%s</td></tr>
+ * > <tr><td>close:</td><td>%s</td></tr></table>'
+ * > }
+ *
+ */
+ $.jqplot.Highlighter = function(options) {
+ // Group: Properties
+ //
+ //prop: show
+ // true to show the highlight.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: markerRenderer
+ // Renderer used to draw the marker of the highlighted point.
+ // Renderer will assimilate attributes from the data point being highlighted,
+ // so no attributes need set on the renderer directly.
+ // Default is to turn off shadow drawing on the highlighted point.
+ this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
+ // prop: showMarker
+ // true to show the marker
+ this.showMarker = true;
+ // prop: lineWidthAdjust
+ // Pixels to add to the lineWidth of the highlight.
+ this.lineWidthAdjust = 2.5;
+ // prop: sizeAdjust
+ // Pixels to add to the overall size of the highlight.
+ this.sizeAdjust = 5;
+ // prop: showTooltip
+ // Show a tooltip with data point values.
+ this.showTooltip = true;
+ // prop: tooltipLocation
+ // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'nw';
+ // prop: fadeTooltip
+ // true = fade in/out tooltip, flase = show/hide tooltip
+ this.fadeTooltip = true;
+ // prop: tooltipFadeSpeed
+ // 'slow', 'def', 'fast', or number of milliseconds.
+ this.tooltipFadeSpeed = "fast";
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the highlight.
+ this.tooltipOffset = 2;
+ // prop: tooltipAxes
+ // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
+ // 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
+ this.tooltipAxes = 'both';
+ // prop; tooltipSeparator
+ // String to use to separate x and y axes in tooltip.
+ this.tooltipSeparator = ', ';
+ // prop; tooltipContentEditor
+ // Function used to edit/augment/replace the formatted tooltip contents.
+ // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)
+ // where str is the generated tooltip html and seriesIndex and pointIndex identify
+ // the data point being highlighted. Should return the html for the tooltip contents.
+ this.tooltipContentEditor = null;
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference.
+ // Additional "p" and "P" format specifiers added by Chris Leonello.
+ this.tooltipFormatString = '%.5P';
+ // prop: formatString
+ // alternative to tooltipFormatString
+ // will format the whole tooltip text, populating with x, y values as
+ // indicated by tooltipAxes option. So, you could have a tooltip like:
+ // 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
+ // If useAxesFormatters is true, values will be formatted according to
+ // Axes formatters and you can populate your tooltip string with
+ // %s placeholders.
+ this.formatString = null;
+ // prop: yvalues
+ // Number of y values to expect in the data point array.
+ // Typically this is 1. Certain plots, like OHLC, will
+ // have more y values in each data point array.
+ this.yvalues = 1;
+ // prop: bringSeriesToFront
+ // This option requires jQuery 1.4+
+ // True to bring the series of the highlighted point to the front
+ // of other series.
+ this.bringSeriesToFront = false;
+ this._tooltipElem;
+ this.isHighlighting = false;
+
+ $.extend(true, this, options);
+ };
+
+ var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
+ var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
+ var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
+
+ // axis.renderer.tickrenderer.formatter
+
+ // called with scope of plot
+ $.jqplot.Highlighter.init = function (target, data, opts){
+ var options = opts || {};
+ // add a highlighter attribute to the plot
+ this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
+ };
+
+ // called within scope of series
+ $.jqplot.Highlighter.parseOptions = function (defaults, options) {
+ // Add a showHighlight option to the series
+ // and set it to true by default.
+ this.showHighlight = true;
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ $.jqplot.Highlighter.postPlotDraw = function() {
+ // Memory Leaks patch
+ if (this.plugins.highlighter &&
+ this.plugins.highlighter.highlightCanvas) {
+ this.plugins.highlighter.highlightCanvas.resetCanvas();
+ this.plugins.highlighter.highlightCanvas = null;
+ }
+
+ this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions));
+ this.plugins.highlighter.highlightCanvas.setContext();
+
+ var p = this.plugins.highlighter;
+ p._tooltipElem = $('<div class="jqplot-highlighter-tooltip" style="position:absolute;display:none"></div>');
+ this.eventCanvas._elem.before(p._tooltipElem);
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
+ $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
+ $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
+
+ function draw(plot, neighbor) {
+ var hl = plot.plugins.highlighter;
+ var s = plot.series[neighbor.seriesIndex];
+ var smr = s.markerRenderer;
+ var mr = hl.markerRenderer;
+ mr.style = smr.style;
+ mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
+ mr.size = smr.size + hl.sizeAdjust;
+ var rgba = $.jqplot.getColorComponents(smr.color);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
+ mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
+ mr.init();
+ mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);
+ }
+
+ function showTooltip(plot, series, neighbor) {
+ // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
+ // gridData should be x,y pixel coords on the grid.
+ // add the plot._gridPadding to that to get x,y in the target.
+ var hl = plot.plugins.highlighter;
+ var elem = hl._tooltipElem;
+ if (hl.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ var str;
+ var xstr = xf(xfstr, neighbor.data[0]);
+ var ystrs = [];
+ for (var i=1; i<hl.yvalues+1; i++) {
+ ystrs.push(yf(yfstr, neighbor.data[i]));
+ }
+ if (hl.formatString) {
+ switch (hl.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ ystrs.unshift(xstr);
+ ystrs.unshift(hl.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'yx':
+ ystrs.push(xstr);
+ ystrs.unshift(hl.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'x':
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, [hl.formatString, xstr]);
+ break;
+ case 'y':
+ ystrs.unshift(hl.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ default: // same as xy
+ ystrs.unshift(xstr);
+ ystrs.unshift(hl.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ }
+ }
+ else {
+ switch (hl.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += hl.tooltipSeparator + ystrs[i];
+ }
+ break;
+ case 'yx':
+ str = '';
+ for (var i=0; i<ystrs.length; i++) {
+ str += ystrs[i] + hl.tooltipSeparator;
+ }
+ str += xstr;
+ break;
+ case 'x':
+ str = xstr;
+ break;
+ case 'y':
+ str = ystrs.join(hl.tooltipSeparator);
+ break;
+ default: // same as 'xy'
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += hl.tooltipSeparator + ystrs[i];
+ }
+ break;
+
+ }
+ }
+ }
+ else {
+ var str;
+ if (hl.tooltipAxes == 'both' || hl.tooltipAxes == 'xy') {
+ str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]) + hl.tooltipSeparator + $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]);
+ }
+ else if (hl.tooltipAxes == 'yx') {
+ str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]) + hl.tooltipSeparator + $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (hl.tooltipAxes == 'x') {
+ str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (hl.tooltipAxes == 'y') {
+ str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]);
+ }
+ }
+ if ($.isFunction(hl.tooltipContentEditor)) {
+ // args str, seriesIndex, pointIndex are essential so the hook can look up
+ // extra data for the point.
+ str = hl.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
+ }
+ elem.html(str);
+ var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
+ var ms = 0;
+ var fact = 0.707;
+ if (series.markerRenderer.show == true) {
+ ms = (series.markerRenderer.size + hl.sizeAdjust)/2;
+ }
+
+ var loc = locations;
+ if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
+ loc = oppositeLocations;
+ }
+
+ switch (loc[locationIndicies[hl.tooltipLocation]]) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - ms;
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + hl.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + fact * ms;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + ms;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + hl.tooltipOffset + fact * ms;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ }
+ elem.css('left', x);
+ elem.css('top', y);
+ if (hl.fadeTooltip) {
+ // Fix for stacked up animations. Thnanks Trevor!
+ elem.stop(true,true).fadeIn(hl.tooltipFadeSpeed);
+ }
+ else {
+ elem.show();
+ }
+ elem = null;
+
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ var hl = plot.plugins.highlighter;
+ var c = plot.plugins.cursor;
+ if (hl.show) {
+ if (neighbor == null && hl.isHighlighting) {
+ var ctx = hl.highlightCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ if (hl.fadeTooltip) {
+ hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
+ }
+ else {
+ hl._tooltipElem.hide();
+ }
+ if (hl.bringSeriesToFront) {
+ plot.restorePreviousSeriesOrder();
+ }
+ hl.isHighlighting = false;
+ ctx = null;
+
+ }
+ else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
+ hl.isHighlighting = true;
+ if (hl.showMarker) {
+ draw(plot, neighbor);
+ }
+ if (hl.showTooltip && (!c || !c._zoom.started)) {
+ showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
+ }
+ if (hl.bringSeriesToFront) {
+ plot.moveSeriesToFront(neighbor.seriesIndex);
+ }
+ }
+ }
+ }
})(jQuery);
\ No newline at end of file diff --git a/libs/jqplot/plugins/jqplot.pieRenderer.js b/libs/jqplot/plugins/jqplot.pieRenderer.js index 499ae88ebb..1094395d3b 100755 --- a/libs/jqplot/plugins/jqplot.pieRenderer.js +++ b/libs/jqplot/plugins/jqplot.pieRenderer.js @@ -1,804 +1,804 @@ -/** - * jqPlot - * Pure JavaScript plotting plugin using jQuery - * - * Version: @VERSION - * - * Copyright (c) 2009-2011 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. - * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: - * chris at jqplot dot com or see http://www.jqplot.com/info.php . - * - * If you are feeling kind and generous, consider supporting the project by - * making a donation at: http://www.jqplot.com/donate.php . - * - * sprintf functions contained in jqplot.sprintf.js by Ash Searle: - * - * version 2007.04.27 - * author Ash Searle - * http://hexmen.com/blog/2007/03/printf-sprintf/ - * http://hexmen.com/js/sprintf.js - * The author (Ash Searle) has placed this code in the public domain: - * "This code is unrestricted: you are free to use it however you like." - * - */ -(function($) { - /** - * Class: $.jqplot.PieRenderer - * Plugin renderer to draw a pie chart. - * x values, if present, will be used as slice labels. - * y values give slice size. - * - * To use this renderer, you need to include the - * pie renderer plugin, for example: - * - * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script> - * - * Properties described here are passed into the $.jqplot function - * as options on the series renderer. For example: - * - * > plot2 = $.jqplot('chart2', [s1, s2], { - * > seriesDefaults: { - * > renderer:$.jqplot.PieRenderer, - * > rendererOptions:{ - * > sliceMargin: 2, - * > startAngle: -90 - * > } - * > } - * > }); - * - * A pie plot will trigger events on the plot target - * according to user interaction. All events return the event object, - * the series index, the point (slice) index, and the point data for - * the appropriate slice. - * - * 'jqplotDataMouseOver' - triggered when user mouseing over a slice. - * 'jqplotDataHighlight' - triggered the first time user mouses over a slice, - * if highlighting is enabled. - * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of - * a highlighted slice. - * 'jqplotDataClick' - triggered when the user clicks on a slice. - * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if - * the "captureRightClick" option is set to true on the plot. - */ - $.jqplot.PieRenderer = function(){ - $.jqplot.LineRenderer.call(this); - }; - - $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer(); - $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer; - - // called with scope of a series - $.jqplot.PieRenderer.prototype.init = function(options, plot) { - // Group: Properties - // - // prop: diameter - // Outer diameter of the pie, auto computed by default - this.diameter = null; - // prop: padding - // padding between the pie and plot edges, legend, etc. - this.padding = 20; - // prop: sliceMargin - // angular spacing between pie slices in degrees. - this.sliceMargin = 0; - // prop: fill - // true or false, wether to fil the slices. - this.fill = true; - // prop: shadowOffset - // offset of the shadow from the slice and offset of - // each succesive stroke of the shadow from the last. - this.shadowOffset = 2; - // prop: shadowAlpha - // transparency of the shadow (0 = transparent, 1 = opaque) - this.shadowAlpha = 0.07; - // prop: shadowDepth - // number of strokes to apply to the shadow, - // each stroke offset shadowOffset from the last. - this.shadowDepth = 5; - // prop: highlightMouseOver - // True to highlight slice when moused over. - // This must be false to enable highlightMouseDown to highlight when clicking on a slice. - this.highlightMouseOver = true; - // prop: highlightMouseDown - // True to highlight when a mouse button is pressed over a slice. - // This will be disabled if highlightMouseOver is true. - this.highlightMouseDown = false; - // prop: highlightColors - // an array of colors to use when highlighting a slice. - this.highlightColors = []; - // prop: dataLabels - // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. - // Defaults to percentage of each pie slice. - this.dataLabels = 'percent'; - // prop: showDataLabels - // true to show data labels on slices. - this.showDataLabels = false; - // prop: dataLabelFormatString - // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. - this.dataLabelFormatString = null; - // prop: dataLabelThreshold - // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed. - // This applies to all label types, not just to percentage labels. - this.dataLabelThreshold = 3; - // prop: dataLabelPositionFactor - // A Multiplier (0-1) of the pie radius which controls position of label on slice. - // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie. - this.dataLabelPositionFactor = 0.52; - // prop: dataLabelNudge - // Number of pixels to slide the label away from (+) or toward (-) the center of the pie. - this.dataLabelNudge = 2; - // prop: dataLabelCenterOn - // True to center the data label at its position. - // False to set the inside facing edge of the label at its position. - this.dataLabelCenterOn = true; - // prop: startAngle - // Angle to start drawing pie in degrees. - // According to orientation of canvas coordinate system: - // 0 = on the positive x axis - // -90 = on the positive y axis. - // 90 = on the negaive y axis. - // 180 or - 180 = on the negative x axis. - this.startAngle = 0; - this.tickRenderer = $.jqplot.PieTickRenderer; - // Used as check for conditions where pie shouldn't be drawn. - this._drawData = true; - this._type = 'pie'; - - // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver - if (options.highlightMouseDown && options.highlightMouseOver == null) { - options.highlightMouseOver = false; - } - - $.extend(true, this, options); - this._diameter = null; - this._radius = null; - // array of [start,end] angles arrays, one for each slice. In radians. - this._sliceAngles = []; - // index of the currenty highlighted point, if any - this._highlightedPoint = null; - - // set highlight colors if none provided - if (this.highlightColors.length == 0) { - for (var i=0; i<this.seriesColors.length; i++){ - var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); - var newrgb = [rgba[0], rgba[1], rgba[2]]; - var sum = newrgb[0] + newrgb[1] + newrgb[2]; - for (var j=0; j<3; j++) { - // when darkening, lowest color component can be is 60. - newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); - newrgb[j] = parseInt(newrgb[j], 10); - } - this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); - } - } - - this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); - - plot.postParseOptionsHooks.addOnce(postParseOptions); - plot.postInitHooks.addOnce(postInit); - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); - plot.eventListenerHooks.addOnce('jqplotClick', handleClick); - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); - plot.postDrawHooks.addOnce(postPlotDraw); - }; - - $.jqplot.PieRenderer.prototype.setGridData = function(plot) { - // set gridData property. This will hold angle in radians of each data point. - var stack = []; - var td = []; - var sa = this.startAngle/180*Math.PI; - var tot = 0; - // don't know if we have any valid data yet, so set plot to not draw. - this._drawData = false; - for (var i=0; i<this.data.length; i++){ - if (this.data[i][1] != 0) { - // we have data, O.K. to draw. - this._drawData = true; - } - stack.push(this.data[i][1]); - td.push([this.data[i][0]]); - if (i>0) { - stack[i] += stack[i-1]; - } - tot += this.data[i][1]; - } - var fact = Math.PI*2/stack[stack.length - 1]; - - for (var i=0; i<stack.length; i++) { - td[i][1] = stack[i] * fact; - td[i][2] = this.data[i][1]/tot; - } - this.gridData = td; - }; - - $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) { - var stack = []; - var td = []; - var tot = 0; - var sa = this.startAngle/180*Math.PI; - // don't know if we have any valid data yet, so set plot to not draw. - this._drawData = false; - for (var i=0; i<data.length; i++){ - if (this.data[i][1] != 0) { - // we have data, O.K. to draw. - this._drawData = true; - } - stack.push(data[i][1]); - td.push([data[i][0]]); - if (i>0) { - stack[i] += stack[i-1]; - } - tot += data[i][1]; - } - var fact = Math.PI*2/stack[stack.length - 1]; - - for (var i=0; i<stack.length; i++) { - td[i][1] = stack[i] * fact; - td[i][2] = data[i][1]/tot; - } - return td; - }; - - $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) { - if (this._drawData) { - var r = this._diameter / 2.0; - var fill = this.fill; - var lineWidth = this.lineWidth; - var sm = this.sliceMargin; - if (this.fill == false) { - sm += this.lineWidth; - } - ctx.save(); - ctx.translate(this._center[0], this._center[1]); - var rprime = 0; - if (Math.abs(ang2-ang1) > 0) { - rprime = parseFloat(sm) / 2.0 / Math.sin((ang2 - ang1)/2.0); - } - var transx = rprime * Math.cos((ang1 + ang2) / 2.0); - var transy = rprime * Math.sin((ang1 + ang2) / 2.0); - if ((ang2 - ang1) <= Math.PI) { - r -= rprime; - } - else { - r += rprime; - } - ctx.translate(transx, transy); - - if (isShadow) { - for (var i=0; i<this.shadowDepth; i++) { - ctx.save(); - ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); - doDraw(r); - } - } - - else { - doDraw(r); - } - } - - function doDraw (rad) { - // Fix for IE and Chrome that can't seem to draw circles correctly. - // ang2 should always be <= 2 pi since that is the way the data is converted. - if (ang2 > 6.282 + this.startAngle) { - ang2 = 6.282 + this.startAngle; - if (ang1 > ang2) { - ang1 = 6.281 + this.startAngle; - } - } - // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids - // ugly line on unfilled pies. - if (ang1 >= ang2) { - return; - } - - ctx.beginPath(); - ctx.fillStyle = color; - ctx.strokeStyle = color; - ctx.lineWidth = lineWidth; - ctx.arc(0, 0, rad, ang1, ang2, false); - ctx.lineTo(0,0); - ctx.closePath(); - - if (fill) { - ctx.fill(); - } - else { - ctx.stroke(); - } - } - - if (isShadow) { - for (var i=0; i<this.shadowDepth; i++) { - ctx.restore(); - } - } - - ctx.restore(); - }; - - // called with scope of series - $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) { - var i; - var opts = (options != undefined) ? options : {}; - // offset and direction of offset due to legend placement - var offx = 0; - var offy = 0; - var trans = 1; - var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); - if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { - var li = options.legendInfo; - switch (li.location) { - case 'nw': - offx = li.width + li.xoffset; - break; - case 'w': - offx = li.width + li.xoffset; - break; - case 'sw': - offx = li.width + li.xoffset; - break; - case 'ne': - offx = li.width + li.xoffset; - trans = -1; - break; - case 'e': - offx = li.width + li.xoffset; - trans = -1; - break; - case 'se': - offx = li.width + li.xoffset; - trans = -1; - break; - case 'n': - offy = li.height + li.yoffset; - break; - case 's': - offy = li.height + li.yoffset; - trans = -1; - break; - default: - break; - } - } - - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; - var fill = (opts.fill != undefined) ? opts.fill : this.fill; - var cw = ctx.canvas.width; - var ch = ctx.canvas.height; - var w = cw - offx - 2 * this.padding; - var h = ch - offy - 2 * this.padding; - var mindim = Math.min(w,h); - var d = mindim; - // this._diameter = this.diameter || d; - this._diameter = this.diameter || d; // - this.sliceMargin; - - var r = this._radius = this._diameter/2; - var sa = this.startAngle / 180 * Math.PI; - this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy]; - - // Fixes issue #272. Thanks hugwijst! - // reset slice angles array. - this._sliceAngles = []; - - if (this.shadow) { - var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; - for (var i=0; i<gd.length; i++) { - var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; - // Adjust ang1 and ang2 for sliceMargin - // ang1 += this.sliceMargin/180*Math.PI; - this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true); - } - - } - for (var i=0; i<gd.length; i++) { - var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; - // Adjust ang1 and ang2 for sliceMargin - // ang1 += this.sliceMargin/180*Math.PI; - var ang2 = gd[i][1] + sa; - this._sliceAngles.push([ang1, ang2]); - - this.renderer.drawSlice.call (this, ctx, ang1, ang2, colorGenerator.next(), false); - - if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) { - var fstr, avgang = (ang1+ang2)/2, label; - - if (this.dataLabels == 'label') { - fstr = this.dataLabelFormatString || '%s'; - label = $.jqplot.sprintf(fstr, gd[i][0]); - } - else if (this.dataLabels == 'value') { - fstr = this.dataLabelFormatString || '%d'; - label = $.jqplot.sprintf(fstr, this.data[i][1]); - } - else if (this.dataLabels == 'percent') { - fstr = this.dataLabelFormatString || '%d%%'; - label = $.jqplot.sprintf(fstr, gd[i][2]*100); - } - else if (this.dataLabels.constructor == Array) { - fstr = this.dataLabelFormatString || '%s'; - label = $.jqplot.sprintf(fstr, this.dataLabels[i]); - } - - var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; - - var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; - var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; - - var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem); - if (this.dataLabelCenterOn) { - x -= labelelem.width()/2; - y -= labelelem.height()/2; - } - else { - x -= labelelem.width() * Math.sin(avgang/2); - y -= labelelem.height()/2; - } - x = Math.round(x); - y = Math.round(y); - labelelem.css({left: x, top: y}); - } - } - - }; - - $.jqplot.PieAxisRenderer = function() { - $.jqplot.LinearAxisRenderer.call(this); - }; - - $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); - $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer; - - - // There are no traditional axes on a pie chart. We just need to provide - // dummy objects with properties so the plot will render. - // called with scope of axis object. - $.jqplot.PieAxisRenderer.prototype.init = function(options){ - // - this.tickRenderer = $.jqplot.PieTickRenderer; - $.extend(true, this, options); - // I don't think I'm going to need _dataBounds here. - // have to go Axis scaling in a way to fit chart onto plot area - // and provide u2p and p2u functionality for mouse cursor, etc. - // for convienence set _dataBounds to 0 and 100 and - // set min/max to 0 and 100. - this._dataBounds = {min:0, max:100}; - this.min = 0; - this.max = 100; - this.showTicks = false; - this.ticks = []; - this.showMark = false; - this.show = false; - }; - - - - - $.jqplot.PieLegendRenderer = function(){ - $.jqplot.TableLegendRenderer.call(this); - }; - - $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); - $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer; - - /** - * Class: $.jqplot.PieLegendRenderer - * Legend Renderer specific to pie plots. Set by default - * when user creates a pie plot. - */ - $.jqplot.PieLegendRenderer.prototype.init = function(options) { - // Group: Properties - // - // prop: numberRows - // Maximum number of rows in the legend. 0 or null for unlimited. - this.numberRows = null; - // prop: numberColumns - // Maximum number of columns in the legend. 0 or null for unlimited. - this.numberColumns = null; - $.extend(true, this, options); - }; - - // called with context of legend - $.jqplot.PieLegendRenderer.prototype.draw = function() { - var legend = this; - if (this.show) { - var series = this._series; - var ss = 'position:absolute;'; - ss += (this.background) ? 'background:'+this.background+';' : ''; - ss += (this.border) ? 'border:'+this.border+';' : ''; - ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; - ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; - ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; - ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; - ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; - ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; - ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; - this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); - // Pie charts legends don't go by number of series, but by number of data points - // in the series. Refactor things here for that. - - var pad = false, - reverse = false, - nr, - nc; - var s = series[0]; - var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); - - if (s.show) { - var pd = s.data; - if (this.numberRows) { - nr = this.numberRows; - if (!this.numberColumns){ - nc = Math.ceil(pd.length/nr); - } - else{ - nc = this.numberColumns; - } - } - else if (this.numberColumns) { - nc = this.numberColumns; - nr = Math.ceil(pd.length/this.numberColumns); - } - else { - nr = pd.length; - nc = 1; - } - - var i, j, tr, td1, td2, lt, rs, color; - var idx = 0; - - for (i=0; i<nr; i++) { - if (reverse){ - tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); - } - else{ - tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); - } - for (j=0; j<nc; j++) { - if (idx < pd.length){ - lt = this.labels[idx] || pd[idx][0].toString(); - color = colorGenerator.next(); - if (!reverse){ - if (i>0){ - pad = true; - } - else{ - pad = false; - } - } - else{ - if (i == nr -1){ - pad = false; - } - else{ - pad = true; - } - } - rs = (pad) ? this.rowSpacing : '0'; - - td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ - '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ - '</div></td>'); - td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); - if (this.escapeHtml){ - td2.text(lt); - } - else { - td2.html(lt); - } - if (reverse) { - td2.prependTo(tr); - td1.prependTo(tr); - } - else { - td1.appendTo(tr); - td2.appendTo(tr); - } - pad = true; - } - idx++; - } - } - } - } - return this._elem; - }; - - $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) { - if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - plot.target.trigger('jqplotDataMouseOver', ins); - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { - plot.target.trigger('jqplotDataHighlight', ins); - highlight (plot, ins[0], ins[1]); - } - } - else if (neighbor == null) { - unhighlight (plot); - } - }; - - - // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); - - // setup default renderers for axes and legend so user doesn't have to - // called with scope of plot - function preInit(target, data, options) { - options = options || {}; - options.axesDefaults = options.axesDefaults || {}; - options.legend = options.legend || {}; - options.seriesDefaults = options.seriesDefaults || {}; - // only set these if there is a pie series - var setopts = false; - if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) { - setopts = true; - } - else if (options.series) { - for (var i=0; i < options.series.length; i++) { - if (options.series[i].renderer == $.jqplot.PieRenderer) { - setopts = true; - } - } - } - - if (setopts) { - options.axesDefaults.renderer = $.jqplot.PieAxisRenderer; - options.legend.renderer = $.jqplot.PieLegendRenderer; - options.legend.preDraw = true; - options.seriesDefaults.pointLabels = {show: false}; - } - } - - function postInit(target, data, options) { - for (var i=0; i<this.series.length; i++) { - if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) { - // don't allow mouseover and mousedown at same time. - if (this.series[i].highlightMouseOver) { - this.series[i].highlightMouseDown = false; - } - } - } - this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); - } - - // called with scope of plot - function postParseOptions(options) { - for (var i=0; i<this.series.length; i++) { - this.series[i].seriesColors = this.seriesColors; - this.series[i].colorGenerator = this.colorGenerator; - } - } - - function highlight (plot, sidx, pidx) { - var s = plot.series[sidx]; - var canvas = plot.plugins.pieRenderer.highlightCanvas; - canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); - s._highlightedPoint = pidx; - plot.plugins.pieRenderer.highlightedSeriesIndex = sidx; - s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false); - } - - function unhighlight (plot) { - var canvas = plot.plugins.pieRenderer.highlightCanvas; - canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); - for (var i=0; i<plot.series.length; i++) { - plot.series[i]._highlightedPoint = null; - } - plot.plugins.pieRenderer.highlightedSeriesIndex = null; - plot.target.trigger('jqplotDataUnhighlight'); - } - - function handleMove(ev, gridpos, datapos, neighbor, plot) { - if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - var evt1 = jQuery.Event('jqplotDataMouseOver'); - evt1.pageX = ev.pageX; - evt1.pageY = ev.pageY; - plot.target.trigger(evt1, ins); - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { - var evt = jQuery.Event('jqplotDataHighlight'); - evt.pageX = ev.pageX; - evt.pageY = ev.pageY; - plot.target.trigger(evt, ins); - highlight (plot, ins[0], ins[1]); - } - } - else if (neighbor == null) { - unhighlight (plot); - } - } - - function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { - if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { - var evt = jQuery.Event('jqplotDataHighlight'); - evt.pageX = ev.pageX; - evt.pageY = ev.pageY; - plot.target.trigger(evt, ins); - highlight (plot, ins[0], ins[1]); - } - } - else if (neighbor == null) { - unhighlight (plot); - } - } - - function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { - var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; - if (idx != null && plot.series[idx].highlightMouseDown) { - unhighlight(plot); - } - } - - function handleClick(ev, gridpos, datapos, neighbor, plot) { - if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - var evt = jQuery.Event('jqplotDataClick'); - evt.pageX = ev.pageX; - evt.pageY = ev.pageY; - plot.target.trigger(evt, ins); - } - } - - function handleRightClick(ev, gridpos, datapos, neighbor, plot) { - if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; - if (idx != null && plot.series[idx].highlightMouseDown) { - unhighlight(plot); - } - var evt = jQuery.Event('jqplotDataRightClick'); - evt.pageX = ev.pageX; - evt.pageY = ev.pageY; - plot.target.trigger(evt, ins); - } - } - - // called within context of plot - // create a canvas which we can draw on. - // insert it before the eventCanvas, so eventCanvas will still capture events. - function postPlotDraw() { - // Memory Leaks patch - if (this.plugins.pieRenderer && - this.plugins.pieRenderer.highlightCanvas) { - this.plugins.pieRenderer.highlightCanvas.resetCanvas(); - this.plugins.pieRenderer.highlightCanvas = null; - } - - this.plugins.pieRenderer = {highlightedSeriesIndex:null}; - this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); - - // do we have any data labels? if so, put highlight canvas before those - var labels = $(this.targetId+' .jqplot-data-label'); - if (labels.length) { - $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions)); - } - // else put highlight canvas before event canvas. - else { - this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions)); - } - - var hctx = this.plugins.pieRenderer.highlightCanvas.setContext(); - } - - $.jqplot.preInitHooks.push(preInit); - - $.jqplot.PieTickRenderer = function() { - $.jqplot.AxisTickRenderer.call(this); - }; - - $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); - $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer; - -})(jQuery); - +/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.PieRenderer
+ * Plugin renderer to draw a pie chart.
+ * x values, if present, will be used as slice labels.
+ * y values give slice size.
+ *
+ * To use this renderer, you need to include the
+ * pie renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.PieRenderer,
+ * > rendererOptions:{
+ * > sliceMargin: 2,
+ * > startAngle: -90
+ * > }
+ * > }
+ * > });
+ *
+ * A pie plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (slice) index, and the point data for
+ * the appropriate slice.
+ *
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted slice.
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.PieRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
+
+ // called with scope of a series
+ $.jqplot.PieRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the pie, auto computed by default
+ this.diameter = null;
+ // prop: padding
+ // padding between the pie and plot edges, legend, etc.
+ this.padding = 20;
+ // prop: sliceMargin
+ // angular spacing between pie slices in degrees.
+ this.sliceMargin = 0;
+ // prop: fill
+ // true or false, wether to fil the slices.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ // prop: dataLabelPositionFactor
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
+ this.dataLabelPositionFactor = 0.52;
+ // prop: dataLabelNudge
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
+ this.dataLabelNudge = 2;
+ // prop: dataLabelCenterOn
+ // True to center the data label at its position.
+ // False to set the inside facing edge of the label at its position.
+ this.dataLabelCenterOn = true;
+ // prop: startAngle
+ // Angle to start drawing pie in degrees.
+ // According to orientation of canvas coordinate system:
+ // 0 = on the positive x axis
+ // -90 = on the positive y axis.
+ // 90 = on the negaive y axis.
+ // 180 or - 180 = on the negative x axis.
+ this.startAngle = 0;
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ // Used as check for conditions where pie shouldn't be drawn.
+ this._drawData = true;
+ this._type = 'pie';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+ this._diameter = null;
+ this._radius = null;
+ // array of [start,end] angles arrays, one for each slice. In radians.
+ this._sliceAngles = [];
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ };
+
+ $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle/180*Math.PI;
+ var tot = 0;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<this.data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += this.data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = this.data[i][1]/tot;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var tot = 0;
+ var sa = this.startAngle/180*Math.PI;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = data[i][1]/tot;
+ }
+ return td;
+ };
+
+ $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
+ if (this._drawData) {
+ var r = this._diameter / 2.0;
+ var fill = this.fill;
+ var lineWidth = this.lineWidth;
+ var sm = this.sliceMargin;
+ if (this.fill == false) {
+ sm += this.lineWidth;
+ }
+ ctx.save();
+ ctx.translate(this._center[0], this._center[1]);
+ var rprime = 0;
+ if (Math.abs(ang2-ang1) > 0) {
+ rprime = parseFloat(sm) / 2.0 / Math.sin((ang2 - ang1)/2.0);
+ }
+ var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
+ var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
+ if ((ang2 - ang1) <= Math.PI) {
+ r -= rprime;
+ }
+ else {
+ r += rprime;
+ }
+ ctx.translate(transx, transy);
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw(r);
+ }
+ }
+
+ else {
+ doDraw(r);
+ }
+ }
+
+ function doDraw (rad) {
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
+ if (ang2 > 6.282 + this.startAngle) {
+ ang2 = 6.282 + this.startAngle;
+ if (ang1 > ang2) {
+ ang1 = 6.281 + this.startAngle;
+ }
+ }
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
+ // ugly line on unfilled pies.
+ if (ang1 >= ang2) {
+ return;
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.arc(0, 0, rad, ang1, ang2, false);
+ ctx.lineTo(0,0);
+ ctx.closePath();
+
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ // called with scope of series
+ $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ var mindim = Math.min(w,h);
+ var d = mindim;
+ // this._diameter = this.diameter || d;
+ this._diameter = this.diameter || d; // - this.sliceMargin;
+
+ var r = this._radius = this._diameter/2;
+ var sa = this.startAngle / 180 * Math.PI;
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
+
+ // Fixes issue #272. Thanks hugwijst!
+ // reset slice angles array.
+ this._sliceAngles = [];
+
+ if (this.shadow) {
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ // ang1 += this.sliceMargin/180*Math.PI;
+ this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
+ }
+
+ }
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ // ang1 += this.sliceMargin/180*Math.PI;
+ var ang2 = gd[i][1] + sa;
+ this._sliceAngles.push([ang1, ang2]);
+
+ this.renderer.drawSlice.call (this, ctx, ang1, ang2, colorGenerator.next(), false);
+
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
+ var fstr, avgang = (ang1+ang2)/2, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
+ }
+
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
+
+ var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
+ if (this.dataLabelCenterOn) {
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ }
+ else {
+ x -= labelelem.width() * Math.sin(avgang/2);
+ y -= labelelem.height()/2;
+ }
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+ }
+
+ };
+
+ $.jqplot.PieAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
+
+
+ // There are no traditional axes on a pie chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.PieAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+
+ $.jqplot.PieLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
+
+ /**
+ * Class: $.jqplot.PieLegendRenderer
+ * Legend Renderer specific to pie plots. Set by default
+ * when user creates a pie plot.
+ */
+ $.jqplot.PieLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.PieLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Pie charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr,
+ nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ plot.target.trigger('jqplotDataMouseOver', ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ plot.target.trigger('jqplotDataHighlight', ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ };
+
+
+ // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
+ options.legend.renderer = $.jqplot.PieLegendRenderer;
+ options.legend.preDraw = true;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = this.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.pieRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.pieRenderer &&
+ this.plugins.pieRenderer.highlightCanvas) {
+ this.plugins.pieRenderer.highlightCanvas.resetCanvas();
+ this.plugins.pieRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.pieRenderer = {highlightedSeriesIndex:null};
+ this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ // do we have any data labels? if so, put highlight canvas before those
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions));
+ }
+
+ var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.PieTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
+
+})(jQuery);
+
\ No newline at end of file |