outfielding-jqplot-rails 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +8 -4
  4. data/changes-jqplot.txt +48 -37
  5. data/copyright-jqplot.txt +17 -17
  6. data/lib/outfielding-jqplot-rails/version.rb +1 -1
  7. data/vendor/assets/javascripts/excanvas.js +1438 -1438
  8. data/vendor/assets/javascripts/jqplot-plugins/jqplot.BezierCurveRenderer.js +313 -313
  9. data/vendor/assets/javascripts/jqplot-plugins/jqplot.barRenderer.js +801 -801
  10. data/vendor/assets/javascripts/jqplot-plugins/jqplot.blockRenderer.js +234 -234
  11. data/vendor/assets/javascripts/jqplot-plugins/jqplot.bubbleRenderer.js +758 -758
  12. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisLabelRenderer.js +202 -202
  13. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisTickRenderer.js +252 -252
  14. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasOverlay.js +1020 -1020
  15. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasTextRenderer.js +448 -448
  16. data/vendor/assets/javascripts/jqplot-plugins/jqplot.categoryAxisRenderer.js +679 -679
  17. data/vendor/assets/javascripts/jqplot-plugins/jqplot.ciParser.js +115 -115
  18. data/vendor/assets/javascripts/jqplot-plugins/jqplot.cursor.js +1108 -1108
  19. data/vendor/assets/javascripts/jqplot-plugins/jqplot.dateAxisRenderer.js +741 -741
  20. data/vendor/assets/javascripts/jqplot-plugins/jqplot.donutRenderer.js +816 -805
  21. data/vendor/assets/javascripts/jqplot-plugins/jqplot.dragable.js +224 -224
  22. data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedLegendRenderer.js +305 -305
  23. data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedPieLegendRenderer.js +261 -0
  24. data/vendor/assets/javascripts/jqplot-plugins/jqplot.funnelRenderer.js +942 -942
  25. data/vendor/assets/javascripts/jqplot-plugins/jqplot.highlighter.js +464 -464
  26. data/vendor/assets/javascripts/jqplot-plugins/jqplot.json2.js +475 -475
  27. data/vendor/assets/javascripts/jqplot-plugins/jqplot.logAxisRenderer.js +533 -533
  28. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoAxisRenderer.js +611 -611
  29. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoRenderer.js +437 -437
  30. data/vendor/assets/javascripts/jqplot-plugins/jqplot.meterGaugeRenderer.js +1029 -1029
  31. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mobile.js +2 -2
  32. data/vendor/assets/javascripts/jqplot-plugins/jqplot.ohlcRenderer.js +373 -373
  33. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pieRenderer.js +945 -903
  34. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pointLabels.js +379 -377
  35. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidAxisRenderer.js +728 -728
  36. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidGridRenderer.js +428 -428
  37. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidRenderer.js +513 -513
  38. data/vendor/assets/javascripts/jqplot-plugins/jqplot.trendline.js +222 -222
  39. data/vendor/assets/javascripts/jquery.jqplot.js +11477 -11411
  40. data/vendor/assets/stylesheets/jquery.jqplot.css +259 -259
  41. metadata +9 -10
