r114648 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r114647‎ | r114648 | r114649 >
Date:16:23, 1 April 2012
Author:jeroendedauw
Status:deferred
Tags:
Comment:
follow up to r114644, rem now obsolete files
Modified paths:
  • /trunk/extensions/SemanticResultFormats/jqPlot/README (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/excanvas.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.barRenderer.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.canvasAxisTickRenderer.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.canvasTextRenderer.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.categoryAxisRenderer.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.pieRenderer.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.pointLabels.min.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jqplot.trendline.js (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jquery.jqplot.css (deleted) (history)
  • /trunk/extensions/SemanticResultFormats/jqPlot/jquery.jqplot.js (deleted) (history)

Diff [purge]

Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.pointLabels.min.js
@@ -1,57 +0,0 @@
2 -/**
3 - * jqPlot
4 - * Pure JavaScript plotting plugin using jQuery
5 - *
6 - * Version: 1.0.0b2_r947
7 - *
8 - * Copyright (c) 2009-2011 Chris Leonello
9 - * jqPlot is currently available for use in all personal or commercial projects
10 - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
11 - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
12 - * choose the license that best suits your project and use it accordingly.
13 - *
14 - * Although not required, the author would appreciate an email letting him
15 - * know of any substantial use of jqPlot. You can reach the author at:
16 - * chris at jqplot dot com or see http://www.jqplot.com/info.php .
17 - *
18 - * If you are feeling kind and generous, consider supporting the project by
19 - * making a donation at: http://www.jqplot.com/donate.php .
20 - *
21 - * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
22 - *
23 - * version 2007.04.27
24 - * author Ash Searle
25 - * http://hexmen.com/blog/2007/03/printf-sprintf/
26 - * http://hexmen.com/js/sprintf.js
27 - * The author (Ash Searle) has placed this code in the public domain:
28 - * "This code is unrestricted: you are free to use it however you like."
29 - *
30 - * included jsDate library by Chris Leonello:
31 - *
32 - * Copyright (c) 2010-2011 Chris Leonello
33 - *
34 - * jsDate is currently available for use in all personal or commercial projects
35 - * under both the MIT and GPL version 2.0 licenses. This means that you can
36 - * choose the license that best suits your project and use it accordingly.
37 - *
38 - * jsDate borrows many concepts and ideas from the Date Instance
39 - * Methods by Ken Snyder along with some parts of Ken's actual code.
40 - *
41 - * Ken's origianl Date Instance Methods and copyright notice:
42 - *
43 - * Ken Snyder (ken d snyder at gmail dot com)
44 - * 2008-09-10
45 - * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
46 - * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
47 - *
48 - * jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
49 - * Larry has generously given permission to adapt his code for inclusion
50 - * into jqPlot.
51 - *
52 - * Larry's original code can be found here:
53 - *
54 - * https://github.com/lsiden/export-jqplot-to-png
55 - *
56 - *
57 - */
58 -(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this._labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=-5;this.formatter=c.jqplot.DefaultTickFormatter;this.formatString="";this.hideZeros=false;this._elems=[];c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(i,h,f,g){var e=c.extend(true,{},f,g);e.pointLabels=e.pointLabels||{};if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"&&!e.pointLabels.location){e.pointLabels.location="e"}this.plugins.pointLabels=new c.jqplot.PointLabels(e.pointLabels);this.plugins.pointLabels.setLabels.call(this)};c.jqplot.PointLabels.prototype.setLabels=function(){var f=this.plugins.pointLabels;var h;if(f.seriesLabelIndex!=null){h=f.seriesLabelIndex}else{if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"){h=0}else{h=(this._plotData.length===0)?0:this._plotData[0].length-1}}f._labels=[];if(f.labels.length===0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){for(var e=0;e<this._plotData.length;e++){f._labels.push(this._plotData[e][h])}}}else{var g=this._plotData;if(this.renderer.constructor===c.jqplot.BarRenderer&&this.waterfall){g=this._data}if(g.length&&g[0].length){for(var e=0;e<g.length;e++){f._labels.push(g[e][h])}}g=null}}else{if(f.labels.length){f._labels=f.labels}}};c.jqplot.PointLabels.prototype.xOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerWidth(true)-this.xpadding;break;case"n":h=-f.outerWidth(true)/2;break;case"ne":h=this.xpadding;break;case"e":h=this.xpadding;break;case"se":h=this.xpadding;break;case"s":h=-f.outerWidth(true)/2;break;case"sw":h=-f.outerWidth(true)-this.xpadding;break;case"w":h=-f.outerWidth(true)-this.xpadding;break;default:h=-f.outerWidth(true)-this.xpadding;break}return h};c.jqplot.PointLabels.prototype.yOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerHeight(true)-this.ypadding;break;case"n":h=-f.outerHeight(true)-this.ypadding;break;case"ne":h=-f.outerHeight(true)-this.ypadding;break;case"e":h=-f.outerHeight(true)/2;break;case"se":h=this.ypadding;break;case"s":h=this.ypadding;break;case"sw":h=this.ypadding;break;case"w":h=-f.outerHeight(true)/2;break;default:h=-f.outerHeight(true)-this.ypadding;break}return h};c.jqplot.PointLabels.draw=function(w,j){var t=this.plugins.pointLabels;t.setLabels.call(this);for(var v=0;v<t._elems.length;v++){t._elems[v].emptyForce()}t._elems.splice(0,t._elems.length);if(t.show){var r="_"+this._stackAxis+"axis";if(!t.formatString){t.formatString=this[r]._ticks[0].formatString;t.formatter=this[r]._ticks[0].formatter}var C=this._plotData;var z=this._xaxis;var q=this._yaxis;var y,f;for(var v=0,u=t._labels.length;v<u;v++){var o=t._labels[v];if(t.hideZeros&&parseInt(t._labels[v],10)==0){o=""}if(o!=null){o=t.formatter(t.formatString,o)}f=document.createElement("div");t._elems[v]=c(f);y=t._elems[v];y.addClass("jqplot-point-label jqplot-series-"+this.index+" jqplot-point-"+v);y.css("position","absolute");y.insertAfter(w.canvas);if(t.escapeHTML){y.text(o)}else{y.html(o)}var g=t.location;if((this.fillToZero&&C[v][1]<0)||(this.fillToZero&&this._type==="bar"&&this.barDirection==="horizontal"&&C[v][0]<0)||(this.waterfall&&parseInt(o,10))<0){g=b[d[g]]}var n=z.u2p(C[v][0])+t.xOffset(y,g);var h=q.u2p(C[v][1])+t.yOffset(y,g);if(this.renderer.constructor==c.jqplot.BarRenderer){if(this.barDirection=="vertical"){n+=this._barNudge}else{h-=this._barNudge}}y.css("left",n);y.css("top",h);var k=n+y.width();var s=h+y.height();var B=t.edgeTolerance;var e=c(w.canvas).position().left;var x=c(w.canvas).position().top;var A=w.canvas.width+e;var m=w.canvas.height+x;if(n-B<e||h-B<x||k+B>A||s+B>m){y.remove()}y=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/excanvas.js
@@ -1,1416 +0,0 @@
2 -// Copyright 2006 Google Inc.
3 -//
4 -// Licensed under the Apache License, Version 2.0 (the "License");
5 -// you may not use this file except in compliance with the License.
6 -// You may obtain a copy of the License at
7 -//
8 -// http://www.apache.org/licenses/LICENSE-2.0
9 -//
10 -// Unless required by applicable law or agreed to in writing, software
11 -// distributed under the License is distributed on an "AS IS" BASIS,
12 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 -// See the License for the specific language governing permissions and
14 -// limitations under the License.
15 -
16 -
17 -// Known Issues:
18 -//
19 -// * Patterns only support repeat.
20 -// * Radial gradient are not implemented. The VML version of these look very
21 -// different from the canvas one.
22 -// * Clipping paths are not implemented.
23 -// * Coordsize. The width and height attribute have higher priority than the
24 -// width and height style values which isn't correct.
25 -// * Painting mode isn't implemented.
26 -// * Canvas width/height should is using content-box by default. IE in
27 -// Quirks mode will draw the canvas using border-box. Either change your
28 -// doctype to HTML5
29 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
30 -// or use Box Sizing Behavior from WebFX
31 -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
32 -// * Non uniform scaling does not correctly scale strokes.
33 -// * Optimize. There is always room for speed improvements.
34 -
35 -// Only add this code if we do not already have a canvas implementation
36 -if (!document.createElement('canvas').getContext) {
37 -
38 -(function() {
39 -
40 - // alias some functions to make (compiled) code shorter
41 - var m = Math;
42 - var mr = m.round;
43 - var ms = m.sin;
44 - var mc = m.cos;
45 - var abs = m.abs;
46 - var sqrt = m.sqrt;
47 -
48 - // this is used for sub pixel precision
49 - var Z = 10;
50 - var Z2 = Z / 2;
51 -
52 - var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
53 -
54 - /**
55 - * This funtion is assigned to the <canvas> elements as element.getContext().
56 - * @this {HTMLElement}
57 - * @return {CanvasRenderingContext2D_}
58 - */
59 - function getContext() {
60 - return this.context_ ||
61 - (this.context_ = new CanvasRenderingContext2D_(this));
62 - }
63 -
64 - var slice = Array.prototype.slice;
65 -
66 - /**
67 - * Binds a function to an object. The returned function will always use the
68 - * passed in {@code obj} as {@code this}.
69 - *
70 - * Example:
71 - *
72 - * g = bind(f, obj, a, b)
73 - * g(c, d) // will do f.call(obj, a, b, c, d)
74 - *
75 - * @param {Function} f The function to bind the object to
76 - * @param {Object} obj The object that should act as this when the function
77 - * is called
78 - * @param {*} var_args Rest arguments that will be used as the initial
79 - * arguments when the function is called
80 - * @return {Function} A new function that has bound this
81 - */
82 - function bind(f, obj, var_args) {
83 - var a = slice.call(arguments, 2);
84 - return function() {
85 - return f.apply(obj, a.concat(slice.call(arguments)));
86 - };
87 - }
88 -
89 - function encodeHtmlAttribute(s) {
90 - return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
91 - }
92 -
93 - function addNamespace(doc, prefix, urn) {
94 - if (!doc.namespaces[prefix]) {
95 - doc.namespaces.add(prefix, urn, '#default#VML');
96 - }
97 - }
98 -
99 - function addNamespacesAndStylesheet(doc) {
100 - addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
101 - addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
102 -
103 - // Setup default CSS. Only add one style sheet per document
104 - if (!doc.styleSheets['ex_canvas_']) {
105 - var ss = doc.createStyleSheet();
106 - ss.owningElement.id = 'ex_canvas_';
107 - ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
108 - // default size is 300x150 in Gecko and Opera
109 - 'text-align:left;width:300px;height:150px}';
110 - }
111 - }
112 -
113 - // Add namespaces and stylesheet at startup.
114 - addNamespacesAndStylesheet(document);
115 -
116 - var G_vmlCanvasManager_ = {
117 - init: function(opt_doc) {
118 - var doc = opt_doc || document;
119 - // Create a dummy element so that IE will allow canvas elements to be
120 - // recognized.
121 - doc.createElement('canvas');
122 - doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
123 - },
124 -
125 - init_: function(doc) {
126 - // find all canvas elements
127 - var els = doc.getElementsByTagName('canvas');
128 - for (var i = 0; i < els.length; i++) {
129 - this.initElement(els[i]);
130 - }
131 - },
132 -
133 - /**
134 - * Public initializes a canvas element so that it can be used as canvas
135 - * element from now on. This is called automatically before the page is
136 - * loaded but if you are creating elements using createElement you need to
137 - * make sure this is called on the element.
138 - * @param {HTMLElement} el The canvas element to initialize.
139 - * @return {HTMLElement} the element that was created.
140 - */
141 - initElement: function(el) {
142 - if (!el.getContext) {
143 - el.getContext = getContext;
144 -
145 - // Add namespaces and stylesheet to document of the element.
146 - addNamespacesAndStylesheet(el.ownerDocument);
147 -
148 - // Remove fallback content. There is no way to hide text nodes so we
149 - // just remove all childNodes. We could hide all elements and remove
150 - // text nodes but who really cares about the fallback content.
151 - el.innerHTML = '';
152 -
153 - // do not use inline function because that will leak memory
154 - el.attachEvent('onpropertychange', onPropertyChange);
155 - el.attachEvent('onresize', onResize);
156 -
157 - var attrs = el.attributes;
158 - if (attrs.width && attrs.width.specified) {
159 - // TODO: use runtimeStyle and coordsize
160 - // el.getContext().setWidth_(attrs.width.nodeValue);
161 - el.style.width = attrs.width.nodeValue + 'px';
162 - } else {
163 - el.width = el.clientWidth;
164 - }
165 - if (attrs.height && attrs.height.specified) {
166 - // TODO: use runtimeStyle and coordsize
167 - // el.getContext().setHeight_(attrs.height.nodeValue);
168 - el.style.height = attrs.height.nodeValue + 'px';
169 - } else {
170 - el.height = el.clientHeight;
171 - }
172 - //el.getContext().setCoordsize_()
173 - }
174 - return el;
175 - }
176 - };
177 -
178 - function onPropertyChange(e) {
179 - var el = e.srcElement;
180 -
181 - switch (e.propertyName) {
182 - case 'width':
183 - el.getContext().clearRect();
184 - el.style.width = el.attributes.width.nodeValue + 'px';
185 - // In IE8 this does not trigger onresize.
186 - el.firstChild.style.width = el.clientWidth + 'px';
187 - break;
188 - case 'height':
189 - el.getContext().clearRect();
190 - el.style.height = el.attributes.height.nodeValue + 'px';
191 - el.firstChild.style.height = el.clientHeight + 'px';
192 - break;
193 - }
194 - }
195 -
196 - function onResize(e) {
197 - var el = e.srcElement;
198 - if (el.firstChild) {
199 - el.firstChild.style.width = el.clientWidth + 'px';
200 - el.firstChild.style.height = el.clientHeight + 'px';
201 - }
202 - }
203 -
204 - G_vmlCanvasManager_.init();
205 -
206 - // precompute "00" to "FF"
207 - var decToHex = [];
208 - for (var i = 0; i < 16; i++) {
209 - for (var j = 0; j < 16; j++) {
210 - decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
211 - }
212 - }
213 -
214 - function createMatrixIdentity() {
215 - return [
216 - [1, 0, 0],
217 - [0, 1, 0],
218 - [0, 0, 1]
219 - ];
220 - }
221 -
222 - function matrixMultiply(m1, m2) {
223 - var result = createMatrixIdentity();
224 -
225 - for (var x = 0; x < 3; x++) {
226 - for (var y = 0; y < 3; y++) {
227 - var sum = 0;
228 -
229 - for (var z = 0; z < 3; z++) {
230 - sum += m1[x][z] * m2[z][y];
231 - }
232 -
233 - result[x][y] = sum;
234 - }
235 - }
236 - return result;
237 - }
238 -
239 - function copyState(o1, o2) {
240 - o2.fillStyle = o1.fillStyle;
241 - o2.lineCap = o1.lineCap;
242 - o2.lineJoin = o1.lineJoin;
243 - o2.lineWidth = o1.lineWidth;
244 - o2.miterLimit = o1.miterLimit;
245 - o2.shadowBlur = o1.shadowBlur;
246 - o2.shadowColor = o1.shadowColor;
247 - o2.shadowOffsetX = o1.shadowOffsetX;
248 - o2.shadowOffsetY = o1.shadowOffsetY;
249 - o2.strokeStyle = o1.strokeStyle;
250 - o2.globalAlpha = o1.globalAlpha;
251 - o2.font = o1.font;
252 - o2.textAlign = o1.textAlign;
253 - o2.textBaseline = o1.textBaseline;
254 - o2.arcScaleX_ = o1.arcScaleX_;
255 - o2.arcScaleY_ = o1.arcScaleY_;
256 - o2.lineScale_ = o1.lineScale_;
257 - }
258 -
259 - var colorData = {
260 - aliceblue: '#F0F8FF',
261 - antiquewhite: '#FAEBD7',
262 - aquamarine: '#7FFFD4',
263 - azure: '#F0FFFF',
264 - beige: '#F5F5DC',
265 - bisque: '#FFE4C4',
266 - black: '#000000',
267 - blanchedalmond: '#FFEBCD',
268 - blueviolet: '#8A2BE2',
269 - brown: '#A52A2A',
270 - burlywood: '#DEB887',
271 - cadetblue: '#5F9EA0',
272 - chartreuse: '#7FFF00',
273 - chocolate: '#D2691E',
274 - coral: '#FF7F50',
275 - cornflowerblue: '#6495ED',
276 - cornsilk: '#FFF8DC',
277 - crimson: '#DC143C',
278 - cyan: '#00FFFF',
279 - darkblue: '#00008B',
280 - darkcyan: '#008B8B',
281 - darkgoldenrod: '#B8860B',
282 - darkgray: '#A9A9A9',
283 - darkgreen: '#006400',
284 - darkgrey: '#A9A9A9',
285 - darkkhaki: '#BDB76B',
286 - darkmagenta: '#8B008B',
287 - darkolivegreen: '#556B2F',
288 - darkorange: '#FF8C00',
289 - darkorchid: '#9932CC',
290 - darkred: '#8B0000',
291 - darksalmon: '#E9967A',
292 - darkseagreen: '#8FBC8F',
293 - darkslateblue: '#483D8B',
294 - darkslategray: '#2F4F4F',
295 - darkslategrey: '#2F4F4F',
296 - darkturquoise: '#00CED1',
297 - darkviolet: '#9400D3',
298 - deeppink: '#FF1493',
299 - deepskyblue: '#00BFFF',
300 - dimgray: '#696969',
301 - dimgrey: '#696969',
302 - dodgerblue: '#1E90FF',
303 - firebrick: '#B22222',
304 - floralwhite: '#FFFAF0',
305 - forestgreen: '#228B22',
306 - gainsboro: '#DCDCDC',
307 - ghostwhite: '#F8F8FF',
308 - gold: '#FFD700',
309 - goldenrod: '#DAA520',
310 - grey: '#808080',
311 - greenyellow: '#ADFF2F',
312 - honeydew: '#F0FFF0',
313 - hotpink: '#FF69B4',
314 - indianred: '#CD5C5C',
315 - indigo: '#4B0082',
316 - ivory: '#FFFFF0',
317 - khaki: '#F0E68C',
318 - lavender: '#E6E6FA',
319 - lavenderblush: '#FFF0F5',
320 - lawngreen: '#7CFC00',
321 - lemonchiffon: '#FFFACD',
322 - lightblue: '#ADD8E6',
323 - lightcoral: '#F08080',
324 - lightcyan: '#E0FFFF',
325 - lightgoldenrodyellow: '#FAFAD2',
326 - lightgreen: '#90EE90',
327 - lightgrey: '#D3D3D3',
328 - lightpink: '#FFB6C1',
329 - lightsalmon: '#FFA07A',
330 - lightseagreen: '#20B2AA',
331 - lightskyblue: '#87CEFA',
332 - lightslategray: '#778899',
333 - lightslategrey: '#778899',
334 - lightsteelblue: '#B0C4DE',
335 - lightyellow: '#FFFFE0',
336 - limegreen: '#32CD32',
337 - linen: '#FAF0E6',
338 - magenta: '#FF00FF',
339 - mediumaquamarine: '#66CDAA',
340 - mediumblue: '#0000CD',
341 - mediumorchid: '#BA55D3',
342 - mediumpurple: '#9370DB',
343 - mediumseagreen: '#3CB371',
344 - mediumslateblue: '#7B68EE',
345 - mediumspringgreen: '#00FA9A',
346 - mediumturquoise: '#48D1CC',
347 - mediumvioletred: '#C71585',
348 - midnightblue: '#191970',
349 - mintcream: '#F5FFFA',
350 - mistyrose: '#FFE4E1',
351 - moccasin: '#FFE4B5',
352 - navajowhite: '#FFDEAD',
353 - oldlace: '#FDF5E6',
354 - olivedrab: '#6B8E23',
355 - orange: '#FFA500',
356 - orangered: '#FF4500',
357 - orchid: '#DA70D6',
358 - palegoldenrod: '#EEE8AA',
359 - palegreen: '#98FB98',
360 - paleturquoise: '#AFEEEE',
361 - palevioletred: '#DB7093',
362 - papayawhip: '#FFEFD5',
363 - peachpuff: '#FFDAB9',
364 - peru: '#CD853F',
365 - pink: '#FFC0CB',
366 - plum: '#DDA0DD',
367 - powderblue: '#B0E0E6',
368 - rosybrown: '#BC8F8F',
369 - royalblue: '#4169E1',
370 - saddlebrown: '#8B4513',
371 - salmon: '#FA8072',
372 - sandybrown: '#F4A460',
373 - seagreen: '#2E8B57',
374 - seashell: '#FFF5EE',
375 - sienna: '#A0522D',
376 - skyblue: '#87CEEB',
377 - slateblue: '#6A5ACD',
378 - slategray: '#708090',
379 - slategrey: '#708090',
380 - snow: '#FFFAFA',
381 - springgreen: '#00FF7F',
382 - steelblue: '#4682B4',
383 - tan: '#D2B48C',
384 - thistle: '#D8BFD8',
385 - tomato: '#FF6347',
386 - turquoise: '#40E0D0',
387 - violet: '#EE82EE',
388 - wheat: '#F5DEB3',
389 - whitesmoke: '#F5F5F5',
390 - yellowgreen: '#9ACD32'
391 - };
392 -
393 -
394 - function getRgbHslContent(styleString) {
395 - var start = styleString.indexOf('(', 3);
396 - var end = styleString.indexOf(')', start + 1);
397 - var parts = styleString.substring(start + 1, end).split(',');
398 - // add alpha if needed
399 - if (parts.length != 4 || styleString.charAt(3) != 'a') {
400 - parts[3] = 1;
401 - }
402 - return parts;
403 - }
404 -
405 - function percent(s) {
406 - return parseFloat(s) / 100;
407 - }
408 -
409 - function clamp(v, min, max) {
410 - return Math.min(max, Math.max(min, v));
411 - }
412 -
413 - function hslToRgb(parts){
414 - var r, g, b, h, s, l;
415 - h = parseFloat(parts[0]) / 360 % 360;
416 - if (h < 0)
417 - h++;
418 - s = clamp(percent(parts[1]), 0, 1);
419 - l = clamp(percent(parts[2]), 0, 1);
420 - if (s == 0) {
421 - r = g = b = l; // achromatic
422 - } else {
423 - var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
424 - var p = 2 * l - q;
425 - r = hueToRgb(p, q, h + 1 / 3);
426 - g = hueToRgb(p, q, h);
427 - b = hueToRgb(p, q, h - 1 / 3);
428 - }
429 -
430 - return '#' + decToHex[Math.floor(r * 255)] +
431 - decToHex[Math.floor(g * 255)] +
432 - decToHex[Math.floor(b * 255)];
433 - }
434 -
435 - function hueToRgb(m1, m2, h) {
436 - if (h < 0)
437 - h++;
438 - if (h > 1)
439 - h--;
440 -
441 - if (6 * h < 1)
442 - return m1 + (m2 - m1) * 6 * h;
443 - else if (2 * h < 1)
444 - return m2;
445 - else if (3 * h < 2)
446 - return m1 + (m2 - m1) * (2 / 3 - h) * 6;
447 - else
448 - return m1;
449 - }
450 -
451 - var processStyleCache = {};
452 -
453 - function processStyle(styleString) {
454 - if (styleString in processStyleCache) {
455 - return processStyleCache[styleString];
456 - }
457 -
458 - var str, alpha = 1;
459 -
460 - styleString = String(styleString);
461 - if (styleString.charAt(0) == '#') {
462 - str = styleString;
463 - } else if (/^rgb/.test(styleString)) {
464 - var parts = getRgbHslContent(styleString);
465 - var str = '#', n;
466 - for (var i = 0; i < 3; i++) {
467 - if (parts[i].indexOf('%') != -1) {
468 - n = Math.floor(percent(parts[i]) * 255);
469 - } else {
470 - n = +parts[i];
471 - }
472 - str += decToHex[clamp(n, 0, 255)];
473 - }
474 - alpha = +parts[3];
475 - } else if (/^hsl/.test(styleString)) {
476 - var parts = getRgbHslContent(styleString);
477 - str = hslToRgb(parts);
478 - alpha = parts[3];
479 - } else {
480 - str = colorData[styleString] || styleString;
481 - }
482 - return processStyleCache[styleString] = {color: str, alpha: alpha};
483 - }
484 -
485 - var DEFAULT_STYLE = {
486 - style: 'normal',
487 - variant: 'normal',
488 - weight: 'normal',
489 - size: 10,
490 - family: 'sans-serif'
491 - };
492 -
493 - // Internal text style cache
494 - var fontStyleCache = {};
495 -
496 - function processFontStyle(styleString) {
497 - if (fontStyleCache[styleString]) {
498 - return fontStyleCache[styleString];
499 - }
500 -
501 - var el = document.createElement('div');
502 - var style = el.style;
503 - try {
504 - style.font = styleString;
505 - } catch (ex) {
506 - // Ignore failures to set to invalid font.
507 - }
508 -
509 - return fontStyleCache[styleString] = {
510 - style: style.fontStyle || DEFAULT_STYLE.style,
511 - variant: style.fontVariant || DEFAULT_STYLE.variant,
512 - weight: style.fontWeight || DEFAULT_STYLE.weight,
513 - size: style.fontSize || DEFAULT_STYLE.size,
514 - family: style.fontFamily || DEFAULT_STYLE.family
515 - };
516 - }
517 -
518 - function getComputedStyle(style, element) {
519 - var computedStyle = {};
520 -
521 - for (var p in style) {
522 - computedStyle[p] = style[p];
523 - }
524 -
525 - // Compute the size
526 - var canvasFontSize = parseFloat(element.currentStyle.fontSize),
527 - fontSize = parseFloat(style.size);
528 -
529 - if (typeof style.size == 'number') {
530 - computedStyle.size = style.size;
531 - } else if (style.size.indexOf('px') != -1) {
532 - computedStyle.size = fontSize;
533 - } else if (style.size.indexOf('em') != -1) {
534 - computedStyle.size = canvasFontSize * fontSize;
535 - } else if(style.size.indexOf('%') != -1) {
536 - computedStyle.size = (canvasFontSize / 100) * fontSize;
537 - } else if (style.size.indexOf('pt') != -1) {
538 - computedStyle.size = fontSize / .75;
539 - } else {
540 - computedStyle.size = canvasFontSize;
541 - }
542 -
543 - // Different scaling between normal text and VML text. This was found using
544 - // trial and error to get the same size as non VML text.
545 - computedStyle.size *= 0.981;
546 -
547 - return computedStyle;
548 - }
549 -
550 - function buildStyle(style) {
551 - return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
552 - style.size + 'px ' + style.family;
553 - }
554 -
555 - var lineCapMap = {
556 - 'butt': 'flat',
557 - 'round': 'round'
558 - };
559 -
560 - function processLineCap(lineCap) {
561 - return lineCapMap[lineCap] || 'square';
562 - }
563 -
564 - /**
565 - * This class implements CanvasRenderingContext2D interface as described by
566 - * the WHATWG.
567 - * @param {HTMLElement} canvasElement The element that the 2D context should
568 - * be associated with
569 - */
570 - function CanvasRenderingContext2D_(canvasElement) {
571 - this.m_ = createMatrixIdentity();
572 -
573 - this.mStack_ = [];
574 - this.aStack_ = [];
575 - this.currentPath_ = [];
576 -
577 - // Canvas context properties
578 - this.strokeStyle = '#000';
579 - this.fillStyle = '#000';
580 -
581 - this.lineWidth = 1;
582 - this.lineJoin = 'miter';
583 - this.lineCap = 'butt';
584 - this.miterLimit = Z * 1;
585 - this.globalAlpha = 1;
586 - this.font = '10px sans-serif';
587 - this.textAlign = 'left';
588 - this.textBaseline = 'alphabetic';
589 - this.canvas = canvasElement;
590 -
591 - var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
592 - canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
593 - var el = canvasElement.ownerDocument.createElement('div');
594 - el.style.cssText = cssText;
595 - canvasElement.appendChild(el);
596 -
597 - var overlayEl = el.cloneNode(false);
598 - // Use a non transparent background.
599 - overlayEl.style.backgroundColor = 'red';
600 - overlayEl.style.filter = 'alpha(opacity=0)';
601 - canvasElement.appendChild(overlayEl);
602 -
603 - this.element_ = el;
604 - this.arcScaleX_ = 1;
605 - this.arcScaleY_ = 1;
606 - this.lineScale_ = 1;
607 - }
608 -
609 - var contextPrototype = CanvasRenderingContext2D_.prototype;
610 - contextPrototype.clearRect = function() {
611 - if (this.textMeasureEl_) {
612 - this.textMeasureEl_.removeNode(true);
613 - this.textMeasureEl_ = null;
614 - }
615 - this.element_.innerHTML = '';
616 - };
617 -
618 - contextPrototype.beginPath = function() {
619 - // TODO: Branch current matrix so that save/restore has no effect
620 - // as per safari docs.
621 - this.currentPath_ = [];
622 - };
623 -
624 - contextPrototype.moveTo = function(aX, aY) {
625 - var p = getCoords(this, aX, aY);
626 - this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
627 - this.currentX_ = p.x;
628 - this.currentY_ = p.y;
629 - };
630 -
631 - contextPrototype.lineTo = function(aX, aY) {
632 - var p = getCoords(this, aX, aY);
633 - this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
634 -
635 - this.currentX_ = p.x;
636 - this.currentY_ = p.y;
637 - };
638 -
639 - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
640 - aCP2x, aCP2y,
641 - aX, aY) {
642 - var p = getCoords(this, aX, aY);
643 - var cp1 = getCoords(this, aCP1x, aCP1y);
644 - var cp2 = getCoords(this, aCP2x, aCP2y);
645 - bezierCurveTo(this, cp1, cp2, p);
646 - };
647 -
648 - // Helper function that takes the already fixed cordinates.
649 - function bezierCurveTo(self, cp1, cp2, p) {
650 - self.currentPath_.push({
651 - type: 'bezierCurveTo',
652 - cp1x: cp1.x,
653 - cp1y: cp1.y,
654 - cp2x: cp2.x,
655 - cp2y: cp2.y,
656 - x: p.x,
657 - y: p.y
658 - });
659 - self.currentX_ = p.x;
660 - self.currentY_ = p.y;
661 - }
662 -
663 - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
664 - // the following is lifted almost directly from
665 - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
666 -
667 - var cp = getCoords(this, aCPx, aCPy);
668 - var p = getCoords(this, aX, aY);
669 -
670 - var cp1 = {
671 - x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
672 - y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
673 - };
674 - var cp2 = {
675 - x: cp1.x + (p.x - this.currentX_) / 3.0,
676 - y: cp1.y + (p.y - this.currentY_) / 3.0
677 - };
678 -
679 - bezierCurveTo(this, cp1, cp2, p);
680 - };
681 -
682 - contextPrototype.arc = function(aX, aY, aRadius,
683 - aStartAngle, aEndAngle, aClockwise) {
684 - aRadius *= Z;
685 - var arcType = aClockwise ? 'at' : 'wa';
686 -
687 - var xStart = aX + mc(aStartAngle) * aRadius - Z2;
688 - var yStart = aY + ms(aStartAngle) * aRadius - Z2;
689 -
690 - var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
691 - var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
692 -
693 - // IE won't render arches drawn counter clockwise if xStart == xEnd.
694 - if (xStart == xEnd && !aClockwise) {
695 - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
696 - // that can be represented in binary
697 - }
698 -
699 - var p = getCoords(this, aX, aY);
700 - var pStart = getCoords(this, xStart, yStart);
701 - var pEnd = getCoords(this, xEnd, yEnd);
702 -
703 - this.currentPath_.push({type: arcType,
704 - x: p.x,
705 - y: p.y,
706 - radius: aRadius,
707 - xStart: pStart.x,
708 - yStart: pStart.y,
709 - xEnd: pEnd.x,
710 - yEnd: pEnd.y});
711 -
712 - };
713 -
714 - contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
715 - this.moveTo(aX, aY);
716 - this.lineTo(aX + aWidth, aY);
717 - this.lineTo(aX + aWidth, aY + aHeight);
718 - this.lineTo(aX, aY + aHeight);
719 - this.closePath();
720 - };
721 -
722 - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
723 - var oldPath = this.currentPath_;
724 - this.beginPath();
725 -
726 - this.moveTo(aX, aY);
727 - this.lineTo(aX + aWidth, aY);
728 - this.lineTo(aX + aWidth, aY + aHeight);
729 - this.lineTo(aX, aY + aHeight);
730 - this.closePath();
731 - this.stroke();
732 -
733 - this.currentPath_ = oldPath;
734 - };
735 -
736 - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
737 - var oldPath = this.currentPath_;
738 - this.beginPath();
739 -
740 - this.moveTo(aX, aY);
741 - this.lineTo(aX + aWidth, aY);
742 - this.lineTo(aX + aWidth, aY + aHeight);
743 - this.lineTo(aX, aY + aHeight);
744 - this.closePath();
745 - this.fill();
746 -
747 - this.currentPath_ = oldPath;
748 - };
749 -
750 - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
751 - var gradient = new CanvasGradient_('gradient');
752 - gradient.x0_ = aX0;
753 - gradient.y0_ = aY0;
754 - gradient.x1_ = aX1;
755 - gradient.y1_ = aY1;
756 - return gradient;
757 - };
758 -
759 - contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
760 - aX1, aY1, aR1) {
761 - var gradient = new CanvasGradient_('gradientradial');
762 - gradient.x0_ = aX0;
763 - gradient.y0_ = aY0;
764 - gradient.r0_ = aR0;
765 - gradient.x1_ = aX1;
766 - gradient.y1_ = aY1;
767 - gradient.r1_ = aR1;
768 - return gradient;
769 - };
770 -
771 - contextPrototype.drawImage = function(image, var_args) {
772 - var dx, dy, dw, dh, sx, sy, sw, sh;
773 -
774 - // to find the original width we overide the width and height
775 - var oldRuntimeWidth = image.runtimeStyle.width;
776 - var oldRuntimeHeight = image.runtimeStyle.height;
777 - image.runtimeStyle.width = 'auto';
778 - image.runtimeStyle.height = 'auto';
779 -
780 - // get the original size
781 - var w = image.width;
782 - var h = image.height;
783 -
784 - // and remove overides
785 - image.runtimeStyle.width = oldRuntimeWidth;
786 - image.runtimeStyle.height = oldRuntimeHeight;
787 -
788 - if (arguments.length == 3) {
789 - dx = arguments[1];
790 - dy = arguments[2];
791 - sx = sy = 0;
792 - sw = dw = w;
793 - sh = dh = h;
794 - } else if (arguments.length == 5) {
795 - dx = arguments[1];
796 - dy = arguments[2];
797 - dw = arguments[3];
798 - dh = arguments[4];
799 - sx = sy = 0;
800 - sw = w;
801 - sh = h;
802 - } else if (arguments.length == 9) {
803 - sx = arguments[1];
804 - sy = arguments[2];
805 - sw = arguments[3];
806 - sh = arguments[4];
807 - dx = arguments[5];
808 - dy = arguments[6];
809 - dw = arguments[7];
810 - dh = arguments[8];
811 - } else {
812 - throw Error('Invalid number of arguments');
813 - }
814 -
815 - var d = getCoords(this, dx, dy);
816 -
817 - var w2 = sw / 2;
818 - var h2 = sh / 2;
819 -
820 - var vmlStr = [];
821 -
822 - var W = 10;
823 - var H = 10;
824 -
825 - // For some reason that I've now forgotten, using divs didn't work
826 - vmlStr.push(' <g_vml_:group',
827 - ' coordsize="', Z * W, ',', Z * H, '"',
828 - ' coordorigin="0,0"' ,
829 - ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
830 -
831 - // If filters are necessary (rotation exists), create them
832 - // filters are bog-slow, so only create them if abbsolutely necessary
833 - // The following check doesn't account for skews (which don't exist
834 - // in the canvas spec (yet) anyway.
835 -
836 - if (this.m_[0][0] != 1 || this.m_[0][1] ||
837 - this.m_[1][1] != 1 || this.m_[1][0]) {
838 - var filter = [];
839 -
840 - // Note the 12/21 reversal
841 - filter.push('M11=', this.m_[0][0], ',',
842 - 'M12=', this.m_[1][0], ',',
843 - 'M21=', this.m_[0][1], ',',
844 - 'M22=', this.m_[1][1], ',',
845 - 'Dx=', mr(d.x / Z), ',',
846 - 'Dy=', mr(d.y / Z), '');
847 -
848 - // Bounding box calculation (need to minimize displayed area so that
849 - // filters don't waste time on unused pixels.
850 - var max = d;
851 - var c2 = getCoords(this, dx + dw, dy);
852 - var c3 = getCoords(this, dx, dy + dh);
853 - var c4 = getCoords(this, dx + dw, dy + dh);
854 -
855 - max.x = m.max(max.x, c2.x, c3.x, c4.x);
856 - max.y = m.max(max.y, c2.y, c3.y, c4.y);
857 -
858 - vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
859 - 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
860 - filter.join(''), ", sizingmethod='clip');");
861 -
862 - } else {
863 - vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
864 - }
865 -
866 - vmlStr.push(' ">' ,
867 - '<g_vml_:image src="', image.src, '"',
868 - ' style="width:', Z * dw, 'px;',
869 - ' height:', Z * dh, 'px"',
870 - ' cropleft="', sx / w, '"',
871 - ' croptop="', sy / h, '"',
872 - ' cropright="', (w - sx - sw) / w, '"',
873 - ' cropbottom="', (h - sy - sh) / h, '"',
874 - ' />',
875 - '</g_vml_:group>');
876 -
877 - this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
878 - };
879 -
880 - contextPrototype.stroke = function(aFill) {
881 - var lineStr = [];
882 - var lineOpen = false;
883 -
884 - var W = 10;
885 - var H = 10;
886 -
887 - lineStr.push('<g_vml_:shape',
888 - ' filled="', !!aFill, '"',
889 - ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
890 - ' coordorigin="0,0"',
891 - ' coordsize="', Z * W, ',', Z * H, '"',
892 - ' stroked="', !aFill, '"',
893 - ' path="');
894 -
895 - var newSeq = false;
896 - var min = {x: null, y: null};
897 - var max = {x: null, y: null};
898 -
899 - for (var i = 0; i < this.currentPath_.length; i++) {
900 - var p = this.currentPath_[i];
901 - var c;
902 -
903 - switch (p.type) {
904 - case 'moveTo':
905 - c = p;
906 - lineStr.push(' m ', mr(p.x), ',', mr(p.y));
907 - break;
908 - case 'lineTo':
909 - lineStr.push(' l ', mr(p.x), ',', mr(p.y));
910 - break;
911 - case 'close':
912 - lineStr.push(' x ');
913 - p = null;
914 - break;
915 - case 'bezierCurveTo':
916 - lineStr.push(' c ',
917 - mr(p.cp1x), ',', mr(p.cp1y), ',',
918 - mr(p.cp2x), ',', mr(p.cp2y), ',',
919 - mr(p.x), ',', mr(p.y));
920 - break;
921 - case 'at':
922 - case 'wa':
923 - lineStr.push(' ', p.type, ' ',
924 - mr(p.x - this.arcScaleX_ * p.radius), ',',
925 - mr(p.y - this.arcScaleY_ * p.radius), ' ',
926 - mr(p.x + this.arcScaleX_ * p.radius), ',',
927 - mr(p.y + this.arcScaleY_ * p.radius), ' ',
928 - mr(p.xStart), ',', mr(p.yStart), ' ',
929 - mr(p.xEnd), ',', mr(p.yEnd));
930 - break;
931 - }
932 -
933 -
934 - // TODO: Following is broken for curves due to
935 - // move to proper paths.
936 -
937 - // Figure out dimensions so we can do gradient fills
938 - // properly
939 - if (p) {
940 - if (min.x == null || p.x < min.x) {
941 - min.x = p.x;
942 - }
943 - if (max.x == null || p.x > max.x) {
944 - max.x = p.x;
945 - }
946 - if (min.y == null || p.y < min.y) {
947 - min.y = p.y;
948 - }
949 - if (max.y == null || p.y > max.y) {
950 - max.y = p.y;
951 - }
952 - }
953 - }
954 - lineStr.push(' ">');
955 -
956 - if (!aFill) {
957 - appendStroke(this, lineStr);
958 - } else {
959 - appendFill(this, lineStr, min, max);
960 - }
961 -
962 - lineStr.push('</g_vml_:shape>');
963 -
964 - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
965 - };
966 -
967 - function appendStroke(ctx, lineStr) {
968 - var a = processStyle(ctx.strokeStyle);
969 - var color = a.color;
970 - var opacity = a.alpha * ctx.globalAlpha;
971 - var lineWidth = ctx.lineScale_ * ctx.lineWidth;
972 -
973 - // VML cannot correctly render a line if the width is less than 1px.
974 - // In that case, we dilute the color to make the line look thinner.
975 - if (lineWidth < 1) {
976 - opacity *= lineWidth;
977 - }
978 -
979 - lineStr.push(
980 - '<g_vml_:stroke',
981 - ' opacity="', opacity, '"',
982 - ' joinstyle="', ctx.lineJoin, '"',
983 - ' miterlimit="', ctx.miterLimit, '"',
984 - ' endcap="', processLineCap(ctx.lineCap), '"',
985 - ' weight="', lineWidth, 'px"',
986 - ' color="', color, '" />'
987 - );
988 - }
989 -
990 - function appendFill(ctx, lineStr, min, max) {
991 - var fillStyle = ctx.fillStyle;
992 - var arcScaleX = ctx.arcScaleX_;
993 - var arcScaleY = ctx.arcScaleY_;
994 - var width = max.x - min.x;
995 - var height = max.y - min.y;
996 - if (fillStyle instanceof CanvasGradient_) {
997 - // TODO: Gradients transformed with the transformation matrix.
998 - var angle = 0;
999 - var focus = {x: 0, y: 0};
1000 -
1001 - // additional offset
1002 - var shift = 0;
1003 - // scale factor for offset
1004 - var expansion = 1;
1005 -
1006 - if (fillStyle.type_ == 'gradient') {
1007 - var x0 = fillStyle.x0_ / arcScaleX;
1008 - var y0 = fillStyle.y0_ / arcScaleY;
1009 - var x1 = fillStyle.x1_ / arcScaleX;
1010 - var y1 = fillStyle.y1_ / arcScaleY;
1011 - var p0 = getCoords(ctx, x0, y0);
1012 - var p1 = getCoords(ctx, x1, y1);
1013 - var dx = p1.x - p0.x;
1014 - var dy = p1.y - p0.y;
1015 - angle = Math.atan2(dx, dy) * 180 / Math.PI;
1016 -
1017 - // The angle should be a non-negative number.
1018 - if (angle < 0) {
1019 - angle += 360;
1020 - }
1021 -
1022 - // Very small angles produce an unexpected result because they are
1023 - // converted to a scientific notation string.
1024 - if (angle < 1e-6) {
1025 - angle = 0;
1026 - }
1027 - } else {
1028 - var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
1029 - focus = {
1030 - x: (p0.x - min.x) / width,
1031 - y: (p0.y - min.y) / height
1032 - };
1033 -
1034 - width /= arcScaleX * Z;
1035 - height /= arcScaleY * Z;
1036 - var dimension = m.max(width, height);
1037 - shift = 2 * fillStyle.r0_ / dimension;
1038 - expansion = 2 * fillStyle.r1_ / dimension - shift;
1039 - }
1040 -
1041 - // We need to sort the color stops in ascending order by offset,
1042 - // otherwise IE won't interpret it correctly.
1043 - var stops = fillStyle.colors_;
1044 - stops.sort(function(cs1, cs2) {
1045 - return cs1.offset - cs2.offset;
1046 - });
1047 -
1048 - var length = stops.length;
1049 - var color1 = stops[0].color;
1050 - var color2 = stops[length - 1].color;
1051 - var opacity1 = stops[0].alpha * ctx.globalAlpha;
1052 - var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
1053 -
1054 - var colors = [];
1055 - for (var i = 0; i < length; i++) {
1056 - var stop = stops[i];
1057 - colors.push(stop.offset * expansion + shift + ' ' + stop.color);
1058 - }
1059 -
1060 - // When colors attribute is used, the meanings of opacity and o:opacity2
1061 - // are reversed.
1062 - lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
1063 - ' method="none" focus="100%"',
1064 - ' color="', color1, '"',
1065 - ' color2="', color2, '"',
1066 - ' colors="', colors.join(','), '"',
1067 - ' opacity="', opacity2, '"',
1068 - ' g_o_:opacity2="', opacity1, '"',
1069 - ' angle="', angle, '"',
1070 - ' focusposition="', focus.x, ',', focus.y, '" />');
1071 - } else if (fillStyle instanceof CanvasPattern_) {
1072 - if (width && height) {
1073 - var deltaLeft = -min.x;
1074 - var deltaTop = -min.y;
1075 - lineStr.push('<g_vml_:fill',
1076 - ' position="',
1077 - deltaLeft / width * arcScaleX * arcScaleX, ',',
1078 - deltaTop / height * arcScaleY * arcScaleY, '"',
1079 - ' type="tile"',
1080 - // TODO: Figure out the correct size to fit the scale.
1081 - //' size="', w, 'px ', h, 'px"',
1082 - ' src="', fillStyle.src_, '" />');
1083 - }
1084 - } else {
1085 - var a = processStyle(ctx.fillStyle);
1086 - var color = a.color;
1087 - var opacity = a.alpha * ctx.globalAlpha;
1088 - lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
1089 - '" />');
1090 - }
1091 - }
1092 -
1093 - contextPrototype.fill = function() {
1094 - this.stroke(true);
1095 - };
1096 -
1097 - contextPrototype.closePath = function() {
1098 - this.currentPath_.push({type: 'close'});
1099 - };
1100 -
1101 - function getCoords(ctx, aX, aY) {
1102 - var m = ctx.m_;
1103 - return {
1104 - x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
1105 - y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
1106 - };
1107 - };
1108 -
1109 - contextPrototype.save = function() {
1110 - var o = {};
1111 - copyState(this, o);
1112 - this.aStack_.push(o);
1113 - this.mStack_.push(this.m_);
1114 - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
1115 - };
1116 -
1117 - contextPrototype.restore = function() {
1118 - if (this.aStack_.length) {
1119 - copyState(this.aStack_.pop(), this);
1120 - this.m_ = this.mStack_.pop();
1121 - }
1122 - };
1123 -
1124 - function matrixIsFinite(m) {
1125 - return isFinite(m[0][0]) && isFinite(m[0][1]) &&
1126 - isFinite(m[1][0]) && isFinite(m[1][1]) &&
1127 - isFinite(m[2][0]) && isFinite(m[2][1]);
1128 - }
1129 -
1130 - function setM(ctx, m, updateLineScale) {
1131 - if (!matrixIsFinite(m)) {
1132 - return;
1133 - }
1134 - ctx.m_ = m;
1135 -
1136 - if (updateLineScale) {
1137 - // Get the line scale.
1138 - // Determinant of this.m_ means how much the area is enlarged by the
1139 - // transformation. So its square root can be used as a scale factor
1140 - // for width.
1141 - var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
1142 - ctx.lineScale_ = sqrt(abs(det));
1143 - }
1144 - }
1145 -
1146 - contextPrototype.translate = function(aX, aY) {
1147 - var m1 = [
1148 - [1, 0, 0],
1149 - [0, 1, 0],
1150 - [aX, aY, 1]
1151 - ];
1152 -
1153 - setM(this, matrixMultiply(m1, this.m_), false);
1154 - };
1155 -
1156 - contextPrototype.rotate = function(aRot) {
1157 - var c = mc(aRot);
1158 - var s = ms(aRot);
1159 -
1160 - var m1 = [
1161 - [c, s, 0],
1162 - [-s, c, 0],
1163 - [0, 0, 1]
1164 - ];
1165 -
1166 - setM(this, matrixMultiply(m1, this.m_), false);
1167 - };
1168 -
1169 - contextPrototype.scale = function(aX, aY) {
1170 - this.arcScaleX_ *= aX;
1171 - this.arcScaleY_ *= aY;
1172 - var m1 = [
1173 - [aX, 0, 0],
1174 - [0, aY, 0],
1175 - [0, 0, 1]
1176 - ];
1177 -
1178 - setM(this, matrixMultiply(m1, this.m_), true);
1179 - };
1180 -
1181 - contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
1182 - var m1 = [
1183 - [m11, m12, 0],
1184 - [m21, m22, 0],
1185 - [dx, dy, 1]
1186 - ];
1187 -
1188 - setM(this, matrixMultiply(m1, this.m_), true);
1189 - };
1190 -
1191 - contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
1192 - var m = [
1193 - [m11, m12, 0],
1194 - [m21, m22, 0],
1195 - [dx, dy, 1]
1196 - ];
1197 -
1198 - setM(this, m, true);
1199 - };
1200 -
1201 - /**
1202 - * The text drawing function.
1203 - * The maxWidth argument isn't taken in account, since no browser supports
1204 - * it yet.
1205 - */
1206 - contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
1207 - var m = this.m_,
1208 - delta = 1000,
1209 - left = 0,
1210 - right = delta,
1211 - offset = {x: 0, y: 0},
1212 - lineStr = [];
1213 -
1214 - var fontStyle = getComputedStyle(processFontStyle(this.font),
1215 - this.element_);
1216 -
1217 - var fontStyleString = buildStyle(fontStyle);
1218 -
1219 - var elementStyle = this.element_.currentStyle;
1220 - var textAlign = this.textAlign.toLowerCase();
1221 - switch (textAlign) {
1222 - case 'left':
1223 - case 'center':
1224 - case 'right':
1225 - break;
1226 - case 'end':
1227 - textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
1228 - break;
1229 - case 'start':
1230 - textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
1231 - break;
1232 - default:
1233 - textAlign = 'left';
1234 - }
1235 -
1236 - // 1.75 is an arbitrary number, as there is no info about the text baseline
1237 - switch (this.textBaseline) {
1238 - case 'hanging':
1239 - case 'top':
1240 - offset.y = fontStyle.size / 1.75;
1241 - break;
1242 - case 'middle':
1243 - break;
1244 - default:
1245 - case null:
1246 - case 'alphabetic':
1247 - case 'ideographic':
1248 - case 'bottom':
1249 - offset.y = -fontStyle.size / 2.25;
1250 - break;
1251 - }
1252 -
1253 - switch(textAlign) {
1254 - case 'right':
1255 - left = delta;
1256 - right = 0.05;
1257 - break;
1258 - case 'center':
1259 - left = right = delta / 2;
1260 - break;
1261 - }
1262 -
1263 - var d = getCoords(this, x + offset.x, y + offset.y);
1264 -
1265 - lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
1266 - ' coordsize="100 100" coordorigin="0 0"',
1267 - ' filled="', !stroke, '" stroked="', !!stroke,
1268 - '" style="position:absolute;width:1px;height:1px;">');
1269 -
1270 - if (stroke) {
1271 - appendStroke(this, lineStr);
1272 - } else {
1273 - // TODO: Fix the min and max params.
1274 - appendFill(this, lineStr, {x: -left, y: 0},
1275 - {x: right, y: fontStyle.size});
1276 - }
1277 -
1278 - var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
1279 - m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
1280 -
1281 - var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
1282 -
1283 - lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
1284 - ' offset="', skewOffset, '" origin="', left ,' 0" />',
1285 - '<g_vml_:path textpathok="true" />',
1286 - '<g_vml_:textpath on="true" string="',
1287 - encodeHtmlAttribute(text),
1288 - '" style="v-text-align:', textAlign,
1289 - ';font:', encodeHtmlAttribute(fontStyleString),
1290 - '" /></g_vml_:line>');
1291 -
1292 - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
1293 - };
1294 -
1295 - contextPrototype.fillText = function(text, x, y, maxWidth) {
1296 - this.drawText_(text, x, y, maxWidth, false);
1297 - };
1298 -
1299 - contextPrototype.strokeText = function(text, x, y, maxWidth) {
1300 - this.drawText_(text, x, y, maxWidth, true);
1301 - };
1302 -
1303 - contextPrototype.measureText = function(text) {
1304 - if (!this.textMeasureEl_) {
1305 - var s = '<span style="position:absolute;' +
1306 - 'top:-20000px;left:0;padding:0;margin:0;border:none;' +
1307 - 'white-space:pre;"></span>';
1308 - this.element_.insertAdjacentHTML('beforeEnd', s);
1309 - this.textMeasureEl_ = this.element_.lastChild;
1310 - }
1311 - var doc = this.element_.ownerDocument;
1312 - this.textMeasureEl_.innerHTML = '';
1313 - this.textMeasureEl_.style.font = this.font;
1314 - // Don't use innerHTML or innerText because they allow markup/whitespace.
1315 - this.textMeasureEl_.appendChild(doc.createTextNode(text));
1316 - return {width: this.textMeasureEl_.offsetWidth};
1317 - };
1318 -
1319 - /******** STUBS ********/
1320 - contextPrototype.clip = function() {
1321 - // TODO: Implement
1322 - };
1323 -
1324 - contextPrototype.arcTo = function() {
1325 - // TODO: Implement
1326 - };
1327 -
1328 - contextPrototype.createPattern = function(image, repetition) {
1329 - return new CanvasPattern_(image, repetition);
1330 - };
1331 -
1332 - // Gradient / Pattern Stubs
1333 - function CanvasGradient_(aType) {
1334 - this.type_ = aType;
1335 - this.x0_ = 0;
1336 - this.y0_ = 0;
1337 - this.r0_ = 0;
1338 - this.x1_ = 0;
1339 - this.y1_ = 0;
1340 - this.r1_ = 0;
1341 - this.colors_ = [];
1342 - }
1343 -
1344 - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
1345 - aColor = processStyle(aColor);
1346 - this.colors_.push({offset: aOffset,
1347 - color: aColor.color,
1348 - alpha: aColor.alpha});
1349 - };
1350 -
1351 - function CanvasPattern_(image, repetition) {
1352 - assertImageIsValid(image);
1353 - switch (repetition) {
1354 - case 'repeat':
1355 - case null:
1356 - case '':
1357 - this.repetition_ = 'repeat';
1358 - break
1359 - case 'repeat-x':
1360 - case 'repeat-y':
1361 - case 'no-repeat':
1362 - this.repetition_ = repetition;
1363 - break;
1364 - default:
1365 - throwException('SYNTAX_ERR');
1366 - }
1367 -
1368 - this.src_ = image.src;
1369 - this.width_ = image.width;
1370 - this.height_ = image.height;
1371 - }
1372 -
1373 - function throwException(s) {
1374 - throw new DOMException_(s);
1375 - }
1376 -
1377 - function assertImageIsValid(img) {
1378 - if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
1379 - throwException('TYPE_MISMATCH_ERR');
1380 - }
1381 - if (img.readyState != 'complete') {
1382 - throwException('INVALID_STATE_ERR');
1383 - }
1384 - }
1385 -
1386 - function DOMException_(s) {
1387 - this.code = this[s];
1388 - this.message = s +': DOM Exception ' + this.code;
1389 - }
1390 - var p = DOMException_.prototype = new Error;
1391 - p.INDEX_SIZE_ERR = 1;
1392 - p.DOMSTRING_SIZE_ERR = 2;
1393 - p.HIERARCHY_REQUEST_ERR = 3;
1394 - p.WRONG_DOCUMENT_ERR = 4;
1395 - p.INVALID_CHARACTER_ERR = 5;
1396 - p.NO_DATA_ALLOWED_ERR = 6;
1397 - p.NO_MODIFICATION_ALLOWED_ERR = 7;
1398 - p.NOT_FOUND_ERR = 8;
1399 - p.NOT_SUPPORTED_ERR = 9;
1400 - p.INUSE_ATTRIBUTE_ERR = 10;
1401 - p.INVALID_STATE_ERR = 11;
1402 - p.SYNTAX_ERR = 12;
1403 - p.INVALID_MODIFICATION_ERR = 13;
1404 - p.NAMESPACE_ERR = 14;
1405 - p.INVALID_ACCESS_ERR = 15;
1406 - p.VALIDATION_ERR = 16;
1407 - p.TYPE_MISMATCH_ERR = 17;
1408 -
1409 - // set up externs
1410 - G_vmlCanvasManager = G_vmlCanvasManager_;
1411 - CanvasRenderingContext2D = CanvasRenderingContext2D_;
1412 - CanvasGradient = CanvasGradient_;
1413 - CanvasPattern = CanvasPattern_;
1414 - DOMException = DOMException_;
1415 -})();
1416 -
1417 -} // if
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.canvasAxisTickRenderer.js
@@ -1,226 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 - /**
21 - * Class: $.jqplot.CanvasAxisTickRenderer
22 - * Renderer to draw axis ticks with a canvas element to support advanced
23 - * featrues such as rotated text. This renderer uses a separate rendering engine
24 - * to draw the text on the canvas. Two modes of rendering the text are available.
25 - * If the browser has native font support for canvas fonts (currently Mozila 3.5
26 - * and Safari 4), you can enable text rendering with the canvas fillText method.
27 - * You do so by setting the "enableFontSupport" option to true.
28 - *
29 - * Browsers lacking native font support will have the text drawn on the canvas
30 - * using the Hershey font metrics. Even if the "enableFontSupport" option is true
31 - * non-supporting browsers will still render with the Hershey font.
32 - */
33 - $.jqplot.CanvasAxisTickRenderer = function(options) {
34 - // Group: Properties
35 -
36 - // prop: mark
37 - // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
38 - this.mark = 'outside';
39 - // prop: showMark
40 - // wether or not to show the mark on the axis.
41 - this.showMark = true;
42 - // prop: showGridline
43 - // wether or not to draw the gridline on the grid at this tick.
44 - this.showGridline = true;
45 - // prop: isMinorTick
46 - // if this is a minor tick.
47 - this.isMinorTick = false;
48 - // prop: angle
49 - // angle of text, measured clockwise from x axis.
50 - this.angle = 0;
51 - // prop: markSize
52 - // Length of the tick marks in pixels. For 'cross' style, length
53 - // will be stoked above and below axis, so total length will be twice this.
54 - this.markSize = 4;
55 - // prop: show
56 - // wether or not to show the tick (mark and label).
57 - this.show = true;
58 - // prop: showLabel
59 - // wether or not to show the label.
60 - this.showLabel = true;
61 - // prop: labelPosition
62 - // 'auto', 'start', 'middle' or 'end'.
63 - // Whether tick label should be positioned so the start, middle, or end
64 - // of the tick mark.
65 - this.labelPosition = 'auto';
66 - this.label = '';
67 - this.value = null;
68 - this._styles = {};
69 - // prop: formatter
70 - // A class of a formatter for the tick text.
71 - // The default $.jqplot.DefaultTickFormatter uses sprintf.
72 - this.formatter = $.jqplot.DefaultTickFormatter;
73 - // prop: formatString
74 - // string passed to the formatter.
75 - this.formatString = '';
76 - // prop: prefix
77 - // string appended to the tick label if no formatString is specified.
78 - this.prefix = '';
79 - // prop: fontFamily
80 - // css spec for the font-family css attribute.
81 - this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
82 - // prop: fontSize
83 - // CSS spec for font size.
84 - this.fontSize = '10pt';
85 - // prop: fontWeight
86 - // CSS spec for fontWeight
87 - this.fontWeight = 'normal';
88 - // prop: fontStretch
89 - // Multiplier to condense or expand font width.
90 - // Applies only to browsers which don't support canvas native font rendering.
91 - this.fontStretch = 1.0;
92 - // prop: textColor
93 - // css spec for the color attribute.
94 - this.textColor = '#666666';
95 - // prop: enableFontSupport
96 - // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
97 - // If true, tick label will be drawn with canvas tag native support for fonts.
98 - // If false, tick label will be drawn with Hershey font metrics.
99 - this.enableFontSupport = true;
100 - // prop: pt2px
101 - // Point to pixel scaling factor, used for computing height of bounding box
102 - // around a label. The labels text renderer has a default setting of 1.4, which
103 - // should be suitable for most fonts. Leave as null to use default. If tops of
104 - // letters appear clipped, increase this. If bounding box seems too big, decrease.
105 - // This is an issue only with the native font renderering capabilities of Mozilla
106 - // 3.5 and Safari 4 since they do not provide a method to determine the font height.
107 - this.pt2px = null;
108 -
109 - this._elem;
110 - this._ctx;
111 - this._plotWidth;
112 - this._plotHeight;
113 - this._plotDimensions = {height:null, width:null};
114 -
115 - $.extend(true, this, options);
116 -
117 - var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
118 - if (this.pt2px) {
119 - ropts.pt2px = this.pt2px;
120 - }
121 -
122 - if (this.enableFontSupport) {
123 -
124 - function support_canvas_text() {
125 - return !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function');
126 - }
127 -
128 - if (support_canvas_text()) {
129 - this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
130 - }
131 -
132 - else {
133 - this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
134 - }
135 - }
136 - else {
137 - this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
138 - }
139 - };
140 -
141 - $.jqplot.CanvasAxisTickRenderer.prototype.init = function(options) {
142 - $.extend(true, this, options);
143 - this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
144 - };
145 -
146 - // return width along the x axis
147 - // will check first to see if an element exists.
148 - // if not, will return the computed text box width.
149 - $.jqplot.CanvasAxisTickRenderer.prototype.getWidth = function(ctx) {
150 - if (this._elem) {
151 - return this._elem.outerWidth(true);
152 - }
153 - else {
154 - var tr = this._textRenderer;
155 - var l = tr.getWidth(ctx);
156 - var h = tr.getHeight(ctx);
157 - var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
158 - return w;
159 - }
160 - };
161 -
162 - // return height along the y axis.
163 - $.jqplot.CanvasAxisTickRenderer.prototype.getHeight = function(ctx) {
164 - if (this._elem) {
165 - return this._elem.outerHeight(true);
166 - }
167 - else {
168 - var tr = this._textRenderer;
169 - var l = tr.getWidth(ctx);
170 - var h = tr.getHeight(ctx);
171 - var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
172 - return w;
173 - }
174 - };
175 -
176 - $.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad = function() {
177 - var a = this.angle * Math.PI/180;
178 - return a;
179 - };
180 -
181 -
182 - $.jqplot.CanvasAxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
183 - this.value = value;
184 - if (isMinor) {
185 - this.isMinorTick = true;
186 - }
187 - return this;
188 - };
189 -
190 - $.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx) {
191 - if (!this.label) {
192 - this.label = this.formatter(this.formatString, this.value);
193 - }
194 - // add prefix if needed
195 - if (this.prefix && !this.formatString) {
196 - this.label = this.prefix + this.label;
197 - }
198 - // create a canvas here, but can't draw on it untill it is appended
199 - // to dom for IE compatability.
200 - var domelem = document.createElement('canvas');
201 - this._textRenderer.setText(this.label, ctx);
202 - var w = this.getWidth(ctx);
203 - var h = this.getHeight(ctx);
204 - domelem.width = w;
205 - domelem.height = h;
206 - domelem.style.width = w;
207 - domelem.style.height = h;
208 - domelem.style.textAlign = 'left';
209 - domelem.style.position = 'absolute';
210 - this._domelem = domelem;
211 - this._elem = $(domelem);
212 - this._elem.css(this._styles);
213 - this._elem.addClass('jqplot-'+this.axis+'-tick');
214 -
215 - return this._elem;
216 - };
217 -
218 - $.jqplot.CanvasAxisTickRenderer.prototype.pack = function() {
219 - if ($.jqplot.use_excanvas) {
220 - window.G_vmlCanvasManager.init_(document);
221 - this._domelem = window.G_vmlCanvasManager.initElement(this._domelem);
222 - }
223 - var ctx = this._elem.get(0).getContext("2d");
224 - this._textRenderer.draw(ctx, this.label);
225 - };
226 -
227 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.pieRenderer.js
@@ -1,766 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 - /**
21 - * Class: $.jqplot.PieRenderer
22 - * Plugin renderer to draw a pie chart.
23 - * x values, if present, will be used as slice labels.
24 - * y values give slice size.
25 - *
26 - * To use this renderer, you need to include the
27 - * pie renderer plugin, for example:
28 - *
29 - * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
30 - *
31 - * Properties described here are passed into the $.jqplot function
32 - * as options on the series renderer. For example:
33 - *
34 - * > plot2 = $.jqplot('chart2', [s1, s2], {
35 - * > seriesDefaults: {
36 - * > renderer:$.jqplot.PieRenderer,
37 - * > rendererOptions:{
38 - * > sliceMargin: 2,
39 - * > startAngle: -90
40 - * > }
41 - * > }
42 - * > });
43 - *
44 - * A pie plot will trigger events on the plot target
45 - * according to user interaction. All events return the event object,
46 - * the series index, the point (slice) index, and the point data for
47 - * the appropriate slice.
48 - *
49 - * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
50 - * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
51 - * if highlighting is enabled.
52 - * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
53 - * a highlighted slice.
54 - * 'jqplotDataClick' - triggered when the user clicks on a slice.
55 - * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
56 - * the "captureRightClick" option is set to true on the plot.
57 - */
58 - $.jqplot.PieRenderer = function(){
59 - $.jqplot.LineRenderer.call(this);
60 - };
61 -
62 - $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
63 - $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
64 -
65 - // called with scope of a series
66 - $.jqplot.PieRenderer.prototype.init = function(options, plot) {
67 - // Group: Properties
68 - //
69 - // prop: diameter
70 - // Outer diameter of the pie, auto computed by default
71 - this.diameter = null;
72 - // prop: padding
73 - // padding between the pie and plot edges, legend, etc.
74 - this.padding = 20;
75 - // prop: sliceMargin
76 - // angular spacing between pie slices in degrees.
77 - this.sliceMargin = 0;
78 - // prop: fill
79 - // true or false, wether to fil the slices.
80 - this.fill = true;
81 - // prop: shadowOffset
82 - // offset of the shadow from the slice and offset of
83 - // each succesive stroke of the shadow from the last.
84 - this.shadowOffset = 2;
85 - // prop: shadowAlpha
86 - // transparency of the shadow (0 = transparent, 1 = opaque)
87 - this.shadowAlpha = 0.07;
88 - // prop: shadowDepth
89 - // number of strokes to apply to the shadow,
90 - // each stroke offset shadowOffset from the last.
91 - this.shadowDepth = 5;
92 - // prop: highlightMouseOver
93 - // True to highlight slice when moused over.
94 - // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
95 - this.highlightMouseOver = true;
96 - // prop: highlightMouseDown
97 - // True to highlight when a mouse button is pressed over a slice.
98 - // This will be disabled if highlightMouseOver is true.
99 - this.highlightMouseDown = false;
100 - // prop: highlightColors
101 - // an array of colors to use when highlighting a slice.
102 - this.highlightColors = [];
103 - // prop: dataLabels
104 - // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
105 - // Defaults to percentage of each pie slice.
106 - this.dataLabels = 'percent';
107 - // prop: showDataLabels
108 - // true to show data labels on slices.
109 - this.showDataLabels = false;
110 - // prop: dataLabelFormatString
111 - // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
112 - this.dataLabelFormatString = null;
113 - // prop: dataLabelThreshold
114 - // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
115 - // This applies to all label types, not just to percentage labels.
116 - this.dataLabelThreshold = 3;
117 - // prop: dataLabelPositionFactor
118 - // A Multiplier (0-1) of the pie radius which controls position of label on slice.
119 - // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
120 - this.dataLabelPositionFactor = 0.52;
121 - // prop: dataLabelNudge
122 - // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
123 - this.dataLabelNudge = 2;
124 - // prop: dataLabelCenterOn
125 - // True to center the data label at its position.
126 - // False to set the inside facing edge of the label at its position.
127 - this.dataLabelCenterOn = true;
128 - // prop: startAngle
129 - // Angle to start drawing pie in degrees.
130 - // According to orientation of canvas coordinate system:
131 - // 0 = on the positive x axis
132 - // -90 = on the positive y axis.
133 - // 90 = on the negaive y axis.
134 - // 180 or - 180 = on the negative x axis.
135 - this.startAngle = 0;
136 - this.tickRenderer = $.jqplot.PieTickRenderer;
137 - // Used as check for conditions where pie shouldn't be drawn.
138 - this._drawData = true;
139 -
140 - // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
141 - if (options.highlightMouseDown && options.highlightMouseOver == null) {
142 - options.highlightMouseOver = false;
143 - }
144 -
145 - $.extend(true, this, options);
146 - if (this.diameter != null) {
147 - this.diameter = this.diameter - this.sliceMargin;
148 - }
149 - this._diameter = null;
150 - this._radius = null;
151 - // array of [start,end] angles arrays, one for each slice. In radians.
152 - this._sliceAngles = [];
153 - // index of the currenty highlighted point, if any
154 - this._highlightedPoint = null;
155 -
156 - // set highlight colors if none provided
157 - if (this.highlightColors.length == 0) {
158 - for (var i=0; i<this.seriesColors.length; i++){
159 - var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
160 - var newrgb = [rgba[0], rgba[1], rgba[2]];
161 - var sum = newrgb[0] + newrgb[1] + newrgb[2];
162 - for (var j=0; j<3; j++) {
163 - // when darkening, lowest color component can be is 60.
164 - newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
165 - newrgb[j] = parseInt(newrgb[j], 10);
166 - }
167 - this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
168 - }
169 - }
170 -
171 - this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
172 -
173 - plot.postParseOptionsHooks.addOnce(postParseOptions);
174 - plot.postInitHooks.addOnce(postInit);
175 - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
176 - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
177 - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
178 - plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
179 - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
180 - plot.postDrawHooks.addOnce(postPlotDraw);
181 - };
182 -
183 - $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
184 - // set gridData property. This will hold angle in radians of each data point.
185 - var stack = [];
186 - var td = [];
187 - var sa = this.startAngle/180*Math.PI;
188 - var tot = 0;
189 - // don't know if we have any valid data yet, so set plot to not draw.
190 - this._drawData = false;
191 - for (var i=0; i<this.data.length; i++){
192 - if (this.data[i][1] != 0) {
193 - // we have data, O.K. to draw.
194 - this._drawData = true;
195 - }
196 - stack.push(this.data[i][1]);
197 - td.push([this.data[i][0]]);
198 - if (i>0) {
199 - stack[i] += stack[i-1];
200 - }
201 - tot += this.data[i][1];
202 - }
203 - var fact = Math.PI*2/stack[stack.length - 1];
204 -
205 - for (var i=0; i<stack.length; i++) {
206 - td[i][1] = stack[i] * fact;
207 - td[i][2] = this.data[i][1]/tot;
208 - }
209 - this.gridData = td;
210 - };
211 -
212 - $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
213 - var stack = [];
214 - var td = [];
215 - var tot = 0;
216 - var sa = this.startAngle/180*Math.PI;
217 - // don't know if we have any valid data yet, so set plot to not draw.
218 - this._drawData = false;
219 - for (var i=0; i<data.length; i++){
220 - if (this.data[i][1] != 0) {
221 - // we have data, O.K. to draw.
222 - this._drawData = true;
223 - }
224 - stack.push(data[i][1]);
225 - td.push([data[i][0]]);
226 - if (i>0) {
227 - stack[i] += stack[i-1];
228 - }
229 - tot += data[i][1];
230 - }
231 - var fact = Math.PI*2/stack[stack.length - 1];
232 -
233 - for (var i=0; i<stack.length; i++) {
234 - td[i][1] = stack[i] * fact;
235 - td[i][2] = data[i][1]/tot;
236 - }
237 - return td;
238 - };
239 -
240 - $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
241 - if (this._drawData) {
242 - var r = this._diameter / 2;
243 - var fill = this.fill;
244 - var lineWidth = this.lineWidth;
245 - ctx.save();
246 - ctx.translate(this._center[0], this._center[1]);
247 - ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2));
248 -
249 - if (isShadow) {
250 - for (var i=0; i<this.shadowDepth; i++) {
251 - ctx.save();
252 - ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
253 - doDraw();
254 - }
255 - }
256 -
257 - else {
258 - doDraw();
259 - }
260 - }
261 -
262 - function doDraw () {
263 - // Fix for IE and Chrome that can't seem to draw circles correctly.
264 - // ang2 should always be <= 2 pi since that is the way the data is converted.
265 - if (ang2 > 6.282 + this.startAngle) {
266 - ang2 = 6.282 + this.startAngle;
267 - if (ang1 > ang2) {
268 - ang1 = 6.281 + this.startAngle;
269 - }
270 - }
271 - // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
272 - // ugly line on unfilled pies.
273 - if (ang1 >= ang2) {
274 - return;
275 - }
276 -
277 - ctx.beginPath();
278 - ctx.fillStyle = color;
279 - ctx.strokeStyle = color;
280 - ctx.lineWidth = lineWidth;
281 - ctx.arc(0, 0, r, ang1, ang2, false);
282 - ctx.lineTo(0,0);
283 - ctx.closePath();
284 -
285 - if (fill) {
286 - ctx.fill();
287 - }
288 - else {
289 - ctx.stroke();
290 - }
291 - }
292 -
293 - if (isShadow) {
294 - for (var i=0; i<this.shadowDepth; i++) {
295 - ctx.restore();
296 - }
297 - }
298 -
299 - ctx.restore();
300 - };
301 -
302 - // called with scope of series
303 - $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
304 - var i;
305 - var opts = (options != undefined) ? options : {};
306 - // offset and direction of offset due to legend placement
307 - var offx = 0;
308 - var offy = 0;
309 - var trans = 1;
310 - var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
311 - if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
312 - var li = options.legendInfo;
313 - switch (li.location) {
314 - case 'nw':
315 - offx = li.width + li.xoffset;
316 - break;
317 - case 'w':
318 - offx = li.width + li.xoffset;
319 - break;
320 - case 'sw':
321 - offx = li.width + li.xoffset;
322 - break;
323 - case 'ne':
324 - offx = li.width + li.xoffset;
325 - trans = -1;
326 - break;
327 - case 'e':
328 - offx = li.width + li.xoffset;
329 - trans = -1;
330 - break;
331 - case 'se':
332 - offx = li.width + li.xoffset;
333 - trans = -1;
334 - break;
335 - case 'n':
336 - offy = li.height + li.yoffset;
337 - break;
338 - case 's':
339 - offy = li.height + li.yoffset;
340 - trans = -1;
341 - break;
342 - default:
343 - break;
344 - }
345 - }
346 -
347 - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
348 - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
349 - var fill = (opts.fill != undefined) ? opts.fill : this.fill;
350 - var cw = ctx.canvas.width;
351 - var ch = ctx.canvas.height;
352 - var w = cw - offx - 2 * this.padding;
353 - var h = ch - offy - 2 * this.padding;
354 - var mindim = Math.min(w,h);
355 - var d = mindim;
356 - // this._diameter = this.diameter || d;
357 - this._diameter = this.diameter || d - this.sliceMargin;
358 -
359 - var r = this._radius = this._diameter/2;
360 - var sa = this.startAngle / 180 * Math.PI;
361 - this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
362 -
363 - if (this.shadow) {
364 - var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
365 - for (var i=0; i<gd.length; i++) {
366 - var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
367 - // Adjust ang1 and ang2 for sliceMargin
368 - ang1 += this.sliceMargin/180*Math.PI;
369 - this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
370 - }
371 -
372 - }
373 - for (var i=0; i<gd.length; i++) {
374 - var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
375 - // Adjust ang1 and ang2 for sliceMargin
376 - ang1 += this.sliceMargin/180*Math.PI;
377 - var ang2 = gd[i][1] + sa;
378 - this._sliceAngles.push([ang1, ang2]);
379 -
380 - this.renderer.drawSlice.call (this, ctx, ang1, ang2, colorGenerator.next(), false);
381 -
382 - if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
383 - var fstr, avgang = (ang1+ang2)/2, label;
384 -
385 - if (this.dataLabels == 'label') {
386 - fstr = this.dataLabelFormatString || '%s';
387 - label = $.jqplot.sprintf(fstr, gd[i][0]);
388 - }
389 - else if (this.dataLabels == 'value') {
390 - fstr = this.dataLabelFormatString || '%d';
391 - label = $.jqplot.sprintf(fstr, this.data[i][1]);
392 - }
393 - else if (this.dataLabels == 'percent') {
394 - fstr = this.dataLabelFormatString || '%d%%';
395 - label = $.jqplot.sprintf(fstr, gd[i][2]*100);
396 - }
397 - else if (this.dataLabels.constructor == Array) {
398 - fstr = this.dataLabelFormatString || '%s';
399 - label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
400 - }
401 -
402 - var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
403 -
404 - var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
405 - var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
406 -
407 - var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
408 - if (this.dataLabelCenterOn) {
409 - x -= labelelem.width()/2;
410 - y -= labelelem.height()/2;
411 - }
412 - else {
413 - x -= labelelem.width() * Math.sin(avgang/2);
414 - y -= labelelem.height()/2;
415 - }
416 - x = Math.round(x);
417 - y = Math.round(y);
418 - labelelem.css({left: x, top: y});
419 - }
420 - }
421 -
422 - };
423 -
424 - $.jqplot.PieAxisRenderer = function() {
425 - $.jqplot.LinearAxisRenderer.call(this);
426 - };
427 -
428 - $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
429 - $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
430 -
431 -
432 - // There are no traditional axes on a pie chart. We just need to provide
433 - // dummy objects with properties so the plot will render.
434 - // called with scope of axis object.
435 - $.jqplot.PieAxisRenderer.prototype.init = function(options){
436 - //
437 - this.tickRenderer = $.jqplot.PieTickRenderer;
438 - $.extend(true, this, options);
439 - // I don't think I'm going to need _dataBounds here.
440 - // have to go Axis scaling in a way to fit chart onto plot area
441 - // and provide u2p and p2u functionality for mouse cursor, etc.
442 - // for convienence set _dataBounds to 0 and 100 and
443 - // set min/max to 0 and 100.
444 - this._dataBounds = {min:0, max:100};
445 - this.min = 0;
446 - this.max = 100;
447 - this.showTicks = false;
448 - this.ticks = [];
449 - this.showMark = false;
450 - this.show = false;
451 - };
452 -
453 -
454 -
455 -
456 - $.jqplot.PieLegendRenderer = function(){
457 - $.jqplot.TableLegendRenderer.call(this);
458 - };
459 -
460 - $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
461 - $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
462 -
463 - /**
464 - * Class: $.jqplot.PieLegendRenderer
465 - * Legend Renderer specific to pie plots. Set by default
466 - * when user creates a pie plot.
467 - */
468 - $.jqplot.PieLegendRenderer.prototype.init = function(options) {
469 - // Group: Properties
470 - //
471 - // prop: numberRows
472 - // Maximum number of rows in the legend. 0 or null for unlimited.
473 - this.numberRows = null;
474 - // prop: numberColumns
475 - // Maximum number of columns in the legend. 0 or null for unlimited.
476 - this.numberColumns = null;
477 - $.extend(true, this, options);
478 - };
479 -
480 - // called with context of legend
481 - $.jqplot.PieLegendRenderer.prototype.draw = function() {
482 - var legend = this;
483 - if (this.show) {
484 - var series = this._series;
485 - var ss = 'position:absolute;';
486 - ss += (this.background) ? 'background:'+this.background+';' : '';
487 - ss += (this.border) ? 'border:'+this.border+';' : '';
488 - ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
489 - ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
490 - ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
491 - ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
492 - ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
493 - ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
494 - ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
495 - this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
496 - // Pie charts legends don't go by number of series, but by number of data points
497 - // in the series. Refactor things here for that.
498 -
499 - var pad = false,
500 - reverse = false,
501 - nr, nc;
502 - var s = series[0];
503 - var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
504 -
505 - if (s.show) {
506 - var pd = s.data;
507 - if (this.numberRows) {
508 - nr = this.numberRows;
509 - if (!this.numberColumns){
510 - nc = Math.ceil(pd.length/nr);
511 - }
512 - else{
513 - nc = this.numberColumns;
514 - }
515 - }
516 - else if (this.numberColumns) {
517 - nc = this.numberColumns;
518 - nr = Math.ceil(pd.length/this.numberColumns);
519 - }
520 - else {
521 - nr = pd.length;
522 - nc = 1;
523 - }
524 -
525 - var i, j, tr, td1, td2, lt, rs, color;
526 - var idx = 0;
527 -
528 - for (i=0; i<nr; i++) {
529 - if (reverse){
530 - tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
531 - }
532 - else{
533 - tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
534 - }
535 - for (j=0; j<nc; j++) {
536 - if (idx < pd.length){
537 - lt = this.labels[idx] || pd[idx][0].toString();
538 - color = colorGenerator.next();
539 - if (!reverse){
540 - if (i>0){
541 - pad = true;
542 - }
543 - else{
544 - pad = false;
545 - }
546 - }
547 - else{
548 - if (i == nr -1){
549 - pad = false;
550 - }
551 - else{
552 - pad = true;
553 - }
554 - }
555 - rs = (pad) ? this.rowSpacing : '0';
556 -
557 - td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
558 - '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
559 - '</div></td>');
560 - td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
561 - if (this.escapeHtml){
562 - td2.text(lt);
563 - }
564 - else {
565 - td2.html(lt);
566 - }
567 - if (reverse) {
568 - td2.prependTo(tr);
569 - td1.prependTo(tr);
570 - }
571 - else {
572 - td1.appendTo(tr);
573 - td2.appendTo(tr);
574 - }
575 - pad = true;
576 - }
577 - idx++;
578 - }
579 - }
580 - }
581 - }
582 - return this._elem;
583 - };
584 -
585 - $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
586 - if (neighbor) {
587 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
588 - plot.target.trigger('jqplotDataMouseOver', ins);
589 - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
590 - plot.target.trigger('jqplotDataHighlight', ins);
591 - highlight (plot, ins[0], ins[1]);
592 - }
593 - }
594 - else if (neighbor == null) {
595 - unhighlight (plot);
596 - }
597 - };
598 -
599 -
600 - // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
601 -
602 - // setup default renderers for axes and legend so user doesn't have to
603 - // called with scope of plot
604 - function preInit(target, data, options) {
605 - options = options || {};
606 - options.axesDefaults = options.axesDefaults || {};
607 - options.legend = options.legend || {};
608 - options.seriesDefaults = options.seriesDefaults || {};
609 - // only set these if there is a pie series
610 - var setopts = false;
611 - if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
612 - setopts = true;
613 - }
614 - else if (options.series) {
615 - for (var i=0; i < options.series.length; i++) {
616 - if (options.series[i].renderer == $.jqplot.PieRenderer) {
617 - setopts = true;
618 - }
619 - }
620 - }
621 -
622 - if (setopts) {
623 - options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
624 - options.legend.renderer = $.jqplot.PieLegendRenderer;
625 - options.legend.preDraw = true;
626 - options.seriesDefaults.pointLabels = {show: false};
627 - }
628 - }
629 -
630 - function postInit(target, data, options) {
631 - for (i=0; i<this.series.length; i++) {
632 - if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
633 - // don't allow mouseover and mousedown at same time.
634 - if (this.series[i].highlightMouseOver) {
635 - this.series[i].highlightMouseDown = false;
636 - }
637 - }
638 - }
639 - this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
640 - }
641 -
642 - // called with scope of plot
643 - function postParseOptions(options) {
644 - for (var i=0; i<this.series.length; i++) {
645 - this.series[i].seriesColors = this.seriesColors;
646 - this.series[i].colorGenerator = this.colorGenerator;
647 - }
648 - }
649 -
650 - function highlight (plot, sidx, pidx) {
651 - var s = plot.series[sidx];
652 - var canvas = plot.plugins.pieRenderer.highlightCanvas;
653 - canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
654 - s._highlightedPoint = pidx;
655 - plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
656 - s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
657 - }
658 -
659 - function unhighlight (plot) {
660 - var canvas = plot.plugins.pieRenderer.highlightCanvas;
661 - canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
662 - for (var i=0; i<plot.series.length; i++) {
663 - plot.series[i]._highlightedPoint = null;
664 - }
665 - plot.plugins.pieRenderer.highlightedSeriesIndex = null;
666 - plot.target.trigger('jqplotDataUnhighlight');
667 - }
668 -
669 - function handleMove(ev, gridpos, datapos, neighbor, plot) {
670 - if (neighbor) {
671 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
672 - var evt1 = jQuery.Event('jqplotDataMouseOver');
673 - evt1.pageX = ev.pageX;
674 - evt1.pageY = ev.pageY;
675 - plot.target.trigger(evt1, ins);
676 - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
677 - var evt = jQuery.Event('jqplotDataHighlight');
678 - evt.pageX = ev.pageX;
679 - evt.pageY = ev.pageY;
680 - plot.target.trigger(evt, ins);
681 - highlight (plot, ins[0], ins[1]);
682 - }
683 - }
684 - else if (neighbor == null) {
685 - unhighlight (plot);
686 - }
687 - }
688 -
689 - function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
690 - if (neighbor) {
691 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
692 - if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
693 - var evt = jQuery.Event('jqplotDataHighlight');
694 - evt.pageX = ev.pageX;
695 - evt.pageY = ev.pageY;
696 - plot.target.trigger(evt, ins);
697 - highlight (plot, ins[0], ins[1]);
698 - }
699 - }
700 - else if (neighbor == null) {
701 - unhighlight (plot);
702 - }
703 - }
704 -
705 - function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
706 - var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
707 - if (idx != null && plot.series[idx].highlightMouseDown) {
708 - unhighlight(plot);
709 - }
710 - }
711 -
712 - function handleClick(ev, gridpos, datapos, neighbor, plot) {
713 - if (neighbor) {
714 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
715 - var evt = jQuery.Event('jqplotDataClick');
716 - evt.pageX = ev.pageX;
717 - evt.pageY = ev.pageY;
718 - plot.target.trigger(evt, ins);
719 - }
720 - }
721 -
722 - function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
723 - if (neighbor) {
724 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
725 - var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
726 - if (idx != null && plot.series[idx].highlightMouseDown) {
727 - unhighlight(plot);
728 - }
729 - var evt = jQuery.Event('jqplotDataRightClick');
730 - evt.pageX = ev.pageX;
731 - evt.pageY = ev.pageY;
732 - plot.target.trigger(evt, ins);
733 - }
734 - }
735 -
736 - // called within context of plot
737 - // create a canvas which we can draw on.
738 - // insert it before the eventCanvas, so eventCanvas will still capture events.
739 - function postPlotDraw() {
740 - this.plugins.pieRenderer = {highlightedSeriesIndex:null};
741 - this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
742 -
743 - // do we have any data labels? if so, put highlight canvas before those
744 - var labels = $(this.targetId+' .jqplot-data-label');
745 - if (labels.length) {
746 - $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions));
747 - }
748 - // else put highlight canvas before event canvas.
749 - else {
750 - this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions));
751 - }
752 -
753 - var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
754 - }
755 -
756 - $.jqplot.preInitHooks.push(preInit);
757 -
758 - $.jqplot.PieTickRenderer = function() {
759 - $.jqplot.AxisTickRenderer.call(this);
760 - };
761 -
762 - $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
763 - $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
764 -
765 -})(jQuery);
766 -
767 -
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.canvasTextRenderer.js
@@ -1,408 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 - // This code is a modified version of the canvastext.js code, copyright below:
21 - //
22 - // This code is released to the public domain by Jim Studt, 2007.
23 - // He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
24 - //
25 - $.jqplot.CanvasTextRenderer = function(options){
26 - this.fontStyle = 'normal'; // normal, italic, oblique [not implemented]
27 - this.fontVariant = 'normal'; // normal, small caps [not implemented]
28 - this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900
29 - this.fontSize = '10px';
30 - this.fontFamily = 'sans-serif';
31 - this.fontStretch = 1.0;
32 - this.fillStyle = '#666666';
33 - this.angle = 0;
34 - this.textAlign = 'start';
35 - this.textBaseline = 'alphabetic';
36 - this.text;
37 - this.width;
38 - this.height;
39 - this.pt2px = 1.28;
40 -
41 - $.extend(true, this, options);
42 - this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
43 - this.setHeight();
44 - };
45 -
46 - $.jqplot.CanvasTextRenderer.prototype.init = function(options) {
47 - $.extend(true, this, options);
48 - this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
49 - this.setHeight();
50 - };
51 -
52 - // convert css spec into point size
53 - // returns float
54 - $.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) {
55 - sz = String(sz);
56 - n = parseFloat(sz);
57 - if (sz.indexOf('px') > -1) {
58 - return n/this.pt2px;
59 - }
60 - else if (sz.indexOf('pt') > -1) {
61 - return n;
62 - }
63 - else if (sz.indexOf('em') > -1) {
64 - return n*12;
65 - }
66 - else if (sz.indexOf('%') > -1) {
67 - return n*12/100;
68 - }
69 - // default to pixels;
70 - else {
71 - return n/this.pt2px;
72 - }
73 - };
74 -
75 -
76 - $.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) {
77 - // w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
78 - // return values adjusted for Hershey font.
79 - if (Number(w)) {
80 - return w/400;
81 - }
82 - else {
83 - switch (w) {
84 - case 'normal':
85 - return 1;
86 - break;
87 - case 'bold':
88 - return 1.75;
89 - break;
90 - case 'bolder':
91 - return 2.25;
92 - break;
93 - case 'lighter':
94 - return 0.75;
95 - break;
96 - default:
97 - return 1;
98 - break;
99 - }
100 - }
101 - };
102 -
103 - $.jqplot.CanvasTextRenderer.prototype.getText = function() {
104 - return this.text;
105 - };
106 -
107 - $.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) {
108 - this.text = t;
109 - this.setWidth(ctx);
110 - return this;
111 - };
112 -
113 - $.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) {
114 - return this.width;
115 - };
116 -
117 - $.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) {
118 - if (!w) {
119 - this.width = this.measure(ctx, this.text);
120 - }
121 - else {
122 - this.width = w;
123 - }
124 - return this;
125 - };
126 -
127 - // return height in pixels.
128 - $.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) {
129 - return this.height;
130 - };
131 -
132 - // w - height in pt
133 - // set heigh in px
134 - $.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) {
135 - if (!w) {
136 - //height = this.fontSize /0.75;
137 - this.height = this.normalizedFontSize * this.pt2px;
138 - }
139 - else {
140 - this.height = w;
141 - }
142 - return this;
143 - };
144 -
145 - $.jqplot.CanvasTextRenderer.prototype.letter = function (ch)
146 - {
147 - return this.letters[ch];
148 - };
149 -
150 - $.jqplot.CanvasTextRenderer.prototype.ascent = function()
151 - {
152 - return this.normalizedFontSize;
153 - };
154 -
155 - $.jqplot.CanvasTextRenderer.prototype.descent = function()
156 - {
157 - return 7.0*this.normalizedFontSize/25.0;
158 - };
159 -
160 - $.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str)
161 - {
162 - var total = 0;
163 - var len = str.length;
164 -
165 - for ( i = 0; i < len; i++) {
166 - var c = this.letter(str.charAt(i));
167 - if (c) {
168 - total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch;
169 - }
170 - }
171 - return total;
172 - };
173 -
174 - $.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str)
175 - {
176 - var x = 0;
177 - // leave room at bottom for descenders.
178 - var y = this.height*0.72;
179 - var total = 0;
180 - var len = str.length;
181 - var mag = this.normalizedFontSize / 25.0;
182 -
183 - ctx.save();
184 - var tx, ty;
185 -
186 - // 1st quadrant
187 - if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
188 - tx = 0;
189 - ty = -Math.sin(this.angle) * this.width;
190 - }
191 - // 4th quadrant
192 - else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
193 - tx = Math.sin(this.angle) * this.height;
194 - ty = 0;
195 - }
196 - // 2nd quadrant
197 - else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
198 - tx = -Math.cos(this.angle) * this.width;
199 - ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
200 - }
201 - // 3rd quadrant
202 - else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
203 - tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
204 - ty = -Math.cos(this.angle) * this.height;
205 - }
206 -
207 - ctx.strokeStyle = this.fillStyle;
208 - ctx.fillStyle = this.fillStyle;
209 - ctx.translate(tx, ty);
210 - ctx.rotate(this.angle);
211 - ctx.lineCap = "round";
212 - // multiplier was 2.0
213 - var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20;
214 - ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight);
215 -
216 - for ( var i = 0; i < len; i++) {
217 - var c = this.letter( str.charAt(i));
218 - if ( !c) {
219 - continue;
220 - }
221 -
222 - ctx.beginPath();
223 -
224 - var penUp = 1;
225 - var needStroke = 0;
226 - for ( var j = 0; j < c.points.length; j++) {
227 - var a = c.points[j];
228 - if ( a[0] == -1 && a[1] == -1) {
229 - penUp = 1;
230 - continue;
231 - }
232 - if ( penUp) {
233 - ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
234 - penUp = false;
235 - } else {
236 - ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
237 - }
238 - }
239 - ctx.stroke();
240 - x += c.width*mag*this.fontStretch;
241 - }
242 - ctx.restore();
243 - return total;
244 - };
245 -
246 - $.jqplot.CanvasTextRenderer.prototype.letters = {
247 - ' ': { width: 16, points: [] },
248 - '!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
249 - '"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] },
250 - '#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] },
251 - '$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
252 - '%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
253 - '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
254 - '\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
255 - '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
256 - ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
257 - '*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] },
258 - '+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] },
259 - ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
260 - '-': { width: 18, points: [[6,9],[12,9]] },
261 - '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
262 - '/': { width: 22, points: [[20,25],[2,-7]] },
263 - '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
264 - '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
265 - '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
266 - '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
267 - '4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] },
268 - '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
269 - '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
270 - '7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] },
271 - '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
272 - '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
273 - ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
274 - ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
275 - '<': { width: 24, points: [[20,18],[4,9],[20,0]] },
276 - '=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] },
277 - '>': { width: 24, points: [[4,18],[20,9],[4,0]] },
278 - '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] },
279 - '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] },
280 - 'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] },
281 - 'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
282 - 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
283 - 'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
284 - 'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] },
285 - 'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] },
286 - 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] },
287 - 'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] },
288 - 'I': { width: 8, points: [[4,21],[4,0]] },
289 - 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
290 - 'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] },
291 - 'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] },
292 - 'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] },
293 - 'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] },
294 - 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
295 - 'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
296 - 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] },
297 - 'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] },
298 - 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
299 - 'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] },
300 - 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
301 - 'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] },
302 - 'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] },
303 - 'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] },
304 - 'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] },
305 - 'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] },
306 - '[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] },
307 - '\\': { width: 14, points: [[0,21],[14,-3]] },
308 - ']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] },
309 - '^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] },
310 - '_': { width: 16, points: [[0,-2],[16,-2]] },
311 - '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
312 - 'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
313 - 'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
314 - 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
315 - 'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
316 - 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
317 - 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] },
318 - 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
319 - 'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
320 - 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] },
321 - 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
322 - 'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] },
323 - 'l': { width: 8, points: [[4,21],[4,0]] },
324 - 'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
325 - 'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
326 - 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
327 - 'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
328 - 'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
329 - 'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] },
330 - 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
331 - 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] },
332 - 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] },
333 - 'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] },
334 - 'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] },
335 - 'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] },
336 - 'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
337 - 'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] },
338 - '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
339 - '|': { width: 8, points: [[4,25],[4,-7]] },
340 - '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
341 - '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] }
342 - };
343 -
344 - $.jqplot.CanvasFontRenderer = function(options) {
345 - options = options || {};
346 - if (!options.pt2px) {
347 - options.pt2px = 1.5;
348 - }
349 - $.jqplot.CanvasTextRenderer.call(this, options);
350 - };
351 -
352 - $.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({});
353 - $.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer;
354 -
355 - $.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str)
356 - {
357 - // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
358 - var fstyle = this.fontSize+' '+this.fontFamily;
359 - ctx.save();
360 - ctx.font = fstyle;
361 - var w = ctx.measureText(str).width;
362 - ctx.restore();
363 - return w;
364 - };
365 -
366 - $.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str)
367 - {
368 - var x = 0;
369 - // leave room at bottom for descenders.
370 - var y = this.height*0.72;
371 - //var y = 12;
372 -
373 - ctx.save();
374 - var tx, ty;
375 -
376 - // 1st quadrant
377 - if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
378 - tx = 0;
379 - ty = -Math.sin(this.angle) * this.width;
380 - }
381 - // 4th quadrant
382 - else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
383 - tx = Math.sin(this.angle) * this.height;
384 - ty = 0;
385 - }
386 - // 2nd quadrant
387 - else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
388 - tx = -Math.cos(this.angle) * this.width;
389 - ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
390 - }
391 - // 3rd quadrant
392 - else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
393 - tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
394 - ty = -Math.cos(this.angle) * this.height;
395 - }
396 - ctx.strokeStyle = this.fillStyle;
397 - ctx.fillStyle = this.fillStyle;
398 - // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
399 - var fstyle = this.fontSize+' '+this.fontFamily;
400 - ctx.font = fstyle;
401 - ctx.translate(tx, ty);
402 - ctx.rotate(this.angle);
403 - ctx.fillText(str, x, y);
404 - // ctx.strokeText(str, x, y);
405 -
406 - ctx.restore();
407 - };
408 -
409 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/README
@@ -1,13 +0,0 @@
2 -The result formats contained in this directory are query printers for
3 -Semantic MediaWiki that display charts using the jqPlot Javascript library:
4 -
5 -http://www.jqplot.com/
6 -
7 -jqPlot itself uses the jQuery Javascript library.
8 -
9 -Currently the directory holds two query printers, for bar and pie charts.
10 -
11 -For more information about the jqPlot result formats, see:
12 -
13 -* http://semantic-mediawiki.org/wiki/Help:jqplotpie_format
14 -* http://semantic-mediawiki.org/wiki/Help:jqplotbar_format
Index: trunk/extensions/SemanticResultFormats/jqPlot/jquery.jqplot.js
@@ -1,6983 +0,0 @@
2 -/**
3 - * Title: jqPlot Charts
4 - *
5 - * Pure JavaScript plotting plugin for jQuery.
6 - *
7 - * About: Version
8 - *
9 - * 0.9.7r635
10 - *
11 - * About: Copyright & License
12 - *
13 - * Copyright (c) 2009 - 2010 Chris Leonello
14 - * jqPlot is currently available for use in all personal or commercial projects
15 - * under both the MIT and GPL version 2.0 licenses. This means that you can
16 - * choose the license that best suits your project and use it accordingly.
17 - *
18 - * See <GPL Version 2> and <MIT License> contained within this distribution for further information.
19 - *
20 - * The author would appreciate an email letting him know of any substantial
21 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
22 - * or see http://www.jqplot.com/info.php. This is, of course, not required.
23 - *
24 - * If you are feeling kind and generous, consider supporting the project by
25 - * making a donation at: http://www.jqplot.com/donate.php.
26 - *
27 - * jqPlot includes `date instance methods and printf/sprintf functions by other authors:
28 - *
29 - * Date instance methods:
30 - *
31 - * author Ken Snyder (ken d snyder at gmail dot com)
32 - * date 2008-09-10
33 - * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
34 - * license Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
35 - *
36 - * JavaScript printf/sprintf functions:
37 - *
38 - * version 2007.04.27
39 - * author Ash Searle
40 - * http://hexmen.com/blog/2007/03/printf-sprintf/
41 - * http://hexmen.com/js/sprintf.js
42 - * The author (Ash Searle) has placed this code in the public domain:
43 - * "This code is unrestricted: you are free to use it however you like."
44 - *
45 - *
46 - * About: Introduction
47 - *
48 - * jqPlot requires jQuery (1.4+ required for certain features). jQuery 1.4.1 is included in the distribution.
49 - * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally
50 - * the excanvas script for IE support in your web page:
51 - *
52 - * > <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
53 - * > <script language="javascript" type="text/javascript" src="jquery-1.4.2.min.js"></script>
54 - * > <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script>
55 - * > <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" />
56 - *
57 - * jqPlot can be customized by overriding the defaults of any of the objects which make
58 - * up the plot. The general usage of jqplot is:
59 - *
60 - * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject});
61 - *
62 - * The options available to jqplot are detailed in <jqPlot Options> in the jqPlotOptions.txt file.
63 - *
64 - * An actual call to $.jqplot() may look like the
65 - * examples below:
66 - *
67 - * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]);
68 - *
69 - * or
70 - *
71 - * > dataArray = [34,12,43,55,77];
72 - * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}});
73 - *
74 - * For more inforrmation, see <jqPlot Usage>.
75 - *
76 - * About: Usage
77 - *
78 - * See <jqPlot Usage>
79 - *
80 - * About: Available Options
81 - *
82 - * See <jqPlot Options> for a list of options available thorugh the options object (not complete yet!)
83 - *
84 - * About: Options Usage
85 - *
86 - * See <Options Tutorial>
87 - *
88 - * About: Changes
89 - *
90 - * See <Change Log>
91 - *
92 - */
93 -
94 -(function($) {
95 - // make sure undefined is undefined
96 - var undefined;
97 -
98 - /**
99 - * Class: $.jqplot
100 - * jQuery function called by the user to create a plot.
101 - *
102 - * Parameters:
103 - * target - ID of target element to render the plot into.
104 - * data - an array of data series.
105 - * options - user defined options object. See the individual classes for available options.
106 - *
107 - * Properties:
108 - * config - object to hold configuration information for jqPlot plot object.
109 - *
110 - * attributes:
111 - * enablePlugins - False to disable plugins by default. Plugins must then be explicitly
112 - * enabled in the individual plot options. Default: false.
113 - * This property sets the "show" property of certain plugins to true or false.
114 - * Only plugins that can be immediately active upon loading are affected. This includes
115 - * non-renderer plugins like cursor, dragable, highlighter, and trendline.
116 - * defaultHeight - Default height for plots where no css height specification exists. This
117 - * is a jqplot wide default.
118 - * defaultWidth - Default height for plots where no css height specification exists. This
119 - * is a jqplot wide default.
120 - */
121 -
122 - $.jqplot = function(target, data, options) {
123 - var _data, _options;
124 -
125 - if (options == null) {
126 - if (data instanceof Array) {
127 - _data = data;
128 - _options = null;
129 - }
130 -
131 - else if (data.constructor == Object) {
132 - _data = null;
133 - _options = data;
134 - }
135 - }
136 - else {
137 - _data = data;
138 - _options = options;
139 - }
140 - var plot = new jqPlot();
141 - // remove any error class that may be stuck on target.
142 - $('#'+target).removeClass('jqplot-error');
143 -
144 - if ($.jqplot.config.catchErrors) {
145 - try {
146 - plot.init(target, _data, _options);
147 - plot.draw();
148 - plot.themeEngine.init.call(plot);
149 - return plot;
150 - }
151 - catch(e) {
152 - var msg = $.jqplot.config.errorMessage || e.message;
153 - $('#'+target).append('<div class="jqplot-error-message">'+msg+'</div>');
154 - $('#'+target).addClass('jqplot-error');
155 - document.getElementById(target).style.background = $.jqplot.config.errorBackground;
156 - document.getElementById(target).style.border = $.jqplot.config.errorBorder;
157 - document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily;
158 - document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize;
159 - document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle;
160 - document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight;
161 - }
162 - }
163 - else {
164 - plot.init(target, _data, _options);
165 - plot.draw();
166 - plot.themeEngine.init.call(plot);
167 - return plot;
168 - }
169 - };
170 -
171 - $.jqplot.debug = 1;
172 - $.jqplot.config = {
173 - debug:1,
174 - enablePlugins:false,
175 - defaultHeight:300,
176 - defaultWidth:400,
177 - UTCAdjust:false,
178 - timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000),
179 - errorMessage: '',
180 - errorBackground: '',
181 - errorBorder: '',
182 - errorFontFamily: '',
183 - errorFontSize: '',
184 - errorFontStyle: '',
185 - errorFontWeight: '',
186 - catchErrors: false,
187 - defaultTickFormatString: "%.1f"
188 - };
189 -
190 - $.jqplot.enablePlugins = $.jqplot.config.enablePlugins;
191 -
192 - // canvas related tests taken from modernizer:
193 - // Copyright � 2009�2010 Faruk Ates.
194 - // http://www.modernizr.com
195 -
196 - $.jqplot.support_canvas = function() {
197 - return !!document.createElement('canvas').getContext;
198 - };
199 -
200 - $.jqplot.support_canvas_text = function() {
201 - return !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function');
202 - };
203 -
204 - $.jqplot.use_excanvas = ($.browser.msie && !$.jqplot.support_canvas()) ? true : false;
205 -
206 - /**
207 - *
208 - * Hooks: jqPlot Pugin Hooks
209 - *
210 - * $.jqplot.preInitHooks - called before initialization.
211 - * $.jqplot.postInitHooks - called after initialization.
212 - * $.jqplot.preParseOptionsHooks - called before user options are parsed.
213 - * $.jqplot.postParseOptionsHooks - called after user options are parsed.
214 - * $.jqplot.preDrawHooks - called before plot draw.
215 - * $.jqplot.postDrawHooks - called after plot draw.
216 - * $.jqplot.preDrawSeriesHooks - called before each series is drawn.
217 - * $.jqplot.postDrawSeriesHooks - called after each series is drawn.
218 - * $.jqplot.preDrawLegendHooks - called before the legend is drawn.
219 - * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins
220 - * can add rows to the legend table.
221 - * $.jqplot.preSeriesInitHooks - called before series is initialized.
222 - * $.jqplot.postSeriesInitHooks - called after series is initialized.
223 - * $.jqplot.preParseSeriesOptionsHooks - called before series related options
224 - * are parsed.
225 - * $.jqplot.postParseSeriesOptionsHooks - called after series related options
226 - * are parsed.
227 - * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds
228 - * listeners to the event canvas which lays on top of the grid area.
229 - * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn.
230 - * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn.
231 - *
232 - */
233 -
234 - $.jqplot.preInitHooks = [];
235 - $.jqplot.postInitHooks = [];
236 - $.jqplot.preParseOptionsHooks = [];
237 - $.jqplot.postParseOptionsHooks = [];
238 - $.jqplot.preDrawHooks = [];
239 - $.jqplot.postDrawHooks = [];
240 - $.jqplot.preDrawSeriesHooks = [];
241 - $.jqplot.postDrawSeriesHooks = [];
242 - $.jqplot.preDrawLegendHooks = [];
243 - $.jqplot.addLegendRowHooks = [];
244 - $.jqplot.preSeriesInitHooks = [];
245 - $.jqplot.postSeriesInitHooks = [];
246 - $.jqplot.preParseSeriesOptionsHooks = [];
247 - $.jqplot.postParseSeriesOptionsHooks = [];
248 - $.jqplot.eventListenerHooks = [];
249 - $.jqplot.preDrawSeriesShadowHooks = [];
250 - $.jqplot.postDrawSeriesShadowHooks = [];
251 -
252 - // A superclass holding some common properties and methods.
253 - $.jqplot.ElemContainer = function() {
254 - this._elem;
255 - this._plotWidth;
256 - this._plotHeight;
257 - this._plotDimensions = {height:null, width:null};
258 - };
259 -
260 - $.jqplot.ElemContainer.prototype.createElement = function(el, offsets, clss, cssopts, attrib) {
261 - this._offsets = offsets;
262 - var klass = clss || 'jqplot';
263 - var elem = document.createElement(el);
264 - this._elem = $(elem);
265 - this._elem.addClass(klass);
266 - this._elem.css(cssopts);
267 - this._elem.attr(attrib);
268 - return this._elem;
269 - };
270 -
271 - $.jqplot.ElemContainer.prototype.getWidth = function() {
272 - if (this._elem) {
273 - return this._elem.outerWidth(true);
274 - }
275 - else {
276 - return null;
277 - }
278 - };
279 -
280 - $.jqplot.ElemContainer.prototype.getHeight = function() {
281 - if (this._elem) {
282 - return this._elem.outerHeight(true);
283 - }
284 - else {
285 - return null;
286 - }
287 - };
288 -
289 - $.jqplot.ElemContainer.prototype.getPosition = function() {
290 - if (this._elem) {
291 - return this._elem.position();
292 - }
293 - else {
294 - return {top:null, left:null, bottom:null, right:null};
295 - }
296 - };
297 -
298 - $.jqplot.ElemContainer.prototype.getTop = function() {
299 - return this.getPosition().top;
300 - };
301 -
302 - $.jqplot.ElemContainer.prototype.getLeft = function() {
303 - return this.getPosition().left;
304 - };
305 -
306 - $.jqplot.ElemContainer.prototype.getBottom = function() {
307 - return this._elem.css('bottom');
308 - };
309 -
310 - $.jqplot.ElemContainer.prototype.getRight = function() {
311 - return this._elem.css('right');
312 - };
313 -
314 -
315 - /**
316 - * Class: Axis
317 - * An individual axis object. Cannot be instantiated directly, but created
318 - * by the Plot oject. Axis properties can be set or overriden by the
319 - * options passed in from the user.
320 - *
321 - */
322 - function Axis(name) {
323 - $.jqplot.ElemContainer.call(this);
324 - // Group: Properties
325 - //
326 - // Axes options are specified within an axes object at the top level of the
327 - // plot options like so:
328 - // > {
329 - // > axes: {
330 - // > xaxis: {min: 5},
331 - // > yaxis: {min: 2, max: 8, numberTicks:4},
332 - // > x2axis: {pad: 1.5},
333 - // > y2axis: {ticks:[22, 44, 66, 88]}
334 - // > }
335 - // > }
336 - // There are 4 axes, 'xaxis', 'yaxis', 'x2axis', 'y2axis'. Any or all of
337 - // which may be specified.
338 - this.name = name;
339 - this._series = [];
340 - // prop: show
341 - // Wether to display the axis on the graph.
342 - this.show = false;
343 - // prop: tickRenderer
344 - // A class of a rendering engine for creating the ticks labels displayed on the plot,
345 - // See <$.jqplot.AxisTickRenderer>.
346 - this.tickRenderer = $.jqplot.AxisTickRenderer;
347 - // prop: tickOptions
348 - // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options.
349 - this.tickOptions = {};
350 - // prop: labelRenderer
351 - // A class of a rendering engine for creating an axis label.
352 - this.labelRenderer = $.jqplot.AxisLabelRenderer;
353 - // prop: labelOptions
354 - // Options passed to the label renderer.
355 - this.labelOptions = {};
356 - // prop: label
357 - // Label for the axis
358 - this.label = null;
359 - // prop: showLabel
360 - // true to show the axis label.
361 - this.showLabel = true;
362 - // prop: min
363 - // minimum value of the axis (in data units, not pixels).
364 - this.min=null;
365 - // prop: max
366 - // maximum value of the axis (in data units, not pixels).
367 - this.max=null;
368 - // prop: autoscale
369 - // Autoscale the axis min and max values to provide sensible tick spacing.
370 - // If axis min or max are set, autoscale will be turned off.
371 - // The numberTicks, tickInterval and pad options do work with
372 - // autoscale, although tickInterval has not been tested yet.
373 - // padMin and padMax do nothing when autoscale is on.
374 - this.autoscale = false;
375 - // prop: pad
376 - // Padding to extend the range above and below the data bounds.
377 - // The data range is multiplied by this factor to determine minimum and maximum axis bounds.
378 - // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0.
379 - this.pad = 1.2;
380 - // prop: padMax
381 - // Padding to extend the range above data bounds.
382 - // The top of the data range is multiplied by this factor to determine maximum axis bounds.
383 - // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0.
384 - this.padMax = null;
385 - // prop: padMin
386 - // Padding to extend the range below data bounds.
387 - // The bottom of the data range is multiplied by this factor to determine minimum axis bounds.
388 - // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0.
389 - this.padMin = null;
390 - // prop: ticks
391 - // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis.
392 - // If no label is specified, the value is formatted into an appropriate label.
393 - this.ticks = [];
394 - // prop: numberTicks
395 - // Desired number of ticks. Default is to compute automatically.
396 - this.numberTicks;
397 - // prop: tickInterval
398 - // number of units between ticks. Mutually exclusive with numberTicks.
399 - this.tickInterval;
400 - // prop: renderer
401 - // A class of a rendering engine that handles tick generation,
402 - // scaling input data to pixel grid units and drawing the axis element.
403 - this.renderer = $.jqplot.LinearAxisRenderer;
404 - // prop: rendererOptions
405 - // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options.
406 - this.rendererOptions = {};
407 - // prop: showTicks
408 - // Wether to show the ticks (both marks and labels) or not.
409 - // Will not override showMark and showLabel options if specified on the ticks themselves.
410 - this.showTicks = true;
411 - // prop: showTickMarks
412 - // Wether to show the tick marks (line crossing grid) or not.
413 - // Overridden by showTicks and showMark option of tick itself.
414 - this.showTickMarks = true;
415 - // prop: showMinorTicks
416 - // Wether or not to show minor ticks. This is renderer dependent.
417 - // The default <$.jqplot.LinearAxisRenderer> does not have minor ticks.
418 - this.showMinorTicks = true;
419 - // prop: useSeriesColor
420 - // Use the color of the first series associated with this axis for the
421 - // tick marks and line bordering this axis.
422 - this.useSeriesColor = false;
423 - // prop: borderWidth
424 - // width of line stroked at the border of the axis. Defaults
425 - // to the width of the grid boarder.
426 - this.borderWidth = null;
427 - // prop: borderColor
428 - // color of the border adjacent to the axis. Defaults to grid border color.
429 - this.borderColor = null;
430 - // minimum and maximum values on the axis.
431 - this._dataBounds = {min:null, max:null};
432 - // pixel position from the top left of the min value and max value on the axis.
433 - this._offsets = {min:null, max:null};
434 - this._ticks=[];
435 - this._label = null;
436 - // prop: syncTicks
437 - // true to try and synchronize tick spacing across multiple axes so that ticks and
438 - // grid lines line up. This has an impact on autoscaling algorithm, however.
439 - // In general, autoscaling an individual axis will work better if it does not
440 - // have to sync ticks.
441 - this.syncTicks = null;
442 - // prop: tickSpacing
443 - // Approximate pixel spacing between ticks on graph. Used during autoscaling.
444 - // This number will be an upper bound, actual spacing will be less.
445 - this.tickSpacing = 75;
446 - // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks
447 - // so they can be restored if altered by plugins.
448 - this._min = null;
449 - this._max = null;
450 - this._tickInterval = null;
451 - this._numberTicks = null;
452 - this.__ticks = null;
453 - }
454 -
455 - Axis.prototype = new $.jqplot.ElemContainer();
456 - Axis.prototype.constructor = Axis;
457 -
458 - Axis.prototype.init = function() {
459 - this.renderer = new this.renderer();
460 - // set the axis name
461 - this.tickOptions.axis = this.name;
462 - // if showMark or showLabel tick options not specified, use value of axis option.
463 - // showTicks overrides showTickMarks.
464 - if (this.tickOptions.showMark == null) {
465 - this.tickOptions.showMark = this.showTicks;
466 - }
467 - if (this.tickOptions.showMark == null) {
468 - this.tickOptions.showMark = this.showTickMarks;
469 - }
470 - if (this.tickOptions.showLabel == null) {
471 - this.tickOptions.showLabel = this.showTicks;
472 - }
473 -
474 - if (this.label == null || this.label == '') {
475 - this.showLabel = false;
476 - }
477 - else {
478 - this.labelOptions.label = this.label;
479 - }
480 - if (this.showLabel == false) {
481 - this.labelOptions.show = false;
482 - }
483 - // set the default padMax, padMin if not specified
484 - // special check, if no padding desired, padding
485 - // should be set to 1.0
486 - if (this.pad == 0) {
487 - this.pad = 1.0;
488 - }
489 - if (this.padMax == 0) {
490 - this.padMax = 1.0;
491 - }
492 - if (this.padMin == 0) {
493 - this.padMin = 1.0;
494 - }
495 - if (this.padMax == null) {
496 - this.padMax = (this.pad-1)/2 + 1;
497 - }
498 - if (this.padMin == null) {
499 - this.padMin = (this.pad-1)/2 + 1;
500 - }
501 - // now that padMin and padMax are correctly set, reset pad in case user has supplied
502 - // padMin and/or padMax
503 - this.pad = this.padMax + this.padMin - 1;
504 - if (this.min != null || this.max != null) {
505 - this.autoscale = false;
506 - }
507 - // if not set, sync ticks for y axes but not x by default.
508 - if (this.syncTicks == null && this.name.indexOf('y') > -1) {
509 - this.syncTicks = true;
510 - }
511 - else if (this.syncTicks == null){
512 - this.syncTicks = false;
513 - }
514 - this.renderer.init.call(this, this.rendererOptions);
515 -
516 - };
517 -
518 - Axis.prototype.draw = function(ctx) {
519 - return this.renderer.draw.call(this, ctx);
520 -
521 - };
522 -
523 - Axis.prototype.set = function() {
524 - this.renderer.set.call(this);
525 - };
526 -
527 - Axis.prototype.pack = function(pos, offsets) {
528 - if (this.show) {
529 - this.renderer.pack.call(this, pos, offsets);
530 - }
531 - // these properties should all be available now.
532 - if (this._min == null) {
533 - this._min = this.min;
534 - this._max = this.max;
535 - this._tickInterval = this.tickInterval;
536 - this._numberTicks = this.numberTicks;
537 - this.__ticks = this._ticks;
538 - }
539 - };
540 -
541 - // reset the axis back to original values if it has been scaled, zoomed, etc.
542 - Axis.prototype.reset = function() {
543 - this.renderer.reset.call(this);
544 - };
545 -
546 - Axis.prototype.resetScale = function() {
547 - this.min = null;
548 - this.max = null;
549 - this.numberTicks = null;
550 - this.tickInterval = null;
551 - };
552 -
553 - /**
554 - * Class: Legend
555 - * Legend object. Cannot be instantiated directly, but created
556 - * by the Plot oject. Legend properties can be set or overriden by the
557 - * options passed in from the user.
558 - */
559 - function Legend(options) {
560 - $.jqplot.ElemContainer.call(this);
561 - // Group: Properties
562 -
563 - // prop: show
564 - // Wether to display the legend on the graph.
565 - this.show = false;
566 - // prop: location
567 - // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w
568 - this.location = 'ne';
569 - // prop: labels
570 - // Array of labels to use. By default the renderer will look for labels on the series.
571 - // Labels specified in this array will override labels specified on the series.
572 - this.labels = [];
573 - // prop: showLabels
574 - // true to show the label text on the legend.
575 - this.showLabels = true;
576 - // prop: showSwatch
577 - // true to show the color swatches on the legend.
578 - this.showSwatches = true;
579 - // prop: placement
580 - // "insideGrid" places legend inside the grid area of the plot.
581 - // "outsideGrid" places the legend outside the grid but inside the plot container,
582 - // shrinking the grid to accomodate the legend.
583 - // "inside" synonym for "insideGrid",
584 - // "outside" places the legend ouside the grid area, but does not shrink the grid which
585 - // can cause the legend to overflow the plot container.
586 - this.placement = "insideGrid";
587 - // prop: xoffset
588 - // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
589 - // properties or via CSS margin styling of the .jqplot-table-legend class.
590 - this.xoffset = 0;
591 - // prop: yoffset
592 - // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
593 - // properties or via CSS margin styling of the .jqplot-table-legend class.
594 - this.yoffset = 0;
595 - // prop: border
596 - // css spec for the border around the legend box.
597 - this.border;
598 - // prop: background
599 - // css spec for the background of the legend box.
600 - this.background;
601 - // prop: textColor
602 - // css color spec for the legend text.
603 - this.textColor;
604 - // prop: fontFamily
605 - // css font-family spec for the legend text.
606 - this.fontFamily;
607 - // prop: fontSize
608 - // css font-size spec for the legend text.
609 - this.fontSize ;
610 - // prop: rowSpacing
611 - // css padding-top spec for the rows in the legend.
612 - this.rowSpacing = '0.5em';
613 - // renderer
614 - // A class that will create a DOM object for the legend,
615 - // see <$.jqplot.TableLegendRenderer>.
616 - this.renderer = $.jqplot.TableLegendRenderer;
617 - // prop: rendererOptions
618 - // renderer specific options passed to the renderer.
619 - this.rendererOptions = {};
620 - // prop: predraw
621 - // Wether to draw the legend before the series or not.
622 - // Used with series specific legend renderers for pie, donut, mekko charts, etc.
623 - this.preDraw = false;
624 - // prop: marginTop
625 - // CSS margin for the legend DOM element. This will set an element
626 - // CSS style for the margin which will override any style sheet setting.
627 - // The default will be taken from the stylesheet.
628 - this.marginTop = null;
629 - // prop: marginRight
630 - // CSS margin for the legend DOM element. This will set an element
631 - // CSS style for the margin which will override any style sheet setting.
632 - // The default will be taken from the stylesheet.
633 - this.marginRight = null;
634 - // prop: marginBottom
635 - // CSS margin for the legend DOM element. This will set an element
636 - // CSS style for the margin which will override any style sheet setting.
637 - // The default will be taken from the stylesheet.
638 - this.marginBottom = null;
639 - // prop: marginLeft
640 - // CSS margin for the legend DOM element. This will set an element
641 - // CSS style for the margin which will override any style sheet setting.
642 - // The default will be taken from the stylesheet.
643 - this.marginLeft = null;
644 -
645 - this.escapeHtml = false;
646 - this._series = [];
647 -
648 - $.extend(true, this, options);
649 - }
650 -
651 - Legend.prototype = new $.jqplot.ElemContainer();
652 - Legend.prototype.constructor = Legend;
653 -
654 - Legend.prototype.setOptions = function(options) {
655 - $.extend(true, this, options);
656 -
657 - // Try to emulate deprecated behaviour
658 - // if user has specified xoffset or yoffset, copy these to
659 - // the margin properties.
660 -
661 - if (this.placement == 'inside') this.placement = 'insideGrid';
662 -
663 - if (this.xoffset >0) {
664 - if (this.placement == 'insideGrid') {
665 - switch (this.location) {
666 - case 'nw':
667 - case 'w':
668 - case 'sw':
669 - if (this.marginLeft == null) {
670 - this.marginLeft = this.xoffset + 'px';
671 - }
672 - this.marginRight = '0px';
673 - break;
674 - case 'ne':
675 - case 'e':
676 - case 'se':
677 - default:
678 - if (this.marginRight == null) {
679 - this.marginRight = this.xoffset + 'px';
680 - }
681 - this.marginLeft = '0px';
682 - break;
683 - }
684 - }
685 - else if (this.placement == 'outside') {
686 - switch (this.location) {
687 - case 'nw':
688 - case 'w':
689 - case 'sw':
690 - if (this.marginRight == null) {
691 - this.marginRight = this.xoffset + 'px';
692 - }
693 - this.marginLeft = '0px';
694 - break;
695 - case 'ne':
696 - case 'e':
697 - case 'se':
698 - default:
699 - if (this.marginLeft == null) {
700 - this.marginLeft = this.xoffset + 'px';
701 - }
702 - this.marginRight = '0px';
703 - break;
704 - }
705 - }
706 - this.xoffset = 0;
707 - }
708 -
709 - if (this.yoffset >0) {
710 - if (this.placement == 'outside') {
711 - switch (this.location) {
712 - case 'sw':
713 - case 's':
714 - case 'se':
715 - if (this.marginTop == null) {
716 - this.marginTop = this.yoffset + 'px';
717 - }
718 - this.marginBottom = '0px';
719 - break;
720 - case 'ne':
721 - case 'n':
722 - case 'nw':
723 - default:
724 - if (this.marginBottom == null) {
725 - this.marginBottom = this.yoffset + 'px';
726 - }
727 - this.marginTop = '0px';
728 - break;
729 - }
730 - }
731 - else if (this.placement == 'insideGrid') {
732 - switch (this.location) {
733 - case 'sw':
734 - case 's':
735 - case 'se':
736 - if (this.marginBottom == null) {
737 - this.marginBottom = this.yoffset + 'px';
738 - }
739 - this.marginTop = '0px';
740 - break;
741 - case 'ne':
742 - case 'n':
743 - case 'nw':
744 - default:
745 - if (this.marginTop == null) {
746 - this.marginTop = this.yoffset + 'px';
747 - }
748 - this.marginBottom = '0px';
749 - break;
750 - }
751 - }
752 - this.yoffset = 0;
753 - }
754 -
755 - // TO-DO:
756 - // Handle case where offsets are < 0.
757 - //
758 - };
759 -
760 - Legend.prototype.init = function() {
761 - this.renderer = new this.renderer();
762 - this.renderer.init.call(this, this.rendererOptions);
763 - };
764 -
765 - Legend.prototype.draw = function(offsets) {
766 - for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){
767 - $.jqplot.preDrawLegendHooks[i].call(this, offsets);
768 - }
769 - return this.renderer.draw.call(this, offsets);
770 - };
771 -
772 - Legend.prototype.pack = function(offsets) {
773 - this.renderer.pack.call(this, offsets);
774 - };
775 -
776 - /**
777 - * Class: Title
778 - * Plot Title object. Cannot be instantiated directly, but created
779 - * by the Plot oject. Title properties can be set or overriden by the
780 - * options passed in from the user.
781 - *
782 - * Parameters:
783 - * text - text of the title.
784 - */
785 - function Title(text) {
786 - $.jqplot.ElemContainer.call(this);
787 - // Group: Properties
788 -
789 - // prop: text
790 - // text of the title;
791 - this.text = text;
792 - // prop: show
793 - // wether or not to show the title
794 - this.show = true;
795 - // prop: fontFamily
796 - // css font-family spec for the text.
797 - this.fontFamily;
798 - // prop: fontSize
799 - // css font-size spec for the text.
800 - this.fontSize ;
801 - // prop: textAlign
802 - // css text-align spec for the text.
803 - this.textAlign;
804 - // prop: textColor
805 - // css color spec for the text.
806 - this.textColor;
807 - // prop: renderer
808 - // A class for creating a DOM element for the title,
809 - // see <$.jqplot.DivTitleRenderer>.
810 - this.renderer = $.jqplot.DivTitleRenderer;
811 - // prop: rendererOptions
812 - // renderer specific options passed to the renderer.
813 - this.rendererOptions = {};
814 - }
815 -
816 - Title.prototype = new $.jqplot.ElemContainer();
817 - Title.prototype.constructor = Title;
818 -
819 - Title.prototype.init = function() {
820 - this.renderer = new this.renderer();
821 - this.renderer.init.call(this, this.rendererOptions);
822 - };
823 -
824 - Title.prototype.draw = function(width) {
825 - return this.renderer.draw.call(this, width);
826 - };
827 -
828 - Title.prototype.pack = function() {
829 - this.renderer.pack.call(this);
830 - };
831 -
832 -
833 - /**
834 - * Class: Series
835 - * An individual data series object. Cannot be instantiated directly, but created
836 - * by the Plot oject. Series properties can be set or overriden by the
837 - * options passed in from the user.
838 - */
839 - function Series() {
840 - $.jqplot.ElemContainer.call(this);
841 - // Group: Properties
842 - // Properties will be assigned from a series array at the top level of the
843 - // options. If you had two series and wanted to change the color and line
844 - // width of the first and set the second to use the secondary y axis with
845 - // no shadow and supply custom labels for each:
846 - // > {
847 - // > series:[
848 - // > {color: '#ff4466', lineWidth: 5, label:'good line'},
849 - // > {yaxis: 'y2axis', shadow: false, label:'bad line'}
850 - // > ]
851 - // > }
852 -
853 - // prop: show
854 - // wether or not to draw the series.
855 - this.show = true;
856 - // prop: xaxis
857 - // which x axis to use with this series, either 'xaxis' or 'x2axis'.
858 - this.xaxis = 'xaxis';
859 - this._xaxis;
860 - // prop: yaxis
861 - // which y axis to use with this series, either 'yaxis' or 'y2axis'.
862 - this.yaxis = 'yaxis';
863 - this._yaxis;
864 - this.gridBorderWidth = 2.0;
865 - // prop: renderer
866 - // A class of a renderer which will draw the series,
867 - // see <$.jqplot.LineRenderer>.
868 - this.renderer = $.jqplot.LineRenderer;
869 - // prop: rendererOptions
870 - // Options to pass on to the renderer.
871 - this.rendererOptions = {};
872 - this.data = [];
873 - this.gridData = [];
874 - // prop: label
875 - // Line label to use in the legend.
876 - this.label = '';
877 - // prop: showLabel
878 - // true to show label for this series in the legend.
879 - this.showLabel = true;
880 - // prop: color
881 - // css color spec for the series
882 - this.color;
883 - // prop: lineWidth
884 - // width of the line in pixels. May have different meanings depending on renderer.
885 - this.lineWidth = 2.5;
886 - // prop: shadow
887 - // wether or not to draw a shadow on the line
888 - this.shadow = true;
889 - // prop: shadowAngle
890 - // Shadow angle in degrees
891 - this.shadowAngle = 45;
892 - // prop: shadowOffset
893 - // Shadow offset from line in pixels
894 - this.shadowOffset = 1.25;
895 - // prop: shadowDepth
896 - // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
897 - this.shadowDepth = 3;
898 - // prop: shadowAlpha
899 - // Alpha channel transparency of shadow. 0 = transparent.
900 - this.shadowAlpha = '0.1';
901 - // prop: breakOnNull
902 - // Not implemented. wether line segments should be be broken at null value.
903 - // False will join point on either side of line.
904 - this.breakOnNull = false;
905 - // prop: markerRenderer
906 - // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points,
907 - // see <$.jqplot.MarkerRenderer>.
908 - this.markerRenderer = $.jqplot.MarkerRenderer;
909 - // prop: markerOptions
910 - // renderer specific options to pass to the markerRenderer,
911 - // see <$.jqplot.MarkerRenderer>.
912 - this.markerOptions = {};
913 - // prop: showLine
914 - // wether to actually draw the line or not. Series will still be renderered, even if no line is drawn.
915 - this.showLine = true;
916 - // prop: showMarker
917 - // wether or not to show the markers at the data points.
918 - this.showMarker = true;
919 - // prop: index
920 - // 0 based index of this series in the plot series array.
921 - this.index;
922 - // prop: fill
923 - // true or false, wether to fill under lines or in bars.
924 - // May not be implemented in all renderers.
925 - this.fill = false;
926 - // prop: fillColor
927 - // CSS color spec to use for fill under line. Defaults to line color.
928 - this.fillColor;
929 - // prop: fillAlpha
930 - // Alpha transparency to apply to the fill under the line.
931 - // Use this to adjust alpha separate from fill color.
932 - this.fillAlpha;
933 - // prop: fillAndStroke
934 - // If true will stroke the line (with color this.color) as well as fill under it.
935 - // Applies only when fill is true.
936 - this.fillAndStroke = false;
937 - // prop: disableStack
938 - // true to not stack this series with other series in the plot.
939 - // To render properly, non-stacked series must come after any stacked series
940 - // in the plot's data series array. So, the plot's data series array would look like:
941 - // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...]
942 - // disableStack will put a gap in the stacking order of series, and subsequent
943 - // stacked series will not fill down through the non-stacked series and will
944 - // most likely not stack properly on top of the non-stacked series.
945 - this.disableStack = false;
946 - // _stack is set by the Plot if the plot is a stacked chart.
947 - // will stack lines or bars on top of one another to build a "mountain" style chart.
948 - // May not be implemented in all renderers.
949 - this._stack = false;
950 - // prop: neighborThreshold
951 - // how close or far (in pixels) the cursor must be from a point marker to detect the point.
952 - this.neighborThreshold = 4;
953 - // prop: fillToZero
954 - // true will force bar and filled series to fill toward zero on the fill Axis.
955 - this.fillToZero = false;
956 - // prop: fillToValue
957 - // fill a filled series to this value on the fill axis.
958 - // Works in conjunction with fillToZero, so that must be true.
959 - this.fillToValue = 0;
960 - // prop: fillAxis
961 - // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true.
962 - // 'y' means fill up/down to 0 on the y axis for this series.
963 - this.fillAxis = 'y';
964 - // prop: useNegativeColors
965 - // true to color negative values differently in filled and bar charts.
966 - this.useNegativeColors = true;
967 - this._stackData = [];
968 - // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If
969 - // stacked, _plotData is accumulation of stacking data.
970 - this._plotData = [];
971 - // _plotValues hold the individual x and y values that will be plotted for this series.
972 - this._plotValues = {x:[], y:[]};
973 - // statistics about the intervals between data points. Used for auto scaling.
974 - this._intervals = {x:{}, y:{}};
975 - // data from the previous series, for stacked charts.
976 - this._prevPlotData = [];
977 - this._prevGridData = [];
978 - this._stackAxis = 'y';
979 - this._primaryAxis = '_xaxis';
980 - // give each series a canvas to draw on. This should allow for redrawing speedups.
981 - this.canvas = new $.jqplot.GenericCanvas();
982 - this.shadowCanvas = new $.jqplot.GenericCanvas();
983 - this.plugins = {};
984 - // sum of y values in this series.
985 - this._sumy = 0;
986 - this._sumx = 0;
987 - }
988 -
989 - Series.prototype = new $.jqplot.ElemContainer();
990 - Series.prototype.constructor = Series;
991 -
992 - Series.prototype.init = function(index, gridbw, plot) {
993 - // weed out any null values in the data.
994 - this.index = index;
995 - this.gridBorderWidth = gridbw;
996 - var d = this.data;
997 - var temp = [], i;
998 - for (i=0; i<d.length; i++) {
999 - if (! this.breakOnNull) {
1000 - if (d[i] == null || d[i][0] == null || d[i][1] == null) {
1001 - continue;
1002 - }
1003 - else {
1004 - temp.push(d[i]);
1005 - }
1006 - }
1007 - else {
1008 - // TODO: figure out what to do with null values
1009 - // probably involve keeping nulls in data array
1010 - // and then updating renderers to break line
1011 - // when it hits null value.
1012 - // For now, just keep value.
1013 - temp.push(d[i]);
1014 - }
1015 - }
1016 - this.data = temp;
1017 - if (!this.fillColor) {
1018 - this.fillColor = this.color;
1019 - }
1020 - if (this.fillAlpha) {
1021 - var comp = $.jqplot.normalize2rgb(this.fillColor);
1022 - var comp = $.jqplot.getColorComponents(comp);
1023 - this.fillColor = 'rgba('+comp[0]+','+comp[1]+','+comp[2]+','+this.fillAlpha+')';
1024 - }
1025 - this.renderer = new this.renderer();
1026 - this.renderer.init.call(this, this.rendererOptions, plot);
1027 - this.markerRenderer = new this.markerRenderer();
1028 - if (!this.markerOptions.color) {
1029 - this.markerOptions.color = this.color;
1030 - }
1031 - if (this.markerOptions.show == null) {
1032 - this.markerOptions.show = this.showMarker;
1033 - }
1034 - this.showMarker = this.markerOptions.show;
1035 - // the markerRenderer is called within it's own scaope, don't want to overwrite series options!!
1036 - this.markerRenderer.init(this.markerOptions);
1037 - };
1038 -
1039 - // data - optional data point array to draw using this series renderer
1040 - // gridData - optional grid data point array to draw using this series renderer
1041 - // stackData - array of cumulative data for stacked plots.
1042 - Series.prototype.draw = function(sctx, opts, plot) {
1043 - var options = (opts == undefined) ? {} : opts;
1044 - sctx = (sctx == undefined) ? this.canvas._ctx : sctx;
1045 - // hooks get called even if series not shown
1046 - // we don't clear canvas here, it would wipe out all other series as well.
1047 - for (var j=0; j<$.jqplot.preDrawSeriesHooks.length; j++) {
1048 - $.jqplot.preDrawSeriesHooks[j].call(this, sctx, options);
1049 - }
1050 - if (this.show) {
1051 - this.renderer.setGridData.call(this, plot);
1052 - if (!options.preventJqPlotSeriesDrawTrigger) {
1053 - $(sctx.canvas).trigger('jqplotSeriesDraw', [this.data, this.gridData]);
1054 - }
1055 - var data = [];
1056 - if (options.data) {
1057 - data = options.data;
1058 - }
1059 - else if (!this._stack) {
1060 - data = this.data;
1061 - }
1062 - else {
1063 - data = this._plotData;
1064 - }
1065 - var gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
1066 - this.renderer.draw.call(this, sctx, gridData, options, plot);
1067 - }
1068 -
1069 - for (var j=0; j<$.jqplot.postDrawSeriesHooks.length; j++) {
1070 - $.jqplot.postDrawSeriesHooks[j].call(this, sctx, options);
1071 - }
1072 - };
1073 -
1074 - Series.prototype.drawShadow = function(sctx, opts, plot) {
1075 - var options = (opts == undefined) ? {} : opts;
1076 - sctx = (sctx == undefined) ? this.shadowCanvas._ctx : sctx;
1077 - // hooks get called even if series not shown
1078 - // we don't clear canvas here, it would wipe out all other series as well.
1079 - for (var j=0; j<$.jqplot.preDrawSeriesShadowHooks.length; j++) {
1080 - $.jqplot.preDrawSeriesShadowHooks[j].call(this, sctx, options);
1081 - }
1082 - if (this.shadow) {
1083 - this.renderer.setGridData.call(this, plot);
1084 -
1085 - var data = [];
1086 - if (options.data) {
1087 - data = options.data;
1088 - }
1089 - else if (!this._stack) {
1090 - data = this.data;
1091 - }
1092 - else {
1093 - data = this._plotData;
1094 - }
1095 - var gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
1096 -
1097 - this.renderer.drawShadow.call(this, sctx, gridData, options);
1098 - }
1099 -
1100 - for (var j=0; j<$.jqplot.postDrawSeriesShadowHooks.length; j++) {
1101 - $.jqplot.postDrawSeriesShadowHooks[j].call(this, sctx, options);
1102 - }
1103 -
1104 - };
1105 -
1106 - // toggles series display on plot, e.g. show/hide series
1107 - Series.prototype.toggleDisplay = function(ev) {
1108 - var s, speed;
1109 - if (ev.data.series) {
1110 - s = ev.data.series;
1111 - }
1112 - else {
1113 - s = this;
1114 - }
1115 - if (ev.data.speed) {
1116 - speed = ev.data.speed;
1117 - }
1118 - if (speed) {
1119 - if (s.canvas._elem.is(':hidden')) {
1120 - if (s.shadowCanvas._elem) {
1121 - s.shadowCanvas._elem.fadeIn(speed);
1122 - }
1123 - s.canvas._elem.fadeIn(speed);
1124 - s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeIn(speed);
1125 - }
1126 - else {
1127 - if (s.shadowCanvas._elem) {
1128 - s.shadowCanvas._elem.fadeOut(speed);
1129 - }
1130 - s.canvas._elem.fadeOut(speed);
1131 - s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeOut(speed);
1132 - }
1133 - }
1134 - else {
1135 - if (s.canvas._elem.is(':hidden')) {
1136 - if (s.shadowCanvas._elem) {
1137 - s.shadowCanvas._elem.show();
1138 - }
1139 - s.canvas._elem.show();
1140 - s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).show();
1141 - }
1142 - else {
1143 - if (s.shadowCanvas._elem) {
1144 - s.shadowCanvas._elem.hide();
1145 - }
1146 - s.canvas._elem.hide();
1147 - s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide();
1148 - }
1149 - }
1150 - };
1151 -
1152 -
1153 -
1154 - /**
1155 - * Class: Grid
1156 - *
1157 - * Object representing the grid on which the plot is drawn. The grid in this
1158 - * context is the area bounded by the axes, the area which will contain the series.
1159 - * Note, the series are drawn on their own canvas.
1160 - * The Grid object cannot be instantiated directly, but is created by the Plot oject.
1161 - * Grid properties can be set or overriden by the options passed in from the user.
1162 - */
1163 - function Grid() {
1164 - $.jqplot.ElemContainer.call(this);
1165 - // Group: Properties
1166 -
1167 - // prop: drawGridlines
1168 - // wether to draw the gridlines on the plot.
1169 - this.drawGridlines = true;
1170 - // prop: gridLineColor
1171 - // color of the grid lines.
1172 - this.gridLineColor = '#cccccc';
1173 - // prop: gridLineWidth
1174 - // width of the grid lines.
1175 - this.gridLineWidth = 1.0;
1176 - // prop: background
1177 - // css spec for the background color.
1178 - this.background = '#fffdf6';
1179 - // prop: borderColor
1180 - // css spec for the color of the grid border.
1181 - this.borderColor = '#999999';
1182 - // prop: borderWidth
1183 - // width of the border in pixels.
1184 - this.borderWidth = 2.0;
1185 - // prop: drawBorder
1186 - // True to draw border around grid.
1187 - this.drawBorder = true;
1188 - // prop: shadow
1189 - // wether to show a shadow behind the grid.
1190 - this.shadow = true;
1191 - // prop: shadowAngle
1192 - // shadow angle in degrees
1193 - this.shadowAngle = 45;
1194 - // prop: shadowOffset
1195 - // Offset of each shadow stroke from the border in pixels
1196 - this.shadowOffset = 1.5;
1197 - // prop: shadowWidth
1198 - // width of the stoke for the shadow
1199 - this.shadowWidth = 3;
1200 - // prop: shadowDepth
1201 - // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
1202 - this.shadowDepth = 3;
1203 - // prop: shadowColor
1204 - // an optional css color spec for the shadow in 'rgba(n, n, n, n)' form
1205 - this.shadowColor = null;
1206 - // prop: shadowAlpha
1207 - // Alpha channel transparency of shadow. 0 = transparent.
1208 - this.shadowAlpha = '0.07';
1209 - this._left;
1210 - this._top;
1211 - this._right;
1212 - this._bottom;
1213 - this._width;
1214 - this._height;
1215 - this._axes = [];
1216 - // prop: renderer
1217 - // Instance of a renderer which will actually render the grid,
1218 - // see <$.jqplot.CanvasGridRenderer>.
1219 - this.renderer = $.jqplot.CanvasGridRenderer;
1220 - // prop: rendererOptions
1221 - // Options to pass on to the renderer,
1222 - // see <$.jqplot.CanvasGridRenderer>.
1223 - this.rendererOptions = {};
1224 - this._offsets = {top:null, bottom:null, left:null, right:null};
1225 - }
1226 -
1227 - Grid.prototype = new $.jqplot.ElemContainer();
1228 - Grid.prototype.constructor = Grid;
1229 -
1230 - Grid.prototype.init = function() {
1231 - this.renderer = new this.renderer();
1232 - this.renderer.init.call(this, this.rendererOptions);
1233 - };
1234 -
1235 - Grid.prototype.createElement = function(offsets) {
1236 - this._offsets = offsets;
1237 - return this.renderer.createElement.call(this);
1238 - };
1239 -
1240 - Grid.prototype.draw = function() {
1241 - this.renderer.draw.call(this);
1242 - };
1243 -
1244 - $.jqplot.GenericCanvas = function() {
1245 - $.jqplot.ElemContainer.call(this);
1246 - this._ctx;
1247 - };
1248 -
1249 - $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer();
1250 - $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas;
1251 -
1252 - $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
1253 - this._offsets = offsets;
1254 - var klass = 'jqplot';
1255 - if (clss != undefined) {
1256 - klass = clss;
1257 - }
1258 - var elem;
1259 - // if this canvas already has a dom element, don't make a new one.
1260 - if (this._elem) {
1261 - elem = this._elem.get(0);
1262 - }
1263 - else {
1264 - elem = document.createElement('canvas');
1265 - }
1266 - // if new plotDimensions supplied, use them.
1267 - if (plotDimensions != undefined) {
1268 - this._plotDimensions = plotDimensions;
1269 - }
1270 -
1271 - elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right;
1272 - elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom;
1273 - this._elem = $(elem);
1274 - this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top });
1275 -
1276 - this._elem.addClass(klass);
1277 - if ($.jqplot.use_excanvas) {
1278 - window.G_vmlCanvasManager.init_(document);
1279 - elem = window.G_vmlCanvasManager.initElement(elem);
1280 - }
1281 - return this._elem;
1282 - };
1283 -
1284 - $.jqplot.GenericCanvas.prototype.setContext = function() {
1285 - this._ctx = this._elem.get(0).getContext("2d");
1286 - return this._ctx;
1287 - };
1288 -
1289 - $.jqplot.HooksManager = function () {
1290 - this.hooks =[];
1291 - };
1292 -
1293 - $.jqplot.HooksManager.prototype.addOnce = function(fn) {
1294 - var havehook = false, i;
1295 - for (i=0; i<this.hooks.length; i++) {
1296 - if (this.hooks[i][0] == fn) {
1297 - havehook = true;
1298 - }
1299 - }
1300 - if (!havehook) {
1301 - this.hooks.push(fn);
1302 - }
1303 - };
1304 -
1305 - $.jqplot.HooksManager.prototype.add = function(fn) {
1306 - this.hooks.push(fn);
1307 - };
1308 -
1309 - $.jqplot.EventListenerManager = function () {
1310 - this.hooks =[];
1311 - };
1312 -
1313 - $.jqplot.EventListenerManager.prototype.addOnce = function(ev, fn) {
1314 - var havehook = false, h, i;
1315 - for (i=0; i<this.hooks.length; i++) {
1316 - h = this.hooks[i];
1317 - if (h[0] == ev && h[1] == fn) {
1318 - havehook = true;
1319 - }
1320 - }
1321 - if (!havehook) {
1322 - this.hooks.push([ev, fn]);
1323 - }
1324 - };
1325 -
1326 - $.jqplot.EventListenerManager.prototype.add = function(ev, fn) {
1327 - this.hooks.push([ev, fn]);
1328 - };
1329 -
1330 - /**
1331 - * Class: jqPlot
1332 - * Plot object returned by call to $.jqplot. Handles parsing user options,
1333 - * creating sub objects (Axes, legend, title, series) and rendering the plot.
1334 - */
1335 - function jqPlot() {
1336 - // Group: Properties
1337 - // These properties are specified at the top of the options object
1338 - // like so:
1339 - // > {
1340 - // > axesDefaults:{min:0},
1341 - // > series:[{color:'#6633dd'}],
1342 - // > title: 'A Plot'
1343 - // > }
1344 - //
1345 - // prop: data
1346 - // user's data. Data should *NOT* be specified in the options object,
1347 - // but be passed in as the second argument to the $.jqplot() function.
1348 - // The data property is described here soley for reference.
1349 - // The data should be in the form of an array of 2D or 1D arrays like
1350 - // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ].
1351 - this.data = [];
1352 - // prop dataRenderer
1353 - // A callable which can be used to preprocess data passed into the plot.
1354 - // Will be called with 2 arguments, the plot data and a reference to the plot.
1355 - this.dataRenderer;
1356 - // prop dataRendererOptions
1357 - // Options that will be passed to the dataRenderer.
1358 - // Can be of any type.
1359 - this.dataRendererOptions;
1360 - // The id of the dom element to render the plot into
1361 - this.targetId = null;
1362 - // the jquery object for the dom target.
1363 - this.target = null;
1364 - this.defaults = {
1365 - // prop: axesDefaults
1366 - // default options that will be applied to all axes.
1367 - // see <Axis> for axes options.
1368 - axesDefaults: {},
1369 - axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}},
1370 - // prop: seriesDefaults
1371 - // default options that will be applied to all series.
1372 - // see <Series> for series options.
1373 - seriesDefaults: {},
1374 - gridPadding: {top:10, right:10, bottom:23, left:10},
1375 - series:[]
1376 - };
1377 - // prop: series
1378 - // Array of series object options.
1379 - // see <Series> for series specific options.
1380 - this.series = [];
1381 - // prop: axes
1382 - // up to 4 axes are supported, each with it's own options,
1383 - // See <Axis> for axis specific options.
1384 - 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')};
1385 - // prop: grid
1386 - // See <Grid> for grid specific options.
1387 - this.grid = new Grid();
1388 - // prop: legend
1389 - // see <$.jqplot.TableLegendRenderer>
1390 - this.legend = new Legend();
1391 - this.baseCanvas = new $.jqplot.GenericCanvas();
1392 - // array of series indicies. Keep track of order
1393 - // which series canvases are displayed, lowest
1394 - // to highest, back to front.
1395 - this.seriesStack = [];
1396 - this.previousSeriesStack = [];
1397 - this.eventCanvas = new $.jqplot.GenericCanvas();
1398 - this._width = null;
1399 - this._height = null;
1400 - this._plotDimensions = {height:null, width:null};
1401 - this._gridPadding = {top:10, right:10, bottom:10, left:10};
1402 - // a shortcut for axis syncTicks options. Not implemented yet.
1403 - this.syncXTicks = true;
1404 - // a shortcut for axis syncTicks options. Not implemented yet.
1405 - this.syncYTicks = true;
1406 - // prop: seriesColors
1407 - // Ann array of CSS color specifications that will be applied, in order,
1408 - // to the series in the plot. Colors will wrap around so, if their
1409 - // are more series than colors, colors will be reused starting at the
1410 - // beginning. For pie charts, this specifies the colors of the slices.
1411 - this.seriesColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"];
1412 - this.negativeSeriesColors = [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"];
1413 - // prop: sortData
1414 - // false to not sort the data passed in by the user.
1415 - // Many bar, stakced and other graphs as well as many plugins depend on
1416 - // having sorted data.
1417 - this.sortData = true;
1418 - var seriesColorsIndex = 0;
1419 - // prop textColor
1420 - // css spec for the css color attribute. Default for the entire plot.
1421 - this.textColor;
1422 - // prop; fontFamily
1423 - // css spec for the font-family attribute. Default for the entire plot.
1424 - this.fontFamily;
1425 - // prop: fontSize
1426 - // css spec for the font-size attribute. Default for the entire plot.
1427 - this.fontSize;
1428 - // prop: title
1429 - // Title object. See <Title> for specific options. As a shortcut, you
1430 - // can specify the title option as just a string like: title: 'My Plot'
1431 - // and this will create a new title object with the specified text.
1432 - this.title = new Title();
1433 - // container to hold all of the merged options. Convienence for plugins.
1434 - this.options = {};
1435 - // prop: stackSeries
1436 - // true or false, creates a stack or "mountain" plot.
1437 - // Not all series renderers may implement this option.
1438 - this.stackSeries = false;
1439 - // prop: defaultAxisStart
1440 - // 1-D data series are internally converted into 2-D [x,y] data point arrays
1441 - // by jqPlot. This is the default starting value for the missing x or y value.
1442 - // The added data will be a monotonically increasing series (e.g. [1, 2, 3, ...])
1443 - // starting at this value.
1444 - this.defaultAxisStart = 1;
1445 - // array to hold the cumulative stacked series data.
1446 - // used to ajust the individual series data, which won't have access to other
1447 - // series data.
1448 - this._stackData = [];
1449 - // array that holds the data to be plotted. This will be the series data
1450 - // merged with the the appropriate data from _stackData according to the stackAxis.
1451 - this._plotData = [];
1452 - // Namespece to hold plugins. Generally non-renderer plugins add themselves to here.
1453 - this.plugins = {};
1454 - // Count how many times the draw method has been called while the plot is visible.
1455 - // Mostly used to test if plot has never been dran (=0), has been successfully drawn
1456 - // into a visible container once (=1) or draw more than once into a visible container.
1457 - // Can use this in tests to see if plot has been visibly drawn at least one time.
1458 - // After plot has been visibly drawn once, it generally doesn't need redrawn if its
1459 - // container is hidden and shown.
1460 - this._drawCount = 0;
1461 - // this.doCustomEventBinding = true;
1462 - // prop: drawIfHidden
1463 - // True to execute the draw method even if the plot target is hidden.
1464 - // Generally, this should be false. Most plot elements will not be sized/
1465 - // positioned correclty if renderered into a hidden container. To render into
1466 - // a hidden container, call the replot method when the container is shown.
1467 - this.drawIfHidden = false;
1468 - // true to intercept right click events and fire a 'jqplotRightClick' event.
1469 - // this will also block the context menu.
1470 - this.captureRightClick = false;
1471 - this.themeEngine = new $.jqplot.ThemeEngine();
1472 - // sum of y values for all series in plot.
1473 - // used in mekko chart.
1474 - this._sumy = 0;
1475 - this._sumx = 0;
1476 - this.preInitHooks = new $.jqplot.HooksManager();
1477 - this.postInitHooks = new $.jqplot.HooksManager();
1478 - this.preParseOptionsHooks = new $.jqplot.HooksManager();
1479 - this.postParseOptionsHooks = new $.jqplot.HooksManager();
1480 - this.preDrawHooks = new $.jqplot.HooksManager();
1481 - this.postDrawHooks = new $.jqplot.HooksManager();
1482 - this.preDrawSeriesHooks = new $.jqplot.HooksManager();
1483 - this.postDrawSeriesHooks = new $.jqplot.HooksManager();
1484 - this.preDrawLegendHooks = new $.jqplot.HooksManager();
1485 - this.addLegendRowHooks = new $.jqplot.HooksManager();
1486 - this.preSeriesInitHooks = new $.jqplot.HooksManager();
1487 - this.postSeriesInitHooks = new $.jqplot.HooksManager();
1488 - this.preParseSeriesOptionsHooks = new $.jqplot.HooksManager();
1489 - this.postParseSeriesOptionsHooks = new $.jqplot.HooksManager();
1490 - this.eventListenerHooks = new $.jqplot.EventListenerManager();
1491 - this.preDrawSeriesShadowHooks = new $.jqplot.HooksManager();
1492 - this.postDrawSeriesShadowHooks = new $.jqplot.HooksManager();
1493 -
1494 - this.colorGenerator = $.jqplot.ColorGenerator;
1495 -
1496 - // Group: methods
1497 - //
1498 - // method: init
1499 - // sets the plot target, checks data and applies user
1500 - // options to plot.
1501 - this.init = function(target, data, options) {
1502 - for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
1503 - $.jqplot.preInitHooks[i].call(this, target, data, options);
1504 - }
1505 -
1506 - for (var i=0; i<this.preInitHooks.hooks.length; i++) {
1507 - this.preInitHooks.hooks[i].call(this, target, data, options);
1508 - }
1509 -
1510 - this.targetId = '#'+target;
1511 - this.target = $('#'+target);
1512 - // remove any error class that may be stuck on target.
1513 - this.target.removeClass('jqplot-error');
1514 - if (!this.target.get(0)) {
1515 - throw "No plot target specified";
1516 - }
1517 -
1518 - // make sure the target is positioned by some means and set css
1519 - if (this.target.css('position') == 'static') {
1520 - this.target.css('position', 'relative');
1521 - }
1522 - if (!this.target.hasClass('jqplot-target')) {
1523 - this.target.addClass('jqplot-target');
1524 - }
1525 -
1526 - // if no height or width specified, use a default.
1527 - if (!this.target.height()) {
1528 - var h;
1529 - if (options && options.height) {
1530 - h = parseInt(options.height, 10);
1531 - }
1532 - else if (this.target.attr('data-height')) {
1533 - h = parseInt(this.target.attr('data-height'), 10);
1534 - }
1535 - else {
1536 - h = parseInt($.jqplot.config.defaultHeight, 10);
1537 - }
1538 - this._height = h;
1539 - this.target.css('height', h+'px');
1540 - }
1541 - else {
1542 - this._height = this.target.height();
1543 - }
1544 - if (!this.target.width()) {
1545 - var w;
1546 - if (options && options.width) {
1547 - w = parseInt(options.width, 10);
1548 - }
1549 - else if (this.target.attr('data-width')) {
1550 - w = parseInt(this.target.attr('data-width'), 10);
1551 - }
1552 - else {
1553 - w = parseInt($.jqplot.config.defaultWidth, 10);
1554 - }
1555 - this._width = w;
1556 - this.target.css('width', w+'px');
1557 - }
1558 - else {
1559 - this._width = this.target.width();
1560 - }
1561 -
1562 - this._plotDimensions.height = this._height;
1563 - this._plotDimensions.width = this._width;
1564 - this.grid._plotDimensions = this._plotDimensions;
1565 - this.title._plotDimensions = this._plotDimensions;
1566 - this.baseCanvas._plotDimensions = this._plotDimensions;
1567 - this.eventCanvas._plotDimensions = this._plotDimensions;
1568 - this.legend._plotDimensions = this._plotDimensions;
1569 - if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
1570 - throw "Canvas dimension not set";
1571 - }
1572 -
1573 - if (options.dataRenderer && typeof(options.dataRenderer) == "function") {
1574 - if (options.dataRendererOptions) {
1575 - this.dataRendererOptions = options.dataRendererOptions;
1576 - }
1577 - this.dataRenderer = options.dataRenderer;
1578 - data = this.dataRenderer(data, this, this.dataRendererOptions);
1579 - }
1580 -
1581 - if (data == null) {
1582 - throw{
1583 - name: "DataError",
1584 - message: "No data to plot."
1585 - };
1586 - }
1587 -
1588 - if (data.constructor != Array || data.length == 0 || data[0].constructor != Array || data[0].length == 0) {
1589 - throw{
1590 - name: "DataError",
1591 - message: "No data to plot."
1592 - };
1593 - }
1594 -
1595 - this.data = data;
1596 -
1597 - this.parseOptions(options);
1598 -
1599 - if (this.textColor) {
1600 - this.target.css('color', this.textColor);
1601 - }
1602 - if (this.fontFamily) {
1603 - this.target.css('font-family', this.fontFamily);
1604 - }
1605 - if (this.fontSize) {
1606 - this.target.css('font-size', this.fontSize);
1607 - }
1608 -
1609 - this.title.init();
1610 - this.legend.init();
1611 - this._sumy = 0;
1612 - this._sumx = 0;
1613 - for (var i=0; i<this.series.length; i++) {
1614 - // set default stacking order for series canvases
1615 - this.seriesStack.push(i);
1616 - this.previousSeriesStack.push(i);
1617 - this.series[i].shadowCanvas._plotDimensions = this._plotDimensions;
1618 - this.series[i].canvas._plotDimensions = this._plotDimensions;
1619 - for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
1620 - $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this);
1621 - }
1622 - for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) {
1623 - this.preSeriesInitHooks.hooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this);
1624 - }
1625 - this.populatePlotData(this.series[i], i);
1626 - this.series[i]._plotDimensions = this._plotDimensions;
1627 - this.series[i].init(i, this.grid.borderWidth, this);
1628 - for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
1629 - $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this);
1630 - }
1631 - for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) {
1632 - this.postSeriesInitHooks.hooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i], this);
1633 - }
1634 - this._sumy += this.series[i]._sumy;
1635 - this._sumx += this.series[i]._sumx;
1636 - }
1637 -
1638 - for (var name in this.axes) {
1639 - this.axes[name]._plotDimensions = this._plotDimensions;
1640 - this.axes[name].init();
1641 - }
1642 -
1643 - if (this.sortData) {
1644 - sortData(this.series);
1645 - }
1646 - this.grid.init();
1647 - this.grid._axes = this.axes;
1648 -
1649 - this.legend._series = this.series;
1650 -
1651 - for (var i=0; i<$.jqplot.postInitHooks.length; i++) {
1652 - $.jqplot.postInitHooks[i].call(this, target, data, options);
1653 - }
1654 -
1655 - for (var i=0; i<this.postInitHooks.hooks.length; i++) {
1656 - this.postInitHooks.hooks[i].call(this, target, data, options);
1657 - }
1658 - };
1659 -
1660 - // method: resetAxesScale
1661 - // Reset the specified axes min, max, numberTicks and tickInterval properties to null
1662 - // or reset these properties on all axes if no list of axes is provided.
1663 - //
1664 - // Parameters:
1665 - // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset.
1666 - this.resetAxesScale = function(axes) {
1667 - var ax = (axes != undefined) ? axes : this.axes;
1668 - if (ax === true) {
1669 - ax = this.axes;
1670 - }
1671 - if (ax.constructor === Array) {
1672 - for (var i = 0; i < ax.length; i++) {
1673 - this.axes[ax[i]].resetScale();
1674 - }
1675 - }
1676 - else if (ax.constructor === Object) {
1677 - for (var name in ax) {
1678 - this.axes[name].resetScale();
1679 - }
1680 - }
1681 - };
1682 - // method: reInitialize
1683 - // reinitialize plot for replotting.
1684 - // not called directly.
1685 - this.reInitialize = function () {
1686 - // Plot should be visible and have a height and width.
1687 - // If plot doesn't have height and width for some
1688 - // reason, set it by other means. Plot must not have
1689 - // a display:none attribute, however.
1690 - if (!this.target.height()) {
1691 - var h;
1692 - if (options && options.height) {
1693 - h = parseInt(options.height, 10);
1694 - }
1695 - else if (this.target.attr('data-height')) {
1696 - h = parseInt(this.target.attr('data-height'), 10);
1697 - }
1698 - else {
1699 - h = parseInt($.jqplot.config.defaultHeight, 10);
1700 - }
1701 - this._height = h;
1702 - this.target.css('height', h+'px');
1703 - }
1704 - else {
1705 - this._height = this.target.height();
1706 - }
1707 - if (!this.target.width()) {
1708 - var w;
1709 - if (options && options.width) {
1710 - w = parseInt(options.width, 10);
1711 - }
1712 - else if (this.target.attr('data-width')) {
1713 - w = parseInt(this.target.attr('data-width'), 10);
1714 - }
1715 - else {
1716 - w = parseInt($.jqplot.config.defaultWidth, 10);
1717 - }
1718 - this._width = w;
1719 - this.target.css('width', w+'px');
1720 - }
1721 - else {
1722 - this._width = this.target.width();
1723 - }
1724 -
1725 - if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
1726 - throw "Target dimension not set";
1727 - }
1728 -
1729 - this._plotDimensions.height = this._height;
1730 - this._plotDimensions.width = this._width;
1731 - this.grid._plotDimensions = this._plotDimensions;
1732 - this.title._plotDimensions = this._plotDimensions;
1733 - this.baseCanvas._plotDimensions = this._plotDimensions;
1734 - this.eventCanvas._plotDimensions = this._plotDimensions;
1735 - this.legend._plotDimensions = this._plotDimensions;
1736 -
1737 - for (var n in this.axes) {
1738 - this.axes[n]._plotWidth = this._width;
1739 - this.axes[n]._plotHeight = this._height;
1740 - }
1741 -
1742 - this.title._plotWidth = this._width;
1743 -
1744 - if (this.textColor) {
1745 - this.target.css('color', this.textColor);
1746 - }
1747 - if (this.fontFamily) {
1748 - this.target.css('font-family', this.fontFamily);
1749 - }
1750 - if (this.fontSize) {
1751 - this.target.css('font-size', this.fontSize);
1752 - }
1753 -
1754 - this._sumy = 0;
1755 - this._sumx = 0;
1756 - for (var i=0; i<this.series.length; i++) {
1757 - this.populatePlotData(this.series[i], i);
1758 - this.series[i]._plotDimensions = this._plotDimensions;
1759 - this.series[i].canvas._plotDimensions = this._plotDimensions;
1760 - //this.series[i].init(i, this.grid.borderWidth);
1761 - this._sumy += this.series[i]._sumy;
1762 - this._sumx += this.series[i]._sumx;
1763 - }
1764 -
1765 - for (var name in this.axes) {
1766 - this.axes[name]._plotDimensions = this._plotDimensions;
1767 - this.axes[name]._ticks = [];
1768 - this.axes[name].renderer.init.call(this.axes[name], {});
1769 - }
1770 -
1771 - if (this.sortData) {
1772 - sortData(this.series);
1773 - }
1774 -
1775 - this.grid._axes = this.axes;
1776 -
1777 - this.legend._series = this.series;
1778 - };
1779 -
1780 - // sort the series data in increasing order.
1781 - function sortData(series) {
1782 - var d, sd, pd, ppd, ret;
1783 - for (var i=0; i<series.length; i++) {
1784 - // d = series[i].data;
1785 - // sd = series[i]._stackData;
1786 - // pd = series[i]._plotData;
1787 - // ppd = series[i]._prevPlotData;
1788 - var check;
1789 - var bat = [series[i].data, series[i]._stackData, series[i]._plotData, series[i]._prevPlotData];
1790 - for (var n=0; n<4; n++) {
1791 - check = true;
1792 - d = bat[n];
1793 - if (series[i]._stackAxis == 'x') {
1794 - for (var j = 0; j < d.length; j++) {
1795 - if (typeof(d[j][1]) != "number") {
1796 - check = false;
1797 - break;
1798 - }
1799 - }
1800 - if (check) {
1801 - d.sort(function(a,b) { return a[1] - b[1]; });
1802 - // sd.sort(function(a,b) { return a[1] - b[1]; });
1803 - // pd.sort(function(a,b) { return a[1] - b[1]; });
1804 - // ppd.sort(function(a,b) { return a[1] - b[1]; });
1805 - }
1806 - }
1807 - else {
1808 - for (var j = 0; j < d.length; j++) {
1809 - if (typeof(d[j][0]) != "number") {
1810 - check = false;
1811 - break;
1812 - }
1813 - }
1814 - if (check) {
1815 - d.sort(function(a,b) { return a[0] - b[0]; });
1816 - // sd.sort(function(a,b) { return a[0] - b[0]; });
1817 - // pd.sort(function(a,b) { return a[0] - b[0]; });
1818 - // ppd.sort(function(a,b) { return a[0] - b[0]; });
1819 - }
1820 - }
1821 - }
1822 -
1823 - }
1824 - }
1825 -
1826 - // populate the _stackData and _plotData arrays for the plot and the series.
1827 - this.populatePlotData = function(series, index) {
1828 - // if a stacked chart, compute the stacked data
1829 - this._plotData = [];
1830 - this._stackData = [];
1831 - series._stackData = [];
1832 - series._plotData = [];
1833 - var plotValues = {x:[], y:[]};
1834 - if (this.stackSeries && !series.disableStack) {
1835 - series._stack = true;
1836 - var sidx = series._stackAxis == 'x' ? 0 : 1;
1837 - var idx = sidx ? 0 : 1;
1838 - // push the current data into stackData
1839 - //this._stackData.push(this.series[i].data);
1840 - var temp = $.extend(true, [], series.data);
1841 - // create the data that will be plotted for this series
1842 - var plotdata = $.extend(true, [], series.data);
1843 - // for first series, nothing to add to stackData.
1844 - for (var j=0; j<index; j++) {
1845 - var cd = this.series[j].data;
1846 - for (var k=0; k<cd.length; k++) {
1847 - temp[k][0] += cd[k][0];
1848 - temp[k][1] += cd[k][1];
1849 - // only need to sum up the stack axis column of data
1850 - plotdata[k][sidx] += cd[k][sidx];
1851 - }
1852 - }
1853 - for (var i=0; i<plotdata.length; i++) {
1854 - plotValues.x.push(plotdata[i][0]);
1855 - plotValues.y.push(plotdata[i][1]);
1856 - }
1857 - this._plotData.push(plotdata);
1858 - this._stackData.push(temp);
1859 - series._stackData = temp;
1860 - series._plotData = plotdata;
1861 - series._plotValues = plotValues;
1862 - }
1863 - else {
1864 - for (var i=0; i<series.data.length; i++) {
1865 - plotValues.x.push(series.data[i][0]);
1866 - plotValues.y.push(series.data[i][1]);
1867 - }
1868 - this._stackData.push(series.data);
1869 - this.series[index]._stackData = series.data;
1870 - this._plotData.push(series.data);
1871 - series._plotData = series.data;
1872 - series._plotValues = plotValues;
1873 - }
1874 - if (index>0) {
1875 - series._prevPlotData = this.series[index-1]._plotData;
1876 - }
1877 - series._sumy = 0;
1878 - series._sumx = 0;
1879 - for (i=series.data.length-1; i>-1; i--) {
1880 - series._sumy += series.data[i][1];
1881 - series._sumx += series.data[i][0];
1882 - }
1883 - };
1884 -
1885 - // function to safely return colors from the color array and wrap around at the end.
1886 - this.getNextSeriesColor = (function(t) {
1887 - var idx = 0;
1888 - var sc = t.seriesColors;
1889 -
1890 - return function () {
1891 - if (idx < sc.length) {
1892 - return sc[idx++];
1893 - }
1894 - else {
1895 - idx = 0;
1896 - return sc[idx++];
1897 - }
1898 - };
1899 - })(this);
1900 -
1901 - this.parseOptions = function(options){
1902 - for (var i=0; i<this.preParseOptionsHooks.hooks.length; i++) {
1903 - this.preParseOptionsHooks.hooks[i].call(this, options);
1904 - }
1905 - for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) {
1906 - $.jqplot.preParseOptionsHooks[i].call(this, options);
1907 - }
1908 - this.options = $.extend(true, {}, this.defaults, options);
1909 - this.stackSeries = this.options.stackSeries;
1910 - if (this.options.seriesColors) {
1911 - this.seriesColors = this.options.seriesColors;
1912 - }
1913 - if (this.options.negativeSeriesColors) {
1914 - this.negativeSeriesColors = this.options.negativeSeriesColors;
1915 - }
1916 - if (this.options.captureRightClick) {
1917 - this.captureRightClick = this.options.captureRightClick;
1918 - }
1919 - this.defaultAxisStart = (options && options.defaultAxisStart != null) ? options.defaultAxisStart : this.defaultAxisStart;
1920 - var cg = new this.colorGenerator(this.seriesColors);
1921 - // this._gridPadding = this.options.gridPadding;
1922 - $.extend(true, this._gridPadding, this.options.gridPadding);
1923 - this.sortData = (this.options.sortData != null) ? this.options.sortData : this.sortData;
1924 - for (var n in this.axes) {
1925 - var axis = this.axes[n];
1926 - $.extend(true, axis, this.options.axesDefaults, this.options.axes[n]);
1927 - axis._plotWidth = this._width;
1928 - axis._plotHeight = this._height;
1929 - }
1930 - if (this.data.length == 0) {
1931 - this.data = [];
1932 - for (var i=0; i<this.options.series.length; i++) {
1933 - this.data.push(this.options.series.data);
1934 - }
1935 - }
1936 -
1937 - var normalizeData = function(data, dir, start) {
1938 - // return data as an array of point arrays,
1939 - // in form [[x1,y1...], [x2,y2...], ...]
1940 - var temp = [];
1941 - var i;
1942 - dir = dir || 'vertical';
1943 - if (!(data[0] instanceof Array)) {
1944 - // we have a series of scalars. One line with just y values.
1945 - // turn the scalar list of data into a data array of form:
1946 - // [[1, data[0]], [2, data[1]], ...]
1947 - for (i=0; i<data.length; i++) {
1948 - if (dir == 'vertical') {
1949 - temp.push([start + i, data[i]]);
1950 - }
1951 - else {
1952 - temp.push([data[i], start+i]);
1953 - }
1954 - }
1955 - }
1956 - else {
1957 - // we have a properly formatted data series, copy it.
1958 - $.extend(true, temp, data);
1959 - }
1960 - return temp;
1961 - };
1962 -
1963 - for (var i=0; i<this.data.length; i++) {
1964 - var temp = new Series();
1965 - for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) {
1966 - $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
1967 - }
1968 - for (var j=0; j<this.preParseSeriesOptionsHooks.hooks.length; j++) {
1969 - this.preParseSeriesOptionsHooks.hooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
1970 - }
1971 - $.extend(true, temp, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i]);
1972 - var dir = 'vertical';
1973 - if (temp.renderer.constructor == $.jqplot.barRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') {
1974 - dir = 'horizontal';
1975 - }
1976 - temp.data = normalizeData(this.data[i], dir, this.defaultAxisStart);
1977 - switch (temp.xaxis) {
1978 - case 'xaxis':
1979 - temp._xaxis = this.axes.xaxis;
1980 - break;
1981 - case 'x2axis':
1982 - temp._xaxis = this.axes.x2axis;
1983 - break;
1984 - default:
1985 - break;
1986 - }
1987 - temp._yaxis = this.axes[temp.yaxis];
1988 - temp._xaxis._series.push(temp);
1989 - temp._yaxis._series.push(temp);
1990 - if (temp.show) {
1991 - temp._xaxis.show = true;
1992 - temp._yaxis.show = true;
1993 - }
1994 -
1995 - // parse the renderer options and apply default colors if not provided
1996 - if (!temp.color && temp.show != false) {
1997 - temp.color = cg.next();
1998 - }
1999 - if (!temp.label) {
2000 - temp.label = 'Series '+ (i+1).toString();
2001 - }
2002 - // temp.rendererOptions.show = temp.show;
2003 - // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions);
2004 - this.series.push(temp);
2005 - for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) {
2006 - $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
2007 - }
2008 - for (var j=0; j<this.postParseSeriesOptionsHooks.hooks.length; j++) {
2009 - this.postParseSeriesOptionsHooks.hooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
2010 - }
2011 - }
2012 -
2013 - // copy the grid and title options into this object.
2014 - $.extend(true, this.grid, this.options.grid);
2015 - // if axis border properties aren't set, set default.
2016 - for (var n in this.axes) {
2017 - var axis = this.axes[n];
2018 - if (axis.borderWidth == null) {
2019 - axis.borderWidth =this.grid.borderWidth;
2020 - }
2021 - if (axis.borderColor == null) {
2022 - if (n != 'xaxis' && n != 'x2axis' && axis.useSeriesColor === true && axis.show) {
2023 - axis.borderColor = axis._series[0].color;
2024 - }
2025 - else {
2026 - axis.borderColor = this.grid.borderColor;
2027 - }
2028 - }
2029 - }
2030 -
2031 - if (typeof this.options.title == 'string') {
2032 - this.title.text = this.options.title;
2033 - }
2034 - else if (typeof this.options.title == 'object') {
2035 - $.extend(true, this.title, this.options.title);
2036 - }
2037 - this.title._plotWidth = this._width;
2038 - this.legend.setOptions(this.options.legend);
2039 -
2040 - for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) {
2041 - $.jqplot.postParseOptionsHooks[i].call(this, options);
2042 - }
2043 - for (var i=0; i<this.postParseOptionsHooks.hooks.length; i++) {
2044 - this.postParseOptionsHooks.hooks[i].call(this, options);
2045 - }
2046 - };
2047 -
2048 - // method: replot
2049 - // Does a reinitialization of the plot followed by
2050 - // a redraw. Method could be used to interactively
2051 - // change plot characteristics and then replot.
2052 - //
2053 - // Parameters:
2054 - // options - Options used for replotting.
2055 - //
2056 - // Properties:
2057 - // clear - false to not clear (empty) the plot container before replotting (default: true).
2058 - // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves.
2059 - // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false).
2060 - this.replot = function(options) {
2061 - var opts = (options != undefined) ? options : {};
2062 - var clear = (opts.clear != undefined) ? opts.clear : true;
2063 - var resetAxes = (opts.resetAxes != undefined) ? opts.resetAxes : false;
2064 - this.target.trigger('jqplotPreReplot');
2065 - if (clear) {
2066 - this.target.empty();
2067 - }
2068 - if (resetAxes) {
2069 - this.resetAxesScale(resetAxes);
2070 - }
2071 - this.reInitialize();
2072 - this.draw();
2073 - this.target.trigger('jqplotPostReplot');
2074 - };
2075 -
2076 - // method: redraw
2077 - // Empties the plot target div and redraws the plot.
2078 - // This enables plot data and properties to be changed
2079 - // and then to comletely clear the plot and redraw.
2080 - // redraw *will not* reinitialize any plot elements.
2081 - // That is, axes will not be autoscaled and defaults
2082 - // will not be reapplied to any plot elements. redraw
2083 - // is used primarily with zooming.
2084 - //
2085 - // Parameters:
2086 - // clear - false to not clear (empty) the plot container before redrawing (default: true).
2087 - this.redraw = function(clear) {
2088 - clear = (clear != null) ? clear : true;
2089 - this.target.trigger('jqplotPreRedraw');
2090 - if (clear) {
2091 - this.target.empty();
2092 - }
2093 - for (var ax in this.axes) {
2094 - this.axes[ax]._ticks = [];
2095 - }
2096 - for (var i=0; i<this.series.length; i++) {
2097 - this.populatePlotData(this.series[i], i);
2098 - }
2099 - this._sumy = 0;
2100 - this._sumx = 0;
2101 - for (i=0; i<this.series.length; i++) {
2102 - this._sumy += this.series[i]._sumy;
2103 - this._sumx += this.series[i]._sumx;
2104 - }
2105 - this.draw();
2106 - this.target.trigger('jqplotPostRedraw');
2107 - };
2108 -
2109 - // method: draw
2110 - // Draws all elements of the plot into the container.
2111 - // Does not clear the container before drawing.
2112 - this.draw = function(){
2113 - if (this.drawIfHidden || this.target.is(':visible')) {
2114 - this.target.trigger('jqplotPreDraw');
2115 - var i, j;
2116 - for (i=0; i<$.jqplot.preDrawHooks.length; i++) {
2117 - $.jqplot.preDrawHooks[i].call(this);
2118 - }
2119 - for (i=0; i<this.preDrawHooks.hooks.length; i++) {
2120 - this.preDrawHooks.hooks[i].call(this);
2121 - }
2122 - // create an underlying canvas to be used for special features.
2123 - this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas'));
2124 - this.baseCanvas.setContext();
2125 - this.target.append(this.title.draw());
2126 - this.title.pack({top:0, left:0});
2127 -
2128 - // make room for the legend between the grid and the edge.
2129 - var legendElem = this.legend.draw();
2130 -
2131 - var gridPadding = {top:0, left:0, bottom:0, right:0};
2132 -
2133 - if (this.legend.placement == "outsideGrid") {
2134 - // temporarily append the legend to get dimensions
2135 - this.target.append(legendElem);
2136 - switch (this.legend.location) {
2137 - case 'n':
2138 - gridPadding.top += this.legend.getHeight();
2139 - break;
2140 - case 's':
2141 - gridPadding.bottom += this.legend.getHeight();
2142 - break;
2143 - case 'ne':
2144 - case 'e':
2145 - case 'se':
2146 - gridPadding.right += this.legend.getWidth();
2147 - break;
2148 - case 'nw':
2149 - case 'w':
2150 - case 'sw':
2151 - gridPadding.left += this.legend.getWidth();
2152 - break;
2153 - default: // same as 'ne'
2154 - gridPadding.right += this.legend.getWidth();
2155 - break;
2156 - }
2157 - legendElem = legendElem.detach();
2158 - }
2159 -
2160 - var ax = this.axes;
2161 - for (var name in ax) {
2162 - this.target.append(ax[name].draw(this.baseCanvas._ctx));
2163 - ax[name].set();
2164 - }
2165 - if (ax.yaxis.show) {
2166 - gridPadding.left += ax.yaxis.getWidth();
2167 - }
2168 - var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
2169 - var rapad = [0, 0, 0, 0, 0, 0, 0, 0];
2170 - var gpr = 0;
2171 - var n;
2172 - for (n=0; n<8; n++) {
2173 - if (ax[ra[n]].show) {
2174 - gpr += ax[ra[n]].getWidth();
2175 - rapad[n] = gpr;
2176 - }
2177 - }
2178 - gridPadding.right += gpr;
2179 - if (ax.x2axis.show) {
2180 - gridPadding.top += ax.x2axis.getHeight();
2181 - }
2182 - if (this.title.show) {
2183 - gridPadding.top += this.title.getHeight();
2184 - }
2185 - if (ax.xaxis.show) {
2186 - gridPadding.bottom += ax.xaxis.getHeight();
2187 - }
2188 -
2189 - // end of gridPadding adjustments.
2190 - var arr = ['top', 'bottom', 'left', 'right'];
2191 - for (var n in arr) {
2192 - if (gridPadding[arr[n]]) {
2193 - this._gridPadding[arr[n]] = gridPadding[arr[n]];
2194 - }
2195 - }
2196 -
2197 - var legendPadding = (this.legend.placement == 'outsideGrid') ? {top:this.title.getHeight(), left: 0, right: 0, bottom: 0} : this._gridPadding;
2198 -
2199 - 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});
2200 - 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});
2201 - 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});
2202 - for (i=8; i>0; i--) {
2203 - 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});
2204 - }
2205 - // ax.y2axis.pack({position:'absolute', top:0, right:0}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
2206 -
2207 - this.target.append(this.grid.createElement(this._gridPadding));
2208 - this.grid.draw();
2209 -
2210 - // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars.
2211 - for (i=0; i<this.series.length; i++) {
2212 - // draw series in order of stacking. This affects only
2213 - // order in which canvases are added to dom.
2214 - j = this.seriesStack[i];
2215 - this.target.append(this.series[j].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-shadowCanvas'));
2216 - this.series[j].shadowCanvas.setContext();
2217 - this.series[j].shadowCanvas._elem.data('seriesIndex', j);
2218 - }
2219 -
2220 - for (i=0; i<this.series.length; i++) {
2221 - // draw series in order of stacking. This affects only
2222 - // order in which canvases are added to dom.
2223 - j = this.seriesStack[i];
2224 - this.target.append(this.series[j].canvas.createElement(this._gridPadding, 'jqplot-series-canvas'));
2225 - this.series[j].canvas.setContext();
2226 - this.series[j].canvas._elem.data('seriesIndex', j);
2227 - }
2228 - // Need to use filled canvas to capture events in IE.
2229 - // Also, canvas seems to block selection of other elements in document on FF.
2230 - this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas'));
2231 - this.eventCanvas.setContext();
2232 - this.eventCanvas._ctx.fillStyle = 'rgba(0,0,0,0)';
2233 - this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width, this.eventCanvas._ctx.canvas.height);
2234 -
2235 - // bind custom event handlers to regular events.
2236 - this.bindCustomEvents();
2237 -
2238 - // draw legend before series if the series needs to know the legend dimensions.
2239 - if (this.legend.preDraw) {
2240 - this.eventCanvas._elem.before(legendElem);
2241 - this.legend.pack(legendPadding);
2242 - if (this.legend._elem) {
2243 - 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}});
2244 - }
2245 - else {
2246 - this.drawSeries();
2247 - }
2248 - }
2249 - else { // draw series before legend
2250 - this.drawSeries();
2251 - $(this.series[this.series.length-1].canvas._elem).after(legendElem);
2252 - this.legend.pack(legendPadding);
2253 - }
2254 -
2255 - // register event listeners on the overlay canvas
2256 - for (var i=0; i<$.jqplot.eventListenerHooks.length; i++) {
2257 - // in the handler, this will refer to the eventCanvas dom element.
2258 - // make sure there are references back into plot objects.
2259 - this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
2260 - }
2261 -
2262 - // register event listeners on the overlay canvas
2263 - for (var i=0; i<this.eventListenerHooks.hooks.length; i++) {
2264 - // in the handler, this will refer to the eventCanvas dom element.
2265 - // make sure there are references back into plot objects.
2266 - this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[i][0], {plot:this}, this.eventListenerHooks.hooks[i][1]);
2267 - }
2268 -
2269 - for (var i=0; i<$.jqplot.postDrawHooks.length; i++) {
2270 - $.jqplot.postDrawHooks[i].call(this);
2271 - }
2272 -
2273 - for (var i=0; i<this.postDrawHooks.hooks.length; i++) {
2274 - this.postDrawHooks.hooks[i].call(this);
2275 - }
2276 -
2277 - if (this.target.is(':visible')) {
2278 - this._drawCount += 1;
2279 - }
2280 -
2281 - this.target.trigger('jqplotPostDraw', [this]);
2282 - }
2283 - };
2284 -
2285 - this.bindCustomEvents = function() {
2286 - this.eventCanvas._elem.bind('click', {plot:this}, this.onClick);
2287 - this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
2288 - this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown);
2289 - this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove);
2290 - this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
2291 - this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
2292 - if (this.captureRightClick) {
2293 - this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onRightClick);
2294 - this.eventCanvas._elem.get(0).oncontextmenu = function() {
2295 - return false;
2296 - };
2297 - }
2298 - else {
2299 - this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp);
2300 - }
2301 - };
2302 -
2303 - function getEventPosition(ev) {
2304 - var plot = ev.data.plot;
2305 - var go = plot.eventCanvas._elem.offset();
2306 - var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
2307 - var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null};
2308 - var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
2309 - var ax = plot.axes;
2310 - var n, axis;
2311 - for (n=11; n>0; n--) {
2312 - axis = an[n-1];
2313 - if (ax[axis].show) {
2314 - dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
2315 - }
2316 - }
2317 -
2318 - return {offsets:go, gridPos:gridPos, dataPos:dataPos};
2319 - }
2320 -
2321 -
2322 - // function to check if event location is over a area area
2323 - function checkIntersection(gridpos, plot) {
2324 - var series = plot.series;
2325 - var i, j, k, s, r, x, y, theta, sm, sa, minang, maxang;
2326 - var d0, d, p, pp, points, bw;
2327 - var threshold, t;
2328 - for (k=plot.seriesStack.length-1; k>=0; k--) {
2329 - i = plot.seriesStack[k];
2330 - s = series[i];
2331 - switch (s.renderer.constructor) {
2332 - case $.jqplot.BarRenderer:
2333 - x = gridpos.x;
2334 - y = gridpos.y;
2335 - for (j=s.gridData.length-1; j>=0; j--) {
2336 - points = s._barPoints[j];
2337 - if (x>points[0][0] && x<points[2][0] && y>points[2][1] && y<points[0][1]) {
2338 - return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]};
2339 - }
2340 - }
2341 - break;
2342 -
2343 - case $.jqplot.DonutRenderer:
2344 - sa = s.startAngle/180*Math.PI;
2345 - x = gridpos.x - s._center[0];
2346 - y = gridpos.y - s._center[1];
2347 - r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
2348 - if (x > 0 && -y >= 0) {
2349 - theta = 2*Math.PI - Math.atan(-y/x);
2350 - }
2351 - else if (x > 0 && -y < 0) {
2352 - theta = -Math.atan(-y/x);
2353 - }
2354 - else if (x < 0) {
2355 - theta = Math.PI - Math.atan(-y/x);
2356 - }
2357 - else if (x == 0 && -y > 0) {
2358 - theta = 3*Math.PI/2;
2359 - }
2360 - else if (x == 0 && -y < 0) {
2361 - theta = Math.PI/2;
2362 - }
2363 - else if (x == 0 && y == 0) {
2364 - theta = 0;
2365 - }
2366 - if (sa) {
2367 - theta -= sa;
2368 - if (theta < 0) {
2369 - theta += 2*Math.PI;
2370 - }
2371 - else if (theta > 2*Math.PI) {
2372 - theta -= 2*Math.PI;
2373 - }
2374 - }
2375 -
2376 - sm = s.sliceMargin/180*Math.PI;
2377 - if (r < s._radius && r > s._innerRadius) {
2378 - for (j=0; j<s.gridData.length; j++) {
2379 - minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
2380 - maxang = s.gridData[j][1];
2381 - if (theta > minang && theta < maxang) {
2382 - return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
2383 - }
2384 - }
2385 - }
2386 - break;
2387 -
2388 - case $.jqplot.PieRenderer:
2389 - sa = s.startAngle/180*Math.PI;
2390 - x = gridpos.x - s._center[0];
2391 - y = gridpos.y - s._center[1];
2392 - r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
2393 - if (x > 0 && -y >= 0) {
2394 - theta = 2*Math.PI - Math.atan(-y/x);
2395 - }
2396 - else if (x > 0 && -y < 0) {
2397 - theta = -Math.atan(-y/x);
2398 - }
2399 - else if (x < 0) {
2400 - theta = Math.PI - Math.atan(-y/x);
2401 - }
2402 - else if (x == 0 && -y > 0) {
2403 - theta = 3*Math.PI/2;
2404 - }
2405 - else if (x == 0 && -y < 0) {
2406 - theta = Math.PI/2;
2407 - }
2408 - else if (x == 0 && y == 0) {
2409 - theta = 0;
2410 - }
2411 - if (sa) {
2412 - theta -= sa;
2413 - if (theta < 0) {
2414 - theta += 2*Math.PI;
2415 - }
2416 - else if (theta > 2*Math.PI) {
2417 - theta -= 2*Math.PI;
2418 - }
2419 - }
2420 -
2421 - sm = s.sliceMargin/180*Math.PI;
2422 - if (r < s._radius) {
2423 - for (j=0; j<s.gridData.length; j++) {
2424 - minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
2425 - maxang = s.gridData[j][1];
2426 - if (theta > minang && theta < maxang) {
2427 - return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
2428 - }
2429 - }
2430 - }
2431 - break;
2432 -
2433 - case $.jqplot.BubbleRenderer:
2434 - x = gridpos.x;
2435 - y = gridpos.y;
2436 - var ret = null;
2437 -
2438 - if (s.show) {
2439 - for (var j=0; j<s.gridData.length; j++) {
2440 - p = s.gridData[j];
2441 - d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
2442 - if (d <= p[2] && (d <= d0 || d0 == null)) {
2443 - d0 = d;
2444 - ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2445 - }
2446 - }
2447 - if (ret != null) return ret;
2448 - }
2449 - break;
2450 -
2451 - case $.jqplot.FunnelRenderer:
2452 - x = gridpos.x;
2453 - y = gridpos.y;
2454 - var v = s._vertices,
2455 - vfirst = v[0],
2456 - vlast = v[v.length-1],
2457 - lex,
2458 - rex;
2459 -
2460 - // equations of right and left sides, returns x, y values given height of section (y value and 2 points)
2461 -
2462 - function findedge (l, p1 , p2) {
2463 - var m = (p1[1] - p2[1])/(p1[0] - p2[0]);
2464 - var b = p1[1] - m*p1[0];
2465 - var y = l + p1[1];
2466 -
2467 - return [(y - b)/m, y];
2468 - }
2469 -
2470 - // check each section
2471 - lex = findedge(y, vfirst[0], vlast[3]);
2472 - rex = findedge(y, vfirst[1], vlast[2]);
2473 - for (j=0; j<v.length; j++) {
2474 - cv = v[j];
2475 - if (y >= cv[0][1] && y <= cv[3][1] && x >= lex[0] && x <= rex[0]) {
2476 - return {seriesIndex:s.index, pointIndex:j, gridData:null, data:s.data[j]};
2477 - }
2478 - }
2479 - break;
2480 -
2481 - case $.jqplot.LineRenderer:
2482 - x = gridpos.x;
2483 - y = gridpos.y;
2484 - r = s.renderer;
2485 - if (s.show) {
2486 - if (s.fill) {
2487 - // first check if it is in bounding box
2488 - var inside = false;
2489 - if (x>s._boundingBox[0][0] && x<s._boundingBox[1][0] && y>s._boundingBox[1][1] && y<s._boundingBox[0][1]) {
2490 - // now check the crossing number
2491 -
2492 - var numPoints = s._areaPoints.length;
2493 - var ii;
2494 - var j = numPoints-1;
2495 -
2496 - for(var ii=0; ii < numPoints; ii++) {
2497 - var vertex1 = [s._areaPoints[ii][0], s._areaPoints[ii][1]];
2498 - var vertex2 = [s._areaPoints[j][0], s._areaPoints[j][1]];
2499 -
2500 - if (vertex1[1] < y && vertex2[1] >= y || vertex2[1] < y && vertex1[1] >= y) {
2501 - if (vertex1[0] + (y - vertex1[1]) / (vertex2[1] - vertex1[1]) * (vertex2[0] - vertex1[0]) < x) {
2502 - inside = !inside;
2503 - }
2504 - }
2505 -
2506 - j = ii;
2507 - }
2508 - }
2509 - if (inside) {
2510 - return {seriesIndex:i, pointIndex:null, gridData:s.gridData, data:s.data, points:s._areaPoints};
2511 - }
2512 - break;
2513 -
2514 - }
2515 - else {
2516 - t = s.markerRenderer.size/2+s.neighborThreshold;
2517 - threshold = (t > 0) ? t : 0;
2518 - for (var j=0; j<s.gridData.length; j++) {
2519 - p = s.gridData[j];
2520 - // neighbor looks different to OHLC chart.
2521 - if (r.constructor == $.jqplot.OHLCRenderer) {
2522 - if (r.candleStick) {
2523 - var yp = s._yaxis.series_u2p;
2524 - 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])) {
2525 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2526 - }
2527 - }
2528 - // if an open hi low close chart
2529 - else if (!r.hlc){
2530 - var yp = s._yaxis.series_u2p;
2531 - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
2532 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2533 - }
2534 - }
2535 - // a hi low close chart
2536 - else {
2537 - var yp = s._yaxis.series_u2p;
2538 - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
2539 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2540 - }
2541 - }
2542 -
2543 - }
2544 - else if (p[0] != null && p[1] != null){
2545 - d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
2546 - if (d <= threshold && (d <= d0 || d0 == null)) {
2547 - d0 = d;
2548 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2549 - }
2550 - }
2551 - }
2552 - }
2553 - }
2554 - break;
2555 -
2556 - default:
2557 - x = gridpos.x;
2558 - y = gridpos.y;
2559 - r = s.renderer;
2560 - if (s.show) {
2561 - t = s.markerRenderer.size/2+s.neighborThreshold;
2562 - threshold = (t > 0) ? t : 0;
2563 - for (var j=0; j<s.gridData.length; j++) {
2564 - p = s.gridData[j];
2565 - // neighbor looks different to OHLC chart.
2566 - if (r.constructor == $.jqplot.OHLCRenderer) {
2567 - if (r.candleStick) {
2568 - var yp = s._yaxis.series_u2p;
2569 - 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])) {
2570 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2571 - }
2572 - }
2573 - // if an open hi low close chart
2574 - else if (!r.hlc){
2575 - var yp = s._yaxis.series_u2p;
2576 - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
2577 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2578 - }
2579 - }
2580 - // a hi low close chart
2581 - else {
2582 - var yp = s._yaxis.series_u2p;
2583 - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
2584 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2585 - }
2586 - }
2587 -
2588 - }
2589 - else {
2590 - d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
2591 - if (d <= threshold && (d <= d0 || d0 == null)) {
2592 - d0 = d;
2593 - return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
2594 - }
2595 - }
2596 - }
2597 - }
2598 - break;
2599 - }
2600 - }
2601 -
2602 - return null;
2603 - }
2604 -
2605 -
2606 -
2607 - this.onClick = function(ev) {
2608 - // Event passed in is normalized and will have data attribute.
2609 - // Event passed out is unnormalized.
2610 - var positions = getEventPosition(ev);
2611 - var p = ev.data.plot;
2612 - var neighbor = checkIntersection(positions.gridPos, p);
2613 - var evt = jQuery.Event('jqplotClick');
2614 - evt.pageX = ev.pageX;
2615 - evt.pageY = ev.pageY;
2616 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2617 - };
2618 -
2619 - this.onDblClick = function(ev) {
2620 - // Event passed in is normalized and will have data attribute.
2621 - // Event passed out is unnormalized.
2622 - var positions = getEventPosition(ev);
2623 - var p = ev.data.plot;
2624 - var neighbor = checkIntersection(positions.gridPos, p);
2625 - var evt = jQuery.Event('jqplotDblClick');
2626 - evt.pageX = ev.pageX;
2627 - evt.pageY = ev.pageY;
2628 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2629 - };
2630 -
2631 - this.onMouseDown = function(ev) {
2632 - var positions = getEventPosition(ev);
2633 - var p = ev.data.plot;
2634 - var neighbor = checkIntersection(positions.gridPos, p);
2635 - var evt = jQuery.Event('jqplotMouseDown');
2636 - evt.pageX = ev.pageX;
2637 - evt.pageY = ev.pageY;
2638 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2639 - };
2640 -
2641 - this.onMouseUp = function(ev) {
2642 - var positions = getEventPosition(ev);
2643 - var evt = jQuery.Event('jqplotMouseUp');
2644 - evt.pageX = ev.pageX;
2645 - evt.pageY = ev.pageY;
2646 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, ev.data.plot]);
2647 - };
2648 -
2649 - this.onRightClick = function(ev) {
2650 - var positions = getEventPosition(ev);
2651 - var p = ev.data.plot;
2652 - var neighbor = checkIntersection(positions.gridPos, p);
2653 - if (p.captureRightClick) {
2654 - if (ev.which == 3) {
2655 - var evt = jQuery.Event('jqplotRightClick');
2656 - evt.pageX = ev.pageX;
2657 - evt.pageY = ev.pageY;
2658 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2659 - }
2660 - else {
2661 - var evt = jQuery.Event('jqplotMouseUp');
2662 - evt.pageX = ev.pageX;
2663 - evt.pageY = ev.pageY;
2664 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2665 - }
2666 - }
2667 - };
2668 -
2669 - this.onMouseMove = function(ev) {
2670 - var positions = getEventPosition(ev);
2671 - var p = ev.data.plot;
2672 - var neighbor = checkIntersection(positions.gridPos, p);
2673 - var evt = jQuery.Event('jqplotMouseMove');
2674 - evt.pageX = ev.pageX;
2675 - evt.pageY = ev.pageY;
2676 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
2677 - };
2678 -
2679 - this.onMouseEnter = function(ev) {
2680 - var positions = getEventPosition(ev);
2681 - var p = ev.data.plot;
2682 - var evt = jQuery.Event('jqplotMouseEnter');
2683 - evt.pageX = ev.pageX;
2684 - evt.pageY = ev.pageY;
2685 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
2686 - };
2687 -
2688 - this.onMouseLeave = function(ev) {
2689 - var positions = getEventPosition(ev);
2690 - var p = ev.data.plot;
2691 - var evt = jQuery.Event('jqplotMouseLeave');
2692 - evt.pageX = ev.pageX;
2693 - evt.pageY = ev.pageY;
2694 - $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
2695 - };
2696 -
2697 - // method: drawSeries
2698 - // Redraws all or just one series on the plot. No axis scaling
2699 - // is performed and no other elements on the plot are redrawn.
2700 - // options is an options object to pass on to the series renderers.
2701 - // It can be an empty object {}. idx is the series index
2702 - // to redraw if only one series is to be redrawn.
2703 - this.drawSeries = function(options, idx){
2704 - var i, series, ctx;
2705 - // if only one argument passed in and it is a number, use it ad idx.
2706 - idx = (typeof(options) == "number" && idx == null) ? options : idx;
2707 - options = (typeof(options) == "object") ? options : {};
2708 - // draw specified series
2709 - if (idx != undefined) {
2710 - series = this.series[idx];
2711 - ctx = series.shadowCanvas._ctx;
2712 - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
2713 - series.drawShadow(ctx, options, this);
2714 - ctx = series.canvas._ctx;
2715 - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
2716 - series.draw(ctx, options, this);
2717 - if (series.renderer.constructor == $.jqplot.BezierCurveRenderer) {
2718 - if (idx < this.series.length - 1) {
2719 - this.drawSeries(idx+1);
2720 - }
2721 - }
2722 - }
2723 -
2724 - else {
2725 - // if call series drawShadow method first, in case all series shadows
2726 - // should be drawn before any series. This will ensure, like for
2727 - // stacked bar plots, that shadows don't overlap series.
2728 - for (i=0; i<this.series.length; i++) {
2729 - // first clear the canvas
2730 - series = this.series[i];
2731 - ctx = series.shadowCanvas._ctx;
2732 - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
2733 - series.drawShadow(ctx, options, this);
2734 - ctx = series.canvas._ctx;
2735 - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
2736 - series.draw(ctx, options, this);
2737 - }
2738 - }
2739 - };
2740 -
2741 - // method: moveSeriesToFront
2742 - // This method requires jQuery 1.4+
2743 - // Moves the specified series canvas in front of all other series canvases.
2744 - // This effectively "draws" the specified series on top of all other series,
2745 - // although it is performed through DOM manipulation, no redrawing is performed.
2746 - //
2747 - // Parameters:
2748 - // idx - 0 based index of the series to move. This will be the index of the series
2749 - // as it was first passed into the jqplot function.
2750 - this.moveSeriesToFront = function (idx) {
2751 - idx = parseInt(idx, 10);
2752 - var stackIndex = $.inArray(idx, this.seriesStack);
2753 - // if already in front, return
2754 - if (stackIndex == -1) {
2755 - return;
2756 - }
2757 - if (stackIndex == this.seriesStack.length -1) {
2758 - this.previousSeriesStack = this.seriesStack.slice(0);
2759 - return;
2760 - }
2761 - var opidx = this.seriesStack[this.seriesStack.length -1];
2762 - var serelem = this.series[idx].canvas._elem.detach();
2763 - var shadelem = this.series[idx].shadowCanvas._elem.detach();
2764 - this.series[opidx].shadowCanvas._elem.after(shadelem);
2765 - this.series[opidx].canvas._elem.after(serelem);
2766 - this.previousSeriesStack = this.seriesStack.slice(0);
2767 - this.seriesStack.splice(stackIndex, 1);
2768 - this.seriesStack.push(idx);
2769 - };
2770 -
2771 - // method: moveSeriesToBack
2772 - // This method requires jQuery 1.4+
2773 - // Moves the specified series canvas behind all other series canvases.
2774 - //
2775 - // Parameters:
2776 - // idx - 0 based index of the series to move. This will be the index of the series
2777 - // as it was first passed into the jqplot function.
2778 - this.moveSeriesToBack = function (idx) {
2779 - idx = parseInt(idx, 10);
2780 - var stackIndex = $.inArray(idx, this.seriesStack);
2781 - // if already in back, return
2782 - if (stackIndex == 0 || stackIndex == -1) {
2783 - return;
2784 - }
2785 - var opidx = this.seriesStack[0];
2786 - var serelem = this.series[idx].canvas._elem.detach();
2787 - var shadelem = this.series[idx].shadowCanvas._elem.detach();
2788 - this.series[opidx].shadowCanvas._elem.before(shadelem);
2789 - this.series[opidx].canvas._elem.before(serelem);
2790 - this.previousSeriesStack = this.seriesStack.slice(0);
2791 - this.seriesStack.splice(stackIndex, 1);
2792 - this.seriesStack.unshift(idx);
2793 - };
2794 -
2795 - // method: restorePreviousSeriesOrder
2796 - // This method requires jQuery 1.4+
2797 - // Restore the series canvas order to its previous state.
2798 - // Useful to put a series back where it belongs after moving
2799 - // it to the front.
2800 - this.restorePreviousSeriesOrder = function () {
2801 - var i, j, serelem, shadelem, temp;
2802 - // if no change, return.
2803 - if (this.seriesStack == this.previousSeriesStack) {
2804 - return;
2805 - }
2806 - for (i=1; i<this.previousSeriesStack.length; i++) {
2807 - move = this.previousSeriesStack[i];
2808 - keep = this.previousSeriesStack[i-1];
2809 - serelem = this.series[move].canvas._elem.detach();
2810 - shadelem = this.series[move].shadowCanvas._elem.detach();
2811 - this.series[keep].shadowCanvas._elem.after(shadelem);
2812 - this.series[keep].canvas._elem.after(serelem);
2813 - }
2814 - temp = this.seriesStack.slice(0);
2815 - this.seriesStack = this.previousSeriesStack.slice(0);
2816 - this.previousSeriesStack = temp;
2817 - };
2818 -
2819 - // method: restoreOriginalSeriesOrder
2820 - // This method requires jQuery 1.4+
2821 - // Restore the series canvas order to its original order
2822 - // when the plot was created.
2823 - this.restoreOriginalSeriesOrder = function () {
2824 - var i, j, arr=[];
2825 - for (i=0; i<this.series.length; i++) {
2826 - arr.push(i);
2827 - }
2828 - if (this.seriesStack == arr) {
2829 - return;
2830 - }
2831 - this.previousSeriesStack = this.seriesStack.slice(0);
2832 - this.seriesStack = arr;
2833 - for (i=1; i<this.seriesStack.length; i++) {
2834 - serelem = this.series[i].canvas._elem.detach();
2835 - shadelem = this.series[i].shadowCanvas._elem.detach();
2836 - this.series[i-1].shadowCanvas._elem.after(shadelem);
2837 - this.series[i-1].canvas._elem.after(serelem);
2838 - }
2839 - };
2840 -
2841 - this.activateTheme = function (name) {
2842 - this.themeEngine.activate(this, name);
2843 - };
2844 - }
2845 -
2846 -
2847 - // conpute a highlight color or array of highlight colors from given colors.
2848 - $.jqplot.computeHighlightColors = function(colors) {
2849 - var ret;
2850 - if (typeof(colors) == "array") {
2851 - ret = [];
2852 - for (var i=0; i<colors.length; i++){
2853 - var rgba = $.jqplot.getColorComponents(colors[i]);
2854 - var newrgb = [rgba[0], rgba[1], rgba[2]];
2855 - var sum = newrgb[0] + newrgb[1] + newrgb[2];
2856 - for (var j=0; j<3; j++) {
2857 - // when darkening, lowest color component can be is 60.
2858 - newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
2859 - newrgb[j] = parseInt(newrgb[j], 10);
2860 - }
2861 - ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
2862 - }
2863 - }
2864 - else {
2865 - var rgba = $.jqplot.getColorComponents(colors);
2866 - var newrgb = [rgba[0], rgba[1], rgba[2]];
2867 - var sum = newrgb[0] + newrgb[1] + newrgb[2];
2868 - for (var j=0; j<3; j++) {
2869 - // when darkening, lowest color component can be is 60.
2870 - newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
2871 - newrgb[j] = parseInt(newrgb[j], 10);
2872 - }
2873 - ret = 'rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')';
2874 - }
2875 - return ret;
2876 - };
2877 -
2878 - $.jqplot.ColorGenerator = function(colors) {
2879 - var idx = 0;
2880 -
2881 - this.next = function () {
2882 - if (idx < colors.length) {
2883 - return colors[idx++];
2884 - }
2885 - else {
2886 - idx = 0;
2887 - return colors[idx++];
2888 - }
2889 - };
2890 -
2891 - this.previous = function () {
2892 - if (idx > 0) {
2893 - return colors[idx--];
2894 - }
2895 - else {
2896 - idx = colors.length-1;
2897 - return colors[idx];
2898 - }
2899 - };
2900 -
2901 - // get a color by index without advancing pointer.
2902 - this.get = function(i) {
2903 - var idx = i - colors.length * Math.floor(i/colors.length);
2904 - return colors[idx];
2905 - };
2906 -
2907 - this.setColors = function(c) {
2908 - colors = c;
2909 - };
2910 -
2911 - this.reset = function() {
2912 - idx = 0;
2913 - };
2914 - };
2915 -
2916 - // convert a hex color string to rgb string.
2917 - // h - 3 or 6 character hex string, with or without leading #
2918 - // a - optional alpha
2919 - $.jqplot.hex2rgb = function(h, a) {
2920 - h = h.replace('#', '');
2921 - if (h.length == 3) {
2922 - h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];
2923 - }
2924 - var rgb;
2925 - rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16);
2926 - if (a) {
2927 - rgb += ', '+a;
2928 - }
2929 - rgb += ')';
2930 - return rgb;
2931 - };
2932 -
2933 - // convert an rgb color spec to a hex spec. ignore any alpha specification.
2934 - $.jqplot.rgb2hex = function(s) {
2935 - var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;
2936 - var m = s.match(pat);
2937 - var h = '#';
2938 - for (i=1; i<4; i++) {
2939 - var temp;
2940 - if (m[i].search(/%/) != -1) {
2941 - temp = parseInt(255*m[i]/100, 10).toString(16);
2942 - if (temp.length == 1) {
2943 - temp = '0'+temp;
2944 - }
2945 - }
2946 - else {
2947 - temp = parseInt(m[i], 10).toString(16);
2948 - if (temp.length == 1) {
2949 - temp = '0'+temp;
2950 - }
2951 - }
2952 - h += temp;
2953 - }
2954 - return h;
2955 - };
2956 -
2957 - // given a css color spec, return an rgb css color spec
2958 - $.jqplot.normalize2rgb = function(s, a) {
2959 - if (s.search(/^ *rgba?\(/) != -1) {
2960 - return s;
2961 - }
2962 - else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) {
2963 - return $.jqplot.hex2rgb(s, a);
2964 - }
2965 - else {
2966 - throw 'invalid color spec';
2967 - }
2968 - };
2969 -
2970 - // extract the r, g, b, a color components out of a css color spec.
2971 - $.jqplot.getColorComponents = function(s) {
2972 - // check to see if a color keyword.
2973 - s = $.jqplot.colorKeywordMap[s] || s;
2974 - var rgb = $.jqplot.normalize2rgb(s);
2975 - var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;
2976 - var m = rgb.match(pat);
2977 - var ret = [];
2978 - for (i=1; i<4; i++) {
2979 - if (m[i].search(/%/) != -1) {
2980 - ret[i-1] = parseInt(255*m[i]/100, 10);
2981 - }
2982 - else {
2983 - ret[i-1] = parseInt(m[i], 10);
2984 - }
2985 - }
2986 - ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0;
2987 - return ret;
2988 - };
2989 -
2990 - $.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)'};
2991 -
2992 - // Convienence function that won't hang IE.
2993 - $.jqplot.log = function() {
2994 - if (window.console && $.jqplot.debug) {
2995 - if (arguments.length == 1) {
2996 - console.log (arguments[0]);
2997 - }
2998 - else {
2999 - console.log(arguments);
3000 - }
3001 - }
3002 - };
3003 - var log = $.jqplot.log;
3004 -
3005 -
3006 - // class: $.jqplot.AxisLabelRenderer
3007 - // Renderer to place labels on the axes.
3008 - $.jqplot.AxisLabelRenderer = function(options) {
3009 - // Group: Properties
3010 - $.jqplot.ElemContainer.call(this);
3011 - // name of the axis associated with this tick
3012 - this.axis;
3013 - // prop: show
3014 - // wether or not to show the tick (mark and label).
3015 - this.show = true;
3016 - // prop: label
3017 - // The text or html for the label.
3018 - this.label = '';
3019 - this.fontFamily = null;
3020 - this.fontSize = null;
3021 - this.textColor = null;
3022 - this._elem;
3023 - // prop: escapeHTML
3024 - // true to escape HTML entities in the label.
3025 - this.escapeHTML = false;
3026 -
3027 - $.extend(true, this, options);
3028 - };
3029 -
3030 - $.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer();
3031 - $.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer;
3032 -
3033 - $.jqplot.AxisLabelRenderer.prototype.init = function(options) {
3034 - $.extend(true, this, options);
3035 - };
3036 -
3037 - $.jqplot.AxisLabelRenderer.prototype.draw = function() {
3038 - this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>');
3039 -
3040 - if (Number(this.label)) {
3041 - this._elem.css('white-space', 'nowrap');
3042 - }
3043 -
3044 - if (!this.escapeHTML) {
3045 - this._elem.html(this.label);
3046 - }
3047 - else {
3048 - this._elem.text(this.label);
3049 - }
3050 - if (this.fontFamily) {
3051 - this._elem.css('font-family', this.fontFamily);
3052 - }
3053 - if (this.fontSize) {
3054 - this._elem.css('font-size', this.fontSize);
3055 - }
3056 - if (this.textColor) {
3057 - this._elem.css('color', this.textColor);
3058 - }
3059 -
3060 - return this._elem;
3061 - };
3062 -
3063 - $.jqplot.AxisLabelRenderer.prototype.pack = function() {
3064 - };
3065 -
3066 - // class: $.jqplot.AxisTickRenderer
3067 - // A "tick" object showing the value of a tick/gridline on the plot.
3068 - $.jqplot.AxisTickRenderer = function(options) {
3069 - // Group: Properties
3070 - $.jqplot.ElemContainer.call(this);
3071 - // prop: mark
3072 - // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
3073 - this.mark = 'outside';
3074 - // name of the axis associated with this tick
3075 - this.axis;
3076 - // prop: showMark
3077 - // wether or not to show the mark on the axis.
3078 - this.showMark = true;
3079 - // prop: showGridline
3080 - // wether or not to draw the gridline on the grid at this tick.
3081 - this.showGridline = true;
3082 - // prop: isMinorTick
3083 - // if this is a minor tick.
3084 - this.isMinorTick = false;
3085 - // prop: size
3086 - // Length of the tick beyond the grid in pixels.
3087 - // DEPRECATED: This has been superceeded by markSize
3088 - this.size = 4;
3089 - // prop: markSize
3090 - // Length of the tick marks in pixels. For 'cross' style, length
3091 - // will be stoked above and below axis, so total length will be twice this.
3092 - this.markSize = 6;
3093 - // prop: show
3094 - // wether or not to show the tick (mark and label).
3095 - // Setting this to false requires more testing. It is recommended
3096 - // to set showLabel and showMark to false instead.
3097 - this.show = true;
3098 - // prop: showLabel
3099 - // wether or not to show the label.
3100 - this.showLabel = true;
3101 - this.label = '';
3102 - this.value = null;
3103 - this._styles = {};
3104 - // prop: formatter
3105 - // A class of a formatter for the tick text. sprintf by default.
3106 - this.formatter = $.jqplot.DefaultTickFormatter;
3107 - // prop: prefix
3108 - // string appended to the tick label if no formatString is specified.
3109 - this.prefix = '';
3110 - // prop: formatString
3111 - // string passed to the formatter.
3112 - this.formatString = '';
3113 - // prop: fontFamily
3114 - // css spec for the font-family css attribute.
3115 - this.fontFamily;
3116 - // prop: fontSize
3117 - // css spec for the font-size css attribute.
3118 - this.fontSize;
3119 - // prop: textColor
3120 - // css spec for the color attribute.
3121 - this.textColor;
3122 - this._elem;
3123 -
3124 - $.extend(true, this, options);
3125 - };
3126 -
3127 - $.jqplot.AxisTickRenderer.prototype.init = function(options) {
3128 - $.extend(true, this, options);
3129 - };
3130 -
3131 - $.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer();
3132 - $.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer;
3133 -
3134 - $.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
3135 - this.value = value;
3136 - this.axis = axisName;
3137 - if (isMinor) {
3138 - this.isMinorTick = true;
3139 - }
3140 - return this;
3141 - };
3142 -
3143 - $.jqplot.AxisTickRenderer.prototype.draw = function() {
3144 - if (!this.label) {
3145 - this.label = this.formatter(this.formatString, this.value);
3146 - }
3147 - // add prefix if needed
3148 - if (this.prefix && !this.formatString) {
3149 - this.label = this.prefix + this.label;
3150 - }
3151 - style ='style="position:absolute;';
3152 - if (Number(this.label)) {
3153 - style +='white-space:nowrap;';
3154 - }
3155 - style += '"';
3156 - this._elem = $('<div '+style+' class="jqplot-'+this.axis+'-tick">'+this.label+'</div>');
3157 - for (var s in this._styles) {
3158 - this._elem.css(s, this._styles[s]);
3159 - }
3160 - if (this.fontFamily) {
3161 - this._elem.css('font-family', this.fontFamily);
3162 - }
3163 - if (this.fontSize) {
3164 - this._elem.css('font-size', this.fontSize);
3165 - }
3166 - if (this.textColor) {
3167 - this._elem.css('color', this.textColor);
3168 - }
3169 - return this._elem;
3170 - };
3171 -
3172 - $.jqplot.DefaultTickFormatter = function (format, val) {
3173 - if (typeof val == 'number') {
3174 - if (!format) {
3175 - format = $.jqplot.config.defaultTickFormatString;
3176 - }
3177 - return $.jqplot.sprintf(format, val);
3178 - }
3179 - else {
3180 - return String(val);
3181 - }
3182 - };
3183 -
3184 - $.jqplot.AxisTickRenderer.prototype.pack = function() {
3185 - };
3186 -
3187 - // Class: $.jqplot.CanvasGridRenderer
3188 - // The default jqPlot grid renderer, creating a grid on a canvas element.
3189 - // The renderer has no additional options beyond the <Grid> class.
3190 - $.jqplot.CanvasGridRenderer = function(){
3191 - this.shadowRenderer = new $.jqplot.ShadowRenderer();
3192 - };
3193 -
3194 - // called with context of Grid object
3195 - $.jqplot.CanvasGridRenderer.prototype.init = function(options) {
3196 - this._ctx;
3197 - $.extend(true, this, options);
3198 - // set the shadow renderer options
3199 - var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor};
3200 - this.renderer.shadowRenderer.init(sopts);
3201 - };
3202 -
3203 - // called with context of Grid.
3204 - $.jqplot.CanvasGridRenderer.prototype.createElement = function() {
3205 - var elem = document.createElement('canvas');
3206 - var w = this._plotDimensions.width;
3207 - var h = this._plotDimensions.height;
3208 - elem.width = w;
3209 - elem.height = h;
3210 - this._elem = $(elem);
3211 - this._elem.addClass('jqplot-grid-canvas');
3212 - this._elem.css({ position: 'absolute', left: 0, top: 0 });
3213 - if ($.jqplot.use_excanvas) {
3214 - window.G_vmlCanvasManager.init_(document);
3215 - }
3216 - if ($.jqplot.use_excanvas) {
3217 - elem = window.G_vmlCanvasManager.initElement(elem);
3218 - }
3219 - this._top = this._offsets.top;
3220 - this._bottom = h - this._offsets.bottom;
3221 - this._left = this._offsets.left;
3222 - this._right = w - this._offsets.right;
3223 - this._width = this._right - this._left;
3224 - this._height = this._bottom - this._top;
3225 - return this._elem;
3226 - };
3227 -
3228 - $.jqplot.CanvasGridRenderer.prototype.draw = function() {
3229 - this._ctx = this._elem.get(0).getContext("2d");
3230 - var ctx = this._ctx;
3231 - var axes = this._axes;
3232 - // Add the grid onto the grid canvas. This is the bottom most layer.
3233 - ctx.save();
3234 - ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height);
3235 - ctx.fillStyle = this.backgroundColor || this.background;
3236 - ctx.fillRect(this._left, this._top, this._width, this._height);
3237 -
3238 - if (this.drawGridlines) {
3239 - ctx.save();
3240 - ctx.lineJoin = 'miter';
3241 - ctx.lineCap = 'butt';
3242 - ctx.lineWidth = this.gridLineWidth;
3243 - ctx.strokeStyle = this.gridLineColor;
3244 - var b, e;
3245 - var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis'];
3246 - for (var i=4; i>0; i--) {
3247 - var name = ax[i-1];
3248 - var axis = axes[name];
3249 - var ticks = axis._ticks;
3250 - if (axis.show) {
3251 - for (var j=ticks.length; j>0; j--) {
3252 - var t = ticks[j-1];
3253 - if (t.show) {
3254 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3255 - switch (name) {
3256 - case 'xaxis':
3257 - // draw the grid line
3258 - if (t.showGridline) {
3259 - drawLine(pos, this._top, pos, this._bottom);
3260 - }
3261 -
3262 - // draw the mark
3263 - if (t.showMark && t.mark) {
3264 - s = t.markSize;
3265 - m = t.mark;
3266 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3267 - switch (m) {
3268 - case 'outside':
3269 - b = this._bottom;
3270 - e = this._bottom+s;
3271 - break;
3272 - case 'inside':
3273 - b = this._bottom-s;
3274 - e = this._bottom;
3275 - break;
3276 - case 'cross':
3277 - b = this._bottom-s;
3278 - e = this._bottom+s;
3279 - break;
3280 - default:
3281 - b = this._bottom;
3282 - e = this._bottom+s;
3283 - break;
3284 - }
3285 - // draw the shadow
3286 - if (this.shadow) {
3287 - this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
3288 - }
3289 - // draw the line
3290 - drawLine(pos, b, pos, e);
3291 - }
3292 - break;
3293 - case 'yaxis':
3294 - // draw the grid line
3295 - if (t.showGridline) {
3296 - drawLine(this._right, pos, this._left, pos);
3297 - }
3298 - // draw the mark
3299 - if (t.showMark && t.mark) {
3300 - s = t.markSize;
3301 - m = t.mark;
3302 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3303 - switch (m) {
3304 - case 'outside':
3305 - b = this._left-s;
3306 - e = this._left;
3307 - break;
3308 - case 'inside':
3309 - b = this._left;
3310 - e = this._left+s;
3311 - break;
3312 - case 'cross':
3313 - b = this._left-s;
3314 - e = this._left+s;
3315 - break;
3316 - default:
3317 - b = this._left-s;
3318 - e = this._left;
3319 - break;
3320 - }
3321 - // draw the shadow
3322 - if (this.shadow) {
3323 - this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
3324 - }
3325 - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
3326 - }
3327 - break;
3328 - case 'x2axis':
3329 - // draw the grid line
3330 - if (t.showGridline) {
3331 - drawLine(pos, this._bottom, pos, this._top);
3332 - }
3333 - // draw the mark
3334 - if (t.showMark && t.mark) {
3335 - s = t.markSize;
3336 - m = t.mark;
3337 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3338 - switch (m) {
3339 - case 'outside':
3340 - b = this._top-s;
3341 - e = this._top;
3342 - break;
3343 - case 'inside':
3344 - b = this._top;
3345 - e = this._top+s;
3346 - break;
3347 - case 'cross':
3348 - b = this._top-s;
3349 - e = this._top+s;
3350 - break;
3351 - default:
3352 - b = this._top-s;
3353 - e = this._top;
3354 - break;
3355 - }
3356 - // draw the shadow
3357 - if (this.shadow) {
3358 - this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
3359 - }
3360 - drawLine(pos, b, pos, e);
3361 - }
3362 - break;
3363 - case 'y2axis':
3364 - // draw the grid line
3365 - if (t.showGridline) {
3366 - drawLine(this._left, pos, this._right, pos);
3367 - }
3368 - // draw the mark
3369 - if (t.showMark && t.mark) {
3370 - s = t.markSize;
3371 - m = t.mark;
3372 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3373 - switch (m) {
3374 - case 'outside':
3375 - b = this._right;
3376 - e = this._right+s;
3377 - break;
3378 - case 'inside':
3379 - b = this._right-s;
3380 - e = this._right;
3381 - break;
3382 - case 'cross':
3383 - b = this._right-s;
3384 - e = this._right+s;
3385 - break;
3386 - default:
3387 - b = this._right;
3388 - e = this._right+s;
3389 - break;
3390 - }
3391 - // draw the shadow
3392 - if (this.shadow) {
3393 - this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
3394 - }
3395 - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
3396 - }
3397 - break;
3398 - default:
3399 - break;
3400 - }
3401 - }
3402 - }
3403 - }
3404 - }
3405 - // Now draw grid lines for additional y axes
3406 - ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
3407 - for (var i=7; i>0; i--) {
3408 - var axis = axes[ax[i-1]];
3409 - var ticks = axis._ticks;
3410 - if (axis.show) {
3411 - var tn = ticks[axis.numberTicks-1];
3412 - var t0 = ticks[0];
3413 - var left = axis.getLeft();
3414 - var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]];
3415 - // draw the shadow
3416 - if (this.shadow) {
3417 - this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false});
3418 - }
3419 - // draw the line
3420 - drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth});
3421 - // draw the tick marks
3422 - for (var j=ticks.length; j>0; j--) {
3423 - var t = ticks[j-1];
3424 - s = t.markSize;
3425 - m = t.mark;
3426 - var pos = Math.round(axis.u2p(t.value)) + 0.5;
3427 - if (t.showMark && t.mark) {
3428 - switch (m) {
3429 - case 'outside':
3430 - b = left;
3431 - e = left+s;
3432 - break;
3433 - case 'inside':
3434 - b = left-s;
3435 - e = left;
3436 - break;
3437 - case 'cross':
3438 - b = left-s;
3439 - e = left+s;
3440 - break;
3441 - default:
3442 - b = left;
3443 - e = left+s;
3444 - break;
3445 - }
3446 - points = [[b,pos], [e,pos]];
3447 - // draw the shadow
3448 - if (this.shadow) {
3449 - this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
3450 - }
3451 - // draw the line
3452 - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
3453 - }
3454 - }
3455 - }
3456 - }
3457 -
3458 - ctx.restore();
3459 - }
3460 -
3461 - function drawLine(bx, by, ex, ey, opts) {
3462 - ctx.save();
3463 - opts = opts || {};
3464 - if (opts.lineWidth == null || opts.lineWidth != 0){
3465 - $.extend(true, ctx, opts);
3466 - ctx.beginPath();
3467 - ctx.moveTo(bx, by);
3468 - ctx.lineTo(ex, ey);
3469 - ctx.stroke();
3470 - ctx.restore();
3471 - }
3472 - }
3473 -
3474 - if (this.shadow) {
3475 - var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
3476 - this.renderer.shadowRenderer.draw(ctx, points);
3477 - }
3478 - // Now draw border around grid. Use axis border definitions. start at
3479 - // upper left and go clockwise.
3480 - if (this.borderWidth != 0 && this.drawBorder) {
3481 - drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
3482 - drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
3483 - drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
3484 - drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
3485 - }
3486 - // ctx.lineWidth = this.borderWidth;
3487 - // ctx.strokeStyle = this.borderColor;
3488 - // ctx.strokeRect(this._left, this._top, this._width, this._height);
3489 -
3490 -
3491 - ctx.restore();
3492 - };
3493 -
3494 - /**
3495 - * Date instance methods
3496 - *
3497 - * @author Ken Snyder (ken d snyder at gmail dot com)
3498 - * @date 2008-09-10
3499 - * @version 2.0.2 (http://kendsnyder.com/sandbox/date/)
3500 - * @license Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
3501 - *
3502 - * @contributions Chris Leonello
3503 - * @comment Bug fix to 12 hour time and additions to handle milliseconds and
3504 - * @comment 24 hour time without am/pm suffix
3505 - *
3506 - */
3507 -
3508 - // begin by creating a scope for utility variables
3509 -
3510 - //
3511 - // pre-calculate the number of milliseconds in a day
3512 - //
3513 -
3514 - var day = 24 * 60 * 60 * 1000;
3515 - //
3516 - // function to add leading zeros
3517 - //
3518 - var zeroPad = function(number, digits) {
3519 - number = String(number);
3520 - while (number.length < digits) {
3521 - number = '0' + number;
3522 - }
3523 - return number;
3524 - };
3525 - //
3526 - // set up integers and functions for adding to a date or subtracting two dates
3527 - //
3528 - var multipliers = {
3529 - millisecond: 1,
3530 - second: 1000,
3531 - minute: 60 * 1000,
3532 - hour: 60 * 60 * 1000,
3533 - day: day,
3534 - week: 7 * day,
3535 - month: {
3536 - // add a number of months
3537 - add: function(d, number) {
3538 - // add any years needed (increments of 12)
3539 - multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12));
3540 - // ensure that we properly wrap betwen December and January
3541 - var prevMonth = d.getMonth() + (number % 12);
3542 - if (prevMonth == 12) {
3543 - prevMonth = 0;
3544 - d.setYear(d.getFullYear() + 1);
3545 - } else if (prevMonth == -1) {
3546 - prevMonth = 11;
3547 - d.setYear(d.getFullYear() - 1);
3548 - }
3549 - d.setMonth(prevMonth);
3550 - },
3551 - // get the number of months between two Date objects (decimal to the nearest day)
3552 - diff: function(d1, d2) {
3553 - // get the number of years
3554 - var diffYears = d1.getFullYear() - d2.getFullYear();
3555 - // get the number of remaining months
3556 - var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12);
3557 - // get the number of remaining days
3558 - var diffDays = d1.getDate() - d2.getDate();
3559 - // return the month difference with the days difference as a decimal
3560 - return diffMonths + (diffDays / 30);
3561 - }
3562 - },
3563 - year: {
3564 - // add a number of years
3565 - add: function(d, number) {
3566 - d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number));
3567 - },
3568 - // get the number of years between two Date objects (decimal to the nearest day)
3569 - diff: function(d1, d2) {
3570 - return multipliers.month.diff(d1, d2) / 12;
3571 - }
3572 - }
3573 - };
3574 - //
3575 - // alias each multiplier with an 's' to allow 'year' and 'years' for example
3576 - //
3577 - for (var unit in multipliers) {
3578 - if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :|
3579 - multipliers[unit + 's'] = multipliers[unit];
3580 - }
3581 - }
3582 - //
3583 - // take a date instance and a format code and return the formatted value
3584 - //
3585 - var format = function(d, code) {
3586 - if (Date.prototype.strftime.formatShortcuts[code]) {
3587 - // process any shortcuts recursively
3588 - return d.strftime(Date.prototype.strftime.formatShortcuts[code]);
3589 - } else {
3590 - // get the format code function and toPaddedString() argument
3591 - var getter = (Date.prototype.strftime.formatCodes[code] || '').split('.');
3592 - var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : '';
3593 - // run toPaddedString() if specified
3594 - if (getter[1]) {
3595 - nbr = zeroPad(nbr, getter[1]);
3596 - }
3597 - // prepend the leading character
3598 - return nbr;
3599 - }
3600 - };
3601 - //
3602 - // Add methods to Date instances
3603 - //
3604 - var instanceMethods = {
3605 - //
3606 - // Return a date one day ahead (or any other unit)
3607 - //
3608 - // @param string unit
3609 - // units: year | month | day | week | hour | minute | second | millisecond
3610 - // @return object Date
3611 - //
3612 - succ: function(unit) {
3613 - return this.clone().add(1, unit);
3614 - },
3615 - //
3616 - // Add an arbitrary amount to the currently stored date
3617 - //
3618 - // @param integer/float number
3619 - // @param string unit
3620 - // @return object Date (chainable)
3621 - //
3622 - add: function(number, unit) {
3623 - var factor = multipliers[unit] || multipliers.day;
3624 - if (typeof factor == 'number') {
3625 - this.setTime(this.getTime() + (factor * number));
3626 - } else {
3627 - factor.add(this, number);
3628 - }
3629 - return this;
3630 - },
3631 - //
3632 - // Find the difference between the current and another date
3633 - //
3634 - // @param string/object dateObj
3635 - // @param string unit
3636 - // @param boolean allowDecimal
3637 - // @return integer/float
3638 - //
3639 - diff: function(dateObj, unit, allowDecimal) {
3640 - // ensure we have a Date object
3641 - dateObj = Date.create(dateObj);
3642 - if (dateObj === null) {
3643 - return null;
3644 - }
3645 - // get the multiplying factor integer or factor function
3646 - var factor = multipliers[unit] || multipliers.day;
3647 - if (typeof factor == 'number') {
3648 - // multiply
3649 - var unitDiff = (this.getTime() - dateObj.getTime()) / factor;
3650 - } else {
3651 - // run function
3652 - var unitDiff = factor.diff(this, dateObj);
3653 - }
3654 - // if decimals are not allowed, round toward zero
3655 - return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff));
3656 - },
3657 - //
3658 - // Convert a date to a string using traditional strftime format codes
3659 - //
3660 - // @param string formatStr
3661 - // @return string
3662 - //
3663 - strftime: function(formatStr) {
3664 - // default the format string to year-month-day
3665 - var source = formatStr || '%Y-%m-%d', result = '', match;
3666 - // Account for display of time in local time or as UTC time
3667 - // var val = ($.jqplot.comfig.convertUTCtoLocaltime) ? this :
3668 - // replace each format code
3669 - while (source.length > 0) {
3670 - if (match = source.match(Date.prototype.strftime.formatCodes.matcher)) {
3671 - result += source.slice(0, match.index);
3672 - result += (match[1] || '') + format(this, match[2]);
3673 - source = source.slice(match.index + match[0].length);
3674 - } else {
3675 - result += source;
3676 - source = '';
3677 - }
3678 - }
3679 - return result;
3680 - },
3681 - //
3682 - // Return a proper two-digit year integer
3683 - //
3684 - // @return integer
3685 - //
3686 - getShortYear: function() {
3687 - return this.getYear() % 100;
3688 - },
3689 - //
3690 - // Get the number of the current month, 1-12
3691 - //
3692 - // @return integer
3693 - //
3694 - getMonthNumber: function() {
3695 - return this.getMonth() + 1;
3696 - },
3697 - //
3698 - // Get the name of the current month
3699 - //
3700 - // @return string
3701 - //
3702 - getMonthName: function() {
3703 - return Date.MONTHNAMES[this.getMonth()];
3704 - },
3705 - //
3706 - // Get the abbreviated name of the current month
3707 - //
3708 - // @return string
3709 - //
3710 - getAbbrMonthName: function() {
3711 - return Date.ABBR_MONTHNAMES[this.getMonth()];
3712 - },
3713 - //
3714 - // Get the name of the current week day
3715 - //
3716 - // @return string
3717 - //
3718 - getDayName: function() {
3719 - return Date.DAYNAMES[this.getDay()];
3720 - },
3721 - //
3722 - // Get the abbreviated name of the current week day
3723 - //
3724 - // @return string
3725 - //
3726 - getAbbrDayName: function() {
3727 - return Date.ABBR_DAYNAMES[this.getDay()];
3728 - },
3729 - //
3730 - // Get the ordinal string associated with the day of the month (i.e. st, nd, rd, th)
3731 - //
3732 - // @return string
3733 - //
3734 - getDayOrdinal: function() {
3735 - return Date.ORDINALNAMES[this.getDate() % 10];
3736 - },
3737 - //
3738 - // Get the current hour on a 12-hour scheme
3739 - //
3740 - // @return integer
3741 - //
3742 - getHours12: function() {
3743 - var hours = this.getHours();
3744 - return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours);
3745 - },
3746 - //
3747 - // Get the AM or PM for the current time
3748 - //
3749 - // @return string
3750 - //
3751 - getAmPm: function() {
3752 - return this.getHours() >= 12 ? 'PM' : 'AM';
3753 - },
3754 - //
3755 - // Get the current date as a Unix timestamp
3756 - //
3757 - // @return integer
3758 - //
3759 - getUnix: function() {
3760 - return Math.round(this.getTime() / 1000, 0);
3761 - },
3762 - //
3763 - // Get the GMT offset in hours and minutes (e.g. +06:30)
3764 - //
3765 - // @return string
3766 - //
3767 - getGmtOffset: function() {
3768 - // divide the minutes offset by 60
3769 - var hours = this.getTimezoneOffset() / 60;
3770 - // decide if we are ahead of or behind GMT
3771 - var prefix = hours < 0 ? '+' : '-';
3772 - // remove the negative sign if any
3773 - hours = Math.abs(hours);
3774 - // add the +/- to the padded number of hours to : to the padded minutes
3775 - return prefix + zeroPad(Math.floor(hours), 2) + ':' + zeroPad((hours % 1) * 60, 2);
3776 - },
3777 - //
3778 - // Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time)
3779 - //
3780 - // @return string
3781 - //
3782 - getTimezoneName: function() {
3783 - var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());
3784 - return match[1] || match[2] || 'GMT' + this.getGmtOffset();
3785 - },
3786 - //
3787 - // Convert the current date to an 8-digit integer (%Y%m%d)
3788 - //
3789 - // @return int
3790 - //
3791 - toYmdInt: function() {
3792 - return (this.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.getDate();
3793 - },
3794 - //
3795 - // Create a copy of a date object
3796 - //
3797 - // @return object
3798 - //
3799 - clone: function() {
3800 - return new Date(this.getTime());
3801 - }
3802 - };
3803 - for (var name in instanceMethods) {
3804 - Date.prototype[name] = instanceMethods[name];
3805 - }
3806 - //
3807 - // Add static methods to the date object
3808 - //
3809 - var staticMethods = {
3810 - //
3811 - // The heart of the date functionality: returns a date object if given a convertable value
3812 - //
3813 - // @param string/object/integer date
3814 - // @return object Date
3815 - //
3816 - create: function(date) {
3817 - // If the passed value is already a date object, return it
3818 - if (date instanceof Date) {
3819 - return date;
3820 - }
3821 - // if (typeof date == 'number') return new Date(date);
3822 - // If the passed value is an integer, interpret it as a javascript timestamp
3823 - if (typeof date == 'number') {
3824 - return new Date(date);
3825 - }
3826 - // If the passed value is a string, attempt to parse it using Date.parse()
3827 - var parsable = String(date).replace(/^\s*(.+)\s*$/, '$1'), i = 0, length = Date.create.patterns.length, pattern;
3828 - var current = parsable;
3829 - while (i < length) {
3830 - ms = Date.parse(current);
3831 - if (!isNaN(ms)) {
3832 - return new Date(ms);
3833 - }
3834 - pattern = Date.create.patterns[i];
3835 - if (typeof pattern == 'function') {
3836 - obj = pattern(current);
3837 - if (obj instanceof Date) {
3838 - return obj;
3839 - }
3840 - } else {
3841 - current = parsable.replace(pattern[0], pattern[1]);
3842 - }
3843 - i++;
3844 - }
3845 - return NaN;
3846 - },
3847 - //
3848 - // constants representing month names, day names, and ordinal names
3849 - // (same names as Ruby Date constants)
3850 - //
3851 - MONTHNAMES : 'January February March April May June July August September October November December'.split(' '),
3852 - ABBR_MONTHNAMES : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '),
3853 - DAYNAMES : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '),
3854 - ABBR_DAYNAMES : 'Sun Mon Tue Wed Thu Fri Sat'.split(' '),
3855 - ORDINALNAMES : 'th st nd rd th th th th th th'.split(' '),
3856 - //
3857 - // Shortcut for full ISO-8601 date conversion
3858 - //
3859 - ISO: '%Y-%m-%dT%H:%M:%S.%N%G',
3860 - //
3861 - // Shortcut for SQL-type formatting
3862 - //
3863 - SQL: '%Y-%m-%d %H:%M:%S',
3864 - //
3865 - // Setter method for month, day, and ordinal names for i18n
3866 - //
3867 - // @param object newNames
3868 - //
3869 - daysInMonth: function(year, month) {
3870 - if (month == 2) {
3871 - return new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
3872 - }
3873 - return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month];
3874 - }
3875 - };
3876 - for (var name in staticMethods) {
3877 - Date[name] = staticMethods[name];
3878 - }
3879 - //
3880 - // format codes for strftime
3881 - //
3882 - // each code must be an array where the first member is the name of a Date.prototype function
3883 - // and optionally a second member indicating the number to pass to Number#toPaddedString()
3884 - //
3885 - Date.prototype.strftime.formatCodes = {
3886 - //
3887 - // 2-part regex matcher for format codes
3888 - //
3889 - // first match must be the character before the code (to account for escaping)
3890 - // second match must be the format code character(s)
3891 - //
3892 - matcher: /()%(#?(%|[a-z]))/i,
3893 - // year
3894 - Y: 'FullYear',
3895 - y: 'ShortYear.2',
3896 - // month
3897 - m: 'MonthNumber.2',
3898 - '#m': 'MonthNumber',
3899 - B: 'MonthName',
3900 - b: 'AbbrMonthName',
3901 - // day
3902 - d: 'Date.2',
3903 - '#d': 'Date',
3904 - e: 'Date',
3905 - A: 'DayName',
3906 - a: 'AbbrDayName',
3907 - w: 'Day',
3908 - o: 'DayOrdinal',
3909 - // hours
3910 - H: 'Hours.2',
3911 - '#H': 'Hours',
3912 - I: 'Hours12.2',
3913 - '#I': 'Hours12',
3914 - p: 'AmPm',
3915 - // minutes
3916 - M: 'Minutes.2',
3917 - '#M': 'Minutes',
3918 - // seconds
3919 - S: 'Seconds.2',
3920 - '#S': 'Seconds',
3921 - s: 'Unix',
3922 - // milliseconds
3923 - N: 'Milliseconds.3',
3924 - '#N': 'Milliseconds',
3925 - // timezone
3926 - O: 'TimezoneOffset',
3927 - Z: 'TimezoneName',
3928 - G: 'GmtOffset'
3929 - };
3930 - //
3931 - // shortcuts that will be translated into their longer version
3932 - //
3933 - // be sure that format shortcuts do not refer to themselves: this will cause an infinite loop
3934 - //
3935 - Date.prototype.strftime.formatShortcuts = {
3936 - // date
3937 - F: '%Y-%m-%d',
3938 - // time
3939 - T: '%H:%M:%S',
3940 - X: '%H:%M:%S',
3941 - // local format date
3942 - x: '%m/%d/%y',
3943 - D: '%m/%d/%y',
3944 - // local format extended
3945 - '#c': '%a %b %e %H:%M:%S %Y',
3946 - // local format short
3947 - v: '%e-%b-%Y',
3948 - R: '%H:%M',
3949 - r: '%I:%M:%S %p',
3950 - // tab and newline
3951 - t: '\t',
3952 - n: '\n',
3953 - '%': '%'
3954 - };
3955 - //
3956 - // A list of conversion patterns (array arguments sent directly to gsub)
3957 - // Add, remove or splice a patterns to customize date parsing ability
3958 - //
3959 - Date.create.patterns = [
3960 - [/-/g, '/'], // US-style time with dashes => Parsable US-style time
3961 - [/st|nd|rd|th/g, ''], // remove st, nd, rd and th
3962 - [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'], // World time => Parsable US-style time
3963 - [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'], // ISO-style time => Parsable US-style time
3964 - function(str) { // 12-hour or 24 hour time with milliseconds
3965 - // var match = str.match(/^(?:(.+)\s+)?([1-9]|1[012])(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d))?\s*(am|pm)\s*$/i);
3966 - var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i);
3967 - // opt. date hour opt. minute opt. second opt. msec opt. am or pm
3968 - if (match) {
3969 - if (match[1]) {
3970 - var d = Date.create(match[1]);
3971 - if (isNaN(d)) {
3972 - return;
3973 - }
3974 - } else {
3975 - var d = new Date();
3976 - d.setMilliseconds(0);
3977 - }
3978 - var hour = parseFloat(match[2]);
3979 - if (match[6]) {
3980 - hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12);
3981 - }
3982 - d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000);
3983 - return d;
3984 - }
3985 - else {
3986 - return str;
3987 - }
3988 - },
3989 - function(str) { // ISO timestamp with time zone.
3990 - var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i);
3991 - if (match) {
3992 - if (match[1]) {
3993 - var d = Date.create(match[1]);
3994 - if (isNaN(d)) {
3995 - return;
3996 - }
3997 - } else {
3998 - var d = new Date();
3999 - d.setMilliseconds(0);
4000 - }
4001 - var hour = parseFloat(match[2]);
4002 - d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000);
4003 - return d;
4004 - }
4005 - else {
4006 - return str;
4007 - }
4008 - },
4009 - function(str) {
4010 - var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/);
4011 - if (match) {
4012 - var d = new Date();
4013 - var y = parseFloat(String(d.getFullYear()).slice(2,4));
4014 - var cent = parseInt(String(d.getFullYear())/100, 10)*100;
4015 - var centoffset = 1;
4016 - var m1 = parseFloat(match[1]);
4017 - var m3 = parseFloat(match[3]);
4018 - var ny, nd, nm;
4019 - if (m1 > 31) { // first number is a year
4020 - nd = match[3];
4021 - if (m1 < y+centoffset) { // if less than 1 year out, assume it is this century.
4022 - ny = cent + m1;
4023 - }
4024 - else {
4025 - ny = cent - 100 + m1;
4026 - }
4027 - }
4028 -
4029 - else { // last number is the year
4030 - nd = match[1];
4031 - if (m3 < y+centoffset) { // if less than 1 year out, assume it is this century.
4032 - ny = cent + m3;
4033 - }
4034 - else {
4035 - ny = cent - 100 + m3;
4036 - }
4037 - }
4038 -
4039 - var nm = $.inArray(match[2], Date.ABBR_MONTHNAMES);
4040 -
4041 - if (nm == -1) {
4042 - nm = $.inArray(match[2], Date.MONTHNAMES);
4043 - }
4044 -
4045 - d.setFullYear(ny, nm, nd);
4046 - d.setHours(0,0,0,0);
4047 - return d;
4048 - }
4049 -
4050 - else {
4051 - return str;
4052 - }
4053 - }
4054 - ];
4055 -
4056 - if ($.jqplot.config.debug) {
4057 - $.date = Date.create;
4058 - }
4059 -
4060 - // Class: $.jqplot.DivTitleRenderer
4061 - // The default title renderer for jqPlot. This class has no options beyond the <Title> class.
4062 - $.jqplot.DivTitleRenderer = function() {
4063 - };
4064 -
4065 - $.jqplot.DivTitleRenderer.prototype.init = function(options) {
4066 - $.extend(true, this, options);
4067 - };
4068 -
4069 - $.jqplot.DivTitleRenderer.prototype.draw = function() {
4070 - var r = this.renderer;
4071 - if (!this.text) {
4072 - this.show = false;
4073 - this._elem = $('<div class="jqplot-title" style="height:0px;width:0px;"></div>');
4074 - }
4075 - else if (this.text) {
4076 - var color;
4077 - if (this.color) {
4078 - color = this.color;
4079 - }
4080 - else if (this.textColor) {
4081 - color = this.textColor;
4082 - }
4083 - // don't trust that a stylesheet is present, set the position.
4084 - var styletext = 'position:absolute;top:0px;left:0px;';
4085 - styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : '';
4086 - styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
4087 - styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;';
4088 - styletext += (color) ? 'color:'+color+';' : '';
4089 - styletext += (this.paddingBottom) ? 'padding-bottom:'+this.paddingBottom+';' : '';
4090 - this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>');
4091 - if (this.fontFamily) {
4092 - this._elem.css('font-family', this.fontFamily);
4093 - }
4094 - }
4095 -
4096 - return this._elem;
4097 - };
4098 -
4099 - $.jqplot.DivTitleRenderer.prototype.pack = function() {
4100 - // nothing to do here
4101 - };
4102 -
4103 - // Class: $.jqplot.LineRenderer
4104 - // The default line renderer for jqPlot, this class has no options beyond the <Series> class.
4105 - // Draws series as a line.
4106 - $.jqplot.LineRenderer = function(){
4107 - this.shapeRenderer = new $.jqplot.ShapeRenderer();
4108 - this.shadowRenderer = new $.jqplot.ShadowRenderer();
4109 - };
4110 -
4111 - // called with scope of series.
4112 - $.jqplot.LineRenderer.prototype.init = function(options, plot) {
4113 - options = options || {};
4114 - var lopts = {highlightMouseOver: options.highlightMouseOver, highlightMouseDown: options.highlightMouseDown, highlightColor: options.highlightColor};
4115 -
4116 - delete (options.highlightMouseOver);
4117 - delete (options.highlightMouseDown);
4118 - delete (options.highlightColor);
4119 -
4120 - $.extend(true, this.renderer, options);
4121 - // set the shape renderer options
4122 - var opts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, closePath:this.fill};
4123 - this.renderer.shapeRenderer.init(opts);
4124 - // set the shadow renderer options
4125 - // scale the shadowOffset to the width of the line.
4126 - if (this.lineWidth > 2.5) {
4127 - var shadow_offset = this.shadowOffset* (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
4128 - // var shadow_offset = this.shadowOffset;
4129 - }
4130 - // for skinny lines, don't make such a big shadow.
4131 - else {
4132 - var shadow_offset = this.shadowOffset*Math.atan((this.lineWidth/2.5))/0.785398163;
4133 - }
4134 - var sopts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, closePath:this.fill};
4135 - this.renderer.shadowRenderer.init(sopts);
4136 - this._areaPoints = [];
4137 - this._boundingBox = [[],[]];
4138 -
4139 - if (!this.isTrendline && this.fill) {
4140 -
4141 - // prop: highlightMouseOver
4142 - // True to highlight area on a filled plot when moused over.
4143 - // This must be false to enable highlightMouseDown to highlight when clicking on an area on a filled plot.
4144 - this.highlightMouseOver = true;
4145 - // prop: highlightMouseDown
4146 - // True to highlight when a mouse button is pressed over an area on a filled plot.
4147 - // This will be disabled if highlightMouseOver is true.
4148 - this.highlightMouseDown = false;
4149 - // prop: highlightColor
4150 - // color to use when highlighting an area on a filled plot.
4151 - this.highlightColor = null;
4152 - // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
4153 - if (lopts.highlightMouseDown && lopts.highlightMouseOver == null) {
4154 - lopts.highlightMouseOver = false;
4155 - }
4156 -
4157 - $.extend(true, this, {highlightMouseOver: lopts.highlightMouseOver, highlightMouseDown: lopts.highlightMouseDown, highlightColor: lopts.highlightColor});
4158 -
4159 - if (!this.highlightColor) {
4160 - this.highlightColor = $.jqplot.computeHighlightColors(this.fillColor);
4161 - }
4162 - // turn off traditional highlighter
4163 - if (this.highlighter) {
4164 - this.highlighter.show = false;
4165 - }
4166 - plot.postInitHooks.addOnce(postInit);
4167 - plot.postDrawHooks.addOnce(postPlotDraw);
4168 - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
4169 - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
4170 - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
4171 - plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
4172 - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
4173 - }
4174 -
4175 - };
4176 -
4177 - // Method: setGridData
4178 - // converts the user data values to grid coordinates and stores them
4179 - // in the gridData array.
4180 - // Called with scope of a series.
4181 - $.jqplot.LineRenderer.prototype.setGridData = function(plot) {
4182 - // recalculate the grid data
4183 - var xp = this._xaxis.series_u2p;
4184 - var yp = this._yaxis.series_u2p;
4185 - var data = this._plotData;
4186 - var pdata = this._prevPlotData;
4187 - this.gridData = [];
4188 - this._prevGridData = [];
4189 - for (var i=0; i<this.data.length; i++) {
4190 - // if not a line series or if no nulls in data, push the converted point onto the array.
4191 - if (data[i][0] != null && data[i][1] != null) {
4192 - this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
4193 - }
4194 - // else if there is a null, preserve it.
4195 - else if (data[i][0] == null) {
4196 - this.gridData.push([null, yp.call(this._yaxis, data[i][1])]);
4197 - }
4198 - else if (data[i][1] == null) {
4199 - this.gridData.push([xp.call(this._xaxis, data[i][0]), null]);
4200 - }
4201 - // if not a line series or if no nulls in data, push the converted point onto the array.
4202 - if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] != null) {
4203 - this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]);
4204 - }
4205 - // else if there is a null, preserve it.
4206 - else if (pdata[i] != null && pdata[i][0] == null) {
4207 - this._prevGridData.push([null, yp.call(this._yaxis, pdata[i][1])]);
4208 - }
4209 - else if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] == null) {
4210 - this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), null]);
4211 - }
4212 - }
4213 - };
4214 -
4215 - // Method: makeGridData
4216 - // converts any arbitrary data values to grid coordinates and
4217 - // returns them. This method exists so that plugins can use a series'
4218 - // linerenderer to generate grid data points without overwriting the
4219 - // grid data associated with that series.
4220 - // Called with scope of a series.
4221 - $.jqplot.LineRenderer.prototype.makeGridData = function(data, plot) {
4222 - // recalculate the grid data
4223 - var xp = this._xaxis.series_u2p;
4224 - var yp = this._yaxis.series_u2p;
4225 - var gd = [];
4226 - var pgd = [];
4227 - for (var i=0; i<data.length; i++) {
4228 - // if not a line series or if no nulls in data, push the converted point onto the array.
4229 - if (data[i][0] != null && data[i][1] != null) {
4230 - gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
4231 - }
4232 - // else if there is a null, preserve it.
4233 - else if (data[i][0] == null) {
4234 - gd.push([null, yp.call(this._yaxis, data[i][1])]);
4235 - }
4236 - else if (data[i][1] == null) {
4237 - gd.push([xp.call(this._xaxis, data[i][0]), null]);
4238 - }
4239 - }
4240 - return gd;
4241 - };
4242 -
4243 -
4244 - // called within scope of series.
4245 - $.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options) {
4246 - var i;
4247 - var opts = (options != undefined) ? options : {};
4248 - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
4249 - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
4250 - var fill = (opts.fill != undefined) ? opts.fill : this.fill;
4251 - var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
4252 - var xmin, ymin, xmax, ymax;
4253 - ctx.save();
4254 - if (gd.length) {
4255 - if (showLine) {
4256 - // if we fill, we'll have to add points to close the curve.
4257 - if (fill) {
4258 - if (this.fillToZero) {
4259 - // have to break line up into shapes at axis crossings
4260 - var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
4261 - var negativeColor = negativeColors.get(this.index);
4262 - if (! this.useNegativeColors) {
4263 - negativeColor = opts.fillStyle;
4264 - }
4265 - var isnegative = false;
4266 - var posfs = opts.fillStyle;
4267 -
4268 - // if stoking line as well as filling, get a copy of line data.
4269 - if (fillAndStroke) {
4270 - var fasgd = gd.slice(0);
4271 - }
4272 - // if not stacked, fill down to axis
4273 - if (this.index == 0 || !this._stack) {
4274 -
4275 - var tempgd = [];
4276 - this._areaPoints = [];
4277 - var pyzero = this._yaxis.series_u2p(this.fillToValue);
4278 - var pxzero = this._xaxis.series_u2p(this.fillToValue);
4279 -
4280 - if (this.fillAxis == 'y') {
4281 - tempgd.push([gd[0][0], pyzero]);
4282 - this._areaPoints.push([gd[0][0], pyzero]);
4283 -
4284 - for (var i=0; i<gd.length-1; i++) {
4285 - tempgd.push(gd[i]);
4286 - this._areaPoints.push(gd[i]);
4287 - // do we have an axis crossing?
4288 - if (this._plotData[i][1] * this._plotData[i+1][1] < 0) {
4289 - if (this._plotData[i][1] < 0) {
4290 - isnegative = true;
4291 - opts.fillStyle = negativeColor;
4292 - }
4293 - else {
4294 - isnegative = false;
4295 - opts.fillStyle = posfs;
4296 - }
4297 -
4298 - var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]);
4299 - tempgd.push([xintercept, pyzero]);
4300 - this._areaPoints.push([xintercept, pyzero]);
4301 - // now draw this shape and shadow.
4302 - if (shadow) {
4303 - this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
4304 - }
4305 - this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
4306 - // now empty temp array and continue
4307 - tempgd = [[xintercept, pyzero]];
4308 - // this._areaPoints = [[xintercept, pyzero]];
4309 - }
4310 - }
4311 - if (this._plotData[gd.length-1][1] < 0) {
4312 - isnegative = true;
4313 - opts.fillStyle = negativeColor;
4314 - }
4315 - else {
4316 - isnegative = false;
4317 - opts.fillStyle = posfs;
4318 - }
4319 - tempgd.push(gd[gd.length-1]);
4320 - this._areaPoints.push(gd[gd.length-1]);
4321 - tempgd.push([gd[gd.length-1][0], pyzero]);
4322 - this._areaPoints.push([gd[gd.length-1][0], pyzero]);
4323 - }
4324 - // now draw this shape and shadow.
4325 - if (shadow) {
4326 - this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
4327 - }
4328 - this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
4329 -
4330 -
4331 - // var gridymin = this._yaxis.series_u2p(0);
4332 - // // IE doesn't return new length on unshift
4333 - // gd.unshift([gd[0][0], gridymin]);
4334 - // len = gd.length;
4335 - // gd.push([gd[len - 1][0], gridymin]);
4336 - }
4337 - // if stacked, fill to line below
4338 - else {
4339 - var prev = this._prevGridData;
4340 - for (var i=prev.length; i>0; i--) {
4341 - gd.push(prev[i-1]);
4342 - // this._areaPoints.push(prev[i-1]);
4343 - }
4344 - if (shadow) {
4345 - this.renderer.shadowRenderer.draw(ctx, gd, opts);
4346 - }
4347 - this._areaPoints = gd;
4348 - this.renderer.shapeRenderer.draw(ctx, gd, opts);
4349 - }
4350 - }
4351 - /////////////////////////
4352 - // Not filled to zero
4353 - ////////////////////////
4354 - else {
4355 - // if stoking line as well as filling, get a copy of line data.
4356 - if (fillAndStroke) {
4357 - var fasgd = gd.slice(0);
4358 - }
4359 - // if not stacked, fill down to axis
4360 - if (this.index == 0 || !this._stack) {
4361 - // var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2;
4362 - var gridymin = ctx.canvas.height;
4363 - // IE doesn't return new length on unshift
4364 - gd.unshift([gd[0][0], gridymin]);
4365 - len = gd.length;
4366 - gd.push([gd[len - 1][0], gridymin]);
4367 - }
4368 - // if stacked, fill to line below
4369 - else {
4370 - var prev = this._prevGridData;
4371 - for (var i=prev.length; i>0; i--) {
4372 - gd.push(prev[i-1]);
4373 - }
4374 - }
4375 - this._areaPoints = gd;
4376 -
4377 - if (shadow) {
4378 - this.renderer.shadowRenderer.draw(ctx, gd, opts);
4379 - }
4380 -
4381 - this.renderer.shapeRenderer.draw(ctx, gd, opts);
4382 - }
4383 - if (fillAndStroke) {
4384 - var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false});
4385 - this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts);
4386 - //////////
4387 - // TODO: figure out some way to do shadows nicely
4388 - // if (shadow) {
4389 - // this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts);
4390 - // }
4391 - // now draw the markers
4392 - if (this.markerRenderer.show) {
4393 - for (i=0; i<fasgd.length; i++) {
4394 - this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions);
4395 - }
4396 - }
4397 - }
4398 - }
4399 - else {
4400 - if (shadow) {
4401 - this.renderer.shadowRenderer.draw(ctx, gd, opts);
4402 - }
4403 -
4404 - this.renderer.shapeRenderer.draw(ctx, gd, opts);
4405 - }
4406 - }
4407 - // calculate the bounding box
4408 - var xmin = xmax = ymin = ymax = null;
4409 - for (i=0; i<this._areaPoints.length; i++) {
4410 - var p = this._areaPoints[i];
4411 - if (xmin > p[0] || xmin == null) {
4412 - xmin = p[0];
4413 - }
4414 - if (ymax < p[1] || ymax == null) {
4415 - ymax = p[1];
4416 - }
4417 - if (xmax < p[0] || xmax == null) {
4418 - xmax = p[0];
4419 - }
4420 - if (ymin > p[1] || ymin == null) {
4421 - ymin = p[1];
4422 - }
4423 - }
4424 - this._boundingBox = [[xmin, ymax], [xmax, ymin]];
4425 -
4426 - // now draw the markers
4427 - if (this.markerRenderer.show && !fill) {
4428 - for (i=0; i<gd.length; i++) {
4429 - if (gd[i][0] != null && gd[i][1] != null) {
4430 - this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions);
4431 - }
4432 - }
4433 - }
4434 - }
4435 -
4436 - ctx.restore();
4437 - };
4438 -
4439 - $.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) {
4440 - // This is a no-op, shadows drawn with lines.
4441 - };
4442 -
4443 - // called with scope of plot.
4444 - // make sure to not leave anything highlighted.
4445 - function postInit(target, data, options) {
4446 - for (i=0; i<this.series.length; i++) {
4447 - if (this.series[i].renderer.constructor == $.jqplot.LineRenderer) {
4448 - // don't allow mouseover and mousedown at same time.
4449 - if (this.series[i].highlightMouseOver) {
4450 - this.series[i].highlightMouseDown = false;
4451 - }
4452 - }
4453 - }
4454 - this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
4455 - }
4456 -
4457 - // called within context of plot
4458 - // create a canvas which we can draw on.
4459 - // insert it before the eventCanvas, so eventCanvas will still capture events.
4460 - function postPlotDraw() {
4461 - this.plugins.lineRenderer = {highlightedSeriesIndex:null};
4462 - this.plugins.lineRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
4463 -
4464 - this.eventCanvas._elem.before(this.plugins.lineRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-lineRenderer-highlight-canvas', this._plotDimensions));
4465 - var hctx = this.plugins.lineRenderer.highlightCanvas.setContext();
4466 - }
4467 -
4468 - function highlight (plot, sidx, pidx, points) {
4469 - var s = plot.series[sidx];
4470 - var canvas = plot.plugins.lineRenderer.highlightCanvas;
4471 - canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
4472 - s._highlightedPoint = pidx;
4473 - plot.plugins.lineRenderer.highlightedSeriesIndex = sidx;
4474 - var opts = {fillStyle: s.highlightColor};
4475 - s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
4476 - }
4477 -
4478 - function unhighlight (plot) {
4479 - var canvas = plot.plugins.lineRenderer.highlightCanvas;
4480 - canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
4481 - for (var i=0; i<plot.series.length; i++) {
4482 - plot.series[i]._highlightedPoint = null;
4483 - }
4484 - plot.plugins.lineRenderer.highlightedSeriesIndex = null;
4485 - plot.target.trigger('jqplotDataUnhighlight');
4486 - }
4487 -
4488 -
4489 - function handleMove(ev, gridpos, datapos, neighbor, plot) {
4490 - if (neighbor) {
4491 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
4492 - var evt1 = jQuery.Event('jqplotDataMouseOver');
4493 - evt1.pageX = ev.pageX;
4494 - evt1.pageY = ev.pageY;
4495 - plot.target.trigger(evt1, ins);
4496 - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
4497 - var evt = jQuery.Event('jqplotDataHighlight');
4498 - evt.pageX = ev.pageX;
4499 - evt.pageY = ev.pageY;
4500 - plot.target.trigger(evt, ins);
4501 - highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
4502 - }
4503 - }
4504 - else if (neighbor == null) {
4505 - unhighlight (plot);
4506 - }
4507 - }
4508 -
4509 - function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
4510 - if (neighbor) {
4511 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
4512 - if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
4513 - var evt = jQuery.Event('jqplotDataHighlight');
4514 - evt.pageX = ev.pageX;
4515 - evt.pageY = ev.pageY;
4516 - plot.target.trigger(evt, ins);
4517 - highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
4518 - }
4519 - }
4520 - else if (neighbor == null) {
4521 - unhighlight (plot);
4522 - }
4523 - }
4524 -
4525 - function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
4526 - var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
4527 - if (idx != null && plot.series[idx].highlightMouseDown) {
4528 - unhighlight(plot);
4529 - }
4530 - }
4531 -
4532 - function handleClick(ev, gridpos, datapos, neighbor, plot) {
4533 - if (neighbor) {
4534 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
4535 - var evt = jQuery.Event('jqplotDataClick');
4536 - evt.pageX = ev.pageX;
4537 - evt.pageY = ev.pageY;
4538 - plot.target.trigger(evt, ins);
4539 - }
4540 - }
4541 -
4542 - function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
4543 - if (neighbor) {
4544 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
4545 - var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
4546 - if (idx != null && plot.series[idx].highlightMouseDown) {
4547 - unhighlight(plot);
4548 - }
4549 - var evt = jQuery.Event('jqplotDataRightClick');
4550 - evt.pageX = ev.pageX;
4551 - evt.pageY = ev.pageY;
4552 - plot.target.trigger(evt, ins);
4553 - }
4554 - }
4555 -
4556 -
4557 - // class: $.jqplot.LinearAxisRenderer
4558 - // The default jqPlot axis renderer, creating a numeric axis.
4559 - // The renderer has no additional options beyond the <Axis> object.
4560 - $.jqplot.LinearAxisRenderer = function() {
4561 - };
4562 -
4563 - // called with scope of axis object.
4564 - $.jqplot.LinearAxisRenderer.prototype.init = function(options){
4565 - $.extend(true, this, options);
4566 - var db = this._dataBounds;
4567 - // Go through all the series attached to this axis and find
4568 - // the min/max bounds for this axis.
4569 - for (var i=0; i<this._series.length; i++) {
4570 - var s = this._series[i];
4571 - var d = s._plotData;
4572 -
4573 - for (var j=0; j<d.length; j++) {
4574 - if (this.name == 'xaxis' || this.name == 'x2axis') {
4575 - if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
4576 - db.min = d[j][0];
4577 - }
4578 - if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
4579 - db.max = d[j][0];
4580 - }
4581 - }
4582 - else {
4583 - if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) {
4584 - db.min = d[j][1];
4585 - }
4586 - if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) {
4587 - db.max = d[j][1];
4588 - }
4589 - }
4590 - }
4591 - }
4592 - };
4593 -
4594 - // called with scope of axis
4595 - $.jqplot.LinearAxisRenderer.prototype.draw = function(ctx) {
4596 - if (this.show) {
4597 - // populate the axis label and value properties.
4598 - // createTicks is a method on the renderer, but
4599 - // call it within the scope of the axis.
4600 - this.renderer.createTicks.call(this);
4601 - // fill a div with axes labels in the right direction.
4602 - // Need to pregenerate each axis to get it's bounds and
4603 - // position it and the labels correctly on the plot.
4604 - var dim=0;
4605 - var temp;
4606 - // Added for theming.
4607 - if (this._elem) {
4608 - this._elem.empty();
4609 - }
4610 -
4611 - this._elem = $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
4612 -
4613 - if (this.name == 'xaxis' || this.name == 'x2axis') {
4614 - this._elem.width(this._plotDimensions.width);
4615 - }
4616 - else {
4617 - this._elem.height(this._plotDimensions.height);
4618 - }
4619 -
4620 - // create a _label object.
4621 - this.labelOptions.axis = this.name;
4622 - this._label = new this.labelRenderer(this.labelOptions);
4623 - if (this._label.show) {
4624 - var elem = this._label.draw(ctx);
4625 - elem.appendTo(this._elem);
4626 - }
4627 -
4628 - var t = this._ticks;
4629 - for (var i=0; i<t.length; i++) {
4630 - var tick = t[i];
4631 - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
4632 - var elem = tick.draw(ctx);
4633 - elem.appendTo(this._elem);
4634 - }
4635 - }
4636 - }
4637 - return this._elem;
4638 - };
4639 -
4640 - // called with scope of an axis
4641 - $.jqplot.LinearAxisRenderer.prototype.reset = function() {
4642 - this.min = this._min;
4643 - this.max = this._max;
4644 - this.tickInterval = this._tickInterval;
4645 - this.numberTicks = this._numberTicks;
4646 - // this._ticks = this.__ticks;
4647 - };
4648 -
4649 - // called with scope of axis
4650 - $.jqplot.LinearAxisRenderer.prototype.set = function() {
4651 - var dim = 0;
4652 - var temp;
4653 - var w = 0;
4654 - var h = 0;
4655 - var lshow = (this._label == null) ? false : this._label.show;
4656 - if (this.show) {
4657 - var t = this._ticks;
4658 - for (var i=0; i<t.length; i++) {
4659 - var tick = t[i];
4660 - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
4661 - if (this.name == 'xaxis' || this.name == 'x2axis') {
4662 - temp = tick._elem.outerHeight(true);
4663 - }
4664 - else {
4665 - temp = tick._elem.outerWidth(true);
4666 - }
4667 - if (temp > dim) {
4668 - dim = temp;
4669 - }
4670 - }
4671 - }
4672 -
4673 - if (lshow) {
4674 - w = this._label._elem.outerWidth(true);
4675 - h = this._label._elem.outerHeight(true);
4676 - }
4677 - if (this.name == 'xaxis') {
4678 - dim = dim + h;
4679 - this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
4680 - }
4681 - else if (this.name == 'x2axis') {
4682 - dim = dim + h;
4683 - this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
4684 - }
4685 - else if (this.name == 'yaxis') {
4686 - dim = dim + w;
4687 - this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
4688 - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
4689 - this._label._elem.css('width', w+'px');
4690 - }
4691 - }
4692 - else {
4693 - dim = dim + w;
4694 - this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
4695 - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
4696 - this._label._elem.css('width', w+'px');
4697 - }
4698 - }
4699 - }
4700 - };
4701 -
4702 - // called with scope of axis
4703 - $.jqplot.LinearAxisRenderer.prototype.createTicks = function() {
4704 - // we're are operating on an axis here
4705 - var ticks = this._ticks;
4706 - var userTicks = this.ticks;
4707 - var name = this.name;
4708 - // databounds were set on axis initialization.
4709 - var db = this._dataBounds;
4710 - var dim, interval;
4711 - var min, max;
4712 - var pos1, pos2;
4713 - var tt, i;
4714 - // get a copy of user's settings for min/max.
4715 - var userMin = this.min;
4716 - var userMax = this.max;
4717 - var userNT = this.numberTicks;
4718 - var userTI = this.tickInterval;
4719 -
4720 - // if we already have ticks, use them.
4721 - // ticks must be in order of increasing value.
4722 -
4723 - if (userTicks.length) {
4724 - // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
4725 - for (i=0; i<userTicks.length; i++){
4726 - var ut = userTicks[i];
4727 - var t = new this.tickRenderer(this.tickOptions);
4728 - if (ut.constructor == Array) {
4729 - t.value = ut[0];
4730 - t.label = ut[1];
4731 - t.setTick(ut[0], this.name);
4732 - this._ticks.push(t);
4733 - }
4734 -
4735 - else {
4736 - t.value = ut;
4737 - t.setTick(ut, this.name);
4738 - this._ticks.push(t);
4739 - }
4740 - }
4741 - this.numberTicks = userTicks.length;
4742 - this.min = this._ticks[0].value;
4743 - this.max = this._ticks[this.numberTicks-1].value;
4744 - this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
4745 - }
4746 -
4747 - // we don't have any ticks yet, let's make some!
4748 - else {
4749 - if (name == 'xaxis' || name == 'x2axis') {
4750 - dim = this._plotDimensions.width;
4751 - }
4752 - else {
4753 - dim = this._plotDimensions.height;
4754 - }
4755 -
4756 - // if min, max and number of ticks specified, user can't specify interval.
4757 - if (!this.autoscale && this.min != null && this.max != null && this.numberTicks != null) {
4758 - this.tickInterval = null;
4759 - }
4760 -
4761 - // if max, min, and interval specified and interval won't fit, ignore interval.
4762 - // if (this.min != null && this.max != null && this.tickInterval != null) {
4763 - // if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
4764 - // this.tickInterval = null;
4765 - // }
4766 - // }
4767 -
4768 - min = ((this.min != null) ? this.min : db.min);
4769 - max = ((this.max != null) ? this.max : db.max);
4770 -
4771 - // if min and max are same, space them out a bit
4772 - if (min == max) {
4773 - var adj = 0.05;
4774 - if (min > 0) {
4775 - adj = Math.max(Math.log(min)/Math.LN10, 0.05);
4776 - }
4777 - min -= adj;
4778 - max += adj;
4779 - }
4780 -
4781 - var range = max - min;
4782 - var rmin, rmax;
4783 - var temp;
4784 -
4785 - // autoscale. Can't autoscale if min or max is supplied.
4786 - // Will use numberTicks and tickInterval if supplied. Ticks
4787 - // across multiple axes may not line up depending on how
4788 - // bars are to be plotted.
4789 - if (this.autoscale && this.min == null && this.max == null) {
4790 - var rrange, ti, margin;
4791 - var forceMinZero = false;
4792 - var forceZeroLine = false;
4793 - var intervals = {min:null, max:null, average:null, stddev:null};
4794 - // if any series are bars, or if any are fill to zero, and if this
4795 - // is the axis to fill toward, check to see if we can start axis at zero.
4796 - for (var i=0; i<this._series.length; i++) {
4797 - var s = this._series[i];
4798 - var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name;
4799 - // check to see if this is the fill axis
4800 - if (this.name == faname) {
4801 - var vals = s._plotValues[s.fillAxis];
4802 - var vmin = vals[0];
4803 - var vmax = vals[0];
4804 - for (var j=1; j<vals.length; j++) {
4805 - if (vals[j] < vmin) {
4806 - vmin = vals[j];
4807 - }
4808 - else if (vals[j] > vmax) {
4809 - vmax = vals[j];
4810 - }
4811 - }
4812 - var dp = (vmax - vmin) / vmax;
4813 - // is this sries a bar?
4814 - if (s.renderer.constructor == $.jqplot.BarRenderer) {
4815 - // if no negative values and could also check range.
4816 - if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
4817 - forceMinZero = true;
4818 - }
4819 - else {
4820 - forceMinZero = false;
4821 - if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) {
4822 - forceZeroLine = true;
4823 - }
4824 - else {
4825 - forceZeroLine = false;
4826 - }
4827 - }
4828 - }
4829 -
4830 - // if not a bar and filling, use appropriate method.
4831 - else if (s.fill) {
4832 - if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
4833 - forceMinZero = true;
4834 - }
4835 - else if (vmin < 0 && vmax > 0 && s.fillToZero) {
4836 - forceMinZero = false;
4837 - forceZeroLine = true;
4838 - }
4839 - else {
4840 - forceMinZero = false;
4841 - forceZeroLine = false;
4842 - }
4843 - }
4844 -
4845 - // if not a bar and not filling, only change existing state
4846 - // if it doesn't make sense
4847 - else if (vmin < 0) {
4848 - forceMinZero = false;
4849 - }
4850 - }
4851 - }
4852 -
4853 - // check if we need make axis min at 0.
4854 - if (forceMinZero) {
4855 - // compute number of ticks
4856 - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
4857 - this.min = 0;
4858 - userMin = 0;
4859 - // what order is this range?
4860 - // what tick interval does that give us?
4861 - ti = max/(this.numberTicks-1);
4862 - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
4863 - if (ti/temp == parseInt(ti/temp, 10)) {
4864 - ti += temp;
4865 - }
4866 - this.tickInterval = Math.ceil(ti/temp) * temp;
4867 - this.max = this.tickInterval * (this.numberTicks - 1);
4868 - }
4869 -
4870 - // check if we need to make sure there is a tick at 0.
4871 - else if (forceZeroLine) {
4872 - // compute number of ticks
4873 - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
4874 - var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1));
4875 - var ntmax = this.numberTicks - 1 - ntmin;
4876 - ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax));
4877 - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
4878 - this.tickInterval = Math.ceil(ti/temp) * temp;
4879 - this.max = this.tickInterval * ntmax;
4880 - this.min = -this.tickInterval * ntmin;
4881 - }
4882 -
4883 - // if nothing else, do autoscaling which will try to line up ticks across axes.
4884 - else {
4885 - if (this.numberTicks == null){
4886 - if (this.tickInterval) {
4887 - this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
4888 - }
4889 - else {
4890 - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
4891 - }
4892 - }
4893 -
4894 - if (this.tickInterval == null) {
4895 - // get a tick interval
4896 - ti = range/(this.numberTicks - 1);
4897 -
4898 - if (ti < 1) {
4899 - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
4900 - }
4901 - else {
4902 - temp = 1;
4903 - }
4904 - this.tickInterval = Math.ceil(ti*temp*this.pad)/temp;
4905 - }
4906 - else {
4907 - temp = 1 / this.tickInterval;
4908 - }
4909 -
4910 - // try to compute a nicer, more even tick interval
4911 - // temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10));
4912 - // this.tickInterval = Math.ceil(ti/temp) * temp;
4913 - rrange = this.tickInterval * (this.numberTicks - 1);
4914 - margin = (rrange - range)/2;
4915 -
4916 - if (this.min == null) {
4917 - this.min = Math.floor(temp*(min-margin))/temp;
4918 - }
4919 - if (this.max == null) {
4920 - this.max = this.min + rrange;
4921 - }
4922 - }
4923 - }
4924 -
4925 - // Use the default algorithm which pads each axis to make the chart
4926 - // centered nicely on the grid.
4927 - else {
4928 - rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1);
4929 - rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1);
4930 - this.min = rmin;
4931 - this.max = rmax;
4932 - range = this.max - this.min;
4933 -
4934 - if (this.numberTicks == null){
4935 - // if tickInterval is specified by user, we will ignore computed maximum.
4936 - // max will be equal or greater to fit even # of ticks.
4937 - if (this.tickInterval != null) {
4938 - this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval)+1;
4939 - this.max = this.min + this.tickInterval*(this.numberTicks-1);
4940 - }
4941 - else if (dim > 100) {
4942 - this.numberTicks = parseInt(3+(dim-100)/75, 10);
4943 - }
4944 - else {
4945 - this.numberTicks = 2;
4946 - }
4947 - }
4948 -
4949 - if (this.tickInterval == null) {
4950 - this.tickInterval = range / (this.numberTicks-1);
4951 - }
4952 - }
4953 -
4954 - if (this.renderer.constructor == $.jqplot.LinearAxisRenderer) {
4955 - // fix for misleading tick display with small range and low precision.
4956 - range = this.max - this.min;
4957 - // figure out precision
4958 - var temptick = new this.tickRenderer(this.tickOptions);
4959 - // use the tick formatString or, the default.
4960 - var fs = temptick.formatString || $.jqplot.config.defaultTickFormatString;
4961 - var fs = fs.match($.jqplot.sprintf.regex)[0];
4962 - var precision = 0;
4963 - if (fs) {
4964 - if (fs.search(/[fFeEgGpP]/) > -1) {
4965 - var m = fs.match(/\%\.(\d{0,})?[eEfFgGpP]/);
4966 - if (m) precision = parseInt(m[1], 10);
4967 - else precision = 6;
4968 - }
4969 - else if (fs.search(/[di]/) > -1) {
4970 - precision = 0;
4971 - }
4972 - // fact will be <= 1;
4973 - var fact = Math.pow(10, -precision);
4974 - if (this.tickInterval < fact) {
4975 - // need to correct underrange
4976 - if (userNT == null && userTI == null) {
4977 - this.tickInterval = fact;
4978 - if (userMax == null && userMin == null) {
4979 - // this.min = Math.floor((this._dataBounds.min - this.tickInterval)/fact) * fact;
4980 - this.min = Math.floor(this._dataBounds.min/fact) * fact;
4981 - if (this.min == this._dataBounds.min) {
4982 - this.min = this._dataBounds.min - this.tickInterval;
4983 - }
4984 - // this.max = Math.ceil((this._dataBounds.max + this.tickInterval)/fact) * fact;
4985 - this.max = Math.ceil(this._dataBounds.max/fact) * fact;
4986 - if (this.max == this._dataBounds.max) {
4987 - this.max = this._dataBounds.max + this.tickInterval;
4988 - }
4989 - var n = (this.max - this.min)/this.tickInterval;
4990 - n = n.toFixed(11);
4991 - n = Math.ceil(n);
4992 - this.numberTicks = n + 1;
4993 - }
4994 - else if (userMax == null) {
4995 - // add one tick for top of range.
4996 - var n = (this._dataBounds.max - this.min) / this.tickInterval;
4997 - n = n.toFixed(11);
4998 - this.numberTicks = Math.ceil(n) + 2;
4999 - this.max = this.min + this.tickInterval * (this.numberTicks-1);
5000 - }
5001 - else if (userMin == null) {
5002 - // add one tick for bottom of range.
5003 - var n = (this.max - this._dataBounds.min) / this.tickInterval;
5004 - n = n.toFixed(11);
5005 - this.numberTicks = Math.ceil(n) + 2;
5006 - this.min = this.max - this.tickInterval * (this.numberTicks-1);
5007 - }
5008 - else {
5009 - // calculate a number of ticks so max is within axis scale
5010 - this.numberTicks = Math.ceil((userMax - userMin)/this.tickInterval) + 1;
5011 - // if user's min and max don't fit evenly in ticks, adjust.
5012 - // This takes care of cases such as user min set to 0, max set to 3.5 but tick
5013 - // format string set to %d (integer ticks)
5014 - this.min = Math.floor(userMin*Math.pow(10, precision))/Math.pow(10, precision);
5015 - this.max = Math.ceil(userMax*Math.pow(10, precision))/Math.pow(10, precision);
5016 - // this.max = this.min + this.tickInterval*(this.numberTicks-1);
5017 - this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval) + 1;
5018 - }
5019 - }
5020 - }
5021 - }
5022 - }
5023 -
5024 -
5025 -
5026 - for (var i=0; i<this.numberTicks; i++){
5027 - tt = this.min + i * this.tickInterval;
5028 - var t = new this.tickRenderer(this.tickOptions);
5029 - // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
5030 -
5031 - t.setTick(tt, this.name);
5032 - this._ticks.push(t);
5033 - }
5034 - }
5035 - };
5036 -
5037 - // called with scope of axis
5038 - $.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) {
5039 - var ticks = this._ticks;
5040 - var max = this.max;
5041 - var min = this.min;
5042 - var offmax = offsets.max;
5043 - var offmin = offsets.min;
5044 - var lshow = (this._label == null) ? false : this._label.show;
5045 -
5046 - for (var p in pos) {
5047 - this._elem.css(p, pos[p]);
5048 - }
5049 -
5050 - this._offsets = offsets;
5051 - // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
5052 - var pixellength = offmax - offmin;
5053 - var unitlength = max - min;
5054 -
5055 - // point to unit and unit to point conversions references to Plot DOM element top left corner.
5056 - this.p2u = function(p){
5057 - return (p - offmin) * unitlength / pixellength + min;
5058 - };
5059 -
5060 - this.u2p = function(u){
5061 - return (u - min) * pixellength / unitlength + offmin;
5062 - };
5063 -
5064 - if (this.name == 'xaxis' || this.name == 'x2axis'){
5065 - this.series_u2p = function(u){
5066 - return (u - min) * pixellength / unitlength;
5067 - };
5068 - this.series_p2u = function(p){
5069 - return p * unitlength / pixellength + min;
5070 - };
5071 - }
5072 -
5073 - else {
5074 - this.series_u2p = function(u){
5075 - return (u - max) * pixellength / unitlength;
5076 - };
5077 - this.series_p2u = function(p){
5078 - return p * unitlength / pixellength + max;
5079 - };
5080 - }
5081 -
5082 - if (this.show) {
5083 - if (this.name == 'xaxis' || this.name == 'x2axis') {
5084 - for (i=0; i<ticks.length; i++) {
5085 - var t = ticks[i];
5086 - if (t.show && t.showLabel) {
5087 - var shim;
5088 -
5089 - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
5090 - // will need to adjust auto positioning based on which axis this is.
5091 - var temp = (this.name == 'xaxis') ? 1 : -1;
5092 - switch (t.labelPosition) {
5093 - case 'auto':
5094 - // position at end
5095 - if (temp * t.angle < 0) {
5096 - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
5097 - }
5098 - // position at start
5099 - else {
5100 - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
5101 - }
5102 - break;
5103 - case 'end':
5104 - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
5105 - break;
5106 - case 'start':
5107 - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
5108 - break;
5109 - case 'middle':
5110 - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
5111 - break;
5112 - default:
5113 - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
5114 - break;
5115 - }
5116 - }
5117 - else {
5118 - shim = -t.getWidth()/2;
5119 - }
5120 - var val = this.u2p(t.value) + shim + 'px';
5121 - t._elem.css('left', val);
5122 - t.pack();
5123 - }
5124 - }
5125 - if (lshow) {
5126 - var w = this._label._elem.outerWidth(true);
5127 - this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
5128 - if (this.name == 'xaxis') {
5129 - this._label._elem.css('bottom', '0px');
5130 - }
5131 - else {
5132 - this._label._elem.css('top', '0px');
5133 - }
5134 - this._label.pack();
5135 - }
5136 - }
5137 - else {
5138 - for (i=0; i<ticks.length; i++) {
5139 - var t = ticks[i];
5140 - if (t.show && t.showLabel) {
5141 - var shim;
5142 - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
5143 - // will need to adjust auto positioning based on which axis this is.
5144 - var temp = (this.name == 'yaxis') ? 1 : -1;
5145 - switch (t.labelPosition) {
5146 - case 'auto':
5147 - // position at end
5148 - case 'end':
5149 - if (temp * t.angle < 0) {
5150 - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
5151 - }
5152 - else {
5153 - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
5154 - }
5155 - break;
5156 - case 'start':
5157 - if (t.angle > 0) {
5158 - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
5159 - }
5160 - else {
5161 - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
5162 - }
5163 - break;
5164 - case 'middle':
5165 - // if (t.angle > 0) {
5166 - // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
5167 - // }
5168 - // else {
5169 - // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
5170 - // }
5171 - shim = -t.getHeight()/2;
5172 - break;
5173 - default:
5174 - shim = -t.getHeight()/2;
5175 - break;
5176 - }
5177 - }
5178 - else {
5179 - shim = -t.getHeight()/2;
5180 - }
5181 -
5182 - var val = this.u2p(t.value) + shim + 'px';
5183 - t._elem.css('top', val);
5184 - t.pack();
5185 - }
5186 - }
5187 - if (lshow) {
5188 - var h = this._label._elem.outerHeight(true);
5189 - this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
5190 - if (this.name == 'yaxis') {
5191 - this._label._elem.css('left', '0px');
5192 - }
5193 - else {
5194 - this._label._elem.css('right', '0px');
5195 - }
5196 - this._label.pack();
5197 - }
5198 - }
5199 - }
5200 - };
5201 -
5202 -
5203 - // class: $.jqplot.MarkerRenderer
5204 - // The default jqPlot marker renderer, rendering the points on the line.
5205 - $.jqplot.MarkerRenderer = function(options){
5206 - // Group: Properties
5207 -
5208 - // prop: show
5209 - // wether or not to show the marker.
5210 - this.show = true;
5211 - // prop: style
5212 - // One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare
5213 - this.style = 'filledCircle';
5214 - // prop: lineWidth
5215 - // size of the line for non-filled markers.
5216 - this.lineWidth = 2;
5217 - // prop: size
5218 - // Size of the marker (diameter or circle, length of edge of square, etc.)
5219 - this.size = 9.0;
5220 - // prop: color
5221 - // color of marker. Will be set to color of series by default on init.
5222 - this.color = '#666666';
5223 - // prop: shadow
5224 - // wether or not to draw a shadow on the line
5225 - this.shadow = true;
5226 - // prop: shadowAngle
5227 - // Shadow angle in degrees
5228 - this.shadowAngle = 45;
5229 - // prop: shadowOffset
5230 - // Shadow offset from line in pixels
5231 - this.shadowOffset = 1;
5232 - // prop: shadowDepth
5233 - // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
5234 - this.shadowDepth = 3;
5235 - // prop: shadowAlpha
5236 - // Alpha channel transparency of shadow. 0 = transparent.
5237 - this.shadowAlpha = '0.07';
5238 - // prop: shadowRenderer
5239 - // Renderer that will draws the shadows on the marker.
5240 - this.shadowRenderer = new $.jqplot.ShadowRenderer();
5241 - // prop: shapeRenderer
5242 - // Renderer that will draw the marker.
5243 - this.shapeRenderer = new $.jqplot.ShapeRenderer();
5244 -
5245 - $.extend(true, this, options);
5246 - };
5247 -
5248 - $.jqplot.MarkerRenderer.prototype.init = function(options) {
5249 - $.extend(true, this, options);
5250 - var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true};
5251 - if (this.style.indexOf('filled') != -1) {
5252 - sdopt.fill = true;
5253 - }
5254 - if (this.style.indexOf('ircle') != -1) {
5255 - sdopt.isarc = true;
5256 - sdopt.closePath = false;
5257 - }
5258 - this.shadowRenderer.init(sdopt);
5259 -
5260 - var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true};
5261 - if (this.style.indexOf('filled') != -1) {
5262 - shopt.fill = true;
5263 - }
5264 - if (this.style.indexOf('ircle') != -1) {
5265 - shopt.isarc = true;
5266 - shopt.closePath = false;
5267 - }
5268 - this.shapeRenderer.init(shopt);
5269 - };
5270 -
5271 - $.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) {
5272 - var stretch = 1.2;
5273 - var dx = this.size/2/stretch;
5274 - var dy = this.size/2*stretch;
5275 - var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]];
5276 - if (this.shadow) {
5277 - this.shadowRenderer.draw(ctx, points);
5278 - }
5279 - this.shapeRenderer.draw(ctx, points, options);
5280 -
5281 - // ctx.restore();
5282 - };
5283 -
5284 - $.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) {
5285 - var stretch = 1.0;
5286 - var dx = this.size/2*stretch;
5287 - var dy = this.size/2*stretch;
5288 - var points1 = [[x, y-dy], [x, y+dy]];
5289 - var points2 = [[x+dx, y], [x-dx, y]];
5290 - var opts = $.extend(true, {}, this.options, {closePath:false});
5291 - if (this.shadow) {
5292 - this.shadowRenderer.draw(ctx, points1, {closePath:false});
5293 - this.shadowRenderer.draw(ctx, points2, {closePath:false});
5294 - }
5295 - this.shapeRenderer.draw(ctx, points1, opts);
5296 - this.shapeRenderer.draw(ctx, points2, opts);
5297 -
5298 - // ctx.restore();
5299 - };
5300 -
5301 - $.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) {
5302 - var stretch = 1.0;
5303 - var dx = this.size/2*stretch;
5304 - var dy = this.size/2*stretch;
5305 - var opts = $.extend(true, {}, this.options, {closePath:false});
5306 - var points1 = [[x-dx, y-dy], [x+dx, y+dy]];
5307 - var points2 = [[x-dx, y+dy], [x+dx, y-dy]];
5308 - if (this.shadow) {
5309 - this.shadowRenderer.draw(ctx, points1, {closePath:false});
5310 - this.shadowRenderer.draw(ctx, points2, {closePath:false});
5311 - }
5312 - this.shapeRenderer.draw(ctx, points1, opts);
5313 - this.shapeRenderer.draw(ctx, points2, opts);
5314 -
5315 - // ctx.restore();
5316 - };
5317 -
5318 - $.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) {
5319 - var stretch = 1.0;
5320 - var dx = this.size/2*stretch;
5321 - var dy = this.size/2*stretch;
5322 - var points = [[x-dx, y], [x+dx, y]];
5323 - if (this.shadow) {
5324 - this.shadowRenderer.draw(ctx, points);
5325 - }
5326 - this.shapeRenderer.draw(ctx, points, options);
5327 -
5328 - // ctx.restore();
5329 - };
5330 -
5331 - $.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) {
5332 - var stretch = 1.0;
5333 - var dx = this.size/2/stretch;
5334 - var dy = this.size/2*stretch;
5335 - var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]];
5336 - if (this.shadow) {
5337 - this.shadowRenderer.draw(ctx, points);
5338 - }
5339 - this.shapeRenderer.draw(ctx, points, options);
5340 -
5341 - // ctx.restore();
5342 - };
5343 -
5344 - $.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) {
5345 - var radius = this.size/2;
5346 - var end = 2*Math.PI;
5347 - var points = [x, y, radius, 0, end, true];
5348 - if (this.shadow) {
5349 - this.shadowRenderer.draw(ctx, points);
5350 - }
5351 - this.shapeRenderer.draw(ctx, points, options);
5352 -
5353 - // ctx.restore();
5354 - };
5355 -
5356 - $.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) {
5357 - options = options || {};
5358 - // hack here b/c shape renderer uses canvas based color style options
5359 - // and marker uses css style names.
5360 - if (options.show == null || options.show != false) {
5361 - if (options.color && !options.fillStyle) {
5362 - options.fillStyle = options.color;
5363 - }
5364 - if (options.color && !options.strokeStyle) {
5365 - options.strokeStyle = options.color;
5366 - }
5367 - switch (this.style) {
5368 - case 'diamond':
5369 - this.drawDiamond(x,y,ctx, false, options);
5370 - break;
5371 - case 'filledDiamond':
5372 - this.drawDiamond(x,y,ctx, true, options);
5373 - break;
5374 - case 'circle':
5375 - this.drawCircle(x,y,ctx, false, options);
5376 - break;
5377 - case 'filledCircle':
5378 - this.drawCircle(x,y,ctx, true, options);
5379 - break;
5380 - case 'square':
5381 - this.drawSquare(x,y,ctx, false, options);
5382 - break;
5383 - case 'filledSquare':
5384 - this.drawSquare(x,y,ctx, true, options);
5385 - break;
5386 - case 'x':
5387 - this.drawX(x,y,ctx, true, options);
5388 - break;
5389 - case 'plus':
5390 - this.drawPlus(x,y,ctx, true, options);
5391 - break;
5392 - case 'dash':
5393 - this.drawDash(x,y,ctx, true, options);
5394 - break;
5395 - default:
5396 - this.drawDiamond(x,y,ctx, false, options);
5397 - break;
5398 - }
5399 - }
5400 - };
5401 -
5402 - // class: $.jqplot.shadowRenderer
5403 - // The default jqPlot shadow renderer, rendering shadows behind shapes.
5404 - $.jqplot.ShadowRenderer = function(options){
5405 - // Group: Properties
5406 -
5407 - // prop: angle
5408 - // Angle of the shadow in degrees. Measured counter-clockwise from the x axis.
5409 - this.angle = 45;
5410 - // prop: offset
5411 - // Pixel offset at the given shadow angle of each shadow stroke from the last stroke.
5412 - this.offset = 1;
5413 - // prop: alpha
5414 - // alpha transparency of shadow stroke.
5415 - this.alpha = 0.07;
5416 - // prop: lineWidth
5417 - // width of the shadow line stroke.
5418 - this.lineWidth = 1.5;
5419 - // prop: lineJoin
5420 - // How line segments of the shadow are joined.
5421 - this.lineJoin = 'miter';
5422 - // prop: lineCap
5423 - // how ends of the shadow line are rendered.
5424 - this.lineCap = 'round';
5425 - // prop; closePath
5426 - // whether line path segment is closed upon itself.
5427 - this.closePath = false;
5428 - // prop: fill
5429 - // whether to fill the shape.
5430 - this.fill = false;
5431 - // prop: depth
5432 - // how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees.
5433 - this.depth = 3;
5434 - this.strokeStyle = 'rgba(0,0,0,0.1)';
5435 - // prop: isarc
5436 - // wether the shadow is an arc or not.
5437 - this.isarc = false;
5438 -
5439 - $.extend(true, this, options);
5440 - };
5441 -
5442 - $.jqplot.ShadowRenderer.prototype.init = function(options) {
5443 - $.extend(true, this, options);
5444 - };
5445 -
5446 - // function: draw
5447 - // draws an transparent black (i.e. gray) shadow.
5448 - //
5449 - // ctx - canvas drawing context
5450 - // points - array of points or [x, y, radius, start angle (rad), end angle (rad)]
5451 - $.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) {
5452 - ctx.save();
5453 - var opts = (options != null) ? options : {};
5454 - var fill = (opts.fill != null) ? opts.fill : this.fill;
5455 - var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
5456 - var offset = (opts.offset != null) ? opts.offset : this.offset;
5457 - var alpha = (opts.alpha != null) ? opts.alpha : this.alpha;
5458 - var depth = (opts.depth != null) ? opts.depth : this.depth;
5459 - var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
5460 - ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth;
5461 - ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin;
5462 - ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap;
5463 - ctx.strokeStyle = opts.strokeStyle || this.strokeStyle || 'rgba(0,0,0,'+alpha+')';
5464 - ctx.fillStyle = opts.fillStyle || this.fillStyle || 'rgba(0,0,0,'+alpha+')';
5465 - for (var j=0; j<depth; j++) {
5466 - ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset);
5467 - ctx.beginPath();
5468 - if (isarc) {
5469 - ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
5470 - }
5471 - else {
5472 - var move = true;
5473 - for (var i=0; i<points.length; i++) {
5474 - // skip to the first non-null point and move to it.
5475 - if (points[i][0] != null && points[i][1] != null) {
5476 - if (move) {
5477 - ctx.moveTo(points[i][0], points[i][1]);
5478 - move = false;
5479 - }
5480 - else {
5481 - ctx.lineTo(points[i][0], points[i][1]);
5482 - }
5483 - }
5484 - else {
5485 - move = true;
5486 - }
5487 - }
5488 -
5489 - }
5490 - if (closePath) {
5491 - ctx.closePath();
5492 - }
5493 - if (fill) {
5494 - ctx.fill();
5495 - }
5496 - else {
5497 - ctx.stroke();
5498 - }
5499 - }
5500 - ctx.restore();
5501 - };
5502 -
5503 - // class: $.jqplot.shapeRenderer
5504 - // The default jqPlot shape renderer. Given a set of points will
5505 - // plot them and either stroke a line (fill = false) or fill them (fill = true).
5506 - // If a filled shape is desired, closePath = true must also be set to close
5507 - // the shape.
5508 - $.jqplot.ShapeRenderer = function(options){
5509 -
5510 - this.lineWidth = 1.5;
5511 - // prop: lineJoin
5512 - // How line segments of the shadow are joined.
5513 - this.lineJoin = 'miter';
5514 - // prop: lineCap
5515 - // how ends of the shadow line are rendered.
5516 - this.lineCap = 'round';
5517 - // prop; closePath
5518 - // whether line path segment is closed upon itself.
5519 - this.closePath = false;
5520 - // prop: fill
5521 - // whether to fill the shape.
5522 - this.fill = false;
5523 - // prop: isarc
5524 - // wether the shadow is an arc or not.
5525 - this.isarc = false;
5526 - // prop: fillRect
5527 - // true to draw shape as a filled rectangle.
5528 - this.fillRect = false;
5529 - // prop: strokeRect
5530 - // true to draw shape as a stroked rectangle.
5531 - this.strokeRect = false;
5532 - // prop: clearRect
5533 - // true to cear a rectangle.
5534 - this.clearRect = false;
5535 - // prop: strokeStyle
5536 - // css color spec for the stoke style
5537 - this.strokeStyle = '#999999';
5538 - // prop: fillStyle
5539 - // css color spec for the fill style.
5540 - this.fillStyle = '#999999';
5541 -
5542 - $.extend(true, this, options);
5543 - };
5544 -
5545 - $.jqplot.ShapeRenderer.prototype.init = function(options) {
5546 - $.extend(true, this, options);
5547 - };
5548 -
5549 - // function: draw
5550 - // draws the shape.
5551 - //
5552 - // ctx - canvas drawing context
5553 - // points - array of points for shapes or
5554 - // [x, y, width, height] for rectangles or
5555 - // [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs.
5556 - $.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) {
5557 - ctx.save();
5558 - var opts = (options != null) ? options : {};
5559 - var fill = (opts.fill != null) ? opts.fill : this.fill;
5560 - var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
5561 - var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
5562 - var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect;
5563 - var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
5564 - var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
5565 - ctx.lineWidth = opts.lineWidth || this.lineWidth;
5566 - ctx.lineJoin = opts.lineJoing || this.lineJoin;
5567 - ctx.lineCap = opts.lineCap || this.lineCap;
5568 - ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle;
5569 - ctx.fillStyle = opts.fillStyle || this.fillStyle;
5570 - ctx.beginPath();
5571 - if (isarc) {
5572 - ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
5573 - if (closePath) {
5574 - ctx.closePath();
5575 - }
5576 - if (fill) {
5577 - ctx.fill();
5578 - }
5579 - else {
5580 - ctx.stroke();
5581 - }
5582 - ctx.restore();
5583 - return;
5584 - }
5585 - else if (clearRect) {
5586 - ctx.clearRect(points[0], points[1], points[2], points[3]);
5587 - ctx.restore();
5588 - return;
5589 - }
5590 - else if (fillRect || strokeRect) {
5591 - if (fillRect) {
5592 - ctx.fillRect(points[0], points[1], points[2], points[3]);
5593 - }
5594 - if (strokeRect) {
5595 - ctx.strokeRect(points[0], points[1], points[2], points[3]);
5596 - ctx.restore();
5597 - return;
5598 - }
5599 - }
5600 - else {
5601 - var move = true;
5602 - for (var i=0; i<points.length; i++) {
5603 - // skip to the first non-null point and move to it.
5604 - if (points[i][0] != null && points[i][1] != null) {
5605 - if (move) {
5606 - ctx.moveTo(points[i][0], points[i][1]);
5607 - move = false;
5608 - }
5609 - else {
5610 - ctx.lineTo(points[i][0], points[i][1]);
5611 - }
5612 - }
5613 - else {
5614 - move = true;
5615 - }
5616 - }
5617 - if (closePath) {
5618 - ctx.closePath();
5619 - }
5620 - if (fill) {
5621 - ctx.fill();
5622 - }
5623 - else {
5624 - ctx.stroke();
5625 - }
5626 - }
5627 - ctx.restore();
5628 - };
5629 -
5630 - // class $.jqplot.TableLegendRenderer
5631 - // The default legend renderer for jqPlot.
5632 - $.jqplot.TableLegendRenderer = function(){
5633 - //
5634 - };
5635 -
5636 - $.jqplot.TableLegendRenderer.prototype.init = function(options) {
5637 - $.extend(true, this, options);
5638 - };
5639 -
5640 - $.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad, reverse) {
5641 - var rs = (pad) ? this.rowSpacing : '0';
5642 - if (reverse){
5643 - var tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
5644 - }
5645 - else{
5646 - var tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
5647 - }
5648 - if (this.showSwatches) {
5649 - $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
5650 - '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+
5651 - '</div></td>').appendTo(tr);
5652 - }
5653 - if (this.showLabels) {
5654 - var elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
5655 - elem.appendTo(tr);
5656 - if (this.escapeHtml) {
5657 - elem.text(label);
5658 - }
5659 - else {
5660 - elem.html(label);
5661 - }
5662 - }
5663 - };
5664 -
5665 - // called with scope of legend
5666 - $.jqplot.TableLegendRenderer.prototype.draw = function() {
5667 - var legend = this;
5668 - if (this.show) {
5669 - var series = this._series;
5670 - // make a table. one line label per row.
5671 - var ss = 'position:absolute;';
5672 - ss += (this.background) ? 'background:'+this.background+';' : '';
5673 - ss += (this.border) ? 'border:'+this.border+';' : '';
5674 - ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
5675 - ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
5676 - ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
5677 - ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
5678 - ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
5679 - ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
5680 - ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
5681 - this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
5682 -
5683 - var pad = false,
5684 - reverse = false;
5685 - for (var i = 0; i< series.length; i++) {
5686 - s = series[i];
5687 - if (s._stack || s.renderer.constructor == $.jqplot.BezierCurveRenderer){
5688 - reverse = true;
5689 - }
5690 - if (s.show && s.showLabel) {
5691 - var lt = this.labels[i] || s.label.toString();
5692 - if (lt) {
5693 - var color = s.color;
5694 - if (reverse && i < series.length - 1){
5695 - pad = true;
5696 - }
5697 - else if (reverse && i == series.length - 1){
5698 - pad = false;
5699 - }
5700 - this.renderer.addrow.call(this, lt, color, pad, reverse);
5701 - pad = true;
5702 - }
5703 - // let plugins add more rows to legend. Used by trend line plugin.
5704 - for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
5705 - var item = $.jqplot.addLegendRowHooks[j].call(this, s);
5706 - if (item) {
5707 - this.renderer.addrow.call(this, item.label, item.color, pad);
5708 - pad = true;
5709 - }
5710 - }
5711 - }
5712 - }
5713 - }
5714 - return this._elem;
5715 - };
5716 -
5717 - $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) {
5718 - if (this.show) {
5719 - if (this.placement == 'insideGrid') {
5720 - switch (this.location) {
5721 - case 'nw':
5722 - var a = offsets.left;
5723 - var b = offsets.top;
5724 - this._elem.css('left', a);
5725 - this._elem.css('top', b);
5726 - break;
5727 - case 'n':
5728 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5729 - var b = offsets.top;
5730 - this._elem.css('left', a);
5731 - this._elem.css('top', b);
5732 - break;
5733 - case 'ne':
5734 - var a = offsets.right;
5735 - var b = offsets.top;
5736 - this._elem.css({right:a, top:b});
5737 - break;
5738 - case 'e':
5739 - var a = offsets.right;
5740 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5741 - this._elem.css({right:a, top:b});
5742 - break;
5743 - case 'se':
5744 - var a = offsets.right;
5745 - var b = offsets.bottom;
5746 - this._elem.css({right:a, bottom:b});
5747 - break;
5748 - case 's':
5749 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5750 - var b = offsets.bottom;
5751 - this._elem.css({left:a, bottom:b});
5752 - break;
5753 - case 'sw':
5754 - var a = offsets.left;
5755 - var b = offsets.bottom;
5756 - this._elem.css({left:a, bottom:b});
5757 - break;
5758 - case 'w':
5759 - var a = offsets.left;
5760 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5761 - this._elem.css({left:a, top:b});
5762 - break;
5763 - default: // same as 'se'
5764 - var a = offsets.right;
5765 - var b = offsets.bottom;
5766 - this._elem.css({right:a, bottom:b});
5767 - break;
5768 - }
5769 -
5770 - }
5771 - else if (this.placement == 'outside'){
5772 - switch (this.location) {
5773 - case 'nw':
5774 - var a = this._plotDimensions.width - offsets.left;
5775 - var b = offsets.top;
5776 - this._elem.css('right', a);
5777 - this._elem.css('top', b);
5778 - break;
5779 - case 'n':
5780 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5781 - var b = this._plotDimensions.height - offsets.top;
5782 - this._elem.css('left', a);
5783 - this._elem.css('bottom', b);
5784 - break;
5785 - case 'ne':
5786 - var a = this._plotDimensions.width - offsets.right;
5787 - var b = offsets.top;
5788 - this._elem.css({left:a, top:b});
5789 - break;
5790 - case 'e':
5791 - var a = this._plotDimensions.width - offsets.right;
5792 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5793 - this._elem.css({left:a, top:b});
5794 - break;
5795 - case 'se':
5796 - var a = this._plotDimensions.width - offsets.right;
5797 - var b = offsets.bottom;
5798 - this._elem.css({left:a, bottom:b});
5799 - break;
5800 - case 's':
5801 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5802 - var b = this._plotDimensions.height - offsets.bottom;
5803 - this._elem.css({left:a, top:b});
5804 - break;
5805 - case 'sw':
5806 - var a = this._plotDimensions.width - offsets.left;
5807 - var b = offsets.bottom;
5808 - this._elem.css({right:a, bottom:b});
5809 - break;
5810 - case 'w':
5811 - var a = this._plotDimensions.width - offsets.left;
5812 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5813 - this._elem.css({right:a, top:b});
5814 - break;
5815 - default: // same as 'se'
5816 - var a = offsets.right;
5817 - var b = offsets.bottom;
5818 - this._elem.css({right:a, bottom:b});
5819 - break;
5820 - }
5821 - }
5822 - else {
5823 - switch (this.location) {
5824 - case 'nw':
5825 - this._elem.css({left:0, top:offsets.top});
5826 - break;
5827 - case 'n':
5828 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5829 - this._elem.css({left: a, top:offsets.top});
5830 - break;
5831 - case 'ne':
5832 - this._elem.css({right:0, top:offsets.top});
5833 - break;
5834 - case 'e':
5835 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5836 - this._elem.css({right:offsets.right, top:b});
5837 - break;
5838 - case 'se':
5839 - this._elem.css({right:offsets.right, bottom:offsets.bottom});
5840 - break;
5841 - case 's':
5842 - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
5843 - this._elem.css({left: a, bottom:offsets.bottom});
5844 - break;
5845 - case 'sw':
5846 - this._elem.css({left:offsets.left, bottom:offsets.bottom});
5847 - break;
5848 - case 'w':
5849 - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
5850 - this._elem.css({left:offsets.left, top:b});
5851 - break;
5852 - default: // same as 'se'
5853 - this._elem.css({right:offsets.right, bottom:offsets.bottom});
5854 - break;
5855 - }
5856 - }
5857 - }
5858 - };
5859 -
5860 - /**
5861 - * Class: $.jqplot.ThemeEngine
5862 - * Theme Engine provides a programatic way to change some of the more
5863 - * common jqplot styling options such as fonts, colors and grid options.
5864 - * A theme engine instance is created with each plot. The theme engine
5865 - * manages a collection of themes which can be modified, added to, or
5866 - * applied to the plot.
5867 - *
5868 - * The themeEngine class is not instantiated directly.
5869 - * When a plot is initialized, the current plot options are scanned
5870 - * an a default theme named "Default" is created. This theme is
5871 - * used as the basis for other themes added to the theme engine and
5872 - * is always available.
5873 - *
5874 - * A theme is a simple javascript object with styling parameters for
5875 - * various entities of the plot. A theme has the form:
5876 - *
5877 - *
5878 - * > {
5879 - * > _name:f "Default",
5880 - * > target: {
5881 - * > backgroundColor: "transparent"
5882 - * > },
5883 - * > legend: {
5884 - * > textColor: null,
5885 - * > fontFamily: null,
5886 - * > fontSize: null,
5887 - * > border: null,
5888 - * > background: null
5889 - * > },
5890 - * > title: {
5891 - * > textColor: "rgb(102, 102, 102)",
5892 - * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
5893 - * > fontSize: "19.2px",
5894 - * > textAlign: "center"
5895 - * > },
5896 - * > seriesStyles: {},
5897 - * > series: [{
5898 - * > color: "#4bb2c5",
5899 - * > lineWidth: 2.5,
5900 - * > shadow: true,
5901 - * > fillColor: "#4bb2c5",
5902 - * > showMarker: true,
5903 - * > markerOptions: {
5904 - * > color: "#4bb2c5",
5905 - * > show: true,
5906 - * > style: 'filledCircle',
5907 - * > lineWidth: 1.5,
5908 - * > size: 4,
5909 - * > shadow: true
5910 - * > }
5911 - * > }],
5912 - * > grid: {
5913 - * > drawGridlines: true,
5914 - * > gridLineColor: "#cccccc",
5915 - * > gridLineWidth: 1,
5916 - * > backgroundColor: "#fffdf6",
5917 - * > borderColor: "#999999",
5918 - * > borderWidth: 2,
5919 - * > shadow: true
5920 - * > },
5921 - * > axesStyles: {
5922 - * > label: {},
5923 - * > ticks: {}
5924 - * > },
5925 - * > axes: {
5926 - * > xaxis: {
5927 - * > borderColor: "#999999",
5928 - * > borderWidth: 2,
5929 - * > ticks: {
5930 - * > show: true,
5931 - * > showGridline: true,
5932 - * > showLabel: true,
5933 - * > showMark: true,
5934 - * > size: 4,
5935 - * > textColor: "",
5936 - * > whiteSpace: "nowrap",
5937 - * > fontSize: "12px",
5938 - * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
5939 - * > },
5940 - * > label: {
5941 - * > textColor: "rgb(102, 102, 102)",
5942 - * > whiteSpace: "normal",
5943 - * > fontSize: "14.6667px",
5944 - * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
5945 - * > fontWeight: "400"
5946 - * > }
5947 - * > },
5948 - * > yaxis: {
5949 - * > borderColor: "#999999",
5950 - * > borderWidth: 2,
5951 - * > ticks: {
5952 - * > show: true,
5953 - * > showGridline: true,
5954 - * > showLabel: true,
5955 - * > showMark: true,
5956 - * > size: 4,
5957 - * > textColor: "",
5958 - * > whiteSpace: "nowrap",
5959 - * > fontSize: "12px",
5960 - * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
5961 - * > },
5962 - * > label: {
5963 - * > textColor: null,
5964 - * > whiteSpace: null,
5965 - * > fontSize: null,
5966 - * > fontFamily: null,
5967 - * > fontWeight: null
5968 - * > }
5969 - * > },
5970 - * > x2axis: {...
5971 - * > },
5972 - * > ...
5973 - * > y9axis: {...
5974 - * > }
5975 - * > }
5976 - * > }
5977 - *
5978 - * "seriesStyles" is a style object that will be applied to all series in the plot.
5979 - * It will forcibly override any styles applied on the individual series. "axesStyles" is
5980 - * a style object that will be applied to all axes in the plot. It will also forcibly
5981 - * override any styles on the individual axes.
5982 - *
5983 - * The example shown above has series options for a line series. Options for other
5984 - * series types are shown below:
5985 - *
5986 - * Bar Series:
5987 - *
5988 - * > {
5989 - * > color: "#4bb2c5",
5990 - * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
5991 - * > lineWidth: 2.5,
5992 - * > shadow: true,
5993 - * > barPadding: 2,
5994 - * > barMargin: 10,
5995 - * > barWidth: 15.09375,
5996 - * > highlightColors: ["rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)"]
5997 - * > }
5998 - *
5999 - * Pie Series:
6000 - *
6001 - * > {
6002 - * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
6003 - * > padding: 20,
6004 - * > sliceMargin: 0,
6005 - * > fill: true,
6006 - * > shadow: true,
6007 - * > startAngle: 0,
6008 - * > lineWidth: 2.5,
6009 - * > highlightColors: ["rgb(129,201,214)", "rgb(240,189,104)", "rgb(214,202,165)", "rgb(137,180,158)", "rgb(168,180,137)", "rgb(180,174,89)", "rgb(180,113,161)", "rgb(129,141,236)", "rgb(227,205,120)", "rgb(255,138,76)", "rgb(76,169,219)", "rgb(215,126,190)", "rgb(220,232,135)", "rgb(200,167,96)", "rgb(103,202,235)", "rgb(208,154,215)"]
6010 - * > }
6011 - *
6012 - * Funnel Series:
6013 - *
6014 - * > {
6015 - * > color: "#4bb2c5",
6016 - * > lineWidth: 2,
6017 - * > shadow: true,
6018 - * > padding: {
6019 - * > top: 20,
6020 - * > right: 20,
6021 - * > bottom: 20,
6022 - * > left: 20
6023 - * > },
6024 - * > sectionMargin: 6,
6025 - * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
6026 - * > highlightColors: ["rgb(147,208,220)", "rgb(242,199,126)", "rgb(220,210,178)", "rgb(154,191,172)", "rgb(180,191,154)", "rgb(191,186,112)", "rgb(191,133,174)", "rgb(147,157,238)", "rgb(231,212,139)", "rgb(255,154,102)", "rgb(102,181,224)", "rgb(221,144,199)", "rgb(225,235,152)", "rgb(200,167,96)", "rgb(124,210,238)", "rgb(215,169,221)"]
6027 - * > }
6028 - *
6029 - */
6030 - $.jqplot.ThemeEngine = function(){
6031 - // Group: Properties
6032 - //
6033 - // prop: themes
6034 - // hash of themes managed by the theme engine.
6035 - // Indexed by theme name.
6036 - this.themes = {};
6037 - // prop: activeTheme
6038 - // Pointer to currently active theme
6039 - this.activeTheme=null;
6040 -
6041 - };
6042 -
6043 - // called with scope of plot
6044 - $.jqplot.ThemeEngine.prototype.init = function() {
6045 - // get the Default theme from the current plot settings.
6046 - var th = new $.jqplot.Theme({_name:'Default'});
6047 - var n, i;
6048 -
6049 - for (n in th.target) {
6050 - if (n == "textColor") {
6051 - th.target[n] = this.target.css('color');
6052 - }
6053 - else {
6054 - th.target[n] = this.target.css(n);
6055 - }
6056 - }
6057 -
6058 - if (this.title.show && this.title._elem) {
6059 - for (n in th.title) {
6060 - if (n == "textColor") {
6061 - th.title[n] = this.title._elem.css('color');
6062 - }
6063 - else {
6064 - th.title[n] = this.title._elem.css(n);
6065 - }
6066 - }
6067 - }
6068 -
6069 - for (n in th.grid) {
6070 - th.grid[n] = this.grid[n];
6071 - }
6072 - if (th.grid.backgroundColor == null && this.grid.background != null) {
6073 - th.grid.backgroundColor = this.grid.background;
6074 - }
6075 - if (this.legend.show && this.legend._elem) {
6076 - for (n in th.legend) {
6077 - if (n == 'textColor') {
6078 - th.legend[n] = this.legend._elem.css('color');
6079 - }
6080 - else {
6081 - th.legend[n] = this.legend._elem.css(n);
6082 - }
6083 - }
6084 - }
6085 - var s;
6086 -
6087 - for (i=0; i<this.series.length; i++) {
6088 - s = this.series[i];
6089 - if (s.renderer.constructor == $.jqplot.LineRenderer) {
6090 - th.series.push(new LineSeriesProperties());
6091 - }
6092 - else if (s.renderer.constructor == $.jqplot.BarRenderer) {
6093 - th.series.push(new BarSeriesProperties());
6094 - }
6095 - else if (s.renderer.constructor == $.jqplot.PieRenderer) {
6096 - th.series.push(new PieSeriesProperties());
6097 - }
6098 - else if (s.renderer.constructor == $.jqplot.DonutRenderer) {
6099 - th.series.push(new DonutSeriesProperties());
6100 - }
6101 - else if (s.renderer.constructor == $.jqplot.FunnelRenderer) {
6102 - th.series.push(new FunnelSeriesProperties());
6103 - }
6104 - else if (s.renderer.constructor == $.jqplot.MeterGaugeRenderer) {
6105 - th.series.push(new MeterSeriesProperties());
6106 - }
6107 - else {
6108 - th.series.push({});
6109 - }
6110 - for (n in th.series[i]) {
6111 - th.series[i][n] = s[n];
6112 - }
6113 - }
6114 - var a, ax;
6115 - for (n in this.axes) {
6116 - ax = this.axes[n];
6117 - a = th.axes[n] = new AxisProperties();
6118 - a.borderColor = ax.borderColor;
6119 - a.borderWidth = ax.borderWidth;
6120 - if (ax._ticks && ax._ticks[0]) {
6121 - for (nn in a.ticks) {
6122 - if (ax._ticks[0].hasOwnProperty(nn)) {
6123 - a.ticks[nn] = ax._ticks[0][nn];
6124 - }
6125 - else if (ax._ticks[0]._elem){
6126 - a.ticks[nn] = ax._ticks[0]._elem.css(nn);
6127 - }
6128 - }
6129 - }
6130 - if (ax._label && ax._label.show) {
6131 - for (nn in a.label) {
6132 - // a.label[nn] = ax._label._elem.css(nn);
6133 - if (ax._label[nn]) {
6134 - a.label[nn] = ax._label[nn];
6135 - }
6136 - else if (ax._label._elem){
6137 - if (nn == 'textColor') {
6138 - a.label[nn] = ax._label._elem.css('color');
6139 - }
6140 - else {
6141 - a.label[nn] = ax._label._elem.css(nn);
6142 - }
6143 - }
6144 - }
6145 - }
6146 - }
6147 - this.themeEngine._add(th);
6148 - this.themeEngine.activeTheme = this.themeEngine.themes[th._name];
6149 - };
6150 - /**
6151 - * Group: methods
6152 - *
6153 - * method: get
6154 - *
6155 - * Get and return the named theme or the active theme if no name given.
6156 - *
6157 - * parameter:
6158 - *
6159 - * name - name of theme to get.
6160 - *
6161 - * returns:
6162 - *
6163 - * Theme instance of given name.
6164 - */
6165 - $.jqplot.ThemeEngine.prototype.get = function(name) {
6166 - if (!name) {
6167 - // return the active theme
6168 - return this.activeTheme;
6169 - }
6170 - else {
6171 - return this.themes[name];
6172 - }
6173 - };
6174 -
6175 - function numericalOrder(a,b) { return a-b; }
6176 -
6177 - /**
6178 - * method: getThemeNames
6179 - *
6180 - * Return the list of theme names in this manager in alpha-numerical order.
6181 - *
6182 - * parameter:
6183 - *
6184 - * None
6185 - *
6186 - * returns:
6187 - *
6188 - * A the list of theme names in this manager in alpha-numerical order.
6189 - */
6190 - $.jqplot.ThemeEngine.prototype.getThemeNames = function() {
6191 - var tn = [];
6192 - for (var n in this.themes) {
6193 - tn.push(n);
6194 - }
6195 - return tn.sort(numericalOrder);
6196 - };
6197 -
6198 - /**
6199 - * method: getThemes
6200 - *
6201 - * Return a list of themes in alpha-numerical order by name.
6202 - *
6203 - * parameter:
6204 - *
6205 - * None
6206 - *
6207 - * returns:
6208 - *
6209 - * A list of themes in alpha-numerical order by name.
6210 - */
6211 - $.jqplot.ThemeEngine.prototype.getThemes = function() {
6212 - var tn = [];
6213 - var themes = [];
6214 - for (var n in this.themes) {
6215 - tn.push(n);
6216 - }
6217 - tn.sort(numericalOrder);
6218 - for (var i=0; i<tn.length; i++) {
6219 - themes.push(this.themes[tn[i]]);
6220 - }
6221 - return themes;
6222 - };
6223 -
6224 - $.jqplot.ThemeEngine.prototype.activate = function(plot, name) {
6225 - // sometimes need to redraw whole plot.
6226 - var redrawPlot = false;
6227 - if (!name && this.activeTheme && this.activeTheme._name) {
6228 - name = this.activeTheme._name;
6229 - }
6230 - if (!this.themes.hasOwnProperty(name)) {
6231 - throw new Error("No theme of that name");
6232 - }
6233 - else {
6234 - var th = this.themes[name];
6235 - this.activeTheme = th;
6236 - var val, checkBorderColor = false, checkBorderWidth = false;
6237 - var arr = ['xaxis', 'x2axis', 'yaxis', 'y2axis'];
6238 -
6239 - for (i=0; i<arr.length; i++) {
6240 - var ax = arr[i];
6241 - if (th.axesStyles.borderColor != null) {
6242 - plot.axes[ax].borderColor = th.axesStyles.borderColor;
6243 - }
6244 - if (th.axesStyles.borderWidth != null) {
6245 - plot.axes[ax].borderWidth = th.axesStyles.borderWidth;
6246 - }
6247 - }
6248 -
6249 - for (axname in plot.axes) {
6250 - var axis = plot.axes[axname];
6251 - if (axis.show) {
6252 - var thaxis = th.axes[axname] || {};
6253 - var thaxstyle = th.axesStyles;
6254 - var thax = $.jqplot.extend(true, {}, thaxis, thaxstyle);
6255 - val = (th.axesStyles.borderColor != null) ? th.axesStyles.borderColor : thax.borderColor;
6256 - if (thax.borderColor != null) {
6257 - axis.borderColor = thax.borderColor;
6258 - redrawPlot = true;
6259 - }
6260 - val = (th.axesStyles.borderWidth != null) ? th.axesStyles.borderWidth : thax.borderWidth;
6261 - if (thax.borderWidth != null) {
6262 - axis.borderWidth = thax.borderWidth;
6263 - redrawPlot = true;
6264 - }
6265 - if (axis._ticks && axis._ticks[0]) {
6266 - for (nn in thax.ticks) {
6267 - // val = null;
6268 - // if (th.axesStyles.ticks && th.axesStyles.ticks[nn] != null) {
6269 - // val = th.axesStyles.ticks[nn];
6270 - // }
6271 - // else if (thax.ticks[nn] != null){
6272 - // val = thax.ticks[nn]
6273 - // }
6274 - val = thax.ticks[nn];
6275 - if (val != null) {
6276 - axis.tickOptions[nn] = val;
6277 - axis._ticks = [];
6278 - redrawPlot = true;
6279 - }
6280 - }
6281 - }
6282 - if (axis._label && axis._label.show) {
6283 - for (nn in thax.label) {
6284 - // val = null;
6285 - // if (th.axesStyles.label && th.axesStyles.label[nn] != null) {
6286 - // val = th.axesStyles.label[nn];
6287 - // }
6288 - // else if (thax.label && thax.label[nn] != null){
6289 - // val = thax.label[nn]
6290 - // }
6291 - val = thax.label[nn];
6292 - if (val != null) {
6293 - axis.labelOptions[nn] = val;
6294 - redrawPlot = true;
6295 - }
6296 - }
6297 - }
6298 -
6299 - }
6300 - }
6301 -
6302 - for (var n in th.grid) {
6303 - if (th.grid[n] != null) {
6304 - plot.grid[n] = th.grid[n];
6305 - }
6306 - }
6307 - if (!redrawPlot) {
6308 - plot.grid.draw();
6309 - }
6310 -
6311 - if (plot.legend.show) {
6312 - for (n in th.legend) {
6313 - if (th.legend[n] != null) {
6314 - plot.legend[n] = th.legend[n];
6315 - }
6316 - }
6317 - }
6318 - if (plot.title.show) {
6319 - for (n in th.title) {
6320 - if (th.title[n] != null) {
6321 - plot.title[n] = th.title[n];
6322 - }
6323 - }
6324 - }
6325 -
6326 - var i;
6327 - for (i=0; i<th.series.length; i++) {
6328 - var opts = {};
6329 - var redrawSeries = false;
6330 - for (n in th.series[i]) {
6331 - val = (th.seriesStyles[n] != null) ? th.seriesStyles[n] : th.series[i][n];
6332 - if (val != null) {
6333 - opts[n] = val;
6334 - if (n == 'color') {
6335 - plot.series[i].renderer.shapeRenderer.fillStyle = val;
6336 - plot.series[i].renderer.shapeRenderer.strokeStyle = val;
6337 - plot.series[i][n] = val;
6338 - }
6339 - else if (n == 'lineWidth') {
6340 - plot.series[i].renderer.shapeRenderer.lineWidth = val;
6341 - plot.series[i][n] = val;
6342 - }
6343 - else if (n == 'markerOptions') {
6344 - merge (plot.series[i].markerOptions, val);
6345 - merge (plot.series[i].markerRenderer, val);
6346 - }
6347 - else {
6348 - plot.series[i][n] = val;
6349 - }
6350 - redrawPlot = true;
6351 - }
6352 - }
6353 - }
6354 -
6355 - if (redrawPlot) {
6356 - plot.target.empty();
6357 - plot.draw();
6358 - }
6359 -
6360 - for (n in th.target) {
6361 - if (th.target[n] != null) {
6362 - plot.target.css(n, th.target[n]);
6363 - }
6364 - }
6365 - }
6366 -
6367 - };
6368 -
6369 - $.jqplot.ThemeEngine.prototype._add = function(theme, name) {
6370 - if (name) {
6371 - theme._name = name;
6372 - }
6373 - if (!theme._name) {
6374 - theme._name = Date.parse(new Date());
6375 - }
6376 - if (!this.themes.hasOwnProperty(theme._name)) {
6377 - this.themes[theme._name] = theme;
6378 - }
6379 - else {
6380 - throw new Error("jqplot.ThemeEngine Error: Theme already in use");
6381 - }
6382 - };
6383 -
6384 - // method remove
6385 - // Delete the named theme, return true on success, false on failure.
6386 -
6387 -
6388 - /**
6389 - * method: remove
6390 - *
6391 - * Remove the given theme from the themeEngine.
6392 - *
6393 - * parameters:
6394 - *
6395 - * name - name of the theme to remove.
6396 - *
6397 - * returns:
6398 - *
6399 - * true on success, false on failure.
6400 - */
6401 - $.jqplot.ThemeEngine.prototype.remove = function(name) {
6402 - if (name == 'Default') {
6403 - return false;
6404 - }
6405 - return delete this.themes[name];
6406 - };
6407 -
6408 - /**
6409 - * method: newTheme
6410 - *
6411 - * Create a new theme based on the default theme, adding it the themeEngine.
6412 - *
6413 - * parameters:
6414 - *
6415 - * name - name of the new theme.
6416 - * obj - optional object of styles to be applied to this new theme.
6417 - *
6418 - * returns:
6419 - *
6420 - * new Theme object.
6421 - */
6422 - $.jqplot.ThemeEngine.prototype.newTheme = function(name, obj) {
6423 - if (typeof(name) == 'object') {
6424 - obj = obj || name;
6425 - name = null;
6426 - }
6427 - if (obj && obj._name) {
6428 - name = obj._name;
6429 - }
6430 - else {
6431 - name = name || Date.parse(new Date());
6432 - }
6433 - // var th = new $.jqplot.Theme(name);
6434 - var th = this.copy(this.themes['Default']._name, name);
6435 - $.jqplot.extend(th, obj);
6436 - return th;
6437 - };
6438 -
6439 - // function clone(obj) {
6440 - // return eval(obj.toSource());
6441 - // }
6442 -
6443 - function clone(obj){
6444 - if(obj == null || typeof(obj) != 'object'){
6445 - return obj;
6446 - }
6447 -
6448 - var temp = new obj.constructor();
6449 - for(var key in obj){
6450 - temp[key] = clone(obj[key]);
6451 - }
6452 - return temp;
6453 - }
6454 -
6455 - $.jqplot.clone = clone;
6456 -
6457 - function merge(obj1, obj2) {
6458 - if (obj2 == null || typeof(obj2) != 'object') {
6459 - return;
6460 - }
6461 - for (var key in obj2) {
6462 - if (key == 'highlightColors') {
6463 - obj1[key] = clone(obj2[key]);
6464 - }
6465 - if (obj2[key] != null && typeof(obj2[key]) == 'object') {
6466 - if (!obj1.hasOwnProperty(key)) {
6467 - obj1[key] = {};
6468 - }
6469 - merge(obj1[key], obj2[key]);
6470 - }
6471 - else {
6472 - obj1[key] = obj2[key];
6473 - }
6474 - }
6475 - }
6476 -
6477 - $.jqplot.merge = merge;
6478 -
6479 - // Use the jQuery 1.3.2 extend function since behaviour in jQuery 1.4 seems problematic
6480 - $.jqplot.extend = function() {
6481 - // copy reference to target object
6482 - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
6483 -
6484 - // Handle a deep copy situation
6485 - if ( typeof target === "boolean" ) {
6486 - deep = target;
6487 - target = arguments[1] || {};
6488 - // skip the boolean and the target
6489 - i = 2;
6490 - }
6491 -
6492 - // Handle case when target is a string or something (possible in deep copy)
6493 - if ( typeof target !== "object" && !toString.call(target) === "[object Function]" ) {
6494 - target = {};
6495 - }
6496 -
6497 - for ( ; i < length; i++ ){
6498 - // Only deal with non-null/undefined values
6499 - if ( (options = arguments[ i ]) != null ) {
6500 - // Extend the base object
6501 - for ( var name in options ) {
6502 - var src = target[ name ], copy = options[ name ];
6503 -
6504 - // Prevent never-ending loop
6505 - if ( target === copy ) {
6506 - continue;
6507 - }
6508 -
6509 - // Recurse if we're merging object values
6510 - if ( deep && copy && typeof copy === "object" && !copy.nodeType ) {
6511 - target[ name ] = $.jqplot.extend( deep,
6512 - // Never move original objects, clone them
6513 - src || ( copy.length != null ? [ ] : { } )
6514 - , copy );
6515 - }
6516 - // Don't bring in undefined values
6517 - else if ( copy !== undefined ) {
6518 - target[ name ] = copy;
6519 - }
6520 - }
6521 - }
6522 - }
6523 - // Return the modified object
6524 - return target;
6525 - };
6526 -
6527 - /**
6528 - * method: rename
6529 - *
6530 - * Rename a theme.
6531 - *
6532 - * parameters:
6533 - *
6534 - * oldName - current name of the theme.
6535 - * newName - desired name of the theme.
6536 - *
6537 - * returns:
6538 - *
6539 - * new Theme object.
6540 - */
6541 - $.jqplot.ThemeEngine.prototype.rename = function (oldName, newName) {
6542 - if (oldName == 'Default' || newName == 'Default') {
6543 - throw new Error ("jqplot.ThemeEngine Error: Cannot rename from/to Default");
6544 - }
6545 - if (this.themes.hasOwnProperty(newName)) {
6546 - throw new Error ("jqplot.ThemeEngine Error: New name already in use.");
6547 - }
6548 - else if (this.themes.hasOwnProperty(oldName)) {
6549 - var th = this.copy (oldName, newName);
6550 - this.remove(oldName);
6551 - return th;
6552 - }
6553 - throw new Error("jqplot.ThemeEngine Error: Old name or new name invalid");
6554 - };
6555 -
6556 - /**
6557 - * method: copy
6558 - *
6559 - * Create a copy of an existing theme in the themeEngine, adding it the themeEngine.
6560 - *
6561 - * parameters:
6562 - *
6563 - * sourceName - name of the existing theme.
6564 - * targetName - name of the copy.
6565 - * obj - optional object of style parameter to apply to the new theme.
6566 - *
6567 - * returns:
6568 - *
6569 - * new Theme object.
6570 - */
6571 - $.jqplot.ThemeEngine.prototype.copy = function (sourceName, targetName, obj) {
6572 - if (targetName == 'Default') {
6573 - throw new Error ("jqplot.ThemeEngine Error: Cannot copy over Default theme");
6574 - }
6575 - if (!this.themes.hasOwnProperty(sourceName)) {
6576 - var s = "jqplot.ThemeEngine Error: Source name invalid";
6577 - throw new Error(s);
6578 - }
6579 - if (this.themes.hasOwnProperty(targetName)) {
6580 - var s = "jqplot.ThemeEngine Error: Target name invalid";
6581 - throw new Error(s);
6582 - }
6583 - else {
6584 - var th = clone(this.themes[sourceName]);
6585 - th._name = targetName;
6586 - $.jqplot.extend(true, th, obj);
6587 - this._add(th);
6588 - return th;
6589 - }
6590 - };
6591 -
6592 -
6593 - $.jqplot.Theme = function(name, obj) {
6594 - if (typeof(name) == 'object') {
6595 - obj = obj || name;
6596 - name = null;
6597 - }
6598 - name = name || Date.parse(new Date());
6599 - this._name = name;
6600 - this.target = {
6601 - backgroundColor: null
6602 - };
6603 - this.legend = {
6604 - textColor: null,
6605 - fontFamily: null,
6606 - fontSize: null,
6607 - border: null,
6608 - background: null
6609 - };
6610 - this.title = {
6611 - textColor: null,
6612 - fontFamily: null,
6613 - fontSize: null,
6614 - textAlign: null
6615 - };
6616 - this.seriesStyles = {};
6617 - this.series = [];
6618 - this.grid = {
6619 - drawGridlines: null,
6620 - gridLineColor: null,
6621 - gridLineWidth: null,
6622 - backgroundColor: null,
6623 - borderColor: null,
6624 - borderWidth: null,
6625 - shadow: null
6626 - };
6627 - this.axesStyles = {label:{}, ticks:{}};
6628 - this.axes = {};
6629 - if (typeof(obj) == 'string') {
6630 - this._name = obj;
6631 - }
6632 - else if(typeof(obj) == 'object') {
6633 - $.jqplot.extend(true, this, obj);
6634 - }
6635 - };
6636 -
6637 - var AxisProperties = function() {
6638 - this.borderColor = null;
6639 - this.borderWidth = null;
6640 - this.ticks = new AxisTicks();
6641 - this.label = new AxisLabel();
6642 - };
6643 -
6644 - var AxisTicks = function() {
6645 - this.show = null;
6646 - this.showGridline = null;
6647 - this.showLabel = null;
6648 - this.showMark = null;
6649 - this.size = null;
6650 - this.textColor = null;
6651 - this.whiteSpace = null;
6652 - this.fontSize = null;
6653 - this.fontFamily = null;
6654 - };
6655 -
6656 - var AxisLabel = function() {
6657 - this.textColor = null;
6658 - this.whiteSpace = null;
6659 - this.fontSize = null;
6660 - this.fontFamily = null;
6661 - this.fontWeight = null;
6662 - };
6663 -
6664 - var LineSeriesProperties = function() {
6665 - this.color=null;
6666 - this.lineWidth=null;
6667 - this.shadow=null;
6668 - this.fillColor=null;
6669 - this.showMarker=null;
6670 - this.markerOptions = new MarkerOptions();
6671 - };
6672 -
6673 - var MarkerOptions = function() {
6674 - this.show = null;
6675 - this.style = null;
6676 - this.lineWidth = null;
6677 - this.size = null;
6678 - this.color = null;
6679 - this.shadow = null;
6680 - };
6681 -
6682 - var BarSeriesProperties = function() {
6683 - this.color=null;
6684 - this.seriesColors=null;
6685 - this.lineWidth=null;
6686 - this.shadow=null;
6687 - this.barPadding=null;
6688 - this.barMargin=null;
6689 - this.barWidth=null;
6690 - this.highlightColors=null;
6691 - };
6692 -
6693 - var PieSeriesProperties = function() {
6694 - this.seriesColors=null;
6695 - this.padding=null;
6696 - this.sliceMargin=null;
6697 - this.fill=null;
6698 - this.shadow=null;
6699 - this.startAngle=null;
6700 - this.lineWidth=null;
6701 - this.highlightColors=null;
6702 - };
6703 -
6704 - var DonutSeriesProperties = function() {
6705 - this.seriesColors=null;
6706 - this.padding=null;
6707 - this.sliceMargin=null;
6708 - this.fill=null;
6709 - this.shadow=null;
6710 - this.startAngle=null;
6711 - this.lineWidth=null;
6712 - this.innerDiameter=null;
6713 - this.thickness=null;
6714 - this.ringMargin=null;
6715 - this.highlightColors=null;
6716 - };
6717 -
6718 - var FunnelSeriesProperties = function() {
6719 - this.color=null;
6720 - this.lineWidth=null;
6721 - this.shadow=null;
6722 - this.padding=null;
6723 - this.sectionMargin=null;
6724 - this.seriesColors=null;
6725 - this.highlightColors=null;
6726 - };
6727 -
6728 - var MeterSeriesProperties = function() {
6729 - this.padding=null;
6730 - this.backgroundColor=null;
6731 - this.ringColor=null;
6732 - this.tickColor=null;
6733 - this.ringWidth=null;
6734 - this.intervalColors=null;
6735 - this.intervalInnerRadius=null;
6736 - this.intervalOuterRadius=null;
6737 - this.hubRadius=null;
6738 - this.needleThickness=null;
6739 - this.needlePad=null;
6740 - };
6741 -
6742 -
6743 -
6744 - /**
6745 - * JavaScript printf/sprintf functions.
6746 - *
6747 - * This code has been adapted from the publicly available sprintf methods
6748 - * by Ash Searle. His original header follows:
6749 - *
6750 - * This code is unrestricted: you are free to use it however you like.
6751 - *
6752 - * The functions should work as expected, performing left or right alignment,
6753 - * truncating strings, outputting numbers with a required precision etc.
6754 - *
6755 - * For complex cases, these functions follow the Perl implementations of
6756 - * (s)printf, allowing arguments to be passed out-of-order, and to set the
6757 - * precision or length of the output based on arguments instead of fixed
6758 - * numbers.
6759 - *
6760 - * See http://perldoc.perl.org/functions/sprintf.html for more information.
6761 - *
6762 - * Implemented:
6763 - * - zero and space-padding
6764 - * - right and left-alignment,
6765 - * - base X prefix (binary, octal and hex)
6766 - * - positive number prefix
6767 - * - (minimum) width
6768 - * - precision / truncation / maximum width
6769 - * - out of order arguments
6770 - *
6771 - * Not implemented (yet):
6772 - * - vector flag
6773 - * - size (bytes, words, long-words etc.)
6774 - *
6775 - * Will not implement:
6776 - * - %n or %p (no pass-by-reference in JavaScript)
6777 - *
6778 - * @version 2007.04.27
6779 - * @author Ash Searle
6780 - *
6781 - * You can see the original work and comments on his blog:
6782 - * http://hexmen.com/blog/2007/03/printf-sprintf/
6783 - * http://hexmen.com/js/sprintf.js
6784 - */
6785 -
6786 - /**
6787 - * @Modifications 2009.05.26
6788 - * @author Chris Leonello
6789 - *
6790 - * Added %p %P specifier
6791 - * Acts like %g or %G but will not add more significant digits to the output than present in the input.
6792 - * Example:
6793 - * Format: '%.3p', Input: 0.012, Output: 0.012
6794 - * Format: '%.3g', Input: 0.012, Output: 0.0120
6795 - * Format: '%.4p', Input: 12.0, Output: 12.0
6796 - * Format: '%.4g', Input: 12.0, Output: 12.00
6797 - * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5
6798 - * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5
6799 - */
6800 - $.jqplot.sprintf = function() {
6801 - function pad(str, len, chr, leftJustify) {
6802 - var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
6803 - return leftJustify ? str + padding : padding + str;
6804 -
6805 - }
6806 -
6807 - function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) {
6808 - var diff = minWidth - value.length;
6809 - if (diff > 0) {
6810 - var spchar = ' ';
6811 - if (htmlSpace) { spchar = '&nbsp;'; }
6812 - if (leftJustify || !zeroPad) {
6813 - value = pad(value, minWidth, spchar, leftJustify);
6814 - } else {
6815 - value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
6816 - }
6817 - }
6818 - return value;
6819 - }
6820 -
6821 - function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
6822 - // Note: casts negative numbers to positive ones
6823 - var number = value >>> 0;
6824 - prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
6825 - value = prefix + pad(number.toString(base), precision || 0, '0', false);
6826 - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
6827 - }
6828 -
6829 - function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
6830 - if (precision != null) {
6831 - value = value.slice(0, precision);
6832 - }
6833 - return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace);
6834 - }
6835 -
6836 - var a = arguments, i = 0, format = a[i++];
6837 -
6838 - return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) {
6839 - if (substring == '%%') { return '%'; }
6840 -
6841 - // parse flags
6842 - var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false;
6843 - for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
6844 - case ' ': positivePrefix = ' '; break;
6845 - case '+': positivePrefix = '+'; break;
6846 - case '-': leftJustify = true; break;
6847 - case '0': zeroPad = true; break;
6848 - case '#': prefixBaseX = true; break;
6849 - case '&': htmlSpace = true; break;
6850 - }
6851 -
6852 - // parameters may be null, undefined, empty-string or real valued
6853 - // we want to ignore null, undefined and empty-string values
6854 -
6855 - if (!minWidth) {
6856 - minWidth = 0;
6857 - }
6858 - else if (minWidth == '*') {
6859 - minWidth = +a[i++];
6860 - }
6861 - else if (minWidth.charAt(0) == '*') {
6862 - minWidth = +a[minWidth.slice(1, -1)];
6863 - }
6864 - else {
6865 - minWidth = +minWidth;
6866 - }
6867 -
6868 - // Note: undocumented perl feature:
6869 - if (minWidth < 0) {
6870 - minWidth = -minWidth;
6871 - leftJustify = true;
6872 - }
6873 -
6874 - if (!isFinite(minWidth)) {
6875 - throw new Error('$.jqplot.sprintf: (minimum-)width must be finite');
6876 - }
6877 -
6878 - if (!precision) {
6879 - precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
6880 - }
6881 - else if (precision == '*') {
6882 - precision = +a[i++];
6883 - }
6884 - else if (precision.charAt(0) == '*') {
6885 - precision = +a[precision.slice(1, -1)];
6886 - }
6887 - else {
6888 - precision = +precision;
6889 - }
6890 -
6891 - // grab value using valueIndex if required?
6892 - var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
6893 -
6894 - switch (type) {
6895 - case 's': {
6896 - if (value == null) {
6897 - return '';
6898 - }
6899 - return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
6900 - }
6901 - case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
6902 - case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace);
6903 - case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
6904 - case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
6905 - case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase();
6906 - case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
6907 - case 'i': {
6908 - var number = parseInt(+value, 10);
6909 - if (isNaN(number)) {
6910 - return '';
6911 - }
6912 - var prefix = number < 0 ? '-' : positivePrefix;
6913 - value = prefix + pad(String(Math.abs(number)), precision, '0', false);
6914 - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
6915 - }
6916 - case 'd': {
6917 - var number = Math.round(+value);
6918 - if (isNaN(number)) {
6919 - return '';
6920 - }
6921 - var prefix = number < 0 ? '-' : positivePrefix;
6922 - value = prefix + pad(String(Math.abs(number)), precision, '0', false);
6923 - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
6924 - }
6925 - case 'e':
6926 - case 'E':
6927 - case 'f':
6928 - case 'F':
6929 - case 'g':
6930 - case 'G':
6931 - {
6932 - var number = +value;
6933 - if (isNaN(number)) {
6934 - return '';
6935 - }
6936 - var prefix = number < 0 ? '-' : positivePrefix;
6937 - var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
6938 - var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
6939 - value = prefix + Math.abs(number)[method](precision);
6940 - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
6941 - }
6942 - case 'p':
6943 - case 'P':
6944 - {
6945 - // make sure number is a number
6946 - var number = +value;
6947 - if (isNaN(number)) {
6948 - return '';
6949 - }
6950 - var prefix = number < 0 ? '-' : positivePrefix;
6951 -
6952 - var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
6953 - var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
6954 - var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
6955 -
6956 - if (Math.abs(number) < 1) {
6957 - if (sd + zeros <= precision) {
6958 - value = prefix + Math.abs(number).toPrecision(sd);
6959 - }
6960 - else {
6961 - if (sd <= precision - 1) {
6962 - value = prefix + Math.abs(number).toExponential(sd-1);
6963 - }
6964 - else {
6965 - value = prefix + Math.abs(number).toExponential(precision-1);
6966 - }
6967 - }
6968 - }
6969 - else {
6970 - var prec = (sd <= precision) ? sd : precision;
6971 - value = prefix + Math.abs(number).toPrecision(prec);
6972 - }
6973 - var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2];
6974 - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
6975 - }
6976 - case 'n': return '';
6977 - default: return substring;
6978 - }
6979 - });
6980 - };
6981 -
6982 - $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0& ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;
6983 -
6984 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.trendline.js
@@ -1,208 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 -
21 - /**
22 - * Class: $.jqplot.Trendline
23 - * Plugin which will automatically compute and draw trendlines for plotted data.
24 - */
25 - $.jqplot.Trendline = function() {
26 - // Group: Properties
27 -
28 - // prop: show
29 - // Wether or not to show the trend line.
30 - this.show = $.jqplot.config.enablePlugins;
31 - // prop: color
32 - // CSS color spec for the trend line.
33 - // By default this wil be the same color as the primary line.
34 - this.color = '#666666';
35 - // prop: renderer
36 - // Renderer to use to draw the trend line.
37 - // The data series that is plotted may not be rendered as a line.
38 - // Therefore, we use our own line renderer here to draw a trend line.
39 - this.renderer = new $.jqplot.LineRenderer();
40 - // prop: rendererOptions
41 - // Options to pass to the line renderer.
42 - // By default, markers are not shown on trend lines.
43 - this.rendererOptions = {marker:{show:false}};
44 - // prop: label
45 - // Label for the trend line to use in the legend.
46 - this.label = '';
47 - // prop: type
48 - // Either 'exponential', 'exp', or 'linear'.
49 - this.type = 'linear';
50 - // prop: shadow
51 - // true or false, wether or not to show the shadow.
52 - this.shadow = true;
53 - // prop: markerRenderer
54 - // Renderer to use to draw markers on the line.
55 - // I think this is wrong.
56 - this.markerRenderer = {show:false};
57 - // prop: lineWidth
58 - // Width of the trend line.
59 - this.lineWidth = 1.5;
60 - // prop: shadowAngle
61 - // Angle of the shadow on the trend line.
62 - this.shadowAngle = 45;
63 - // prop: shadowOffset
64 - // pixel offset for each stroke of the shadow.
65 - this.shadowOffset = 1.0;
66 - // prop: shadowAlpha
67 - // Alpha transparency of the shadow.
68 - this.shadowAlpha = 0.07;
69 - // prop: shadowDepth
70 - // number of strokes to make of the shadow.
71 - this.shadowDepth = 3;
72 - this.isTrendline = true;
73 -
74 - };
75 -
76 - $.jqplot.postSeriesInitHooks.push(parseTrendLineOptions);
77 - $.jqplot.postDrawSeriesHooks.push(drawTrendline);
78 - $.jqplot.addLegendRowHooks.push(addTrendlineLegend);
79 -
80 - // called witin scope of the legend object
81 - // current series passed in
82 - // must return null or an object {label:label, color:color}
83 - function addTrendlineLegend(series) {
84 - var lt = series.trendline.label.toString();
85 - var ret = null;
86 - if (this.renderer.constructor != $.jqplot.PieRenderer && series.trendline.show && lt) {
87 - ret = {label:lt, color:series.trendline.color};
88 - }
89 - return ret;
90 - }
91 -
92 - // called within scope of a series
93 - function parseTrendLineOptions (target, data, seriesDefaults, options, plot) {
94 - if (this.renderer.constructor == $.jqplot.LineRenderer) {
95 - this.trendline = new $.jqplot.Trendline();
96 - options = options || {};
97 - $.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline);
98 - this.trendline.renderer.init.call(this.trendline, null);
99 - }
100 - }
101 -
102 - // called within scope of series object
103 - function drawTrendline(sctx, options) {
104 - // if we have options, merge trendline options in with precedence
105 - options = $.extend(true, {}, this.trendline, options);
106 -
107 - if (options.show && this.renderer.constructor != $.jqplot.PieRenderer) {
108 - var fit;
109 - // this.renderer.setGridData.call(this);
110 - var data = options.data || this.data;
111 - fit = fitData(data, this.trendline.type);
112 - var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data);
113 - this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow});
114 - }
115 - }
116 -
117 - function regression(x, y, typ) {
118 - var type = (typ == null) ? 'linear' : typ;
119 - var N = x.length;
120 - var slope;
121 - var intercept;
122 - var SX = 0;
123 - var SY = 0;
124 - var SXX = 0;
125 - var SXY = 0;
126 - var SYY = 0;
127 - var Y = [];
128 - var X = [];
129 -
130 - if (type == 'linear') {
131 - X = x;
132 - Y = y;
133 - }
134 - else if (type == 'exp' || type == 'exponential') {
135 - for ( var i=0; i<y.length; i++) {
136 - // ignore points <= 0, log undefined.
137 - if (y[i] <= 0) {
138 - N--;
139 - }
140 - else {
141 - X.push(x[i]);
142 - Y.push(Math.log(y[i]));
143 - }
144 - }
145 - }
146 -
147 - for ( var i = 0; i < N; i++) {
148 - SX = SX + X[i];
149 - SY = SY + Y[i];
150 - SXY = SXY + X[i]* Y[i];
151 - SXX = SXX + X[i]* X[i];
152 - SYY = SYY + Y[i]* Y[i];
153 - }
154 -
155 - slope = (N*SXY - SX*SY)/(N*SXX - SX*SX);
156 - intercept = (SY - slope*SX)/N;
157 -
158 - return [slope, intercept];
159 - }
160 -
161 - function linearRegression(X,Y) {
162 - var ret;
163 - ret = regression(X,Y,'linear');
164 - return [ret[0],ret[1]];
165 - }
166 -
167 - function expRegression(X,Y) {
168 - var ret;
169 - var x = X;
170 - var y = Y;
171 - ret = regression(x, y,'exp');
172 - var base = Math.exp(ret[0]);
173 - var coeff = Math.exp(ret[1]);
174 - return [base, coeff];
175 - }
176 -
177 - function fitData(data, typ) {
178 - var type = (typ == null) ? 'linear' : typ;
179 - var ret;
180 - var res;
181 - var x = [];
182 - var y = [];
183 - var ypred = [];
184 -
185 - for (i=0; i<data.length; i++){
186 - if (data[i] != null && data[i][0] != null && data[i][1] != null) {
187 - x.push(data[i][0]);
188 - y.push(data[i][1]);
189 - }
190 - }
191 -
192 - if (type == 'linear') {
193 - ret = linearRegression(x,y);
194 - for ( var i=0; i<x.length; i++){
195 - res = ret[0]*x[i] + ret[1];
196 - ypred.push([x[i], res]);
197 - }
198 - }
199 - else if (type == 'exp' || type == 'exponential') {
200 - ret = expRegression(x,y);
201 - for ( var i=0; i<x.length; i++){
202 - res = ret[1]*Math.pow(ret[0],x[i]);
203 - ypred.push([x[i], res]);
204 - }
205 - }
206 - return {data: ypred, slope: ret[0], intercept: ret[1]};
207 - }
208 -
209 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.categoryAxisRenderer.js
@@ -1,621 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 - /**
21 - * class: $.jqplot.CategoryAxisRenderer
22 - * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series.
23 - *
24 - * To use this renderer, include the plugin in your source
25 - * > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script>
26 - *
27 - * and supply the appropriate options to your plot
28 - *
29 - * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}}
30 - **/
31 - $.jqplot.CategoryAxisRenderer = function(options) {
32 - $.jqplot.LinearAxisRenderer.call(this);
33 - // prop: sortMergedLabels
34 - // True to sort tick labels when labels are created by merging
35 - // x axis values from multiple series. That is, say you have
36 - // two series like:
37 - // > line1 = [[2006, 4], [2008, 9], [2009, 16]];
38 - // > line2 = [[2006, 3], [2007, 7], [2008, 6]];
39 - // If no label array is specified, tick labels will be collected
40 - // from the x values of the series. With sortMergedLabels
41 - // set to true, tick labels will be:
42 - // > [2006, 2007, 2008, 2009]
43 - // With sortMergedLabels set to false, tick labels will be:
44 - // > [2006, 2008, 2009, 2007]
45 - //
46 - // Note, this property is specified on the renderOptions for the
47 - // axes when creating a plot:
48 - // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}}
49 - this.sortMergedLabels = false;
50 - };
51 -
52 - $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
53 - $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
54 -
55 - $.jqplot.CategoryAxisRenderer.prototype.init = function(options){
56 - this.groups = 1;
57 - this.groupLabels = [];
58 - this._groupLabels = [];
59 - this._grouped = false;
60 - this._barsPerGroup = null;
61 - // prop: tickRenderer
62 - // A class of a rendering engine for creating the ticks labels displayed on the plot,
63 - // See <$.jqplot.AxisTickRenderer>.
64 - // this.tickRenderer = $.jqplot.AxisTickRenderer;
65 - // this.labelRenderer = $.jqplot.AxisLabelRenderer;
66 - $.extend(true, this, {tickOptions:{formatString:'%d'}}, options);
67 - var db = this._dataBounds;
68 - // Go through all the series attached to this axis and find
69 - // the min/max bounds for this axis.
70 - for (var i=0; i<this._series.length; i++) {
71 - var s = this._series[i];
72 - if (s.groups) {
73 - this.groups = s.groups;
74 - }
75 - var d = s.data;
76 -
77 - for (var j=0; j<d.length; j++) {
78 - if (this.name == 'xaxis' || this.name == 'x2axis') {
79 - if (d[j][0] < db.min || db.min == null) {
80 - db.min = d[j][0];
81 - }
82 - if (d[j][0] > db.max || db.max == null) {
83 - db.max = d[j][0];
84 - }
85 - }
86 - else {
87 - if (d[j][1] < db.min || db.min == null) {
88 - db.min = d[j][1];
89 - }
90 - if (d[j][1] > db.max || db.max == null) {
91 - db.max = d[j][1];
92 - }
93 - }
94 - }
95 - }
96 -
97 - if (this.groupLabels.length) {
98 - this.groups = this.groupLabels.length;
99 - }
100 - };
101 -
102 -
103 - $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
104 - // we're are operating on an axis here
105 - var ticks = this._ticks;
106 - var userTicks = this.ticks;
107 - var name = this.name;
108 - // databounds were set on axis initialization.
109 - var db = this._dataBounds;
110 - var dim, interval;
111 - var min, max;
112 - var pos1, pos2;
113 - var tt, i;
114 -
115 - // if we already have ticks, use them.
116 - if (userTicks.length) {
117 - // adjust with blanks if we have groups
118 - if (this.groups > 1 && !this._grouped) {
119 - var l = userTicks.length;
120 - var skip = parseInt(l/this.groups, 10);
121 - var count = 0;
122 - for (var i=skip; i<l; i+=skip) {
123 - userTicks.splice(i+count, 0, ' ');
124 - count++;
125 - }
126 - this._grouped = true;
127 - }
128 - this.min = 0.5;
129 - this.max = userTicks.length + 0.5;
130 - var range = this.max - this.min;
131 - this.numberTicks = 2*userTicks.length + 1;
132 - for (i=0; i<userTicks.length; i++){
133 - tt = this.min + 2 * i * range / (this.numberTicks-1);
134 - // need a marker before and after the tick
135 - var t = new this.tickRenderer(this.tickOptions);
136 - t.showLabel = false;
137 - // t.showMark = true;
138 - t.setTick(tt, this.name);
139 - this._ticks.push(t);
140 - var t = new this.tickRenderer(this.tickOptions);
141 - t.label = userTicks[i];
142 - // t.showLabel = true;
143 - t.showMark = false;
144 - t.showGridline = false;
145 - t.setTick(tt+0.5, this.name);
146 - this._ticks.push(t);
147 - }
148 - // now add the last tick at the end
149 - var t = new this.tickRenderer(this.tickOptions);
150 - t.showLabel = false;
151 - // t.showMark = true;
152 - t.setTick(tt+1, this.name);
153 - this._ticks.push(t);
154 - }
155 -
156 - // we don't have any ticks yet, let's make some!
157 - else {
158 - if (name == 'xaxis' || name == 'x2axis') {
159 - dim = this._plotDimensions.width;
160 - }
161 - else {
162 - dim = this._plotDimensions.height;
163 - }
164 -
165 - // if min, max and number of ticks specified, user can't specify interval.
166 - if (this.min != null && this.max != null && this.numberTicks != null) {
167 - this.tickInterval = null;
168 - }
169 -
170 - // if max, min, and interval specified and interval won't fit, ignore interval.
171 - if (this.min != null && this.max != null && this.tickInterval != null) {
172 - if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
173 - this.tickInterval = null;
174 - }
175 - }
176 -
177 - // find out how many categories are in the lines and collect labels
178 - var labels = [];
179 - var numcats = 0;
180 - var min = 0.5;
181 - var max, val;
182 - var isMerged = false;
183 - for (var i=0; i<this._series.length; i++) {
184 - var s = this._series[i];
185 - for (var j=0; j<s.data.length; j++) {
186 - if (this.name == 'xaxis' || this.name == 'x2axis') {
187 - val = s.data[j][0];
188 - }
189 - else {
190 - val = s.data[j][1];
191 - }
192 - if ($.inArray(val, labels) == -1) {
193 - isMerged = true;
194 - numcats += 1;
195 - labels.push(val);
196 - }
197 - }
198 - }
199 -
200 - if (isMerged && this.sortMergedLabels) {
201 - labels.sort(function(a,b) { return a - b; });
202 - }
203 -
204 - // keep a reference to these tick labels to use for redrawing plot (see bug #57)
205 - this.ticks = labels;
206 -
207 - // now bin the data values to the right lables.
208 - for (var i=0; i<this._series.length; i++) {
209 - var s = this._series[i];
210 - for (var j=0; j<s.data.length; j++) {
211 - if (this.name == 'xaxis' || this.name == 'x2axis') {
212 - val = s.data[j][0];
213 - }
214 - else {
215 - val = s.data[j][1];
216 - }
217 - // for category axis, force the values into category bins.
218 - // we should have the value in the label array now.
219 - var idx = $.inArray(val, labels)+1;
220 - if (this.name == 'xaxis' || this.name == 'x2axis') {
221 - s.data[j][0] = idx;
222 - }
223 - else {
224 - s.data[j][1] = idx;
225 - }
226 - }
227 - }
228 -
229 - // adjust with blanks if we have groups
230 - if (this.groups > 1 && !this._grouped) {
231 - var l = labels.length;
232 - var skip = parseInt(l/this.groups, 10);
233 - var count = 0;
234 - for (var i=skip; i<l; i+=skip+1) {
235 - labels[i] = ' ';
236 - }
237 - this._grouped = true;
238 - }
239 -
240 - max = numcats + 0.5;
241 - if (this.numberTicks == null) {
242 - this.numberTicks = 2*numcats + 1;
243 - }
244 -
245 - var range = max - min;
246 - this.min = min;
247 - this.max = max;
248 - var track = 0;
249 -
250 - // todo: adjust this so more ticks displayed.
251 - var maxVisibleTicks = parseInt(3+dim/20, 10);
252 - var skip = parseInt(numcats/maxVisibleTicks, 10);
253 -
254 - if (this.tickInterval == null) {
255 -
256 - this.tickInterval = range / (this.numberTicks-1);
257 -
258 - }
259 - // if tickInterval is specified, we will ignore any computed maximum.
260 - for (var i=0; i<this.numberTicks; i++){
261 - tt = this.min + i * this.tickInterval;
262 - var t = new this.tickRenderer(this.tickOptions);
263 - // if even tick, it isn't a category, it's a divider
264 - if (i/2 == parseInt(i/2, 10)) {
265 - t.showLabel = false;
266 - t.showMark = true;
267 - }
268 - else {
269 - if (skip>0 && track<skip) {
270 - t.showLabel = false;
271 - track += 1;
272 - }
273 - else {
274 - t.showLabel = true;
275 - track = 0;
276 - }
277 - t.label = t.formatter(t.formatString, labels[(i-1)/2]);
278 - t.showMark = false;
279 - t.showGridline = false;
280 - }
281 - t.setTick(tt, this.name);
282 - this._ticks.push(t);
283 - }
284 - }
285 -
286 - };
287 -
288 - // called with scope of axis
289 - $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx) {
290 - if (this.show) {
291 - // populate the axis label and value properties.
292 - // createTicks is a method on the renderer, but
293 - // call it within the scope of the axis.
294 - this.renderer.createTicks.call(this);
295 - // fill a div with axes labels in the right direction.
296 - // Need to pregenerate each axis to get it's bounds and
297 - // position it and the labels correctly on the plot.
298 - var dim=0;
299 - var temp;
300 - // Added for theming.
301 - if (this._elem) {
302 - this._elem.empty();
303 - }
304 -
305 - this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
306 -
307 - if (this.name == 'xaxis' || this.name == 'x2axis') {
308 - this._elem.width(this._plotDimensions.width);
309 - }
310 - else {
311 - this._elem.height(this._plotDimensions.height);
312 - }
313 -
314 - // create a _label object.
315 - this.labelOptions.axis = this.name;
316 - this._label = new this.labelRenderer(this.labelOptions);
317 - if (this._label.show) {
318 - var elem = this._label.draw(ctx);
319 - elem.appendTo(this._elem);
320 - }
321 -
322 - var t = this._ticks;
323 - for (var i=0; i<t.length; i++) {
324 - var tick = t[i];
325 - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
326 - var elem = tick.draw(ctx);
327 - elem.appendTo(this._elem);
328 - }
329 - }
330 -
331 - this._groupLabels = [];
332 - // now make group labels
333 - for (var i=0; i<this.groupLabels.length; i++)
334 - {
335 - var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>');
336 - elem.html(this.groupLabels[i]);
337 - this._groupLabels.push(elem);
338 - elem.appendTo(this._elem);
339 - }
340 - }
341 - return this._elem;
342 - };
343 -
344 - // called with scope of axis
345 - $.jqplot.CategoryAxisRenderer.prototype.set = function() {
346 - var dim = 0;
347 - var temp;
348 - var w = 0;
349 - var h = 0;
350 - var lshow = (this._label == null) ? false : this._label.show;
351 - if (this.show) {
352 - var t = this._ticks;
353 - for (var i=0; i<t.length; i++) {
354 - var tick = t[i];
355 - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
356 - if (this.name == 'xaxis' || this.name == 'x2axis') {
357 - temp = tick._elem.outerHeight(true);
358 - }
359 - else {
360 - temp = tick._elem.outerWidth(true);
361 - }
362 - if (temp > dim) {
363 - dim = temp;
364 - }
365 - }
366 - }
367 -
368 - var dim2 = 0;
369 - for (var i=0; i<this._groupLabels.length; i++) {
370 - var l = this._groupLabels[i];
371 - if (this.name == 'xaxis' || this.name == 'x2axis') {
372 - temp = l.outerHeight(true);
373 - }
374 - else {
375 - temp = l.outerWidth(true);
376 - }
377 - if (temp > dim2) {
378 - dim2 = temp;
379 - }
380 - }
381 -
382 - if (lshow) {
383 - w = this._label._elem.outerWidth(true);
384 - h = this._label._elem.outerHeight(true);
385 - }
386 - if (this.name == 'xaxis') {
387 - dim += dim2 + h;
388 - this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
389 - }
390 - else if (this.name == 'x2axis') {
391 - dim += dim2 + h;
392 - this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
393 - }
394 - else if (this.name == 'yaxis') {
395 - dim += dim2 + w;
396 - this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
397 - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
398 - this._label._elem.css('width', w+'px');
399 - }
400 - }
401 - else {
402 - dim += dim2 + w;
403 - this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
404 - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
405 - this._label._elem.css('width', w+'px');
406 - }
407 - }
408 - }
409 - };
410 -
411 - // called with scope of axis
412 - $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) {
413 - var ticks = this._ticks;
414 - var max = this.max;
415 - var min = this.min;
416 - var offmax = offsets.max;
417 - var offmin = offsets.min;
418 - var lshow = (this._label == null) ? false : this._label.show;
419 -
420 - for (var p in pos) {
421 - this._elem.css(p, pos[p]);
422 - }
423 -
424 - this._offsets = offsets;
425 - // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
426 - var pixellength = offmax - offmin;
427 - var unitlength = max - min;
428 -
429 - // point to unit and unit to point conversions references to Plot DOM element top left corner.
430 - this.p2u = function(p){
431 - return (p - offmin) * unitlength / pixellength + min;
432 - };
433 -
434 - this.u2p = function(u){
435 - return (u - min) * pixellength / unitlength + offmin;
436 - };
437 -
438 - if (this.name == 'xaxis' || this.name == 'x2axis'){
439 - this.series_u2p = function(u){
440 - return (u - min) * pixellength / unitlength;
441 - };
442 - this.series_p2u = function(p){
443 - return p * unitlength / pixellength + min;
444 - };
445 - }
446 -
447 - else {
448 - this.series_u2p = function(u){
449 - return (u - max) * pixellength / unitlength;
450 - };
451 - this.series_p2u = function(p){
452 - return p * unitlength / pixellength + max;
453 - };
454 - }
455 -
456 - if (this.show) {
457 - if (this.name == 'xaxis' || this.name == 'x2axis') {
458 - for (i=0; i<ticks.length; i++) {
459 - var t = ticks[i];
460 - if (t.show && t.showLabel) {
461 - var shim;
462 -
463 - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
464 - // will need to adjust auto positioning based on which axis this is.
465 - var temp = (this.name == 'xaxis') ? 1 : -1;
466 - switch (t.labelPosition) {
467 - case 'auto':
468 - // position at end
469 - if (temp * t.angle < 0) {
470 - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
471 - }
472 - // position at start
473 - else {
474 - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
475 - }
476 - break;
477 - case 'end':
478 - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
479 - break;
480 - case 'start':
481 - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
482 - break;
483 - case 'middle':
484 - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
485 - break;
486 - default:
487 - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
488 - break;
489 - }
490 - }
491 - else {
492 - shim = -t.getWidth()/2;
493 - }
494 - var val = this.u2p(t.value) + shim + 'px';
495 - t._elem.css('left', val);
496 - t.pack();
497 - }
498 - }
499 -
500 - var labeledge=['bottom', 0];
501 - if (lshow) {
502 - var w = this._label._elem.outerWidth(true);
503 - this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
504 - if (this.name == 'xaxis') {
505 - this._label._elem.css('bottom', '0px');
506 - labeledge = ['bottom', this._label._elem.outerHeight(true)];
507 - }
508 - else {
509 - this._label._elem.css('top', '0px');
510 - labeledge = ['top', this._label._elem.outerHeight(true)];
511 - }
512 - this._label.pack();
513 - }
514 -
515 - // draw the group labels
516 - var step = parseInt(this._ticks.length/this.groups, 10);
517 - for (i=0; i<this._groupLabels.length; i++) {
518 - var mid = 0;
519 - var count = 0;
520 - for (var j=i*step; j<=(i+1)*step; j++) {
521 - if (this._ticks[j]._elem && this._ticks[j].label != " ") {
522 - var t = this._ticks[j]._elem;
523 - var p = t.position();
524 - mid += p.left + t.outerWidth(true)/2;
525 - count++;
526 - }
527 - }
528 - mid = mid/count;
529 - this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)});
530 - this._groupLabels[i].css(labeledge[0], labeledge[1]);
531 - }
532 - }
533 - else {
534 - for (i=0; i<ticks.length; i++) {
535 - var t = ticks[i];
536 - if (t.show && t.showLabel) {
537 - var shim;
538 - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
539 - // will need to adjust auto positioning based on which axis this is.
540 - var temp = (this.name == 'yaxis') ? 1 : -1;
541 - switch (t.labelPosition) {
542 - case 'auto':
543 - // position at end
544 - case 'end':
545 - if (temp * t.angle < 0) {
546 - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
547 - }
548 - else {
549 - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
550 - }
551 - break;
552 - case 'start':
553 - if (t.angle > 0) {
554 - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
555 - }
556 - else {
557 - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
558 - }
559 - break;
560 - case 'middle':
561 - // if (t.angle > 0) {
562 - // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
563 - // }
564 - // else {
565 - // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
566 - // }
567 - shim = -t.getHeight()/2;
568 - break;
569 - default:
570 - shim = -t.getHeight()/2;
571 - break;
572 - }
573 - }
574 - else {
575 - shim = -t.getHeight()/2;
576 - }
577 -
578 - var val = this.u2p(t.value) + shim + 'px';
579 - t._elem.css('top', val);
580 - t.pack();
581 - }
582 - }
583 -
584 - var labeledge=['left', 0];
585 - if (lshow) {
586 - var h = this._label._elem.outerHeight(true);
587 - this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
588 - if (this.name == 'yaxis') {
589 - this._label._elem.css('left', '0px');
590 - labeledge = ['left', this._label._elem.outerWidth(true)];
591 - }
592 - else {
593 - this._label._elem.css('right', '0px');
594 - labeledge = ['right', this._label._elem.outerWidth(true)];
595 - }
596 - this._label.pack();
597 - }
598 -
599 - // draw the group labels, position top here, do left after label position.
600 - var step = parseInt(this._ticks.length/this.groups, 10);
601 - for (i=0; i<this._groupLabels.length; i++) {
602 - var mid = 0;
603 - var count = 0;
604 - for (var j=i*step; j<=(i+1)*step; j++) {
605 - if (this._ticks[j]._elem && this._ticks[j].label != " ") {
606 - var t = this._ticks[j]._elem;
607 - var p = t.position();
608 - mid += p.top + t.outerHeight()/2;
609 - count++;
610 - }
611 - }
612 - mid = mid/count;
613 - this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2});
614 - this._groupLabels[i].css(labeledge[0], labeledge[1]);
615 -
616 - }
617 - }
618 - }
619 - };
620 -
621 -
622 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jqplot.barRenderer.js
@@ -1,629 +0,0 @@
2 -/**
3 - * Copyright (c) 2009 - 2010 Chris Leonello
4 - * jqPlot is currently available for use in all personal or commercial projects
5 - * under both the MIT and GPL version 2.0 licenses. This means that you can
6 - * choose the license that best suits your project and use it accordingly.
7 - *
8 - * The author would appreciate an email letting him know of any substantial
9 - * use of jqPlot. You can reach the author at: chris at jqplot dot com
10 - * or see http://www.jqplot.com/info.php . This is, of course,
11 - * not required.
12 - *
13 - * If you are feeling kind and generous, consider supporting the project by
14 - * making a donation at: http://www.jqplot.com/donate.php .
15 - *
16 - * Thanks for using jqPlot!
17 - *
18 - */
19 -(function($) {
20 -
21 - // Class: $.jqplot.BarRenderer
22 - // A plugin renderer for jqPlot to draw a bar plot.
23 - // Draws series as a line.
24 -
25 - $.jqplot.BarRenderer = function(){
26 - $.jqplot.LineRenderer.call(this);
27 - };
28 -
29 - $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
30 - $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
31 -
32 - // called with scope of series.
33 - $.jqplot.BarRenderer.prototype.init = function(options, plot) {
34 - // Group: Properties
35 - //
36 - // prop: barPadding
37 - // Number of pixels between adjacent bars at the same axis value.
38 - this.barPadding = 8;
39 - // prop: barMargin
40 - // Number of pixels between groups of bars at adjacent axis values.
41 - this.barMargin = 10;
42 - // prop: barDirection
43 - // 'vertical' = up and down bars, 'horizontal' = side to side bars
44 - this.barDirection = 'vertical';
45 - // prop: barWidth
46 - // Width of the bar in pixels (auto by devaul). null = calculated automatically.
47 - this.barWidth = null;
48 - // prop: shadowOffset
49 - // offset of the shadow from the slice and offset of
50 - // each succesive stroke of the shadow from the last.
51 - this.shadowOffset = 2;
52 - // prop: shadowDepth
53 - // number of strokes to apply to the shadow,
54 - // each stroke offset shadowOffset from the last.
55 - this.shadowDepth = 5;
56 - // prop: shadowAlpha
57 - // transparency of the shadow (0 = transparent, 1 = opaque)
58 - this.shadowAlpha = 0.08;
59 - // prop: waterfall
60 - // true to enable waterfall plot.
61 - this.waterfall = false;
62 - // prop: groups
63 - // group bars into this many groups
64 - this.groups = 1;
65 - // prop: varyBarColor
66 - // true to color each bar of a series separately rather than
67 - // have every bar of a given series the same color.
68 - // If used for non-stacked multiple series bar plots, user should
69 - // specify a separate 'seriesColors' array for each series.
70 - // Otherwise, each series will set their bars to the same color array.
71 - // This option has no Effect for stacked bar charts and is disabled.
72 - this.varyBarColor = false;
73 - // prop: highlightMouseOver
74 - // True to highlight slice when moused over.
75 - // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
76 - this.highlightMouseOver = true;
77 - // prop: highlightMouseDown
78 - // True to highlight when a mouse button is pressed over a slice.
79 - // This will be disabled if highlightMouseOver is true.
80 - this.highlightMouseDown = false;
81 - // prop: highlightColors
82 - // an array of colors to use when highlighting a bar.
83 - this.highlightColors = [];
84 -
85 - // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
86 - if (options.highlightMouseDown && options.highlightMouseOver == null) {
87 - options.highlightMouseOver = false;
88 - }
89 -
90 - $.extend(true, this, options);
91 - // fill is still needed to properly draw the legend.
92 - // bars have to be filled.
93 - this.fill = true;
94 -
95 - if (this.waterfall) {
96 - this.fillToZero = false;
97 - this.disableStack = true;
98 - }
99 -
100 - if (this.barDirection == 'vertical' ) {
101 - this._primaryAxis = '_xaxis';
102 - this._stackAxis = 'y';
103 - this.fillAxis = 'y';
104 - }
105 - else {
106 - this._primaryAxis = '_yaxis';
107 - this._stackAxis = 'x';
108 - this.fillAxis = 'x';
109 - }
110 - // index of the currenty highlighted point, if any
111 - this._highlightedPoint = null;
112 - // total number of values for all bar series, total number of bar series, and position of this series
113 - this._plotSeriesInfo = null;
114 - // Array of actual data colors used for each data point.
115 - this._dataColors = [];
116 - this._barPoints = [];
117 -
118 - // set the shape renderer options
119 - var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
120 - this.renderer.shapeRenderer.init(opts);
121 - // set the shadow renderer options
122 - var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
123 - this.renderer.shadowRenderer.init(sopts);
124 -
125 - plot.postInitHooks.addOnce(postInit);
126 - plot.postDrawHooks.addOnce(postPlotDraw);
127 - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
128 - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
129 - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
130 - plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
131 - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
132 - };
133 -
134 - // called with scope of series
135 - function barPreInit(target, data, seriesDefaults, options) {
136 - if (this.rendererOptions.barDirection == 'horizontal') {
137 - this._stackAxis = 'x';
138 - this._primaryAxis = '_yaxis';
139 - }
140 - if (this.rendererOptions.waterfall == true) {
141 - this._data = $.extend(true, [], this.data);
142 - var sum = 0;
143 - var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection == 'vertical') ? 1 : 0;
144 - for(var i=0; i<this.data.length; i++) {
145 - sum += this.data[i][pos];
146 - if (i>0) {
147 - this.data[i][pos] += this.data[i-1][pos];
148 - }
149 - }
150 - this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
151 - this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
152 - }
153 - if (this.rendererOptions.groups > 1) {
154 - this.breakOnNull = true;
155 - var l = this.data.length;
156 - var skip = parseInt(l/this.rendererOptions.groups, 10);
157 - var count = 0;
158 - for (var i=skip; i<l; i+=skip) {
159 - this.data.splice(i+count, 0, [null, null]);
160 - count++;
161 - }
162 - for (i=0; i<this.data.length; i++) {
163 - if (this._primaryAxis == '_xaxis') {
164 - this.data[i][0] = i+1;
165 - }
166 - else {
167 - this.data[i][1] = i+1;
168 - }
169 - }
170 - }
171 - }
172 -
173 - $.jqplot.preSeriesInitHooks.push(barPreInit);
174 -
175 - // needs to be called with scope of series, not renderer.
176 - $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
177 - var nvals = 0;
178 - var nseries = 0;
179 - var paxis = this[this._primaryAxis];
180 - var s, series, pos;
181 - // loop through all series on this axis
182 - for (var i=0; i < paxis._series.length; i++) {
183 - series = paxis._series[i];
184 - if (series === this) {
185 - pos = i;
186 - }
187 - // is the series rendered as a bar?
188 - if (series.renderer.constructor == $.jqplot.BarRenderer) {
189 - // gridData may not be computed yet, use data length insted
190 - nvals += series.data.length;
191 - nseries += 1;
192 - }
193 - }
194 - // return total number of values for all bar series, total number of bar series, and position of this series
195 - return [nvals, nseries, pos];
196 - };
197 -
198 - $.jqplot.BarRenderer.prototype.setBarWidth = function() {
199 - // need to know how many data values we have on the approprate axis and figure it out.
200 - var i;
201 - var nvals = 0;
202 - var nseries = 0;
203 - var paxis = this[this._primaryAxis];
204 - var s, series, pos;
205 - var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
206 - nvals = temp[0];
207 - nseries = temp[1];
208 - var nticks = paxis.numberTicks;
209 - var nbins = (nticks-1)/2;
210 - // so, now we have total number of axis values.
211 - if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
212 - if (this._stack) {
213 - this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
214 - }
215 - else {
216 - this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
217 - // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
218 - }
219 - }
220 - else {
221 - if (this._stack) {
222 - this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
223 - }
224 - else {
225 - this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
226 - // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
227 - }
228 - }
229 - return [nvals, nseries];
230 - };
231 -
232 - function computeHighlightColors (colors) {
233 - var ret = [];
234 - for (var i=0; i<colors.length; i++){
235 - var rgba = $.jqplot.getColorComponents(colors[i]);
236 - var newrgb = [rgba[0], rgba[1], rgba[2]];
237 - var sum = newrgb[0] + newrgb[1] + newrgb[2];
238 - for (var j=0; j<3; j++) {
239 - // when darkening, lowest color component can be is 60.
240 - newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
241 - newrgb[j] = parseInt(newrgb[j], 10);
242 - }
243 - ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
244 - }
245 - return ret;
246 - }
247 -
248 - $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options) {
249 - var i;
250 - var opts = (options != undefined) ? options : {};
251 - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
252 - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
253 - var fill = (opts.fill != undefined) ? opts.fill : this.fill;
254 - var xaxis = this.xaxis;
255 - var yaxis = this.yaxis;
256 - var xp = this._xaxis.series_u2p;
257 - var yp = this._yaxis.series_u2p;
258 - var pointx, pointy, nvals, nseries, pos;
259 - // clear out data colors.
260 - this._dataColors = [];
261 - this._barPoints = [];
262 -
263 - if (this.barWidth == null) {
264 - this.renderer.setBarWidth.call(this);
265 - }
266 -
267 - var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
268 - nvals = temp[0];
269 - nseries = temp[1];
270 - pos = temp[2];
271 -
272 - if (this._stack) {
273 - this._barNudge = 0;
274 - }
275 - else {
276 - this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
277 - }
278 - if (showLine) {
279 - var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
280 - var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
281 - var negativeColor = negativeColors.get(this.index);
282 - if (! this.useNegativeColors) {
283 - negativeColor = opts.fillStyle;
284 - }
285 - var positiveColor = opts.fillStyle;
286 -
287 - if (this.barDirection == 'vertical') {
288 - for (var i=0; i<gridData.length; i++) {
289 - if (this.data[i][1] == null) {
290 - continue;
291 - }
292 - points = [];
293 - var base = gridData[i][0] + this._barNudge;
294 - var ystart;
295 -
296 - // stacked
297 - if (this._stack && this._prevGridData.length) {
298 - ystart = this._prevGridData[i][1];
299 - }
300 - // not stacked and first series in stack
301 - else {
302 - if (this.fillToZero) {
303 - ystart = this._yaxis.series_u2p(0);
304 - }
305 - else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
306 - ystart = this.gridData[i-1][1];
307 - }
308 - else {
309 - ystart = ctx.canvas.height;
310 - }
311 - }
312 - if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
313 - if (this.varyBarColor && !this._stack) {
314 - if (this.useNegativeColors) {
315 - opts.fillStyle = negativeColors.next();
316 - }
317 - else {
318 - opts.fillStyle = positiveColors.next();
319 - }
320 - }
321 - else {
322 - opts.fillStyle = negativeColor;
323 - }
324 - }
325 - else {
326 - if (this.varyBarColor && !this._stack) {
327 - opts.fillStyle = positiveColors.next();
328 - }
329 - else {
330 - opts.fillStyle = positiveColor;
331 - }
332 - }
333 -
334 - points.push([base-this.barWidth/2, ystart]);
335 - points.push([base-this.barWidth/2, gridData[i][1]]);
336 - points.push([base+this.barWidth/2, gridData[i][1]]);
337 - points.push([base+this.barWidth/2, ystart]);
338 - this._barPoints.push(points);
339 - // now draw the shadows if not stacked.
340 - // for stacked plots, they are predrawn by drawShadow
341 - if (shadow && !this._stack) {
342 - var sopts = $.extend(true, {}, opts);
343 - // need to get rid of fillStyle on shadow.
344 - delete sopts.fillStyle;
345 - this.renderer.shadowRenderer.draw(ctx, points, sopts);
346 - }
347 - var clr = opts.fillStyle || this.color;
348 - this._dataColors.push(clr);
349 - this.renderer.shapeRenderer.draw(ctx, points, opts);
350 - }
351 - }
352 -
353 - else if (this.barDirection == 'horizontal'){
354 - for (var i=0; i<gridData.length; i++) {
355 - if (this.data[i][0] == null) {
356 - continue;
357 - }
358 - points = [];
359 - var base = gridData[i][1] - this._barNudge;
360 - var xstart;
361 -
362 - if (this._stack && this._prevGridData.length) {
363 - xstart = this._prevGridData[i][0];
364 - }
365 - // not stacked and first series in stack
366 - else {
367 - if (this.fillToZero) {
368 - xstart = this._xaxis.series_u2p(0);
369 - }
370 - else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
371 - xstart = this.gridData[i-1][1];
372 - }
373 - else {
374 - xstart = 0;
375 - }
376 - }
377 - if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
378 - if (this.varyBarColor && !this._stack) {
379 - if (this.useNegativeColors) {
380 - opts.fillStyle = negativeColors.next();
381 - }
382 - else {
383 - opts.fillStyle = positiveColors.next();
384 - }
385 - }
386 - }
387 - else {
388 - if (this.varyBarColor && !this._stack) {
389 - opts.fillStyle = positiveColors.next();
390 - }
391 - else {
392 - opts.fillStyle = positiveColor;
393 - }
394 - }
395 -
396 - points.push([xstart, base+this.barWidth/2]);
397 - points.push([xstart, base-this.barWidth/2]);
398 - points.push([gridData[i][0], base-this.barWidth/2]);
399 - points.push([gridData[i][0], base+this.barWidth/2]);
400 - this._barPoints.push(points);
401 - // now draw the shadows if not stacked.
402 - // for stacked plots, they are predrawn by drawShadow
403 - if (shadow && !this._stack) {
404 - var sopts = $.extend(true, {}, opts);
405 - delete sopts.fillStyle;
406 - this.renderer.shadowRenderer.draw(ctx, points, sopts);
407 - }
408 - var clr = opts.fillStyle || this.color;
409 - this._dataColors.push(clr);
410 - this.renderer.shapeRenderer.draw(ctx, points, opts);
411 - }
412 - }
413 - }
414 -
415 - if (this.highlightColors.length == 0) {
416 - this.highlightColors = computeHighlightColors(this._dataColors);
417 - }
418 -
419 - else if (typeof(this.highlightColors) == 'string') {
420 - var temp = this.highlightColors;
421 - this.highlightColors = [];
422 - for (var i=0; i<this._dataColors.length; i++) {
423 - this.highlightColors.push(temp);
424 - }
425 - }
426 -
427 - };
428 -
429 -
430 - // for stacked plots, shadows will be pre drawn by drawShadow.
431 - $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options) {
432 - var i;
433 - var opts = (options != undefined) ? options : {};
434 - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
435 - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
436 - var fill = (opts.fill != undefined) ? opts.fill : this.fill;
437 - var xaxis = this.xaxis;
438 - var yaxis = this.yaxis;
439 - var xp = this._xaxis.series_u2p;
440 - var yp = this._yaxis.series_u2p;
441 - var pointx, pointy, nvals, nseries, pos;
442 -
443 - if (this._stack && this.shadow) {
444 - if (this.barWidth == null) {
445 - this.renderer.setBarWidth.call(this);
446 - }
447 -
448 - var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
449 - nvals = temp[0];
450 - nseries = temp[1];
451 - pos = temp[2];
452 -
453 - if (this._stack) {
454 - this._barNudge = 0;
455 - }
456 - else {
457 - this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
458 - }
459 - if (showLine) {
460 -
461 - if (this.barDirection == 'vertical') {
462 - for (var i=0; i<gridData.length; i++) {
463 - if (this.data[i][1] == null) {
464 - continue;
465 - }
466 - points = [];
467 - var base = gridData[i][0] + this._barNudge;
468 - var ystart;
469 -
470 - if (this._stack && this._prevGridData.length) {
471 - ystart = this._prevGridData[i][1];
472 - }
473 - else {
474 - if (this.fillToZero) {
475 - ystart = this._yaxis.series_u2p(0);
476 - }
477 - else {
478 - ystart = ctx.canvas.height;
479 - }
480 - }
481 -
482 - points.push([base-this.barWidth/2, ystart]);
483 - points.push([base-this.barWidth/2, gridData[i][1]]);
484 - points.push([base+this.barWidth/2, gridData[i][1]]);
485 - points.push([base+this.barWidth/2, ystart]);
486 - this.renderer.shadowRenderer.draw(ctx, points, opts);
487 - }
488 - }
489 -
490 - else if (this.barDirection == 'horizontal'){
491 - for (var i=0; i<gridData.length; i++) {
492 - if (this.data[i][0] == null) {
493 - continue;
494 - }
495 - points = [];
496 - var base = gridData[i][1] - this._barNudge;
497 - var xstart;
498 -
499 - if (this._stack && this._prevGridData.length) {
500 - xstart = this._prevGridData[i][0];
501 - }
502 - else {
503 - xstart = 0;
504 - }
505 -
506 - points.push([xstart, base+this.barWidth/2]);
507 - points.push([gridData[i][0], base+this.barWidth/2]);
508 - points.push([gridData[i][0], base-this.barWidth/2]);
509 - points.push([xstart, base-this.barWidth/2]);
510 - this.renderer.shadowRenderer.draw(ctx, points, opts);
511 - }
512 - }
513 - }
514 -
515 - }
516 - };
517 -
518 - function postInit(target, data, options) {
519 - for (i=0; i<this.series.length; i++) {
520 - if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) {
521 - // don't allow mouseover and mousedown at same time.
522 - if (this.series[i].highlightMouseOver) {
523 - this.series[i].highlightMouseDown = false;
524 - }
525 - }
526 - }
527 - this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
528 - }
529 -
530 - // called within context of plot
531 - // create a canvas which we can draw on.
532 - // insert it before the eventCanvas, so eventCanvas will still capture events.
533 - function postPlotDraw() {
534 - this.plugins.barRenderer = {highlightedSeriesIndex:null};
535 - this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
536 -
537 - this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions));
538 - var hctx = this.plugins.barRenderer.highlightCanvas.setContext();
539 - }
540 -
541 - function highlight (plot, sidx, pidx, points) {
542 - var s = plot.series[sidx];
543 - var canvas = plot.plugins.barRenderer.highlightCanvas;
544 - canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
545 - s._highlightedPoint = pidx;
546 - plot.plugins.barRenderer.highlightedSeriesIndex = sidx;
547 - var opts = {fillStyle: s.highlightColors[pidx]};
548 - s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
549 - }
550 -
551 - function unhighlight (plot) {
552 - var canvas = plot.plugins.barRenderer.highlightCanvas;
553 - canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
554 - for (var i=0; i<plot.series.length; i++) {
555 - plot.series[i]._highlightedPoint = null;
556 - }
557 - plot.plugins.barRenderer.highlightedSeriesIndex = null;
558 - plot.target.trigger('jqplotDataUnhighlight');
559 - }
560 -
561 -
562 - function handleMove(ev, gridpos, datapos, neighbor, plot) {
563 - if (neighbor) {
564 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
565 - var evt1 = jQuery.Event('jqplotDataMouseOver');
566 - evt1.pageX = ev.pageX;
567 - evt1.pageY = ev.pageY;
568 - plot.target.trigger(evt1, ins);
569 - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
570 - var evt = jQuery.Event('jqplotDataHighlight');
571 - evt.pageX = ev.pageX;
572 - evt.pageY = ev.pageY;
573 - plot.target.trigger(evt, ins);
574 - highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
575 - }
576 - }
577 - else if (neighbor == null) {
578 - unhighlight (plot);
579 - }
580 - }
581 -
582 - function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
583 - if (neighbor) {
584 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
585 - if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
586 - var evt = jQuery.Event('jqplotDataHighlight');
587 - evt.pageX = ev.pageX;
588 - evt.pageY = ev.pageY;
589 - plot.target.trigger(evt, ins);
590 - highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
591 - }
592 - }
593 - else if (neighbor == null) {
594 - unhighlight (plot);
595 - }
596 - }
597 -
598 - function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
599 - var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
600 - if (idx != null && plot.series[idx].highlightMouseDown) {
601 - unhighlight(plot);
602 - }
603 - }
604 -
605 - function handleClick(ev, gridpos, datapos, neighbor, plot) {
606 - if (neighbor) {
607 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
608 - var evt = jQuery.Event('jqplotDataClick');
609 - evt.pageX = ev.pageX;
610 - evt.pageY = ev.pageY;
611 - plot.target.trigger(evt, ins);
612 - }
613 - }
614 -
615 - function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
616 - if (neighbor) {
617 - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
618 - var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
619 - if (idx != null && plot.series[idx].highlightMouseDown) {
620 - unhighlight(plot);
621 - }
622 - var evt = jQuery.Event('jqplotDataRightClick');
623 - evt.pageX = ev.pageX;
624 - evt.pageY = ev.pageY;
625 - plot.target.trigger(evt, ins);
626 - }
627 - }
628 -
629 -
630 -})(jQuery);
\ No newline at end of file
Index: trunk/extensions/SemanticResultFormats/jqPlot/jquery.jqplot.css
@@ -1,165 +0,0 @@
2 -/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/
3 -.jqplot-target {
4 - position: relative;
5 - color: #666666;
6 - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
7 - font-size: 1em;
8 -}
9 -
10 -/*rules applied to all axes*/
11 -.jqplot-axis {
12 - font-size: 0.75em;
13 -}
14 -
15 -.jqplot-xaxis {
16 - margin-top: 10px;
17 -}
18 -
19 -.jqplot-x2axis {
20 - margin-bottom: 10px;
21 -}
22 -
23 -.jqplot-yaxis {
24 - margin-right: 10px;
25 -}
26 -
27 -.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis {
28 - margin-left: 10px;
29 - margin-right: 10px;
30 -}
31 -
32 -/*rules applied to all axis tick divs*/
33 -.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick {
34 - position: absolute;
35 -}
36 -
37 -
38 -.jqplot-xaxis-tick {
39 - top: 0px;
40 - /* initial position until tick is drawn in proper place */
41 - left: 15px;
42 -/* padding-top: 10px;*/
43 - vertical-align: top;
44 -}
45 -
46 -.jqplot-x2axis-tick {
47 - bottom: 0px;
48 - /* initial position until tick is drawn in proper place */
49 - left: 15px;
50 -/* padding-bottom: 10px;*/
51 - vertical-align: bottom;
52 -}
53 -
54 -.jqplot-yaxis-tick {
55 - right: 0px;
56 - /* initial position until tick is drawn in proper place */
57 - top: 15px;
58 -/* padding-right: 10px;*/
59 - text-align: right;
60 -}
61 -
62 -.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick {
63 - left: 0px;
64 - /* initial position until tick is drawn in proper place */
65 - top: 15px;
66 -/* padding-left: 10px;*/
67 -/* padding-right: 15px;*/
68 - text-align: left;
69 -}
70 -
71 -.jqplot-xaxis-label {
72 - margin-top: 10px;
73 - font-size: 11pt;
74 - position: absolute;
75 -}
76 -
77 -.jqplot-x2axis-label {
78 - margin-bottom: 10px;
79 - font-size: 11pt;
80 - position: absolute;
81 -}
82 -
83 -.jqplot-yaxis-label {
84 - margin-right: 10px;
85 -/* text-align: center;*/
86 - font-size: 11pt;
87 - position: absolute;
88 -}
89 -
90 -.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
91 -/* text-align: center;*/
92 - font-size: 11pt;
93 - position: absolute;
94 -}
95 -
96 -table.jqplot-table-legend, table.jqplot-cursor-legend {
97 - background-color: rgba(255,255,255,0.6);
98 - border: 1px solid #cccccc;
99 - position: absolute;
100 - font-size: 0.75em;
101 -}
102 -
103 -td.jqplot-table-legend {
104 - vertical-align:middle;
105 -}
106 -
107 -td.jqplot-table-legend > div {
108 - border:1px solid #cccccc;
109 - padding:0.2em;
110 -}
111 -
112 -div.jqplot-table-legend-swatch {
113 - width:0px;
114 - height:0px;
115 - border-top-width: 0.35em;
116 - border-bottom-width: 0.35em;
117 - border-left-width: 0.6em;
118 - border-right-width: 0.6em;
119 - border-top-style: solid;
120 - border-bottom-style: solid;
121 - border-left-style: solid;
122 - border-right-style: solid;
123 -}
124 -
125 -.jqplot-title {
126 - top: 0px;
127 - left: 0px;
128 - padding-bottom: 0.5em;
129 - font-size: 1.2em;
130 -}
131 -
132 -table.jqplot-cursor-tooltip {
133 - border: 1px solid #cccccc;
134 - font-size: 0.75em;
135 -}
136 -
137 -
138 -.jqplot-cursor-tooltip {
139 - border: 1px solid #cccccc;
140 - font-size: 0.75em;
141 - white-space: nowrap;
142 - background: rgba(208,208,208,0.5);
143 - padding: 1px;
144 -}
145 -
146 -.jqplot-highlighter-tooltip {
147 - border: 1px solid #cccccc;
148 - font-size: 0.75em;
149 - white-space: nowrap;
150 - background: rgba(208,208,208,0.5);
151 - padding: 1px;
152 -}
153 -
154 -.jqplot-point-label {
155 - font-size: 0.75em;
156 -}
157 -
158 -td.jqplot-cursor-legend-swatch {
159 - vertical-align:middle;
160 - text-align:center;
161 -}
162 -
163 -div.jqplot-cursor-legend-swatch {
164 - width:1.2em;
165 - height:0.7em;
166 -}

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r114644applied patch by MWJames provided at bug 35627jeroendedauw15:37, 31 March 2012

Status & tagging log