Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial jqplot files

  • Loading branch information...
commit b8603f16b8da45be0256f966f3b763b80a273d5f 1 parent db19a1f
Marc Delisle lem9 authored
10,901 js/jqplot/jquery.jqplot.js
10,901 additions, 0 deletions not shown
899 js/jqplot/plugins/jqplot.pieRenderer.js
... ... @@ -0,0 +1,899 @@
  1 +/**
  2 + * jqPlot
  3 + * Pure JavaScript plotting plugin using jQuery
  4 + *
  5 + * Version: 1.0.0b2_r1012
  6 + *
  7 + * Copyright (c) 2009-2011 Chris Leonello
  8 + * jqPlot is currently available for use in all personal or commercial projects
  9 + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
  10 + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
  11 + * choose the license that best suits your project and use it accordingly.
  12 + *
  13 + * Although not required, the author would appreciate an email letting him
  14 + * know of any substantial use of jqPlot. You can reach the author at:
  15 + * chris at jqplot dot com or see http://www.jqplot.com/info.php .
  16 + *
  17 + * If you are feeling kind and generous, consider supporting the project by
  18 + * making a donation at: http://www.jqplot.com/donate.php .
  19 + *
  20 + * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
  21 + *
  22 + * version 2007.04.27
  23 + * author Ash Searle
  24 + * http://hexmen.com/blog/2007/03/printf-sprintf/
  25 + * http://hexmen.com/js/sprintf.js
  26 + * The author (Ash Searle) has placed this code in the public domain:
  27 + * "This code is unrestricted: you are free to use it however you like."
  28 + *
  29 + */
  30 +(function($) {
  31 + /**
  32 + * Class: $.jqplot.PieRenderer
  33 + * Plugin renderer to draw a pie chart.
  34 + * x values, if present, will be used as slice labels.
  35 + * y values give slice size.
  36 + *
  37 + * To use this renderer, you need to include the
  38 + * pie renderer plugin, for example:
  39 + *
  40 + * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
  41 + *
  42 + * Properties described here are passed into the $.jqplot function
  43 + * as options on the series renderer. For example:
  44 + *
  45 + * > plot2 = $.jqplot('chart2', [s1, s2], {
  46 + * > seriesDefaults: {
  47 + * > renderer:$.jqplot.PieRenderer,
  48 + * > rendererOptions:{
  49 + * > sliceMargin: 2,
  50 + * > startAngle: -90
  51 + * > }
  52 + * > }
  53 + * > });
  54 + *
  55 + * A pie plot will trigger events on the plot target
  56 + * according to user interaction. All events return the event object,
  57 + * the series index, the point (slice) index, and the point data for
  58 + * the appropriate slice.
  59 + *
  60 + * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
  61 + * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
  62 + * if highlighting is enabled.
  63 + * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
  64 + * a highlighted slice.
  65 + * 'jqplotDataClick' - triggered when the user clicks on a slice.
  66 + * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
  67 + * the "captureRightClick" option is set to true on the plot.
  68 + */
  69 + $.jqplot.PieRenderer = function(){
  70 + $.jqplot.LineRenderer.call(this);
  71 + };
  72 +
  73 + $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
  74 + $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
  75 +
  76 + // called with scope of a series
  77 + $.jqplot.PieRenderer.prototype.init = function(options, plot) {
  78 + // Group: Properties
  79 + //
  80 + // prop: diameter
  81 + // Outer diameter of the pie, auto computed by default
  82 + this.diameter = null;
  83 + // prop: padding
  84 + // padding between the pie and plot edges, legend, etc.
  85 + this.padding = 20;
  86 + // prop: sliceMargin
  87 + // angular spacing between pie slices in degrees.
  88 + this.sliceMargin = 0;
  89 + // prop: fill
  90 + // true or false, wether to fil the slices.
  91 + this.fill = true;
  92 + // prop: shadowOffset
  93 + // offset of the shadow from the slice and offset of
  94 + // each succesive stroke of the shadow from the last.
  95 + this.shadowOffset = 2;
  96 + // prop: shadowAlpha
  97 + // transparency of the shadow (0 = transparent, 1 = opaque)
  98 + this.shadowAlpha = 0.07;
  99 + // prop: shadowDepth
  100 + // number of strokes to apply to the shadow,
  101 + // each stroke offset shadowOffset from the last.
  102 + this.shadowDepth = 5;
  103 + // prop: highlightMouseOver
  104 + // True to highlight slice when moused over.
  105 + // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
  106 + this.highlightMouseOver = true;
  107 + // prop: highlightMouseDown
  108 + // True to highlight when a mouse button is pressed over a slice.
  109 + // This will be disabled if highlightMouseOver is true.
  110 + this.highlightMouseDown = false;
  111 + // prop: highlightColors
  112 + // an array of colors to use when highlighting a slice.
  113 + this.highlightColors = [];
  114 + // prop: dataLabels
  115 + // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
  116 + // Defaults to percentage of each pie slice.
  117 + this.dataLabels = 'percent';
  118 + // prop: showDataLabels
  119 + // true to show data labels on slices.
  120 + this.showDataLabels = false;
  121 + // prop: dataLabelFormatString
  122 + // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
  123 + this.dataLabelFormatString = null;
  124 + // prop: dataLabelThreshold
  125 + // Threshhold in percentage (0-100) of pie area, below which no label will be displayed.
  126 + // This applies to all label types, not just to percentage labels.
  127 + this.dataLabelThreshold = 3;
  128 + // prop: dataLabelPositionFactor
  129 + // A Multiplier (0-1) of the pie radius which controls position of label on slice.
  130 + // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
  131 + this.dataLabelPositionFactor = 0.52;
  132 + // prop: dataLabelNudge
  133 + // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
  134 + this.dataLabelNudge = 2;
  135 + // prop: dataLabelCenterOn
  136 + // True to center the data label at its position.
  137 + // False to set the inside facing edge of the label at its position.
  138 + this.dataLabelCenterOn = true;
  139 + // prop: startAngle
  140 + // Angle to start drawing pie in degrees.
  141 + // According to orientation of canvas coordinate system:
  142 + // 0 = on the positive x axis
  143 + // -90 = on the positive y axis.
  144 + // 90 = on the negaive y axis.
  145 + // 180 or - 180 = on the negative x axis.
  146 + this.startAngle = 0;
  147 + this.tickRenderer = $.jqplot.PieTickRenderer;
  148 + // Used as check for conditions where pie shouldn't be drawn.
  149 + this._drawData = true;
  150 + this._type = 'pie';
  151 +
  152 + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
  153 + if (options.highlightMouseDown && options.highlightMouseOver == null) {
  154 + options.highlightMouseOver = false;
  155 + }
  156 +
  157 + $.extend(true, this, options);
  158 +
  159 + if (this.sliceMargin < 0) {
  160 + this.sliceMargin = 0;
  161 + }
  162 +
  163 + this._diameter = null;
  164 + this._radius = null;
  165 + // array of [start,end] angles arrays, one for each slice. In radians.
  166 + this._sliceAngles = [];
  167 + // index of the currenty highlighted point, if any
  168 + this._highlightedPoint = null;
  169 +
  170 + // set highlight colors if none provided
  171 + if (this.highlightColors.length == 0) {
  172 + for (var i=0; i<this.seriesColors.length; i++){
  173 + var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
  174 + var newrgb = [rgba[0], rgba[1], rgba[2]];
  175 + var sum = newrgb[0] + newrgb[1] + newrgb[2];
  176 + for (var j=0; j<3; j++) {
  177 + // when darkening, lowest color component can be is 60.
  178 + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
  179 + newrgb[j] = parseInt(newrgb[j], 10);
  180 + }
  181 + this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
  182 + }
  183 + }
  184 +
  185 + this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
  186 +
  187 + plot.postParseOptionsHooks.addOnce(postParseOptions);
  188 + plot.postInitHooks.addOnce(postInit);
  189 + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
  190 + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
  191 + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
  192 + plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
  193 + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
  194 + plot.postDrawHooks.addOnce(postPlotDraw);
  195 + };
  196 +
  197 + $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
  198 + // set gridData property. This will hold angle in radians of each data point.
  199 + var stack = [];
  200 + var td = [];
  201 + var sa = this.startAngle/180*Math.PI;
  202 + var tot = 0;
  203 + // don't know if we have any valid data yet, so set plot to not draw.
  204 + this._drawData = false;
  205 + for (var i=0; i<this.data.length; i++){
  206 + if (this.data[i][1] != 0) {
  207 + // we have data, O.K. to draw.
  208 + this._drawData = true;
  209 + }
  210 + stack.push(this.data[i][1]);
  211 + td.push([this.data[i][0]]);
  212 + if (i>0) {
  213 + stack[i] += stack[i-1];
  214 + }
  215 + tot += this.data[i][1];
  216 + }
  217 + var fact = Math.PI*2/stack[stack.length - 1];
  218 +
  219 + for (var i=0; i<stack.length; i++) {
  220 + td[i][1] = stack[i] * fact;
  221 + td[i][2] = this.data[i][1]/tot;
  222 + }
  223 + this.gridData = td;
  224 + };
  225 +
  226 + $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
  227 + var stack = [];
  228 + var td = [];
  229 + var tot = 0;
  230 + var sa = this.startAngle/180*Math.PI;
  231 + // don't know if we have any valid data yet, so set plot to not draw.
  232 + this._drawData = false;
  233 + for (var i=0; i<data.length; i++){
  234 + if (this.data[i][1] != 0) {
  235 + // we have data, O.K. to draw.
  236 + this._drawData = true;
  237 + }
  238 + stack.push(data[i][1]);
  239 + td.push([data[i][0]]);
  240 + if (i>0) {
  241 + stack[i] += stack[i-1];
  242 + }
  243 + tot += data[i][1];
  244 + }
  245 + var fact = Math.PI*2/stack[stack.length - 1];
  246 +
  247 + for (var i=0; i<stack.length; i++) {
  248 + td[i][1] = stack[i] * fact;
  249 + td[i][2] = data[i][1]/tot;
  250 + }
  251 + return td;
  252 + };
  253 +
  254 + function calcRadiusAdjustment(ang) {
  255 + return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0);
  256 + }
  257 +
  258 + function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
  259 + var rprime = 0;
  260 + var ang = ang2 - ang1;
  261 + var absang = Math.abs(ang);
  262 + var sm = sliceMargin;
  263 + if (fill == false) {
  264 + sm += lineWidth;
  265 + }
  266 +
  267 + if (sm > 0 && absang > 0.01 && absang < 6.282) {
  268 + rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang);
  269 + }
  270 +
  271 + return rprime;
  272 + }
  273 +
  274 + $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
  275 + if (this._drawData) {
  276 + var r = this._radius;
  277 + var fill = this.fill;
  278 + var lineWidth = this.lineWidth;
  279 + var sm = this.sliceMargin;
  280 + if (this.fill == false) {
  281 + sm += this.lineWidth;
  282 + }
  283 + ctx.save();
  284 + ctx.translate(this._center[0], this._center[1]);
  285 +
  286 + var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
  287 +
  288 + var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
  289 + var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
  290 +
  291 + if ((ang2 - ang1) <= Math.PI) {
  292 + r -= rprime;
  293 + }
  294 + else {
  295 + r += rprime;
  296 + }
  297 +
  298 + ctx.translate(transx, transy);
  299 +
  300 + if (isShadow) {
  301 + for (var i=0, l=this.shadowDepth; i<l; i++) {
  302 + ctx.save();
  303 + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
  304 + doDraw(r);
  305 + }
  306 + for (var i=0, l=this.shadowDepth; i<l; i++) {
  307 + ctx.restore();
  308 + }
  309 + }
  310 +
  311 + else {
  312 + doDraw(r);
  313 + }
  314 + ctx.restore();
  315 + }
  316 +
  317 + function doDraw (rad) {
  318 + // Fix for IE and Chrome that can't seem to draw circles correctly.
  319 + // ang2 should always be <= 2 pi since that is the way the data is converted.
  320 + // 2Pi = 6.2831853, Pi = 3.1415927
  321 + if (ang2 > 6.282 + this.startAngle) {
  322 + ang2 = 6.282 + this.startAngle;
  323 + if (ang1 > ang2) {
  324 + ang1 = 6.281 + this.startAngle;
  325 + }
  326 + }
  327 + // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
  328 + // ugly line on unfilled pies.
  329 + if (ang1 >= ang2) {
  330 + return;
  331 + }
  332 +
  333 + ctx.beginPath();
  334 + ctx.fillStyle = color;
  335 + ctx.strokeStyle = color;
  336 + ctx.lineWidth = lineWidth;
  337 + ctx.arc(0, 0, rad, ang1, ang2, false);
  338 + ctx.lineTo(0,0);
  339 + ctx.closePath();
  340 +
  341 + if (fill) {
  342 + ctx.fill();
  343 + }
  344 + else {
  345 + ctx.stroke();
  346 + }
  347 + }
  348 + };
  349 +
  350 + // called with scope of series
  351 + $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
  352 + var i;
  353 + var opts = (options != undefined) ? options : {};
  354 + // offset and direction of offset due to legend placement
  355 + var offx = 0;
  356 + var offy = 0;
  357 + var trans = 1;
  358 + var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
  359 + if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
  360 + var li = options.legendInfo;
  361 + switch (li.location) {
  362 + case 'nw':
  363 + offx = li.width + li.xoffset;
  364 + break;
  365 + case 'w':
  366 + offx = li.width + li.xoffset;
  367 + break;
  368 + case 'sw':
  369 + offx = li.width + li.xoffset;
  370 + break;
  371 + case 'ne':
  372 + offx = li.width + li.xoffset;
  373 + trans = -1;
  374 + break;
  375 + case 'e':
  376 + offx = li.width + li.xoffset;
  377 + trans = -1;
  378 + break;
  379 + case 'se':
  380 + offx = li.width + li.xoffset;
  381 + trans = -1;
  382 + break;
  383 + case 'n':
  384 + offy = li.height + li.yoffset;
  385 + break;
  386 + case 's':
  387 + offy = li.height + li.yoffset;
  388 + trans = -1;
  389 + break;
  390 + default:
  391 + break;
  392 + }
  393 + }
  394 +
  395 + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
  396 + var fill = (opts.fill != undefined) ? opts.fill : this.fill;
  397 + var cw = ctx.canvas.width;
  398 + var ch = ctx.canvas.height;
  399 + var w = cw - offx - 2 * this.padding;
  400 + var h = ch - offy - 2 * this.padding;
  401 + var mindim = Math.min(w,h);
  402 + var d = mindim;
  403 +
  404 + // Fixes issue #272. Thanks hugwijst!
  405 + // reset slice angles array.
  406 + this._sliceAngles = [];
  407 +
  408 + var sm = this.sliceMargin;
  409 + if (this.fill == false) {
  410 + sm += this.lineWidth;
  411 + }
  412 +
  413 + var rprime;
  414 + var maxrprime = 0;
  415 +
  416 + var ang, ang1, ang2, shadowColor;
  417 + var sa = this.startAngle / 180 * Math.PI;
  418 +
  419 + // have to pre-draw shadows, so loop throgh here and calculate some values also.
  420 + for (var i=0, l=gd.length; i<l; i++) {
  421 + ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
  422 + ang2 = gd[i][1] + sa;
  423 +
  424 + this._sliceAngles.push([ang1, ang2]);
  425 +
  426 + rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
  427 +
  428 + if (Math.abs(ang2-ang1) > Math.PI) {
  429 + maxrprime = Math.max(rprime, maxrprime);
  430 + }
  431 + }
  432 +
  433 + if (this.diameter != null && this.diameter > 0) {
  434 + this._diameter = this.diameter - 2*maxrprime;
  435 + }
  436 + else {
  437 + this._diameter = d - 2*maxrprime;
  438 + }
  439 +
  440 + // Need to check for undersized pie. This can happen if
  441 + // plot area too small and legend is too big.
  442 + if (this._diameter < 6) {
  443 + $.jqplot.log('Diameter of pie too small, not rendering.');
  444 + return;
  445 + }
  446 +
  447 + var r = this._radius = this._diameter/2;
  448 +
  449 + this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)];
  450 +
  451 + if (this.shadow) {
  452 + for (var i=0, l=gd.length; i<l; i++) {
  453 + shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
  454 + this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true);
  455 + }
  456 + }
  457 +
  458 + for (var i=0; i<gd.length; i++) {
  459 +
  460 + this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false);
  461 +
  462 + if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
  463 + var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label;
  464 +
  465 + if (this.dataLabels == 'label') {
  466 + fstr = this.dataLabelFormatString || '%s';
  467 + label = $.jqplot.sprintf(fstr, gd[i][0]);
  468 + }
  469 + else if (this.dataLabels == 'value') {
  470 + fstr = this.dataLabelFormatString || '%d';
  471 + label = $.jqplot.sprintf(fstr, this.data[i][1]);
  472 + }
  473 + else if (this.dataLabels == 'percent') {
  474 + fstr = this.dataLabelFormatString || '%d%%';
  475 + label = $.jqplot.sprintf(fstr, gd[i][2]*100);
  476 + }
  477 + else if (this.dataLabels.constructor == Array) {
  478 + fstr = this.dataLabelFormatString || '%s';
  479 + label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
  480 + }
  481 +
  482 + var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
  483 +
  484 + var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
  485 + var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
  486 +
  487 + var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
  488 + if (this.dataLabelCenterOn) {
  489 + x -= labelelem.width()/2;
  490 + y -= labelelem.height()/2;
  491 + }
  492 + else {
  493 + x -= labelelem.width() * Math.sin(avgang/2);
  494 + y -= labelelem.height()/2;
  495 + }
  496 + x = Math.round(x);
  497 + y = Math.round(y);
  498 + labelelem.css({left: x, top: y});
  499 + }
  500 + }
  501 + };
  502 +
  503 + $.jqplot.PieAxisRenderer = function() {
  504 + $.jqplot.LinearAxisRenderer.call(this);
  505 + };
  506 +
  507 + $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
  508 + $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
  509 +
  510 +
  511 + // There are no traditional axes on a pie chart. We just need to provide
  512 + // dummy objects with properties so the plot will render.
  513 + // called with scope of axis object.
  514 + $.jqplot.PieAxisRenderer.prototype.init = function(options){
  515 + //
  516 + this.tickRenderer = $.jqplot.PieTickRenderer;
  517 + $.extend(true, this, options);
  518 + // I don't think I'm going to need _dataBounds here.
  519 + // have to go Axis scaling in a way to fit chart onto plot area
  520 + // and provide u2p and p2u functionality for mouse cursor, etc.
  521 + // for convienence set _dataBounds to 0 and 100 and
  522 + // set min/max to 0 and 100.
  523 + this._dataBounds = {min:0, max:100};
  524 + this.min = 0;
  525 + this.max = 100;
  526 + this.showTicks = false;
  527 + this.ticks = [];
  528 + this.showMark = false;
  529 + this.show = false;
  530 + };
  531 +
  532 +
  533 +
  534 +
  535 + $.jqplot.PieLegendRenderer = function(){
  536 + $.jqplot.TableLegendRenderer.call(this);
  537 + };
  538 +
  539 + $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
  540 + $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
  541 +
  542 + /**
  543 + * Class: $.jqplot.PieLegendRenderer
  544 + * Legend Renderer specific to pie plots. Set by default
  545 + * when user creates a pie plot.
  546 + */
  547 + $.jqplot.PieLegendRenderer.prototype.init = function(options) {
  548 + // Group: Properties
  549 + //
  550 + // prop: numberRows
  551 + // Maximum number of rows in the legend. 0 or null for unlimited.
  552 + this.numberRows = null;
  553 + // prop: numberColumns
  554 + // Maximum number of columns in the legend. 0 or null for unlimited.
  555 + this.numberColumns = null;
  556 + $.extend(true, this, options);
  557 + };
  558 +
  559 + // called with context of legend
  560 + $.jqplot.PieLegendRenderer.prototype.draw = function() {
  561 + var legend = this;
  562 + if (this.show) {
  563 + var series = this._series;
  564 +
  565 +
  566 + this._elem = $(document.createElement('table'));
  567 + this._elem.addClass('jqplot-table-legend');
  568 +
  569 + var ss = {position:'absolute'};
  570 + if (this.background) {
  571 + ss['background'] = this.background;
  572 + }
  573 + if (this.border) {
  574 + ss['border'] = this.border;
  575 + }
  576 + if (this.fontSize) {
  577 + ss['fontSize'] = this.fontSize;
  578 + }
  579 + if (this.fontFamily) {
  580 + ss['fontFamily'] = this.fontFamily;
  581 + }
  582 + if (this.textColor) {
  583 + ss['textColor'] = this.textColor;
  584 + }
  585 + if (this.marginTop != null) {
  586 + ss['marginTop'] = this.marginTop;
  587 + }
  588 + if (this.marginBottom != null) {
  589 + ss['marginBottom'] = this.marginBottom;
  590 + }
  591 + if (this.marginLeft != null) {
  592 + ss['marginLeft'] = this.marginLeft;
  593 + }
  594 + if (this.marginRight != null) {
  595 + ss['marginRight'] = this.marginRight;
  596 + }
  597 +
  598 + this._elem.css(ss);
  599 +
  600 + // Pie charts legends don't go by number of series, but by number of data points
  601 + // in the series. Refactor things here for that.
  602 +
  603 + var pad = false,
  604 + reverse = false,
  605 + nr,
  606 + nc;
  607 + var s = series[0];
  608 + var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
  609 +
  610 + if (s.show) {
  611 + var pd = s.data;
  612 + if (this.numberRows) {
  613 + nr = this.numberRows;
  614 + if (!this.numberColumns){
  615 + nc = Math.ceil(pd.length/nr);
  616 + }
  617 + else{
  618 + nc = this.numberColumns;
  619 + }
  620 + }
  621 + else if (this.numberColumns) {
  622 + nc = this.numberColumns;
  623 + nr = Math.ceil(pd.length/this.numberColumns);
  624 + }
  625 + else {
  626 + nr = pd.length;
  627 + nc = 1;
  628 + }
  629 +
  630 + var i, j;
  631 + var tr, td1, td2;
  632 + var lt, rs, color;
  633 + var idx = 0;
  634 + var div0, div1;
  635 +
  636 + for (i=0; i<nr; i++) {
  637 + tr = $(document.createElement('tr'));
  638 + tr.addClass('jqplot-table-legend');
  639 +
  640 + if (reverse){
  641 + tr.prependTo(this._elem);
  642 + }
  643 +
  644 + else{
  645 + tr.appendTo(this._elem);
  646 + }
  647 +
  648 + for (j=0; j<nc; j++) {
  649 + if (idx < pd.length){
  650 + lt = this.labels[idx] || pd[idx][0].toString();
  651 + color = colorGenerator.next();
  652 + if (!reverse){
  653 + if (i>0){
  654 + pad = true;
  655 + }
  656 + else{
  657 + pad = false;
  658 + }
  659 + }
  660 + else{
  661 + if (i == nr -1){
  662 + pad = false;
  663 + }
  664 + else{
  665 + pad = true;
  666 + }
  667 + }
  668 + rs = (pad) ? this.rowSpacing : '0';
  669 +
  670 +
  671 +
  672 + td1 = $(document.createElement('td'));
  673 + td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
  674 + td1.css({textAlign: 'center', paddingTop: rs});
  675 +
  676 + div0 = $(document.createElement('div'));
  677 + div0.addClass('jqplot-table-legend-swatch-outline');
  678 + div1 = $(document.createElement('div'));
  679 + div1.addClass('jqplot-table-legend-swatch');
  680 + div1.css({backgroundColor: color, borderColor: color});
  681 + td1.append(div0.append(div1));
  682 +
  683 + td2 = $(document.createElement('td'));
  684 + td2.addClass('jqplot-table-legend jqplot-table-legend-label');
  685 + td2.css('paddingTop', rs);
  686 +
  687 + if (this.escapeHtml){
  688 + td2.text(lt);
  689 + }
  690 + else {
  691 + td2.html(lt);
  692 + }
  693 + if (reverse) {
  694 + td2.prependTo(tr);
  695 + td1.prependTo(tr);
  696 + }
  697 + else {
  698 + td1.appendTo(tr);
  699 + td2.appendTo(tr);
  700 + }
  701 + pad = true;
  702 + }
  703 + idx++;
  704 + }
  705 + }
  706 + }
  707 + }
  708 + return this._elem;
  709 + };
  710 +
  711 + $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
  712 + if (neighbor) {
  713 + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  714 + plot.target.trigger('jqplotDataMouseOver', ins);
  715 + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
  716 + plot.target.trigger('jqplotDataHighlight', ins);
  717 + highlight (plot, ins[0], ins[1]);
  718 + }
  719 + }
  720 + else if (neighbor == null) {
  721 + unhighlight (plot);
  722 + }
  723 + };
  724 +
  725 +
  726 + // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
  727 +
  728 + // setup default renderers for axes and legend so user doesn't have to
  729 + // called with scope of plot
  730 + function preInit(target, data, options) {
  731 + options = options || {};
  732 + options.axesDefaults = options.axesDefaults || {};
  733 + options.legend = options.legend || {};
  734 + options.seriesDefaults = options.seriesDefaults || {};
  735 + // only set these if there is a pie series
  736 + var setopts = false;
  737 + if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
  738 + setopts = true;
  739 + }
  740 + else if (options.series) {
  741 + for (var i=0; i < options.series.length; i++) {
  742 + if (options.series[i].renderer == $.jqplot.PieRenderer) {
  743 + setopts = true;
  744 + }
  745 + }
  746 + }
  747 +
  748 + if (setopts) {
  749 + options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
  750 + options.legend.renderer = $.jqplot.PieLegendRenderer;
  751 + options.legend.preDraw = true;
  752 + options.seriesDefaults.pointLabels = {show: false};
  753 + }
  754 + }
  755 +
  756 + function postInit(target, data, options) {
  757 + for (var i=0; i<this.series.length; i++) {
  758 + if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
  759 + // don't allow mouseover and mousedown at same time.
  760 + if (this.series[i].highlightMouseOver) {
  761 + this.series[i].highlightMouseDown = false;
  762 + }
  763 + }
  764 + }
  765 + }
  766 +
  767 + // called with scope of plot
  768 + function postParseOptions(options) {
  769 + for (var i=0; i<this.series.length; i++) {
  770 + this.series[i].seriesColors = this.seriesColors;
  771 + this.series[i].colorGenerator = $.jqplot.colorGenerator;
  772 + }
  773 + }
  774 +
  775 + function highlight (plot, sidx, pidx) {
  776 + var s = plot.series[sidx];
  777 + var canvas = plot.plugins.pieRenderer.highlightCanvas;
  778 + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
  779 + s._highlightedPoint = pidx;
  780 + plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
  781 + s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
  782 + }
  783 +
  784 + function unhighlight (plot) {
  785 + var canvas = plot.plugins.pieRenderer.highlightCanvas;
  786 + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
  787 + for (var i=0; i<plot.series.length; i++) {
  788 + plot.series[i]._highlightedPoint = null;
  789 + }
  790 + plot.plugins.pieRenderer.highlightedSeriesIndex = null;
  791 + plot.target.trigger('jqplotDataUnhighlight');
  792 + }
  793 +
  794 + function handleMove(ev, gridpos, datapos, neighbor, plot) {
  795 + if (neighbor) {
  796 + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  797 + var evt1 = jQuery.Event('jqplotDataMouseOver');
  798 + evt1.pageX = ev.pageX;
  799 + evt1.pageY = ev.pageY;
  800 + plot.target.trigger(evt1, ins);
  801 + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
  802 + var evt = jQuery.Event('jqplotDataHighlight');
  803 + evt.pageX = ev.pageX;
  804 + evt.pageY = ev.pageY;
  805 + plot.target.trigger(evt, ins);
  806 + highlight (plot, ins[0], ins[1]);
  807 + }
  808 + }
  809 + else if (neighbor == null) {
  810 + unhighlight (plot);
  811 + }
  812 + }
  813 +
  814 + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
  815 + if (neighbor) {
  816 + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  817 + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
  818 + var evt = jQuery.Event('jqplotDataHighlight');
  819 + evt.pageX = ev.pageX;
  820 + evt.pageY = ev.pageY;
  821 + plot.target.trigger(evt, ins);
  822 + highlight (plot, ins[0], ins[1]);
  823 + }
  824 + }
  825 + else if (neighbor == null) {
  826 + unhighlight (plot);
  827 + }
  828 + }
  829 +
  830 + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
  831 + var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
  832 + if (idx != null && plot.series[idx].highlightMouseDown) {
  833 + unhighlight(plot);
  834 + }
  835 + }
  836 +
  837 + function handleClick(ev, gridpos, datapos, neighbor, plot) {
  838 + if (neighbor) {
  839 + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  840 + var evt = jQuery.Event('jqplotDataClick');
  841 + evt.pageX = ev.pageX;
  842 + evt.pageY = ev.pageY;
  843 + plot.target.trigger(evt, ins);
  844 + }
  845 + }
  846 +
  847 + function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
  848 + if (neighbor) {
  849 + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  850 + var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
  851 + if (idx != null && plot.series[idx].highlightMouseDown) {
  852 + unhighlight(plot);
  853 + }
  854 + var evt = jQuery.Event('jqplotDataRightClick');
  855 + evt.pageX = ev.pageX;
  856 + evt.pageY = ev.pageY;
  857 + plot.target.trigger(evt, ins);
  858 + }
  859 + }
  860 +
  861 + // called within context of plot
  862 + // create a canvas which we can draw on.
  863 + // insert it before the eventCanvas, so eventCanvas will still capture events.
  864 + function postPlotDraw() {
  865 + // Memory Leaks patch
  866 + if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) {
  867 + this.plugins.pieRenderer.highlightCanvas.resetCanvas();
  868 + this.plugins.pieRenderer.highlightCanvas = null;
  869 + }
  870 +
  871 + this.plugins.pieRenderer = {highlightedSeriesIndex:null};
  872 + this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
  873 +
  874 + // do we have any data labels? if so, put highlight canvas before those
  875 + var labels = $(this.targetId+' .jqplot-data-label');
  876 + if (labels.length) {
  877 + $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
  878 + }
  879 + // else put highlight canvas before event canvas.
  880 + else {
  881 + this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
  882 + }
  883 +
  884 + var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
  885 + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
  886 + }
  887 +
  888 + $.jqplot.preInitHooks.push(preInit);
  889 +
  890 + $.jqplot.PieTickRenderer = function() {
  891 + $.jqplot.AxisTickRenderer.call(this);
  892 + };
  893 +
  894 + $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
  895 + $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
  896 +
  897 +})(jQuery);
  898 +
  899 +
