mdoc 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +2 -2
  3. data/examples/jqplot.html +62 -0
  4. data/examples/jqplot.md +8 -0
  5. data/examples/js/jquery.jqplot.css +259 -0
  6. data/examples/js/jquery.jqplot.js +11411 -0
  7. data/examples/js/jquery.jqplot.min.css +1 -0
  8. data/examples/js/jquery.jqplot.min.js +3 -0
  9. data/examples/js/jquery.js +9597 -0
  10. data/examples/js/jquery.min.js +5 -0
  11. data/examples/js/plugins/jqplot.BezierCurveRenderer.js +314 -0
  12. data/examples/js/plugins/jqplot.BezierCurveRenderer.min.js +3 -0
  13. data/examples/js/plugins/jqplot.barRenderer.js +801 -0
  14. data/examples/js/plugins/jqplot.barRenderer.min.js +3 -0
  15. data/examples/js/plugins/jqplot.blockRenderer.js +235 -0
  16. data/examples/js/plugins/jqplot.blockRenderer.min.js +3 -0
  17. data/examples/js/plugins/jqplot.bubbleRenderer.js +759 -0
  18. data/examples/js/plugins/jqplot.bubbleRenderer.min.js +3 -0
  19. data/examples/js/plugins/jqplot.canvasAxisLabelRenderer.js +203 -0
  20. data/examples/js/plugins/jqplot.canvasAxisLabelRenderer.min.js +3 -0
  21. data/examples/js/plugins/jqplot.canvasAxisTickRenderer.js +253 -0
  22. data/examples/js/plugins/jqplot.canvasAxisTickRenderer.min.js +3 -0
  23. data/examples/js/plugins/jqplot.canvasOverlay.js +1021 -0
  24. data/examples/js/plugins/jqplot.canvasOverlay.min.js +3 -0
  25. data/examples/js/plugins/jqplot.canvasTextRenderer.js +449 -0
  26. data/examples/js/plugins/jqplot.canvasTextRenderer.min.js +3 -0
  27. data/examples/js/plugins/jqplot.categoryAxisRenderer.js +679 -0
  28. data/examples/js/plugins/jqplot.categoryAxisRenderer.min.js +3 -0
  29. data/examples/js/plugins/jqplot.ciParser.js +116 -0
  30. data/examples/js/plugins/jqplot.ciParser.min.js +3 -0
  31. data/examples/js/plugins/jqplot.cursor.js +1108 -0
  32. data/examples/js/plugins/jqplot.cursor.min.js +3 -0
  33. data/examples/js/plugins/jqplot.dateAxisRenderer.js +741 -0
  34. data/examples/js/plugins/jqplot.dateAxisRenderer.min.js +3 -0
  35. data/examples/js/plugins/jqplot.donutRenderer.js +805 -0
  36. data/examples/js/plugins/jqplot.donutRenderer.min.js +3 -0
  37. data/examples/js/plugins/jqplot.dragable.js +225 -0
  38. data/examples/js/plugins/jqplot.dragable.min.js +3 -0
  39. data/examples/js/plugins/jqplot.enhancedLegendRenderer.js +305 -0
  40. data/examples/js/plugins/jqplot.enhancedLegendRenderer.min.js +3 -0
  41. data/examples/js/plugins/jqplot.funnelRenderer.js +943 -0
  42. data/examples/js/plugins/jqplot.funnelRenderer.min.js +3 -0
  43. data/examples/js/plugins/jqplot.highlighter.js +465 -0
  44. data/examples/js/plugins/jqplot.highlighter.min.js +3 -0
  45. data/examples/js/plugins/jqplot.json2.js +475 -0
  46. data/examples/js/plugins/jqplot.json2.min.js +3 -0
  47. data/examples/js/plugins/jqplot.logAxisRenderer.js +534 -0
  48. data/examples/js/plugins/jqplot.logAxisRenderer.min.js +3 -0
  49. data/examples/js/plugins/jqplot.mekkoAxisRenderer.js +611 -0
  50. data/examples/js/plugins/jqplot.mekkoAxisRenderer.min.js +3 -0
  51. data/examples/js/plugins/jqplot.mekkoRenderer.js +437 -0
  52. data/examples/js/plugins/jqplot.mekkoRenderer.min.js +3 -0
  53. data/examples/js/plugins/jqplot.meterGaugeRenderer.js +1029 -0
  54. data/examples/js/plugins/jqplot.meterGaugeRenderer.min.js +3 -0
  55. data/examples/js/plugins/jqplot.mobile.js +45 -0
  56. data/examples/js/plugins/jqplot.mobile.min.js +3 -0
  57. data/examples/js/plugins/jqplot.ohlcRenderer.js +373 -0
  58. data/examples/js/plugins/jqplot.ohlcRenderer.min.js +3 -0
  59. data/examples/js/plugins/jqplot.pieRenderer.js +904 -0
  60. data/examples/js/plugins/jqplot.pieRenderer.min.js +3 -0
  61. data/examples/js/plugins/jqplot.pointLabels.js +377 -0
  62. data/examples/js/plugins/jqplot.pointLabels.min.js +3 -0
  63. data/examples/js/plugins/jqplot.pyramidAxisRenderer.js +728 -0
  64. data/examples/js/plugins/jqplot.pyramidAxisRenderer.min.js +3 -0
  65. data/examples/js/plugins/jqplot.pyramidGridRenderer.js +429 -0
  66. data/examples/js/plugins/jqplot.pyramidGridRenderer.min.js +3 -0
  67. data/examples/js/plugins/jqplot.pyramidRenderer.js +514 -0
  68. data/examples/js/plugins/jqplot.pyramidRenderer.min.js +3 -0
  69. data/examples/js/plugins/jqplot.trendline.js +223 -0
  70. data/examples/js/plugins/jqplot.trendline.min.js +3 -0
  71. data/examples/js/raphael-min.js +11 -0
  72. data/examples/js/sequence-diagram-min.js +8 -0
  73. data/examples/js/underscore-min.js +5 -0
  74. data/lib/mdoc.rb +1 -0
  75. data/lib/mdoc/processor/jqplot.rb +48 -0
  76. data/lib/mdoc/version.rb +1 -1
  77. data/templates/default.html.erb +1 -1
  78. metadata +74 -2
