1 | /** |
---|
2 | * o------------------------------------------------------------------------------o |
---|
3 | * | This file is part of the RGraph package - you can learn more at: | |
---|
4 | * | | |
---|
5 | * | http://www.rgraph.net | |
---|
6 | * | | |
---|
7 | * | This package is licensed under the RGraph license. For all kinds of business | |
---|
8 | * | purposes there is a small one-time licensing fee to pay and for non | |
---|
9 | * | commercial purposes it is free to use. You can read the full license here: | |
---|
10 | * | | |
---|
11 | * | http://www.rgraph.net/LICENSE.txt | |
---|
12 | * o------------------------------------------------------------------------------o |
---|
13 | */ |
---|
14 | |
---|
15 | /** |
---|
16 | * Initialise the various objects |
---|
17 | */ |
---|
18 | if (typeof(RGraph) == 'undefined') RGraph = {isRGraph:true,type:'common'}; |
---|
19 | |
---|
20 | |
---|
21 | RGraph.Registry = {}; |
---|
22 | RGraph.Registry.store = []; |
---|
23 | RGraph.Registry.store['chart.event.handlers'] = []; |
---|
24 | RGraph.background = {}; |
---|
25 | RGraph.objects = []; |
---|
26 | RGraph.Resizing = {}; |
---|
27 | RGraph.events = []; |
---|
28 | |
---|
29 | |
---|
30 | |
---|
31 | /** |
---|
32 | * Returns five values which are used as a nice scale |
---|
33 | * |
---|
34 | * @param max int The maximum value of the graph |
---|
35 | * @param obj object The graph object |
---|
36 | * @return array An appropriate scale |
---|
37 | */ |
---|
38 | RGraph.getScale = function (max, obj) |
---|
39 | { |
---|
40 | /** |
---|
41 | * Special case for 0 |
---|
42 | */ |
---|
43 | if (max == 0) { |
---|
44 | return ['0.2', '0.4', '0.6', '0.8', '1.0']; |
---|
45 | } |
---|
46 | |
---|
47 | var original_max = max; |
---|
48 | |
---|
49 | /** |
---|
50 | * Manually do decimals |
---|
51 | */ |
---|
52 | if (max <= 1) { |
---|
53 | if (max > 0.5) { |
---|
54 | return [0.2,0.4,0.6,0.8, Number(1).toFixed(1)]; |
---|
55 | |
---|
56 | } else if (max >= 0.1) { |
---|
57 | return obj.Get('chart.scale.round') ? [0.2,0.4,0.6,0.8,1] : [0.1,0.2,0.3,0.4,0.5]; |
---|
58 | |
---|
59 | } else { |
---|
60 | |
---|
61 | var tmp = max; |
---|
62 | var exp = 0; |
---|
63 | |
---|
64 | while (tmp < 1.01) { |
---|
65 | exp += 1; |
---|
66 | tmp *= 10; |
---|
67 | } |
---|
68 | |
---|
69 | var ret = ['2e-' + exp, '4e-' + exp, '6e-' + exp, '8e-' + exp, '10e-' + exp]; |
---|
70 | |
---|
71 | |
---|
72 | if (max <= ('5e-' + exp)) { |
---|
73 | ret = ['1e-' + exp, '2e-' + exp, '3e-' + exp, '4e-' + exp, '5e-' + exp]; |
---|
74 | } |
---|
75 | |
---|
76 | return ret; |
---|
77 | } |
---|
78 | } |
---|
79 | |
---|
80 | // Take off any decimals |
---|
81 | if (String(max).indexOf('.') > 0) { |
---|
82 | max = String(max).replace(/\.\d+$/, ''); |
---|
83 | } |
---|
84 | |
---|
85 | var interval = Math.pow(10, Number(String(Number(max)).length - 1)); |
---|
86 | var topValue = interval; |
---|
87 | |
---|
88 | while (topValue < max) { |
---|
89 | topValue += (interval / 2); |
---|
90 | } |
---|
91 | |
---|
92 | // Handles cases where the max is (for example) 50.5 |
---|
93 | if (Number(original_max) > Number(topValue)) { |
---|
94 | topValue += (interval / 2); |
---|
95 | } |
---|
96 | |
---|
97 | // Custom if the max is greater than 5 and less than 10 |
---|
98 | if (max < 10) { |
---|
99 | topValue = (Number(original_max) <= 5 ? 5 : 10); |
---|
100 | } |
---|
101 | |
---|
102 | /** |
---|
103 | * Added 02/11/2010 to create "nicer" scales |
---|
104 | */ |
---|
105 | if (obj && typeof(obj.Get('chart.scale.round')) == 'boolean' && obj.Get('chart.scale.round')) { |
---|
106 | topValue = 10 * interval; |
---|
107 | } |
---|
108 | |
---|
109 | return [topValue * 0.2, topValue * 0.4, topValue * 0.6, topValue * 0.8, topValue]; |
---|
110 | } |
---|
111 | |
---|
112 | |
---|
113 | /** |
---|
114 | * Returns the maximum numeric value which is in an array |
---|
115 | * |
---|
116 | * @param array arr The array (can also be a number, in which case it's returned as-is) |
---|
117 | * @param int Whether to ignore signs (ie negative/positive) |
---|
118 | * @return int The maximum value in the array |
---|
119 | */ |
---|
120 | RGraph.array_max = function (arr) |
---|
121 | { |
---|
122 | var max = null; |
---|
123 | |
---|
124 | if (typeof(arr) == 'number') { |
---|
125 | return arr; |
---|
126 | } |
---|
127 | |
---|
128 | for (var i=0; i<arr.length; ++i) { |
---|
129 | if (typeof(arr[i]) == 'number') { |
---|
130 | |
---|
131 | var val = arguments[1] ? Math.abs(arr[i]) : arr[i]; |
---|
132 | |
---|
133 | if (typeof(max) == 'number') { |
---|
134 | max = Math.max(max, val); |
---|
135 | } else { |
---|
136 | max = val; |
---|
137 | } |
---|
138 | } |
---|
139 | } |
---|
140 | |
---|
141 | return max; |
---|
142 | } |
---|
143 | |
---|
144 | |
---|
145 | /** |
---|
146 | * Returns the maximum value which is in an array |
---|
147 | * |
---|
148 | * @param array arr The array |
---|
149 | * @param int len The length to pad the array to |
---|
150 | * @param mixed The value to use to pad the array (optional) |
---|
151 | */ |
---|
152 | RGraph.array_pad = function (arr, len) |
---|
153 | { |
---|
154 | if (arr.length < len) { |
---|
155 | var val = arguments[2] ? arguments[2] : null; |
---|
156 | |
---|
157 | for (var i=arr.length; i<len; ++i) { |
---|
158 | arr[i] = val; |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | return arr; |
---|
163 | } |
---|
164 | |
---|
165 | |
---|
166 | /** |
---|
167 | * An array sum function |
---|
168 | * |
---|
169 | * @param array arr The array to calculate the total of |
---|
170 | * @return int The summed total of the arrays elements |
---|
171 | */ |
---|
172 | RGraph.array_sum = function (arr) |
---|
173 | { |
---|
174 | // Allow integers |
---|
175 | if (typeof(arr) == 'number') { |
---|
176 | return arr; |
---|
177 | } |
---|
178 | |
---|
179 | var i, sum; |
---|
180 | var len = arr.length; |
---|
181 | |
---|
182 | for(i=0,sum=0;i<len;sum+=arr[i++]); |
---|
183 | return sum; |
---|
184 | } |
---|
185 | |
---|
186 | |
---|
187 | |
---|
188 | /** |
---|
189 | * A simple is_array() function |
---|
190 | * |
---|
191 | * @param mixed obj The object you want to check |
---|
192 | * @return bool Whether the object is an array or not |
---|
193 | */ |
---|
194 | RGraph.is_array = function (obj) |
---|
195 | { |
---|
196 | return obj != null && obj.constructor.toString().indexOf('Array') != -1; |
---|
197 | } |
---|
198 | |
---|
199 | |
---|
200 | /** |
---|
201 | * Converts degrees to radians |
---|
202 | * |
---|
203 | * @param int degrees The number of degrees |
---|
204 | * @return float The number of radians |
---|
205 | */ |
---|
206 | RGraph.degrees2Radians = function (degrees) |
---|
207 | { |
---|
208 | return degrees * (Math.PI / 180); |
---|
209 | } |
---|
210 | |
---|
211 | |
---|
212 | /** |
---|
213 | * This function draws an angled line. The angle is cosidered to be clockwise |
---|
214 | * |
---|
215 | * @param obj ctxt The context object |
---|
216 | * @param int x The X position |
---|
217 | * @param int y The Y position |
---|
218 | * @param int angle The angle in RADIANS |
---|
219 | * @param int length The length of the line |
---|
220 | */ |
---|
221 | RGraph.lineByAngle = function (context, x, y, angle, length) |
---|
222 | { |
---|
223 | context.arc(x, y, length, angle, angle, false); |
---|
224 | context.lineTo(x, y); |
---|
225 | context.arc(x, y, length, angle, angle, false); |
---|
226 | } |
---|
227 | |
---|
228 | |
---|
229 | /** |
---|
230 | * This is a useful function which is basically a shortcut for drawing left, right, top and bottom alligned text. |
---|
231 | * |
---|
232 | * @param object context The context |
---|
233 | * @param string font The font |
---|
234 | * @param int size The size of the text |
---|
235 | * @param int x The X coordinate |
---|
236 | * @param int y The Y coordinate |
---|
237 | * @param string text The text to draw |
---|
238 | * @parm string The vertical alignment. Can be null. "center" gives center aligned text, "top" gives top aligned text. |
---|
239 | * Anything else produces bottom aligned text. Default is bottom. |
---|
240 | * @param string The horizontal alignment. Can be null. "center" gives center aligned text, "right" gives right aligned text. |
---|
241 | * Anything else produces left aligned text. Default is left. |
---|
242 | * @param bool Whether to show a bounding box around the text. Defaults not to |
---|
243 | * @param int The angle that the text should be rotate at (IN DEGREES) |
---|
244 | * @param string Background color for the text |
---|
245 | * @param bool Whether the text is bold or not |
---|
246 | * @param bool Whether the bounding box has a placement indicator |
---|
247 | */ |
---|
248 | RGraph.Text = function (context, font, size, x, y, text) |
---|
249 | { |
---|
250 | /** |
---|
251 | * This calls the text function recursively to accommodate multi-line text |
---|
252 | */ |
---|
253 | if (typeof(text) == 'string' && text.match(/\r\n/)) { |
---|
254 | |
---|
255 | var arr = text.split('\r\n'); |
---|
256 | |
---|
257 | text = arr[0]; |
---|
258 | arr = RGraph.array_shift(arr); |
---|
259 | |
---|
260 | var nextline = arr.join('\r\n') |
---|
261 | |
---|
262 | RGraph.Text(context, font, size, arguments[9] == -90 ? (x + (size * 1.5)) : x, y + (size * 1.5), nextline, arguments[6] ? arguments[6] : null, 'center', arguments[8], arguments[9], arguments[10], arguments[11], arguments[12]); |
---|
263 | } |
---|
264 | |
---|
265 | |
---|
266 | // Accommodate MSIE |
---|
267 | if (RGraph.isIE8()) { |
---|
268 | y += 2; |
---|
269 | } |
---|
270 | |
---|
271 | |
---|
272 | context.font = (arguments[11] ? 'Bold ': '') + size + 'pt ' + font; |
---|
273 | |
---|
274 | var i; |
---|
275 | var origX = x; |
---|
276 | var origY = y; |
---|
277 | var originalFillStyle = context.fillStyle; |
---|
278 | var originalLineWidth = context.lineWidth; |
---|
279 | |
---|
280 | // Need these now the angle can be specified, ie defaults for the former two args |
---|
281 | if (typeof(arguments[6]) == null) arguments[6] = 'bottom'; // Vertical alignment. Default to bottom/baseline |
---|
282 | if (typeof(arguments[7]) == null) arguments[7] = 'left'; // Horizontal alignment. Default to left |
---|
283 | if (typeof(arguments[8]) == null) arguments[8] = null; // Show a bounding box. Useful for positioning during development. Defaults to false |
---|
284 | if (typeof(arguments[9]) == null) arguments[9] = 0; // Angle (IN DEGREES) that the text should be drawn at. 0 is middle right, and it goes clockwise |
---|
285 | if (typeof(arguments[12]) == null) arguments[12] = true; // Whether the bounding box has the placement indicator |
---|
286 | |
---|
287 | // The alignment is recorded here for purposes of Opera compatibility |
---|
288 | if (navigator.userAgent.indexOf('Opera') != -1) { |
---|
289 | context.canvas.__rgraph_valign__ = arguments[6]; |
---|
290 | context.canvas.__rgraph_halign__ = arguments[7]; |
---|
291 | } |
---|
292 | |
---|
293 | // First, translate to x/y coords |
---|
294 | context.save(); |
---|
295 | |
---|
296 | context.canvas.__rgraph_originalx__ = x; |
---|
297 | context.canvas.__rgraph_originaly__ = y; |
---|
298 | |
---|
299 | context.translate(x, y); |
---|
300 | x = 0; |
---|
301 | y = 0; |
---|
302 | |
---|
303 | // Rotate the canvas if need be |
---|
304 | if (arguments[9]) { |
---|
305 | context.rotate(arguments[9] / 57.3); |
---|
306 | } |
---|
307 | |
---|
308 | // Vertical alignment - defaults to bottom |
---|
309 | if (arguments[6]) { |
---|
310 | var vAlign = arguments[6]; |
---|
311 | |
---|
312 | if (vAlign == 'center') { |
---|
313 | context.translate(0, size / 2); |
---|
314 | } else if (vAlign == 'top') { |
---|
315 | context.translate(0, size); |
---|
316 | } |
---|
317 | } |
---|
318 | |
---|
319 | |
---|
320 | // Hoeizontal alignment - defaults to left |
---|
321 | if (arguments[7]) { |
---|
322 | var hAlign = arguments[7]; |
---|
323 | var width = context.measureText(text).width; |
---|
324 | |
---|
325 | if (hAlign) { |
---|
326 | if (hAlign == 'center') { |
---|
327 | context.translate(-1 * (width / 2), 0) |
---|
328 | } else if (hAlign == 'right') { |
---|
329 | context.translate(-1 * width, 0) |
---|
330 | } |
---|
331 | } |
---|
332 | } |
---|
333 | |
---|
334 | |
---|
335 | context.fillStyle = originalFillStyle; |
---|
336 | |
---|
337 | /** |
---|
338 | * Draw a bounding box if requested |
---|
339 | */ |
---|
340 | context.save(); |
---|
341 | context.fillText(text,0,0); |
---|
342 | context.lineWidth = 0.5; |
---|
343 | |
---|
344 | if (arguments[8]) { |
---|
345 | |
---|
346 | var width = context.measureText(text).width; |
---|
347 | var ieOffset = RGraph.isIE8() ? 2 : 0; |
---|
348 | |
---|
349 | context.translate(x, y); |
---|
350 | context.strokeRect(0 - 3, 0 - 3 - size - ieOffset, width + 6, 0 + size + 6); |
---|
351 | |
---|
352 | /** |
---|
353 | * If requested, draw a background for the text |
---|
354 | */ |
---|
355 | if (arguments[10]) { |
---|
356 | |
---|
357 | var offset = 3; |
---|
358 | var ieOffset = RGraph.isIE8() ? 2 : 0; |
---|
359 | var width = context.measureText(text).width |
---|
360 | |
---|
361 | //context.strokeStyle = 'gray'; |
---|
362 | context.fillStyle = arguments[10]; |
---|
363 | context.fillRect(x - offset, y - size - offset - ieOffset, width + (2 * offset), size + (2 * offset)); |
---|
364 | //context.strokeRect(x - offset, y - size - offset - ieOffset, width + (2 * offset), size + (2 * offset)); |
---|
365 | } |
---|
366 | |
---|
367 | /** |
---|
368 | * Do the actual drawing of the text |
---|
369 | */ |
---|
370 | context.fillStyle = originalFillStyle; |
---|
371 | context.fillText(text,0,0); |
---|
372 | |
---|
373 | if (arguments[12]) { |
---|
374 | context.fillRect( |
---|
375 | arguments[7] == 'left' ? 0 : (arguments[7] == 'center' ? width / 2 : width ) - 2, |
---|
376 | arguments[6] == 'bottom' ? 0 : (arguments[6] == 'center' ? (0 - size) / 2 : 0 - size) - 2, |
---|
377 | 4, |
---|
378 | 4 |
---|
379 | ); |
---|
380 | } |
---|
381 | } |
---|
382 | context.restore(); |
---|
383 | |
---|
384 | // Reset the lineWidth |
---|
385 | context.lineWidth = originalLineWidth; |
---|
386 | |
---|
387 | context.restore(); |
---|
388 | } |
---|
389 | |
---|
390 | |
---|
391 | /** |
---|
392 | * Clears the canvas by setting the width. You can specify a colour if you wish. |
---|
393 | * |
---|
394 | * @param object canvas The canvas to clear |
---|
395 | */ |
---|
396 | RGraph.Clear = function (canvas) |
---|
397 | { |
---|
398 | var context = canvas.getContext('2d'); |
---|
399 | var color = arguments[1]; |
---|
400 | |
---|
401 | if (RGraph.isIE8() && !color) { |
---|
402 | color = 'white'; |
---|
403 | } |
---|
404 | |
---|
405 | /** |
---|
406 | * Can now clear the canvas back to fully transparent |
---|
407 | */ |
---|
408 | if (!color || (color && color == 'transparent')) { |
---|
409 | |
---|
410 | context.fillStyle = 'rgba(0,0,0,0)'; |
---|
411 | context.globalCompositeOperation = 'source-in'; |
---|
412 | context = canvas.getContext('2d'); |
---|
413 | context.beginPath(); |
---|
414 | context.fillRect(-1000,-1000,canvas.width + 2000,canvas.height + 2000); |
---|
415 | context.fill(); |
---|
416 | |
---|
417 | // Reset the globalCompositeOperation |
---|
418 | context.globalCompositeOperation = 'source-over'; |
---|
419 | |
---|
420 | } else { |
---|
421 | |
---|
422 | context.fillStyle = color; |
---|
423 | context = canvas.getContext('2d'); |
---|
424 | context.beginPath(); |
---|
425 | |
---|
426 | if (RGraph.isIE8()) { |
---|
427 | context.fillRect(0,0,canvas.width,canvas.height); |
---|
428 | } else { |
---|
429 | context.fillRect(-1000,-1000,canvas.width + 2000,canvas.height + 2000); |
---|
430 | } |
---|
431 | |
---|
432 | context.fill(); |
---|
433 | } |
---|
434 | |
---|
435 | // Don't do this as it also clears any translation that may have occurred |
---|
436 | //canvas.width = canvas.width; |
---|
437 | |
---|
438 | if (RGraph.ClearAnnotations) { |
---|
439 | RGraph.ClearAnnotations(canvas.id); |
---|
440 | } |
---|
441 | |
---|
442 | RGraph.FireCustomEvent(canvas.__object__, 'onclear'); |
---|
443 | } |
---|
444 | |
---|
445 | |
---|
446 | /** |
---|
447 | * Draws the title of the graph |
---|
448 | * |
---|
449 | * @param object canvas The canvas object |
---|
450 | * @param string text The title to write |
---|
451 | * @param integer gutter The size of the gutter |
---|
452 | * @param integer The center X point (optional - if not given it will be generated from the canvas width) |
---|
453 | * @param integer Size of the text. If not given it will be 14 |
---|
454 | */ |
---|
455 | RGraph.DrawTitle = function (canvas, text, gutterTop) |
---|
456 | { |
---|
457 | var obj = canvas.__object__; |
---|
458 | var context = canvas.getContext('2d'); |
---|
459 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
460 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
461 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
462 | var size = arguments[4] ? arguments[4] : 12; |
---|
463 | var centerx = (arguments[3] ? arguments[3] : ((RGraph.GetWidth(obj) - gutterLeft - gutterRight) / 2) + gutterLeft); |
---|
464 | var keypos = obj.Get('chart.key.position'); |
---|
465 | var vpos = obj.Get('chart.title.vpos'); |
---|
466 | var hpos = obj.Get('chart.title.hpos'); |
---|
467 | var bgcolor = obj.Get('chart.title.background'); |
---|
468 | |
---|
469 | // Account for 3D effect by faking the key position |
---|
470 | if (obj.type == 'bar' && obj.Get('chart.variant') == '3d') { |
---|
471 | keypos = 'gutter'; |
---|
472 | } |
---|
473 | |
---|
474 | context.beginPath(); |
---|
475 | context.fillStyle = obj.Get('chart.text.color') ? obj.Get('chart.text.color') : 'black'; |
---|
476 | |
---|
477 | /** |
---|
478 | * Vertically center the text if the key is not present |
---|
479 | */ |
---|
480 | if (keypos && keypos != 'gutter') { |
---|
481 | var vCenter = 'center'; |
---|
482 | |
---|
483 | } else if (!keypos) { |
---|
484 | var vCenter = 'center'; |
---|
485 | |
---|
486 | } else { |
---|
487 | var vCenter = 'bottom'; |
---|
488 | } |
---|
489 | |
---|
490 | // if chart.title.vpos does not equal 0.5, use that |
---|
491 | if (typeof(obj.Get('chart.title.vpos')) == 'number') { |
---|
492 | vpos = obj.Get('chart.title.vpos') * gutterTop; |
---|
493 | |
---|
494 | if (obj.Get('chart.xaxispos') == 'top') { |
---|
495 | vpos = obj.Get('chart.title.vpos') * gutterBottom + gutterTop + (obj.canvas.height - gutterTop - gutterBottom); |
---|
496 | } |
---|
497 | } else { |
---|
498 | vpos = gutterTop - size - 5; |
---|
499 | |
---|
500 | if (obj.Get('chart.xaxispos') == 'top') { |
---|
501 | vpos = obj.canvas.height - gutterBottom + size + 5; |
---|
502 | } |
---|
503 | } |
---|
504 | |
---|
505 | // if chart.title.hpos is a number, use that. It's multiplied with the (entire) canvas width |
---|
506 | if (typeof(hpos) == 'number') { |
---|
507 | centerx = hpos * canvas.width; |
---|
508 | } |
---|
509 | |
---|
510 | // Set the colour |
---|
511 | if (typeof(obj.Get('chart.title.color') != null)) { |
---|
512 | var oldColor = context.fillStyle |
---|
513 | var newColor = obj.Get('chart.title.color') |
---|
514 | context.fillStyle = newColor ? newColor : 'black'; |
---|
515 | } |
---|
516 | |
---|
517 | /** |
---|
518 | * Default font is Verdana |
---|
519 | */ |
---|
520 | var font = obj.Get('chart.text.font'); |
---|
521 | |
---|
522 | /** |
---|
523 | * Draw the title itself |
---|
524 | */ |
---|
525 | RGraph.Text(context, font, size, centerx, vpos, text, vCenter, 'center', bgcolor != null, null, bgcolor, true); |
---|
526 | |
---|
527 | // Reset the fill colour |
---|
528 | context.fillStyle = oldColor; |
---|
529 | } |
---|
530 | |
---|
531 | |
---|
532 | /** |
---|
533 | * This function returns the mouse position in relation to the canvas |
---|
534 | * |
---|
535 | * @param object e The event object. |
---|
536 | */ |
---|
537 | RGraph.getMouseXY = function (e) |
---|
538 | { |
---|
539 | var obj = (RGraph.isIE8() ? event.srcElement : e.target); |
---|
540 | var x; |
---|
541 | var y; |
---|
542 | |
---|
543 | if (RGraph.isIE8()) e = event; |
---|
544 | |
---|
545 | // Browser with offsetX and offsetY |
---|
546 | if (typeof(e.offsetX) == 'number' && typeof(e.offsetY) == 'number') { |
---|
547 | x = e.offsetX; |
---|
548 | y = e.offsetY; |
---|
549 | |
---|
550 | // FF and other |
---|
551 | } else { |
---|
552 | x = 0; |
---|
553 | y = 0; |
---|
554 | |
---|
555 | while (obj != document.body && obj) { |
---|
556 | x += obj.offsetLeft; |
---|
557 | y += obj.offsetTop; |
---|
558 | |
---|
559 | obj = obj.offsetParent; |
---|
560 | } |
---|
561 | |
---|
562 | x = e.pageX - x; |
---|
563 | y = e.pageY - y; |
---|
564 | } |
---|
565 | |
---|
566 | return [x, y]; |
---|
567 | } |
---|
568 | |
---|
569 | |
---|
570 | /** |
---|
571 | * This function returns a two element array of the canvas x/y position in |
---|
572 | * relation to the page |
---|
573 | * |
---|
574 | * @param object canvas |
---|
575 | */ |
---|
576 | RGraph.getCanvasXY = function (canvas) |
---|
577 | { |
---|
578 | var x = 0; |
---|
579 | var y = 0; |
---|
580 | var obj = canvas; |
---|
581 | |
---|
582 | do { |
---|
583 | |
---|
584 | x += obj.offsetLeft; |
---|
585 | y += obj.offsetTop; |
---|
586 | |
---|
587 | obj = obj.offsetParent; |
---|
588 | |
---|
589 | } while (obj && obj.tagName.toLowerCase() != 'body'); |
---|
590 | |
---|
591 | return [x, y]; |
---|
592 | } |
---|
593 | |
---|
594 | |
---|
595 | /** |
---|
596 | * Registers a graph object (used when the canvas is redrawn) |
---|
597 | * |
---|
598 | * @param object obj The object to be registered |
---|
599 | */ |
---|
600 | RGraph.Register = function (obj) |
---|
601 | { |
---|
602 | var key = obj.id + '_' + obj.type; |
---|
603 | |
---|
604 | RGraph.objects[key] = obj; |
---|
605 | } |
---|
606 | |
---|
607 | |
---|
608 | /** |
---|
609 | * Causes all registered objects to be redrawn |
---|
610 | * |
---|
611 | * @param string An optional string indicating which canvas is not to be redrawn |
---|
612 | * @param string An optional color to use to clear the canvas |
---|
613 | */ |
---|
614 | RGraph.Redraw = function () |
---|
615 | { |
---|
616 | for (i in RGraph.objects) { |
---|
617 | // TODO FIXME Maybe include more intense checking for whether the object is an RGraph object, eg obj.isRGraph == true ...? |
---|
618 | if ( |
---|
619 | typeof(i) == 'string' |
---|
620 | && typeof(RGraph.objects[i]) == 'object' |
---|
621 | && typeof(RGraph.objects[i].type) == 'string' |
---|
622 | && RGraph.objects[i].isRGraph) { |
---|
623 | |
---|
624 | if (!arguments[0] || arguments[0] != RGraph.objects[i].id) { |
---|
625 | RGraph.Clear(RGraph.objects[i].canvas, arguments[1] ? arguments[1] : null); |
---|
626 | RGraph.objects[i].Draw(); |
---|
627 | } |
---|
628 | } |
---|
629 | } |
---|
630 | } |
---|
631 | |
---|
632 | |
---|
633 | /** |
---|
634 | * Loosly mimicks the PHP function print_r(); |
---|
635 | */ |
---|
636 | RGraph.pr = function (obj) |
---|
637 | { |
---|
638 | var str = ''; |
---|
639 | var indent = (arguments[2] ? arguments[2] : ''); |
---|
640 | |
---|
641 | switch (typeof(obj)) { |
---|
642 | case 'number': |
---|
643 | if (indent == '') { |
---|
644 | str+= 'Number: ' |
---|
645 | } |
---|
646 | str += String(obj); |
---|
647 | break; |
---|
648 | |
---|
649 | case 'string': |
---|
650 | if (indent == '') { |
---|
651 | str+= 'String (' + obj.length + '):' |
---|
652 | } |
---|
653 | str += '"' + String(obj) + '"'; |
---|
654 | break; |
---|
655 | |
---|
656 | case 'object': |
---|
657 | // In case of null |
---|
658 | if (obj == null) { |
---|
659 | str += 'null'; |
---|
660 | break; |
---|
661 | } |
---|
662 | |
---|
663 | str += 'Object\n' + indent + '(\n'; |
---|
664 | |
---|
665 | for (var i=0; i<obj.length; ++i) { |
---|
666 | str += indent + ' ' + i + ' => ' + RGraph.pr(obj[i], true, indent + ' ') + '\n'; |
---|
667 | } |
---|
668 | |
---|
669 | var str = str + indent + ')'; |
---|
670 | break; |
---|
671 | |
---|
672 | case 'function': |
---|
673 | str += obj; |
---|
674 | break; |
---|
675 | |
---|
676 | case 'boolean': |
---|
677 | str += 'Boolean: ' + (obj ? 'true' : 'false'); |
---|
678 | break; |
---|
679 | } |
---|
680 | |
---|
681 | /** |
---|
682 | * Finished, now either return if we're in a recursed call, or alert() |
---|
683 | * if we're not. |
---|
684 | */ |
---|
685 | if (arguments[1]) { |
---|
686 | return str; |
---|
687 | } else { |
---|
688 | alert(str); |
---|
689 | } |
---|
690 | } |
---|
691 | |
---|
692 | |
---|
693 | /** |
---|
694 | * The RGraph registry Set() function |
---|
695 | * |
---|
696 | * @param string name The name of the key |
---|
697 | * @param mixed value The value to set |
---|
698 | * @return mixed Returns the same value as you pass it |
---|
699 | */ |
---|
700 | RGraph.Registry.Set = function (name, value) |
---|
701 | { |
---|
702 | // Store the setting |
---|
703 | RGraph.Registry.store[name] = value; |
---|
704 | |
---|
705 | // Don't really need to do this, but ho-hum |
---|
706 | return value; |
---|
707 | } |
---|
708 | |
---|
709 | |
---|
710 | /** |
---|
711 | * The RGraph registry Get() function |
---|
712 | * |
---|
713 | * @param string name The name of the particular setting to fetch |
---|
714 | * @return mixed The value if exists, null otherwise |
---|
715 | */ |
---|
716 | RGraph.Registry.Get = function (name) |
---|
717 | { |
---|
718 | //return RGraph.Registry.store[name] == null ? null : RGraph.Registry.store[name]; |
---|
719 | return RGraph.Registry.store[name]; |
---|
720 | } |
---|
721 | |
---|
722 | |
---|
723 | /** |
---|
724 | * This function draws the background for the bar chart, line chart and scatter chart. |
---|
725 | * |
---|
726 | * @param object obj The graph object |
---|
727 | */ |
---|
728 | RGraph.background.Draw = function (obj) |
---|
729 | { |
---|
730 | var canvas = obj.canvas; |
---|
731 | var context = obj.context; |
---|
732 | var height = 0; |
---|
733 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
734 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
735 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
736 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
737 | var variant = obj.Get('chart.variant'); |
---|
738 | |
---|
739 | context.fillStyle = obj.Get('chart.text.color'); |
---|
740 | |
---|
741 | // If it's a bar and 3D variant, translate |
---|
742 | if (variant == '3d') { |
---|
743 | context.save(); |
---|
744 | context.translate(10, -5); |
---|
745 | } |
---|
746 | |
---|
747 | // X axis title |
---|
748 | if (typeof(obj.Get('chart.title.xaxis')) == 'string' && obj.Get('chart.title.xaxis').length) { |
---|
749 | |
---|
750 | var size = obj.Get('chart.text.size'); |
---|
751 | var font = obj.Get('chart.text.font'); |
---|
752 | |
---|
753 | context.beginPath(); |
---|
754 | RGraph.Text(context, font, size + 2, RGraph.GetWidth(obj) / 2, RGraph.GetHeight(obj) - (gutterBottom * obj.Get('chart.title.xaxis.pos')), obj.Get('chart.title.xaxis'), 'center', 'center', false, false, false, true); |
---|
755 | context.fill(); |
---|
756 | } |
---|
757 | |
---|
758 | // Y axis title |
---|
759 | if (typeof(obj.Get('chart.title.yaxis')) == 'string' && obj.Get('chart.title.yaxis').length) { |
---|
760 | |
---|
761 | var size = obj.Get('chart.text.size'); |
---|
762 | var font = obj.Get('chart.text.font'); |
---|
763 | var angle = 270; |
---|
764 | var yaxis_title_pos = obj.Get('chart.title.yaxis.pos'); |
---|
765 | |
---|
766 | if (obj.Get('chart.title.yaxis.align') == 'right' || obj.Get('chart.title.yaxis.position') == 'right') { |
---|
767 | angle = 90; |
---|
768 | yaxis_title_pos = yaxis_title_pos * obj.Get('chart.gutter.right') + (obj.canvas.width - obj.Get('chart.gutter.right')); |
---|
769 | } else { |
---|
770 | yaxis_title_pos *= obj.Get('chart.gutter.left'); |
---|
771 | } |
---|
772 | |
---|
773 | |
---|
774 | context.beginPath(); |
---|
775 | RGraph.Text(context, |
---|
776 | font, |
---|
777 | size + 2, |
---|
778 | yaxis_title_pos, |
---|
779 | RGraph.GetHeight(obj) / 2, |
---|
780 | obj.Get('chart.title.yaxis'), |
---|
781 | 'center', |
---|
782 | 'center', |
---|
783 | false, |
---|
784 | angle, |
---|
785 | false, |
---|
786 | true); |
---|
787 | context.fill(); |
---|
788 | } |
---|
789 | |
---|
790 | obj.context.beginPath(); |
---|
791 | |
---|
792 | // Draw the horizontal bars |
---|
793 | context.fillStyle = obj.Get('chart.background.barcolor1'); |
---|
794 | height = (RGraph.GetHeight(obj) - gutterBottom); |
---|
795 | |
---|
796 | for (var i=gutterTop; i < height ; i+=80) { |
---|
797 | obj.context.fillRect(gutterLeft, i, RGraph.GetWidth(obj) - gutterLeft - gutterRight, Math.min(40, RGraph.GetHeight(obj) - gutterBottom - i) ); |
---|
798 | } |
---|
799 | |
---|
800 | context.fillStyle = obj.Get('chart.background.barcolor2'); |
---|
801 | height = (RGraph.GetHeight(obj) - gutterBottom); |
---|
802 | |
---|
803 | for (var i= (40 + gutterTop); i < height; i+=80) { |
---|
804 | obj.context.fillRect(gutterLeft, i, RGraph.GetWidth(obj) - gutterLeft - gutterRight, i + 40 > (RGraph.GetHeight(obj) - gutterBottom) ? RGraph.GetHeight(obj) - (gutterBottom + i) : 40); |
---|
805 | } |
---|
806 | |
---|
807 | context.stroke(); |
---|
808 | |
---|
809 | |
---|
810 | // Draw the background grid |
---|
811 | if (obj.Get('chart.background.grid')) { |
---|
812 | |
---|
813 | // If autofit is specified, use the .numhlines and .numvlines along with the width to work |
---|
814 | // out the hsize and vsize |
---|
815 | if (obj.Get('chart.background.grid.autofit')) { |
---|
816 | |
---|
817 | /** |
---|
818 | * Align the grid to the tickmarks |
---|
819 | */ |
---|
820 | if (obj.Get('chart.background.grid.autofit.align')) { |
---|
821 | |
---|
822 | // Align the horizontal lines |
---|
823 | obj.Set('chart.background.grid.autofit.numhlines', obj.Get('chart.ylabels.count')); |
---|
824 | |
---|
825 | // Align the vertical lines for the line |
---|
826 | if (obj.type == 'line') { |
---|
827 | if (obj.Get('chart.labels') && obj.Get('chart.labels').length) { |
---|
828 | obj.Set('chart.background.grid.autofit.numvlines', obj.Get('chart.labels').length - 1); |
---|
829 | } else { |
---|
830 | obj.Set('chart.background.grid.autofit.numvlines', obj.data[0].length - 1); |
---|
831 | } |
---|
832 | |
---|
833 | // Align the vertical lines for the bar |
---|
834 | } else if (obj.type == 'bar' && obj.Get('chart.labels') && obj.Get('chart.labels').length) { |
---|
835 | obj.Set('chart.background.grid.autofit.numvlines', obj.Get('chart.labels').length); |
---|
836 | } |
---|
837 | } |
---|
838 | |
---|
839 | var vsize = ((RGraph.GetWidth(obj) - gutterLeft - gutterRight)) / obj.Get('chart.background.grid.autofit.numvlines'); |
---|
840 | var hsize = (RGraph.GetHeight(obj) - gutterTop - gutterBottom) / obj.Get('chart.background.grid.autofit.numhlines'); |
---|
841 | |
---|
842 | obj.Set('chart.background.grid.vsize', vsize); |
---|
843 | obj.Set('chart.background.grid.hsize', hsize); |
---|
844 | } |
---|
845 | |
---|
846 | context.beginPath(); |
---|
847 | context.lineWidth = obj.Get('chart.background.grid.width') ? obj.Get('chart.background.grid.width') : 1; |
---|
848 | context.strokeStyle = obj.Get('chart.background.grid.color'); |
---|
849 | |
---|
850 | // Draw the horizontal lines |
---|
851 | if (obj.Get('chart.background.grid.hlines')) { |
---|
852 | height = (RGraph.GetHeight(obj) - gutterBottom) |
---|
853 | for (y=gutterTop; y<height; y+=obj.Get('chart.background.grid.hsize')) { |
---|
854 | context.moveTo(gutterLeft, y); |
---|
855 | context.lineTo(RGraph.GetWidth(obj) - gutterRight, y); |
---|
856 | } |
---|
857 | } |
---|
858 | |
---|
859 | if (obj.Get('chart.background.grid.vlines')) { |
---|
860 | // Draw the vertical lines |
---|
861 | var width = (RGraph.GetWidth(obj) - gutterRight) |
---|
862 | for (x=gutterLeft; x<=width; x+=obj.Get('chart.background.grid.vsize')) { |
---|
863 | context.moveTo(x, gutterTop); |
---|
864 | context.lineTo(x, RGraph.GetHeight(obj) - gutterBottom); |
---|
865 | } |
---|
866 | } |
---|
867 | |
---|
868 | if (obj.Get('chart.background.grid.border')) { |
---|
869 | // Make sure a rectangle, the same colour as the grid goes around the graph |
---|
870 | context.strokeStyle = obj.Get('chart.background.grid.color'); |
---|
871 | context.strokeRect(gutterLeft, gutterTop, RGraph.GetWidth(obj) - gutterLeft - gutterRight, RGraph.GetHeight(obj) - gutterTop - gutterBottom); |
---|
872 | } |
---|
873 | } |
---|
874 | |
---|
875 | context.stroke(); |
---|
876 | |
---|
877 | // If it's a bar and 3D variant, translate |
---|
878 | if (variant == '3d') { |
---|
879 | context.restore(); |
---|
880 | } |
---|
881 | |
---|
882 | // Draw the title if one is set |
---|
883 | if ( typeof(obj.Get('chart.title')) == 'string') { |
---|
884 | |
---|
885 | if (obj.type == 'gantt') { |
---|
886 | gutterTop -= 10; |
---|
887 | } |
---|
888 | |
---|
889 | RGraph.DrawTitle(canvas, |
---|
890 | obj.Get('chart.title'), |
---|
891 | gutterTop, |
---|
892 | null, |
---|
893 | obj.Get('chart.text.size') + 2); |
---|
894 | } |
---|
895 | |
---|
896 | context.stroke(); |
---|
897 | } |
---|
898 | |
---|
899 | |
---|
900 | /** |
---|
901 | * Returns the day number for a particular date. Eg 1st February would be 32 |
---|
902 | * |
---|
903 | * @param object obj A date object |
---|
904 | * @return int The day number of the given date |
---|
905 | */ |
---|
906 | RGraph.GetDays = function (obj) |
---|
907 | { |
---|
908 | var year = obj.getFullYear(); |
---|
909 | var days = obj.getDate(); |
---|
910 | var month = obj.getMonth(); |
---|
911 | |
---|
912 | if (month == 0) return days; |
---|
913 | if (month >= 1) days += 31; |
---|
914 | if (month >= 2) days += 28; |
---|
915 | |
---|
916 | // Leap years. Crude, but if this code is still being used |
---|
917 | // when it stops working, then you have my permission to shoot |
---|
918 | // me. Oh, you won't be able to - I'll be dead... |
---|
919 | if (year >= 2008 && year % 4 == 0) days += 1; |
---|
920 | |
---|
921 | if (month >= 3) days += 31; |
---|
922 | if (month >= 4) days += 30; |
---|
923 | if (month >= 5) days += 31; |
---|
924 | if (month >= 6) days += 30; |
---|
925 | if (month >= 7) days += 31; |
---|
926 | if (month >= 8) days += 31; |
---|
927 | if (month >= 9) days += 30; |
---|
928 | if (month >= 10) days += 31; |
---|
929 | if (month >= 11) days += 30; |
---|
930 | |
---|
931 | return days; |
---|
932 | } |
---|
933 | |
---|
934 | |
---|
935 | |
---|
936 | |
---|
937 | |
---|
938 | |
---|
939 | |
---|
940 | |
---|
941 | |
---|
942 | |
---|
943 | |
---|
944 | |
---|
945 | |
---|
946 | |
---|
947 | |
---|
948 | /** |
---|
949 | * Draws the graph key (used by various graphs) |
---|
950 | * |
---|
951 | * @param object obj The graph object |
---|
952 | * @param array key An array of the texts to be listed in the key |
---|
953 | * @param colors An array of the colors to be used |
---|
954 | */ |
---|
955 | RGraph.DrawKey = function (obj, key, colors) |
---|
956 | { |
---|
957 | var canvas = obj.canvas; |
---|
958 | var context = obj.context; |
---|
959 | context.lineWidth = 1; |
---|
960 | |
---|
961 | context.beginPath(); |
---|
962 | |
---|
963 | /** |
---|
964 | * Key positioned in the gutter |
---|
965 | */ |
---|
966 | var keypos = obj.Get('chart.key.position'); |
---|
967 | var textsize = obj.Get('chart.text.size'); |
---|
968 | |
---|
969 | /** |
---|
970 | * Change the older chart.key.vpos to chart.key.position.y |
---|
971 | */ |
---|
972 | if (typeof(obj.Get('chart.key.vpos')) == 'number') { |
---|
973 | obj.Set('chart.key.position.y', obj.Get('chart.key.vpos') * this.Get('chart.gutter.top') ); |
---|
974 | } |
---|
975 | |
---|
976 | /** |
---|
977 | * Account for null values in the key |
---|
978 | */ |
---|
979 | var key_non_null = []; |
---|
980 | var colors_non_null = []; |
---|
981 | for (var i=0; i<key.length; ++i) { |
---|
982 | if (key[i] != null) { |
---|
983 | colors_non_null.push(colors[i]); |
---|
984 | key_non_null.push(key[i]); |
---|
985 | } |
---|
986 | } |
---|
987 | |
---|
988 | key = key_non_null; |
---|
989 | colors = colors_non_null; |
---|
990 | |
---|
991 | |
---|
992 | |
---|
993 | if (keypos && keypos == 'gutter') { |
---|
994 | |
---|
995 | RGraph.DrawKey_gutter(obj, key, colors); |
---|
996 | |
---|
997 | |
---|
998 | /** |
---|
999 | * In-graph style key |
---|
1000 | */ |
---|
1001 | } else if (keypos && keypos == 'graph') { |
---|
1002 | |
---|
1003 | RGraph.DrawKey_graph(obj, key, colors); |
---|
1004 | |
---|
1005 | } else { |
---|
1006 | alert('[COMMON] (' + obj.id + ') Unknown key position: ' + keypos); |
---|
1007 | } |
---|
1008 | } |
---|
1009 | |
---|
1010 | |
---|
1011 | |
---|
1012 | |
---|
1013 | |
---|
1014 | /** |
---|
1015 | * This does the actual drawing of the key when it's in the graph |
---|
1016 | * |
---|
1017 | * @param object obj The graph object |
---|
1018 | * @param array key The key items to draw |
---|
1019 | * @param array colors An aray of colors that the key will use |
---|
1020 | */ |
---|
1021 | RGraph.DrawKey_graph = function (obj, key, colors) |
---|
1022 | { |
---|
1023 | var canvas = obj.canvas; |
---|
1024 | var context = obj.context; |
---|
1025 | var text_size = typeof(obj.Get('chart.key.text.size')) == 'number' ? obj.Get('chart.key.text.size') : obj.Get('chart.text.size'); |
---|
1026 | var text_font = obj.Get('chart.text.font'); |
---|
1027 | |
---|
1028 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
1029 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
1030 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
1031 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
1032 | |
---|
1033 | var hpos = obj.Get('chart.yaxispos') == 'right' ? gutterLeft + 10 : RGraph.GetWidth(obj) - gutterRight - 10; |
---|
1034 | var vpos = gutterTop + 10; |
---|
1035 | var title = obj.Get('chart.title'); |
---|
1036 | var blob_size = text_size; // The blob of color |
---|
1037 | var hmargin = 8; // This is the size of the gaps between the blob of color and the text |
---|
1038 | var vmargin = 4; // This is the vertical margin of the key |
---|
1039 | var fillstyle = obj.Get('chart.key.background'); |
---|
1040 | var strokestyle = '#333'; |
---|
1041 | var height = 0; |
---|
1042 | var width = 0; |
---|
1043 | |
---|
1044 | |
---|
1045 | obj.coordsKey = []; |
---|
1046 | |
---|
1047 | |
---|
1048 | // Need to set this so that measuring the text works out OK |
---|
1049 | context.font = text_size + 'pt ' + obj.Get('chart.text.font'); |
---|
1050 | |
---|
1051 | // Work out the longest bit of text |
---|
1052 | for (i=0; i<key.length; ++i) { |
---|
1053 | width = Math.max(width, context.measureText(key[i]).width); |
---|
1054 | } |
---|
1055 | |
---|
1056 | width += 5; |
---|
1057 | width += blob_size; |
---|
1058 | width += 5; |
---|
1059 | width += 5; |
---|
1060 | width += 5; |
---|
1061 | |
---|
1062 | /** |
---|
1063 | * Now we know the width, we can move the key left more accurately |
---|
1064 | */ |
---|
1065 | if ( obj.Get('chart.yaxispos') == 'left' |
---|
1066 | || (obj.type == 'pie' && !obj.Get('chart.yaxispos')) |
---|
1067 | || (obj.type == 'hbar' && !obj.Get('chart.yaxispos')) |
---|
1068 | || (obj.type == 'hbar' && obj.Get('chart.yaxispos') == 'center') |
---|
1069 | || (obj.type == 'rscatter' && !obj.Get('chart.yaxispos')) |
---|
1070 | || (obj.type == 'radar' && !obj.Get('chart.yaxispos')) |
---|
1071 | || (obj.type == 'rose' && !obj.Get('chart.yaxispos')) |
---|
1072 | || (obj.type == 'funnel' && !obj.Get('chart.yaxispos')) |
---|
1073 | || (obj.type == 'vprogress' && !obj.Get('chart.yaxispos')) |
---|
1074 | || (obj.type == 'hprogress' && !obj.Get('chart.yaxispos')) |
---|
1075 | ) { |
---|
1076 | |
---|
1077 | hpos -= width; |
---|
1078 | } |
---|
1079 | |
---|
1080 | /** |
---|
1081 | * Horizontal alignment |
---|
1082 | */ |
---|
1083 | if (typeof(obj.Get('chart.key.halign')) == 'string') { |
---|
1084 | if (obj.Get('chart.key.halign') == 'left') { |
---|
1085 | hpos = gutterLeft + 10; |
---|
1086 | } else if (obj.Get('chart.key.halign') == 'right') { |
---|
1087 | hpos = RGraph.GetWidth(obj) - gutterRight - width; |
---|
1088 | } |
---|
1089 | } |
---|
1090 | |
---|
1091 | /** |
---|
1092 | * Specific location coordinates |
---|
1093 | */ |
---|
1094 | if (typeof(obj.Get('chart.key.position.x')) == 'number') { |
---|
1095 | hpos = obj.Get('chart.key.position.x'); |
---|
1096 | } |
---|
1097 | |
---|
1098 | if (typeof(obj.Get('chart.key.position.y')) == 'number') { |
---|
1099 | vpos = obj.Get('chart.key.position.y'); |
---|
1100 | } |
---|
1101 | |
---|
1102 | |
---|
1103 | // Stipulate the shadow for the key box |
---|
1104 | if (obj.Get('chart.key.shadow')) { |
---|
1105 | context.shadowColor = obj.Get('chart.key.shadow.color'); |
---|
1106 | context.shadowBlur = obj.Get('chart.key.shadow.blur'); |
---|
1107 | context.shadowOffsetX = obj.Get('chart.key.shadow.offsetx'); |
---|
1108 | context.shadowOffsetY = obj.Get('chart.key.shadow.offsety'); |
---|
1109 | } |
---|
1110 | |
---|
1111 | |
---|
1112 | |
---|
1113 | |
---|
1114 | // Draw the box that the key resides in |
---|
1115 | context.beginPath(); |
---|
1116 | context.fillStyle = obj.Get('chart.key.background'); |
---|
1117 | context.strokeStyle = 'black'; |
---|
1118 | |
---|
1119 | |
---|
1120 | if (arguments[3] != false) { |
---|
1121 | |
---|
1122 | context.lineWidth = obj.Get('chart.key.linewidth') ? obj.Get('chart.key.linewidth') : 1; |
---|
1123 | |
---|
1124 | // The older square rectangled key |
---|
1125 | if (obj.Get('chart.key.rounded') == true) { |
---|
1126 | context.beginPath(); |
---|
1127 | context.strokeStyle = strokestyle; |
---|
1128 | RGraph.strokedCurvyRect(context, hpos, vpos, width - 5, 5 + ( (text_size + 5) * RGraph.getKeyLength(key)),4); |
---|
1129 | |
---|
1130 | context.stroke(); |
---|
1131 | context.fill(); |
---|
1132 | |
---|
1133 | RGraph.NoShadow(obj); |
---|
1134 | |
---|
1135 | } else { |
---|
1136 | context.strokeRect(hpos, vpos, width - 5, 5 + ( (text_size + 5) * RGraph.getKeyLength(key))); |
---|
1137 | context.fillRect(hpos, vpos, width - 5, 5 + ( (text_size + 5) * RGraph.getKeyLength(key))); |
---|
1138 | } |
---|
1139 | } |
---|
1140 | |
---|
1141 | RGraph.NoShadow(obj); |
---|
1142 | |
---|
1143 | context.beginPath(); |
---|
1144 | |
---|
1145 | // Draw the labels given |
---|
1146 | for (var i=key.length - 1; i>=0; i--) { |
---|
1147 | |
---|
1148 | var j = Number(i) + 1; |
---|
1149 | |
---|
1150 | // Draw the blob of color |
---|
1151 | if (obj.Get('chart.key.color.shape') == 'circle') { |
---|
1152 | context.beginPath(); |
---|
1153 | context.strokeStyle = 'rgba(0,0,0,0)'; |
---|
1154 | context.fillStyle = colors[i]; |
---|
1155 | context.arc(hpos + 5 + (blob_size / 2), vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2), blob_size / 2, 0, 6.26, 0); |
---|
1156 | context.fill(); |
---|
1157 | |
---|
1158 | } else if (obj.Get('chart.key.color.shape') == 'line') { |
---|
1159 | context.beginPath(); |
---|
1160 | context.strokeStyle = colors[i]; |
---|
1161 | context.moveTo(hpos + 5, vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2)); |
---|
1162 | context.lineTo(hpos + blob_size + 5, vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2)); |
---|
1163 | context.stroke(); |
---|
1164 | |
---|
1165 | } else { |
---|
1166 | context.fillStyle = colors[i]; |
---|
1167 | context.fillRect(hpos + 5, vpos + (5 * j) + (text_size * j) - text_size, text_size, text_size + 1); |
---|
1168 | } |
---|
1169 | |
---|
1170 | context.beginPath(); |
---|
1171 | |
---|
1172 | context.fillStyle = 'black'; |
---|
1173 | |
---|
1174 | RGraph.Text(context, |
---|
1175 | text_font, |
---|
1176 | text_size, |
---|
1177 | hpos + blob_size + 5 + 5, |
---|
1178 | vpos + (5 * j) + (text_size * j), |
---|
1179 | key[i]); |
---|
1180 | |
---|
1181 | if (obj.Get('chart.key.interactive')) { |
---|
1182 | |
---|
1183 | var px = hpos + 5; |
---|
1184 | var py = vpos + (5 * j) + (text_size * j) - text_size; |
---|
1185 | var pw = width - 5 - 5 - 5; |
---|
1186 | var ph = text_size; |
---|
1187 | |
---|
1188 | |
---|
1189 | obj.coordsKey.push([px, py, pw, ph]); |
---|
1190 | } |
---|
1191 | |
---|
1192 | } |
---|
1193 | context.fill(); |
---|
1194 | |
---|
1195 | /** |
---|
1196 | * Install the interactivity event handler |
---|
1197 | */ |
---|
1198 | if (obj.Get('chart.key.interactive')) { |
---|
1199 | |
---|
1200 | RGraph.Register(obj); |
---|
1201 | |
---|
1202 | var key_mousemove = function (e) |
---|
1203 | { |
---|
1204 | var obj = e.target.__object__; |
---|
1205 | var canvas = obj.canvas; |
---|
1206 | var context = obj.context; |
---|
1207 | var mouseCoords = RGraph.getMouseXY(e); |
---|
1208 | var mouseX = mouseCoords[0]; |
---|
1209 | var mouseY = mouseCoords[1]; |
---|
1210 | |
---|
1211 | for (var i=0; i<obj.coordsKey.length; ++i) { |
---|
1212 | |
---|
1213 | var px = obj.coordsKey[i][0]; |
---|
1214 | var py = obj.coordsKey[i][1]; |
---|
1215 | var pw = obj.coordsKey[i][2]; |
---|
1216 | var ph = obj.coordsKey[i][3]; |
---|
1217 | |
---|
1218 | if ( mouseX > px && mouseX < (px + pw) && mouseY > py && mouseY < (py + ph) ) { |
---|
1219 | |
---|
1220 | // Necessary? |
---|
1221 | //var index = obj.coordsKey.length - i - 1; |
---|
1222 | |
---|
1223 | canvas.style.cursor = 'pointer'; |
---|
1224 | |
---|
1225 | |
---|
1226 | |
---|
1227 | return; |
---|
1228 | } |
---|
1229 | |
---|
1230 | canvas.style.cursor = 'default'; |
---|
1231 | |
---|
1232 | if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(canvas_onmousemove_func) == 'function') { |
---|
1233 | canvas_onmousemove_func(e); |
---|
1234 | } |
---|
1235 | } |
---|
1236 | } |
---|
1237 | canvas.addEventListener('mousemove', key_mousemove, false); |
---|
1238 | RGraph.AddEventListener(canvas.id, 'mousemove', key_mousemove); |
---|
1239 | |
---|
1240 | |
---|
1241 | var key_click = function (e) |
---|
1242 | { |
---|
1243 | RGraph.Redraw(); |
---|
1244 | |
---|
1245 | var obj = e.target.__object__; |
---|
1246 | var canvas = obj.canvas; |
---|
1247 | var context = obj.context; |
---|
1248 | var mouseCoords = RGraph.getMouseXY(e); |
---|
1249 | var mouseX = mouseCoords[0]; |
---|
1250 | var mouseY = mouseCoords[1]; |
---|
1251 | |
---|
1252 | RGraph.DrawKey(obj, obj.Get('chart.key'), obj.Get('chart.colors')); |
---|
1253 | |
---|
1254 | for (var i=0; i<obj.coordsKey.length; ++i) { |
---|
1255 | |
---|
1256 | var px = obj.coordsKey[i][0]; |
---|
1257 | var py = obj.coordsKey[i][1]; |
---|
1258 | var pw = obj.coordsKey[i][2]; |
---|
1259 | var ph = obj.coordsKey[i][3]; |
---|
1260 | |
---|
1261 | if ( mouseX > px && mouseX < (px + pw) && mouseY > py && mouseY < (py + ph) ) { |
---|
1262 | |
---|
1263 | var index = obj.coordsKey.length - i - 1; |
---|
1264 | |
---|
1265 | // HIGHLIGHT THE LINE HERE |
---|
1266 | context.beginPath(); |
---|
1267 | context.fillStyle = 'rgba(255,255,255,0.9)'; |
---|
1268 | context.fillRect(obj.Get('chart.gutter.left'),obj.Get('chart.gutter.top'),canvas.width - obj.Get('chart.gutter.left') - obj.Get('chart.gutter.right'),canvas.height - obj.Get('chart.gutter.top') - obj.Get('chart.gutter.bottom')); |
---|
1269 | context.fill(); |
---|
1270 | |
---|
1271 | context.beginPath(); |
---|
1272 | context.strokeStyle = obj.Get('chart.colors')[index]; |
---|
1273 | context.lineWidth = obj.Get('chart.linewidth'); |
---|
1274 | for (var j=0; j<obj.coords2[index].length; ++j) { |
---|
1275 | |
---|
1276 | var x = obj.coords2[index][j][0]; |
---|
1277 | var y = obj.coords2[index][j][1]; |
---|
1278 | |
---|
1279 | if (j == 0) { |
---|
1280 | context.moveTo(x, y); |
---|
1281 | } else { |
---|
1282 | context.lineTo(x, y); |
---|
1283 | } |
---|
1284 | } |
---|
1285 | context.stroke(); |
---|
1286 | |
---|
1287 | |
---|
1288 | context.lineWidth = 1; |
---|
1289 | context.beginPath(); |
---|
1290 | context.strokeStyle = 'black'; |
---|
1291 | context.fillStyle = 'white'; |
---|
1292 | |
---|
1293 | RGraph.SetShadow(obj, 'rgba(0,0,0,0.5)', 0,0,10); |
---|
1294 | |
---|
1295 | context.strokeRect(px - 2, py - 2, pw + 4, ph + 4); |
---|
1296 | context.fillRect(px - 2, py - 2, pw + 4, ph + 4); |
---|
1297 | |
---|
1298 | context.stroke(); |
---|
1299 | context.fill(); |
---|
1300 | |
---|
1301 | |
---|
1302 | RGraph.NoShadow(obj); |
---|
1303 | |
---|
1304 | |
---|
1305 | context.beginPath(); |
---|
1306 | context.fillStyle = obj.Get('chart.colors')[index]; |
---|
1307 | context.fillRect(px, py, blob_size, blob_size); |
---|
1308 | context.fill(); |
---|
1309 | |
---|
1310 | context.beginPath(); |
---|
1311 | context.fillStyle = obj.Get('chart.text.color'); |
---|
1312 | |
---|
1313 | RGraph.Text(context, |
---|
1314 | obj.Get('chart.text.font'), |
---|
1315 | obj.Get('chart.text.size'), |
---|
1316 | px + 5 + blob_size, |
---|
1317 | py + ph, |
---|
1318 | obj.Get('chart.key')[obj.Get('chart.key').length - i - 1] |
---|
1319 | ); |
---|
1320 | context.fill(); |
---|
1321 | |
---|
1322 | |
---|
1323 | canvas.style.cursor = 'pointer'; |
---|
1324 | |
---|
1325 | return; |
---|
1326 | } |
---|
1327 | |
---|
1328 | canvas.style.cursor = 'default'; |
---|
1329 | } |
---|
1330 | } |
---|
1331 | canvas.addEventListener('click', key_click, false); |
---|
1332 | RGraph.AddEventListener(canvas.id, 'click', key_click); |
---|
1333 | |
---|
1334 | |
---|
1335 | //var key_window_click = function (e) |
---|
1336 | //{ |
---|
1337 | // RGraph.Redraw(); |
---|
1338 | //} |
---|
1339 | //window.addEventListener('click', key_window_click, false); |
---|
1340 | //RGraph.AddEventListener(canvas.id, 'window_click', key_window_click); |
---|
1341 | } |
---|
1342 | } |
---|
1343 | |
---|
1344 | |
---|
1345 | |
---|
1346 | |
---|
1347 | |
---|
1348 | |
---|
1349 | /** |
---|
1350 | * This does the actual drawing of the key when it's in the gutter |
---|
1351 | * |
---|
1352 | * @param object obj The graph object |
---|
1353 | * @param array key The key items to draw |
---|
1354 | * @param array colors An aray of colors that the key will use |
---|
1355 | */ |
---|
1356 | RGraph.DrawKey_gutter = function (obj, key, colors) |
---|
1357 | { |
---|
1358 | var canvas = obj.canvas; |
---|
1359 | var context = obj.context; |
---|
1360 | var text_size = typeof(obj.Get('chart.key.text.size')) == 'number' ? obj.Get('chart.key.text.size') : obj.Get('chart.text.size'); |
---|
1361 | var text_font = obj.Get('chart.text.font'); |
---|
1362 | |
---|
1363 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
1364 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
1365 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
1366 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
1367 | |
---|
1368 | var hpos = RGraph.GetWidth(obj) / 2; |
---|
1369 | var vpos = (gutterTop / 2) - 5; |
---|
1370 | var title = obj.Get('chart.title'); |
---|
1371 | var blob_size = text_size; // The blob of color |
---|
1372 | var hmargin = 8; // This is the size of the gaps between the blob of color and the text |
---|
1373 | var vmargin = 4; // This is the vertical margin of the key |
---|
1374 | var fillstyle = obj.Get('chart.key.background'); |
---|
1375 | var strokestyle = 'black'; |
---|
1376 | var length = 0; |
---|
1377 | |
---|
1378 | |
---|
1379 | |
---|
1380 | // Need to work out the length of the key first |
---|
1381 | context.font = text_size + 'pt ' + text_font; |
---|
1382 | for (i=0; i<key.length; ++i) { |
---|
1383 | length += hmargin; |
---|
1384 | length += blob_size; |
---|
1385 | length += hmargin; |
---|
1386 | length += context.measureText(key[i]).width; |
---|
1387 | } |
---|
1388 | length += hmargin; |
---|
1389 | |
---|
1390 | |
---|
1391 | |
---|
1392 | |
---|
1393 | /** |
---|
1394 | * Work out hpos since in the Pie it isn't necessarily dead center |
---|
1395 | */ |
---|
1396 | if (obj.type == 'pie') { |
---|
1397 | if (obj.Get('chart.align') == 'left') { |
---|
1398 | var hpos = obj.radius + gutterLeft; |
---|
1399 | |
---|
1400 | } else if (obj.Get('chart.align') == 'right') { |
---|
1401 | var hpos = obj.canvas.width - obj.radius - gutterRight; |
---|
1402 | |
---|
1403 | } else { |
---|
1404 | hpos = canvas.width / 2; |
---|
1405 | } |
---|
1406 | } |
---|
1407 | |
---|
1408 | |
---|
1409 | |
---|
1410 | |
---|
1411 | |
---|
1412 | /** |
---|
1413 | * This makes the key centered |
---|
1414 | */ |
---|
1415 | hpos -= (length / 2); |
---|
1416 | |
---|
1417 | |
---|
1418 | /** |
---|
1419 | * Override the horizontal/vertical positioning |
---|
1420 | */ |
---|
1421 | if (typeof(obj.Get('chart.key.position.x')) == 'number') { |
---|
1422 | hpos = obj.Get('chart.key.position.x'); |
---|
1423 | } |
---|
1424 | if (typeof(obj.Get('chart.key.position.y')) == 'number') { |
---|
1425 | vpos = obj.Get('chart.key.position.y'); |
---|
1426 | } |
---|
1427 | |
---|
1428 | |
---|
1429 | |
---|
1430 | /** |
---|
1431 | * Draw the box that the key sits in |
---|
1432 | */ |
---|
1433 | if (obj.Get('chart.key.position.gutter.boxed')) { |
---|
1434 | |
---|
1435 | if (obj.Get('chart.key.shadow')) { |
---|
1436 | context.shadowColor = obj.Get('chart.key.shadow.color'); |
---|
1437 | context.shadowBlur = obj.Get('chart.key.shadow.blur'); |
---|
1438 | context.shadowOffsetX = obj.Get('chart.key.shadow.offsetx'); |
---|
1439 | context.shadowOffsetY = obj.Get('chart.key.shadow.offsety'); |
---|
1440 | } |
---|
1441 | |
---|
1442 | |
---|
1443 | context.beginPath(); |
---|
1444 | context.fillStyle = fillstyle; |
---|
1445 | context.strokeStyle = strokestyle; |
---|
1446 | |
---|
1447 | if (obj.Get('chart.key.rounded')) { |
---|
1448 | RGraph.strokedCurvyRect(context, hpos, vpos - vmargin, length, text_size + vmargin + vmargin) |
---|
1449 | // Odd... RGraph.filledCurvyRect(context, hpos, vpos - vmargin, length, text_size + vmargin + vmargin); |
---|
1450 | } else { |
---|
1451 | context.strokeRect(hpos, vpos - vmargin, length, text_size + vmargin + vmargin); |
---|
1452 | context.fillRect(hpos, vpos - vmargin, length, text_size + vmargin + vmargin); |
---|
1453 | } |
---|
1454 | |
---|
1455 | context.stroke(); |
---|
1456 | context.fill(); |
---|
1457 | |
---|
1458 | |
---|
1459 | RGraph.NoShadow(obj); |
---|
1460 | } |
---|
1461 | |
---|
1462 | |
---|
1463 | /** |
---|
1464 | * Draw the blobs of color and the text |
---|
1465 | */ |
---|
1466 | for (var i=0, pos=hpos; i<key.length; ++i) { |
---|
1467 | pos += hmargin; |
---|
1468 | |
---|
1469 | // Draw the blob of color - line |
---|
1470 | if (obj.Get('chart.key.color.shape') =='line') { |
---|
1471 | |
---|
1472 | context.beginPath(); |
---|
1473 | context.strokeStyle = colors[i]; |
---|
1474 | context.moveTo(pos, vpos + (blob_size / 2)); |
---|
1475 | context.lineTo(pos + blob_size, vpos + (blob_size / 2)); |
---|
1476 | context.stroke(); |
---|
1477 | |
---|
1478 | // Circle |
---|
1479 | } else if (obj.Get('chart.key.color.shape') == 'circle') { |
---|
1480 | |
---|
1481 | context.beginPath(); |
---|
1482 | context.fillStyle = colors[i]; |
---|
1483 | context.moveTo(pos, vpos + (blob_size / 2)); |
---|
1484 | context.arc(pos + (blob_size / 2), vpos + (blob_size / 2), (blob_size / 2), 0, 6.28, 0); |
---|
1485 | context.fill(); |
---|
1486 | |
---|
1487 | |
---|
1488 | } else { |
---|
1489 | |
---|
1490 | context.beginPath(); |
---|
1491 | context.fillStyle = colors[i]; |
---|
1492 | context.fillRect(pos, vpos, blob_size, blob_size); |
---|
1493 | context.fill(); |
---|
1494 | } |
---|
1495 | |
---|
1496 | pos += blob_size; |
---|
1497 | |
---|
1498 | pos += hmargin; |
---|
1499 | |
---|
1500 | context.beginPath(); |
---|
1501 | context.fillStyle = 'black'; |
---|
1502 | RGraph.Text(context, text_font, text_size, pos, vpos + text_size - 1, key[i]); |
---|
1503 | context.fill(); |
---|
1504 | pos += context.measureText(key[i]).width; |
---|
1505 | } |
---|
1506 | } |
---|
1507 | |
---|
1508 | |
---|
1509 | /** |
---|
1510 | * Returns the key length, but accounts for null values |
---|
1511 | * |
---|
1512 | * @param array key The key elements |
---|
1513 | */ |
---|
1514 | RGraph.getKeyLength = function (key) |
---|
1515 | { |
---|
1516 | var len = 0; |
---|
1517 | |
---|
1518 | for (var i=0; i<key.length; ++i) { |
---|
1519 | if (key[i] != null) { |
---|
1520 | ++len; |
---|
1521 | } |
---|
1522 | } |
---|
1523 | |
---|
1524 | return len; |
---|
1525 | } |
---|
1526 | |
---|
1527 | |
---|
1528 | |
---|
1529 | |
---|
1530 | |
---|
1531 | |
---|
1532 | /** |
---|
1533 | * A shortcut for RGraph.pr() |
---|
1534 | */ |
---|
1535 | function pd(variable) |
---|
1536 | { |
---|
1537 | RGraph.pr(variable); |
---|
1538 | } |
---|
1539 | |
---|
1540 | function p(variable) |
---|
1541 | { |
---|
1542 | RGraph.pr(variable); |
---|
1543 | } |
---|
1544 | |
---|
1545 | /** |
---|
1546 | * A shortcut for console.log - as used by Firebug and Chromes console |
---|
1547 | */ |
---|
1548 | function cl (variable) |
---|
1549 | { |
---|
1550 | return console.log(variable); |
---|
1551 | } |
---|
1552 | |
---|
1553 | |
---|
1554 | /** |
---|
1555 | * Makes a clone of an object |
---|
1556 | * |
---|
1557 | * @param obj val The object to clone |
---|
1558 | */ |
---|
1559 | RGraph.array_clone = function (obj) |
---|
1560 | { |
---|
1561 | if(obj == null || typeof(obj) != 'object') { |
---|
1562 | return obj; |
---|
1563 | } |
---|
1564 | |
---|
1565 | var temp = []; |
---|
1566 | //var temp = new obj.constructor(); |
---|
1567 | |
---|
1568 | for(var i=0;i<obj.length; ++i) { |
---|
1569 | temp[i] = RGraph.array_clone(obj[i]); |
---|
1570 | } |
---|
1571 | |
---|
1572 | return temp; |
---|
1573 | } |
---|
1574 | |
---|
1575 | |
---|
1576 | /** |
---|
1577 | * This function reverses an array |
---|
1578 | */ |
---|
1579 | RGraph.array_reverse = function (arr) |
---|
1580 | { |
---|
1581 | var newarr = []; |
---|
1582 | |
---|
1583 | for (var i=arr.length - 1; i>=0; i--) { |
---|
1584 | newarr.push(arr[i]); |
---|
1585 | } |
---|
1586 | |
---|
1587 | return newarr; |
---|
1588 | } |
---|
1589 | |
---|
1590 | |
---|
1591 | /** |
---|
1592 | * Formats a number with thousand seperators so it's easier to read |
---|
1593 | * |
---|
1594 | * @param integer num The number to format |
---|
1595 | * @param string The (optional) string to prepend to the string |
---|
1596 | * @param string The (optional) string to ap |
---|
1597 | * pend to the string |
---|
1598 | * @return string The formatted number |
---|
1599 | */ |
---|
1600 | RGraph.number_format = function (obj, num) |
---|
1601 | { |
---|
1602 | var i; |
---|
1603 | var prepend = arguments[2] ? String(arguments[2]) : ''; |
---|
1604 | var append = arguments[3] ? String(arguments[3]) : ''; |
---|
1605 | var output = ''; |
---|
1606 | var decimal = ''; |
---|
1607 | var decimal_seperator = obj.Get('chart.scale.point') ? obj.Get('chart.scale.point') : '.'; |
---|
1608 | var thousand_seperator = obj.Get('chart.scale.thousand') ? obj.Get('chart.scale.thousand') : ','; |
---|
1609 | RegExp.$1 = ''; |
---|
1610 | var i,j; |
---|
1611 | |
---|
1612 | if (typeof(obj.Get('chart.scale.formatter')) == 'function') { |
---|
1613 | return obj.Get('chart.scale.formatter')(obj, num); |
---|
1614 | } |
---|
1615 | |
---|
1616 | // Ignore the preformatted version of "1e-2" |
---|
1617 | if (String(num).indexOf('e') > 0) { |
---|
1618 | return String(prepend + String(num) + append); |
---|
1619 | } |
---|
1620 | |
---|
1621 | // We need then number as a string |
---|
1622 | num = String(num); |
---|
1623 | |
---|
1624 | // Take off the decimal part - we re-append it later |
---|
1625 | if (num.indexOf('.') > 0) { |
---|
1626 | num = num.replace(/\.(.*)/, ''); |
---|
1627 | decimal = RegExp.$1; |
---|
1628 | } |
---|
1629 | |
---|
1630 | // Thousand seperator |
---|
1631 | //var seperator = arguments[1] ? String(arguments[1]) : ','; |
---|
1632 | var seperator = thousand_seperator; |
---|
1633 | |
---|
1634 | /** |
---|
1635 | * Work backwards adding the thousand seperators |
---|
1636 | */ |
---|
1637 | var foundPoint; |
---|
1638 | for (i=(num.length - 1),j=0; i>=0; j++,i--) { |
---|
1639 | var character = num.charAt(i); |
---|
1640 | |
---|
1641 | if ( j % 3 == 0 && j != 0) { |
---|
1642 | output += seperator; |
---|
1643 | } |
---|
1644 | |
---|
1645 | /** |
---|
1646 | * Build the output |
---|
1647 | */ |
---|
1648 | output += character; |
---|
1649 | } |
---|
1650 | |
---|
1651 | /** |
---|
1652 | * Now need to reverse the string |
---|
1653 | */ |
---|
1654 | var rev = output; |
---|
1655 | output = ''; |
---|
1656 | for (i=(rev.length - 1); i>=0; i--) { |
---|
1657 | output += rev.charAt(i); |
---|
1658 | } |
---|
1659 | |
---|
1660 | // Tidy up |
---|
1661 | output = output.replace(/^-,/, '-'); |
---|
1662 | |
---|
1663 | // Reappend the decimal |
---|
1664 | if (decimal.length) { |
---|
1665 | output = output + decimal_seperator + decimal; |
---|
1666 | decimal = ''; |
---|
1667 | RegExp.$1 = ''; |
---|
1668 | } |
---|
1669 | |
---|
1670 | // Minor bugette |
---|
1671 | if (output.charAt(0) == '-') { |
---|
1672 | output = output.replace(/-/, ''); |
---|
1673 | prepend = '-' + prepend; |
---|
1674 | } |
---|
1675 | |
---|
1676 | return prepend + output + append; |
---|
1677 | } |
---|
1678 | |
---|
1679 | |
---|
1680 | /** |
---|
1681 | * Draws horizontal coloured bars on something like the bar, line or scatter |
---|
1682 | */ |
---|
1683 | RGraph.DrawBars = function (obj) |
---|
1684 | { |
---|
1685 | var hbars = obj.Get('chart.background.hbars'); |
---|
1686 | |
---|
1687 | /** |
---|
1688 | * Draws a horizontal bar |
---|
1689 | */ |
---|
1690 | obj.context.beginPath(); |
---|
1691 | |
---|
1692 | for (i=0; i<hbars.length; ++i) { |
---|
1693 | |
---|
1694 | // If null is specified as the "height", set it to the upper max value |
---|
1695 | if (hbars[i][1] == null) { |
---|
1696 | hbars[i][1] = obj.max; |
---|
1697 | |
---|
1698 | // If the first index plus the second index is greater than the max value, adjust accordingly |
---|
1699 | } else if (hbars[i][0] + hbars[i][1] > obj.max) { |
---|
1700 | hbars[i][1] = obj.max - hbars[i][0]; |
---|
1701 | } |
---|
1702 | |
---|
1703 | |
---|
1704 | // If height is negative, and the abs() value is greater than .max, use a negative max instead |
---|
1705 | if (Math.abs(hbars[i][1]) > obj.max) { |
---|
1706 | hbars[i][1] = -1 * obj.max; |
---|
1707 | } |
---|
1708 | |
---|
1709 | |
---|
1710 | // If start point is greater than max, change it to max |
---|
1711 | if (Math.abs(hbars[i][0]) > obj.max) { |
---|
1712 | hbars[i][0] = obj.max; |
---|
1713 | } |
---|
1714 | |
---|
1715 | // If start point plus height is less than negative max, use the negative max plus the start point |
---|
1716 | if (hbars[i][0] + hbars[i][1] < (-1 * obj.max) ) { |
---|
1717 | hbars[i][1] = -1 * (obj.max + hbars[i][0]); |
---|
1718 | } |
---|
1719 | |
---|
1720 | // If the X axis is at the bottom, and a negative max is given, warn the user |
---|
1721 | if (obj.Get('chart.xaxispos') == 'bottom' && (hbars[i][0] < 0 || (hbars[i][1] + hbars[i][1] < 0)) ) { |
---|
1722 | alert('[' + obj.type.toUpperCase() + ' (ID: ' + obj.id + ') BACKGROUND HBARS] You have a negative value in one of your background hbars values, whilst the X axis is in the center'); |
---|
1723 | } |
---|
1724 | |
---|
1725 | var ystart = (obj.grapharea - ((hbars[i][0] / obj.max) * obj.grapharea)); |
---|
1726 | var height = (Math.min(hbars[i][1], obj.max - hbars[i][0]) / obj.max) * obj.grapharea; |
---|
1727 | |
---|
1728 | // Account for the X axis being in the center |
---|
1729 | if (obj.Get('chart.xaxispos') == 'center') { |
---|
1730 | ystart /= 2; |
---|
1731 | height /= 2; |
---|
1732 | } |
---|
1733 | |
---|
1734 | ystart += obj.Get('chart.gutter.top') |
---|
1735 | |
---|
1736 | var x = obj.Get('chart.gutter.left'); |
---|
1737 | var y = ystart - height; |
---|
1738 | var w = obj.canvas.width - obj.Get('chart.gutter.left') - obj.Get('chart.gutter.right'); |
---|
1739 | var h = height; |
---|
1740 | |
---|
1741 | // Accommodate Opera :-/ |
---|
1742 | if (navigator.userAgent.indexOf('Opera') != -1 && obj.Get('chart.xaxispos') == 'center' && h < 0) { |
---|
1743 | h *= -1; |
---|
1744 | y = y - h; |
---|
1745 | } |
---|
1746 | |
---|
1747 | /** |
---|
1748 | * Account for X axis at the top |
---|
1749 | */ |
---|
1750 | if (obj.Get('chart.xaxispos') == 'top') { |
---|
1751 | y = obj.canvas.height - y; |
---|
1752 | h *= -1; |
---|
1753 | } |
---|
1754 | |
---|
1755 | obj.context.fillStyle = hbars[i][2]; |
---|
1756 | obj.context.fillRect(x, y, w, h); |
---|
1757 | } |
---|
1758 | |
---|
1759 | obj.context.fill(); |
---|
1760 | } |
---|
1761 | |
---|
1762 | |
---|
1763 | /** |
---|
1764 | * Draws in-graph labels. |
---|
1765 | * |
---|
1766 | * @param object obj The graph object |
---|
1767 | */ |
---|
1768 | RGraph.DrawInGraphLabels = function (obj) |
---|
1769 | { |
---|
1770 | var canvas = obj.canvas; |
---|
1771 | var context = obj.context; |
---|
1772 | var labels = obj.Get('chart.labels.ingraph'); |
---|
1773 | var labels_processed = []; |
---|
1774 | |
---|
1775 | // Defaults |
---|
1776 | var fgcolor = 'black'; |
---|
1777 | var bgcolor = 'white'; |
---|
1778 | var direction = 1; |
---|
1779 | |
---|
1780 | if (!labels) { |
---|
1781 | return; |
---|
1782 | } |
---|
1783 | |
---|
1784 | /** |
---|
1785 | * Preprocess the labels array. Numbers are expanded |
---|
1786 | */ |
---|
1787 | for (var i=0; i<labels.length; ++i) { |
---|
1788 | if (typeof(labels[i]) == 'number') { |
---|
1789 | for (var j=0; j<labels[i]; ++j) { |
---|
1790 | labels_processed.push(null); |
---|
1791 | } |
---|
1792 | } else if (typeof(labels[i]) == 'string' || typeof(labels[i]) == 'object') { |
---|
1793 | labels_processed.push(labels[i]); |
---|
1794 | |
---|
1795 | } else { |
---|
1796 | labels_processed.push(''); |
---|
1797 | } |
---|
1798 | } |
---|
1799 | |
---|
1800 | /** |
---|
1801 | * Turn off any shadow |
---|
1802 | */ |
---|
1803 | RGraph.NoShadow(obj); |
---|
1804 | |
---|
1805 | if (labels_processed && labels_processed.length > 0) { |
---|
1806 | |
---|
1807 | for (var i=0; i<labels_processed.length; ++i) { |
---|
1808 | if (labels_processed[i]) { |
---|
1809 | var coords = obj.coords[i]; |
---|
1810 | |
---|
1811 | if (coords && coords.length > 0) { |
---|
1812 | var x = (obj.type == 'bar' ? coords[0] + (coords[2] / 2) : coords[0]); |
---|
1813 | var y = (obj.type == 'bar' ? coords[1] + (coords[3] / 2) : coords[1]); |
---|
1814 | var length = typeof(labels_processed[i][4]) == 'number' ? labels_processed[i][4] : 25; |
---|
1815 | |
---|
1816 | |
---|
1817 | context.beginPath(); |
---|
1818 | context.fillStyle = 'black'; |
---|
1819 | context.strokeStyle = 'black'; |
---|
1820 | |
---|
1821 | |
---|
1822 | if (obj.type == 'bar') { |
---|
1823 | |
---|
1824 | /** |
---|
1825 | * X axis at the top |
---|
1826 | */ |
---|
1827 | if (obj.Get('chart.xaxispos') == 'top') { |
---|
1828 | length *= -1; |
---|
1829 | } |
---|
1830 | |
---|
1831 | if (obj.Get('chart.variant') == 'dot') { |
---|
1832 | context.moveTo(x, obj.coords[i][1] - 5); |
---|
1833 | context.lineTo(x, obj.coords[i][1] - 5 - length); |
---|
1834 | |
---|
1835 | var text_x = x; |
---|
1836 | var text_y = obj.coords[i][1] - 5 - length; |
---|
1837 | |
---|
1838 | } else if (obj.Get('chart.variant') == 'arrow') { |
---|
1839 | context.moveTo(x, obj.coords[i][1] - 5); |
---|
1840 | context.lineTo(x, obj.coords[i][1] - 5 - length); |
---|
1841 | |
---|
1842 | var text_x = x; |
---|
1843 | var text_y = obj.coords[i][1] - 5 - length; |
---|
1844 | |
---|
1845 | } else { |
---|
1846 | |
---|
1847 | context.arc(x, y, 2.5, 0, 6.28, 0); |
---|
1848 | context.moveTo(x, y); |
---|
1849 | context.lineTo(x, y - length); |
---|
1850 | |
---|
1851 | var text_x = x; |
---|
1852 | var text_y = y - length; |
---|
1853 | } |
---|
1854 | |
---|
1855 | context.stroke(); |
---|
1856 | context.fill(); |
---|
1857 | |
---|
1858 | |
---|
1859 | } else if (obj.type == 'line') { |
---|
1860 | |
---|
1861 | if ( |
---|
1862 | typeof(labels_processed[i]) == 'object' && |
---|
1863 | typeof(labels_processed[i][3]) == 'number' && |
---|
1864 | labels_processed[i][3] == -1 |
---|
1865 | ) { |
---|
1866 | |
---|
1867 | context.moveTo(x, y + 5); |
---|
1868 | context.lineTo(x, y + 5 + length); |
---|
1869 | |
---|
1870 | context.stroke(); |
---|
1871 | context.beginPath(); |
---|
1872 | |
---|
1873 | // This draws the arrow |
---|
1874 | context.moveTo(x, y + 5); |
---|
1875 | context.lineTo(x - 3, y + 10); |
---|
1876 | context.lineTo(x + 3, y + 10); |
---|
1877 | context.closePath(); |
---|
1878 | |
---|
1879 | var text_x = x; |
---|
1880 | var text_y = y + 5 + length; |
---|
1881 | |
---|
1882 | } else { |
---|
1883 | |
---|
1884 | var text_x = x; |
---|
1885 | var text_y = y - 5 - length; |
---|
1886 | |
---|
1887 | context.moveTo(x, y - 5); |
---|
1888 | context.lineTo(x, y - 5 - length); |
---|
1889 | |
---|
1890 | context.stroke(); |
---|
1891 | context.beginPath(); |
---|
1892 | |
---|
1893 | // This draws the arrow |
---|
1894 | context.moveTo(x, y - 5); |
---|
1895 | context.lineTo(x - 3, y - 10); |
---|
1896 | context.lineTo(x + 3, y - 10); |
---|
1897 | context.closePath(); |
---|
1898 | } |
---|
1899 | |
---|
1900 | context.fill(); |
---|
1901 | } |
---|
1902 | |
---|
1903 | // Taken out on the 10th Nov 2010 - unnecessary |
---|
1904 | //var width = context.measureText(labels[i]).width; |
---|
1905 | |
---|
1906 | context.beginPath(); |
---|
1907 | |
---|
1908 | // Fore ground color |
---|
1909 | context.fillStyle = (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][1]) == 'string') ? labels_processed[i][1] : 'black'; |
---|
1910 | |
---|
1911 | RGraph.Text(context, |
---|
1912 | obj.Get('chart.text.font'), |
---|
1913 | obj.Get('chart.text.size'), |
---|
1914 | text_x, |
---|
1915 | text_y, |
---|
1916 | (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][0]) == 'string') ? labels_processed[i][0] : labels_processed[i], |
---|
1917 | 'bottom', |
---|
1918 | 'center', |
---|
1919 | true, |
---|
1920 | null, |
---|
1921 | (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][2]) == 'string') ? labels_processed[i][2] : 'white'); |
---|
1922 | context.fill(); |
---|
1923 | } |
---|
1924 | } |
---|
1925 | } |
---|
1926 | } |
---|
1927 | } |
---|
1928 | |
---|
1929 | |
---|
1930 | /** |
---|
1931 | * This function "fills in" key missing properties that various implementations lack |
---|
1932 | * |
---|
1933 | * @param object e The event object |
---|
1934 | */ |
---|
1935 | RGraph.FixEventObject = function (e) |
---|
1936 | { |
---|
1937 | if (RGraph.isIE8()) { |
---|
1938 | |
---|
1939 | var e = event; |
---|
1940 | |
---|
1941 | e.pageX = (event.clientX + document.body.scrollLeft); |
---|
1942 | e.pageY = (event.clientY + document.body.scrollTop); |
---|
1943 | e.target = event.srcElement; |
---|
1944 | |
---|
1945 | if (!document.body.scrollTop && document.documentElement.scrollTop) { |
---|
1946 | e.pageX += parseInt(document.documentElement.scrollLeft); |
---|
1947 | e.pageY += parseInt(document.documentElement.scrollTop); |
---|
1948 | } |
---|
1949 | } |
---|
1950 | |
---|
1951 | // This is mainly for FF which doesn't provide offsetX |
---|
1952 | if (typeof(e.offsetX) == 'undefined' && typeof(e.offsetY) == 'undefined') { |
---|
1953 | var coords = RGraph.getMouseXY(e); |
---|
1954 | e.offsetX = coords[0]; |
---|
1955 | e.offsetY = coords[1]; |
---|
1956 | } |
---|
1957 | |
---|
1958 | // Any browser that doesn't implement stopPropagation() (MSIE) |
---|
1959 | if (!e.stopPropagation) { |
---|
1960 | e.stopPropagation = function () {window.event.cancelBubble = true;} |
---|
1961 | } |
---|
1962 | |
---|
1963 | return e; |
---|
1964 | } |
---|
1965 | |
---|
1966 | |
---|
1967 | /** |
---|
1968 | * Draw crosshairs if enabled |
---|
1969 | * |
---|
1970 | * @param object obj The graph object (from which we can get the context and canvas as required) |
---|
1971 | */ |
---|
1972 | RGraph.DrawCrosshairs = function (obj) |
---|
1973 | { |
---|
1974 | if (obj.Get('chart.crosshairs')) { |
---|
1975 | var canvas = obj.canvas; |
---|
1976 | var context = obj.context; |
---|
1977 | |
---|
1978 | // 5th November 2010 - removed now that tooltips are DOM2 based. |
---|
1979 | //if (obj.Get('chart.tooltips') && obj.Get('chart.tooltips').length > 0) { |
---|
1980 | //alert('[' + obj.type.toUpperCase() + '] Sorry - you cannot have crosshairs enabled with tooltips! Turning off crosshairs...'); |
---|
1981 | //obj.Set('chart.crosshairs', false); |
---|
1982 | //return; |
---|
1983 | //} |
---|
1984 | |
---|
1985 | canvas.onmousemove = function (e) |
---|
1986 | { |
---|
1987 | var e = RGraph.FixEventObject(e); |
---|
1988 | var canvas = obj.canvas; |
---|
1989 | var context = obj.context; |
---|
1990 | var width = canvas.width; |
---|
1991 | var height = canvas.height; |
---|
1992 | var adjustments = obj.Get('chart.tooltips.coords.adjust'); |
---|
1993 | |
---|
1994 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
1995 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
1996 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
1997 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
1998 | |
---|
1999 | var mouseCoords = RGraph.getMouseXY(e); |
---|
2000 | var x = mouseCoords[0]; |
---|
2001 | var y = mouseCoords[1]; |
---|
2002 | |
---|
2003 | if (typeof(adjustments) == 'object' && adjustments[0] && adjustments[1]) { |
---|
2004 | x = x - adjustments[0]; |
---|
2005 | y = y - adjustments[1]; |
---|
2006 | } |
---|
2007 | |
---|
2008 | RGraph.Clear(canvas); |
---|
2009 | obj.Draw(); |
---|
2010 | |
---|
2011 | if ( x >= gutterLeft |
---|
2012 | && y >= gutterTop |
---|
2013 | && x <= (width - gutterRight) |
---|
2014 | && y <= (height - gutterBottom) |
---|
2015 | ) { |
---|
2016 | |
---|
2017 | var linewidth = obj.Get('chart.crosshairs.linewidth'); |
---|
2018 | context.lineWidth = linewidth ? linewidth : 1; |
---|
2019 | |
---|
2020 | context.beginPath(); |
---|
2021 | context.strokeStyle = obj.Get('chart.crosshairs.color'); |
---|
2022 | |
---|
2023 | // Draw a top vertical line |
---|
2024 | context.moveTo(x, gutterTop); |
---|
2025 | context.lineTo(x, height - gutterBottom); |
---|
2026 | |
---|
2027 | // Draw a horizontal line |
---|
2028 | context.moveTo(gutterLeft, y); |
---|
2029 | context.lineTo(width - gutterRight, y); |
---|
2030 | |
---|
2031 | context.stroke(); |
---|
2032 | |
---|
2033 | /** |
---|
2034 | * Need to show the coords? |
---|
2035 | */ |
---|
2036 | if (obj.Get('chart.crosshairs.coords')) { |
---|
2037 | if (obj.type == 'scatter') { |
---|
2038 | |
---|
2039 | var xCoord = (((x - obj.Get('chart.gutter.left')) / (obj.canvas.width - gutterLeft - gutterRight)) * (obj.Get('chart.xmax') - obj.Get('chart.xmin'))) + obj.Get('chart.xmin'); |
---|
2040 | xCoord = xCoord.toFixed(obj.Get('chart.scale.decimals')); |
---|
2041 | var yCoord = obj.max - (((y - obj.Get('chart.gutter.top')) / (obj.canvas.height - gutterTop - gutterBottom)) * obj.max); |
---|
2042 | |
---|
2043 | if (obj.type == 'scatter' && obj.Get('chart.xaxispos') == 'center') { |
---|
2044 | yCoord = (yCoord - (obj.max / 2)) * 2; |
---|
2045 | } |
---|
2046 | |
---|
2047 | yCoord = yCoord.toFixed(obj.Get('chart.scale.decimals')); |
---|
2048 | var div = RGraph.Registry.Get('chart.coordinates.coords.div'); |
---|
2049 | var mouseCoords = RGraph.getMouseXY(e); |
---|
2050 | var canvasXY = RGraph.getCanvasXY(canvas); |
---|
2051 | |
---|
2052 | if (!div) { |
---|
2053 | |
---|
2054 | div = document.createElement('DIV'); |
---|
2055 | div.__object__ = obj; |
---|
2056 | div.style.position = 'absolute'; |
---|
2057 | div.style.backgroundColor = 'white'; |
---|
2058 | div.style.border = '1px solid black'; |
---|
2059 | div.style.fontFamily = 'Arial, Verdana, sans-serif'; |
---|
2060 | div.style.fontSize = '10pt' |
---|
2061 | div.style.padding = '2px'; |
---|
2062 | div.style.opacity = 1; |
---|
2063 | div.style.WebkitBorderRadius = '3px'; |
---|
2064 | div.style.borderRadius = '3px'; |
---|
2065 | div.style.MozBorderRadius = '3px'; |
---|
2066 | document.body.appendChild(div); |
---|
2067 | |
---|
2068 | RGraph.Registry.Set('chart.coordinates.coords.div', div); |
---|
2069 | } |
---|
2070 | |
---|
2071 | // Convert the X/Y pixel coords to correspond to the scale |
---|
2072 | |
---|
2073 | div.style.opacity = 1; |
---|
2074 | div.style.display = 'inline'; |
---|
2075 | |
---|
2076 | if (!obj.Get('chart.crosshairs.coords.fixed')) { |
---|
2077 | div.style.left = Math.max(2, (e.pageX - div.offsetWidth - 3)) + 'px'; |
---|
2078 | div.style.top = Math.max(2, (e.pageY - div.offsetHeight - 3)) + 'px'; |
---|
2079 | } else { |
---|
2080 | div.style.left = canvasXY[0] + gutterLeft + 3 + 'px'; |
---|
2081 | div.style.top = canvasXY[1] + gutterTop + 3 + 'px'; |
---|
2082 | } |
---|
2083 | |
---|
2084 | div.innerHTML = '<span style="color: #666">' + obj.Get('chart.crosshairs.coords.labels.x') + ':</span> ' + xCoord + '<br><span style="color: #666">' + obj.Get('chart.crosshairs.coords.labels.y') + ':</span> ' + yCoord; |
---|
2085 | |
---|
2086 | canvas.addEventListener('mouseout', RGraph.HideCrosshairCoords, false); |
---|
2087 | |
---|
2088 | } else { |
---|
2089 | alert('[RGRAPH] Showing crosshair coordinates is only supported on the Scatter chart'); |
---|
2090 | } |
---|
2091 | } |
---|
2092 | } else { |
---|
2093 | RGraph.HideCrosshairCoords(); |
---|
2094 | } |
---|
2095 | } |
---|
2096 | } |
---|
2097 | } |
---|
2098 | |
---|
2099 | /** |
---|
2100 | * Thisz function hides the crosshairs coordinates |
---|
2101 | */ |
---|
2102 | RGraph.HideCrosshairCoords = function () |
---|
2103 | { |
---|
2104 | var div = RGraph.Registry.Get('chart.coordinates.coords.div'); |
---|
2105 | |
---|
2106 | if ( div |
---|
2107 | && div.style.opacity == 1 |
---|
2108 | && div.__object__.Get('chart.crosshairs.coords.fadeout') |
---|
2109 | ) { |
---|
2110 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.9;}, 50); |
---|
2111 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.8;}, 100); |
---|
2112 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.7;}, 150); |
---|
2113 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.6;}, 200); |
---|
2114 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.5;}, 250); |
---|
2115 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.4;}, 300); |
---|
2116 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.3;}, 350); |
---|
2117 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.2;}, 400); |
---|
2118 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.1;}, 450); |
---|
2119 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0;}, 500); |
---|
2120 | setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.display = 'none';}, 550); |
---|
2121 | } |
---|
2122 | } |
---|
2123 | |
---|
2124 | |
---|
2125 | /** |
---|
2126 | * Trims the right hand side of a string. Removes SPACE, TAB |
---|
2127 | * CR and LF. |
---|
2128 | * |
---|
2129 | * @param string str The string to trim |
---|
2130 | */ |
---|
2131 | RGraph.rtrim = function (str) |
---|
2132 | { |
---|
2133 | return str.replace(/( |\n|\r|\t)+$/, ''); |
---|
2134 | } |
---|
2135 | |
---|
2136 | |
---|
2137 | /** |
---|
2138 | * Draws the3D axes/background |
---|
2139 | */ |
---|
2140 | RGraph.Draw3DAxes = function (obj) |
---|
2141 | { |
---|
2142 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
2143 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
2144 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
2145 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
2146 | |
---|
2147 | var context = obj.context; |
---|
2148 | var canvas = obj.canvas; |
---|
2149 | |
---|
2150 | context.strokeStyle = '#aaa'; |
---|
2151 | context.fillStyle = '#ddd'; |
---|
2152 | |
---|
2153 | // Draw the vertical left side |
---|
2154 | context.beginPath(); |
---|
2155 | context.moveTo(gutterLeft, gutterTop); |
---|
2156 | context.lineTo(gutterLeft + 10, gutterTop - 5); |
---|
2157 | context.lineTo(gutterLeft + 10, canvas.height - gutterBottom - 5); |
---|
2158 | context.lineTo(gutterLeft, canvas.height - gutterBottom); |
---|
2159 | context.closePath(); |
---|
2160 | |
---|
2161 | context.stroke(); |
---|
2162 | context.fill(); |
---|
2163 | |
---|
2164 | // Draw the bottom floor |
---|
2165 | context.beginPath(); |
---|
2166 | context.moveTo(gutterLeft, canvas.height - gutterBottom); |
---|
2167 | context.lineTo(gutterLeft + 10, canvas.height - gutterBottom - 5); |
---|
2168 | context.lineTo(canvas.width - gutterRight + 10, canvas.height - gutterBottom - 5); |
---|
2169 | context.lineTo(canvas.width - gutterRight, canvas.height - gutterBottom); |
---|
2170 | context.closePath(); |
---|
2171 | |
---|
2172 | context.stroke(); |
---|
2173 | context.fill(); |
---|
2174 | } |
---|
2175 | |
---|
2176 | /** |
---|
2177 | * Turns off any shadow |
---|
2178 | * |
---|
2179 | * @param object obj The graph object |
---|
2180 | */ |
---|
2181 | RGraph.NoShadow = function (obj) |
---|
2182 | { |
---|
2183 | obj.context.shadowColor = 'rgba(0,0,0,0)'; |
---|
2184 | obj.context.shadowBlur = 0; |
---|
2185 | obj.context.shadowOffsetX = 0; |
---|
2186 | obj.context.shadowOffsetY = 0; |
---|
2187 | } |
---|
2188 | |
---|
2189 | |
---|
2190 | /** |
---|
2191 | * Sets the four shadow properties - a shortcut function |
---|
2192 | * |
---|
2193 | * @param object obj Your graph object |
---|
2194 | * @param string color The shadow color |
---|
2195 | * @param number offsetx The shadows X offset |
---|
2196 | * @param number offsety The shadows Y offset |
---|
2197 | * @param number blur The blurring effect applied to the shadow |
---|
2198 | */ |
---|
2199 | RGraph.SetShadow = function (obj, color, offsetx, offsety, blur) |
---|
2200 | { |
---|
2201 | obj.context.shadowColor = color; |
---|
2202 | obj.context.shadowOffsetX = offsetx; |
---|
2203 | obj.context.shadowOffsetY = offsety; |
---|
2204 | obj.context.shadowBlur = blur; |
---|
2205 | } |
---|
2206 | |
---|
2207 | |
---|
2208 | /** |
---|
2209 | * This function attempts to "fill in" missing functions from the canvas |
---|
2210 | * context object. Only two at the moment - measureText() nd fillText(). |
---|
2211 | * |
---|
2212 | * @param object context The canvas 2D context |
---|
2213 | */ |
---|
2214 | RGraph.OldBrowserCompat = function (context) |
---|
2215 | { |
---|
2216 | if (!context.measureText) { |
---|
2217 | |
---|
2218 | // This emulates the measureText() function |
---|
2219 | context.measureText = function (text) |
---|
2220 | { |
---|
2221 | var textObj = document.createElement('DIV'); |
---|
2222 | textObj.innerHTML = text; |
---|
2223 | textObj.style.backgroundColor = 'white'; |
---|
2224 | textObj.style.position = 'absolute'; |
---|
2225 | textObj.style.top = -100 |
---|
2226 | textObj.style.left = 0; |
---|
2227 | document.body.appendChild(textObj); |
---|
2228 | |
---|
2229 | var width = {width: textObj.offsetWidth}; |
---|
2230 | |
---|
2231 | textObj.style.display = 'none'; |
---|
2232 | |
---|
2233 | return width; |
---|
2234 | } |
---|
2235 | } |
---|
2236 | |
---|
2237 | if (!context.fillText) { |
---|
2238 | // This emulates the fillText() method |
---|
2239 | context.fillText = function (text, targetX, targetY) |
---|
2240 | { |
---|
2241 | return false; |
---|
2242 | } |
---|
2243 | } |
---|
2244 | |
---|
2245 | // If IE8, add addEventListener() |
---|
2246 | if (!context.canvas.addEventListener) { |
---|
2247 | window.addEventListener = function (ev, func, bubble) |
---|
2248 | { |
---|
2249 | return this.attachEvent('on' + ev, func); |
---|
2250 | } |
---|
2251 | |
---|
2252 | context.canvas.addEventListener = function (ev, func, bubble) |
---|
2253 | { |
---|
2254 | return this.attachEvent('on' + ev, func); |
---|
2255 | } |
---|
2256 | } |
---|
2257 | } |
---|
2258 | |
---|
2259 | |
---|
2260 | |
---|
2261 | /** |
---|
2262 | * This is a function that can be used to run code asynchronously, which can |
---|
2263 | * be used to speed up the loading of you pages. |
---|
2264 | * |
---|
2265 | * @param string func This is the code to run. It can also be a function pointer. |
---|
2266 | * The front page graphs show this function in action. Basically |
---|
2267 | * each graphs code is made in a function, and that function is |
---|
2268 | * passed to this function to run asychronously. |
---|
2269 | */ |
---|
2270 | RGraph.Async = function (func) |
---|
2271 | { |
---|
2272 | return setTimeout(func, arguments[1] ? arguments[1] : 1); |
---|
2273 | } |
---|
2274 | |
---|
2275 | |
---|
2276 | /** |
---|
2277 | * A custom random number function |
---|
2278 | * |
---|
2279 | * @param number min The minimum that the number should be |
---|
2280 | * @param number max The maximum that the number should be |
---|
2281 | * @param number How many decimal places there should be. Default for this is 0 |
---|
2282 | */ |
---|
2283 | RGraph.random = function (min, max) |
---|
2284 | { |
---|
2285 | var dp = arguments[2] ? arguments[2] : 0; |
---|
2286 | var r = Math.random(); |
---|
2287 | |
---|
2288 | return Number((((max - min) * r) + min).toFixed(dp)); |
---|
2289 | } |
---|
2290 | |
---|
2291 | |
---|
2292 | /** |
---|
2293 | * Draws a rectangle with curvy corners |
---|
2294 | * |
---|
2295 | * @param context object The context |
---|
2296 | * @param x number The X coordinate (top left of the square) |
---|
2297 | * @param y number The Y coordinate (top left of the square) |
---|
2298 | * @param w number The width of the rectangle |
---|
2299 | * @param h number The height of the rectangle |
---|
2300 | * @param number The radius of the curved corners |
---|
2301 | * @param boolean Whether the top left corner is curvy |
---|
2302 | * @param boolean Whether the top right corner is curvy |
---|
2303 | * @param boolean Whether the bottom right corner is curvy |
---|
2304 | * @param boolean Whether the bottom left corner is curvy |
---|
2305 | */ |
---|
2306 | RGraph.strokedCurvyRect = function (context, x, y, w, h) |
---|
2307 | { |
---|
2308 | // The corner radius |
---|
2309 | var r = arguments[5] ? arguments[5] : 3; |
---|
2310 | |
---|
2311 | // The corners |
---|
2312 | var corner_tl = (arguments[6] || arguments[6] == null) ? true : false; |
---|
2313 | var corner_tr = (arguments[7] || arguments[7] == null) ? true : false; |
---|
2314 | var corner_br = (arguments[8] || arguments[8] == null) ? true : false; |
---|
2315 | var corner_bl = (arguments[9] || arguments[9] == null) ? true : false; |
---|
2316 | |
---|
2317 | context.beginPath(); |
---|
2318 | |
---|
2319 | // Top left side |
---|
2320 | context.moveTo(x + (corner_tl ? r : 0), y); |
---|
2321 | context.lineTo(x + w - (corner_tr ? r : 0), y); |
---|
2322 | |
---|
2323 | // Top right corner |
---|
2324 | if (corner_tr) { |
---|
2325 | context.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2, false); |
---|
2326 | } |
---|
2327 | |
---|
2328 | // Top right side |
---|
2329 | context.lineTo(x + w, y + h - (corner_br ? r : 0) ); |
---|
2330 | |
---|
2331 | // Bottom right corner |
---|
2332 | if (corner_br) { |
---|
2333 | context.arc(x + w - r, y - r + h, r, Math.PI * 2, Math.PI * 0.5, false); |
---|
2334 | } |
---|
2335 | |
---|
2336 | // Bottom right side |
---|
2337 | context.lineTo(x + (corner_bl ? r : 0), y + h); |
---|
2338 | |
---|
2339 | // Bottom left corner |
---|
2340 | if (corner_bl) { |
---|
2341 | context.arc(x + r, y - r + h, r, Math.PI * 0.5, Math.PI, false); |
---|
2342 | } |
---|
2343 | |
---|
2344 | // Bottom left side |
---|
2345 | context.lineTo(x, y + (corner_tl ? r : 0) ); |
---|
2346 | |
---|
2347 | // Top left corner |
---|
2348 | if (corner_tl) { |
---|
2349 | context.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5, false); |
---|
2350 | } |
---|
2351 | |
---|
2352 | context.stroke(); |
---|
2353 | } |
---|
2354 | |
---|
2355 | |
---|
2356 | /** |
---|
2357 | * Draws a filled rectangle with curvy corners |
---|
2358 | * |
---|
2359 | * @param context object The context |
---|
2360 | * @param x number The X coordinate (top left of the square) |
---|
2361 | * @param y number The Y coordinate (top left of the square) |
---|
2362 | * @param w number The width of the rectangle |
---|
2363 | * @param h number The height of the rectangle |
---|
2364 | * @param number The radius of the curved corners |
---|
2365 | * @param boolean Whether the top left corner is curvy |
---|
2366 | * @param boolean Whether the top right corner is curvy |
---|
2367 | * @param boolean Whether the bottom right corner is curvy |
---|
2368 | * @param boolean Whether the bottom left corner is curvy |
---|
2369 | */ |
---|
2370 | RGraph.filledCurvyRect = function (context, x, y, w, h) |
---|
2371 | { |
---|
2372 | // The corner radius |
---|
2373 | var r = arguments[5] ? arguments[5] : 3; |
---|
2374 | |
---|
2375 | // The corners |
---|
2376 | var corner_tl = (arguments[6] || arguments[6] == null) ? true : false; |
---|
2377 | var corner_tr = (arguments[7] || arguments[7] == null) ? true : false; |
---|
2378 | var corner_br = (arguments[8] || arguments[8] == null) ? true : false; |
---|
2379 | var corner_bl = (arguments[9] || arguments[9] == null) ? true : false; |
---|
2380 | |
---|
2381 | context.beginPath(); |
---|
2382 | |
---|
2383 | // First draw the corners |
---|
2384 | |
---|
2385 | // Top left corner |
---|
2386 | if (corner_tl) { |
---|
2387 | context.moveTo(x + r, y + r); |
---|
2388 | context.arc(x + r, y + r, r, Math.PI, 1.5 * Math.PI, false); |
---|
2389 | } else { |
---|
2390 | context.fillRect(x, y, r, r); |
---|
2391 | } |
---|
2392 | |
---|
2393 | // Top right corner |
---|
2394 | if (corner_tr) { |
---|
2395 | context.moveTo(x + w - r, y + r); |
---|
2396 | context.arc(x + w - r, y + r, r, 1.5 * Math.PI, 0, false); |
---|
2397 | } else { |
---|
2398 | context.moveTo(x + w - r, y); |
---|
2399 | context.fillRect(x + w - r, y, r, r); |
---|
2400 | } |
---|
2401 | |
---|
2402 | |
---|
2403 | // Bottom right corner |
---|
2404 | if (corner_br) { |
---|
2405 | context.moveTo(x + w - r, y + h - r); |
---|
2406 | context.arc(x + w - r, y - r + h, r, 0, Math.PI / 2, false); |
---|
2407 | } else { |
---|
2408 | context.moveTo(x + w - r, y + h - r); |
---|
2409 | context.fillRect(x + w - r, y + h - r, r, r); |
---|
2410 | } |
---|
2411 | |
---|
2412 | // Bottom left corner |
---|
2413 | if (corner_bl) { |
---|
2414 | context.moveTo(x + r, y + h - r); |
---|
2415 | context.arc(x + r, y - r + h, r, Math.PI / 2, Math.PI, false); |
---|
2416 | } else { |
---|
2417 | context.moveTo(x, y + h - r); |
---|
2418 | context.fillRect(x, y + h - r, r, r); |
---|
2419 | } |
---|
2420 | |
---|
2421 | // Now fill it in |
---|
2422 | context.fillRect(x + r, y, w - r - r, h); |
---|
2423 | context.fillRect(x, y + r, r + 1, h - r - r); |
---|
2424 | context.fillRect(x + w - r - 1, y + r, r + 1, h - r - r); |
---|
2425 | |
---|
2426 | context.fill(); |
---|
2427 | } |
---|
2428 | |
---|
2429 | |
---|
2430 | /** |
---|
2431 | * A crude timing function |
---|
2432 | * |
---|
2433 | * @param string label The label to use for the time |
---|
2434 | */ |
---|
2435 | RGraph.Timer = function (label) |
---|
2436 | { |
---|
2437 | var d = new Date(); |
---|
2438 | |
---|
2439 | // This uses the Firebug console |
---|
2440 | console.log(label + ': ' + d.getSeconds() + '.' + d.getMilliseconds()); |
---|
2441 | } |
---|
2442 | |
---|
2443 | |
---|
2444 | /** |
---|
2445 | * Hides the palette if it's visible |
---|
2446 | */ |
---|
2447 | RGraph.HidePalette = function () |
---|
2448 | { |
---|
2449 | var div = RGraph.Registry.Get('palette'); |
---|
2450 | |
---|
2451 | if (typeof(div) == 'object' && div) { |
---|
2452 | div.style.visibility = 'hidden'; |
---|
2453 | div.style.display = 'none'; |
---|
2454 | RGraph.Registry.Set('palette', null); |
---|
2455 | } |
---|
2456 | } |
---|
2457 | |
---|
2458 | |
---|
2459 | /** |
---|
2460 | * Hides the zoomed canvas |
---|
2461 | */ |
---|
2462 | RGraph.HideZoomedCanvas = function () |
---|
2463 | { |
---|
2464 | if (typeof(__zoomedimage__) == 'object') { |
---|
2465 | obj = __zoomedimage__.obj; |
---|
2466 | } else { |
---|
2467 | return; |
---|
2468 | } |
---|
2469 | |
---|
2470 | if (obj.Get('chart.zoom.fade.out')) { |
---|
2471 | for (var i=10,j=1; i>=0; --i, ++j) { |
---|
2472 | if (typeof(__zoomedimage__) == 'object') { |
---|
2473 | setTimeout("__zoomedimage__.style.opacity = " + String(i / 10), j * 30); |
---|
2474 | } |
---|
2475 | } |
---|
2476 | |
---|
2477 | if (typeof(__zoomedbackground__) == 'object') { |
---|
2478 | setTimeout("__zoomedbackground__.style.opacity = " + String(i / 10), j * 30); |
---|
2479 | } |
---|
2480 | } |
---|
2481 | |
---|
2482 | if (typeof(__zoomedimage__) == 'object') { |
---|
2483 | setTimeout("__zoomedimage__.style.display = 'none'", obj.Get('chart.zoom.fade.out') ? 310 : 0); |
---|
2484 | } |
---|
2485 | |
---|
2486 | if (typeof(__zoomedbackground__) == 'object') { |
---|
2487 | setTimeout("__zoomedbackground__.style.display = 'none'", obj.Get('chart.zoom.fade.out') ? 310 : 0); |
---|
2488 | } |
---|
2489 | } |
---|
2490 | |
---|
2491 | |
---|
2492 | /** |
---|
2493 | * Adds an event handler |
---|
2494 | * |
---|
2495 | * @param object obj The graph object |
---|
2496 | * @param string event The name of the event, eg ontooltip |
---|
2497 | * @param object func The callback function |
---|
2498 | */ |
---|
2499 | RGraph.AddCustomEventListener = function (obj, name, func) |
---|
2500 | { |
---|
2501 | if (typeof(RGraph.events[obj.id]) == 'undefined') { |
---|
2502 | RGraph.events[obj.id] = []; |
---|
2503 | } |
---|
2504 | |
---|
2505 | RGraph.events[obj.id].push([obj, name, func]); |
---|
2506 | |
---|
2507 | return RGraph.events[obj.id].length - 1; |
---|
2508 | } |
---|
2509 | |
---|
2510 | |
---|
2511 | /** |
---|
2512 | * Used to fire one of the RGraph custom events |
---|
2513 | * |
---|
2514 | * @param object obj The graph object that fires the event |
---|
2515 | * @param string event The name of the event to fire |
---|
2516 | */ |
---|
2517 | RGraph.FireCustomEvent = function (obj, name) |
---|
2518 | { |
---|
2519 | if (obj && obj.isRGraph) { |
---|
2520 | var id = obj.id; |
---|
2521 | |
---|
2522 | if ( typeof(id) == 'string' |
---|
2523 | && typeof(RGraph.events) == 'object' |
---|
2524 | && typeof(RGraph.events[id]) == 'object' |
---|
2525 | && RGraph.events[id].length > 0) { |
---|
2526 | |
---|
2527 | for(var j=0; j<RGraph.events[id].length; ++j) { |
---|
2528 | if (RGraph.events[id][j] && RGraph.events[id][j][1] == name) { |
---|
2529 | RGraph.events[id][j][2](obj); |
---|
2530 | } |
---|
2531 | } |
---|
2532 | } |
---|
2533 | } |
---|
2534 | } |
---|
2535 | |
---|
2536 | |
---|
2537 | /** |
---|
2538 | * Checks the browser for traces of MSIE8 |
---|
2539 | */ |
---|
2540 | RGraph.isIE8 = function () |
---|
2541 | { |
---|
2542 | return navigator.userAgent.indexOf('MSIE 8') > 0; |
---|
2543 | } |
---|
2544 | |
---|
2545 | |
---|
2546 | /** |
---|
2547 | * Checks the browser for traces of MSIE9 |
---|
2548 | */ |
---|
2549 | RGraph.isIE9 = function () |
---|
2550 | { |
---|
2551 | return navigator.userAgent.indexOf('MSIE 9') > 0; |
---|
2552 | } |
---|
2553 | |
---|
2554 | |
---|
2555 | /** |
---|
2556 | * Checks the browser for traces of MSIE9 |
---|
2557 | */ |
---|
2558 | RGraph.isIE9up = function () |
---|
2559 | { |
---|
2560 | navigator.userAgent.match(/MSIE (\d+)/); |
---|
2561 | |
---|
2562 | return Number(RegExp.$1) >= 9; |
---|
2563 | } |
---|
2564 | |
---|
2565 | |
---|
2566 | /** |
---|
2567 | * This clears a canvases event handlers. Used at the start of each graphs .Draw() method. |
---|
2568 | * |
---|
2569 | * @param string id The ID of the canvas whose event handlers will be cleared |
---|
2570 | */ |
---|
2571 | RGraph.ClearEventListeners = function (id) |
---|
2572 | { |
---|
2573 | for (var i=0; i<RGraph.Registry.Get('chart.event.handlers').length; ++i) { |
---|
2574 | |
---|
2575 | var el = RGraph.Registry.Get('chart.event.handlers')[i]; |
---|
2576 | |
---|
2577 | if (el && (el[0] == id || el[0] == ('window_' + id)) ) { |
---|
2578 | if (el[0].substring(0, 7) == 'window_') { |
---|
2579 | window.removeEventListener(el[1], el[2], false); |
---|
2580 | } else { |
---|
2581 | document.getElementById(id).removeEventListener(el[1], el[2], false); |
---|
2582 | } |
---|
2583 | |
---|
2584 | RGraph.Registry.Get('chart.event.handlers')[i] = null; |
---|
2585 | } |
---|
2586 | } |
---|
2587 | } |
---|
2588 | |
---|
2589 | |
---|
2590 | /** |
---|
2591 | * |
---|
2592 | */ |
---|
2593 | RGraph.AddEventListener = function (id, e, func) |
---|
2594 | { |
---|
2595 | RGraph.Registry.Get('chart.event.handlers').push([id, e, func]); |
---|
2596 | } |
---|
2597 | |
---|
2598 | |
---|
2599 | /** |
---|
2600 | * This function suggests a gutter size based on the widest left label. Given that the bottom |
---|
2601 | * labels may be longer, this may be a little out. |
---|
2602 | * |
---|
2603 | * @param object obj The graph object |
---|
2604 | * @param array data An array of graph data |
---|
2605 | * @return int A suggested gutter setting |
---|
2606 | */ |
---|
2607 | RGraph.getGutterSuggest = function (obj, data) |
---|
2608 | { |
---|
2609 | var str = RGraph.number_format(obj, RGraph.array_max(RGraph.getScale(RGraph.array_max(data), obj)), obj.Get('chart.units.pre'), obj.Get('chart.units.post')); |
---|
2610 | |
---|
2611 | // Take into account the HBar |
---|
2612 | if (obj.type == 'hbar') { |
---|
2613 | |
---|
2614 | var str = ''; |
---|
2615 | var len = 0; |
---|
2616 | |
---|
2617 | for (var i=0; i<obj.Get('chart.labels').length; ++i) { |
---|
2618 | str = (obj.Get('chart.labels').length > str.length ? obj.Get('chart.labels')[i] : str); |
---|
2619 | } |
---|
2620 | } |
---|
2621 | |
---|
2622 | obj.context.font = obj.Get('chart.text.size') + 'pt ' + obj.Get('chart.text.font'); |
---|
2623 | |
---|
2624 | len = obj.context.measureText(str).width + 5; |
---|
2625 | |
---|
2626 | return (obj.type == 'hbar' ? len / 3 : len); |
---|
2627 | } |
---|
2628 | |
---|
2629 | |
---|
2630 | /** |
---|
2631 | * A basic Array shift gunction |
---|
2632 | * |
---|
2633 | * @param object The numerical array to work on |
---|
2634 | * @return The new array |
---|
2635 | */ |
---|
2636 | RGraph.array_shift = function (arr) |
---|
2637 | { |
---|
2638 | var ret = []; |
---|
2639 | |
---|
2640 | for (var i=1; i<arr.length; ++i) ret.push(arr[i]); |
---|
2641 | |
---|
2642 | return ret; |
---|
2643 | } |
---|
2644 | |
---|
2645 | |
---|
2646 | /** |
---|
2647 | * If you prefer, you can use the SetConfig() method to set the configuration information |
---|
2648 | * for your chart. You may find that setting the configuration this way eases reuse. |
---|
2649 | * |
---|
2650 | * @param object obj The graph object |
---|
2651 | * @param object config The graph configuration information |
---|
2652 | */ |
---|
2653 | RGraph.SetConfig = function (obj, c) |
---|
2654 | { |
---|
2655 | for (i in c) { |
---|
2656 | if (typeof(i) == 'string') { |
---|
2657 | obj.Set(i, c[i]); |
---|
2658 | } |
---|
2659 | } |
---|
2660 | |
---|
2661 | return obj; |
---|
2662 | } |
---|
2663 | |
---|
2664 | |
---|
2665 | /** |
---|
2666 | * This function gets the canvas height. Defaults to the actual |
---|
2667 | * height but this can be changed by setting chart.height. |
---|
2668 | * |
---|
2669 | * @param object obj The graph object |
---|
2670 | */ |
---|
2671 | RGraph.GetHeight = function (obj) |
---|
2672 | { |
---|
2673 | return obj.canvas.height; |
---|
2674 | } |
---|
2675 | |
---|
2676 | |
---|
2677 | /** |
---|
2678 | * This function gets the canvas width. Defaults to the actual |
---|
2679 | * width but this can be changed by setting chart.width. |
---|
2680 | * |
---|
2681 | * @param object obj The graph object |
---|
2682 | */ |
---|
2683 | RGraph.GetWidth = function (obj) |
---|
2684 | { |
---|
2685 | return obj.canvas.width; |
---|
2686 | } |
---|
2687 | |
---|
2688 | |
---|
2689 | /** |
---|
2690 | * Clears all the custom event listeners that have been registered |
---|
2691 | * |
---|
2692 | * @param string Limits the clearing to this object ID |
---|
2693 | */ |
---|
2694 | RGraph.RemoveAllCustomEventListeners = function () |
---|
2695 | { |
---|
2696 | var id = arguments[0]; |
---|
2697 | |
---|
2698 | if (id && RGraph.events[id]) { |
---|
2699 | RGraph.events[id] = []; |
---|
2700 | } else { |
---|
2701 | RGraph.events = []; |
---|
2702 | } |
---|
2703 | } |
---|
2704 | |
---|
2705 | |
---|
2706 | /** |
---|
2707 | * Clears a particular custom event listener |
---|
2708 | * |
---|
2709 | * @param object obj The graph object |
---|
2710 | * @param number i This is the index that is return by .AddCustomEventListener() |
---|
2711 | */ |
---|
2712 | RGraph.RemoveCustomEventListener = function (obj, i) |
---|
2713 | { |
---|
2714 | if ( typeof(RGraph.events) == 'object' |
---|
2715 | && typeof(RGraph.events[obj.id]) == 'object' |
---|
2716 | && typeof(RGraph.events[obj.id][i]) == 'object') { |
---|
2717 | |
---|
2718 | RGraph.events[obj.id][i] = null; |
---|
2719 | } |
---|
2720 | } |
---|
2721 | |
---|
2722 | |
---|
2723 | /** |
---|
2724 | * This draws the background |
---|
2725 | * |
---|
2726 | * @param object obj The graph object |
---|
2727 | */ |
---|
2728 | RGraph.DrawBackgroundImage = function (obj) |
---|
2729 | { |
---|
2730 | var img = new Image(); |
---|
2731 | img.__object__ = obj; |
---|
2732 | img.__canvas__ = obj.canvas; |
---|
2733 | img.__context__ = obj.context; |
---|
2734 | img.src = obj.Get('chart.background.image'); |
---|
2735 | |
---|
2736 | obj.__background_image__ = img; |
---|
2737 | |
---|
2738 | img.onload = function () |
---|
2739 | { |
---|
2740 | var obj = this.__object__; |
---|
2741 | |
---|
2742 | var gutterLeft = obj.Get('chart.gutter.left'); |
---|
2743 | var gutterRight = obj.Get('chart.gutter.right'); |
---|
2744 | var gutterTop = obj.Get('chart.gutter.top'); |
---|
2745 | var gutterBottom = obj.Get('chart.gutter.bottom'); |
---|
2746 | |
---|
2747 | RGraph.Clear(obj.canvas); |
---|
2748 | |
---|
2749 | obj.context.drawImage(this,gutterLeft,gutterTop, RGraph.GetWidth(obj) - gutterLeft - gutterRight, RGraph.GetHeight(obj) - gutterTop - gutterBottom); |
---|
2750 | |
---|
2751 | // Draw the graph |
---|
2752 | obj.Draw(); |
---|
2753 | } |
---|
2754 | |
---|
2755 | img.onerror = function () |
---|
2756 | { |
---|
2757 | var obj = this.__canvas__.__object__; |
---|
2758 | |
---|
2759 | // Show an error alert |
---|
2760 | alert('[ERROR] There was an error with the background image that you specified: ' + img.src); |
---|
2761 | |
---|
2762 | // Draw the graph, because the onload doesn't fire, and thus that won't draw the chart |
---|
2763 | obj.Draw(); |
---|
2764 | } |
---|
2765 | } |
---|
2766 | |
---|
2767 | |
---|
2768 | /** |
---|
2769 | * This resets the canvas. Keep in mind that any translate() that has been performed will also be reset. |
---|
2770 | * |
---|
2771 | * @param object canvas The canvas |
---|
2772 | */ |
---|
2773 | RGraph.Reset = function (canvas) |
---|
2774 | { |
---|
2775 | canvas.width = canvas.width; |
---|
2776 | } |
---|