262 themes/original/css/theme_right.css.php
@@ -3042,3 +3042,265 @@
3042 3042 .ui-dialog fieldset legend a {
3043 3043 color: #0000FF;
3044 3044 }
  3045 +
  3046 +/* jqPlot */
  3047 +
  3048 +/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/
  3049 +.jqplot-target {
  3050 + position: relative;
  3051 + color: #666666;
  3052 + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  3053 + font-size: 1em;
  3054 +/* height: 300px;
  3055 + width: 400px;*/
  3056 +}
  3057 +
  3058 +/*rules applied to all axes*/
  3059 +.jqplot-axis {
  3060 + font-size: 0.75em;
  3061 +}
  3062 +
  3063 +.jqplot-xaxis {
  3064 + margin-top: 10px;
  3065 +}
  3066 +
  3067 +.jqplot-x2axis {
  3068 + margin-bottom: 10px;
  3069 +}
  3070 +
  3071 +.jqplot-yaxis {
  3072 + margin-right: 10px;
  3073 +}
  3074 +
  3075 +.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis {
  3076 + margin-left: 10px;
  3077 + margin-right: 10px;
  3078 +}
  3079 +
  3080 +/*rules applied to all axis tick divs*/
  3081 +.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick {
  3082 + position: absolute;
  3083 + white-space: pre;
  3084 +}
  3085 +
  3086 +
  3087 +.jqplot-xaxis-tick {
  3088 + top: 0px;
  3089 + /* initial position untill tick is drawn in proper place */
  3090 + left: 15px;
  3091 +/* padding-top: 10px;*/
  3092 + vertical-align: top;
  3093 +}
  3094 +
  3095 +.jqplot-x2axis-tick {
  3096 + bottom: 0px;
  3097 + /* initial position untill tick is drawn in proper place */
  3098 + left: 15px;
  3099 +/* padding-bottom: 10px;*/
  3100 + vertical-align: bottom;
  3101 +}
  3102 +
  3103 +.jqplot-yaxis-tick {
  3104 + right: 0px;
  3105 + /* initial position untill tick is drawn in proper place */
  3106 + top: 15px;
  3107 +/* padding-right: 10px;*/
  3108 + text-align: right;
  3109 +}
  3110 +
  3111 +.jqplot-yaxis-tick.jqplot-breakTick {
  3112 + right: -20px;
  3113 + margin-right: 0px;
  3114 + padding:1px 5px 1px 5px;
  3115 +/* background-color: white;*/
  3116 + z-index: 2;
  3117 + font-size: 1.5em;
  3118 +}
  3119 +
  3120 +.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick {
  3121 + left: 0px;
  3122 + /* initial position untill tick is drawn in proper place */
  3123 + top: 15px;
  3124 +/* padding-left: 10px;*/
  3125 +/* padding-right: 15px;*/
  3126 + text-align: left;
  3127 +}
  3128 +
  3129 +.jqplot-yMidAxis-tick {
  3130 + text-align: center;
  3131 + white-space: nowrap;
  3132 +}
  3133 +
  3134 +.jqplot-xaxis-label {
  3135 + margin-top: 10px;
  3136 + font-size: 11pt;
  3137 + position: absolute;
  3138 +}
  3139 +
  3140 +.jqplot-x2axis-label {
  3141 + margin-bottom: 10px;
  3142 + font-size: 11pt;
  3143 + position: absolute;
  3144 +}
  3145 +
  3146 +.jqplot-yaxis-label {
  3147 + margin-right: 10px;
  3148 +/* text-align: center;*/
  3149 + font-size: 11pt;
  3150 + position: absolute;
  3151 +}
  3152 +
  3153 +.jqplot-yMidAxis-label {
  3154 + font-size: 11pt;
  3155 + position: absolute;
  3156 +}
  3157 +
  3158 +.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
  3159 +/* text-align: center;*/
  3160 + font-size: 11pt;
  3161 + margin-left: 10px;
  3162 + position: absolute;
  3163 +}
  3164 +
  3165 +.jqplot-meterGauge-tick {
  3166 + font-size: 0.75em;
  3167 + color: #999999;
  3168 +}
  3169 +
  3170 +.jqplot-meterGauge-label {
  3171 + font-size: 1em;
  3172 + color: #999999;
  3173 +}
  3174 +
  3175 +table.jqplot-table-legend {
  3176 + margin-top: 12px;
  3177 + margin-bottom: 12px;
  3178 + margin-left: 12px;
  3179 + margin-right: 12px;
  3180 +}
  3181 +
  3182 +table.jqplot-table-legend, table.jqplot-cursor-legend {
  3183 + background-color: rgba(255,255,255,0.6);
  3184 + border: 1px solid #cccccc;
  3185 + position: absolute;
  3186 + font-size: 0.75em;
  3187 +}
  3188 +
  3189 +td.jqplot-table-legend {
  3190 + vertical-align:middle;
  3191 +}
  3192 +
  3193 +/*
  3194 +These rules could be used instead of assigning
  3195 +element styles and relying on js object properties.
  3196 +*/
  3197 +
  3198 +/*
  3199 +td.jqplot-table-legend-swatch {
  3200 + padding-top: 0.5em;
  3201 + text-align: center;
  3202 +}
  3203 +
  3204 +tr.jqplot-table-legend:first td.jqplot-table-legend-swatch {
  3205 + padding-top: 0px;
  3206 +}
  3207 +*/
  3208 +
  3209 +td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active {
  3210 + cursor: pointer;
  3211 +}
  3212 +
  3213 +.jqplot-table-legend .jqplot-series-hidden {
  3214 + text-decoration: line-through;
  3215 +}
  3216 +
  3217 +div.jqplot-table-legend-swatch-outline {
  3218 + border: 1px solid #cccccc;
  3219 + padding:1px;
  3220 +}
  3221 +
  3222 +div.jqplot-table-legend-swatch {
  3223 + width:0px;
  3224 + height:0px;
  3225 + border-top-width: 5px;
  3226 + border-bottom-width: 5px;
  3227 + border-left-width: 6px;
  3228 + border-right-width: 6px;
  3229 + border-top-style: solid;
  3230 + border-bottom-style: solid;
  3231 + border-left-style: solid;
  3232 + border-right-style: solid;
  3233 +}
  3234 +
  3235 +.jqplot-title {
  3236 + top: 0px;
  3237 + left: 0px;
  3238 + padding-bottom: 0.5em;
  3239 + font-size: 1.2em;
  3240 +}
  3241 +
  3242 +table.jqplot-cursor-tooltip {
  3243 + border: 1px solid #cccccc;
  3244 + font-size: 0.75em;
  3245 +}
  3246 +
  3247 +
  3248 +.jqplot-cursor-tooltip {
  3249 + border: 1px solid #cccccc;
  3250 + font-size: 0.75em;
  3251 + white-space: nowrap;
  3252 + background: rgba(208,208,208,0.5);
  3253 + padding: 1px;
  3254 +}
  3255 +
  3256 +.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
  3257 + border: 1px solid #cccccc;
  3258 + font-size: 0.75em;
  3259 + white-space: nowrap;
  3260 + background: rgba(208,208,208,0.5);
  3261 + padding: 1px;
  3262 +}
  3263 +
  3264 +.jqplot-point-label {
  3265 + font-size: 0.75em;
  3266 + z-index: 2;
  3267 +}
  3268 +
  3269 +td.jqplot-cursor-legend-swatch {
  3270 + vertical-align: middle;
  3271 + text-align: center;
  3272 +}
  3273 +
  3274 +div.jqplot-cursor-legend-swatch {