[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/libraries/jquery/jqplot/plugins/ -> jqplot.funnelRenderer.js (source)

   1  /**
   2   * jqPlot
   3   * Pure JavaScript plotting plugin using jQuery
   4   *
   5   * Version: 1.0.2
   6   * Revision: 1108
   7   *
   8   * Copyright (c) 2009-2011 Chris Leonello
   9   * jqPlot is currently available for use in all personal or commercial projects 
  10   * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 
  11   * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 
  12   * choose the license that best suits your project and use it accordingly. 
  13   *
  14   * Although not required, the author would appreciate an email letting him 
  15   * know of any substantial use of jqPlot.  You can reach the author at: 
  16   * chris at jqplot dot com or see http://www.jqplot.com/info.php .
  17   *
  18   * If you are feeling kind and generous, consider supporting the project by
  19   * making a donation at: http://www.jqplot.com/donate.php .
  20   *
  21   * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
  22   *
  23   *     version 2007.04.27
  24   *     author Ash Searle
  25   *     http://hexmen.com/blog/2007/03/printf-sprintf/
  26   *     http://hexmen.com/js/sprintf.js
  27   *     The author (Ash Searle) has placed this code in the public domain:
  28   *     "This code is unrestricted: you are free to use it however you like."
  29   * 
  30   */
  31  (function($) {
  32      /**
  33       * Class: $.jqplot.FunnelRenderer
  34       * Plugin renderer to draw a funnel chart.
  35       * x values, if present, will be used as labels.
  36       * y values give area size.
  37       * 
  38       * Funnel charts will draw a single series
  39       * only.
  40       * 
  41       * To use this renderer, you need to include the 
  42       * funnel renderer plugin, for example:
  43       * 
  44       * > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script>
  45       * 
  46       * Properties described here are passed into the $.jqplot function
  47       * as options on the series renderer.  For example:
  48       * 
  49       * > plot2 = $.jqplot('chart2', [s1, s2], {
  50       * >     seriesDefaults: {
  51       * >         renderer:$.jqplot.FunnelRenderer,
  52       * >         rendererOptions:{
  53       * >              sectionMargin: 12,
  54       * >              widthRatio: 0.3
  55       * >          }
  56       * >      }
  57       * > });
  58       * 
  59       * IMPORTANT
  60       * 
  61       * *The funnel renderer will reorder data in descending order* so the largest value in
  62       * the data set is first and displayed on top of the funnel.  Data will then
  63       * be displayed in descending order down the funnel.  The area of each funnel
  64       * section will correspond to the value of each data point relative to the sum
  65       * of all values.  That is section area is proportional to section value divided by 
  66       * sum of all section values.
  67       * 
  68       * If your data is not in descending order when passed into the plot, *it will be
  69       * reordered* when stored in the series.data property.  A copy of the unordered
  70       * data is kept in the series._unorderedData property.
  71       * 
  72       * A funnel plot will trigger events on the plot target
  73       * according to user interaction.  All events return the event object,
  74       * the series index, the point (section) index, and the point data for 
  75       * the appropriate section. *Note* the point index will referr to the ordered
  76       * data, not the original unordered data.
  77       * 
  78       * 'jqplotDataMouseOver' - triggered when mousing over a section.
  79       * 'jqplotDataHighlight' - triggered the first time user mouses over a section,
  80       * if highlighting is enabled.
  81       * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
  82       * a highlighted section.
  83       * 'jqplotDataClick' - triggered when the user clicks on a section.
  84       * 'jqplotDataRightClick' - tiggered when the user right clicks on a section if
  85       * the "captureRightClick" option is set to true on the plot.
  86       */
  87      $.jqplot.FunnelRenderer = function(){
  88          $.jqplot.LineRenderer.call(this);
  89      };
  90      
  91      $.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer();
  92      $.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer;
  93      
  94      // called with scope of a series
  95      $.jqplot.FunnelRenderer.prototype.init = function(options, plot) {
  96          // Group: Properties
  97          //
  98          // prop: padding
  99          // padding between the funnel and plot edges, legend, etc.
 100          this.padding = {top: 20, right: 20, bottom: 20, left: 20};
 101          // prop: sectionMargin
 102          // spacing between funnel sections in pixels.
 103          this.sectionMargin = 6;
 104          // prop: fill
 105          // true or false, wether to fill the areas.
 106          this.fill = true;
 107          // prop: shadowOffset
 108          // offset of the shadow from the area and offset of 
 109          // each succesive stroke of the shadow from the last.
 110          this.shadowOffset = 2;
 111          // prop: shadowAlpha
 112          // transparency of the shadow (0 = transparent, 1 = opaque)
 113          this.shadowAlpha = 0.07;
 114          // prop: shadowDepth
 115          // number of strokes to apply to the shadow, 
 116          // each stroke offset shadowOffset from the last.
 117          this.shadowDepth = 5;
 118          // prop: highlightMouseOver
 119          // True to highlight area when moused over.
 120          // This must be false to enable highlightMouseDown to highlight when clicking on a area.
 121          this.highlightMouseOver = true;
 122          // prop: highlightMouseDown
 123          // True to highlight when a mouse button is pressed over a area.
 124          // This will be disabled if highlightMouseOver is true.
 125          this.highlightMouseDown = false;
 126          // prop: highlightColors
 127          // array of colors to use when highlighting an area.
 128          this.highlightColors = [];
 129          // prop: widthRatio
 130          // The ratio of the width of the top of the funnel to the bottom.
 131          // a ratio of 0 will make an upside down pyramid. 
 132          this.widthRatio = 0.2;
 133          // prop: lineWidth
 134          // width of line if areas are stroked and not filled.
 135          this.lineWidth = 2;
 136          // prop: dataLabels
 137          // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
 138          // Defaults to percentage of each pie slice.
 139          this.dataLabels = 'percent';
 140          // prop: showDataLabels
 141          // true to show data labels on slices.
 142          this.showDataLabels = false;
 143          // prop: dataLabelFormatString
 144          // Format string for data labels.  If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
 145          this.dataLabelFormatString = null;
 146          // prop: dataLabelThreshold
 147          // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
 148          // This applies to all label types, not just to percentage labels.
 149          this.dataLabelThreshold = 3;
 150          this._type = 'funnel';
 151          
 152          this.tickRenderer = $.jqplot.FunnelTickRenderer;
 153          
 154          // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
 155          if (options.highlightMouseDown && options.highlightMouseOver == null) {
 156              options.highlightMouseOver = false;
 157          }
 158          
 159          $.extend(true, this, options);
 160          
 161          // index of the currenty highlighted point, if any
 162          this._highlightedPoint = null;
 163          
 164          // lengths of bases, or horizontal sides of areas of trapezoid.
 165          this._bases = [];
 166          // total area
 167          this._atot;
 168          // areas of segments.
 169          this._areas = [];
 170          // vertical lengths of segments.
 171          this._lengths = [];
 172          // angle of the funnel to vertical.
 173          this._angle;
 174          this._dataIndices = [];
 175          
 176          // sort data
 177          this._unorderedData = $.extend(true, [], this.data);
 178          var idxs = $.extend(true, [], this.data);
 179          for (var i=0; i<idxs.length; i++) {
 180              idxs[i].push(i);
 181          }
 182          this.data.sort( function (a, b) { return b[1] - a[1]; } );
 183          idxs.sort( function (a, b) { return b[1] - a[1]; });
 184          for (var i=0; i<idxs.length; i++) {
 185              this._dataIndices.push(idxs[i][2]);
 186          }
 187          
 188          // set highlight colors if none provided
 189          if (this.highlightColors.length == 0) {
 190              for (var i=0; i<this.seriesColors.length; i++){
 191                  var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
 192                  var newrgb = [rgba[0], rgba[1], rgba[2]];
 193                  var sum = newrgb[0] + newrgb[1] + newrgb[2];
 194                  for (var j=0; j<3; j++) {
 195                      // when darkening, lowest color component can be is 60.
 196                      newrgb[j] = (sum > 570) ?  newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]);
 197                      newrgb[j] = parseInt(newrgb[j], 10);
 198                  }
 199                  this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
 200              }
 201          }
 202  
 203          plot.postParseOptionsHooks.addOnce(postParseOptions);
 204          plot.postInitHooks.addOnce(postInit);
 205          plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
 206          plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
 207          plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
 208          plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
 209          plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
 210          plot.postDrawHooks.addOnce(postPlotDraw);        
 211          
 212      };
 213      
 214      // gridData will be of form [label, percentage of total]
 215      $.jqplot.FunnelRenderer.prototype.setGridData = function(plot) {
 216          // set gridData property.  This will hold angle in radians of each data point.
 217          var sum = 0;
 218          var td = [];
 219          for (var i=0; i<this.data.length; i++){
 220              sum += this.data[i][1];
 221              td.push([this.data[i][0], this.data[i][1]]);
 222          }
 223          
 224          // normalize y values, so areas are proportional.
 225          for (var i=0; i<td.length; i++) {
 226              td[i][1] = td[i][1]/sum;
 227          }
 228          
 229          this._bases = new Array(td.length + 1);
 230          this._lengths = new Array(td.length);
 231          
 232          this.gridData = td;
 233      };
 234      
 235      $.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) {
 236          // set gridData property.  This will hold angle in radians of each data point.
 237          var sum = 0;
 238          var td = [];
 239          for (var i=0; i<this.data.length; i++){
 240              sum += this.data[i][1];
 241              td.push([this.data[i][0], this.data[i][1]]);
 242          }
 243          
 244          // normalize y values, so areas are proportional.
 245          for (var i=0; i<td.length; i++) {
 246              td[i][1] = td[i][1]/sum;
 247          }
 248          
 249          this._bases = new Array(td.length + 1);
 250          this._lengths = new Array(td.length);
 251          
 252          return td;
 253      };
 254      
 255      $.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) {
 256          var fill = this.fill;
 257          var lineWidth = this.lineWidth;
 258          ctx.save();
 259          
 260          if (isShadow) {
 261              for (var i=0; i<this.shadowDepth; i++) {
 262                  ctx.save();
 263                  ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
 264                  doDraw();
 265              }
 266          }
 267          
 268          else {
 269              doDraw();
 270          }
 271          
 272          function doDraw () {
 273              ctx.beginPath();  
 274              ctx.fillStyle = color;
 275              ctx.strokeStyle = color;
 276              ctx.lineWidth = lineWidth;
 277              ctx.moveTo(vertices[0][0], vertices[0][1]);
 278              for (var i=1; i<4; i++) {
 279                  ctx.lineTo(vertices[i][0], vertices[i][1]);
 280              }
 281              ctx.closePath();
 282              if (fill) {
 283                  ctx.fill();
 284              }
 285              else {
 286                  ctx.stroke();
 287              }
 288          }
 289          
 290          if (isShadow) {
 291              for (var i=0; i<this.shadowDepth; i++) {
 292                  ctx.restore();
 293              }
 294          }
 295          
 296          ctx.restore();
 297      };
 298      
 299      // called with scope of series
 300      $.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) {
 301          var i;
 302          var opts = (options != undefined) ? options : {};
 303          // offset and direction of offset due to legend placement
 304          var offx = 0;
 305          var offy = 0;
 306          var trans = 1;
 307          this._areas = [];
 308          // var colorGenerator = new this.colorGenerator(this.seriesColors);
 309          if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
 310              var li = options.legendInfo;
 311              switch (li.location) {
 312                  case 'nw':
 313                      offx = li.width + li.xoffset;
 314                      break;
 315                  case 'w':
 316                      offx = li.width + li.xoffset;
 317                      break;
 318                  case 'sw':
 319                      offx = li.width + li.xoffset;
 320                      break;
 321                  case 'ne':
 322                      offx = li.width + li.xoffset;
 323                      trans = -1;
 324                      break;
 325                  case 'e':
 326                      offx = li.width + li.xoffset;
 327                      trans = -1;
 328                      break;
 329                  case 'se':
 330                      offx = li.width + li.xoffset;
 331                      trans = -1;
 332                      break;
 333                  case 'n':
 334                      offy = li.height + li.yoffset;
 335                      break;
 336                  case 's':
 337                      offy = li.height + li.yoffset;
 338                      trans = -1;
 339                      break;
 340                  default:
 341                      break;
 342              }
 343          }
 344          
 345          var loff = (trans==1) ? this.padding.left + offx : this.padding.left;
 346          var toff = (trans==1) ? this.padding.top + offy : this.padding.top;
 347          var roff = (trans==-1) ? this.padding.right + offx : this.padding.right;
 348          var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom;
 349          
 350          var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
 351          var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
 352          var fill = (opts.fill != undefined) ? opts.fill : this.fill;
 353          var cw = ctx.canvas.width;
 354          var ch = ctx.canvas.height;
 355          this._bases[0] = cw - loff - roff;
 356          var ltot = this._length = ch - toff - boff;
 357  
 358          var hend = this._bases[0]*this.widthRatio;
 359          this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio);
 360  
 361          this._angle = Math.atan((this._bases[0] - hend)/2/ltot);
 362  
 363          for (i=0; i<gd.length; i++) {
 364              this._areas.push(gd[i][1] * this._atot);
 365          }
 366  
 367          
 368          var guess, err, count, lsum=0;
 369          var tolerance = 0.0001;
 370  
 371          for (i=0; i<this._areas.length; i++) {
 372              guess = this._areas[i]/this._bases[i];
 373              err = 999999;
 374              this._lengths[i] = guess;
 375              count = 0;
 376              while (err > this._lengths[i]*tolerance && count < 100) {
 377                  this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle));
 378                  err = Math.abs(this._lengths[i] - guess);
 379                  this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle));
 380                  guess = this._lengths[i];
 381                  count++;
 382              }
 383              lsum += this._lengths[i];
 384          }
 385          
 386          // figure out vertices of each section
 387          this._vertices = new Array(gd.length);
 388          
 389          // these are 4 coners of entire trapezoid
 390          var p0 = [loff, toff],
 391              p1 = [loff+this._bases[0], toff],
 392              p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length],
 393              p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]];
 394              
 395          // equations of right and left sides, returns x, y values given height of section (y value)
 396          function findleft (l) {
 397              var m = (p0[1] - p2[1])/(p0[0] - p2[0]);
 398              var b = p0[1] - m*p0[0];
 399              var y = l + p0[1];
 400              
 401              return [(y - b)/m, y];
 402          }
 403          
 404          function findright (l) {
 405              var m = (p1[1] - p3[1])/(p1[0] - p3[0]);
 406              var b = p1[1] - m*p1[0];
 407              var y = l + p1[1];
 408              
 409              return [(y - b)/m, y];
 410          }
 411          
 412          var x = offx, y = offy;
 413          var h=0, adj=0;
 414          
 415          for (i=0; i<gd.length; i++) {
 416              this._vertices[i] = new Array();
 417              var v = this._vertices[i];
 418              var sm = this.sectionMargin;
 419              if (i == 0) {
 420                  adj = 0;
 421              }
 422              if (i == 1) {
 423                  adj = sm/3;
 424              }
 425              else if (i > 0 && i < gd.length-1) {
 426                  adj = sm/2;
 427              }
 428              else if (i == gd.length -1) {
 429                  adj = 2*sm/3;
 430              }
 431              v.push(findleft(h+adj));
 432              v.push(findright(h+adj));
 433              h += this._lengths[i];
 434              if (i == 0) {
 435                  adj = -2*sm/3;
 436              }
 437              else if (i > 0 && i < gd.length-1) {
 438                  adj = -sm/2;
 439              }
 440              else if (i == gd.length - 1) {
 441                  adj = 0;
 442              }
 443              v.push(findright(h+adj));
 444              v.push(findleft(h+adj));
 445              
 446          }
 447  
 448          if (this.shadow) {
 449              var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
 450              for (var i=0; i<gd.length; i++) {
 451                  this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true);
 452              }
 453              
 454          }
 455          for (var i=0; i<gd.length; i++) {
 456              var v = this._vertices[i];
 457              this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]);
 458              
 459              if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) {
 460                  var fstr, label;
 461                  
 462                  if (this.dataLabels == 'label') {
 463                      fstr = this.dataLabelFormatString || '%s';
 464                      label = $.jqplot.sprintf(fstr, gd[i][0]);
 465                  }
 466                  else if (this.dataLabels == 'value') {
 467                      fstr = this.dataLabelFormatString || '%d';
 468                      label = $.jqplot.sprintf(fstr, this.data[i][1]);
 469                  }
 470                  else if (this.dataLabels == 'percent') {
 471                      fstr = this.dataLabelFormatString || '%d%%';
 472                      label = $.jqplot.sprintf(fstr, gd[i][1]*100);
 473                  }
 474                  else if (this.dataLabels.constructor == Array) {
 475                      fstr = this.dataLabelFormatString || '%s';
 476                      label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]);
 477                  }
 478                  
 479                  var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
 480                  
 481                  var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left;
 482                  var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top;
 483                  
 484                  var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
 485                  x -= labelelem.width()/2;
 486                  y -= labelelem.height()/2;
 487                  x = Math.round(x);
 488                  y = Math.round(y);
 489                  labelelem.css({left: x, top: y});
 490              }
 491              
 492          }
 493                 
 494      };
 495      
 496      $.jqplot.FunnelAxisRenderer = function() {
 497          $.jqplot.LinearAxisRenderer.call(this);
 498      };
 499      
 500      $.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
 501      $.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer;
 502          
 503      
 504      // There are no traditional axes on a funnel chart.  We just need to provide
 505      // dummy objects with properties so the plot will render.
 506      // called with scope of axis object.
 507      $.jqplot.FunnelAxisRenderer.prototype.init = function(options){
 508          //
 509          this.tickRenderer = $.jqplot.FunnelTickRenderer;
 510          $.extend(true, this, options);
 511          // I don't think I'm going to need _dataBounds here.
 512          // have to go Axis scaling in a way to fit chart onto plot area
 513          // and provide u2p and p2u functionality for mouse cursor, etc.
 514          // for convienence set _dataBounds to 0 and 100 and
 515          // set min/max to 0 and 100.
 516          this._dataBounds = {min:0, max:100};
 517          this.min = 0;
 518          this.max = 100;
 519          this.showTicks = false;
 520          this.ticks = [];
 521          this.showMark = false;
 522          this.show = false; 
 523      };
 524      
 525      
 526      
 527      /**
 528       * Class: $.jqplot.FunnelLegendRenderer
 529       * Legend Renderer specific to funnel plots.  Set by default
 530       * when the user creates a funnel plot.
 531       */
 532      $.jqplot.FunnelLegendRenderer = function(){
 533          $.jqplot.TableLegendRenderer.call(this);
 534      };
 535      
 536      $.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
 537      $.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer;
 538      
 539      $.jqplot.FunnelLegendRenderer.prototype.init = function(options) {
 540          // Group: Properties
 541          //
 542          // prop: numberRows
 543          // Maximum number of rows in the legend.  0 or null for unlimited.
 544          this.numberRows = null;
 545          // prop: numberColumns
 546          // Maximum number of columns in the legend.  0 or null for unlimited.
 547          this.numberColumns = null;
 548          $.extend(true, this, options);
 549      };
 550      
 551      // called with context of legend
 552      $.jqplot.FunnelLegendRenderer.prototype.draw = function() {
 553          var legend = this;
 554          if (this.show) {
 555              var series = this._series;
 556              var ss = 'position:absolute;';
 557              ss += (this.background) ? 'background:'+this.background+';' : '';
 558              ss += (this.border) ? 'border:'+this.border+';' : '';
 559              ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
 560              ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
 561              ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
 562              ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
 563              ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
 564              ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
 565              ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
 566              this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
 567              // Funnel charts legends don't go by number of series, but by number of data points
 568              // in the series.  Refactor things here for that.
 569              
 570              var pad = false, 
 571                  reverse = false,
 572                  nr, nc;
 573              var s = series[0];
 574              var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
 575              
 576              if (s.show) {
 577                  var pd = s.data;
 578                  if (this.numberRows) {
 579                      nr = this.numberRows;
 580                      if (!this.numberColumns){
 581                          nc = Math.ceil(pd.length/nr);
 582                      }
 583                      else{
 584                          nc = this.numberColumns;
 585                      }
 586                  }
 587                  else if (this.numberColumns) {
 588                      nc = this.numberColumns;
 589                      nr = Math.ceil(pd.length/this.numberColumns);
 590                  }
 591                  else {
 592                      nr = pd.length;
 593                      nc = 1;
 594                  }
 595                  
 596                  var i, j, tr, td1, td2, lt, rs, color;
 597                  var idx = 0;    
 598                  
 599                  for (i=0; i<nr; i++) {
 600                      if (reverse){
 601                          tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
 602                      }
 603                      else{
 604                          tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
 605                      }
 606                      for (j=0; j<nc; j++) {
 607                          if (idx < pd.length){
 608                              lt = this.labels[idx] || pd[idx][0].toString();
 609                              color = colorGenerator.next();
 610                              if (!reverse){
 611                                  if (i>0){
 612                                      pad = true;
 613                                  }
 614                                  else{
 615                                      pad = false;
 616                                  }
 617                              }
 618                              else{
 619                                  if (i == nr -1){
 620                                      pad = false;
 621                                  }
 622                                  else{
 623                                      pad = true;
 624                                  }
 625                              }
 626                              rs = (pad) ? this.rowSpacing : '0';
 627                  
 628                              td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
 629                                  '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
 630                                  '</div></td>');
 631                              td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
 632                              if (this.escapeHtml){
 633                                  td2.text(lt);
 634                              }
 635                              else {
 636                                  td2.html(lt);
 637                              }
 638                              if (reverse) {
 639                                  td2.prependTo(tr);
 640                                  td1.prependTo(tr);
 641                              }
 642                              else {
 643                                  td1.appendTo(tr);
 644                                  td2.appendTo(tr);
 645                              }
 646                              pad = true;
 647                          }
 648                          idx++;
 649                      }   
 650                  }
 651              }
 652          }
 653          return this._elem;                
 654      };
 655      
 656      // $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) {
 657      //     if (this.show) {
 658      //         // fake a grid for positioning
 659      //         var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
 660      //         if (this.placement == 'insideGrid') {
 661      //             switch (this.location) {
 662      //                 case 'nw':
 663      //                     var a = grid._left + this.xoffset;
 664      //                     var b = grid._top + this.yoffset;
 665      //                     this._elem.css('left', a);
 666      //                     this._elem.css('top', b);
 667      //                     break;
 668      //                 case 'n':
 669      //                     var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
 670      //                     var b = grid._top + this.yoffset;
 671      //                     this._elem.css('left', a);
 672      //                     this._elem.css('top', b);
 673      //                     break;
 674      //                 case 'ne':
 675      //                     var a = offsets.right + this.xoffset;
 676      //                     var b = grid._top + this.yoffset;
 677      //                     this._elem.css({right:a, top:b});
 678      //                     break;
 679      //                 case 'e':
 680      //                     var a = offsets.right + this.xoffset;
 681      //                     var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
 682      //                     this._elem.css({right:a, top:b});
 683      //                     break;
 684      //                 case 'se':
 685      //                     var a = offsets.right + this.xoffset;
 686      //                     var b = offsets.bottom + this.yoffset;
 687      //                     this._elem.css({right:a, bottom:b});
 688      //                     break;
 689      //                 case 's':
 690      //                     var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
 691      //                     var b = offsets.bottom + this.yoffset;
 692      //                     this._elem.css({left:a, bottom:b});
 693      //                     break;
 694      //                 case 'sw':
 695      //                     var a = grid._left + this.xoffset;
 696      //                     var b = offsets.bottom + this.yoffset;
 697      //                     this._elem.css({left:a, bottom:b});
 698      //                     break;
 699      //                 case 'w':
 700      //                     var a = grid._left + this.xoffset;
 701      //                     var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
 702      //                     this._elem.css({left:a, top:b});
 703      //                     break;
 704      //                 default:  // same as 'se'
 705      //                     var a = grid._right - this.xoffset;
 706      //                     var b = grid._bottom + this.yoffset;
 707      //                     this._elem.css({right:a, bottom:b});
 708      //                     break;
 709      //             }
 710      //             
 711      //         }
 712      //         else {
 713      //             switch (this.location) {
 714      //                 case 'nw':
 715      //                     var a = this._plotDimensions.width - grid._left + this.xoffset;
 716      //                     var b = grid._top + this.yoffset;
 717      //                     this._elem.css('right', a);
 718      //                     this._elem.css('top', b);
 719      //                     break;
 720      //                 case 'n':
 721      //                     var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
 722      //                     var b = this._plotDimensions.height - grid._top + this.yoffset;
 723      //                     this._elem.css('left', a);
 724      //                     this._elem.css('bottom', b);
 725      //                     break;
 726      //                 case 'ne':
 727      //                     var a = this._plotDimensions.width - offsets.right + this.xoffset;
 728      //                     var b = grid._top + this.yoffset;
 729      //                     this._elem.css({left:a, top:b});
 730      //                     break;
 731      //                 case 'e':
 732      //                     var a = this._plotDimensions.width - offsets.right + this.xoffset;
 733      //                     var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
 734      //                     this._elem.css({left:a, top:b});
 735      //                     break;
 736      //                 case 'se':
 737      //                     var a = this._plotDimensions.width - offsets.right + this.xoffset;
 738      //                     var b = offsets.bottom + this.yoffset;
 739      //                     this._elem.css({left:a, bottom:b});
 740      //                     break;
 741      //                 case 's':
 742      //                     var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
 743      //                     var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
 744      //                     this._elem.css({left:a, top:b});
 745      //                     break;
 746      //                 case 'sw':
 747      //                     var a = this._plotDimensions.width - grid._left + this.xoffset;
 748      //                     var b = offsets.bottom + this.yoffset;
 749      //                     this._elem.css({right:a, bottom:b});
 750      //                     break;
 751      //                 case 'w':
 752      //                     var a = this._plotDimensions.width - grid._left + this.xoffset;
 753      //                     var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
 754      //                     this._elem.css({right:a, top:b});
 755      //                     break;
 756      //                 default:  // same as 'se'
 757      //                     var a = grid._right - this.xoffset;
 758      //                     var b = grid._bottom + this.yoffset;
 759      //                     this._elem.css({right:a, bottom:b});
 760      //                     break;
 761      //             }
 762      //         }
 763      //     } 
 764      // };
 765      
 766      // setup default renderers for axes and legend so user doesn't have to
 767      // called with scope of plot
 768      function preInit(target, data, options) {
 769          options = options || {};
 770          options.axesDefaults = options.axesDefaults || {};
 771          options.legend = options.legend || {};
 772          options.seriesDefaults = options.seriesDefaults || {};
 773          // only set these if there is a funnel series
 774          var setopts = false;
 775          if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) {
 776              setopts = true;
 777          }
 778          else if (options.series) {
 779              for (var i=0; i < options.series.length; i++) {
 780                  if (options.series[i].renderer == $.jqplot.FunnelRenderer) {
 781                      setopts = true;
 782                  }
 783              }
 784          }
 785          
 786          if (setopts) {
 787              options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer;
 788              options.legend.renderer = $.jqplot.FunnelLegendRenderer;
 789              options.legend.preDraw = true;
 790              options.sortData = false;
 791              options.seriesDefaults.pointLabels = {show: false};
 792          }
 793      }
 794      
 795      function postInit(target, data, options) {
 796          // if multiple series, add a reference to the previous one so that
 797          // funnel rings can nest.
 798          for (var i=0; i<this.series.length; i++) {
 799              if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) {
 800                  // don't allow mouseover and mousedown at same time.
 801                  if (this.series[i].highlightMouseOver) {
 802                      this.series[i].highlightMouseDown = false;
 803                  }
 804              }
 805          }
 806      }
 807      
 808      // called with scope of plot
 809      function postParseOptions(options) {
 810          for (var i=0; i<this.series.length; i++) {
 811              this.series[i].seriesColors = this.seriesColors;
 812              this.series[i].colorGenerator = $.jqplot.colorGenerator;
 813          }
 814      }
 815      
 816      function highlight (plot, sidx, pidx) {
 817          var s = plot.series[sidx];
 818          var canvas = plot.plugins.funnelRenderer.highlightCanvas;
 819          canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
 820          s._highlightedPoint = pidx;
 821          plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx;
 822          s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false);
 823      }
 824      
 825      function unhighlight (plot) {
 826          var canvas = plot.plugins.funnelRenderer.highlightCanvas;
 827          canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
 828          for (var i=0; i<plot.series.length; i++) {
 829              plot.series[i]._highlightedPoint = null;
 830          }
 831          plot.plugins.funnelRenderer.highlightedSeriesIndex = null;
 832          plot.target.trigger('jqplotDataUnhighlight');
 833      }
 834      
 835      function handleMove(ev, gridpos, datapos, neighbor, plot) {
 836          if (neighbor) {
 837              var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
 838              var evt1 = jQuery.Event('jqplotDataMouseOver');
 839              evt1.pageX = ev.pageX;
 840              evt1.pageY = ev.pageY;
 841              plot.target.trigger(evt1, ins);
 842              if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
 843                  var evt = jQuery.Event('jqplotDataHighlight');
 844          evt.which = ev.which;
 845                  evt.pageX = ev.pageX;
 846                  evt.pageY = ev.pageY;
 847                  plot.target.trigger(evt, ins);
 848                  highlight (plot, ins[0], ins[1]);
 849              }
 850          }
 851          else if (neighbor == null) {
 852              unhighlight (plot);
 853          }
 854      }
 855      
 856      function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
 857          if (neighbor) {
 858              var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
 859              if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
 860                  var evt = jQuery.Event('jqplotDataHighlight');
 861          evt.which = ev.which;
 862                  evt.pageX = ev.pageX;
 863                  evt.pageY = ev.pageY;
 864                  plot.target.trigger(evt, ins);
 865                  highlight (plot, ins[0], ins[1]);
 866              }
 867          }
 868          else if (neighbor == null) {
 869              unhighlight (plot);
 870          }
 871      }
 872      
 873      function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
 874          var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
 875          if (idx != null && plot.series[idx].highlightMouseDown) {
 876              unhighlight(plot);
 877          }
 878      }
 879      
 880      function handleClick(ev, gridpos, datapos, neighbor, plot) {
 881          if (neighbor) {
 882              var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
 883              var evt = jQuery.Event('jqplotDataClick');
 884          evt.which = ev.which;
 885              evt.pageX = ev.pageX;
 886              evt.pageY = ev.pageY;
 887              plot.target.trigger(evt, ins);
 888          }
 889      }
 890      
 891      function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
 892          if (neighbor) {
 893              var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
 894              var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
 895              if (idx != null && plot.series[idx].highlightMouseDown) {
 896                  unhighlight(plot);
 897              }
 898              var evt = jQuery.Event('jqplotDataRightClick');
 899          evt.which = ev.which;
 900              evt.pageX = ev.pageX;
 901              evt.pageY = ev.pageY;
 902              plot.target.trigger(evt, ins);
 903          }
 904      }
 905      
 906      // called within context of plot
 907      // create a canvas which we can draw on.
 908      // insert it before the eventCanvas, so eventCanvas will still capture events.
 909      function postPlotDraw() {
 910          // Memory Leaks patch    
 911          if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) {
 912              this.plugins.funnelRenderer.highlightCanvas.resetCanvas();
 913              this.plugins.funnelRenderer.highlightCanvas = null;
 914          }
 915  
 916          this.plugins.funnelRenderer = {};
 917          this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
 918          
 919          // do we have any data labels?  if so, put highlight canvas before those
 920          var labels = $(this.targetId+' .jqplot-data-label');
 921          if (labels.length) {
 922              $(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
 923          }
 924          // else put highlight canvas before event canvas.
 925          else {
 926              this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
 927          }
 928          var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext();
 929          this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
 930      }
 931      
 932      $.jqplot.preInitHooks.push(preInit);
 933      
 934      $.jqplot.FunnelTickRenderer = function() {
 935          $.jqplot.AxisTickRenderer.call(this);
 936      };
 937      
 938      $.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
 939      $.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer;
 940      
 941  })(jQuery);
 942      
 943      


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1