1 | /** |
---|
2 | * Title: jqPlot Charts |
---|
3 | * |
---|
4 | * Pure JavaScript plotting plugin for jQuery. |
---|
5 | * |
---|
6 | * About: Version |
---|
7 | * |
---|
8 | * @VERSION |
---|
9 | * |
---|
10 | * About: Copyright & License |
---|
11 | * |
---|
12 | * Copyright (c) 2009-2011 Chris Leonello |
---|
13 | * jqPlot is currently available for use in all personal or commercial projects |
---|
14 | * under both the MIT and GPL version 2.0 licenses. This means that you can |
---|
15 | * choose the license that best suits your project and use it accordingly. |
---|
16 | * |
---|
17 | * See <GPL Version 2> and <MIT License> contained within this distribution for further information. |
---|
18 | * |
---|
19 | * The author would appreciate an email letting him know of any substantial |
---|
20 | * use of jqPlot. You can reach the author at: chris at jqplot dot com |
---|
21 | * or see http://www.jqplot.com/info.php. This is, of course, not required. |
---|
22 | * |
---|
23 | * If you are feeling kind and generous, consider supporting the project by |
---|
24 | * making a donation at: http://www.jqplot.com/donate.php. |
---|
25 | * |
---|
26 | * sprintf functions contained in jqplot.sprintf.js by Ash Searle: |
---|
27 | * |
---|
28 | * version 2007.04.27 |
---|
29 | * author Ash Searle |
---|
30 | * http://hexmen.com/blog/2007/03/printf-sprintf/ |
---|
31 | * http://hexmen.com/js/sprintf.js |
---|
32 | * The author (Ash Searle) has placed this code in the public domain: |
---|
33 | * "This code is unrestricted: you are free to use it however you like." |
---|
34 | * |
---|
35 | * |
---|
36 | * About: Introduction |
---|
37 | * |
---|
38 | * jqPlot requires jQuery (1.4+ required for certain features). jQuery 1.4.2 is included in the distribution. |
---|
39 | * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally |
---|
40 | * the excanvas script for IE support in your web page: |
---|
41 | * |
---|
42 | * > <!--[if lt IE 9]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]--> |
---|
43 | * > <script language="javascript" type="text/javascript" src="jquery-1.4.4.min.js"></script> |
---|
44 | * > <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script> |
---|
45 | * > <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" /> |
---|
46 | * |
---|
47 | * jqPlot can be customized by overriding the defaults of any of the objects which make |
---|
48 | * up the plot. The general usage of jqplot is: |
---|
49 | * |
---|
50 | * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject}); |
---|
51 | * |
---|
52 | * The options available to jqplot are detailed in <jqPlot Options> in the jqPlotOptions.txt file. |
---|
53 | * |
---|
54 | * An actual call to $.jqplot() may look like the |
---|
55 | * examples below: |
---|
56 | * |
---|
57 | * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]); |
---|
58 | * |
---|
59 | * or |
---|
60 | * |
---|
61 | * > dataArray = [34,12,43,55,77]; |
---|
62 | * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}}); |
---|
63 | * |
---|
64 | * For more inforrmation, see <jqPlot Usage>. |
---|
65 | * |
---|
66 | * About: Usage |
---|
67 | * |
---|
68 | * See <jqPlot Usage> |
---|
69 | * |
---|
70 | * About: Available Options |
---|
71 | * |
---|
72 | * See <jqPlot Options> for a list of options available thorugh the options object (not complete yet!) |
---|
73 | * |
---|
74 | * About: Options Usage |
---|
75 | * |
---|
76 | * See <Options Tutorial> |
---|
77 | * |
---|
78 | * About: Changes |
---|
79 | * |
---|
80 | * See <Change Log> |
---|
81 | * |
---|
82 | */ |
---|
83 | |
---|
84 | (function($) { |
---|
85 | // make sure undefined is undefined |
---|
86 | var undefined; |
---|
87 | |
---|
88 | $.fn.emptyForce = function() { |
---|
89 | for ( var i = 0, elem; (elem = $(this)[i]) != null; i++ ) { |
---|
90 | // Remove element nodes and prevent memory leaks |
---|
91 | if ( elem.nodeType === 1 ) { |
---|
92 | jQuery.cleanData( elem.getElementsByTagName("*") ); |
---|
93 | } |
---|
94 | |
---|
95 | // Remove any remaining nodes |
---|
96 | if ($.jqplot_use_excanvas) { |
---|
97 | elem.outerHTML = ""; |
---|
98 | } |
---|
99 | else { |
---|
100 | while ( elem.firstChild ) { |
---|
101 | elem.removeChild( elem.firstChild ); |
---|
102 | } |
---|
103 | } |
---|
104 | |
---|
105 | elem = null; |
---|
106 | } |
---|
107 | |
---|
108 | return $(this); |
---|
109 | }; |
---|
110 | |
---|
111 | $.fn.removeChildForce = function(parent) { |
---|
112 | while ( parent.firstChild ) { |
---|
113 | this.removeChildForce( parent.firstChild ); |
---|
114 | parent.removeChild( parent.firstChild ); |
---|
115 | } |
---|
116 | }; |
---|
117 | |
---|
118 | |
---|
119 | /** |
---|
120 | * Namespace: $.jqplot |
---|
121 | * jQuery function called by the user to create a plot. |
---|
122 | * |
---|
123 | * Parameters: |
---|
124 | * target - ID of target element to render the plot into. |
---|
125 | * data - an array of data series. |
---|
126 | * options - user defined options object. See the individual classes for available options. |
---|
127 | * |
---|
128 | * Properties: |
---|
129 | * config - object to hold configuration information for jqPlot plot object. |
---|
130 | * |
---|
131 | * attributes: |
---|
132 | * enablePlugins - False to disable plugins by default. Plugins must then be explicitly |
---|
133 | * enabled in the individual plot options. Default: false. |
---|
134 | * This property sets the "show" property of certain plugins to true or false. |
---|
135 | * Only plugins that can be immediately active upon loading are affected. This includes |
---|
136 | * non-renderer plugins like cursor, dragable, highlighter, and trendline. |
---|
137 | * defaultHeight - Default height for plots where no css height specification exists. This |
---|
138 | * is a jqplot wide default. |
---|
139 | * defaultWidth - Default height for plots where no css height specification exists. This |
---|
140 | * is a jqplot wide default. |
---|
141 | */ |
---|
142 | |
---|
143 | $.jqplot = function(target, data, options) { |
---|
144 | var _data, _options; |
---|
145 | |
---|
146 | if (options == null) { |
---|
147 | if (jQuery.isArray(data)) { |
---|
148 | _data = data; |
---|
149 | _options = null; |
---|
150 | } |
---|
151 | |
---|
152 | else if (typeof(data) === 'object') { |
---|
153 | _data = null; |
---|
154 | _options = data; |
---|
155 | } |
---|
156 | } |
---|
157 | else { |
---|
158 | _data = data; |
---|
159 | _options = options; |
---|
160 | } |
---|
161 | var plot = new jqPlot(); |
---|
162 | // remove any error class that may be stuck on target. |
---|
163 | $('#'+target).removeClass('jqplot-error'); |
---|
164 | |
---|
165 | if ($.jqplot.config.catchErrors) { |
---|
166 | try { |
---|
167 | plot.init(target, _data, _options); |
---|
168 | plot.draw(); |
---|
169 | plot.themeEngine.init.call(plot); |
---|
170 | return plot; |
---|
171 | } |
---|
172 | catch(e) { |
---|
173 | var msg = $.jqplot.config.errorMessage || e.message; |
---|
174 | $('#'+target).append('<div class="jqplot-error-message">'+msg+'</div>'); |
---|
175 | $('#'+target).addClass('jqplot-error'); |
---|
176 | document.getElementById(target).style.background = $.jqplot.config.errorBackground; |
---|
177 | document.getElementById(target).style.border = $.jqplot.config.errorBorder; |
---|
178 | document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily; |
---|
179 | document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize; |
---|
180 | document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle; |
---|
181 | document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight; |
---|
182 | } |
---|
183 | } |
---|
184 | else { |
---|
185 | plot.init(target, _data, _options); |
---|
186 | plot.draw(); |
---|
187 | plot.themeEngine.init.call(plot); |
---|
188 | return plot; |
---|
189 | } |
---|
190 | }; |
---|
191 | |
---|
192 | $.jqplot.version = "@VERSION"; |
---|
193 | |
---|
194 | // canvas manager to reuse canvases on the plot. |
---|
195 | // Should help solve problem of canvases not being freed and |
---|
196 | // problem of waiting forever for firefox to decide to free memory. |
---|
197 | $.jqplot.CanvasManager = function() { |
---|
198 | // canvases are managed globally so that they can be reused |
---|
199 | // across plots after they have been freed |
---|
200 | if (typeof $.jqplot.CanvasManager.canvases == 'undefined') { |
---|
201 | $.jqplot.CanvasManager.canvases = []; |
---|
202 | $.jqplot.CanvasManager.free = []; |
---|
203 | } |
---|
204 | |
---|
205 | var myCanvases = []; |
---|
206 | |
---|
207 | this.getCanvas = function() { |
---|
208 | var canvas; |
---|
209 | var makeNew = true; |
---|
210 | |
---|
211 | if (!$.jqplot.use_excanvas) { |
---|
212 | for (var i = 0, l = $.jqplot.CanvasManager.canvases.length; i < l; i++) { |
---|
213 | if ($.jqplot.CanvasManager.free[i] === true) { |
---|
214 | makeNew = false; |
---|
215 | canvas = $.jqplot.CanvasManager.canvases[i]; |
---|
216 | // $(canvas).removeClass('jqplot-canvasManager-free').addClass('jqplot-canvasManager-inuse'); |
---|
217 | $.jqplot.CanvasManager.free[i] = false; |
---|
218 | myCanvases.push(i); |
---|
219 | break; |
---|
220 | } |
---|
221 | } |
---|
222 | } |
---|
223 | |
---|
224 | if (makeNew) { |
---|
225 | canvas = document.createElement('canvas'); |
---|
226 | myCanvases.push($.jqplot.CanvasManager.canvases.length); |
---|
227 | $.jqplot.CanvasManager.canvases.push(canvas); |
---|
228 | $.jqplot.CanvasManager.free.push(false); |
---|
229 | } |
---|
230 | |
---|
231 | return canvas; |
---|
232 | }; |
---|
233 | |
---|
234 | // this method has to be used after settings the dimesions |
---|
235 | // on the element returned by getCanvas() |
---|
236 | this.initCanvas = function(canvas) { |
---|
237 | if ($.jqplot.use_excanvas) { |
---|
238 | return window.G_vmlCanvasManager.initElement(canvas); |
---|
239 | } |
---|
240 | return canvas; |
---|
241 | }; |
---|
242 | |
---|
243 | this.freeAllCanvases = function() { |
---|
244 | for (var i = 0, l=myCanvases.length; i < l; i++) { |
---|
245 | this.freeCanvas(myCanvases[i]); |
---|
246 | } |
---|
247 | myCanvases = []; |
---|
248 | }; |
---|
249 | |
---|
250 | this.freeCanvas = function(idx) { |
---|
251 | if ($.jqplot.use_excanvas) { |
---|
252 | // excanvas can't be reused, but properly unset |
---|
253 | window.G_vmlCanvasManager.uninitElement($.jqplot.CanvasManager.canvases[idx]); |
---|
254 | $.jqplot.CanvasManager.canvases[idx] = null; |
---|
255 | } |
---|
256 | else { |
---|
257 | var canvas = $.jqplot.CanvasManager.canvases[idx]; |
---|
258 | canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); |
---|
259 | $(canvas).unbind().removeAttr('class').removeAttr('style'); |
---|
260 | // Style attributes seemed to be still hanging around. wierd. Some ticks |
---|
261 | // still retained a left: 0px attribute after reusing a canvas. |
---|
262 | $(canvas).css({left: '', top: '', position: ''}); |
---|
263 | // setting size to 0 may save memory of unused canvases? |
---|
264 | canvas.width = 0; |
---|
265 | canvas.height = 0; |
---|
266 | $.jqplot.CanvasManager.free[idx] = true; |
---|
267 | } |
---|
268 | }; |
---|
269 | |
---|
270 | }; |
---|
271 | |
---|
272 | |
---|
273 | // Convienence function that won't hang IE or FF without FireBug. |
---|
274 | $.jqplot.log = function() { |
---|
275 | if (window.console) { |
---|
276 | console.log.apply(console, arguments); |
---|
277 | } |
---|
278 | }; |
---|
279 | |
---|
280 | $.jqplot.config = { |
---|
281 | enablePlugins:false, |
---|
282 | defaultHeight:300, |
---|
283 | defaultWidth:400, |
---|
284 | UTCAdjust:false, |
---|
285 | timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000), |
---|
286 | errorMessage: '', |
---|
287 | errorBackground: '', |
---|
288 | errorBorder: '', |
---|
289 | errorFontFamily: '', |
---|
290 | errorFontSize: '', |
---|
291 | errorFontStyle: '', |
---|
292 | errorFontWeight: '', |
---|
293 | catchErrors: false, |
---|
294 | defaultTickFormatString: "%.1f", |
---|
295 | defaultColors: [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"], |
---|
296 | defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"] |
---|
297 | }; |
---|
298 | |
---|
299 | |
---|
300 | $.jqplot.arrayMax = function( array ){ |
---|
301 | return Math.max.apply( Math, array ); |
---|
302 | }; |
---|
303 | |
---|
304 | $.jqplot.arrayMin = function( array ){ |
---|
305 | return Math.min.apply( Math, array ); |
---|
306 | }; |
---|
307 | |
---|
308 | $.jqplot.enablePlugins = $.jqplot.config.enablePlugins; |
---|
309 | |
---|
310 | // canvas related tests taken from modernizer: |
---|
311 | // Copyright (c) 2009 - 2010 Faruk Ates. |
---|
312 | // http://www.modernizr.com |
---|
313 | |
---|
314 | $.jqplot.support_canvas = function() { |
---|
315 | if (typeof $.jqplot.support_canvas.result == 'undefined') { |
---|
316 | $.jqplot.support_canvas.result = !!document.createElement('canvas').getContext; |
---|
317 | } |
---|
318 | return $.jqplot.support_canvas.result; |
---|
319 | }; |
---|
320 | |
---|
321 | $.jqplot.support_canvas_text = function() { |
---|
322 | if (typeof $.jqplot.support_canvas_text.result == 'undefined') { |
---|
323 | $.jqplot.support_canvas_text.result = !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function'); |
---|
324 | } |
---|
325 | return $.jqplot.support_canvas_text.result; |
---|
326 | }; |
---|
327 | |
---|
328 | $.jqplot.use_excanvas = ($.browser.msie && !$.jqplot.support_canvas()) ? true : false; |
---|
329 | |
---|
330 | /** |
---|
331 | * |
---|
332 | * Hooks: jqPlot Pugin Hooks |
---|
333 | * |
---|
334 | * $.jqplot.preInitHooks - called before initialization. |
---|
335 | * $.jqplot.postInitHooks - called after initialization. |
---|
336 | * $.jqplot.preParseOptionsHooks - called before user options are parsed. |
---|
337 | * $.jqplot.postParseOptionsHooks - called after user options are parsed. |
---|
338 | * $.jqplot.preDrawHooks - called before plot draw. |
---|
339 | * $.jqplot.postDrawHooks - called after plot draw. |
---|
340 | * $.jqplot.preDrawSeriesHooks - called before each series is drawn. |
---|
341 | * $.jqplot.postDrawSeriesHooks - called after each series is drawn. |
---|
342 | * $.jqplot.preDrawLegendHooks - called before the legend is drawn. |
---|
343 | * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins |
---|
344 | * can add rows to the legend table. |
---|
345 | * $.jqplot.preSeriesInitHooks - called before series is initialized. |
---|
346 | * $.jqplot.postSeriesInitHooks - called after series is initialized. |
---|
347 | * $.jqplot.preParseSeriesOptionsHooks - called before series related options |
---|
348 | * are parsed. |
---|
349 | * $.jqplot.postParseSeriesOptionsHooks - called after series related options |
---|
350 | * are parsed. |
---|
351 | * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds |
---|
352 | * listeners to the event canvas which lays on top of the grid area. |
---|
353 | * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn. |
---|
354 | * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn. |
---|
355 | * |
---|
356 | */ |
---|
357 | |
---|
358 | $.jqplot.preInitHooks = []; |
---|
359 | $.jqplot.postInitHooks = []; |
---|
360 | $.jqplot.preParseOptionsHooks = []; |
---|
361 | $.jqplot.postParseOptionsHooks = []; |
---|
362 | $.jqplot.preDrawHooks = []; |
---|
363 | $.jqplot.postDrawHooks = []; |
---|
364 | $.jqplot.preDrawSeriesHooks = []; |
---|
365 | $.jqplot.postDrawSeriesHooks = []; |
---|
366 | $.jqplot.preDrawLegendHooks = []; |
---|
367 | $.jqplot.addLegendRowHooks = []; |
---|
368 | $.jqplot.preSeriesInitHooks = []; |
---|
369 | $.jqplot.postSeriesInitHooks = []; |
---|
370 | $.jqplot.preParseSeriesOptionsHooks = []; |
---|
371 | $.jqplot.postParseSeriesOptionsHooks = []; |
---|
372 | $.jqplot.eventListenerHooks = []; |
---|
373 | $.jqplot.preDrawSeriesShadowHooks = []; |
---|
374 | $.jqplot.postDrawSeriesShadowHooks = []; |
---|
375 | |
---|
376 | // A superclass holding some common properties and methods. |
---|
377 | $.jqplot.ElemContainer = function() { |
---|
378 | this._elem; |
---|
379 | this._plotWidth; |
---|
380 | this._plotHeight; |
---|
381 | this._plotDimensions = {height:null, width:null}; |
---|
382 | }; |
---|
383 | |
---|
384 | $.jqplot.ElemContainer.prototype.createElement = function(el, offsets, clss, cssopts, attrib) { |
---|
385 | this._offsets = offsets; |
---|
386 | var klass = clss || 'jqplot'; |
---|
387 | var elem = document.createElement(el); |
---|
388 | this._elem = $(elem); |
---|
389 | this._elem.addClass(klass); |
---|
390 | this._elem.css(cssopts); |
---|
391 | this._elem.attr(attrib); |
---|
392 | // avoid memory leak; |
---|
393 | elem = null; |
---|
394 | return this._elem; |
---|
395 | }; |
---|
396 | |
---|
397 | $.jqplot.ElemContainer.prototype.getWidth = function() { |
---|
398 | if (this._elem) { |
---|
399 | return this._elem.outerWidth(true); |
---|
400 | } |
---|
401 | else { |
---|
402 | return null; |
---|
403 | } |
---|
404 | }; |
---|
405 | |
---|
406 | $.jqplot.ElemContainer.prototype.getHeight = function() { |
---|
407 | if (this._elem) { |
---|
408 | return this._elem.outerHeight(true); |
---|
409 | } |
---|
410 | else { |
---|
411 | return null; |
---|
412 | } |
---|
413 | }; |
---|
414 | |
---|
415 | $.jqplot.ElemContainer.prototype.getPosition = function() { |
---|
416 | if (this._elem) { |
---|
417 | return this._elem.position(); |
---|
418 | } |
---|
419 | else { |
---|
420 | return {top:null, left:null, bottom:null, right:null}; |
---|
421 | } |
---|
422 | }; |
---|
423 | |
---|
424 | $.jqplot.ElemContainer.prototype.getTop = function() { |
---|
425 | return this.getPosition().top; |
---|
426 | }; |
---|
427 | |
---|
428 | $.jqplot.ElemContainer.prototype.getLeft = function() { |
---|
429 | return this.getPosition().left; |
---|
430 | }; |
---|
431 | |
---|
432 | $.jqplot.ElemContainer.prototype.getBottom = function() { |
---|
433 | return this._elem.css('bottom'); |
---|
434 | }; |
---|
435 | |
---|
436 | $.jqplot.ElemContainer.prototype.getRight = function() { |
---|
437 | return this._elem.css('right'); |
---|
438 | }; |
---|
439 | |
---|
440 | |
---|
441 | /** |
---|
442 | * Class: Axis |
---|
443 | * An individual axis object. Cannot be instantiated directly, but created |
---|
444 | * by the Plot oject. Axis properties can be set or overriden by the |
---|
445 | * options passed in from the user. |
---|
446 | * |
---|
447 | */ |
---|
448 | function Axis(name) { |
---|
449 | $.jqplot.ElemContainer.call(this); |
---|
450 | // Group: Properties |
---|
451 | // |
---|
452 | // Axes options are specified within an axes object at the top level of the |
---|
453 | // plot options like so: |
---|
454 | // > { |
---|
455 | // > axes: { |
---|
456 | // > xaxis: {min: 5}, |
---|
457 | // > yaxis: {min: 2, max: 8, numberTicks:4}, |
---|
458 | // > x2axis: {pad: 1.5}, |
---|
459 | // > y2axis: {ticks:[22, 44, 66, 88]} |
---|
460 | // > } |
---|
461 | // > } |
---|
462 | // There are 2 x axes, 'xaxis' and 'x2axis', and |
---|
463 | // 9 yaxes, 'yaxis', 'y2axis'. 'y3axis', ... Any or all of which may be specified. |
---|
464 | this.name = name; |
---|
465 | this._series = []; |
---|
466 | // prop: show |
---|
467 | // Wether to display the axis on the graph. |
---|
468 | this.show = false; |
---|
469 | // prop: tickRenderer |
---|
470 | // A class of a rendering engine for creating the ticks labels displayed on the plot, |
---|
471 | // See <$.jqplot.AxisTickRenderer>. |
---|
472 | this.tickRenderer = $.jqplot.AxisTickRenderer; |
---|
473 | // prop: tickOptions |
---|
474 | // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options. |
---|
475 | this.tickOptions = {}; |
---|
476 | // prop: labelRenderer |
---|
477 | // A class of a rendering engine for creating an axis label. |
---|
478 | this.labelRenderer = $.jqplot.AxisLabelRenderer; |
---|
479 | // prop: labelOptions |
---|
480 | // Options passed to the label renderer. |
---|
481 | this.labelOptions = {}; |
---|
482 | // prop: label |
---|
483 | // Label for the axis |
---|
484 | this.label = null; |
---|
485 | // prop: showLabel |
---|
486 | // true to show the axis label. |
---|
487 | this.showLabel = true; |
---|
488 | // prop: min |
---|
489 | // minimum value of the axis (in data units, not pixels). |
---|
490 | this.min=null; |
---|
491 | // prop: max |
---|
492 | // maximum value of the axis (in data units, not pixels). |
---|
493 | this.max=null; |
---|
494 | // prop: autoscale |
---|
495 | // Autoscale the axis min and max values to provide sensible tick spacing. |
---|
496 | // If axis min or max are set, autoscale will be turned off. |
---|
497 | // The numberTicks, tickInterval and pad options do work with |
---|
498 | // autoscale, although tickInterval has not been tested yet. |
---|
499 | // padMin and padMax do nothing when autoscale is on. |
---|
500 | this.autoscale = false; |
---|
501 | // prop: pad |
---|
502 | // Padding to extend the range above and below the data bounds. |
---|
503 | // The data range is multiplied by this factor to determine minimum and maximum axis bounds. |
---|
504 | // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0. |
---|
505 | this.pad = 1.2; |
---|
506 | // prop: padMax |
---|
507 | // Padding to extend the range above data bounds. |
---|
508 | // The top of the data range is multiplied by this factor to determine maximum axis bounds. |
---|
509 | // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0. |
---|
510 | this.padMax = null; |
---|
511 | // prop: padMin |
---|
512 | // Padding to extend the range below data bounds. |
---|
513 | // The bottom of the data range is multiplied by this factor to determine minimum axis bounds. |
---|
514 | // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0. |
---|
515 | this.padMin = null; |
---|
516 | // prop: ticks |
---|
517 | // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis. |
---|
518 | // If no label is specified, the value is formatted into an appropriate label. |
---|
519 | this.ticks = []; |
---|
520 | // prop: numberTicks |
---|
521 | // Desired number of ticks. Default is to compute automatically. |
---|
522 | this.numberTicks; |
---|
523 | // prop: tickInterval |
---|
524 | // number of units between ticks. Mutually exclusive with numberTicks. |
---|
525 | this.tickInterval; |
---|
526 | // prop: renderer |
---|
527 | // A class of a rendering engine that handles tick generation, |
---|
528 | // scaling input data to pixel grid units and drawing the axis element. |
---|
529 | this.renderer = $.jqplot.LinearAxisRenderer; |
---|
530 | // prop: rendererOptions |
---|
531 | // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options. |
---|
532 | this.rendererOptions = {}; |
---|
533 | // prop: showTicks |
---|
534 | // Wether to show the ticks (both marks and labels) or not. |
---|
535 | // Will not override showMark and showLabel options if specified on the ticks themselves. |
---|
536 | this.showTicks = true; |
---|
537 | // prop: showTickMarks |
---|
538 | // Wether to show the tick marks (line crossing grid) or not. |
---|
539 | // Overridden by showTicks and showMark option of tick itself. |
---|
540 | this.showTickMarks = true; |
---|
541 | // prop: showMinorTicks |
---|
542 | // Wether or not to show minor ticks. This is renderer dependent. |
---|
543 | // The default <$.jqplot.LinearAxisRenderer> does not have minor ticks. |
---|
544 | this.showMinorTicks = true; |
---|
545 | // prop: useSeriesColor |
---|
546 | // Use the color of the first series associated with this axis for the |
---|
547 | // tick marks and line bordering this axis. |
---|
548 | this.useSeriesColor = false; |
---|
549 | // prop: borderWidth |
---|
550 | // width of line stroked at the border of the axis. Defaults |
---|
551 | // to the width of the grid boarder. |
---|
552 | this.borderWidth = null; |
---|
553 | // prop: borderColor |
---|
554 | // color of the border adjacent to the axis. Defaults to grid border color. |
---|
555 | this.borderColor = null; |
---|
556 | // minimum and maximum values on the axis. |
---|
557 | this._dataBounds = {min:null, max:null}; |
---|
558 | // statistics (min, max, mean) as well as actual data intervals for each series attached to axis. |
---|
559 | // holds collection of {intervals:[], min:, max:, mean: } objects for each series on axis. |
---|
560 | this._intervalStats = []; |
---|
561 | // pixel position from the top left of the min value and max value on the axis. |
---|
562 | this._offsets = {min:null, max:null}; |
---|
563 | this._ticks=[]; |
---|
564 | this._label = null; |
---|
565 | // prop: syncTicks |
---|
566 | // true to try and synchronize tick spacing across multiple axes so that ticks and |
---|
567 | // grid lines line up. This has an impact on autoscaling algorithm, however. |
---|
568 | // In general, autoscaling an individual axis will work better if it does not |
---|
569 | // have to sync ticks. |
---|
570 | this.syncTicks = null; |
---|
571 | // prop: tickSpacing |
---|
572 | // Approximate pixel spacing between ticks on graph. Used during autoscaling. |
---|
573 | // This number will be an upper bound, actual spacing will be less. |
---|
574 | this.tickSpacing = 75; |
---|
575 | // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks |
---|
576 | // so they can be restored if altered by plugins. |
---|
577 | this._min = null; |
---|
578 | this._max = null; |
---|
579 | this._tickInterval = null; |
---|
580 | this._numberTicks = null; |
---|
581 | this.__ticks = null; |
---|
582 | // hold original user options. |
---|
583 | this._options = {}; |
---|
584 | } |
---|
585 | |
---|
586 | Axis.prototype = new $.jqplot.ElemContainer(); |
---|
587 | Axis.prototype.constructor = Axis; |
---|
588 | |
---|
589 | Axis.prototype.init = function() { |
---|
590 | this.renderer = new this.renderer(); |
---|
591 | // set the axis name |
---|
592 | this.tickOptions.axis = this.name; |
---|
593 | // if showMark or showLabel tick options not specified, use value of axis option. |
---|
594 | // showTicks overrides showTickMarks. |
---|
595 | if (this.tickOptions.showMark == null) { |
---|
596 | this.tickOptions.showMark = this.showTicks; |
---|
597 | } |
---|
598 | if (this.tickOptions.showMark == null) { |
---|
599 | this.tickOptions.showMark = this.showTickMarks; |
---|
600 | } |
---|
601 | if (this.tickOptions.showLabel == null) { |
---|
602 | this.tickOptions.showLabel = this.showTicks; |
---|
603 | } |
---|
604 | |
---|
605 | if (this.label == null || this.label == '') { |
---|
606 | this.showLabel = false; |
---|
607 | } |
---|
608 | else { |
---|
609 | this.labelOptions.label = this.label; |
---|
610 | } |
---|
611 | if (this.showLabel == false) { |
---|
612 | this.labelOptions.show = false; |
---|
613 | } |
---|
614 | // set the default padMax, padMin if not specified |
---|
615 | // special check, if no padding desired, padding |
---|
616 | // should be set to 1.0 |
---|
617 | if (this.pad == 0) { |
---|
618 | this.pad = 1.0; |
---|
619 | } |
---|
620 | if (this.padMax == 0) { |
---|
621 | this.padMax = 1.0; |
---|
622 | } |
---|
623 | if (this.padMin == 0) { |
---|
624 | this.padMin = 1.0; |
---|
625 | } |
---|
626 | if (this.padMax == null) { |
---|
627 | this.padMax = (this.pad-1)/2 + 1; |
---|
628 | } |
---|
629 | if (this.padMin == null) { |
---|
630 | this.padMin = (this.pad-1)/2 + 1; |
---|
631 | } |
---|
632 | // now that padMin and padMax are correctly set, reset pad in case user has supplied |
---|
633 | // padMin and/or padMax |
---|
634 | this.pad = this.padMax + this.padMin - 1; |
---|
635 | if (this.min != null || this.max != null) { |
---|
636 | this.autoscale = false; |
---|
637 | } |
---|
638 | // if not set, sync ticks for y axes but not x by default. |
---|
639 | if (this.syncTicks == null && this.name.indexOf('y') > -1) { |
---|
640 | this.syncTicks = true; |
---|
641 | } |
---|
642 | else if (this.syncTicks == null){ |
---|
643 | this.syncTicks = false; |
---|
644 | } |
---|
645 | this.renderer.init.call(this, this.rendererOptions); |
---|
646 | |
---|
647 | }; |
---|
648 | |
---|
649 | Axis.prototype.draw = function(ctx, plot) { |
---|
650 | // Memory Leaks patch |
---|
651 | if (this.__ticks) { |
---|
652 | this.__ticks = null; |
---|
653 | } |
---|
654 | |
---|
655 | return this.renderer.draw.call(this, ctx, plot); |
---|
656 | |
---|
657 | }; |
---|
658 | |
---|
659 | Axis.prototype.set = function() { |
---|
660 | this.renderer.set.call(this); |
---|
661 | }; |
---|
662 | |
---|
663 | Axis.prototype.pack = function(pos, offsets) { |
---|
664 | if (this.show) { |
---|
665 | this.renderer.pack.call(this, pos, offsets); |
---|
666 | } |
---|
667 | // these properties should all be available now. |
---|
668 | if (this._min == null) { |
---|
669 | this._min = this.min; |
---|
670 | this._max = this.max; |
---|
671 | this._tickInterval = this.tickInterval; |
---|
672 | this._numberTicks = this.numberTicks; |
---|
673 | this.__ticks = this._ticks; |
---|
674 | } |
---|
675 | }; |
---|
676 | |
---|
677 | // reset the axis back to original values if it has been scaled, zoomed, etc. |
---|
678 | Axis.prototype.reset = function() { |
---|
679 | this.renderer.reset.call(this); |
---|
680 | }; |
---|
681 | |
---|
682 | Axis.prototype.resetScale = function(opts) { |
---|
683 | $.extend(true, this, {min: null, max: null, numberTicks: null, tickInterval: null, _ticks: [], ticks: []}, opts); |
---|
684 | this.resetDataBounds(); |
---|
685 | }; |
---|
686 | |
---|
687 | Axis.prototype.resetDataBounds = function() { |
---|
688 | // Go through all the series attached to this axis and find |
---|
689 | // the min/max bounds for this axis. |
---|
690 | var db = this._dataBounds; |
---|
691 | db.min = null; |
---|
692 | db.max = null; |
---|
693 | // check for when to force min 0 on bar series plots. |
---|
694 | var doforce = (this.show) ? true : false; |
---|
695 | for (var i=0; i<this._series.length; i++) { |
---|
696 | var s = this._series[i]; |
---|
697 | var d = s._plotData; |
---|
698 | var minyidx = 1, maxyidx = 1; |
---|
699 | |
---|
700 | if (s._type != null && s._type == 'ohlc') { |
---|
701 | minyidx = 3; |
---|
702 | maxyidx = 2; |
---|
703 | } |
---|
704 | |
---|
705 | for (var j=0; j<d.length; j++) { |
---|
706 | if (this.name == 'xaxis' || this.name == 'x2axis') { |
---|
707 | if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) { |
---|
708 | db.min = d[j][0]; |
---|
709 | } |
---|
710 | if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) { |
---|
711 | db.max = d[j][0]; |
---|
712 | } |
---|
713 | } |
---|
714 | else { |
---|
715 | if ((d[j][minyidx] != null && d[j][minyidx] < db.min) || db.min == null) { |
---|
716 | db.min = d[j][minyidx]; |
---|
717 | } |
---|
718 | if ((d[j][maxyidx] != null && d[j][maxyidx] > db.max) || db.max == null) { |
---|
719 | db.max = d[j][maxyidx]; |
---|
720 | } |
---|
721 | } |
---|
722 | } |
---|
723 | |
---|
724 | // Hack to not pad out bottom of bar plots unless user has specified a padding. |
---|
725 | // every series will have a chance to set doforce to false. once it is set to |
---|
726 | // false, it cannot be reset to true. |
---|
727 | // If any series attached to axis is not a bar, wont force 0. |
---|
728 | if (doforce && s.renderer.constructor !== $.jqplot.BarRenderer) { |
---|
729 | doforce = false; |
---|
730 | } |
---|
731 | |
---|
732 | else if (doforce && this._options.hasOwnProperty('forceTickAt0') && this._options.forceTickAt0 == false) { |
---|
733 | doforce = false; |
---|
734 | } |
---|
735 | |
---|
736 | else if (doforce && s.renderer.constructor === $.jqplot.BarRenderer) { |
---|
737 | if (s.barDirection == 'vertical' && this.name != 'xaxis' && this.name != 'x2axis') { |
---|
738 | if (this._options.pad != null || this._options.padMin != null) { |
---|
739 | doforce = false; |
---|
740 | } |
---|
741 | } |
---|
742 | |
---|
743 | else if (s.barDirection == 'horizontal' && (this.name == 'xaxis' || this.name == 'x2axis')) { |
---|
744 | if (this._options.pad != null || this._options.padMin != null) { |
---|
745 | doforce = false; |
---|
746 | } |
---|
747 | } |
---|
748 | |
---|
749 | } |
---|
750 | } |
---|
751 | |
---|
752 | if (doforce && this.renderer.constructor === $.jqplot.LinearAxisRenderer && db.min >= 0) { |
---|
753 | this.padMin = 1.0; |
---|
754 | this.forceTickAt0 = true; |
---|
755 | } |
---|
756 | }; |
---|
757 | |
---|
758 | /** |
---|
759 | * Class: Legend |
---|
760 | * Legend object. Cannot be instantiated directly, but created |
---|
761 | * by the Plot oject. Legend properties can be set or overriden by the |
---|
762 | * options passed in from the user. |
---|
763 | */ |
---|
764 | function Legend(options) { |
---|
765 | $.jqplot.ElemContainer.call(this); |
---|
766 | // Group: Properties |
---|
767 | |
---|
768 | // prop: show |
---|
769 | // Wether to display the legend on the graph. |
---|
770 | this.show = false; |
---|
771 | // prop: location |
---|
772 | // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w |
---|
773 | this.location = 'ne'; |
---|
774 | // prop: labels |
---|
775 | // Array of labels to use. By default the renderer will look for labels on the series. |
---|
776 | // Labels specified in this array will override labels specified on the series. |
---|
777 | this.labels = []; |
---|
778 | // prop: showLabels |
---|
779 | // true to show the label text on the legend. |
---|
780 | this.showLabels = true; |
---|
781 | // prop: showSwatch |
---|
782 | // true to show the color swatches on the legend. |
---|
783 | this.showSwatches = true; |
---|
784 | // prop: placement |
---|
785 | // "insideGrid" places legend inside the grid area of the plot. |
---|
786 | // "outsideGrid" places the legend outside the grid but inside the plot container, |
---|
787 | // shrinking the grid to accomodate the legend. |
---|
788 | // "inside" synonym for "insideGrid", |
---|
789 | // "outside" places the legend ouside the grid area, but does not shrink the grid which |
---|
790 | // can cause the legend to overflow the plot container. |
---|
791 | this.placement = "insideGrid"; |
---|
792 | // prop: xoffset |
---|
793 | // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc. |
---|
794 | // properties or via CSS margin styling of the .jqplot-table-legend class. |
---|
795 | this.xoffset = 0; |
---|
796 | // prop: yoffset |
---|
797 | // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc. |
---|
798 | // properties or via CSS margin styling of the .jqplot-table-legend class. |
---|
799 | this.yoffset = 0; |
---|
800 | // prop: border |
---|
801 | // css spec for the border around the legend box. |
---|
802 | this.border; |
---|
803 | // prop: background |
---|
804 | // css spec for the background of the legend box. |
---|
805 | this.background; |
---|
806 | // prop: textColor |
---|
807 | // css color spec for the legend text. |
---|
808 | this.textColor; |
---|
809 | // prop: fontFamily |
---|
810 | // css font-family spec for the legend text. |
---|
811 | this.fontFamily; |
---|
812 | // prop: fontSize |
---|
813 | // css font-size spec for the legend text. |
---|
814 | this.fontSize ; |
---|
815 | // prop: rowSpacing |
---|
816 | // css padding-top spec for the rows in the legend. |
---|
817 | this.rowSpacing = '0.5em'; |
---|
818 | // renderer |
---|
819 | // A class that will create a DOM object for the legend, |
---|
820 | // see <$.jqplot.TableLegendRenderer>. |
---|
821 | this.renderer = $.jqplot.TableLegendRenderer; |
---|
822 | // prop: rendererOptions |
---|
823 | // renderer specific options passed to the renderer. |
---|
824 | this.rendererOptions = {}; |
---|
825 | // prop: predraw |
---|
826 | // Wether to draw the legend before the series or not. |
---|
827 | // Used with series specific legend renderers for pie, donut, mekko charts, etc. |
---|
828 | this.preDraw = false; |
---|
829 | // prop: marginTop |
---|
830 | // CSS margin for the legend DOM element. This will set an element |
---|
831 | // CSS style for the margin which will override any style sheet setting. |
---|
832 | // The default will be taken from the stylesheet. |
---|
833 | this.marginTop = null; |
---|
834 | // prop: marginRight |
---|
835 | // CSS margin for the legend DOM element. This will set an element |
---|
836 | // CSS style for the margin which will override any style sheet setting. |
---|
837 | // The default will be taken from the stylesheet. |
---|
838 | this.marginRight = null; |
---|
839 | // prop: marginBottom |
---|
840 | // CSS margin for the legend DOM element. This will set an element |
---|
841 | // CSS style for the margin which will override any style sheet setting. |
---|
842 | // The default will be taken from the stylesheet. |
---|
843 | this.marginBottom = null; |
---|
844 | // prop: marginLeft |
---|
845 | // CSS margin for the legend DOM element. This will set an element |
---|
846 | // CSS style for the margin which will override any style sheet setting. |
---|
847 | // The default will be taken from the stylesheet. |
---|
848 | this.marginLeft = null; |
---|
849 | |
---|
850 | this.escapeHtml = false; |
---|
851 | this._series = []; |
---|
852 | |
---|
853 | $.extend(true, this, options); |
---|
854 | } |
---|
855 | |
---|
856 | Legend.prototype = new $.jqplot.ElemContainer(); |
---|
857 | Legend.prototype.constructor = Legend; |
---|
858 | |
---|
859 | Legend.prototype.setOptions = function(options) { |
---|
860 | $.extend(true, this, options); |
---|
861 | |
---|
862 | // Try to emulate deprecated behaviour |
---|
863 | // if user has specified xoffset or yoffset, copy these to |
---|
864 | // the margin properties. |
---|
865 | |
---|
866 | if (this.placement == 'inside') { |
---|
867 | this.placement = 'insideGrid'; |
---|
868 | } |
---|
869 | |
---|
870 | if (this.xoffset >0) { |
---|
871 | if (this.placement == 'insideGrid') { |
---|
872 | switch (this.location) { |
---|
873 | case 'nw': |
---|
874 | case 'w': |
---|
875 | case 'sw': |
---|
876 | if (this.marginLeft == null) { |
---|
877 | this.marginLeft = this.xoffset + 'px'; |
---|
878 | } |
---|
879 | this.marginRight = '0px'; |
---|
880 | break; |
---|
881 | case 'ne': |
---|
882 | case 'e': |
---|
883 | case 'se': |
---|
884 | default: |
---|
885 | if (this.marginRight == null) { |
---|
886 | this.marginRight = this.xoffset + 'px'; |
---|
887 | } |
---|
888 | this.marginLeft = '0px'; |
---|
889 | break; |
---|
890 | } |
---|
891 | } |
---|
892 | else if (this.placement == 'outside') { |
---|
893 | switch (this.location) { |
---|
894 | case 'nw': |
---|
895 | case 'w': |
---|
896 | case 'sw': |
---|
897 | if (this.marginRight == null) { |
---|
898 | this.marginRight = this.xoffset + 'px'; |
---|
899 | } |
---|
900 | this.marginLeft = '0px'; |
---|
901 | break; |
---|
902 | case 'ne': |
---|
903 | case 'e': |
---|
904 | case 'se': |
---|
905 | default: |
---|
906 | if (this.marginLeft == null) { |
---|
907 | this.marginLeft = this.xoffset + 'px'; |
---|
908 | } |
---|
909 | this.marginRight = '0px'; |
---|
910 | break; |
---|
911 | } |
---|
912 | } |
---|
913 | this.xoffset = 0; |
---|
914 | } |
---|
915 | |
---|
916 | if (this.yoffset >0) { |
---|
917 | if (this.placement == 'outside') { |
---|
918 | switch (this.location) { |
---|
919 | case 'sw': |
---|
920 | case 's': |
---|
921 | case 'se': |
---|
922 | if (this.marginTop == null) { |
---|
923 | this.marginTop = this.yoffset + 'px'; |
---|
924 | } |
---|
925 | this.marginBottom = '0px'; |
---|
926 | break; |
---|
927 | case 'ne': |
---|
928 | case 'n': |
---|
929 | case 'nw': |
---|
930 | default: |
---|
931 | if (this.marginBottom == null) { |
---|
932 | this.marginBottom = this.yoffset + 'px'; |
---|
933 | } |
---|
934 | this.marginTop = '0px'; |
---|
935 | break; |
---|
936 | } |
---|
937 | } |
---|
938 | else if (this.placement == 'insideGrid') { |
---|
939 | switch (this.location) { |
---|
940 | case 'sw': |
---|
941 | case 's': |
---|
942 | case 'se': |
---|
943 | if (this.marginBottom == null) { |
---|
944 | this.marginBottom = this.yoffset + 'px'; |
---|
945 | } |
---|
946 | this.marginTop = '0px'; |
---|
947 | break; |
---|
948 | case 'ne': |
---|
949 | case 'n': |
---|
950 | case 'nw': |
---|
951 | default: |
---|
952 | if (this.marginTop == null) { |
---|
953 | this.marginTop = this.yoffset + 'px'; |
---|
954 | } |
---|
955 | this.marginBottom = '0px'; |
---|
956 | break; |
---|
957 | } |
---|
958 | } |
---|
959 | this.yoffset = 0; |
---|
960 | } |
---|
961 | |
---|
962 | // TO-DO: |
---|
963 | // Handle case where offsets are < 0. |
---|
964 | // |
---|
965 | }; |
---|
966 | |
---|
967 | Legend.prototype.init = function() { |
---|
968 | this.renderer = new this.renderer(); |
---|
969 | this.renderer.init.call(this, this.rendererOptions); |
---|
970 | }; |
---|
971 | |
---|
972 | Legend.prototype.draw = function(offsets) { |
---|
973 | for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){ |
---|
974 | $.jqplot.preDrawLegendHooks[i].call(this, offsets); |
---|
975 | } |
---|
976 | return this.renderer.draw.call(this, offsets); |
---|
977 | }; |
---|
978 | |
---|
979 | Legend.prototype.pack = function(offsets) { |
---|
980 | this.renderer.pack.call(this, offsets); |
---|
981 | }; |
---|
982 | |
---|
983 | /** |
---|
984 | * Class: Title |
---|
985 | * Plot Title object. Cannot be instantiated directly, but created |
---|
986 | * by the Plot oject. Title properties can be set or overriden by the |
---|
987 | * options passed in from the user. |
---|
988 | * |
---|
989 | * Parameters: |
---|
990 | * text - text of the title. |
---|
991 | */ |
---|
992 | function Title(text) { |
---|
993 | $.jqplot.ElemContainer.call(this); |
---|
994 | // Group: Properties |
---|
995 | |
---|
996 | // prop: text |
---|
997 | // text of the title; |
---|
998 | this.text = text; |
---|
999 | // prop: show |
---|
1000 | // wether or not to show the title |
---|
1001 | this.show = true; |
---|
1002 | // prop: fontFamily |
---|
1003 | // css font-family spec for the text. |
---|
1004 | this.fontFamily; |
---|
1005 | // prop: fontSize |
---|
1006 | // css font-size spec for the text. |
---|
1007 | this.fontSize ; |
---|
1008 | // prop: textAlign |
---|
1009 | // css text-align spec for the text. |
---|
1010 | this.textAlign; |
---|
1011 | // prop: textColor |
---|
1012 | // css color spec for the text. |
---|
1013 | this.textColor; |
---|
1014 | // prop: renderer |
---|
1015 | // A class for creating a DOM element for the title, |
---|
1016 | // see <$.jqplot.DivTitleRenderer>. |
---|
1017 | this.renderer = $.jqplot.DivTitleRenderer; |
---|
1018 | // prop: rendererOptions |
---|
1019 | // renderer specific options passed to the renderer. |
---|
1020 | this.rendererOptions = {}; |
---|
1021 | } |
---|
1022 | |
---|
1023 | Title.prototype = new $.jqplot.ElemContainer(); |
---|
1024 | Title.prototype.constructor = Title; |
---|
1025 | |
---|
1026 | Title.prototype.init = function() { |
---|
1027 | this.renderer = new this.renderer(); |
---|
1028 | this.renderer.init.call(this, this.rendererOptions); |
---|
1029 | }; |
---|
1030 | |
---|
1031 | Title.prototype.draw = function(width) { |
---|
1032 | return this.renderer.draw.call(this, width); |
---|
1033 | }; |
---|
1034 | |
---|
1035 | Title.prototype.pack = function() { |
---|
1036 | this.renderer.pack.call(this); |
---|
1037 | }; |
---|
1038 | |
---|
1039 | |
---|
1040 | /** |
---|
1041 | * Class: Series |
---|
1042 | * An individual data series object. Cannot be instantiated directly, but created |
---|
1043 | * by the Plot oject. Series properties can be set or overriden by the |
---|
1044 | * options passed in from the user. |
---|
1045 | */ |
---|
1046 | function Series() { |
---|
1047 | $.jqplot.ElemContainer.call(this); |
---|
1048 | // Group: Properties |
---|
1049 | // Properties will be assigned from a series array at the top level of the |
---|
1050 | // options. If you had two series and wanted to change the color and line |
---|
1051 | // width of the first and set the second to use the secondary y axis with |
---|
1052 | // no shadow and supply custom labels for each: |
---|
1053 | // > { |
---|
1054 | // > series:[ |
---|
1055 | // > {color: '#ff4466', lineWidth: 5, label:'good line'}, |
---|
1056 | // > {yaxis: 'y2axis', shadow: false, label:'bad line'} |
---|
1057 | // > ] |
---|
1058 | // > } |
---|
1059 | |
---|
1060 | // prop: show |
---|
1061 | // wether or not to draw the series. |
---|
1062 | this.show = true; |
---|
1063 | // prop: xaxis |
---|
1064 | // which x axis to use with this series, either 'xaxis' or 'x2axis'. |
---|
1065 | this.xaxis = 'xaxis'; |
---|
1066 | this._xaxis; |
---|
1067 | // prop: yaxis |
---|
1068 | // which y axis to use with this series, either 'yaxis' or 'y2axis'. |
---|
1069 | this.yaxis = 'yaxis'; |
---|
1070 | this._yaxis; |
---|
1071 | this.gridBorderWidth = 2.0; |
---|
1072 | // prop: renderer |
---|
1073 | // A class of a renderer which will draw the series, |
---|
1074 | // see <$.jqplot.LineRenderer>. |
---|
1075 | this.renderer = $.jqplot.LineRenderer; |
---|
1076 | // prop: rendererOptions |
---|
1077 | // Options to pass on to the renderer. |
---|
1078 | this.rendererOptions = {}; |
---|
1079 | this.data = []; |
---|
1080 | this.gridData = []; |
---|
1081 | // prop: label |
---|
1082 | // Line label to use in the legend. |
---|
1083 | this.label = ''; |
---|
1084 | // prop: showLabel |
---|
1085 | // true to show label for this series in the legend. |
---|
1086 | this.showLabel = true; |
---|
1087 | // prop: color |
---|
1088 | // css color spec for the series |
---|
1089 | this.color; |
---|
1090 | // prop: lineWidth |
---|
1091 | // width of the line in pixels. May have different meanings depending on renderer. |
---|
1092 | this.lineWidth = 2.5; |
---|
1093 | // prop: lineJoin |
---|
1094 | // Canvas lineJoin style between segments of series. |
---|
1095 | this.lineJoin = 'round'; |
---|
1096 | // prop: lineCap |
---|
1097 | // Canvas lineCap style at ends of line. |
---|
1098 | this.lineCap = 'round'; |
---|
1099 | // prop: shadow |
---|
1100 | // wether or not to draw a shadow on the line |
---|
1101 | this.shadow = true; |
---|
1102 | // prop: shadowAngle |
---|
1103 | // Shadow angle in degrees |
---|
1104 | this.shadowAngle = 45; |
---|
1105 | // prop: shadowOffset |
---|
1106 | // Shadow offset from line in pixels |
---|
1107 | this.shadowOffset = 1.25; |
---|
1108 | // prop: shadowDepth |
---|
1109 | // Number of times shadow is stroked, each stroke offset shadowOffset from the last. |
---|
1110 | this.shadowDepth = 3; |
---|
1111 | // prop: shadowAlpha |
---|
1112 | // Alpha channel transparency of shadow. 0 = transparent. |
---|
1113 | this.shadowAlpha = '0.1'; |
---|
1114 | // prop: breakOnNull |
---|
1115 | // Wether line segments should be be broken at null value. |
---|
1116 | // False will join point on either side of line. |
---|
1117 | this.breakOnNull = false; |
---|
1118 | // prop: markerRenderer |
---|
1119 | // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points, |
---|
1120 | // see <$.jqplot.MarkerRenderer>. |
---|
1121 | this.markerRenderer = $.jqplot.MarkerRenderer; |
---|
1122 | // prop: markerOptions |
---|
1123 | // renderer specific options to pass to the markerRenderer, |
---|
1124 | // see <$.jqplot.MarkerRenderer>. |
---|
1125 | this.markerOptions = {}; |
---|
1126 | // prop: showLine |
---|
1127 | // wether to actually draw the line or not. Series will still be renderered, even if no line is drawn. |
---|
1128 | this.showLine = true; |
---|
1129 | // prop: showMarker |
---|
1130 | // wether or not to show the markers at the data points. |
---|
1131 | this.showMarker = true; |
---|
1132 | // prop: index |
---|
1133 | // 0 based index of this series in the plot series array. |
---|
1134 | this.index; |
---|
1135 | // prop: fill |
---|
1136 | // true or false, wether to fill under lines or in bars. |
---|
1137 | // May not be implemented in all renderers. |
---|
1138 | this.fill = false; |
---|
1139 | // prop: fillColor |
---|
1140 | // CSS color spec to use for fill under line. Defaults to line color. |
---|
1141 | this.fillColor; |
---|
1142 | // prop: fillAlpha |
---|
1143 | // Alpha transparency to apply to the fill under the line. |
---|
1144 | // Use this to adjust alpha separate from fill color. |
---|
1145 | this.fillAlpha; |
---|
1146 | // prop: fillAndStroke |
---|
1147 | // If true will stroke the line (with color this.color) as well as fill under it. |
---|
1148 | // Applies only when fill is true. |
---|
1149 | this.fillAndStroke = false; |
---|
1150 | // prop: disableStack |
---|
1151 | // true to not stack this series with other series in the plot. |
---|
1152 | // To render properly, non-stacked series must come after any stacked series |
---|
1153 | // in the plot's data series array. So, the plot's data series array would look like: |
---|
1154 | // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...] |
---|
1155 | // disableStack will put a gap in the stacking order of series, and subsequent |
---|
1156 | // stacked series will not fill down through the non-stacked series and will |
---|
1157 | // most likely not stack properly on top of the non-stacked series. |
---|
1158 | this.disableStack = false; |
---|
1159 | // _stack is set by the Plot if the plot is a stacked chart. |
---|
1160 | // will stack lines or bars on top of one another to build a "mountain" style chart. |
---|
1161 | // May not be implemented in all renderers. |
---|
1162 | this._stack = false; |
---|
1163 | // prop: neighborThreshold |
---|
1164 | // how close or far (in pixels) the cursor must be from a point marker to detect the point. |
---|
1165 | this.neighborThreshold = 4; |
---|
1166 | // prop: fillToZero |
---|
1167 | // true will force bar and filled series to fill toward zero on the fill Axis. |
---|
1168 | this.fillToZero = false; |
---|
1169 | // prop: fillToValue |
---|
1170 | // fill a filled series to this value on the fill axis. |
---|
1171 | // Works in conjunction with fillToZero, so that must be true. |
---|
1172 | this.fillToValue = 0; |
---|
1173 | // prop: fillAxis |
---|
1174 | // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true. |
---|
1175 | // 'y' means fill up/down to 0 on the y axis for this series. |
---|
1176 | this.fillAxis = 'y'; |
---|
1177 | // prop: useNegativeColors |
---|
1178 | // true to color negative values differently in filled and bar charts. |
---|
1179 | this.useNegativeColors = true; |
---|
1180 | this._stackData = []; |
---|
1181 | // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If |
---|
1182 | // stacked, _plotData is accumulation of stacking data. |
---|
1183 | this._plotData = []; |
---|
1184 | // _plotValues hold the individual x and y values that will be plotted for this series. |
---|
1185 | this._plotValues = {x:[], y:[]}; |
---|
1186 | // statistics about the intervals between data points. Used for auto scaling. |
---|
1187 | this._intervals = {x:{}, y:{}}; |
---|
1188 | // data from the previous series, for stacked charts. |
---|
1189 | this._prevPlotData = []; |
---|
1190 | this._prevGridData = []; |
---|
1191 | this._stackAxis = 'y'; |
---|
1192 | this._primaryAxis = '_xaxis'; |
---|
1193 | // give each series a canvas to draw on. This should allow for redrawing speedups. |
---|
1194 | this.canvas = new $.jqplot.GenericCanvas(); |
---|
1195 | this.shadowCanvas = new $.jqplot.GenericCanvas(); |
---|
1196 | this.plugins = {}; |
---|
1197 | // sum of y values in this series. |
---|
1198 | this._sumy = 0; |
---|
1199 | this._sumx = 0; |
---|
1200 | this._type = ''; |
---|
1201 | } |
---|
1202 | |
---|
1203 | Series.prototype = new $.jqplot.ElemContainer(); |
---|
1204 | Series.prototype.constructor = Series; |
---|
1205 | |
---|
1206 | Series.prototype.init = function(index, gridbw, plot) { |
---|
1207 | // weed out any null values in the data. |
---|
1208 | this.index = index; |
---|
1209 | this.gridBorderWidth = gridbw; |
---|
1210 | var d = this.data; |
---|
1211 | var temp = [], i; |
---|
1212 | for (i=0; i<d.length; i++) { |
---|
1213 | if (! this.breakOnNull) { |
---|
1214 | if (d[i] == null || d[i][0] == null || d[i][1] == null) { |
---|
1215 | continue; |
---|
1216 | } |
---|
1217 | else { |
---|
1218 | temp.push(d[i]); |
---|
1219 | } |
---|
1220 | } |
---|
1221 | else { |
---|
1222 | // TODO: figure out what to do with null values |
---|
1223 | // probably involve keeping nulls in data array |
---|
1224 | // and then updating renderers to break line |
---|
1225 | // when it hits null value. |
---|
1226 | // For now, just keep value. |
---|
1227 | temp.push(d[i]); |
---|
1228 | } |
---|
1229 | } |
---|
1230 | this.data = temp; |
---|
1231 | if (!this.fillColor) { |
---|
1232 | this.fillColor = this.color; |
---|
1233 | } |
---|
1234 | if (this.fillAlpha) { |
---|
1235 | var comp = $.jqplot.normalize2rgb(this.fillColor); |
---|
1236 | var comp = $.jqplot.getColorComponents(comp); |
---|
1237 | this.fillColor = 'rgba('+comp[0]+','+comp[1]+','+comp[2]+','+this.fillAlpha+')'; |
---|
1238 | } |
---|
1239 | this.renderer = new this.renderer(); |
---|
1240 | this.renderer.init.call(this, this.rendererOptions, plot); |
---|
1241 | this.markerRenderer = new this.markerRenderer(); |
---|
1242 | if (!this.markerOptions.color) { |
---|
1243 | this.markerOptions.color = this.color; |
---|
1244 | } |
---|
1245 | if (this.markerOptions.show == null) { |
---|
1246 | this.markerOptions.show = this.showMarker; |
---|
1247 | } |
---|
1248 | this.showMarker = this.markerOptions.show; |
---|
1249 | // the markerRenderer is called within it's own scaope, don't want to overwrite series options!! |
---|
1250 | this.markerRenderer.init(this.markerOptions); |
---|
1251 | }; |
---|
1252 | |
---|
1253 | // data - optional data point array to draw using this series renderer |
---|
1254 | // gridData - optional grid data point array to draw using this series renderer |
---|
1255 | // stackData - array of cumulative data for stacked plots. |
---|
1256 | Series.prototype.draw = function(sctx, opts, plot) { |
---|
1257 | var options = (opts == undefined) ? {} : opts; |
---|
1258 | sctx = (sctx == undefined) ? this.canvas._ctx : sctx; |
---|
1259 | |
---|
1260 | var j, data, gridData; |
---|
1261 | |
---|
1262 | // hooks get called even if series not shown |
---|
1263 | // we don't clear canvas here, it would wipe out all other series as well. |
---|
1264 | for (j=0; j<$.jqplot.preDrawSeriesHooks.length; j++) { |
---|
1265 | $.jqplot.preDrawSeriesHooks[j].call(this, sctx, options); |
---|
1266 | } |
---|
1267 | if (this.show) { |
---|
1268 | this.renderer.setGridData.call(this, plot); |
---|
1269 | if (!options.preventJqPlotSeriesDrawTrigger) { |
---|
1270 | $(sctx.canvas).trigger('jqplotSeriesDraw', [this.data, this.gridData]); |
---|
1271 | } |
---|
1272 | data = []; |
---|
1273 | if (options.data) { |
---|
1274 | data = options.data; |
---|
1275 | } |
---|
1276 | else if (!this._stack) { |
---|
1277 | data = this.data; |
---|
1278 | } |
---|
1279 | else { |
---|
1280 | data = this._plotData; |
---|
1281 | } |
---|
1282 | gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot); |
---|
1283 | this.renderer.draw.call(this, sctx, gridData, options, plot); |
---|
1284 | } |
---|
1285 | |
---|
1286 | for (j=0; j<$.jqplot.postDrawSeriesHooks.length; j++) { |
---|
1287 | $.jqplot.postDrawSeriesHooks[j].call(this, sctx, options); |
---|
1288 | } |
---|
1289 | |
---|
1290 | sctx = opts = plot = j = data = gridData = null; |
---|
1291 | }; |
---|
1292 | |
---|
1293 | Series.prototype.drawShadow = function(sctx, opts, plot) { |
---|
1294 | var options = (opts == undefined) ? {} : opts; |
---|
1295 | sctx = (sctx == undefined) ? this.shadowCanvas._ctx : sctx; |
---|
1296 | |
---|
1297 | var j, data, gridData; |
---|
1298 | |
---|
1299 | // hooks get called even if series not shown |
---|
1300 | // we don't clear canvas here, it would wipe out all other series as well. |
---|
1301 | for (j=0; j<$.jqplot.preDrawSeriesShadowHooks.length; j++) { |
---|
1302 | $.jqplot.preDrawSeriesShadowHooks[j].call(this, sctx, options); |
---|
1303 | } |
---|
1304 | if (this.shadow) { |
---|
1305 | this.renderer.setGridData.call(this, plot); |
---|
1306 | |
---|
1307 | data = []; |
---|
1308 | if (options.data) { |
---|
1309 | data = options.data; |
---|
1310 | } |
---|
1311 | else if (!this._stack) { |
---|
1312 | data = this.data; |
---|
1313 | } |
---|
1314 | else { |
---|
1315 | data = this._plotData; |
---|
1316 | } |
---|
1317 | gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot); |
---|
1318 | |
---|
1319 | this.renderer.drawShadow.call(this, sctx, gridData, options); |
---|
1320 | } |
---|
1321 | |
---|
1322 | for (j=0; j<$.jqplot.postDrawSeriesShadowHooks.length; j++) { |
---|
1323 | $.jqplot.postDrawSeriesShadowHooks[j].call(this, sctx, options); |
---|
1324 | } |
---|
1325 | |
---|
1326 | sctx = opts = plot = j = data = gridData = null; |
---|
1327 | |
---|
1328 | }; |
---|
1329 | |
---|
1330 | // toggles series display on plot, e.g. show/hide series |
---|
1331 | Series.prototype.toggleDisplay = function(ev) { |
---|
1332 | var s, speed; |
---|
1333 | if (ev.data.series) { |
---|
1334 | s = ev.data.series; |
---|
1335 | } |
---|
1336 | else { |
---|
1337 | s = this; |
---|
1338 | } |
---|
1339 | if (ev.data.speed) { |
---|
1340 | speed = ev.data.speed; |
---|
1341 | } |
---|
1342 | if (speed) { |
---|
1343 | if (s.canvas._elem.is(':hidden')) { |
---|
1344 | if (s.shadowCanvas._elem) { |
---|
1345 | s.shadowCanvas._elem.fadeIn(speed); |
---|
1346 | } |
---|
1347 | s.canvas._elem.fadeIn(speed); |
---|
1348 | s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeIn(speed); |
---|
1349 | } |
---|
1350 | else { |
---|
1351 | if (s.shadowCanvas._elem) { |
---|
1352 | s.shadowCanvas._elem.fadeOut(speed); |
---|
1353 | } |
---|
1354 | s.canvas._elem.fadeOut(speed); |
---|
1355 | s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeOut(speed); |
---|
1356 | } |
---|
1357 | } |
---|
1358 | else { |
---|
1359 | if (s.canvas._elem.is(':hidden')) { |
---|
1360 | if (s.shadowCanvas._elem) { |
---|
1361 | s.shadowCanvas._elem.show(); |
---|
1362 | } |
---|
1363 | s.canvas._elem.show(); |
---|
1364 | s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).show(); |
---|
1365 | } |
---|
1366 | else { |
---|
1367 | if (s.shadowCanvas._elem) { |
---|
1368 | s.shadowCanvas._elem.hide(); |
---|
1369 | } |
---|
1370 | s.canvas._elem.hide(); |
---|
1371 | s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide(); |
---|
1372 | } |
---|
1373 | } |
---|
1374 | }; |
---|
1375 | |
---|
1376 | |
---|
1377 | |
---|
1378 | /** |
---|
1379 | * Class: Grid |
---|
1380 | * |
---|
1381 | * Object representing the grid on which the plot is drawn. The grid in this |
---|
1382 | * context is the area bounded by the axes, the area which will contain the series. |
---|
1383 | * Note, the series are drawn on their own canvas. |
---|
1384 | * The Grid object cannot be instantiated directly, but is created by the Plot oject. |
---|
1385 | * Grid properties can be set or overriden by the options passed in from the user. |
---|
1386 | */ |
---|
1387 | function Grid() { |
---|
1388 | $.jqplot.ElemContainer.call(this); |
---|
1389 | // Group: Properties |
---|
1390 | |
---|
1391 | // prop: drawGridlines |
---|
1392 | // wether to draw the gridlines on the plot. |
---|
1393 | this.drawGridlines = true; |
---|
1394 | // prop: gridLineColor |
---|
1395 | // color of the grid lines. |
---|
1396 | this.gridLineColor = '#cccccc'; |
---|
1397 | // prop: gridLineWidth |
---|
1398 | // width of the grid lines. |
---|
1399 | this.gridLineWidth = 1.0; |
---|
1400 | // prop: background |
---|
1401 | // css spec for the background color. |
---|
1402 | this.background = '#fffdf6'; |
---|
1403 | // prop: borderColor |
---|
1404 | // css spec for the color of the grid border. |
---|
1405 | this.borderColor = '#999999'; |
---|
1406 | // prop: borderWidth |
---|
1407 | // width of the border in pixels. |
---|
1408 | this.borderWidth = 2.0; |
---|
1409 | // prop: drawBorder |
---|
1410 | // True to draw border around grid. |
---|
1411 | this.drawBorder = true; |
---|
1412 | // prop: shadow |
---|
1413 | // wether to show a shadow behind the grid. |
---|
1414 | this.shadow = true; |
---|
1415 | // prop: shadowAngle |
---|
1416 | // shadow angle in degrees |
---|
1417 | this.shadowAngle = 45; |
---|
1418 | // prop: shadowOffset |
---|
1419 | // Offset of each shadow stroke from the border in pixels |
---|
1420 | this.shadowOffset = 1.5; |
---|
1421 | // prop: shadowWidth |
---|
1422 | // width of the stoke for the shadow |
---|
1423 | this.shadowWidth = 3; |
---|
1424 | // prop: shadowDepth |
---|
1425 | // Number of times shadow is stroked, each stroke offset shadowOffset from the last. |
---|
1426 | this.shadowDepth = 3; |
---|
1427 | // prop: shadowColor |
---|
1428 | // an optional css color spec for the shadow in 'rgba(n, n, n, n)' form |
---|
1429 | this.shadowColor = null; |
---|
1430 | // prop: shadowAlpha |
---|
1431 | // Alpha channel transparency of shadow. 0 = transparent. |
---|
1432 | this.shadowAlpha = '0.07'; |
---|
1433 | this._left; |
---|
1434 | this._top; |
---|
1435 | this._right; |
---|
1436 | this._bottom; |
---|
1437 | this._width; |
---|
1438 | this._height; |
---|
1439 | this._axes = []; |
---|
1440 | // prop: renderer |
---|
1441 | // Instance of a renderer which will actually render the grid, |
---|
1442 | // see <$.jqplot.CanvasGridRenderer>. |
---|
1443 | this.renderer = $.jqplot.CanvasGridRenderer; |
---|
1444 | // prop: rendererOptions |
---|
1445 | // Options to pass on to the renderer, |
---|
1446 | // see <$.jqplot.CanvasGridRenderer>. |
---|
1447 | this.rendererOptions = {}; |
---|
1448 | this._offsets = {top:null, bottom:null, left:null, right:null}; |
---|
1449 | } |
---|
1450 | |
---|
1451 | Grid.prototype = new $.jqplot.ElemContainer(); |
---|
1452 | Grid.prototype.constructor = Grid; |
---|
1453 | |
---|
1454 | Grid.prototype.init = function() { |
---|
1455 | this.renderer = new this.renderer(); |
---|
1456 | this.renderer.init.call(this, this.rendererOptions); |
---|
1457 | }; |
---|
1458 | |
---|
1459 | Grid.prototype.createElement = function(offsets,plot) { |
---|
1460 | this._offsets = offsets; |
---|
1461 | return this.renderer.createElement.call(this, plot); |
---|
1462 | }; |
---|
1463 | |
---|
1464 | Grid.prototype.draw = function() { |
---|
1465 | this.renderer.draw.call(this); |
---|
1466 | }; |
---|
1467 | |
---|
1468 | $.jqplot.GenericCanvas = function() { |
---|
1469 | $.jqplot.ElemContainer.call(this); |
---|
1470 | this._ctx; |
---|
1471 | }; |
---|
1472 | |
---|
1473 | $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer(); |
---|
1474 | $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas; |
---|
1475 | |
---|
1476 | $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions, plot) { |
---|
1477 | this._offsets = offsets; |
---|
1478 | var klass = 'jqplot'; |
---|
1479 | if (clss != undefined) { |
---|
1480 | klass = clss; |
---|
1481 | } |
---|
1482 | var elem; |
---|
1483 | |
---|
1484 | // if (this._elem) { |
---|
1485 | // // Memory Leaks patch |
---|
1486 | // if ($.jqplot.use_excanvas) { |
---|
1487 | // window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); |
---|
1488 | // } |
---|
1489 | // } |
---|
1490 | // else { |
---|
1491 | // // don't use the canvas manager with excanvas. |
---|
1492 | // if ($.jqplot.use_excanvas) { |
---|
1493 | // elem = document.createElement('canvas'); |
---|
1494 | // } |
---|
1495 | // else { |
---|
1496 | // elem = plot.canvasManager.getCanvas(); |
---|
1497 | // } |
---|
1498 | |
---|
1499 | // } |
---|
1500 | |
---|
1501 | elem = plot.canvasManager.getCanvas(); |
---|
1502 | |
---|
1503 | // if new plotDimensions supplied, use them. |
---|
1504 | if (plotDimensions != null) { |
---|
1505 | this._plotDimensions = plotDimensions; |
---|
1506 | } |
---|
1507 | |
---|
1508 | elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right; |
---|
1509 | elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom; |
---|
1510 | this._elem = $(elem); |
---|
1511 | this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top }); |
---|
1512 | |
---|
1513 | this._elem.addClass(klass); |
---|
1514 | |
---|
1515 | elem = plot.canvasManager.initCanvas(elem); |
---|
1516 | |
---|
1517 | elem = null; |
---|
1518 | return this._elem; |
---|
1519 | }; |
---|
1520 | |
---|
1521 | $.jqplot.GenericCanvas.prototype.setContext = function() { |
---|
1522 | this._ctx = this._elem.get(0).getContext("2d"); |
---|
1523 | return this._ctx; |
---|
1524 | }; |
---|
1525 | |
---|
1526 | // Memory Leaks patch |
---|
1527 | $.jqplot.GenericCanvas.prototype.resetCanvas = function() { |
---|
1528 | if (this._elem) { |
---|
1529 | if ($.jqplot.use_excanvas) { |
---|
1530 | window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); |
---|
1531 | } |
---|
1532 | |
---|
1533 | //this._elem.remove(); |
---|
1534 | this._elem.emptyForce(); |
---|
1535 | } |
---|
1536 | |
---|
1537 | this._ctx = null; |
---|
1538 | }; |
---|
1539 | |
---|
1540 | $.jqplot.HooksManager = function () { |
---|
1541 | this.hooks =[]; |
---|
1542 | }; |
---|
1543 | |
---|
1544 | $.jqplot.HooksManager.prototype.addOnce = function(fn) { |
---|
1545 | var havehook = false, i; |
---|
1546 | for (i=0; i<this.hooks.length; i++) { |
---|
1547 | if (this.hooks[i][0] == fn) { |
---|
1548 | havehook = true; |
---|
1549 | } |
---|
1550 | } |
---|
1551 | if (!havehook) { |
---|
1552 | this.hooks.push(fn); |
---|
1553 | } |
---|
1554 | }; |
---|
1555 | |
---|
1556 | $.jqplot.HooksManager.prototype.add = function(fn) { |
---|
1557 | this.hooks.push(fn); |
---|
1558 | }; |
---|
1559 | |
---|
1560 | $.jqplot.EventListenerManager = function () { |
---|
1561 | this.hooks =[]; |
---|
1562 | }; |
---|
1563 | |
---|
1564 | $.jqplot.EventListenerManager.prototype.addOnce = function(ev, fn) { |
---|
1565 | var havehook = false, h, i; |
---|
1566 | for (i=0; i<this.hooks.length; i++) { |
---|
1567 | h = this.hooks[i]; |
---|
1568 | if (h[0] == ev && h[1] == fn) { |
---|
1569 | havehook = true; |
---|
1570 | } |
---|
1571 | } |
---|
1572 | if (!havehook) { |
---|
1573 | this.hooks.push([ev, fn]); |
---|
1574 | } |
---|
1575 | }; |
---|
1576 | |
---|
1577 | $.jqplot.EventListenerManager.prototype.add = function(ev, fn) { |
---|
1578 | this.hooks.push([ev, fn]); |
---|
1579 | }; |
---|
1580 | |
---|
1581 | /** |
---|
1582 | * Class: jqPlot |
---|
1583 | * Plot object returned by call to $.jqplot. Handles parsing user options, |
---|
1584 | * creating sub objects (Axes, legend, title, series) and rendering the plot. |
---|
1585 | */ |
---|
1586 | function jqPlot() { |
---|
1587 | // Group: Properties |
---|
1588 | // These properties are specified at the top of the options object |
---|
1589 | // like so: |
---|
1590 | // > { |
---|
1591 | // > axesDefaults:{min:0}, |
---|
1592 | // > series:[{color:'#6633dd'}], |
---|
1593 | // > title: 'A Plot' |
---|
1594 | // > } |
---|
1595 | // |
---|
1596 | // prop: data |
---|
1597 | // user's data. Data should *NOT* be specified in the options object, |
---|
1598 | // but be passed in as the second argument to the $.jqplot() function. |
---|
1599 | // The data property is described here soley for reference. |
---|
1600 | // The data should be in the form of an array of 2D or 1D arrays like |
---|
1601 | // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ]. |
---|
1602 | this.data = []; |
---|
1603 | // prop dataRenderer |
---|
1604 | // A callable which can be used to preprocess data passed into the plot. |
---|
1605 | // Will be called with 2 arguments, the plot data and a reference to the plot. |
---|
1606 | this.dataRenderer; |
---|
1607 | // prop dataRendererOptions |
---|
1608 | // Options that will be passed to the dataRenderer. |
---|
1609 | // Can be of any type. |
---|
1610 | this.dataRendererOptions; |
---|
1611 | // prop noDataIndicator |
---|
1612 | // Options to set up a mock plot with a data loading indicator if no data is specified. |
---|
1613 | this.noDataIndicator = { |
---|
1614 | show: false, |
---|
1615 | indicator: 'Loading Data...', |
---|
1616 | axes: { |
---|
1617 | xaxis: { |
---|
1618 | min: 0, |
---|
1619 | max: 10, |
---|
1620 | tickInterval: 2, |
---|
1621 | show: true |
---|
1622 | }, |
---|
1623 | yaxis: { |
---|
1624 | min: 0, |
---|
1625 | max: 12, |
---|
1626 | tickInterval: 3, |
---|
1627 | show: true |
---|
1628 | } |
---|
1629 | } |
---|
1630 | }; |
---|
1631 | // The id of the dom element to render the plot into |
---|
1632 | this.targetId = null; |
---|
1633 | // the jquery object for the dom target. |
---|
1634 | this.target = null; |
---|
1635 | this.defaults = { |
---|
1636 | // prop: axesDefaults |
---|
1637 | // default options that will be applied to all axes. |
---|
1638 | // see <Axis> for axes options. |
---|
1639 | axesDefaults: {}, |
---|
1640 | axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}}, |
---|
1641 | // prop: seriesDefaults |
---|
1642 | // default options that will be applied to all series. |
---|
1643 | // see <Series> for series options. |
---|
1644 | seriesDefaults: {}, |
---|
1645 | series:[] |
---|
1646 | }; |
---|
1647 | // prop: series |
---|
1648 | // Array of series object options. |
---|
1649 | // see <Series> for series specific options. |
---|
1650 | this.series = []; |
---|
1651 | // prop: axes |
---|
1652 | // up to 4 axes are supported, each with it's own options, |
---|
1653 | // See <Axis> for axis specific options. |
---|
1654 | this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis')}; |
---|
1655 | // prop: grid |
---|
1656 | // See <Grid> for grid specific options. |
---|
1657 | this.grid = new Grid(); |
---|
1658 | // prop: legend |
---|
1659 | // see <$.jqplot.TableLegendRenderer> |
---|
1660 | this.legend = new Legend(); |
---|
1661 | this.baseCanvas = new $.jqplot.GenericCanvas(); |
---|
1662 | // array of series indicies. Keep track of order |
---|
1663 | // which series canvases are displayed, lowest |
---|
1664 | // to highest, back to front. |
---|
1665 | this.seriesStack = []; |
---|
1666 | this.previousSeriesStack = []; |
---|
1667 | this.eventCanvas = new $.jqplot.GenericCanvas(); |
---|
1668 | this._width = null; |
---|
1669 | this._height = null; |
---|
1670 | this._plotDimensions = {height:null, width:null}; |
---|
1671 | this._gridPadding = {top:null, right:null, bottom:null, left:null}; |
---|
1672 | this._defaultGridPadding = {top:10, right:10, bottom:23, left:10}; |
---|
1673 | // a shortcut for axis syncTicks options. Not implemented yet. |
---|
1674 | this.syncXTicks = true; |
---|
1675 | // a shortcut for axis syncTicks options. Not implemented yet. |
---|
1676 | this.syncYTicks = true; |
---|
1677 | // prop: seriesColors |
---|
1678 | // Ann array of CSS color specifications that will be applied, in order, |
---|
1679 | // to the series in the plot. Colors will wrap around so, if their |
---|
1680 | // are more series than colors, colors will be reused starting at the |
---|
1681 | // beginning. For pie charts, this specifies the colors of the slices. |
---|
1682 | this.seriesColors = $.jqplot.config.defaultColors; |
---|
1683 | this.negativeSeriesColors = $.jqplot.config.defaultNegativeColors; |
---|
1684 | // prop: sortData |
---|
1685 | // false to not sort the data passed in by the user. |
---|
1686 | // Many bar, stakced and other graphs as well as many plugins depend on |
---|
1687 | // having sorted data. |
---|
1688 | this.sortData = true; |
---|
1689 | var seriesColorsIndex = 0; |
---|
1690 | // prop textColor |
---|
1691 | // css spec for the css color attribute. Default for the entire plot. |
---|
1692 | this.textColor; |
---|
1693 | // prop; fontFamily |
---|
1694 | // css spec for the font-family attribute. Default for the entire plot. |
---|
1695 | this.fontFamily; |
---|
1696 | // prop: fontSize |
---|
1697 | // css spec for the font-size attribute. Default for the entire plot. |
---|
1698 | this.fontSize; |
---|
1699 | // prop: title |
---|
1700 | // Title object. See <Title> for specific options. As a shortcut, you |
---|
1701 | // can specify the title option as just a string like: title: 'My Plot' |
---|
1702 | // and this will create a new title object with the specified text. |
---|
1703 | this.title = new Title(); |
---|
1704 | // container to hold all of the merged options. Convienence for plugins. |
---|
1705 | this.options = {}; |
---|
1706 | // prop: stackSeries |
---|
1707 | // true or false, creates a stack or "mountain" plot. |
---|
1708 | // Not all series renderers may implement this option. |
---|
1709 | this.stackSeries = false; |
---|
1710 | // prop: defaultAxisStart |
---|
1711 | // 1-D data series are internally converted into 2-D [x,y] data point arrays |
---|
1712 | // by jqPlot. This is the default starting value for the missing x or y value. |
---|
1713 | // The added data will be a monotonically increasing series (e.g. [1, 2, 3, ...]) |
---|
1714 | // starting at this value. |
---|
1715 | this.defaultAxisStart = 1; |
---|
1716 | // array to hold the cumulative stacked series data. |
---|
1717 | // used to ajust the individual series data, which won't have access to other |
---|
1718 | // series data. |
---|
1719 | this._stackData = []; |
---|
1720 | // array that holds the data to be plotted. This will be the series data |
---|
1721 | // merged with the the appropriate data from _stackData according to the stackAxis. |
---|
1722 | this._plotData = []; |
---|
1723 | // Namespece to hold plugins. Generally non-renderer plugins add themselves to here. |
---|
1724 | this.plugins = {}; |
---|
1725 | // Count how many times the draw method has been called while the plot is visible. |
---|
1726 | // Mostly used to test if plot has never been dran (=0), has been successfully drawn |
---|
1727 | // into a visible container once (=1) or draw more than once into a visible container. |
---|
1728 | // Can use this in tests to see if plot has been visibly drawn at least one time. |
---|
1729 | // After plot has been visibly drawn once, it generally doesn't need redrawn if its |
---|
1730 | // container is hidden and shown. |
---|
1731 | this._drawCount = 0; |
---|
1732 | // this.doCustomEventBinding = true; |
---|
1733 | // prop: drawIfHidden |
---|
1734 | // True to execute the draw method even if the plot target is hidden. |
---|
1735 | // Generally, this should be false. Most plot elements will not be sized/ |
---|
1736 | // positioned correclty if renderered into a hidden container. To render into |
---|
1737 | // a hidden container, call the replot method when the container is shown. |
---|
1738 | this.drawIfHidden = false; |
---|
1739 | // true to intercept right click events and fire a 'jqplotRightClick' event. |
---|
1740 | // this will also block the context menu. |
---|
1741 | this.captureRightClick = false; |
---|
1742 | this.themeEngine = new $.jqplot.ThemeEngine(); |
---|
1743 | // sum of y values for all series in plot. |
---|
1744 | // used in mekko chart. |
---|
1745 | this._sumy = 0; |
---|
1746 | this._sumx = 0; |
---|
1747 | this.preInitHooks = new $.jqplot.HooksManager(); |
---|
1748 | this.postInitHooks = new $.jqplot.HooksManager(); |
---|
1749 | this.preParseOptionsHooks = new $.jqplot.HooksManager(); |
---|
1750 | this.postParseOptionsHooks = new $.jqplot.HooksManager(); |
---|
1751 | this.preDrawHooks = new $.jqplot.HooksManager(); |
---|
1752 | this.postDrawHooks = new $.jqplot.HooksManager(); |
---|
1753 | this.preDrawSeriesHooks = new $.jqplot.HooksManager(); |
---|
1754 | this.postDrawSeriesHooks = new $.jqplot.HooksManager(); |
---|
1755 | this.preDrawLegendHooks = new $.jqplot.HooksManager(); |
---|
1756 | this.addLegendRowHooks = new $.jqplot.HooksManager(); |
---|
1757 | this.preSeriesInitHooks = new $.jqplot.HooksManager(); |
---|
1758 | this.postSeriesInitHooks = new $.jqplot.HooksManager(); |
---|
1759 | this.preParseSeriesOptionsHooks = new $.jqplot.HooksManager(); |
---|
1760 | this.postParseSeriesOptionsHooks = new $.jqplot.HooksManager(); |
---|
1761 | this.eventListenerHooks = new $.jqplot.EventListenerManager(); |
---|
1762 | this.preDrawSeriesShadowHooks = new $.jqplot.HooksManager(); |
---|
1763 | this.postDrawSeriesShadowHooks = new $.jqplot.HooksManager(); |
---|
1764 | |
---|
1765 | this.colorGenerator = $.jqplot.ColorGenerator; |
---|
1766 | |
---|
1767 | this.canvasManager = new $.jqplot.CanvasManager(); |
---|
1768 | |
---|
1769 | // Group: methods |
---|
1770 | // |
---|
1771 | // method: init |
---|
1772 | // sets the plot target, checks data and applies user |
---|
1773 | // options to plot. |
---|
1774 | this.init = function(target, data, options) { |
---|
1775 | options = options || {}; |
---|
1776 | for (var i=0; i<$.jqplot.preInitHooks.length; i++) { |
---|
1777 | $.jqplot.preInitHooks[i].call(this, target, data, options); |
---|
1778 | } |
---|
1779 | |
---|
1780 | for (var i=0; i<this.preInitHooks.hooks.length; i++) { |
---|
1781 | this.preInitHooks.hooks[i].call(this, target, data, options); |
---|
1782 | } |
---|
1783 | |
---|
1784 | this.targetId = '#'+target; |
---|
1785 | this.target = $('#'+target); |
---|
1786 | // remove any error class that may be stuck on target. |
---|
1787 | this.target.removeClass('jqplot-error'); |
---|
1788 | if (!this.target.get(0)) { |
---|
1789 | throw "No plot target specified"; |
---|
1790 | } |
---|
1791 | |
---|
1792 | // make sure the target is positioned by some means and set css |
---|
1793 | if (this.target.css('position') == 'static') { |
---|
1794 | this.target.css('position', 'relative'); |
---|
1795 | } |
---|
1796 | if (!this.target.hasClass('jqplot-target')) { |
---|
1797 | this.target.addClass('jqplot-target'); |
---|
1798 | } |
---|
1799 | |
---|
1800 | // if no height or width specified, use a default. |
---|
1801 | if (!this.target.height()) { |
---|
1802 | var h; |
---|
1803 | if (options && options.height) { |
---|
1804 | h = parseInt(options.height, 10); |
---|
1805 | } |
---|
1806 | else if (this.target.attr('data-height')) { |
---|
1807 | h = parseInt(this.target.attr('data-height'), 10); |
---|
1808 | } |
---|
1809 | else { |
---|
1810 | h = parseInt($.jqplot.config.defaultHeight, 10); |
---|
1811 | } |
---|
1812 | this._height = h; |
---|
1813 | this.target.css('height', h+'px'); |
---|
1814 | } |
---|
1815 | else { |
---|
1816 | this._height = h = this.target.height(); |
---|
1817 | } |
---|
1818 | if (!this.target.width()) { |
---|
1819 | var w; |
---|
1820 | if (options && options.width) { |
---|
1821 | w = parseInt(options.width, 10); |
---|
1822 | } |
---|
1823 | else if (this.target.attr('data-width')) { |
---|
1824 | w = parseInt(this.target.attr('data-width'), 10); |
---|
1825 | } |
---|
1826 | else { |
---|
1827 | w = parseInt($.jqplot.config.defaultWidth, 10); |
---|
1828 | } |
---|
1829 | this._width = w; |
---|
1830 | this.target.css('width', w+'px'); |
---|
1831 | } |
---|
1832 | else { |
---|
1833 | this._width = w = this.target.width(); |
---|
1834 | } |
---|
1835 | |
---|
1836 | this._plotDimensions.height = this._height; |
---|
1837 | this._plotDimensions.width = this._width; |
---|
1838 | this.grid._plotDimensions = this._plotDimensions; |
---|
1839 | this.title._plotDimensions = this._plotDimensions; |
---|
1840 | this.baseCanvas._plotDimensions = this._plotDimensions; |
---|
1841 | this.eventCanvas._plotDimensions = this._plotDimensions; |
---|
1842 | this.legend._plotDimensions = this._plotDimensions; |
---|
1843 | if (this._height <=0 || this._width <=0 || !this._height || !this._width) { |
---|
1844 | throw "Canvas dimension not set"; |
---|
1845 | } |
---|
1846 | |
---|
1847 | if (options.dataRenderer && jQuery.isFunction(options.dataRenderer)) { |
---|
1848 | if (options.dataRendererOptions) { |
---|
1849 | this.dataRendererOptions = options.dataRendererOptions; |
---|
1850 | } |
---|
1851 | this.dataRenderer = options.dataRenderer; |
---|
1852 | data = this.dataRenderer(data, this, this.dataRendererOptions); |
---|
1853 | } |
---|
1854 | |
---|
1855 | if (options.noDataIndicator && jQuery.isPlainObject(options.noDataIndicator)) { |
---|
1856 | $.extend(true, this.noDataIndicator, options.noDataIndicator); |
---|
1857 | } |
---|
1858 | |
---|
1859 | if (data == null || jQuery.isArray(data) == false || data.length == 0 || jQuery.isArray(data[0]) == false || data[0].length == 0) { |
---|
1860 | |
---|
1861 | if (this.noDataIndicator.show == false) { |
---|
1862 | throw{ |
---|
1863 | name: "DataError", |
---|
1864 | message: "No data to plot." |
---|
1865 | }; |
---|
1866 | } |
---|
1867 | |
---|
1868 | else { |
---|
1869 | // have to be descructive here in order for plot to not try and render series. |
---|
1870 | // This means that $.jqplot() will have to be called again when there is data. |
---|
1871 | //delete options.series; |
---|
1872 | |
---|
1873 | for (var ax in this.noDataIndicator.axes) { |
---|
1874 | for (var prop in this.noDataIndicator.axes[ax]) { |
---|
1875 | this.axes[ax][prop] = this.noDataIndicator.axes[ax][prop]; |
---|
1876 | } |
---|
1877 | } |
---|
1878 | |
---|
1879 | this.postDrawHooks.add(function() { |
---|
1880 | var eh = this.eventCanvas.getHeight(); |
---|
1881 | var ew = this.eventCanvas.getWidth(); |
---|
1882 | var temp = $('<div class="jqplot-noData-container" style="position:absolute;"></div>'); |
---|
1883 | this.target.append(temp); |
---|
1884 | temp.height(eh); |
---|
1885 | temp.width(ew); |
---|
1886 | temp.css('top', this.eventCanvas._offsets.top); |
---|
1887 | temp.css('left', this.eventCanvas._offsets.left); |
---|
1888 | |
---|
1889 | var temp2 = $('<div class="jqplot-noData-contents" style="text-align:center; position:relative; margin-left:auto; margin-right:auto;"></div>'); |
---|
1890 | temp.append(temp2); |
---|
1891 | temp2.html(this.noDataIndicator.indicator); |
---|
1892 | var th = temp2.height(); |
---|
1893 | var tw = temp2.width(); |
---|
1894 | temp2.height(th); |
---|
1895 | temp2.width(tw); |
---|
1896 | temp2.css('top', (eh - th)/2 + 'px'); |
---|
1897 | }); |
---|
1898 | |
---|
1899 | } |
---|
1900 | } |
---|
1901 | |
---|
1902 | this.data = data; |
---|
1903 | |
---|
1904 | this.parseOptions(options); |
---|
1905 | |
---|
1906 | if (this.textColor) { |
---|
1907 | this.target.css('color', this.textColor); |
---|
1908 | } |
---|
1909 | if (this.fontFamily) { |
---|
1910 | this.target.css('font-family', this.fontFamily); |
---|
1911 | } |
---|
1912 | if (this.fontSize) { |
---|
1913 | this.target.css('font-size', this.fontSize); |
---|
1914 | } |
---|
1915 | |
---|
1916 | this.title.init(); |
---|
1917 | this.legend.init(); |
---|
1918 | this._sumy = 0; |
---|
1919 | this._sumx = 0; |
---|
1920 | for (var i=0; i<this.series.length; i++) { |
---|
1921 | // set default stacking order for series canvases |
---|
1922 | this.seriesStack.push(i); |
---|
1923 | this.previousSeriesStack.push(i); |
---|
1924 | this.series[i].shadowCanvas._plotDimensions = this._plotDimensions; |
---|
1925 | this.series[i].canvas._plotDimensions = this._plotDimensions; |
---|
1926 | for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) { |
---|
1927 | $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this); |
---|
1928 | } |
---|
1929 | for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) { |
---|
1930 | this.preSeriesInitHooks.hooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this); |
---|
1931 | } |
---|
1932 | this.populatePlotData(this.series[i], i); |
---|
1933 | this.series[i]._plotDimensions = this._plotDimensions; |
---|
1934 | this.series[i].init(i, this.grid.borderWidth, this); |
---|
1935 | for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) { |
---|
1936 | $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this); |
---|
1937 | } |
---|
1938 | for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) { |
---|
1939 | this.postSeriesInitHooks.hooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this); |
---|
1940 | } |
---|
1941 | this._sumy += this.series[i]._sumy; |
---|
1942 | this._sumx += this.series[i]._sumx; |
---|
1943 | } |
---|
1944 | |
---|
1945 | for (var name in this.axes) { |
---|
1946 | this.axes[name]._plotDimensions = this._plotDimensions; |
---|
1947 | this.axes[name].init(); |
---|
1948 | } |
---|
1949 | |
---|
1950 | if (this.sortData) { |
---|
1951 | sortData(this.series); |
---|
1952 | } |
---|
1953 | this.grid.init(); |
---|
1954 | this.grid._axes = this.axes; |
---|
1955 | |
---|
1956 | this.legend._series = this.series; |
---|
1957 | |
---|
1958 | for (var i=0; i<$.jqplot.postInitHooks.length; i++) { |
---|
1959 | $.jqplot.postInitHooks[i].call(this, target, data, options); |
---|
1960 | } |
---|
1961 | |
---|
1962 | for (var i=0; i<this.postInitHooks.hooks.length; i++) { |
---|
1963 | this.postInitHooks.hooks[i].call(this, target, data, options); |
---|
1964 | } |
---|
1965 | }; |
---|
1966 | |
---|
1967 | // method: resetAxesScale |
---|
1968 | // Reset the specified axes min, max, numberTicks and tickInterval properties to null |
---|
1969 | // or reset these properties on all axes if no list of axes is provided. |
---|
1970 | // |
---|
1971 | // Parameters: |
---|
1972 | // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset. |
---|
1973 | this.resetAxesScale = function(axes, options) { |
---|
1974 | var opts = options || {}; |
---|
1975 | var ax = axes || this.axes; |
---|
1976 | if (ax === true) { |
---|
1977 | ax = this.axes; |
---|
1978 | } |
---|
1979 | if (jQuery.isArray(ax)) { |
---|
1980 | for (var i = 0; i < ax.length; i++) { |
---|
1981 | this.axes[ax[i]].resetScale(opts[ax[i]]); |
---|
1982 | } |
---|
1983 | } |
---|
1984 | else if (typeof(ax) === 'object') { |
---|
1985 | for (var name in ax) { |
---|
1986 | this.axes[name].resetScale(opts[name]); |
---|
1987 | } |
---|
1988 | } |
---|
1989 | }; |
---|
1990 | // method: reInitialize |
---|
1991 | // reinitialize plot for replotting. |
---|
1992 | // not called directly. |
---|
1993 | this.reInitialize = function () { |
---|
1994 | // Plot should be visible and have a height and width. |
---|
1995 | // If plot doesn't have height and width for some |
---|
1996 | // reason, set it by other means. Plot must not have |
---|
1997 | // a display:none attribute, however. |
---|
1998 | |
---|
1999 | // |
---|
2000 | // Wont have options here |
---|
2001 | /* |
---|
2002 | if (!this.target.height()) { |
---|
2003 | var h; |
---|
2004 | if (options && options.height) { |
---|
2005 | h = parseInt(options.height, 10); |
---|
2006 | } |
---|
2007 | else if (this.target.attr('data-height')) { |
---|
2008 | h = parseInt(this.target.attr('data-height'), 10); |
---|
2009 | } |
---|
2010 | else { |
---|
2011 | h = parseInt($.jqplot.config.defaultHeight, 10); |
---|
2012 | } |
---|
2013 | this._height = h; |
---|
2014 | this.target.css('height', h+'px'); |
---|
2015 | } |
---|
2016 | else { |
---|
2017 | this._height = this.target.height(); |
---|
2018 | } |
---|
2019 | if (!this.target.width()) { |
---|
2020 | var w; |
---|
2021 | if (options && options.width) { |
---|
2022 | w = parseInt(options.width, 10); |
---|
2023 | } |
---|
2024 | else if (this.target.attr('data-width')) { |
---|
2025 | w = parseInt(this.target.attr('data-width'), 10); |
---|
2026 | } |
---|
2027 | else { |
---|
2028 | w = parseInt($.jqplot.config.defaultWidth, 10); |
---|
2029 | } |
---|
2030 | this._width = w; |
---|
2031 | this.target.css('width', w+'px'); |
---|
2032 | } |
---|
2033 | else { |
---|
2034 | this._width = this.target.width(); |
---|
2035 | } |
---|
2036 | */ |
---|
2037 | |
---|
2038 | this._height = this.target.height(); |
---|
2039 | this._width = this.target.width(); |
---|
2040 | |
---|
2041 | if (this._height <=0 || this._width <=0 || !this._height || !this._width) { |
---|
2042 | throw "Target dimension not set"; |
---|
2043 | } |
---|
2044 | |
---|
2045 | this._plotDimensions.height = this._height; |
---|
2046 | this._plotDimensions.width = this._width; |
---|
2047 | this.grid._plotDimensions = this._plotDimensions; |
---|
2048 | this.title._plotDimensions = this._plotDimensions; |
---|
2049 | this.baseCanvas._plotDimensions = this._plotDimensions; |
---|
2050 | this.eventCanvas._plotDimensions = this._plotDimensions; |
---|
2051 | this.legend._plotDimensions = this._plotDimensions; |
---|
2052 | |
---|
2053 | for (var n in this.axes) { |
---|
2054 | this.axes[n]._plotWidth = this._width; |
---|
2055 | this.axes[n]._plotHeight = this._height; |
---|
2056 | } |
---|
2057 | |
---|
2058 | this.title._plotWidth = this._width; |
---|
2059 | |
---|
2060 | if (this.textColor) { |
---|
2061 | this.target.css('color', this.textColor); |
---|
2062 | } |
---|
2063 | if (this.fontFamily) { |
---|
2064 | this.target.css('font-family', this.fontFamily); |
---|
2065 | } |
---|
2066 | if (this.fontSize) { |
---|
2067 | this.target.css('font-size', this.fontSize); |
---|
2068 | } |
---|
2069 | |
---|
2070 | this._sumy = 0; |
---|
2071 | this._sumx = 0; |
---|
2072 | for (var i=0; i<this.series.length; i++) { |
---|
2073 | this.populatePlotData(this.series[i], i); |
---|
2074 | this.series[i]._plotDimensions = this._plotDimensions; |
---|
2075 | this.series[i].canvas._plotDimensions = this._plotDimensions; |
---|
2076 | //this.series[i].init(i, this.grid.borderWidth); |
---|
2077 | this._sumy += this.series[i]._sumy; |
---|
2078 | this._sumx += this.series[i]._sumx; |
---|
2079 | } |
---|
2080 | |
---|
2081 | for (var name in this.axes) { |
---|
2082 | // Memory Leaks patch : clear ticks elements |
---|
2083 | var t = this.axes[name]._ticks; |
---|
2084 | for (var i = 0; i < t.length; i++) { |
---|
2085 | var el = t[i]._elem; |
---|
2086 | if (el) { |
---|
2087 | // if canvas renderer |
---|
2088 | if ($.jqplot.use_excanvas) { |
---|
2089 | window.G_vmlCanvasManager.uninitElement(el.get(0)); |
---|
2090 | } |
---|
2091 | el.emptyForce(); |
---|
2092 | el = null; |
---|
2093 | t._elem = null; |
---|
2094 | } |
---|
2095 | } |
---|
2096 | t = null; |
---|
2097 | |
---|
2098 | this.axes[name]._plotDimensions = this._plotDimensions; |
---|
2099 | this.axes[name]._ticks = []; |
---|
2100 | this.axes[name].renderer.init.call(this.axes[name], {}); |
---|
2101 | } |
---|
2102 | |
---|
2103 | if (this.sortData) { |
---|
2104 | sortData(this.series); |
---|
2105 | } |
---|
2106 | |
---|
2107 | this.grid._axes = this.axes; |
---|
2108 | |
---|
2109 | this.legend._series = this.series; |
---|
2110 | }; |
---|
2111 | |
---|
2112 | // sort the series data in increasing order. |
---|
2113 | function sortData(series) { |
---|
2114 | var d, sd, pd, ppd, ret; |
---|
2115 | for (var i=0; i<series.length; i++) { |
---|
2116 | // d = series[i].data; |
---|
2117 | // sd = series[i]._stackData; |
---|
2118 | // pd = series[i]._plotData; |
---|
2119 | // ppd = series[i]._prevPlotData; |
---|
2120 | var check; |
---|
2121 | var bat = [series[i].data, series[i]._stackData, series[i]._plotData, series[i]._prevPlotData]; |
---|
2122 | for (var n=0; n<4; n++) { |
---|
2123 | check = true; |
---|
2124 | d = bat[n]; |
---|
2125 | if (series[i]._stackAxis == 'x') { |
---|
2126 | for (var j = 0; j < d.length; j++) { |
---|
2127 | if (typeof(d[j][1]) != "number") { |
---|
2128 | check = false; |
---|
2129 | break; |
---|
2130 | } |
---|
2131 | } |
---|
2132 | if (check) { |
---|
2133 | d.sort(function(a,b) { return a[1] - b[1]; }); |
---|
2134 | // sd.sort(function(a,b) { return a[1] - b[1]; }); |
---|
2135 | // pd.sort(function(a,b) { return a[1] - b[1]; }); |
---|
2136 | // ppd.sort(function(a,b) { return a[1] - b[1]; }); |
---|
2137 | } |
---|
2138 | } |
---|
2139 | else { |
---|
2140 | for (var j = 0; j < d.length; j++) { |
---|
2141 | if (typeof(d[j][0]) != "number") { |
---|
2142 | check = false; |
---|
2143 | break; |
---|
2144 | } |
---|
2145 | } |
---|
2146 | if (check) { |
---|
2147 | d.sort(function(a,b) { return a[0] - b[0]; }); |
---|
2148 | // sd.sort(function(a,b) { return a[0] - b[0]; }); |
---|
2149 | // pd.sort(function(a,b) { return a[0] - b[0]; }); |
---|
2150 | // ppd.sort(function(a,b) { return a[0] - b[0]; }); |
---|
2151 | } |
---|
2152 | } |
---|
2153 | } |
---|
2154 | |
---|
2155 | } |
---|
2156 | } |
---|
2157 | |
---|
2158 | // populate the _stackData and _plotData arrays for the plot and the series. |
---|
2159 | this.populatePlotData = function(series, index) { |
---|
2160 | // if a stacked chart, compute the stacked data |
---|
2161 | this._plotData = []; |
---|
2162 | this._stackData = []; |
---|
2163 | series._stackData = []; |
---|
2164 | series._plotData = []; |
---|
2165 | var plotValues = {x:[], y:[]}; |
---|
2166 | if (this.stackSeries && !series.disableStack) { |
---|
2167 | series._stack = true; |
---|
2168 | var sidx = series._stackAxis == 'x' ? 0 : 1; |
---|
2169 | var idx = sidx ? 0 : 1; |
---|
2170 | // push the current data into stackData |
---|
2171 | //this._stackData.push(this.series[i].data); |
---|
2172 | var temp = $.extend(true, [], series.data); |
---|
2173 | // create the data that will be plotted for this series |
---|
2174 | var plotdata = $.extend(true, [], series.data); |
---|
2175 | // for first series, nothing to add to stackData. |
---|
2176 | for (var j=0; j<index; j++) { |
---|
2177 | var cd = this.series[j].data; |
---|
2178 | for (var k=0; k<cd.length; k++) { |
---|
2179 | temp[k][0] += cd[k][0]; |
---|
2180 | temp[k][1] += cd[k][1]; |
---|
2181 | // only need to sum up the stack axis column of data |
---|
2182 | plotdata[k][sidx] += cd[k][sidx]; |
---|
2183 | } |
---|
2184 | } |
---|
2185 | for (var i=0; i<plotdata.length; i++) { |
---|
2186 | plotValues.x.push(plotdata[i][0]); |
---|
2187 | plotValues.y.push(plotdata[i][1]); |
---|
2188 | } |
---|
2189 | this._plotData.push(plotdata); |
---|
2190 | this._stackData.push(temp); |
---|
2191 | series._stackData = temp; |
---|
2192 | series._plotData = plotdata; |
---|
2193 | series._plotValues = plotValues; |
---|
2194 | } |
---|
2195 | else { |
---|
2196 | for (var i=0; i<series.data.length; i++) { |
---|
2197 | plotValues.x.push(series.data[i][0]); |
---|
2198 | plotValues.y.push(series.data[i][1]); |
---|
2199 | } |
---|
2200 | this._stackData.push(series.data); |
---|
2201 | this.series[index]._stackData = series.data; |
---|
2202 | this._plotData.push(series.data); |
---|
2203 | series._plotData = series.data; |
---|
2204 | series._plotValues = plotValues; |
---|
2205 | } |
---|
2206 | if (index>0) { |
---|
2207 | series._prevPlotData = this.series[index-1]._plotData; |
---|
2208 | } |
---|
2209 | series._sumy = 0; |
---|
2210 | series._sumx = 0; |
---|
2211 | for (i=series.data.length-1; i>-1; i--) { |
---|
2212 | series._sumy += series.data[i][1]; |
---|
2213 | series._sumx += series.data[i][0]; |
---|
2214 | } |
---|
2215 | }; |
---|
2216 | |
---|
2217 | // this.setData = function(seriesIndex, newdata) { |
---|
2218 | // // if newdata is null, assume all data is passed in as first argument |
---|
2219 | // if (newdata == null) { |
---|
2220 | |
---|
2221 | // } |
---|
2222 | // }; |
---|
2223 | |
---|
2224 | // function to safely return colors from the color array and wrap around at the end. |
---|
2225 | this.getNextSeriesColor = (function(t) { |
---|
2226 | var idx = 0; |
---|
2227 | var sc = t.seriesColors; |
---|
2228 | |
---|
2229 | return function () { |
---|
2230 | if (idx < sc.length) { |
---|
2231 | return sc[idx++]; |
---|
2232 | } |
---|
2233 | else { |
---|
2234 | idx = 0; |
---|
2235 | return sc[idx++]; |
---|
2236 | } |
---|
2237 | }; |
---|
2238 | })(this); |
---|
2239 | |
---|
2240 | this.parseOptions = function(options){ |
---|
2241 | for (var i=0; i<this.preParseOptionsHooks.hooks.length; i++) { |
---|
2242 | this.preParseOptionsHooks.hooks[i].call(this, options); |
---|
2243 | } |
---|
2244 | for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) { |
---|
2245 | $.jqplot.preParseOptionsHooks[i].call(this, options); |
---|
2246 | } |
---|
2247 | this.options = $.extend(true, {}, this.defaults, options); |
---|
2248 | this.stackSeries = this.options.stackSeries; |
---|
2249 | if (this.options.seriesColors) { |
---|
2250 | this.seriesColors = this.options.seriesColors; |
---|
2251 | } |
---|
2252 | if (this.options.negativeSeriesColors) { |
---|
2253 | this.negativeSeriesColors = this.options.negativeSeriesColors; |
---|
2254 | } |
---|
2255 | if (this.options.captureRightClick) { |
---|
2256 | this.captureRightClick = this.options.captureRightClick; |
---|
2257 | } |
---|
2258 | this.defaultAxisStart = (options && options.defaultAxisStart != null) ? options.defaultAxisStart : this.defaultAxisStart; |
---|
2259 | var cg = new this.colorGenerator(this.seriesColors); |
---|
2260 | // this._gridPadding = this.options.gridPadding; |
---|
2261 | $.extend(true, this._gridPadding, this.options.gridPadding); |
---|
2262 | this.sortData = (this.options.sortData != null) ? this.options.sortData : this.sortData; |
---|
2263 | for (var n in this.axes) { |
---|
2264 | var axis = this.axes[n]; |
---|
2265 | axis._options = $.extend(true, {}, this.options.axesDefaults, this.options.axes[n]); |
---|
2266 | $.extend(true, axis, this.options.axesDefaults, this.options.axes[n]); |
---|
2267 | axis._plotWidth = this._width; |
---|
2268 | axis._plotHeight = this._height; |
---|
2269 | } |
---|
2270 | // if (this.data.length == 0) { |
---|
2271 | // this.data = []; |
---|
2272 | // for (var i=0; i<this.options.series.length; i++) { |
---|
2273 | // this.data.push(this.options.series.data); |
---|
2274 | // } |
---|
2275 | // } |
---|
2276 | |
---|
2277 | var normalizeData = function(data, dir, start) { |
---|
2278 | // return data as an array of point arrays, |
---|
2279 | // in form [[x1,y1...], [x2,y2...], ...] |
---|
2280 | var temp = []; |
---|
2281 | var i; |
---|
2282 | dir = dir || 'vertical'; |
---|
2283 | if (!jQuery.isArray(data[0])) { |
---|
2284 | // we have a series of scalars. One line with just y values. |
---|
2285 | // turn the scalar list of data into a data array of form: |
---|
2286 | // [[1, data[0]], [2, data[1]], ...] |
---|
2287 | for (i=0; i<data.length; i++) { |
---|
2288 | if (dir == 'vertical') { |
---|
2289 | temp.push([start + i, data[i]]); |
---|
2290 | } |
---|
2291 | else { |
---|
2292 | temp.push([data[i], start+i]); |
---|
2293 | } |
---|
2294 | } |
---|
2295 | } |
---|
2296 | else { |
---|
2297 | // we have a properly formatted data series, copy it. |
---|
2298 | $.extend(true, temp, data); |
---|
2299 | } |
---|
2300 | return temp; |
---|
2301 | }; |
---|
2302 | |
---|
2303 | for (var i=0; i<this.data.length; i++) { |
---|
2304 | var temp = new Series(); |
---|
2305 | for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) { |
---|
2306 | $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]); |
---|
2307 | } |
---|
2308 | for (var j=0; j<this.preParseSeriesOptionsHooks.hooks.length; j++) { |
---|
2309 | this.preParseSeriesOptionsHooks.hooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]); |
---|
2310 | } |
---|
2311 | $.extend(true, temp, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i]); |
---|
2312 | var dir = 'vertical'; |
---|
2313 | if (temp.renderer === $.jqplot.BarRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') { |
---|
2314 | dir = 'horizontal'; |
---|
2315 | } |
---|
2316 | temp.data = normalizeData(this.data[i], dir, this.defaultAxisStart); |
---|
2317 | switch (temp.xaxis) { |
---|
2318 | case 'xaxis': |
---|
2319 | temp._xaxis = this.axes.xaxis; |
---|
2320 | break; |
---|
2321 | case 'x2axis': |
---|
2322 | temp._xaxis = this.axes.x2axis; |
---|
2323 | break; |
---|
2324 | default: |
---|
2325 | break; |
---|
2326 | } |
---|
2327 | temp._yaxis = this.axes[temp.yaxis]; |
---|
2328 | temp._xaxis._series.push(temp); |
---|
2329 | temp._yaxis._series.push(temp); |
---|
2330 | if (temp.show) { |
---|
2331 | temp._xaxis.show = true; |
---|
2332 | temp._yaxis.show = true; |
---|
2333 | } |
---|
2334 | |
---|
2335 | // parse the renderer options and apply default colors if not provided |
---|
2336 | if (!temp.color && temp.show != false) { |
---|
2337 | temp.color = cg.next(); |
---|
2338 | } |
---|
2339 | if (!temp.label) { |
---|
2340 | temp.label = 'Series '+ (i+1).toString(); |
---|
2341 | } |
---|
2342 | // temp.rendererOptions.show = temp.show; |
---|
2343 | // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions); |
---|
2344 | this.series.push(temp); |
---|
2345 | for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) { |
---|
2346 | $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]); |
---|
2347 | } |
---|
2348 | for (var j=0; j<this.postParseSeriesOptionsHooks.hooks.length; j++) { |
---|
2349 | this.postParseSeriesOptionsHooks.hooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]); |
---|
2350 | } |
---|
2351 | } |
---|
2352 | |
---|
2353 | // copy the grid and title options into this object. |
---|
2354 | $.extend(true, this.grid, this.options.grid); |
---|
2355 | // if axis border properties aren't set, set default. |
---|
2356 | for (var n in this.axes) { |
---|
2357 | var axis = this.axes[n]; |
---|
2358 | if (axis.borderWidth == null) { |
---|
2359 | axis.borderWidth =this.grid.borderWidth; |
---|
2360 | } |
---|
2361 | if (axis.borderColor == null) { |
---|
2362 | if (n != 'xaxis' && n != 'x2axis' && axis.useSeriesColor === true && axis.show) { |
---|
2363 | axis.borderColor = axis._series[0].color; |
---|
2364 | } |
---|
2365 | else { |
---|
2366 | axis.borderColor = this.grid.borderColor; |
---|
2367 | } |
---|
2368 | } |
---|
2369 | } |
---|
2370 | |
---|
2371 | if (typeof this.options.title == 'string') { |
---|
2372 | this.title.text = this.options.title; |
---|
2373 | } |
---|
2374 | else if (typeof this.options.title == 'object') { |
---|
2375 | $.extend(true, this.title, this.options.title); |
---|
2376 | } |
---|
2377 | this.title._plotWidth = this._width; |
---|
2378 | this.legend.setOptions(this.options.legend); |
---|
2379 | |
---|
2380 | for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) { |
---|
2381 | $.jqplot.postParseOptionsHooks[i].call(this, options); |
---|
2382 | } |
---|
2383 | for (var i=0; i<this.postParseOptionsHooks.hooks.length; i++) { |
---|
2384 | this.postParseOptionsHooks.hooks[i].call(this, options); |
---|
2385 | } |
---|
2386 | }; |
---|
2387 | |
---|
2388 | // method: destroy |
---|
2389 | // Releases all resources occupied by the plot |
---|
2390 | this.destroy = function() { |
---|
2391 | this.canvasManager.freeAllCanvases(); |
---|
2392 | this.target[0].innerHTML = ''; |
---|
2393 | }; |
---|
2394 | |
---|
2395 | // method: replot |
---|
2396 | // Does a reinitialization of the plot followed by |
---|
2397 | // a redraw. Method could be used to interactively |
---|
2398 | // change plot characteristics and then replot. |
---|
2399 | // |
---|
2400 | // Parameters: |
---|
2401 | // options - Options used for replotting. |
---|
2402 | // |
---|
2403 | // Properties: |
---|
2404 | // clear - false to not clear (empty) the plot container before replotting (default: true). |
---|
2405 | // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves. |
---|
2406 | // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false). |
---|
2407 | this.replot = function(options) { |
---|
2408 | var opts = options || {}; |
---|
2409 | var clear = opts.clear || true; |
---|
2410 | var resetAxes = opts.resetAxes || false; |
---|
2411 | this.target.trigger('jqplotPreReplot'); |
---|
2412 | |
---|
2413 | if (clear) { |
---|
2414 | this.canvasManager.freeAllCanvases(); |
---|
2415 | // Memory Leaks patch |
---|
2416 | // this.target.find("table.jqplot-table-legend,table.jqplot-legend").each( function() { |
---|
2417 | // $(this).unbind(); |
---|
2418 | |
---|
2419 | // $(this).find(".jqplot-seriesToggle").each( function() { |
---|
2420 | // $(this).unbind(); |
---|
2421 | // }); |
---|
2422 | // $.gcCollect(this); |
---|
2423 | // }); |
---|
2424 | |
---|
2425 | // this.target.find(".jqplot-title").each( function() { |
---|
2426 | // $(this).unbind(); |
---|
2427 | // $.gcCollect(this); |
---|
2428 | // }); |
---|
2429 | |
---|
2430 | // $.gcClear(); |
---|
2431 | |
---|
2432 | if (this._eventCanvas) { |
---|
2433 | this.eventCanvas._elem.unbind(); |
---|
2434 | } |
---|
2435 | this.target.unbind(); |
---|
2436 | |
---|
2437 | // Couple of posts on Stack Overflow indicate that empty() doesn't |
---|
2438 | // always cear up the dom and release memory. Sometimes setting |
---|
2439 | // innerHTML property to null is needed. Particularly on IE, may |
---|
2440 | // have to directly set it to null, bypassing jQuery. |
---|
2441 | this.target.empty(); |
---|
2442 | } |
---|
2443 | this.reInitialize(); |
---|
2444 | if (resetAxes) { |
---|
2445 | this.resetAxesScale(resetAxes, opts.axes); |
---|
2446 | } |
---|
2447 | this.draw(); |
---|
2448 | this.target.trigger('jqplotPostReplot'); |
---|
2449 | }; |
---|
2450 | |
---|
2451 | // method: redraw |
---|
2452 | // Empties the plot target div and redraws the plot. |
---|
2453 | // This enables plot data and properties to be changed |
---|
2454 | // and then to comletely clear the plot and redraw. |
---|
2455 | // redraw *will not* reinitialize any plot elements. |
---|
2456 | // That is, axes will not be autoscaled and defaults |
---|
2457 | // will not be reapplied to any plot elements. redraw |
---|
2458 | // is used primarily with zooming. |
---|
2459 | // |
---|
2460 | // Parameters: |
---|
2461 | // clear - false to not clear (empty) the plot container before redrawing (default: true). |
---|
2462 | this.redraw = function(clear) { |
---|
2463 | clear = (clear != null) ? clear : true; |
---|
2464 | this.target.trigger('jqplotPreRedraw'); |
---|
2465 | if (clear) { |
---|
2466 | this.canvasManager.freeAllCanvases(); |
---|
2467 | this.eventCanvas._elem.unbind(); |
---|
2468 | this.target.unbind(); |
---|
2469 | this.target.empty(); |
---|
2470 | } |
---|
2471 | for (var ax in this.axes) { |
---|
2472 | this.axes[ax]._ticks = []; |
---|
2473 | } |
---|
2474 | for (var i=0; i<this.series.length; i++) { |
---|
2475 | this.populatePlotData(this.series[i], i); |
---|
2476 | } |
---|
2477 | this._sumy = 0; |
---|
2478 | this._sumx = 0; |
---|
2479 | for (i=0; i<this.series.length; i++) { |
---|
2480 | this._sumy += this.series[i]._sumy; |
---|
2481 | this._sumx += this.series[i]._sumx; |
---|
2482 | } |
---|
2483 | this.draw(); |
---|
2484 | this.target.trigger('jqplotPostRedraw'); |
---|
2485 | }; |
---|
2486 | |
---|
2487 | // method: draw |
---|
2488 | // Draws all elements of the plot into the container. |
---|
2489 | // Does not clear the container before drawing. |
---|
2490 | this.draw = function(){ |
---|
2491 | if (this.drawIfHidden || this.target.is(':visible')) { |
---|
2492 | this.target.trigger('jqplotPreDraw'); |
---|
2493 | var i, j; |
---|
2494 | for (i=0; i<$.jqplot.preDrawHooks.length; i++) { |
---|
2495 | $.jqplot.preDrawHooks[i].call(this); |
---|
2496 | } |
---|
2497 | for (i=0; i<this.preDrawHooks.hooks.length; i++) { |
---|
2498 | this.preDrawHooks.hooks[i].call(this); |
---|
2499 | } |
---|
2500 | // create an underlying canvas to be used for special features. |
---|
2501 | this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas', null, this)); |
---|
2502 | this.baseCanvas.setContext(); |
---|
2503 | this.target.append(this.title.draw()); |
---|
2504 | this.title.pack({top:0, left:0}); |
---|
2505 | |
---|
2506 | // make room for the legend between the grid and the edge. |
---|
2507 | var legendElem = this.legend.draw(); |
---|
2508 | |
---|
2509 | var gridPadding = {top:0, left:0, bottom:0, right:0}; |
---|
2510 | |
---|
2511 | if (this.legend.placement == "outsideGrid") { |
---|
2512 | // temporarily append the legend to get dimensions |
---|
2513 | this.target.append(legendElem); |
---|
2514 | switch (this.legend.location) { |
---|
2515 | case 'n': |
---|
2516 | gridPadding.top += this.legend.getHeight(); |
---|
2517 | break; |
---|
2518 | case 's': |
---|
2519 | gridPadding.bottom += this.legend.getHeight(); |
---|
2520 | break; |
---|
2521 | case 'ne': |
---|
2522 | case 'e': |
---|
2523 | case 'se': |
---|
2524 | gridPadding.right += this.legend.getWidth(); |
---|
2525 | break; |
---|
2526 | case 'nw': |
---|
2527 | case 'w': |
---|
2528 | case 'sw': |
---|
2529 | gridPadding.left += this.legend.getWidth(); |
---|
2530 | break; |
---|
2531 | default: // same as 'ne' |
---|
2532 | gridPadding.right += this.legend.getWidth(); |
---|
2533 | break; |
---|
2534 | } |
---|
2535 | legendElem = legendElem.detach(); |
---|
2536 | } |
---|
2537 | |
---|
2538 | var ax = this.axes; |
---|
2539 | for (var name in ax) { |
---|
2540 | this.target.append(ax[name].draw(this.baseCanvas._ctx, this)); |
---|
2541 | ax[name].set(); |
---|
2542 | } |
---|
2543 | if (ax.yaxis.show) { |
---|
2544 | gridPadding.left += ax.yaxis.getWidth(); |
---|
2545 | } |
---|
2546 | var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; |
---|
2547 | var rapad = [0, 0, 0, 0, 0, 0, 0, 0]; |
---|
2548 | var gpr = 0; |
---|
2549 | var n; |
---|
2550 | for (n=0; n<8; n++) { |
---|
2551 | if (ax[ra[n]].show) { |
---|
2552 | gpr += ax[ra[n]].getWidth(); |
---|
2553 | rapad[n] = gpr; |
---|
2554 | } |
---|
2555 | } |
---|
2556 | gridPadding.right += gpr; |
---|
2557 | if (ax.x2axis.show) { |
---|
2558 | gridPadding.top += ax.x2axis.getHeight(); |
---|
2559 | } |
---|
2560 | if (this.title.show) { |
---|
2561 | gridPadding.top += this.title.getHeight(); |
---|
2562 | } |
---|
2563 | if (ax.xaxis.show) { |
---|
2564 | gridPadding.bottom += ax.xaxis.getHeight(); |
---|
2565 | } |
---|
2566 | |
---|
2567 | // end of gridPadding adjustments. |
---|
2568 | var arr = ['top', 'bottom', 'left', 'right']; |
---|
2569 | for (var n in arr) { |
---|
2570 | if (this._gridPadding[arr[n]] == null && gridPadding[arr[n]] > 0) { |
---|
2571 | this._gridPadding[arr[n]] = gridPadding[arr[n]]; |
---|
2572 | } |
---|
2573 | else if (this._gridPadding[arr[n]] == null) { |
---|
2574 | this._gridPadding[arr[n]] = this._defaultGridPadding[arr[n]]; |
---|
2575 | } |
---|
2576 | } |
---|
2577 | |
---|
2578 | var legendPadding = (this.legend.placement == 'outsideGrid') ? {top:this.title.getHeight(), left: 0, right: 0, bottom: 0} : this._gridPadding; |
---|
2579 | |
---|
2580 | ax.xaxis.pack({position:'absolute', bottom:this._gridPadding.bottom - ax.xaxis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); |
---|
2581 | ax.yaxis.pack({position:'absolute', top:0, left:this._gridPadding.left - ax.yaxis.getWidth(), height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); |
---|
2582 | ax.x2axis.pack({position:'absolute', top:this._gridPadding.top - ax.x2axis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); |
---|
2583 | for (i=8; i>0; i--) { |
---|
2584 | ax[ra[i-1]].pack({position:'absolute', top:0, right:this._gridPadding.right - rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); |
---|
2585 | } |
---|
2586 | // ax.y2axis.pack({position:'absolute', top:0, right:0}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); |
---|
2587 | |
---|
2588 | this.target.append(this.grid.createElement(this._gridPadding, this)); |
---|
2589 | this.grid.draw(); |
---|
2590 | |
---|
2591 | // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars. |
---|
2592 | for (i=0; i<this.series.length; i++) { |
---|
2593 | // draw series in order of stacking. This affects only |
---|
2594 | // order in which canvases are added to dom. |
---|
2595 | j = this.seriesStack[i]; |
---|
2596 | this.target.append(this.series[j].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-shadowCanvas', null, this)); |
---|
2597 | this.series[j].shadowCanvas.setContext(); |
---|
2598 | this.series[j].shadowCanvas._elem.data('seriesIndex', j); |
---|
2599 | } |
---|
2600 | |
---|
2601 | for (i=0; i<this.series.length; i++) { |
---|
2602 | // draw series in order of stacking. This affects only |
---|
2603 | // order in which canvases are added to dom. |
---|
2604 | j = this.seriesStack[i]; |
---|
2605 | this.target.append(this.series[j].canvas.createElement(this._gridPadding, 'jqplot-series-canvas', null, this)); |
---|
2606 | this.series[j].canvas.setContext(); |
---|
2607 | this.series[j].canvas._elem.data('seriesIndex', j); |
---|
2608 | } |
---|
2609 | // Need to use filled canvas to capture events in IE. |
---|
2610 | // Also, canvas seems to block selection of other elements in document on FF. |
---|
2611 | this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas', null, this)); |
---|
2612 | this.eventCanvas.setContext(); |
---|
2613 | this.eventCanvas._ctx.fillStyle = 'rgba(0,0,0,0)'; |
---|
2614 | this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width, this.eventCanvas._ctx.canvas.height); |
---|
2615 | |
---|
2616 | // bind custom event handlers to regular events. |
---|
2617 | this.bindCustomEvents(); |
---|
2618 | |
---|
2619 | // draw legend before series if the series needs to know the legend dimensions. |
---|
2620 | if (this.legend.preDraw) { |
---|
2621 | this.eventCanvas._elem.before(legendElem); |
---|
2622 | this.legend.pack(legendPadding); |
---|
2623 | if (this.legend._elem) { |
---|
2624 | this.drawSeries({legendInfo:{location:this.legend.location, placement:this.legend.placement, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}}); |
---|
2625 | } |
---|
2626 | else { |
---|
2627 | this.drawSeries(); |
---|
2628 | } |
---|
2629 | } |
---|
2630 | else { // draw series before legend |
---|
2631 | this.drawSeries(); |
---|
2632 | if (this.series.length) { |
---|
2633 | $(this.series[this.series.length-1].canvas._elem).after(legendElem); |
---|
2634 | } |
---|
2635 | this.legend.pack(legendPadding); |
---|
2636 | } |
---|
2637 | |
---|
2638 | // register event listeners on the overlay canvas |
---|
2639 | for (var i=0; i<$.jqplot.eventListenerHooks.length; i++) { |
---|
2640 | // in the handler, this will refer to the eventCanvas dom element. |
---|
2641 | // make sure there are references back into plot objects. |
---|
2642 | this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); |
---|
2643 | } |
---|
2644 | |
---|
2645 | // register event listeners on the overlay canvas |
---|
2646 | for (var i=0; i<this.eventListenerHooks.hooks.length; i++) { |
---|
2647 | // in the handler, this will refer to the eventCanvas dom element. |
---|
2648 | // make sure there are references back into plot objects. |
---|
2649 | this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[i][0], {plot:this}, this.eventListenerHooks.hooks[i][1]); |
---|
2650 | } |
---|
2651 | |
---|
2652 | for (var i=0; i<$.jqplot.postDrawHooks.length; i++) { |
---|
2653 | $.jqplot.postDrawHooks[i].call(this); |
---|
2654 | } |
---|
2655 | |
---|
2656 | for (var i=0; i<this.postDrawHooks.hooks.length; i++) { |
---|
2657 | this.postDrawHooks.hooks[i].call(this); |
---|
2658 | } |
---|
2659 | |
---|
2660 | if (this.target.is(':visible')) { |
---|
2661 | this._drawCount += 1; |
---|
2662 | } |
---|
2663 | |
---|
2664 | this.target.trigger('jqplotPostDraw', [this]); |
---|
2665 | } |
---|
2666 | }; |
---|
2667 | |
---|
2668 | this.bindCustomEvents = function() { |
---|
2669 | this.eventCanvas._elem.bind('click', {plot:this}, this.onClick); |
---|
2670 | this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick); |
---|
2671 | this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown); |
---|
2672 | this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove); |
---|
2673 | this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter); |
---|
2674 | this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave); |
---|
2675 | if (this.captureRightClick) { |
---|
2676 | this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onRightClick); |
---|
2677 | this.eventCanvas._elem.get(0).oncontextmenu = function() { |
---|
2678 | return false; |
---|
2679 | }; |
---|
2680 | } |
---|
2681 | else { |
---|
2682 | this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp); |
---|
2683 | } |
---|
2684 | }; |
---|
2685 | |
---|
2686 | function getEventPosition(ev) { |
---|
2687 | var plot = ev.data.plot; |
---|
2688 | var go = plot.eventCanvas._elem.offset(); |
---|
2689 | var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; |
---|
2690 | var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null}; |
---|
2691 | var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; |
---|
2692 | var ax = plot.axes; |
---|
2693 | var n, axis; |
---|
2694 | for (n=11; n>0; n--) { |
---|
2695 | axis = an[n-1]; |
---|
2696 | if (ax[axis].show) { |
---|
2697 | dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); |
---|
2698 | } |
---|
2699 | } |
---|
2700 | |
---|
2701 | return {offsets:go, gridPos:gridPos, dataPos:dataPos}; |
---|
2702 | } |
---|
2703 | |
---|
2704 | |
---|
2705 | // function to check if event location is over a area area |
---|
2706 | function checkIntersection(gridpos, plot) { |
---|
2707 | var series = plot.series; |
---|
2708 | var i, j, k, s, r, x, y, theta, sm, sa, minang, maxang; |
---|
2709 | var d0, d, p, pp, points, bw; |
---|
2710 | var threshold, t; |
---|
2711 | for (k=plot.seriesStack.length-1; k>=0; k--) { |
---|
2712 | i = plot.seriesStack[k]; |
---|
2713 | s = series[i]; |
---|
2714 | switch (s.renderer.constructor) { |
---|
2715 | case $.jqplot.BarRenderer: |
---|
2716 | x = gridpos.x; |
---|
2717 | y = gridpos.y; |
---|
2718 | for (j=0; j<s._barPoints.length; j++) { |
---|
2719 | points = s._barPoints[j]; |
---|
2720 | p = s.gridData[j]; |
---|
2721 | if (x>points[0][0] && x<points[2][0] && y>points[2][1] && y<points[0][1]) { |
---|
2722 | return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]}; |
---|
2723 | } |
---|
2724 | } |
---|
2725 | break; |
---|
2726 | |
---|
2727 | case $.jqplot.DonutRenderer: |
---|
2728 | sa = s.startAngle/180*Math.PI; |
---|
2729 | x = gridpos.x - s._center[0]; |
---|
2730 | y = gridpos.y - s._center[1]; |
---|
2731 | r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); |
---|
2732 | if (x > 0 && -y >= 0) { |
---|
2733 | theta = 2*Math.PI - Math.atan(-y/x); |
---|
2734 | } |
---|
2735 | else if (x > 0 && -y < 0) { |
---|
2736 | theta = -Math.atan(-y/x); |
---|
2737 | } |
---|
2738 | else if (x < 0) { |
---|
2739 | theta = Math.PI - Math.atan(-y/x); |
---|
2740 | } |
---|
2741 | else if (x == 0 && -y > 0) { |
---|
2742 | theta = 3*Math.PI/2; |
---|
2743 | } |
---|
2744 | else if (x == 0 && -y < 0) { |
---|
2745 | theta = Math.PI/2; |
---|
2746 | } |
---|
2747 | else if (x == 0 && y == 0) { |
---|
2748 | theta = 0; |
---|
2749 | } |
---|
2750 | if (sa) { |
---|
2751 | theta -= sa; |
---|
2752 | if (theta < 0) { |
---|
2753 | theta += 2*Math.PI; |
---|
2754 | } |
---|
2755 | else if (theta > 2*Math.PI) { |
---|
2756 | theta -= 2*Math.PI; |
---|
2757 | } |
---|
2758 | } |
---|
2759 | |
---|
2760 | sm = s.sliceMargin/180*Math.PI; |
---|
2761 | if (r < s._radius && r > s._innerRadius) { |
---|
2762 | for (j=0; j<s.gridData.length; j++) { |
---|
2763 | minang = (j>0) ? s.gridData[j-1][1]+sm : sm; |
---|
2764 | maxang = s.gridData[j][1]; |
---|
2765 | if (theta > minang && theta < maxang) { |
---|
2766 | return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]}; |
---|
2767 | } |
---|
2768 | } |
---|
2769 | } |
---|
2770 | break; |
---|
2771 | |
---|
2772 | case $.jqplot.PieRenderer: |
---|
2773 | sa = s.startAngle/180*Math.PI; |
---|
2774 | x = gridpos.x - s._center[0]; |
---|
2775 | y = gridpos.y - s._center[1]; |
---|
2776 | r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); |
---|
2777 | if (x > 0 && -y >= 0) { |
---|
2778 | theta = 2*Math.PI - Math.atan(-y/x); |
---|
2779 | } |
---|
2780 | else if (x > 0 && -y < 0) { |
---|
2781 | theta = -Math.atan(-y/x); |
---|
2782 | } |
---|
2783 | else if (x < 0) { |
---|
2784 | theta = Math.PI - Math.atan(-y/x); |
---|
2785 | } |
---|
2786 | else if (x == 0 && -y > 0) { |
---|
2787 | theta = 3*Math.PI/2; |
---|
2788 | } |
---|
2789 | else if (x == 0 && -y < 0) { |
---|
2790 | theta = Math.PI/2; |
---|
2791 | } |
---|
2792 | else if (x == 0 && y == 0) { |
---|
2793 | theta = 0; |
---|
2794 | } |
---|
2795 | if (sa) { |
---|
2796 | theta -= sa; |
---|
2797 | if (theta < 0) { |
---|
2798 | theta += 2*Math.PI; |
---|
2799 | } |
---|
2800 | else if (theta > 2*Math.PI) { |
---|
2801 | theta -= 2*Math.PI; |
---|
2802 | } |
---|
2803 | } |
---|
2804 | |
---|
2805 | sm = s.sliceMargin/180*Math.PI; |
---|
2806 | if (r < s._radius) { |
---|
2807 | for (j=0; j<s.gridData.length; j++) { |
---|
2808 | minang = (j>0) ? s.gridData[j-1][1]+sm : sm; |
---|
2809 | maxang = s.gridData[j][1]; |
---|
2810 | if (theta > minang && theta < maxang) { |
---|
2811 | return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]}; |
---|
2812 | } |
---|
2813 | } |
---|
2814 | } |
---|
2815 | break; |
---|
2816 | |
---|
2817 | case $.jqplot.BubbleRenderer: |
---|
2818 | x = gridpos.x; |
---|
2819 | y = gridpos.y; |
---|
2820 | var ret = null; |
---|
2821 | |
---|
2822 | if (s.show) { |
---|
2823 | for (var j=0; j<s.gridData.length; j++) { |
---|
2824 | p = s.gridData[j]; |
---|
2825 | d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); |
---|
2826 | if (d <= p[2] && (d <= d0 || d0 == null)) { |
---|
2827 | d0 = d; |
---|
2828 | ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2829 | } |
---|
2830 | } |
---|
2831 | if (ret != null) { |
---|
2832 | return ret; |
---|
2833 | } |
---|
2834 | } |
---|
2835 | break; |
---|
2836 | |
---|
2837 | case $.jqplot.FunnelRenderer: |
---|
2838 | x = gridpos.x; |
---|
2839 | y = gridpos.y; |
---|
2840 | var v = s._vertices, |
---|
2841 | vfirst = v[0], |
---|
2842 | vlast = v[v.length-1], |
---|
2843 | lex, |
---|
2844 | rex, |
---|
2845 | cv; |
---|
2846 | |
---|
2847 | // equations of right and left sides, returns x, y values given height of section (y value and 2 points) |
---|
2848 | |
---|
2849 | function findedge (l, p1 , p2) { |
---|
2850 | var m = (p1[1] - p2[1])/(p1[0] - p2[0]); |
---|
2851 | var b = p1[1] - m*p1[0]; |
---|
2852 | var y = l + p1[1]; |
---|
2853 | |
---|
2854 | return [(y - b)/m, y]; |
---|
2855 | } |
---|
2856 | |
---|
2857 | // check each section |
---|
2858 | lex = findedge(y, vfirst[0], vlast[3]); |
---|
2859 | rex = findedge(y, vfirst[1], vlast[2]); |
---|
2860 | for (j=0; j<v.length; j++) { |
---|
2861 | cv = v[j]; |
---|
2862 | if (y >= cv[0][1] && y <= cv[3][1] && x >= lex[0] && x <= rex[0]) { |
---|
2863 | return {seriesIndex:s.index, pointIndex:j, gridData:null, data:s.data[j]}; |
---|
2864 | } |
---|
2865 | } |
---|
2866 | break; |
---|
2867 | |
---|
2868 | case $.jqplot.LineRenderer: |
---|
2869 | x = gridpos.x; |
---|
2870 | y = gridpos.y; |
---|
2871 | r = s.renderer; |
---|
2872 | if (s.show) { |
---|
2873 | if (s.fill) { |
---|
2874 | // first check if it is in bounding box |
---|
2875 | var inside = false; |
---|
2876 | if (x>s._boundingBox[0][0] && x<s._boundingBox[1][0] && y>s._boundingBox[1][1] && y<s._boundingBox[0][1]) { |
---|
2877 | // now check the crossing number |
---|
2878 | |
---|
2879 | var numPoints = s._areaPoints.length; |
---|
2880 | var ii; |
---|
2881 | var j = numPoints-1; |
---|
2882 | |
---|
2883 | for(var ii=0; ii < numPoints; ii++) { |
---|
2884 | var vertex1 = [s._areaPoints[ii][0], s._areaPoints[ii][1]]; |
---|
2885 | var vertex2 = [s._areaPoints[j][0], s._areaPoints[j][1]]; |
---|
2886 | |
---|
2887 | if (vertex1[1] < y && vertex2[1] >= y || vertex2[1] < y && vertex1[1] >= y) { |
---|
2888 | if (vertex1[0] + (y - vertex1[1]) / (vertex2[1] - vertex1[1]) * (vertex2[0] - vertex1[0]) < x) { |
---|
2889 | inside = !inside; |
---|
2890 | } |
---|
2891 | } |
---|
2892 | |
---|
2893 | j = ii; |
---|
2894 | } |
---|
2895 | } |
---|
2896 | if (inside) { |
---|
2897 | return {seriesIndex:i, pointIndex:null, gridData:s.gridData, data:s.data, points:s._areaPoints}; |
---|
2898 | } |
---|
2899 | break; |
---|
2900 | |
---|
2901 | } |
---|
2902 | else { |
---|
2903 | t = s.markerRenderer.size/2+s.neighborThreshold; |
---|
2904 | threshold = (t > 0) ? t : 0; |
---|
2905 | for (var j=0; j<s.gridData.length; j++) { |
---|
2906 | p = s.gridData[j]; |
---|
2907 | // neighbor looks different to OHLC chart. |
---|
2908 | if (r.constructor == $.jqplot.OHLCRenderer) { |
---|
2909 | if (r.candleStick) { |
---|
2910 | var yp = s._yaxis.series_u2p; |
---|
2911 | if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { |
---|
2912 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2913 | } |
---|
2914 | } |
---|
2915 | // if an open hi low close chart |
---|
2916 | else if (!r.hlc){ |
---|
2917 | var yp = s._yaxis.series_u2p; |
---|
2918 | if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { |
---|
2919 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2920 | } |
---|
2921 | } |
---|
2922 | // a hi low close chart |
---|
2923 | else { |
---|
2924 | var yp = s._yaxis.series_u2p; |
---|
2925 | if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) { |
---|
2926 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2927 | } |
---|
2928 | } |
---|
2929 | |
---|
2930 | } |
---|
2931 | else if (p[0] != null && p[1] != null){ |
---|
2932 | d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); |
---|
2933 | if (d <= threshold && (d <= d0 || d0 == null)) { |
---|
2934 | d0 = d; |
---|
2935 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2936 | } |
---|
2937 | } |
---|
2938 | } |
---|
2939 | } |
---|
2940 | } |
---|
2941 | break; |
---|
2942 | |
---|
2943 | default: |
---|
2944 | x = gridpos.x; |
---|
2945 | y = gridpos.y; |
---|
2946 | r = s.renderer; |
---|
2947 | if (s.show) { |
---|
2948 | t = s.markerRenderer.size/2+s.neighborThreshold; |
---|
2949 | threshold = (t > 0) ? t : 0; |
---|
2950 | for (var j=0; j<s.gridData.length; j++) { |
---|
2951 | p = s.gridData[j]; |
---|
2952 | // neighbor looks different to OHLC chart. |
---|
2953 | if (r.constructor == $.jqplot.OHLCRenderer) { |
---|
2954 | if (r.candleStick) { |
---|
2955 | var yp = s._yaxis.series_u2p; |
---|
2956 | if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { |
---|
2957 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2958 | } |
---|
2959 | } |
---|
2960 | // if an open hi low close chart |
---|
2961 | else if (!r.hlc){ |
---|
2962 | var yp = s._yaxis.series_u2p; |
---|
2963 | if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { |
---|
2964 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2965 | } |
---|
2966 | } |
---|
2967 | // a hi low close chart |
---|
2968 | else { |
---|
2969 | var yp = s._yaxis.series_u2p; |
---|
2970 | if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) { |
---|
2971 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2972 | } |
---|
2973 | } |
---|
2974 | |
---|
2975 | } |
---|
2976 | else { |
---|
2977 | d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); |
---|
2978 | if (d <= threshold && (d <= d0 || d0 == null)) { |
---|
2979 | d0 = d; |
---|
2980 | return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; |
---|
2981 | } |
---|
2982 | } |
---|
2983 | } |
---|
2984 | } |
---|
2985 | break; |
---|
2986 | } |
---|
2987 | } |
---|
2988 | |
---|
2989 | return null; |
---|
2990 | } |
---|
2991 | |
---|
2992 | |
---|
2993 | |
---|
2994 | this.onClick = function(ev) { |
---|
2995 | // Event passed in is normalized and will have data attribute. |
---|
2996 | // Event passed out is unnormalized. |
---|
2997 | var positions = getEventPosition(ev); |
---|
2998 | var p = ev.data.plot; |
---|
2999 | var neighbor = checkIntersection(positions.gridPos, p); |
---|
3000 | var evt = jQuery.Event('jqplotClick'); |
---|
3001 | evt.pageX = ev.pageX; |
---|
3002 | evt.pageY = ev.pageY; |
---|
3003 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3004 | }; |
---|
3005 | |
---|
3006 | this.onDblClick = function(ev) { |
---|
3007 | // Event passed in is normalized and will have data attribute. |
---|
3008 | // Event passed out is unnormalized. |
---|
3009 | var positions = getEventPosition(ev); |
---|
3010 | var p = ev.data.plot; |
---|
3011 | var neighbor = checkIntersection(positions.gridPos, p); |
---|
3012 | var evt = jQuery.Event('jqplotDblClick'); |
---|
3013 | evt.pageX = ev.pageX; |
---|
3014 | evt.pageY = ev.pageY; |
---|
3015 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3016 | }; |
---|
3017 | |
---|
3018 | this.onMouseDown = function(ev) { |
---|
3019 | var positions = getEventPosition(ev); |
---|
3020 | var p = ev.data.plot; |
---|
3021 | var neighbor = checkIntersection(positions.gridPos, p); |
---|
3022 | var evt = jQuery.Event('jqplotMouseDown'); |
---|
3023 | evt.pageX = ev.pageX; |
---|
3024 | evt.pageY = ev.pageY; |
---|
3025 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3026 | }; |
---|
3027 | |
---|
3028 | this.onMouseUp = function(ev) { |
---|
3029 | var positions = getEventPosition(ev); |
---|
3030 | var evt = jQuery.Event('jqplotMouseUp'); |
---|
3031 | evt.pageX = ev.pageX; |
---|
3032 | evt.pageY = ev.pageY; |
---|
3033 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, ev.data.plot]); |
---|
3034 | }; |
---|
3035 | |
---|
3036 | this.onRightClick = function(ev) { |
---|
3037 | var positions = getEventPosition(ev); |
---|
3038 | var p = ev.data.plot; |
---|
3039 | var neighbor = checkIntersection(positions.gridPos, p); |
---|
3040 | if (p.captureRightClick) { |
---|
3041 | if (ev.which == 3) { |
---|
3042 | var evt = jQuery.Event('jqplotRightClick'); |
---|
3043 | evt.pageX = ev.pageX; |
---|
3044 | evt.pageY = ev.pageY; |
---|
3045 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3046 | } |
---|
3047 | else { |
---|
3048 | var evt = jQuery.Event('jqplotMouseUp'); |
---|
3049 | evt.pageX = ev.pageX; |
---|
3050 | evt.pageY = ev.pageY; |
---|
3051 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3052 | } |
---|
3053 | } |
---|
3054 | }; |
---|
3055 | |
---|
3056 | this.onMouseMove = function(ev) { |
---|
3057 | var positions = getEventPosition(ev); |
---|
3058 | var p = ev.data.plot; |
---|
3059 | var neighbor = checkIntersection(positions.gridPos, p); |
---|
3060 | var evt = jQuery.Event('jqplotMouseMove'); |
---|
3061 | evt.pageX = ev.pageX; |
---|
3062 | evt.pageY = ev.pageY; |
---|
3063 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); |
---|
3064 | }; |
---|
3065 | |
---|
3066 | this.onMouseEnter = function(ev) { |
---|
3067 | var positions = getEventPosition(ev); |
---|
3068 | var p = ev.data.plot; |
---|
3069 | var evt = jQuery.Event('jqplotMouseEnter'); |
---|
3070 | evt.pageX = ev.pageX; |
---|
3071 | evt.pageY = ev.pageY; |
---|
3072 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]); |
---|
3073 | }; |
---|
3074 | |
---|
3075 | this.onMouseLeave = function(ev) { |
---|
3076 | var positions = getEventPosition(ev); |
---|
3077 | var p = ev.data.plot; |
---|
3078 | var evt = jQuery.Event('jqplotMouseLeave'); |
---|
3079 | evt.pageX = ev.pageX; |
---|
3080 | evt.pageY = ev.pageY; |
---|
3081 | $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]); |
---|
3082 | }; |
---|
3083 | |
---|
3084 | // method: drawSeries |
---|
3085 | // Redraws all or just one series on the plot. No axis scaling |
---|
3086 | // is performed and no other elements on the plot are redrawn. |
---|
3087 | // options is an options object to pass on to the series renderers. |
---|
3088 | // It can be an empty object {}. idx is the series index |
---|
3089 | // to redraw if only one series is to be redrawn. |
---|
3090 | this.drawSeries = function(options, idx){ |
---|
3091 | var i, series, ctx; |
---|
3092 | // if only one argument passed in and it is a number, use it ad idx. |
---|
3093 | idx = (typeof(options) === "number" && idx == null) ? options : idx; |
---|
3094 | options = (typeof(options) === "object") ? options : {}; |
---|
3095 | // draw specified series |
---|
3096 | if (idx != undefined) { |
---|
3097 | series = this.series[idx]; |
---|
3098 | ctx = series.shadowCanvas._ctx; |
---|
3099 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
---|
3100 | series.drawShadow(ctx, options, this); |
---|
3101 | ctx = series.canvas._ctx; |
---|
3102 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
---|
3103 | series.draw(ctx, options, this); |
---|
3104 | if (series.renderer.constructor == $.jqplot.BezierCurveRenderer) { |
---|
3105 | if (idx < this.series.length - 1) { |
---|
3106 | this.drawSeries(idx+1); |
---|
3107 | } |
---|
3108 | } |
---|
3109 | } |
---|
3110 | |
---|
3111 | else { |
---|
3112 | // if call series drawShadow method first, in case all series shadows |
---|
3113 | // should be drawn before any series. This will ensure, like for |
---|
3114 | // stacked bar plots, that shadows don't overlap series. |
---|
3115 | for (i=0; i<this.series.length; i++) { |
---|
3116 | // first clear the canvas |
---|
3117 | series = this.series[i]; |
---|
3118 | ctx = series.shadowCanvas._ctx; |
---|
3119 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
---|
3120 | series.drawShadow(ctx, options, this); |
---|
3121 | ctx = series.canvas._ctx; |
---|
3122 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
---|
3123 | series.draw(ctx, options, this); |
---|
3124 | } |
---|
3125 | } |
---|
3126 | options = idx = i = series = ctx = null; |
---|
3127 | }; |
---|
3128 | |
---|
3129 | // method: moveSeriesToFront |
---|
3130 | // This method requires jQuery 1.4+ |
---|
3131 | // Moves the specified series canvas in front of all other series canvases. |
---|
3132 | // This effectively "draws" the specified series on top of all other series, |
---|
3133 | // although it is performed through DOM manipulation, no redrawing is performed. |
---|
3134 | // |
---|
3135 | // Parameters: |
---|
3136 | // idx - 0 based index of the series to move. This will be the index of the series |
---|
3137 | // as it was first passed into the jqplot function. |
---|
3138 | this.moveSeriesToFront = function (idx) { |
---|
3139 | idx = parseInt(idx, 10); |
---|
3140 | var stackIndex = $.inArray(idx, this.seriesStack); |
---|
3141 | // if already in front, return |
---|
3142 | if (stackIndex == -1) { |
---|
3143 | return; |
---|
3144 | } |
---|
3145 | if (stackIndex == this.seriesStack.length -1) { |
---|
3146 | this.previousSeriesStack = this.seriesStack.slice(0); |
---|
3147 | return; |
---|
3148 | } |
---|
3149 | var opidx = this.seriesStack[this.seriesStack.length -1]; |
---|
3150 | var serelem = this.series[idx].canvas._elem.detach(); |
---|
3151 | var shadelem = this.series[idx].shadowCanvas._elem.detach(); |
---|
3152 | this.series[opidx].shadowCanvas._elem.after(shadelem); |
---|
3153 | this.series[opidx].canvas._elem.after(serelem); |
---|
3154 | this.previousSeriesStack = this.seriesStack.slice(0); |
---|
3155 | this.seriesStack.splice(stackIndex, 1); |
---|
3156 | this.seriesStack.push(idx); |
---|
3157 | }; |
---|
3158 | |
---|
3159 | // method: moveSeriesToBack |
---|
3160 | // This method requires jQuery 1.4+ |
---|
3161 | // Moves the specified series canvas behind all other series canvases. |
---|
3162 | // |
---|
3163 | // Parameters: |
---|
3164 | // idx - 0 based index of the series to move. This will be the index of the series |
---|
3165 | // as it was first passed into the jqplot function. |
---|
3166 | this.moveSeriesToBack = function (idx) { |
---|
3167 | idx = parseInt(idx, 10); |
---|
3168 | var stackIndex = $.inArray(idx, this.seriesStack); |
---|
3169 | // if already in back, return |
---|
3170 | if (stackIndex == 0 || stackIndex == -1) { |
---|
3171 | return; |
---|
3172 | } |
---|
3173 | var opidx = this.seriesStack[0]; |
---|
3174 | var serelem = this.series[idx].canvas._elem.detach(); |
---|
3175 | var shadelem = this.series[idx].shadowCanvas._elem.detach(); |
---|
3176 | this.series[opidx].shadowCanvas._elem.before(shadelem); |
---|
3177 | this.series[opidx].canvas._elem.before(serelem); |
---|
3178 | this.previousSeriesStack = this.seriesStack.slice(0); |
---|
3179 | this.seriesStack.splice(stackIndex, 1); |
---|
3180 | this.seriesStack.unshift(idx); |
---|
3181 | }; |
---|
3182 | |
---|
3183 | // method: restorePreviousSeriesOrder |
---|
3184 | // This method requires jQuery 1.4+ |
---|
3185 | // Restore the series canvas order to its previous state. |
---|
3186 | // Useful to put a series back where it belongs after moving |
---|
3187 | // it to the front. |
---|
3188 | this.restorePreviousSeriesOrder = function () { |
---|
3189 | var i, j, serelem, shadelem, temp, move, keep; |
---|
3190 | // if no change, return. |
---|
3191 | if (this.seriesStack == this.previousSeriesStack) { |
---|
3192 | return; |
---|
3193 | } |
---|
3194 | for (i=1; i<this.previousSeriesStack.length; i++) { |
---|
3195 | move = this.previousSeriesStack[i]; |
---|
3196 | keep = this.previousSeriesStack[i-1]; |
---|
3197 | serelem = this.series[move].canvas._elem.detach(); |
---|
3198 | shadelem = this.series[move].shadowCanvas._elem.detach(); |
---|
3199 | this.series[keep].shadowCanvas._elem.after(shadelem); |
---|
3200 | this.series[keep].canvas._elem.after(serelem); |
---|
3201 | } |
---|
3202 | temp = this.seriesStack.slice(0); |
---|
3203 | this.seriesStack = this.previousSeriesStack.slice(0); |
---|
3204 | this.previousSeriesStack = temp; |
---|
3205 | }; |
---|
3206 | |
---|
3207 | // method: restoreOriginalSeriesOrder |
---|
3208 | // This method requires jQuery 1.4+ |
---|
3209 | // Restore the series canvas order to its original order |
---|
3210 | // when the plot was created. |
---|
3211 | this.restoreOriginalSeriesOrder = function () { |
---|
3212 | var i, j, arr=[], serelem, shadelem; |
---|
3213 | for (i=0; i<this.series.length; i++) { |
---|
3214 | arr.push(i); |
---|
3215 | } |
---|
3216 | if (this.seriesStack == arr) { |
---|
3217 | return; |
---|
3218 | } |
---|
3219 | this.previousSeriesStack = this.seriesStack.slice(0); |
---|
3220 | this.seriesStack = arr; |
---|
3221 | for (i=1; i<this.seriesStack.length; i++) { |
---|
3222 | serelem = this.series[i].canvas._elem.detach(); |
---|
3223 | shadelem = this.series[i].shadowCanvas._elem.detach(); |
---|
3224 | this.series[i-1].shadowCanvas._elem.after(shadelem); |
---|
3225 | this.series[i-1].canvas._elem.after(serelem); |
---|
3226 | } |
---|
3227 | }; |
---|
3228 | |
---|
3229 | this.activateTheme = function (name) { |
---|
3230 | this.themeEngine.activate(this, name); |
---|
3231 | }; |
---|
3232 | } |
---|
3233 | |
---|
3234 | |
---|
3235 | // conpute a highlight color or array of highlight colors from given colors. |
---|
3236 | $.jqplot.computeHighlightColors = function(colors) { |
---|
3237 | var ret; |
---|
3238 | if (jQuery.isArray(colors)) { |
---|
3239 | ret = []; |
---|
3240 | for (var i=0; i<colors.length; i++){ |
---|
3241 | var rgba = $.jqplot.getColorComponents(colors[i]); |
---|
3242 | var newrgb = [rgba[0], rgba[1], rgba[2]]; |
---|
3243 | var sum = newrgb[0] + newrgb[1] + newrgb[2]; |
---|
3244 | for (var j=0; j<3; j++) { |
---|
3245 | // when darkening, lowest color component can be is 60. |
---|
3246 | newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); |
---|
3247 | newrgb[j] = parseInt(newrgb[j], 10); |
---|
3248 | } |
---|
3249 | ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); |
---|
3250 | } |
---|
3251 | } |
---|
3252 | else { |
---|
3253 | var rgba = $.jqplot.getColorComponents(colors); |
---|
3254 | var newrgb = [rgba[0], rgba[1], rgba[2]]; |
---|
3255 | var sum = newrgb[0] + newrgb[1] + newrgb[2]; |
---|
3256 | for (var j=0; j<3; j++) { |
---|
3257 | // when darkening, lowest color component can be is 60. |
---|
3258 | newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); |
---|
3259 | newrgb[j] = parseInt(newrgb[j], 10); |
---|
3260 | } |
---|
3261 | ret = 'rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'; |
---|
3262 | } |
---|
3263 | return ret; |
---|
3264 | }; |
---|
3265 | |
---|
3266 | $.jqplot.ColorGenerator = function(colors) { |
---|
3267 | colors = colors || $.jqplot.config.defaultColors; |
---|
3268 | var idx = 0; |
---|
3269 | |
---|
3270 | this.next = function () { |
---|
3271 | if (idx < colors.length) { |
---|
3272 | return colors[idx++]; |
---|
3273 | } |
---|
3274 | else { |
---|
3275 | idx = 0; |
---|
3276 | return colors[idx++]; |
---|
3277 | } |
---|
3278 | }; |
---|
3279 | |
---|
3280 | this.previous = function () { |
---|
3281 | if (idx > 0) { |
---|
3282 | return colors[idx--]; |
---|
3283 | } |
---|
3284 | else { |
---|
3285 | idx = colors.length-1; |
---|
3286 | return colors[idx]; |
---|
3287 | } |
---|
3288 | }; |
---|
3289 | |
---|
3290 | // get a color by index without advancing pointer. |
---|
3291 | this.get = function(i) { |
---|
3292 | var idx = i - colors.length * Math.floor(i/colors.length); |
---|
3293 | return colors[idx]; |
---|
3294 | }; |
---|
3295 | |
---|
3296 | this.setColors = function(c) { |
---|
3297 | colors = c; |
---|
3298 | }; |
---|
3299 | |
---|
3300 | this.reset = function() { |
---|
3301 | idx = 0; |
---|
3302 | }; |
---|
3303 | }; |
---|
3304 | |
---|
3305 | // convert a hex color string to rgb string. |
---|
3306 | // h - 3 or 6 character hex string, with or without leading # |
---|
3307 | // a - optional alpha |
---|
3308 | $.jqplot.hex2rgb = function(h, a) { |
---|
3309 | h = h.replace('#', ''); |
---|
3310 | if (h.length == 3) { |
---|
3311 | h = h.charAt(0)+h.charAt(0)+h.charAt(1)+h.charAt(1)+h.charAt(2)+h.charAt(2); |
---|
3312 | } |
---|
3313 | var rgb; |
---|
3314 | rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16); |
---|
3315 | if (a) { |
---|
3316 | rgb += ', '+a; |
---|
3317 | } |
---|
3318 | rgb += ')'; |
---|
3319 | return rgb; |
---|
3320 | }; |
---|
3321 | |
---|
3322 | // convert an rgb color spec to a hex spec. ignore any alpha specification. |
---|
3323 | $.jqplot.rgb2hex = function(s) { |
---|
3324 | var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/; |
---|
3325 | var m = s.match(pat); |
---|
3326 | var h = '#'; |
---|
3327 | for (var i=1; i<4; i++) { |
---|
3328 | var temp; |
---|
3329 | if (m[i].search(/%/) != -1) { |
---|
3330 | temp = parseInt(255*m[i]/100, 10).toString(16); |
---|
3331 | if (temp.length == 1) { |
---|
3332 | temp = '0'+temp; |
---|
3333 | } |
---|
3334 | } |
---|
3335 | else { |
---|
3336 | temp = parseInt(m[i], 10).toString(16); |
---|
3337 | if (temp.length == 1) { |
---|
3338 | temp = '0'+temp; |
---|
3339 | } |
---|
3340 | } |
---|
3341 | h += temp; |
---|
3342 | } |
---|
3343 | return h; |
---|
3344 | }; |
---|
3345 | |
---|
3346 | // given a css color spec, return an rgb css color spec |
---|
3347 | $.jqplot.normalize2rgb = function(s, a) { |
---|
3348 | if (s.search(/^ *rgba?\(/) != -1) { |
---|
3349 | return s; |
---|
3350 | } |
---|
3351 | else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) { |
---|
3352 | return $.jqplot.hex2rgb(s, a); |
---|
3353 | } |
---|
3354 | else { |
---|
3355 | throw 'invalid color spec'; |
---|
3356 | } |
---|
3357 | }; |
---|
3358 | |
---|
3359 | // extract the r, g, b, a color components out of a css color spec. |
---|
3360 | $.jqplot.getColorComponents = function(s) { |
---|
3361 | // check to see if a color keyword. |
---|
3362 | s = $.jqplot.colorKeywordMap[s] || s; |
---|
3363 | var rgb = $.jqplot.normalize2rgb(s); |
---|
3364 | var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/; |
---|
3365 | var m = rgb.match(pat); |
---|
3366 | var ret = []; |
---|
3367 | for (var i=1; i<4; i++) { |
---|
3368 | if (m[i].search(/%/) != -1) { |
---|
3369 | ret[i-1] = parseInt(255*m[i]/100, 10); |
---|
3370 | } |
---|
3371 | else { |
---|
3372 | ret[i-1] = parseInt(m[i], 10); |
---|
3373 | } |
---|
3374 | } |
---|
3375 | ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0; |
---|
3376 | return ret; |
---|
3377 | }; |
---|
3378 | |
---|
3379 | $.jqplot.colorKeywordMap = {aliceblue: 'rgb(240, 248, 255)', antiquewhite: 'rgb(250, 235, 215)', aqua: 'rgb( 0, 255, 255)', aquamarine: 'rgb(127, 255, 212)', azure: 'rgb(240, 255, 255)', beige: 'rgb(245, 245, 220)', bisque: 'rgb(255, 228, 196)', black: 'rgb( 0, 0, 0)', blanchedalmond: 'rgb(255, 235, 205)', blue: 'rgb( 0, 0, 255)', blueviolet: 'rgb(138, 43, 226)', brown: 'rgb(165, 42, 42)', burlywood: 'rgb(222, 184, 135)', cadetblue: 'rgb( 95, 158, 160)', chartreuse: 'rgb(127, 255, 0)', chocolate: 'rgb(210, 105, 30)', coral: 'rgb(255, 127, 80)', cornflowerblue: 'rgb(100, 149, 237)', cornsilk: 'rgb(255, 248, 220)', crimson: 'rgb(220, 20, 60)', cyan: 'rgb( 0, 255, 255)', darkblue: 'rgb( 0, 0, 139)', darkcyan: 'rgb( 0, 139, 139)', darkgoldenrod: 'rgb(184, 134, 11)', darkgray: 'rgb(169, 169, 169)', darkgreen: 'rgb( 0, 100, 0)', darkgrey: 'rgb(169, 169, 169)', darkkhaki: 'rgb(189, 183, 107)', darkmagenta: 'rgb(139, 0, 139)', darkolivegreen: 'rgb( 85, 107, 47)', darkorange: 'rgb(255, 140, 0)', darkorchid: 'rgb(153, 50, 204)', darkred: 'rgb(139, 0, 0)', darksalmon: 'rgb(233, 150, 122)', darkseagreen: 'rgb(143, 188, 143)', darkslateblue: 'rgb( 72, 61, 139)', darkslategray: 'rgb( 47, 79, 79)', darkslategrey: 'rgb( 47, 79, 79)', darkturquoise: 'rgb( 0, 206, 209)', darkviolet: 'rgb(148, 0, 211)', deeppink: 'rgb(255, 20, 147)', deepskyblue: 'rgb( 0, 191, 255)', dimgray: 'rgb(105, 105, 105)', dimgrey: 'rgb(105, 105, 105)', dodgerblue: 'rgb( 30, 144, 255)', firebrick: 'rgb(178, 34, 34)', floralwhite: 'rgb(255, 250, 240)', forestgreen: 'rgb( 34, 139, 34)', fuchsia: 'rgb(255, 0, 255)', gainsboro: 'rgb(220, 220, 220)', ghostwhite: 'rgb(248, 248, 255)', gold: 'rgb(255, 215, 0)', goldenrod: 'rgb(218, 165, 32)', gray: 'rgb(128, 128, 128)', grey: 'rgb(128, 128, 128)', green: 'rgb( 0, 128, 0)', greenyellow: 'rgb(173, 255, 47)', honeydew: 'rgb(240, 255, 240)', hotpink: 'rgb(255, 105, 180)', indianred: 'rgb(205, 92, 92)', indigo: 'rgb( 75, 0, 130)', ivory: 'rgb(255, 255, 240)', khaki: 'rgb(240, 230, 140)', lavender: 'rgb(230, 230, 250)', lavenderblush: 'rgb(255, 240, 245)', lawngreen: 'rgb(124, 252, 0)', lemonchiffon: 'rgb(255, 250, 205)', lightblue: 'rgb(173, 216, 230)', lightcoral: 'rgb(240, 128, 128)', lightcyan: 'rgb(224, 255, 255)', lightgoldenrodyellow: 'rgb(250, 250, 210)', lightgray: 'rgb(211, 211, 211)', lightgreen: 'rgb(144, 238, 144)', lightgrey: 'rgb(211, 211, 211)', lightpink: 'rgb(255, 182, 193)', lightsalmon: 'rgb(255, 160, 122)', lightseagreen: 'rgb( 32, 178, 170)', lightskyblue: 'rgb(135, 206, 250)', lightslategray: 'rgb(119, 136, 153)', lightslategrey: 'rgb(119, 136, 153)', lightsteelblue: 'rgb(176, 196, 222)', lightyellow: 'rgb(255, 255, 224)', lime: 'rgb( 0, 255, 0)', limegreen: 'rgb( 50, 205, 50)', linen: 'rgb(250, 240, 230)', magenta: 'rgb(255, 0, 255)', maroon: 'rgb(128, 0, 0)', mediumaquamarine: 'rgb(102, 205, 170)', mediumblue: 'rgb( 0, 0, 205)', mediumorchid: 'rgb(186, 85, 211)', mediumpurple: 'rgb(147, 112, 219)', mediumseagreen: 'rgb( 60, 179, 113)', mediumslateblue: 'rgb(123, 104, 238)', mediumspringgreen: 'rgb( 0, 250, 154)', mediumturquoise: 'rgb( 72, 209, 204)', mediumvioletred: 'rgb(199, 21, 133)', midnightblue: 'rgb( 25, 25, 112)', mintcream: 'rgb(245, 255, 250)', mistyrose: 'rgb(255, 228, 225)', moccasin: 'rgb(255, 228, 181)', navajowhite: 'rgb(255, 222, 173)', navy: 'rgb( 0, 0, 128)', oldlace: 'rgb(253, 245, 230)', olive: 'rgb(128, 128, 0)', olivedrab: 'rgb(107, 142, 35)', orange: 'rgb(255, 165, 0)', orangered: 'rgb(255, 69, 0)', orchid: 'rgb(218, 112, 214)', palegoldenrod: 'rgb(238, 232, 170)', palegreen: 'rgb(152, 251, 152)', paleturquoise: 'rgb(175, 238, 238)', palevioletred: 'rgb(219, 112, 147)', papayawhip: 'rgb(255, 239, 213)', peachpuff: 'rgb(255, 218, 185)', peru: 'rgb(205, 133, 63)', pink: 'rgb(255, 192, 203)', plum: 'rgb(221, 160, 221)', powderblue: 'rgb(176, 224, 230)', purple: 'rgb(128, 0, 128)', red: 'rgb(255, 0, 0)', rosybrown: 'rgb(188, 143, 143)', royalblue: 'rgb( 65, 105, 225)', saddlebrown: 'rgb(139, 69, 19)', salmon: 'rgb(250, 128, 114)', sandybrown: 'rgb(244, 164, 96)', seagreen: 'rgb( 46, 139, 87)', seashell: 'rgb(255, 245, 238)', sienna: 'rgb(160, 82, 45)', silver: 'rgb(192, 192, 192)', skyblue: 'rgb(135, 206, 235)', slateblue: 'rgb(106, 90, 205)', slategray: 'rgb(112, 128, 144)', slategrey: 'rgb(112, 128, 144)', snow: 'rgb(255, 250, 250)', springgreen: 'rgb( 0, 255, 127)', steelblue: 'rgb( 70, 130, 180)', tan: 'rgb(210, 180, 140)', teal: 'rgb( 0, 128, 128)', thistle: 'rgb(216, 191, 216)', tomato: 'rgb(255, 99, 71)', turquoise: 'rgb( 64, 224, 208)', violet: 'rgb(238, 130, 238)', wheat: 'rgb(245, 222, 179)', white: 'rgb(255, 255, 255)', whitesmoke: 'rgb(245, 245, 245)', yellow: 'rgb(255, 255, 0)', yellowgreen: 'rgb(154, 205, 50)'}; |
---|
3380 | |
---|
3381 | |
---|
3382 | })(jQuery); |
---|