@@ -0,0 +1,3 @@
1
+ /* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com
2
+ jsDate | (c) 2010-2013 Chris Leonello
3
+ */(function(c){c.jqplot.EnhancedLegendRenderer=function(){c.jqplot.TableLegendRenderer.call(this)};c.jqplot.EnhancedLegendRenderer.prototype=new c.jqplot.TableLegendRenderer();c.jqplot.EnhancedLegendRenderer.prototype.constructor=c.jqplot.EnhancedLegendRenderer;c.jqplot.EnhancedLegendRenderer.prototype.init=function(d){this.numberRows=null;this.numberColumns=null;this.seriesToggle="normal";this.seriesToggleReplot=false;this.disableIEFading=true;c.extend(true,this,d);if(this.seriesToggle){c.jqplot.postDrawHooks.push(b)}};c.jqplot.EnhancedLegendRenderer.prototype.draw=function(m,y){var f=this;if(this.show){var r=this._series;var u;var w="position:absolute;";w+=(this.background)?"background:"+this.background+";":"";w+=(this.border)?"border:"+this.border+";":"";w+=(this.fontSize)?"font-size:"+this.fontSize+";":"";w+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";w+=(this.textColor)?"color:"+this.textColor+";":"";w+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";w+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";w+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";w+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=c('<table class="jqplot-table-legend" style="'+w+'"></table>');if(this.seriesToggle){this._elem.css("z-index","3")}var C=false,q=false,d,o;if(this.numberRows){d=this.numberRows;if(!this.numberColumns){o=Math.ceil(r.length/d)}else{o=this.numberColumns}}else{if(this.numberColumns){o=this.numberColumns;d=Math.ceil(r.length/this.numberColumns)}else{d=r.length;o=1}}var B,z,e,l,k,n,p,t,h,g;var v=0;for(B=r.length-1;B>=0;B--){if(o==1&&r[B]._stack||r[B].renderer.constructor==c.jqplot.BezierCurveRenderer){q=true}}for(B=0;B<d;B++){e=c(document.createElement("tr"));e.addClass("jqplot-table-legend");if(q){e.prependTo(this._elem)}else{e.appendTo(this._elem)}for(z=0;z<o;z++){if(v<r.length&&(r[v].show||r[v].showLabel)){u=r[v];n=this.labels[v]||u.label.toString();if(n){var x=u.color;if(!q){if(B>0){C=true}else{C=false}}else{if(B==d-1){C=false}else{C=true}}p=(C)?this.rowSpacing:"0";l=c(document.createElement("td"));l.addClass("jqplot-table-legend jqplot-table-legend-swatch");l.css({textAlign:"center",paddingTop:p});h=c(document.createElement("div"));h.addClass("jqplot-table-legend-swatch-outline");g=c(document.createElement("div"));g.addClass("jqplot-table-legend-swatch");g.css({backgroundColor:x,borderColor:x});l.append(h.append(g));k=c(document.createElement("td"));k.addClass("jqplot-table-legend jqplot-table-legend-label");k.css("paddingTop",p);if(this.escapeHtml){k.text(n)}else{k.html(n)}if(q){if(this.showLabels){k.prependTo(e)}if(this.showSwatches){l.prependTo(e)}}else{if(this.showSwatches){l.appendTo(e)}if(this.showLabels){k.appendTo(e)}}if(this.seriesToggle){var A;if(typeof(this.seriesToggle)==="string"||typeof(this.seriesToggle)==="number"){if(!c.jqplot.use_excanvas||!this.disableIEFading){A=this.seriesToggle}}if(this.showSwatches){l.bind("click",{series:u,speed:A,plot:y,replot:this.seriesToggleReplot},a);l.addClass("jqplot-seriesToggle")}if(this.showLabels){k.bind("click",{series:u,speed:A,plot:y,replot:this.seriesToggleReplot},a);k.addClass("jqplot-seriesToggle")}if(!u.show&&u.showLabel){l.addClass("jqplot-series-hidden");k.addClass("jqplot-series-hidden")}}C=true}}v++}l=k=h=g=null}}return this._elem};var a=function(j){var i=j.data,m=i.series,k=i.replot,h=i.plot,f=i.speed,l=m.index,g=false;if(m.canvas._elem.is(":hidden")||!m.show){g=true}var e=function(){if(k){var n={};if(c.isPlainObject(k)){c.extend(true,n,k)}h.replot(n);if(g&&f){var d=h.series[l];if(d.shadowCanvas._elem){d.shadowCanvas._elem.hide().fadeIn(f)}d.canvas._elem.hide().fadeIn(f);d.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+d.index).hide().fadeIn(f)}}else{var d=h.series[l];if(d.canvas._elem.is(":hidden")||!d.show){if(typeof h.options.legend.showSwatches==="undefined"||h.options.legend.showSwatches===true){h.legend._elem.find("td").eq(l*2).addClass("jqplot-series-hidden")}if(typeof h.options.legend.showLabels==="undefined"||h.options.legend.showLabels===true){h.legend._elem.find("td").eq((l*2)+1).addClass("jqplot-series-hidden")}}else{if(typeof h.options.legend.showSwatches==="undefined"||h.options.legend.showSwatches===true){h.legend._elem.find("td").eq(l*2).removeClass("jqplot-series-hidden")}if(typeof h.options.legend.showLabels==="undefined"||h.options.legend.showLabels===true){h.legend._elem.find("td").eq((l*2)+1).removeClass("jqplot-series-hidden")}}}};m.toggleDisplay(j,e)};var b=function(){if(this.legend.renderer.constructor==c.jqplot.EnhancedLegendRenderer&&this.legend.seriesToggle){var d=this.legend._elem.detach();this.eventCanvas._elem.after(d)}}})(jQuery);
@@ -0,0 +1,943 @@
1
+ /**
2
+ * jqPlot
3
+ * Pure JavaScript plotting plugin using jQuery
4
+ *
5
+ * Version: 1.0.8
6
+ * Revision: 1250
7
+ *
8
+ * Copyright (c) 2009-2013 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, whether 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
+