@@ -1,1029 +1,1029 @@
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.MeterGaugeRenderer
34
- * Plugin renderer to draw a meter gauge chart.
35
- *
36
- * Data consists of a single series with 1 data point to position the gauge needle.
37
- *
38
- * To use this renderer, you need to include the
39
- * meter gauge renderer plugin, for example:
40
- *
41
- * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script>
42
- *
43
- * Properties described here are passed into the $.jqplot function
44
- * as options on the series renderer. For example:
45
- *
46
- * > plot0 = $.jqplot('chart0',[[18]],{
47
- * > title: 'Network Speed',
48
- * > seriesDefaults: {
49
- * > renderer: $.jqplot.MeterGaugeRenderer,
50
- * > rendererOptions: {
51
- * > label: 'MB/s'
52
- * > }
53
- * > }
54
- * > });
55
- *
56
- * A meterGauge plot does not support events.
57
- */
58
- $.jqplot.MeterGaugeRenderer = function(){
59
- $.jqplot.LineRenderer.call(this);
60
- };
61
-
62
- $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer();
63
- $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer;
64
-
65
- // called with scope of a series
66
- $.jqplot.MeterGaugeRenderer.prototype.init = function(options) {
67
- // Group: Properties
68
- //
69
- // prop: diameter
70
- // Outer diameter of the meterGauge, auto computed by default
71
- this.diameter = null;
72
- // prop: padding
73
- // padding between the meterGauge and plot edges, auto
74
- // calculated by default.
75
- this.padding = null;
76
- // prop: shadowOffset
77
- // offset of the shadow from the gauge ring and offset of
78
- // each succesive stroke of the shadow from the last.
79
- this.shadowOffset = 2;
80
- // prop: shadowAlpha
81
- // transparency of the shadow (0 = transparent, 1 = opaque)
82
- this.shadowAlpha = 0.07;
83
- // prop: shadowDepth
84
- // number of strokes to apply to the shadow,
85
- // each stroke offset shadowOffset from the last.
86
- this.shadowDepth = 4;
87
- // prop: background
88
- // background color of the inside of the gauge.
89
- this.background = "#efefef";
90
- // prop: ringColor
91
- // color of the outer ring, hub, and needle of the gauge.
92
- this.ringColor = "#BBC6D0";
93
- // needle color not implemented yet.
94
- this.needleColor = "#C3D3E5";
95
- // prop: tickColor
96
- // color of the tick marks around the gauge.
97
- this.tickColor = "#989898";
98
- // prop: ringWidth
99
- // width of the ring around the gauge. Auto computed by default.
100
- this.ringWidth = null;
101
- // prop: min
102
- // Minimum value on the gauge. Auto computed by default
103
- this.min;
104
- // prop: max
105
- // Maximum value on the gauge. Auto computed by default
106
- this.max;
107
- // prop: ticks
108
- // Array of tick values. Auto computed by default.
109
- this.ticks = [];
110
- // prop: showTicks
111
- // true to show ticks around gauge.
112
- this.showTicks = true;
113
- // prop: showTickLabels
114
- // true to show tick labels next to ticks.
115
- this.showTickLabels = true;
116
- // prop: label
117
- // A gauge label like 'kph' or 'Volts'
118
- this.label = null;
119
- // prop: labelHeightAdjust
120
- // Number of Pixels to offset the label up (-) or down (+) from its default position.
121
- this.labelHeightAdjust = 0;
122
- // prop: labelPosition
123
- // Where to position the label, either 'inside' or 'bottom'.
124
- this.labelPosition = 'inside';
125
- // prop: intervals
126
- // Array of ranges to be drawn around the gauge.
127
- // Array of form:
128
- // > [value1, value2, ...]
129
- // indicating the values for the first, second, ... intervals.
130
- this.intervals = [];
131
- // prop: intervalColors
132
- // Array of colors to use for the intervals.
133
- this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"];
134
- // prop: intervalInnerRadius
135
- // Radius of the inner circle of the interval ring.
136
- this.intervalInnerRadius = null;
137
- // prop: intervalOuterRadius
138
- // Radius of the outer circle of the interval ring.
139
- this.intervalOuterRadius = null;
140
- this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
141
- // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc.
142
- this.tickPositions = [1, 2, 2.5, 5, 10];
143
- // prop: tickSpacing
144
- // Degrees between ticks. This is a target number, if
145
- // incompatible span and ticks are supplied, a suitable
146
- // spacing close to this value will be computed.
147
- this.tickSpacing = 30;
148
- this.numberMinorTicks = null;
149
- // prop: hubRadius
150
- // Radius of the hub at the bottom center of gauge which the needle attaches to.
151
- // Auto computed by default
152
- this.hubRadius = null;
153
- // prop: tickPadding
154
- // padding of the tick marks to the outer ring and the tick labels to marks.
155
- // Auto computed by default.
156
- this.tickPadding = null;
157
- // prop: needleThickness
158
- // Maximum thickness the needle. Auto computed by default.
159
- this.needleThickness = null;
160
- // prop: needlePad
161
- // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value.
162
- this.needlePad = 6;
163
- // prop: pegNeedle
164
- // True will stop needle just below/above the min/max values if data is below/above min/max,
165
- // as if the meter is "pegged".
166
- this.pegNeedle = true;
167
- this._type = 'meterGauge';
168
-
169
- $.extend(true, this, options);
170
- this.type = null;
171
- this.numberTicks = null;
172
- this.tickInterval = null;
173
- // span, the sweep (in degrees) from min to max. This gauge is
174
- // a semi-circle.
175
- this.span = 180;
176
- // get rid of this nonsense
177
- // this.innerSpan = this.span;
178
- if (this.type == 'circular') {
179
- this.semiCircular = false;
180
- }
181
- else if (this.type != 'circular') {
182
- this.semiCircular = true;
183
- }
184
- else {
185
- this.semiCircular = (this.span <= 180) ? true : false;
186
- }
187
- this._tickPoints = [];
188
- // reference to label element.
189
- this._labelElem = null;
190
-
191
- // start the gauge at the beginning of the span
192
- this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180;
193
- this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180;
194
-
195
- this.setmin = !!(this.min == null);
196
- this.setmax = !!(this.max == null);
197
-
198
- // if given intervals and is an array of values, create labels and colors.
199
- if (this.intervals.length) {
200
- if (this.intervals[0].length == null || this.intervals.length == 1) {
201
- for (var i=0; i<this.intervals.length; i++) {
202
- this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]];
203
- }
204
- }
205
- else if (this.intervals[0].length == 2) {
206
- for (i=0; i<this.intervals.length; i++) {
207
- this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]];
208
- }
209
- }
210
- }
211
-
212
- // compute min, max and ticks if not supplied:
213
- if (this.ticks.length) {
214
- if (this.ticks[0].length == null || this.ticks[0].length == 1) {
215
- for (var i=0; i<this.ticks.length; i++) {
216
- this.ticks[i] = [this.ticks[i], this.ticks[i]];
217
- }
218
- }
219
- this.min = (this.min == null) ? this.ticks[0][0] : this.min;
220
- this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max;
221
- this.setmin = false;
222
- this.setmax = false;
223
- this.numberTicks = this.ticks.length;
224
- this.tickInterval = this.ticks[1][0] - this.ticks[0][0];
225
- this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11)));
226
- // use the first interal to calculate minor ticks;
227
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
228
- if (!this.numberMinorTicks) {
229
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
230
- }
231
- if (!this.numberMinorTicks) {
232
- this.numberMinorTicks = 1;
233
- }
234
- }
235
-
236
- else if (this.intervals.length) {
237
- this.min = (this.min == null) ? 0 : this.min;
238
- this.setmin = false;
239
- if (this.max == null) {
240
- if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) {
241
- this.max = this.intervals[this.intervals.length-1][0];
242
- this.setmax = false;
243
- }
244
- }
245
- else {
246
- this.setmax = false;
247
- }
248
- }
249
-
250
- else {
251
- // no ticks and no intervals supplied, put needle in middle
252
- this.min = (this.min == null) ? 0 : this.min;
253
- this.setmin = false;
254
- if (this.max == null) {
255
- this.max = this.data[0][1] * 1.25;
256
- this.setmax = true;
257
- }
258
- else {
259
- this.setmax = false;
260
- }
261
- }
262
- };
263
-
264
- $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) {
265
- // set gridData property. This will hold angle in radians of each data point.
266
- var stack = [];
267
- var td = [];
268
- var sa = this.startAngle;
269
- for (var i=0; i<this.data.length; i++){
270
- stack.push(this.data[i][1]);
271
- td.push([this.data[i][0]]);
272
- if (i>0) {
273
- stack[i] += stack[i-1];
274
- }
275
- }
276
- var fact = Math.PI*2/stack[stack.length - 1];
277
-
278
- for (var i=0; i<stack.length; i++) {
279
- td[i][1] = stack[i] * fact;
280
- }
281
- this.gridData = td;
282
- };
283
-
284
- $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) {
285
- var stack = [];
286
- var td = [];
287
- var sa = this.startAngle;
288
- for (var i=0; i<data.length; i++){
289
- stack.push(data[i][1]);
290
- td.push([data[i][0]]);
291
- if (i>0) {
292
- stack[i] += stack[i-1];
293
- }
294
- }
295
- var fact = Math.PI*2/stack[stack.length - 1];
296
-
297
- for (var i=0; i<stack.length; i++) {
298
- td[i][1] = stack[i] * fact;
299
- }
300
- return td;
301
- };
302
-
303
-
304
- function getnmt(pos, interval, fact) {
305
- var temp;
306
- for (var i=pos.length-1; i>=0; i--) {
307
- temp = interval/(pos[i] * Math.pow(10, fact));
308
- if (temp == 4 || temp == 5) {
309
- return temp - 1;
310
- }
311
- }
312
- return null;
313
- }
314
-
315
- // called with scope of series
316
- $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) {
317
- var i;
318
- var opts = (options != undefined) ? options : {};
319
- // offset and direction of offset due to legend placement
320
- var offx = 0;
321
- var offy = 0;
322
- var trans = 1;
323
- if (options.legendInfo && options.legendInfo.placement == 'inside') {
324
- var li = options.legendInfo;
325
- switch (li.location) {
326
- case 'nw':
327
- offx = li.width + li.xoffset;
328
- break;
329
- case 'w':
330
- offx = li.width + li.xoffset;
331
- break;
332
- case 'sw':
333
- offx = li.width + li.xoffset;
334
- break;
335
- case 'ne':
336
- offx = li.width + li.xoffset;
337
- trans = -1;
338
- break;
339
- case 'e':
340
- offx = li.width + li.xoffset;
341
- trans = -1;
342
- break;
343
- case 'se':
344
- offx = li.width + li.xoffset;
345
- trans = -1;
346
- break;
347
- case 'n':
348
- offy = li.height + li.yoffset;
349
- break;
350
- case 's':
351
- offy = li.height + li.yoffset;
352
- trans = -1;
353
- break;
354
- default:
355
- break;
356
- }
357
- }
358
-
359
-
360
-
361
- // pre-draw so can get its dimensions.
362
- if (this.label) {
363
- this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
364
- this.canvas._elem.after(this._labelElem);
365
- }
366
-
367
- var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
368
- var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
369
- var fill = (opts.fill != undefined) ? opts.fill : this.fill;
370
- var cw = ctx.canvas.width;
371
- var ch = ctx.canvas.height;
372
- if (this.padding == null) {
373
- this.padding = Math.round(Math.min(cw, ch)/30);
374
- }
375
- var w = cw - offx - 2 * this.padding;
376
- var h = ch - offy - 2 * this.padding;
377
- if (this.labelPosition == 'bottom' && this.label) {
378
- h -= this._labelElem.outerHeight(true);
379
- }
380
- var mindim = Math.min(w,h);
381
- var d = mindim;
382
-
383
- if (!this.diameter) {
384
- if (this.semiCircular) {
385
- if ( w >= 2*h) {
386
- if (!this.ringWidth) {
387
- this.ringWidth = 2*h/35;
388
- }
389
- this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
390
- this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
391
- this.diameter = 2 * (h - 2*this.innerPad);
392
- }
393
- else {
394
- if (!this.ringWidth) {
395
- this.ringWidth = w/35;
396
- }
397
- this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
398
- this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
399
- this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding;
400
- }
401
- // center taking into account legend and over draw for gauge bottom below hub.
402
- // this will be center of hub.
403
- this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)];
404
- }
405
- else {
406
- if (!this.ringWidth) {
407
- this.ringWidth = d/35;
408
- }
409
- this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
410
- this.innerPad = 0;
411
- this.diameter = d - this.ringWidth;
412
- // center in middle of canvas taking into account legend.
413
- // will be center of hub.
414
- this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy];
415
- }
416
- if (this._labelElem && this.labelPosition == 'bottom') {
417
- this._center[1] -= this._labelElem.outerHeight(true);
418
- }
419
-
420
- }
421
-
422
- this._radius = this.diameter/2;
423
-
424
- this.tickSpacing = 6000/this.diameter;
425
-
426
- if (!this.hubRadius) {
427
- this.hubRadius = this.diameter/18;
428
- }
429
-
430
- this.shadowOffset = 0.5 + this.ringWidth/9;
431
- this.shadowWidth = this.ringWidth*1;
432
-
433
- this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7);
434
- this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding;
435
- this.tickLength = (this.showTicks) ? this._radius/13 : 0;
436
-
437
- if (this.ticks.length == 0) {
438
- // no ticks, lets make some.
439
- var max = this.max,
440
- min = this.min,
441
- setmax = this.setmax,
442
- setmin = this.setmin,
443
- ti = (max - min) * this.tickSpacing / this.span;
444
- var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11)));
445
- var tp = (ti/Math.pow(10, tf));
446
- (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp);
447
- var t = this.tickPositions;
448
- var tpindex, nt;
449
-
450
- for (i=0; i<t.length; i++) {
451
- if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
452
- ti = t[i]*Math.pow(10, tf);
453
- tpindex = i;
454
- }
455
- }
456
-
457
- for (i=0; i<t.length; i++) {
458
- if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
459
- ti = t[i]*Math.pow(10, tf);
460
- nt = Math.ceil((max - min) / ti);
461
- }
462
- }
463
-
464
- // both max and min are free
465
- if (setmax && setmin) {
466
- var tmin = (min > 0) ? min - min % ti : min - min % ti - ti;
467
- if (!this.forceZero) {
468
- var diff = Math.min(min - tmin, 0.8*ti);
469
- var ntp = Math.floor(diff/t[tpindex]);
470
- if (ntp > 1) {
471
- tmin = tmin + t[tpindex] * (ntp-1);
472
- if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) {
473
- tmin = tmin - t[tpindex];
474
- }
475
- }
476
- }
477
- if (min == tmin) {
478
- min -= ti;
479
- }
480
- else {
481
- // tmin should always be lower than dataMin
482
- if (min - tmin > 0.23*ti) {
483
- min = tmin;
484
- }
485
- else {
486
- min = tmin -ti;
487
- nt += 1;
488
- }
489
- }
490
- nt += 1;
491
- var tmax = min + (nt - 1) * ti;
492
- if (max >= tmax) {
493
- tmax += ti;
494
- nt += 1;
495
- }
496
- // now tmax should always be mroe than dataMax
497
- if (tmax - max < 0.23*ti) {
498
- tmax += ti;
499
- nt += 1;
500
- }
501
- this.max = max = tmax;
502
- this.min = min;
503
-
504
- this.tickInterval = ti;
505
- this.numberTicks = nt;
506
- var it;
507
- for (i=0; i<nt; i++) {
508
- it = parseFloat((min+i*ti).toFixed(11));
509
- this.ticks.push([it, it]);
510
- }
511
- this.max = this.ticks[nt-1][1];
512
-
513
- this.tickFactor = tf;
514
- // determine number of minor ticks
515
-
516
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
517
-
518
- if (!this.numberMinorTicks) {
519
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
520
- }
521
- }
522
- // max is free, min is fixed
523
- else if (setmax) {
524
- var tmax = min + (nt - 1) * ti;
525
- if (max >= tmax) {
526
- max = tmax + ti;
527
- nt += 1;
528
- }
529
- else {
530
- max = tmax;
531
- }
532
-
533
- this.tickInterval = this.tickInterval || ti;
534
- this.numberTicks = this.numberTicks || nt;
535
- var it;
536
- for (i=0; i<this.numberTicks; i++) {
537
- it = parseFloat((min+i*this.tickInterval).toFixed(11));
538
- this.ticks.push([it, it]);
539
- }
540
- this.max = this.ticks[this.numberTicks-1][1];
541
-
542
- this.tickFactor = tf;
543
- // determine number of minor ticks
544
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
545
-
546
- if (!this.numberMinorTicks) {
547
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
548
- }
549
- }
550
-
551
- // not setting max or min
552
- if (!setmax && !setmin) {
553
- var range = this.max - this.min;
554
- tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1;
555
- var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange;
556
- // check to see how many zeros are at the end of the range
557
- if (range > 1) {
558
- var rstr = String(range);
559
- if (rstr.search(/\./) == -1) {
560
- var pos = rstr.search(/0+$/);
561
- nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0;
562
- }
563
- }
564
- sigRange = range/Math.pow(10, nonSigDigits);
565
- for (i=0; i<nticks.length; i++) {
566
- res = sigRange/(nticks[i]-1);
567
- if (res == parseInt(res, 10)) {
568
- this.numberTicks = nticks[i];
569
- this.tickInterval = range/(this.numberTicks-1);
570
- this.tickFactor = tf+1;
571
- break;
572
- }
573
- }
574
- var it;
575
- for (i=0; i<this.numberTicks; i++) {
576
- it = parseFloat((this.min+i*this.tickInterval).toFixed(11));
577
- this.ticks.push([it, it]);
578
- }
579
- // determine number of minor ticks
580
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
581
-
582
- if (!this.numberMinorTicks) {
583
- this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
584
- }
585
-
586
- if (!this.numberMinorTicks) {
587
- this.numberMinorTicks = 1;
588
- var nums = [4, 5, 3, 6, 2];
589
- for (i=0; i<5; i++) {
590
- var temp = this.tickInterval/nums[i];
591
- if (temp == parseInt(temp, 10)) {
592
- this.numberMinorTicks = nums[i]-1;
593
- break;
594
- }
595
- }
596
- }
597
- }
598
- }
599
-
600
-
601
- var r = this._radius,
602
- sa = this.startAngle,
603
- ea = this.endAngle,
604
- pi = Math.PI,
605
- hpi = Math.PI/2;
606
-
607
- if (this.semiCircular) {
608
- var overAngle = Math.atan(this.innerPad/r),
609
- outersa = this.outerStartAngle = sa - overAngle,
610
- outerea = this.outerEndAngle = ea + overAngle,
611
- hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2),
612
- hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2);
613
-
614
- ctx.save();
615
-
616
- ctx.translate(this._center[0], this._center[1]);
617
- ctx.lineJoin = "round";
618
- ctx.lineCap = "round";
619
-
620
- // draw the innerbackground
621
- ctx.save();
622
- ctx.beginPath();
623
- ctx.fillStyle = this.background;
624
- ctx.arc(0, 0, r, outersa, outerea, false);
625
- ctx.closePath();
626
- ctx.fill();
627
- ctx.restore();
628
-
629
- // draw the shadow
630
- // the outer ring.
631
- var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
632
- ctx.save();
633
- for (var i=0; i<this.shadowDepth; i++) {
634
- ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
635
- ctx.beginPath();
636
- ctx.strokeStyle = shadowColor;
637
- ctx.lineWidth = this.shadowWidth;
638
- ctx.arc(0 ,0, r, outersa, outerea, false);
639
- ctx.closePath();
640
- ctx.stroke();
641
- }
642
- ctx.restore();
643
-
644
- // the inner hub.
645
- ctx.save();
646
- var tempd = parseInt((this.shadowDepth+1)/2, 10);
647
- for (var i=0; i<tempd; i++) {
648
- ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
649
- ctx.beginPath();
650
- ctx.fillStyle = shadowColor;
651
- ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false);
652
- ctx.closePath();
653
- ctx.fill();
654
- }
655
- ctx.restore();
656
-
657
- // draw the outer ring.
658
- ctx.save();
659
- ctx.beginPath();
660
- ctx.strokeStyle = this.ringColor;
661
- ctx.lineWidth = this.ringWidth;
662
- ctx.arc(0 ,0, r, outersa, outerea, false);
663
- ctx.closePath();
664
- ctx.stroke();
665
- ctx.restore();
666
-
667
- // draw the hub
668
-
669
- ctx.save();
670
- ctx.beginPath();
671
- ctx.fillStyle = this.ringColor;
672
- ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false);
673
- ctx.closePath();
674
- ctx.fill();
675
- ctx.restore();
676
-
677
- // draw the ticks
678
- if (this.showTicks) {
679
- ctx.save();
680
- var orad = this.tickOuterRadius,
681
- tl = this.tickLength,
682
- mtl = tl/2,
683
- nmt = this.numberMinorTicks,
684
- ts = this.span * Math.PI / 180 / (this.ticks.length-1),
685
- mts = ts/(nmt + 1);
686
-
687
- for (i = 0; i<this.ticks.length; i++) {
688
- ctx.beginPath();
689
- ctx.lineWidth = 1.5 + this.diameter/360;
690
- ctx.strokeStyle = this.ringColor;
691
- var wps = ts*i+sa;
692
- ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa));
693
- ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa));
694
- this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]);
695
- ctx.stroke();
696
- ctx.lineWidth = 1.0 + this.diameter/440;
697
- if (i<this.ticks.length-1) {
698
- for (var j=1; j<=nmt; j++) {
699
- ctx.beginPath();
700
- ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa));
701
- ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa));
702
- ctx.stroke();
703
- }
704
- }
705
- }
706
- ctx.restore();
707
- }
708
-
709
- // draw the tick labels
710
- if (this.showTickLabels) {
711
- var elem, l, t, ew, eh, dim, maxdim=0;
712
- var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
713
- for (i=0; i<this.ticks.length; i++) {
714
- elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>');
715
- this.canvas._elem.after(elem);
716
- ew = elem.outerWidth(true);
717
- eh = elem.outerHeight(true);
718
- l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]);
719
- t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ;
720
- // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]);
721
- elem.css({left:l, top:t, color: this.tickColor});
722
- dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2);
723
- maxdim = (dim > maxdim) ? dim : maxdim;
724
- }
725
- }
726
-
727
- // draw the gauge label
728
- if (this.label && this.labelPosition == 'inside') {
729
- var l = this._center[0] + this.canvas._offsets.left;
730
- var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
731
- var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust;
732
- // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
733
- // this.canvas._elem.after(this._labelElem);
734
- l -= this._labelElem.outerWidth(true)/2;
735
- t -= this._labelElem.outerHeight(true)/2;
736
- this._labelElem.css({left:l, top:t});
737
- }
738
-
739
- else if (this.label && this.labelPosition == 'bottom') {
740
- var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2;
741
- var t = this._center[1] + this.canvas._offsets.top + this.innerPad + this.ringWidth + this.padding + this.labelHeightAdjust;
742
- this._labelElem.css({left:l, top:t});
743
-
744
- }
745
-
746
- // draw the intervals
747
-
748
- ctx.save();
749
- var inner = this.intervalInnerRadius || this.hubRadius * 1.5;
750
- if (this.intervalOuterRadius == null) {
751
- if (this.showTickLabels) {
752
- var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8);
753
- }
754
- else {
755
- var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16);
756
- }
757
- }
758
- else {
759
- var outer = this.intervalOuterRadius;
760
- }
761
- var range = this.max - this.min;
762
- var intrange = this.intervals[this.intervals.length-1] - this.min;
763
- var start, end, span = this.span*Math.PI/180;
764
- for (i=0; i<this.intervals.length; i++) {
765
- start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range;
766
- if (start < 0) {
767
- start = 0;
768
- }
769
- end = sa + (this.intervals[i][0] - this.min)*span/range;
770
- if (end < 0) {
771
- end = 0;
772
- }
773
- ctx.beginPath();
774
- ctx.fillStyle = this.intervals[i][2];
775
- ctx.arc(0, 0, inner, start, end, false);
776
- ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end));
777
- ctx.arc(0, 0, outer, end, start, true);
778
- ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start));
779
- ctx.closePath();
780
- ctx.fill();
781
- }
782
- ctx.restore();
783
-
784
- // draw the needle
785
- var datapoint = this.data[0][1];
786
- var dataspan = this.max - this.min;
787
- if (this.pegNeedle) {
788
- if (this.data[0][1] > this.max + dataspan*3/this.span) {
789
- datapoint = this.max + dataspan*3/this.span;
790
- }
791
- if (this.data[0][1] < this.min - dataspan*3/this.span) {
792
- datapoint = this.min - dataspan*3/this.span;
793
- }
794
- }
795
- var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle;
796
-
797
-
798
- ctx.save();
799
- ctx.beginPath();
800
- ctx.fillStyle = this.ringColor;
801
- ctx.strokeStyle = this.ringColor;
802
- this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85;
803
- this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness;
804
- var endwidth = this.needleThickness * 0.4;
805
-
806
-
807
- var dl = this.needleLength/10;
808
- var dt = (this.needleThickness - endwidth)/10;
809
- var templ;
810
- for (var i=0; i<10; i++) {
811
- templ = this.needleThickness - i*dt;
812
- ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang));
813
- ctx.lineWidth = templ;
814
- ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang));
815
- ctx.stroke();
816
- }
817
-
818
- ctx.restore();
819
- }
820
- else {
821
- this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
822
- }
823
- };
824
-
825
- $.jqplot.MeterGaugeAxisRenderer = function() {
826
- $.jqplot.LinearAxisRenderer.call(this);
827
- };
828
-
829
- $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
830
- $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer;
831
-
832
-
833
- // There are no traditional axes on a gauge chart. We just need to provide
834
- // dummy objects with properties so the plot will render.
835
- // called with scope of axis object.
836
- $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){
837
- //
838
- this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
839
- $.extend(true, this, options);
840
- // I don't think I'm going to need _dataBounds here.
841
- // have to go Axis scaling in a way to fit chart onto plot area
842
- // and provide u2p and p2u functionality for mouse cursor, etc.
843
- // for convienence set _dataBounds to 0 and 100 and
844
- // set min/max to 0 and 100.
845
- this._dataBounds = {min:0, max:100};
846
- this.min = 0;
847
- this.max = 100;
848
- this.showTicks = false;
849
- this.ticks = [];
850
- this.showMark = false;
851
- this.show = false;
852
- };
853
-
854
- $.jqplot.MeterGaugeLegendRenderer = function(){
855
- $.jqplot.TableLegendRenderer.call(this);
856
- };
857
-
858
- $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
859
- $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer;
860
-
861
- /**
862
- * Class: $.jqplot.MeterGaugeLegendRenderer
863
- *Meter gauges don't typically have a legend, this overrides the default legend renderer.
864
- */
865
- $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) {
866
- // Maximum number of rows in the legend. 0 or null for unlimited.
867
- this.numberRows = null;
868
- // Maximum number of columns in the legend. 0 or null for unlimited.
869
- this.numberColumns = null;
870
- $.extend(true, this, options);
871
- };
872
-
873
- // called with context of legend
874
- $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() {
875
- if (this.show) {
876
- var series = this._series;
877
- var ss = 'position:absolute;';
878
- ss += (this.background) ? 'background:'+this.background+';' : '';
879
- ss += (this.border) ? 'border:'+this.border+';' : '';
880
- ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
881
- ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
882
- ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
883
- ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
884
- ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
885
- ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
886
- ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
887
- this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
888
- // MeterGauge charts legends don't go by number of series, but by number of data points
889
- // in the series. Refactor things here for that.
890
-
891
- var pad = false,
892
- reverse = false,
893
- nr, nc;
894
- var s = series[0];
895
-
896
- if (s.show) {
897
- var pd = s.data;
898
- if (this.numberRows) {
899
- nr = this.numberRows;
900
- if (!this.numberColumns){
901
- nc = Math.ceil(pd.length/nr);
902
- }
903
- else{
904
- nc = this.numberColumns;
905
- }
906
- }
907
- else if (this.numberColumns) {
908
- nc = this.numberColumns;
909
- nr = Math.ceil(pd.length/this.numberColumns);
910
- }
911
- else {
912
- nr = pd.length;
913
- nc = 1;
914
- }
915
-
916
- var i, j, tr, td1, td2, lt, rs, color;
917
- var idx = 0;
918
-
919
- for (i=0; i<nr; i++) {
920
- if (reverse){
921
- tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
922
- }
923
- else{
924
- tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
925
- }
926
- for (j=0; j<nc; j++) {
927
- if (idx < pd.length){
928
- // debugger
929
- lt = this.labels[idx] || pd[idx][0].toString();
930
- color = s.color;
931
- if (!reverse){
932
- if (i>0){
933
- pad = true;
934
- }
935
- else{
936
- pad = false;
937
- }
938
- }
939
- else{
940
- if (i == nr -1){
941
- pad = false;
942
- }
943
- else{
944
- pad = true;
945
- }
946
- }
947
- rs = (pad) ? this.rowSpacing : '0';
948
-
949
- td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
950
- '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
951
- '</div></td>');
952
- td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
953
- if (this.escapeHtml){
954
- td2.text(lt);
955
- }
956
- else {
957
- td2.html(lt);
958
- }
959
- if (reverse) {
960
- td2.prependTo(tr);
961
- td1.prependTo(tr);
962
- }
963
- else {
964
- td1.appendTo(tr);
965
- td2.appendTo(tr);
966
- }
967
- pad = true;
968
- }
969
- idx++;
970
- }
971
- }
972
- }
973
- }
974
- return this._elem;
975
- };
976
-
977
-
978
- // setup default renderers for axes and legend so user doesn't have to
979
- // called with scope of plot
980
- function preInit(target, data, options) {
981
- // debugger
982
- options = options || {};
983
- options.axesDefaults = options.axesDefaults || {};
984
- options.legend = options.legend || {};
985
- options.seriesDefaults = options.seriesDefaults || {};
986
- options.grid = options.grid || {};
987
-
988
- // only set these if there is a gauge series
989
- var setopts = false;
990
- if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) {
991
- setopts = true;
992
- }
993
- else if (options.series) {
994
- for (var i=0; i < options.series.length; i++) {
995
- if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) {
996
- setopts = true;
997
- }
998
- }
999
- }
1000
-
1001
- if (setopts) {
1002
- options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer;
1003
- options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer;
1004
- options.legend.preDraw = true;
1005
- options.grid.background = options.grid.background || 'white';
1006
- options.grid.drawGridlines = false;
1007
- options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0;
1008
- options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false;
1009
- }
1010
- }
1011
-
1012
- // called with scope of plot
1013
- function postParseOptions(options) {
1014
- //
1015
- }
1016
-
1017
- $.jqplot.preInitHooks.push(preInit);
1018
- $.jqplot.postParseOptionsHooks.push(postParseOptions);
1019
-
1020
- $.jqplot.MeterGaugeTickRenderer = function() {
1021
- $.jqplot.AxisTickRenderer.call(this);
1022
- };
1023
-
1024
- $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
1025
- $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer;
1026
-
1027
- })(jQuery);
1028
-
1029
-
1
+ /**
2
+ * jqPlot
3
+ * Pure JavaScript plotting plugin using jQuery
4
+ *
5
+ * Version: 1.0.9
6
+ * Revision: d96a669
7
+ *
8
+ * Copyright (c) 2009-2016 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.MeterGaugeRenderer
34
+ * Plugin renderer to draw a meter gauge chart.
35
+ *
36
+ * Data consists of a single series with 1 data point to position the gauge needle.
37
+ *
38
+ * To use this renderer, you need to include the
39
+ * meter gauge renderer plugin, for example:
40
+ *
41
+ * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script>
42
+ *
43
+ * Properties described here are passed into the $.jqplot function
44
+ * as options on the series renderer. For example:
45
+ *
46
+ * > plot0 = $.jqplot('chart0',[[18]],{
47
+ * > title: 'Network Speed',
48
+ * > seriesDefaults: {
49
+ * > renderer: $.jqplot.MeterGaugeRenderer,
50
+ * > rendererOptions: {
51
+ * > label: 'MB/s'
52
+ * > }
53
+ * > }
54
+ * > });
55
+ *
56
+ * A meterGauge plot does not support events.
57
+ */
58
+ $.jqplot.MeterGaugeRenderer = function(){
59
+ $.jqplot.LineRenderer.call(this);
60
+ };
61
+
62
+ $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer();
63
+ $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer;
64
+
65
+ // called with scope of a series
66
+ $.jqplot.MeterGaugeRenderer.prototype.init = function(options) {
67
+ // Group: Properties
68
+ //
69
+ // prop: diameter
70
+ // Outer diameter of the meterGauge, auto computed by default
71
+ this.diameter = null;
72
+ // prop: padding
73
+ // padding between the meterGauge and plot edges, auto
74
+ // calculated by default.
75
+ this.padding = null;
76
+ // prop: shadowOffset
77
+ // offset of the shadow from the gauge ring and offset of
78
+ // each succesive stroke of the shadow from the last.
79
+ this.shadowOffset = 2;
80
+ // prop: shadowAlpha
81
+ // transparency of the shadow (0 = transparent, 1 = opaque)
82
+ this.shadowAlpha = 0.07;
83
+ // prop: shadowDepth
84
+ // number of strokes to apply to the shadow,
85
+ // each stroke offset shadowOffset from the last.
86
+ this.shadowDepth = 4;
87
+ // prop: background
88
+ // background color of the inside of the gauge.
89
+ this.background = "#efefef";
90
+ // prop: ringColor
91
+ // color of the outer ring, hub, and needle of the gauge.
92
+ this.ringColor = "#BBC6D0";
93
+ // needle color not implemented yet.
94
+ this.needleColor = "#C3D3E5";
95
+ // prop: tickColor
96
+ // color of the tick marks around the gauge.
97
+ this.tickColor = "#989898";
98
+ // prop: ringWidth
99
+ // width of the ring around the gauge. Auto computed by default.
100
+ this.ringWidth = null;
101
+ // prop: min
102
+ // Minimum value on the gauge. Auto computed by default
103
+ this.min;
104
+ // prop: max
105
+ // Maximum value on the gauge. Auto computed by default
106
+ this.max;
107
+ // prop: ticks
108
+ // Array of tick values. Auto computed by default.
109
+ this.ticks = [];
110
+ // prop: showTicks
111
+ // true to show ticks around gauge.
112
+ this.showTicks = true;
113
+ // prop: showTickLabels
114
+ // true to show tick labels next to ticks.
115
+ this.showTickLabels = true;
116
+ // prop: label
117
+ // A gauge label like 'kph' or 'Volts'
118
+ this.label = null;
119
+ // prop: labelHeightAdjust
120
+ // Number of Pixels to offset the label up (-) or down (+) from its default position.
121
+ this.labelHeightAdjust = 0;
122
+ // prop: labelPosition
123
+ // Where to position the label, either 'inside' or 'bottom'.
124
+ this.labelPosition = 'inside';
125
+ // prop: intervals
126
+ // Array of ranges to be drawn around the gauge.
127
+ // Array of form:
128
+ // > [value1, value2, ...]
129
+ // indicating the values for the first, second, ... intervals.
130
+ this.intervals = [];
131
+ // prop: intervalColors
132
+ // Array of colors to use for the intervals.
133
+ this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"];
134
+ // prop: intervalInnerRadius
135
+ // Radius of the inner circle of the interval ring.
136
+ this.intervalInnerRadius = null;
137
+ // prop: intervalOuterRadius
138
+ // Radius of the outer circle of the interval ring.
139
+ this.intervalOuterRadius = null;
140
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
141
+ // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc.
142
+ this.tickPositions = [1, 2, 2.5, 5, 10];
143
+ // prop: tickSpacing
144
+ // Degrees between ticks. This is a target number, if
145
+ // incompatible span and ticks are supplied, a suitable
146
+ // spacing close to this value will be computed.
147
+ this.tickSpacing = 30;
148
+ this.numberMinorTicks = null;
149
+ // prop: hubRadius
150
+ // Radius of the hub at the bottom center of gauge which the needle attaches to.
151
+ // Auto computed by default
152
+ this.hubRadius = null;
153
+ // prop: tickPadding
154
+ // padding of the tick marks to the outer ring and the tick labels to marks.
155
+ // Auto computed by default.
156
+ this.tickPadding = null;
157
+ // prop: needleThickness
158
+ // Maximum thickness the needle. Auto computed by default.
159
+ this.needleThickness = null;
160
+ // prop: needlePad
161
+ // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value.
162
+ this.needlePad = 6;
163
+ // prop: pegNeedle
164
+ // True will stop needle just below/above the min/max values if data is below/above min/max,
165
+ // as if the meter is "pegged".
166
+ this.pegNeedle = true;
167
+ this._type = 'meterGauge';
168
+
169
+ $.extend(true, this, options);
170
+ this.type = null;
171
+ this.numberTicks = null;
172
+ this.tickInterval = null;
173
+ // span, the sweep (in degrees) from min to max. This gauge is
174
+ // a semi-circle.
175
+ this.span = 180;
176
+ // get rid of this nonsense
177
+ // this.innerSpan = this.span;
178
+ if (this.type == 'circular') {
179
+ this.semiCircular = false;
180
+ }
181
+ else if (this.type != 'circular') {
182
+ this.semiCircular = true;
183
+ }
184
+ else {
185
+ this.semiCircular = (this.span <= 180) ? true : false;
186
+ }
187
+ this._tickPoints = [];
188
+ // reference to label element.
189
+ this._labelElem = null;
190
+
191
+ // start the gauge at the beginning of the span
192
+ this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180;
193
+ this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180;
194
+
195
+ this.setmin = !!(this.min == null);
196
+ this.setmax = !!(this.max == null);
197
+
198
+ // if given intervals and is an array of values, create labels and colors.
199
+ if (this.intervals.length) {
200
+ if (this.intervals[0].length == null || this.intervals.length == 1) {
201
+ for (var i=0; i<this.intervals.length; i++) {
202
+ this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]];
203
+ }
204
+ }
205
+ else if (this.intervals[0].length == 2) {
206
+ for (i=0; i<this.intervals.length; i++) {
207
+ this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]];
208
+ }
209
+ }
210
+ }
211
+
212
+ // compute min, max and ticks if not supplied:
213
+ if (this.ticks.length) {
214
+ if (this.ticks[0].length == null || this.ticks[0].length == 1) {
215
+ for (var i=0; i<this.ticks.length; i++) {
216
+ this.ticks[i] = [this.ticks[i], this.ticks[i]];
217
+ }
218
+ }
219
+ this.min = (this.min == null) ? this.ticks[0][0] : this.min;
220
+ this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max;
221
+ this.setmin = false;
222
+ this.setmax = false;
223
+ this.numberTicks = this.ticks.length;
224
+ this.tickInterval = this.ticks[1][0] - this.ticks[0][0];
225
+ this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11)));
226
+ // use the first interal to calculate minor ticks;
227
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
228
+ if (!this.numberMinorTicks) {
229
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
230
+ }
231
+ if (!this.numberMinorTicks) {
232
+ this.numberMinorTicks = 1;
233
+ }
234
+ }
235
+
236
+ else if (this.intervals.length) {
237
+ this.min = (this.min == null) ? 0 : this.min;
238
+ this.setmin = false;
239
+ if (this.max == null) {
240
+ if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) {
241
+ this.max = this.intervals[this.intervals.length-1][0];
242
+ this.setmax = false;
243
+ }
244
+ }
245
+ else {
246
+ this.setmax = false;
247
+ }
248
+ }
249
+
250
+ else {
251
+ // no ticks and no intervals supplied, put needle in middle
252
+ this.min = (this.min == null) ? 0 : this.min;
253
+ this.setmin = false;
254
+ if (this.max == null) {
255
+ this.max = this.data[0][1] * 1.25;
256
+ this.setmax = true;
257
+ }
258
+ else {
259
+ this.setmax = false;
260
+ }
261
+ }
262
+ };
263
+
264
+ $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) {
265
+ // set gridData property. This will hold angle in radians of each data point.
266
+ var stack = [];
267
+ var td = [];
268
+ var sa = this.startAngle;
269
+ for (var i=0; i<this.data.length; i++){
270
+ stack.push(this.data[i][1]);
271
+ td.push([this.data[i][0]]);
272
+ if (i>0) {
273
+ stack[i] += stack[i-1];
274
+ }
275
+ }
276
+ var fact = Math.PI*2/stack[stack.length - 1];
277
+
278
+ for (var i=0; i<stack.length; i++) {
279
+ td[i][1] = stack[i] * fact;
280
+ }
281
+ this.gridData = td;
282
+ };
283
+
284
+ $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) {
285
+ var stack = [];
286
+ var td = [];
287
+ var sa = this.startAngle;
288
+ for (var i=0; i<data.length; i++){
289
+ stack.push(data[i][1]);
290
+ td.push([data[i][0]]);
291
+ if (i>0) {
292
+ stack[i] += stack[i-1];
293
+ }
294
+ }
295
+ var fact = Math.PI*2/stack[stack.length - 1];
296
+
297
+ for (var i=0; i<stack.length; i++) {
298
+ td[i][1] = stack[i] * fact;
299
+ }
300
+ return td;
301
+ };
302
+
303
+
304
+ function getnmt(pos, interval, fact) {
305
+ var temp;
306
+ for (var i=pos.length-1; i>=0; i--) {
307
+ temp = interval/(pos[i] * Math.pow(10, fact));
308
+ if (temp == 4 || temp == 5) {
309
+ return temp - 1;
310
+ }
311
+ }
312
+ return null;
313
+ }
314
+
315
+ // called with scope of series
316
+ $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) {
317
+ var i;
318
+ var opts = (options != undefined) ? options : {};
319
+ // offset and direction of offset due to legend placement
320
+ var offx = 0;
321
+ var offy = 0;
322
+ var trans = 1;
323
+ if (options.legendInfo && options.legendInfo.placement == 'inside') {
324
+ var li = options.legendInfo;
325
+ switch (li.location) {
326
+ case 'nw':
327
+ offx = li.width + li.xoffset;
328
+ break;
329
+ case 'w':
330
+ offx = li.width + li.xoffset;
331
+ break;
332
+ case 'sw':
333
+ offx = li.width + li.xoffset;
334
+ break;
335
+ case 'ne':
336
+ offx = li.width + li.xoffset;
337
+ trans = -1;
338
+ break;
339
+ case 'e':
340
+ offx = li.width + li.xoffset;
341
+ trans = -1;
342
+ break;
343
+ case 'se':
344
+ offx = li.width + li.xoffset;
345
+ trans = -1;
346
+ break;
347
+ case 'n':
348
+ offy = li.height + li.yoffset;
349
+ break;
350
+ case 's':
351
+ offy = li.height + li.yoffset;
352
+ trans = -1;
353
+ break;
354
+ default:
355
+ break;
356
+ }
357
+ }
358
+
359
+
360
+
361
+ // pre-draw so can get its dimensions.
362
+ if (this.label) {
363
+ this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
364
+ this.canvas._elem.after(this._labelElem);
365
+ }
366
+
367
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
368
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
369
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
370
+ var cw = ctx.canvas.width;
371
+ var ch = ctx.canvas.height;
372
+ if (this.padding == null) {
373
+ this.padding = Math.round(Math.min(cw, ch)/30);
374
+ }
375
+ var w = cw - offx - 2 * this.padding;
376
+ var h = ch - offy - 2 * this.padding;
377
+ if (this.labelPosition == 'bottom' && this.label) {
378
+ h -= this._labelElem.outerHeight(true);
379
+ }
380
+ var mindim = Math.min(w,h);
381
+ var d = mindim;
382
+
383
+ if (!this.diameter) {
384
+ if (this.semiCircular) {
385
+ if ( w >= 2*h) {
386
+ if (!this.ringWidth) {
387
+ this.ringWidth = 2*h/35;
388
+ }
389
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
390
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
391
+ this.diameter = 2 * (h - 2*this.innerPad);
392
+ }
393
+ else {
394
+ if (!this.ringWidth) {
395
+ this.ringWidth = w/35;
396
+ }
397
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
398
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
399
+ this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding;
400
+ }
401
+ // center taking into account legend and over draw for gauge bottom below hub.
402
+ // this will be center of hub.
403
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)];
404
+ }
405
+ else {
406
+ if (!this.ringWidth) {
407
+ this.ringWidth = d/35;
408
+ }
409
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
410
+ this.innerPad = 0;
411
+ this.diameter = d - this.ringWidth;
412
+ // center in middle of canvas taking into account legend.
413
+ // will be center of hub.
414
+ this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy];
415
+ }
416
+ if (this._labelElem && this.labelPosition == 'bottom') {
417
+ this._center[1] -= this._labelElem.outerHeight(true);
418
+ }
419
+
420
+ }
421
+
422
+ this._radius = this.diameter/2;
423
+
424
+ this.tickSpacing = 6000/this.diameter;
425
+
426
+ if (!this.hubRadius) {
427
+ this.hubRadius = this.diameter/18;
428
+ }
429
+
430
+ this.shadowOffset = 0.5 + this.ringWidth/9;
431
+ this.shadowWidth = this.ringWidth*1;
432
+
433
+ this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7);
434
+ this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding;
435
+ this.tickLength = (this.showTicks) ? this._radius/13 : 0;
436
+
437
+ if (this.ticks.length == 0) {
438
+ // no ticks, lets make some.
439
+ var max = this.max,
440
+ min = this.min,
441
+ setmax = this.setmax,
442
+ setmin = this.setmin,
443
+ ti = (max - min) * this.tickSpacing / this.span;
444
+ var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11)));
445
+ var tp = (ti/Math.pow(10, tf));
446
+ (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp);
447
+ var t = this.tickPositions;
448
+ var tpindex, nt;
449
+
450
+ for (i=0; i<t.length; i++) {
451
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
452
+ ti = t[i]*Math.pow(10, tf);
453
+ tpindex = i;
454
+ }
455
+ }
456
+
457
+ for (i=0; i<t.length; i++) {
458
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
459
+ ti = t[i]*Math.pow(10, tf);
460
+ nt = Math.ceil((max - min) / ti);
461
+ }
462
+ }
463
+
464
+ // both max and min are free
465
+ if (setmax && setmin) {
466
+ var tmin = (min > 0) ? min - min % ti : min - min % ti - ti;
467
+ if (!this.forceZero) {
468
+ var diff = Math.min(min - tmin, 0.8*ti);
469
+ var ntp = Math.floor(diff/t[tpindex]);
470
+ if (ntp > 1) {
471
+ tmin = tmin + t[tpindex] * (ntp-1);
472
+ if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) {
473
+ tmin = tmin - t[tpindex];
474
+ }
475
+ }
476
+ }
477
+ if (min == tmin) {
478
+ min -= ti;
479
+ }
480
+ else {
481
+ // tmin should always be lower than dataMin
482
+ if (min - tmin > 0.23*ti) {
483
+ min = tmin;
484
+ }
485
+ else {
486
+ min = tmin -ti;
487
+ nt += 1;
488
+ }
489
+ }
490
+ nt += 1;
491
+ var tmax = min + (nt - 1) * ti;
492
+ if (max >= tmax) {
493
+ tmax += ti;
494
+ nt += 1;
495
+ }
496
+ // now tmax should always be mroe than dataMax
497
+ if (tmax - max < 0.23*ti) {
498
+ tmax += ti;
499
+ nt += 1;
500
+ }
501
+ this.max = max = tmax;
502
+ this.min = min;
503
+
504
+ this.tickInterval = ti;
505
+ this.numberTicks = nt;
506
+ var it;
507
+ for (i=0; i<nt; i++) {
508
+ it = parseFloat((min+i*ti).toFixed(11));
509
+ this.ticks.push([it, it]);
510
+ }
511
+ this.max = this.ticks[nt-1][1];
512
+
513
+ this.tickFactor = tf;
514
+ // determine number of minor ticks
515
+
516
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
517
+
518
+ if (!this.numberMinorTicks) {
519
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
520
+ }
521
+ }
522
+ // max is free, min is fixed
523
+ else if (setmax) {
524
+ var tmax = min + (nt - 1) * ti;
525
+ if (max >= tmax) {
526
+ max = tmax + ti;
527
+ nt += 1;
528
+ }
529
+ else {
530
+ max = tmax;
531
+ }
532
+
533
+ this.tickInterval = this.tickInterval || ti;
534
+ this.numberTicks = this.numberTicks || nt;
535
+ var it;
536
+ for (i=0; i<this.numberTicks; i++) {
537
+ it = parseFloat((min+i*this.tickInterval).toFixed(11));
538
+ this.ticks.push([it, it]);
539
+ }
540
+ this.max = this.ticks[this.numberTicks-1][1];
541
+
542
+ this.tickFactor = tf;
543
+ // determine number of minor ticks
544
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
545
+
546
+ if (!this.numberMinorTicks) {
547
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
548
+ }
549
+ }
550
+
551
+ // not setting max or min
552
+ if (!setmax && !setmin) {
553
+ var range = this.max - this.min;
554
+ tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1;
555
+ var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange;
556
+ // check to see how many zeros are at the end of the range
557
+ if (range > 1) {
558
+ var rstr = String(range);
559
+ if (rstr.search(/\./) == -1) {
560
+ var pos = rstr.search(/0+$/);
561
+ nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0;
562
+ }
563
+ }
564
+ sigRange = range/Math.pow(10, nonSigDigits);
565
+ for (i=0; i<nticks.length; i++) {
566
+ res = sigRange/(nticks[i]-1);
567
+ if (res == parseInt(res, 10)) {
568
+ this.numberTicks = nticks[i];
569
+ this.tickInterval = range/(this.numberTicks-1);
570
+ this.tickFactor = tf+1;
571
+ break;
572
+ }
573
+ }
574
+ var it;
575
+ for (i=0; i<this.numberTicks; i++) {
576
+ it = parseFloat((this.min+i*this.tickInterval).toFixed(11));
577
+ this.ticks.push([it, it]);
578
+ }
579
+ // determine number of minor ticks
580
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
581
+
582
+ if (!this.numberMinorTicks) {
583
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
584
+ }
585
+
586
+ if (!this.numberMinorTicks) {
587
+ this.numberMinorTicks = 1;
588
+ var nums = [4, 5, 3, 6, 2];
589
+ for (i=0; i<5; i++) {
590
+ var temp = this.tickInterval/nums[i];
591
+ if (temp == parseInt(temp, 10)) {
592
+ this.numberMinorTicks = nums[i]-1;
593
+ break;
594
+ }
595
+ }
596
+ }
597
+ }
598
+ }
599
+
600
+
601
+ var r = this._radius,
602
+ sa = this.startAngle,
603
+ ea = this.endAngle,
604
+ pi = Math.PI,
605
+ hpi = Math.PI/2;
606
+
607
+ if (this.semiCircular) {
608
+ var overAngle = Math.atan(this.innerPad/r),
609
+ outersa = this.outerStartAngle = sa - overAngle,
610
+ outerea = this.outerEndAngle = ea + overAngle,
611
+ hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2),
612
+ hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2);
613
+
614
+ ctx.save();
615
+
616
+ ctx.translate(this._center[0], this._center[1]);
617
+ ctx.lineJoin = "round";
618
+ ctx.lineCap = "round";
619
+
620
+ // draw the innerbackground
621
+ ctx.save();
622
+ ctx.beginPath();
623
+ ctx.fillStyle = this.background;
624
+ ctx.arc(0, 0, r, outersa, outerea, false);
625
+ ctx.closePath();
626
+ ctx.fill();
627
+ ctx.restore();
628
+
629
+ // draw the shadow
630
+ // the outer ring.
631
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
632
+ ctx.save();
633
+ for (var i=0; i<this.shadowDepth; i++) {
634
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
635
+ ctx.beginPath();
636
+ ctx.strokeStyle = shadowColor;
637
+ ctx.lineWidth = this.shadowWidth;
638
+ ctx.arc(0 ,0, r, outersa, outerea, false);
639
+ ctx.closePath();
640
+ ctx.stroke();
641
+ }
642
+ ctx.restore();
643
+
644
+ // the inner hub.
645
+ ctx.save();
646
+ var tempd = parseInt((this.shadowDepth+1)/2, 10);
647
+ for (var i=0; i<tempd; i++) {
648
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
649
+ ctx.beginPath();
650
+ ctx.fillStyle = shadowColor;
651
+ ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false);
652
+ ctx.closePath();
653
+ ctx.fill();
654
+ }
655
+ ctx.restore();
656
+
657
+ // draw the outer ring.
658
+ ctx.save();
659
+ ctx.beginPath();
660
+ ctx.strokeStyle = this.ringColor;
661
+ ctx.lineWidth = this.ringWidth;
662
+ ctx.arc(0 ,0, r, outersa, outerea, false);
663
+ ctx.closePath();
664
+ ctx.stroke();
665
+ ctx.restore();
666
+
667
+ // draw the hub
668
+
669
+ ctx.save();
670
+ ctx.beginPath();
671
+ ctx.fillStyle = this.ringColor;
672
+ ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false);
673
+ ctx.closePath();
674
+ ctx.fill();
675
+ ctx.restore();
676
+
677
+ // draw the ticks
678
+ if (this.showTicks) {
679
+ ctx.save();
680
+ var orad = this.tickOuterRadius,
681
+ tl = this.tickLength,
682
+ mtl = tl/2,
683
+ nmt = this.numberMinorTicks,
684
+ ts = this.span * Math.PI / 180 / (this.ticks.length-1),
685
+ mts = ts/(nmt + 1);
686
+
687
+ for (i = 0; i<this.ticks.length; i++) {
688
+ ctx.beginPath();
689
+ ctx.lineWidth = 1.5 + this.diameter/360;
690
+ ctx.strokeStyle = this.ringColor;
691
+ var wps = ts*i+sa;
692
+ ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa));
693
+ ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa));
694
+ this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]);
695
+ ctx.stroke();
696
+ ctx.lineWidth = 1.0 + this.diameter/440;
697
+ if (i<this.ticks.length-1) {
698
+ for (var j=1; j<=nmt; j++) {
699
+ ctx.beginPath();
700
+ ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa));
701
+ ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa));
702
+ ctx.stroke();
703
+ }
704
+ }
705
+ }
706
+ ctx.restore();
707
+ }
708
+
709
+ // draw the tick labels
710
+ if (this.showTickLabels) {
711
+ var elem, l, t, ew, eh, dim, maxdim=0;
712
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
713
+ for (i=0; i<this.ticks.length; i++) {
714
+ elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>');
715
+ this.canvas._elem.after(elem);
716
+ ew = elem.outerWidth(true);
717
+ eh = elem.outerHeight(true);
718
+ l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]);
719
+ t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ;
720
+ // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]);
721
+ elem.css({left:l, top:t, color: this.tickColor});
722
+ dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2);
723
+ maxdim = (dim > maxdim) ? dim : maxdim;
724
+ }
725
+ }
726
+
727
+ // draw the gauge label
728
+ if (this.label && this.labelPosition == 'inside') {
729
+ var l = this._center[0] + this.canvas._offsets.left;
730
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
731
+ var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust;
732
+ // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
733
+ // this.canvas._elem.after(this._labelElem);
734
+ l -= this._labelElem.outerWidth(true)/2;
735
+ t -= this._labelElem.outerHeight(true)/2;
736
+ this._labelElem.css({left:l, top:t});
737
+ }
738
+
739
+ else if (this.label && this.labelPosition == 'bottom') {
740
+ var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2;
741
+ var t = this._center[1] + this.canvas._offsets.top + this.innerPad + this.ringWidth + this.padding + this.labelHeightAdjust;
742
+ this._labelElem.css({left:l, top:t});
743
+
744
+ }
745
+
746
+ // draw the intervals
747
+
748
+ ctx.save();
749
+ var inner = this.intervalInnerRadius || this.hubRadius * 1.5;
750
+ if (this.intervalOuterRadius == null) {
751
+ if (this.showTickLabels) {
752
+ var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8);
753
+ }
754
+ else {
755
+ var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16);
756
+ }
757
+ }
758
+ else {
759
+ var outer = this.intervalOuterRadius;
760
+ }
761
+ var range = this.max - this.min;
762
+ var intrange = this.intervals[this.intervals.length-1] - this.min;
763
+ var start, end, span = this.span*Math.PI/180;
764
+ for (i=0; i<this.intervals.length; i++) {
765
+ start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range;
766
+ if (start < 0) {
767
+ start = 0;
768
+ }
769
+ end = sa + (this.intervals[i][0] - this.min)*span/range;
770
+ if (end < 0) {
771
+ end = 0;
772
+ }
773
+ ctx.beginPath();
774
+ ctx.fillStyle = this.intervals[i][2];
775
+ ctx.arc(0, 0, inner, start, end, false);
776
+ ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end));
777
+ ctx.arc(0, 0, outer, end, start, true);
778
+ ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start));
779
+ ctx.closePath();
780
+ ctx.fill();
781
+ }
782
+ ctx.restore();
783
+
784
+ // draw the needle
785
+ var datapoint = this.data[0][1];
786
+ var dataspan = this.max - this.min;
787
+ if (this.pegNeedle) {
788
+ if (this.data[0][1] > this.max + dataspan*3/this.span) {
789
+ datapoint = this.max + dataspan*3/this.span;
790
+ }
791
+ if (this.data[0][1] < this.min - dataspan*3/this.span) {
792
+ datapoint = this.min - dataspan*3/this.span;
793
+ }
794
+ }
795
+ var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle;
796
+
797
+
798
+ ctx.save();
799
+ ctx.beginPath();
800
+ ctx.fillStyle = this.ringColor;
801
+ ctx.strokeStyle = this.ringColor;
802
+ this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85;
803
+ this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness;
804
+ var endwidth = this.needleThickness * 0.4;
805
+
806
+
807
+ var dl = this.needleLength/10;
808
+ var dt = (this.needleThickness - endwidth)/10;
809
+ var templ;
810
+ for (var i=0; i<10; i++) {
811
+ templ = this.needleThickness - i*dt;
812
+ ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang));
813
+ ctx.lineWidth = templ;
814
+ ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang));
815
+ ctx.stroke();
816
+ }
817
+
818
+ ctx.restore();
819
+ }
820
+ else {
821
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
822
+ }
823
+ };
824
+
825
+ $.jqplot.MeterGaugeAxisRenderer = function() {
826
+ $.jqplot.LinearAxisRenderer.call(this);
827
+ };
828
+
829
+ $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
830
+ $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer;
831
+
832
+
833
+ // There are no traditional axes on a gauge chart. We just need to provide
834
+ // dummy objects with properties so the plot will render.
835
+ // called with scope of axis object.
836
+ $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){
837
+ //
838
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
839
+ $.extend(true, this, options);
840
+ // I don't think I'm going to need _dataBounds here.
841
+ // have to go Axis scaling in a way to fit chart onto plot area
842
+ // and provide u2p and p2u functionality for mouse cursor, etc.
843
+ // for convienence set _dataBounds to 0 and 100 and
844
+ // set min/max to 0 and 100.
845
+ this._dataBounds = {min:0, max:100};
846
+ this.min = 0;
847
+ this.max = 100;
848
+ this.showTicks = false;
849
+ this.ticks = [];
850
+ this.showMark = false;
851
+ this.show = false;
852
+ };
853
+
854
+ $.jqplot.MeterGaugeLegendRenderer = function(){
855
+ $.jqplot.TableLegendRenderer.call(this);
856
+ };
857
+
858
+ $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
859
+ $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer;
860
+
861
+ /**
862
+ * Class: $.jqplot.MeterGaugeLegendRenderer
863
+ *Meter gauges don't typically have a legend, this overrides the default legend renderer.
864
+ */
865
+ $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) {
866
+ // Maximum number of rows in the legend. 0 or null for unlimited.
867
+ this.numberRows = null;
868
+ // Maximum number of columns in the legend. 0 or null for unlimited.
869
+ this.numberColumns = null;
870
+ $.extend(true, this, options);
871
+ };
872
+
873
+ // called with context of legend
874
+ $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() {
875
+ if (this.show) {
876
+ var series = this._series;
877
+ var ss = 'position:absolute;';
878
+ ss += (this.background) ? 'background:'+this.background+';' : '';
879
+ ss += (this.border) ? 'border:'+this.border+';' : '';
880
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
881
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
882
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
883
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
884
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
885
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
886
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
887
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
888
+ // MeterGauge charts legends don't go by number of series, but by number of data points
889
+ // in the series. Refactor things here for that.
890
+
891
+ var pad = false,
892
+ reverse = false,
893
+ nr, nc;
894
+ var s = series[0];
895
+
896
+ if (s.show) {
897
+ var pd = s.data;
898
+ if (this.numberRows) {
899
+ nr = this.numberRows;
900
+ if (!this.numberColumns){
901
+ nc = Math.ceil(pd.length/nr);
902
+ }
903
+ else{
904
+ nc = this.numberColumns;
905
+ }
906
+ }
907
+ else if (this.numberColumns) {
908
+ nc = this.numberColumns;
909
+ nr = Math.ceil(pd.length/this.numberColumns);
910
+ }
911
+ else {
912
+ nr = pd.length;
913
+ nc = 1;
914
+ }
915
+
916
+ var i, j, tr, td1, td2, lt, rs, color;
917
+ var idx = 0;
918
+
919
+ for (i=0; i<nr; i++) {
920
+ if (reverse){
921
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
922
+ }
923
+ else{
924
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
925
+ }
926
+ for (j=0; j<nc; j++) {
927
+ if (idx < pd.length){
928
+ // debugger
929
+ lt = this.labels[idx] || pd[idx][0].toString();
930
+ color = s.color;
931
+ if (!reverse){
932
+ if (i>0){
933
+ pad = true;
934
+ }
935
+ else{
936
+ pad = false;
937
+ }
938
+ }
939
+ else{
940
+ if (i == nr -1){
941
+ pad = false;
942
+ }
943
+ else{
944
+ pad = true;
945
+ }
946
+ }
947
+ rs = (pad) ? this.rowSpacing : '0';
948
+
949
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
950
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
951
+ '</div></td>');
952
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
953
+ if (this.escapeHtml){
954
+ td2.text(lt);
955
+ }
956
+ else {
957
+ td2.html(lt);
958
+ }
959
+ if (reverse) {
960
+ td2.prependTo(tr);
961
+ td1.prependTo(tr);
962
+ }
963
+ else {
964
+ td1.appendTo(tr);
965
+ td2.appendTo(tr);
966
+ }
967
+ pad = true;
968
+ }
969
+ idx++;
970
+ }
971
+ }
972
+ }
973
+ }
974
+ return this._elem;
975
+ };
976
+
977
+
978
+ // setup default renderers for axes and legend so user doesn't have to
979
+ // called with scope of plot
980
+ function preInit(target, data, options) {
981
+ // debugger
982
+ options = options || {};
983
+ options.axesDefaults = options.axesDefaults || {};
984
+ options.legend = options.legend || {};
985
+ options.seriesDefaults = options.seriesDefaults || {};
986
+ options.grid = options.grid || {};
987
+
988
+ // only set these if there is a gauge series
989
+ var setopts = false;
990
+ if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) {
991
+ setopts = true;
992
+ }
993
+ else if (options.series) {
994
+ for (var i=0; i < options.series.length; i++) {
995
+ if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) {
996
+ setopts = true;
997
+ }
998
+ }
999
+ }
1000
+
1001
+ if (setopts) {
1002
+ options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer;
1003
+ options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer;
1004
+ options.legend.preDraw = true;
1005
+ options.grid.background = options.grid.background || 'white';
1006
+ options.grid.drawGridlines = false;
1007
+ options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0;
1008
+ options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false;
1009
+ }
1010
+ }
1011
+
1012
+ // called with scope of plot
1013
+ function postParseOptions(options) {
1014
+ //
1015
+ }
1016
+
1017
+ $.jqplot.preInitHooks.push(preInit);
1018
+ $.jqplot.postParseOptionsHooks.push(postParseOptions);
1019
+
1020
+ $.jqplot.MeterGaugeTickRenderer = function() {
1021
+ $.jqplot.AxisTickRenderer.call(this);
1022
+ };
1023
+
1024
+ $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
1025
+ $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer;
1026
+
1027
+ })(jQuery);
1028
+
1029
+