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 | if (typeof(RGraph) == 'undefined') RGraph = {}; |
---|
16 | |
---|
17 | /** |
---|
18 | * The bar chart constructor |
---|
19 | * |
---|
20 | * @param object canvas The canvas object |
---|
21 | * @param array data The chart data |
---|
22 | */ |
---|
23 | RGraph.Waterfall = function (id, data) |
---|
24 | { |
---|
25 | // Get the canvas and context objects |
---|
26 | this.id = id; |
---|
27 | this.canvas = document.getElementById(id); |
---|
28 | this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; |
---|
29 | this.canvas.__object__ = this; |
---|
30 | this.type = 'waterfall'; |
---|
31 | this.max = 0; |
---|
32 | this.isRGraph = true; |
---|
33 | this.coords = []; |
---|
34 | |
---|
35 | /** |
---|
36 | * Compatibility with older browsers |
---|
37 | */ |
---|
38 | RGraph.OldBrowserCompat(this.context); |
---|
39 | |
---|
40 | |
---|
41 | // Various config |
---|
42 | this.properties = { |
---|
43 | 'chart.background.barcolor1': 'rgba(0,0,0,0)', |
---|
44 | 'chart.background.barcolor2': 'rgba(0,0,0,0)', |
---|
45 | 'chart.background.grid': true, |
---|
46 | 'chart.background.grid.color': '#ddd', |
---|
47 | 'chart.background.grid.width': 1, |
---|
48 | 'chart.background.grid.hsize': 20, |
---|
49 | 'chart.background.grid.vsize': 20, |
---|
50 | 'chart.background.grid.vlines': true, |
---|
51 | 'chart.background.grid.hlines': true, |
---|
52 | 'chart.background.grid.border': true, |
---|
53 | 'chart.background.grid.autofit':false, |
---|
54 | 'chart.background.grid.autofit.numhlines': 7, |
---|
55 | 'chart.background.grid.autofit.numvlines': 20, |
---|
56 | 'chart.background.grid.autofit.align': false, |
---|
57 | 'chart.background.image': null, |
---|
58 | 'chart.background.hbars': null, // ??? |
---|
59 | |
---|
60 | 'chart.numyticks': 10, |
---|
61 | 'chart.hmargin': 5, |
---|
62 | 'chart.strokestyle': '#666', |
---|
63 | 'chart.axis.color': 'black', |
---|
64 | 'chart.gutter.left': 25, |
---|
65 | 'chart.gutter.right': 25, |
---|
66 | 'chart.gutter.top': 25, |
---|
67 | 'chart.gutter.bottom': 25, |
---|
68 | 'chart.labels': [], |
---|
69 | 'chart.ylabels': true, |
---|
70 | 'chart.text.color': 'black', |
---|
71 | 'chart.text.size': 10, |
---|
72 | 'chart.text.angle': 0, |
---|
73 | 'chart.text.font': 'Verdana', |
---|
74 | 'chart.ymax': null, |
---|
75 | |
---|
76 | 'chart.title': '', |
---|
77 | 'chart.title.color': 'black', |
---|
78 | 'chart.title.background': null, |
---|
79 | 'chart.title.hpos': null, |
---|
80 | 'chart.title.vpos': null, |
---|
81 | 'chart.title.xaxis': '', |
---|
82 | 'chart.title.yaxis': '', |
---|
83 | 'chart.title.xaxis.pos': 0.25, |
---|
84 | 'chart.title.yaxis.pos': 0.25, |
---|
85 | 'chart.title.yaxis.align': 'left', |
---|
86 | |
---|
87 | 'chart.colors': ['green', 'red', 'blue'], |
---|
88 | |
---|
89 | 'chart.shadow': false, |
---|
90 | 'chart.shadow.color': '#666', |
---|
91 | 'chart.shadow.offsetx': 3, |
---|
92 | 'chart.shadow.offsety': 3, |
---|
93 | 'chart.shadow.blur': 3, |
---|
94 | |
---|
95 | 'chart.tooltips': null, |
---|
96 | 'chart.tooltips.effect': 'fade', |
---|
97 | 'chart.tooltips.css.class': 'RGraph_tooltip', |
---|
98 | //'chart.tooltips.event': 'onclick', |
---|
99 | 'chart.tooltips.coords.adjust': [0,0], |
---|
100 | 'chart.tooltips.highlight': true, |
---|
101 | 'chart.tooltips.override': null, |
---|
102 | |
---|
103 | 'chart.highlight.stroke': 'black', |
---|
104 | 'chart.highlight.fill': 'rgba(255,255,255,0.5)', |
---|
105 | |
---|
106 | 'chart.contextmenu': null, |
---|
107 | |
---|
108 | 'chart.units.pre': '', |
---|
109 | 'chart.units.post': '', |
---|
110 | |
---|
111 | //'chart.scale.decimals': 0, |
---|
112 | //'chart.scale.point': '.', |
---|
113 | //'chart.scale.thousand': ',', |
---|
114 | //'chart.scale.formatter': null, |
---|
115 | |
---|
116 | 'chart.crosshairs': false, |
---|
117 | 'chart.crosshairs.color': '#333', |
---|
118 | |
---|
119 | 'chart.annotatable': false, |
---|
120 | 'chart.annotate.color': 'black', |
---|
121 | |
---|
122 | 'chart.zoom.factor': 1.5, |
---|
123 | 'chart.zoom.fade.in': true, |
---|
124 | 'chart.zoom.fade.out': true, |
---|
125 | 'chart.zoom.hdir': 'right', |
---|
126 | 'chart.zoom.vdir': 'down', |
---|
127 | 'chart.zoom.frames': 10, |
---|
128 | 'chart.zoom.delay': 50, |
---|
129 | 'chart.zoom.shadow': true, |
---|
130 | 'chart.zoom.mode': 'canvas', |
---|
131 | 'chart.zoom.thumbnail.width': 75, |
---|
132 | 'chart.zoom.thumbnail.height': 75, |
---|
133 | 'chart.zoom.background': true, |
---|
134 | |
---|
135 | 'chart.resizable': false, |
---|
136 | 'chart.resize.handle.adjust': [0,0], |
---|
137 | 'chart.resize.handle.background': null, |
---|
138 | |
---|
139 | 'chart.noaxes': false, |
---|
140 | 'chart.noxaxis': false, |
---|
141 | 'chart.noyaxis': false, |
---|
142 | |
---|
143 | 'chart.axis.color': 'black', |
---|
144 | 'chart.total': true |
---|
145 | } |
---|
146 | |
---|
147 | // Check for support |
---|
148 | if (!this.canvas) { |
---|
149 | alert('[WATERFALL] No canvas support'); |
---|
150 | return; |
---|
151 | } |
---|
152 | |
---|
153 | // Store the data |
---|
154 | this.data = data; |
---|
155 | } |
---|
156 | |
---|
157 | |
---|
158 | /** |
---|
159 | * A setter |
---|
160 | * |
---|
161 | * @param name string The name of the property to set |
---|
162 | * @param value mixed The value of the property |
---|
163 | */ |
---|
164 | RGraph.Waterfall.prototype.Set = function (name, value) |
---|
165 | { |
---|
166 | this.properties[name.toLowerCase()] = value; |
---|
167 | } |
---|
168 | |
---|
169 | |
---|
170 | /** |
---|
171 | * A getter |
---|
172 | * |
---|
173 | * @param name string The name of the property to get |
---|
174 | */ |
---|
175 | RGraph.Waterfall.prototype.Get = function (name) |
---|
176 | { |
---|
177 | return this.properties[name.toLowerCase()]; |
---|
178 | } |
---|
179 | |
---|
180 | |
---|
181 | /** |
---|
182 | * The function you call to draw the bar chart |
---|
183 | */ |
---|
184 | RGraph.Waterfall.prototype.Draw = function () |
---|
185 | { |
---|
186 | // MUST be the first thing done! |
---|
187 | if (typeof(this.Get('chart.background.image')) == 'string' && !this.__background_image__) { |
---|
188 | RGraph.DrawBackgroundImage(this); |
---|
189 | return; |
---|
190 | } |
---|
191 | |
---|
192 | |
---|
193 | /** |
---|
194 | * Fire the onbeforedraw event |
---|
195 | */ |
---|
196 | RGraph.FireCustomEvent(this, 'onbeforedraw'); |
---|
197 | |
---|
198 | /** |
---|
199 | * Clear all of this canvases event handlers (the ones installed by RGraph) |
---|
200 | */ |
---|
201 | RGraph.ClearEventListeners(this.id); |
---|
202 | |
---|
203 | /** |
---|
204 | * This is new in May 2011 and facilitates indiviual gutter settings, |
---|
205 | * eg chart.gutter.left |
---|
206 | */ |
---|
207 | this.gutterLeft = this.Get('chart.gutter.left'); |
---|
208 | this.gutterRight = this.Get('chart.gutter.right'); |
---|
209 | this.gutterTop = this.Get('chart.gutter.top'); |
---|
210 | this.gutterBottom = this.Get('chart.gutter.bottom'); |
---|
211 | |
---|
212 | /** |
---|
213 | * Stop the coords array from growing uncontrollably |
---|
214 | */ |
---|
215 | this.coords = []; |
---|
216 | |
---|
217 | /** |
---|
218 | * Work out a few things. They need to be here because they depend on things you can change after you instantiate the object |
---|
219 | */ |
---|
220 | this.max = 0; |
---|
221 | this.grapharea = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom; |
---|
222 | this.graphwidth = RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight; |
---|
223 | this.halfTextHeight = this.Get('chart.text.size') / 2; |
---|
224 | |
---|
225 | // Work out the resulting total |
---|
226 | if (typeof(this.Get('chart.total')) == 'boolean' && this.Get('chart.total')) { |
---|
227 | var total = RGraph.array_sum(this.data); |
---|
228 | this.data.push(total); |
---|
229 | this.Set('chart.total', total); |
---|
230 | } |
---|
231 | |
---|
232 | /** |
---|
233 | * Work out the maximum value |
---|
234 | */ |
---|
235 | var runningTotal = 0; |
---|
236 | for (var i=0; i<this.data.length - 1; ++i) { |
---|
237 | runningTotal += this.data[i]; |
---|
238 | this.max = Math.max(this.max, runningTotal); |
---|
239 | } |
---|
240 | |
---|
241 | this.scale = RGraph.getScale(typeof(this.Get('chart.ymax')) == 'number' ? this.Get('chart.ymax') : this.max, this); |
---|
242 | this.max = this.scale[4]; |
---|
243 | var decimals = this.Get('chart.scale.decimals'); |
---|
244 | |
---|
245 | this.scale = [ |
---|
246 | (this.max * (1/5)).toFixed(decimals), |
---|
247 | (this.max * (2/5)).toFixed(decimals), |
---|
248 | (this.max * (3/5)).toFixed(decimals), |
---|
249 | (this.max * (4/5)).toFixed(decimals), |
---|
250 | this.max.toFixed(decimals) |
---|
251 | ]; |
---|
252 | |
---|
253 | |
---|
254 | // Progressively Draw the chart |
---|
255 | RGraph.background.Draw(this); |
---|
256 | |
---|
257 | this.Drawbars(); |
---|
258 | this.DrawAxes(); |
---|
259 | this.DrawLabels(); |
---|
260 | |
---|
261 | /** |
---|
262 | * Setup the context menu if required |
---|
263 | */ |
---|
264 | if (this.Get('chart.contextmenu')) { |
---|
265 | RGraph.ShowContext(this); |
---|
266 | } |
---|
267 | |
---|
268 | |
---|
269 | /** |
---|
270 | * Draw crosschairs |
---|
271 | */ |
---|
272 | if (this.Get('chart.crosshairs')) { |
---|
273 | RGraph.DrawCrosshairs(this); |
---|
274 | } |
---|
275 | |
---|
276 | /** |
---|
277 | * If the canvas is annotatable, do install the event handlers |
---|
278 | */ |
---|
279 | if (this.Get('chart.annotatable')) { |
---|
280 | RGraph.Annotate(this); |
---|
281 | } |
---|
282 | |
---|
283 | /** |
---|
284 | * This bit shows the mini zoom window if requested |
---|
285 | */ |
---|
286 | if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') { |
---|
287 | RGraph.ShowZoomWindow(this); |
---|
288 | } |
---|
289 | |
---|
290 | |
---|
291 | /** |
---|
292 | * This function enables resizing |
---|
293 | */ |
---|
294 | if (this.Get('chart.resizable')) { |
---|
295 | RGraph.AllowResizing(this); |
---|
296 | } |
---|
297 | |
---|
298 | /** |
---|
299 | * Tooltips |
---|
300 | */ |
---|
301 | if (this.Get('chart.tooltips')) { |
---|
302 | |
---|
303 | RGraph.Register(this); |
---|
304 | |
---|
305 | |
---|
306 | |
---|
307 | |
---|
308 | |
---|
309 | |
---|
310 | |
---|
311 | |
---|
312 | |
---|
313 | |
---|
314 | |
---|
315 | |
---|
316 | |
---|
317 | |
---|
318 | /** |
---|
319 | * Install the onclick event handler for the tooltips |
---|
320 | */ |
---|
321 | var canvas_onclick_func = function (e) |
---|
322 | { |
---|
323 | e = RGraph.FixEventObject(e); |
---|
324 | |
---|
325 | var canvas = document.getElementById(this.id); |
---|
326 | var context = canvas.getContext('2d'); |
---|
327 | var obj = canvas.__object__; |
---|
328 | |
---|
329 | /** |
---|
330 | * Redraw the graph first, in effect resetting the graph to as it was when it was first drawn |
---|
331 | * This "deselects" any already selected bar |
---|
332 | */ |
---|
333 | RGraph.Clear(canvas); |
---|
334 | obj.Draw(); |
---|
335 | |
---|
336 | /** |
---|
337 | * Get the mouse X/Y coordinates |
---|
338 | */ |
---|
339 | var mouseCoords = RGraph.getMouseXY(e); |
---|
340 | var mouseX = mouseCoords[0]; |
---|
341 | var mouseY = mouseCoords[1]; |
---|
342 | var adjust = obj.Get('chart.tooltips.coords.adjust'); |
---|
343 | |
---|
344 | /** |
---|
345 | * Loop through the bars determining if the mouse is over a bar |
---|
346 | */ |
---|
347 | for (var i=0; i<obj.coords.length; i++) { |
---|
348 | |
---|
349 | var coordsX = obj.coords[i][0]; |
---|
350 | var coordsY = obj.coords[i][1]; |
---|
351 | var coordsW = obj.coords[i][2]; |
---|
352 | var coordsH = obj.coords[i][3]; |
---|
353 | |
---|
354 | if ( |
---|
355 | mouseX >= (coordsX + adjust[0]) && |
---|
356 | mouseX <= (coordsX + coordsW + adjust[0]) && |
---|
357 | mouseY >= (coordsY + adjust[1]) && |
---|
358 | mouseY <= (coordsY + coordsH + adjust[1]) |
---|
359 | ) { |
---|
360 | |
---|
361 | if (!obj.Get('chart.tooltips')[i]) { |
---|
362 | return; |
---|
363 | } |
---|
364 | |
---|
365 | // Draw the highlight (if necessary) |
---|
366 | if (obj.Get('chart.tooltips.highlight')) { |
---|
367 | context.beginPath(); |
---|
368 | context.fillStyle = obj.Get('chart.highlight.fill'); |
---|
369 | context.strokeStyle = obj.Get('chart.highlight.stroke'); |
---|
370 | context.strokeRect(coordsX, coordsY, coordsW, coordsH); |
---|
371 | context.fillRect(coordsX, coordsY, coordsW, coordsH); |
---|
372 | context.stroke(); |
---|
373 | context.fill(); |
---|
374 | } |
---|
375 | |
---|
376 | /** |
---|
377 | * Get the tooltip text |
---|
378 | */ |
---|
379 | if (typeof(obj.Get('chart.tooltips')) == 'function') { |
---|
380 | var text = String(obj.Get('chart.tooltips')(i)); |
---|
381 | |
---|
382 | } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[i]) == 'function') { |
---|
383 | var text = String(obj.Get('chart.tooltips')[barCoords[5]](i)); |
---|
384 | |
---|
385 | } else if (typeof(obj.Get('chart.tooltips')) == 'object' && (typeof(obj.Get('chart.tooltips')[i]) == 'string' || typeof(obj.Get('chart.tooltips')[i]) == 'number')) { |
---|
386 | var text = String(obj.Get('chart.tooltips')[i]); |
---|
387 | |
---|
388 | } else { |
---|
389 | var text = null; |
---|
390 | } |
---|
391 | |
---|
392 | if (text) { |
---|
393 | canvas.style.cursor = 'pointer'; |
---|
394 | } else { |
---|
395 | canvas.style.cursor = 'default'; |
---|
396 | } |
---|
397 | |
---|
398 | RGraph.Tooltip(canvas, obj.Get('chart.tooltips')[i], e.pageX, e.pageY, text, i); |
---|
399 | } |
---|
400 | } |
---|
401 | |
---|
402 | /** |
---|
403 | * Stop the event bubbling |
---|
404 | */ |
---|
405 | e.stopPropagation(); |
---|
406 | |
---|
407 | return false; |
---|
408 | } |
---|
409 | this.canvas.addEventListener('click', canvas_onclick_func, false); |
---|
410 | RGraph.AddEventListener(this.id, 'click', canvas_onclick_func); |
---|
411 | |
---|
412 | /** |
---|
413 | * Install the window onclick handler |
---|
414 | */ |
---|
415 | var window_onclick_func = function (){RGraph.Redraw();}; |
---|
416 | window.addEventListener('click', window_onclick_func, false); |
---|
417 | RGraph.AddEventListener('window_' + this.id, 'click', window_onclick_func); |
---|
418 | |
---|
419 | |
---|
420 | |
---|
421 | |
---|
422 | |
---|
423 | |
---|
424 | |
---|
425 | |
---|
426 | |
---|
427 | |
---|
428 | |
---|
429 | |
---|
430 | |
---|
431 | /** |
---|
432 | * Install the onmousemove event handler for the tooltips |
---|
433 | */ |
---|
434 | var canvas_onmousemove_func = function (e) |
---|
435 | { |
---|
436 | e = RGraph.FixEventObject(e); |
---|
437 | |
---|
438 | var canvas = document.getElementById(this.id); |
---|
439 | var context = canvas.getContext('2d'); |
---|
440 | var obj = canvas.__object__; |
---|
441 | |
---|
442 | /** |
---|
443 | * Get the mouse X/Y coordinates |
---|
444 | */ |
---|
445 | var mouseCoords = RGraph.getMouseXY(e); |
---|
446 | var mouseX = mouseCoords[0]; |
---|
447 | var mouseY = mouseCoords[1]; |
---|
448 | var adjust = obj.Get('chart.tooltips.coords.adjust'); |
---|
449 | |
---|
450 | /** |
---|
451 | * Loop through the bars determining if the mouse is over a bar |
---|
452 | */ |
---|
453 | for (var i=0; i<obj.coords.length; i++) { |
---|
454 | |
---|
455 | var coordsX = obj.coords[i][0]; |
---|
456 | var coordsY = obj.coords[i][1]; |
---|
457 | var coordsW = obj.coords[i][2]; |
---|
458 | var coordsH = obj.coords[i][3]; |
---|
459 | |
---|
460 | if ( |
---|
461 | mouseX >= (coordsX + adjust[0]) && |
---|
462 | mouseX <= (coordsX + coordsW + adjust[0]) && |
---|
463 | mouseY >= (coordsY + adjust[1]) && |
---|
464 | mouseY <= (coordsY + coordsH + adjust[1]) |
---|
465 | ) { |
---|
466 | if (obj.Get('chart.tooltips')[i]) { |
---|
467 | canvas.style.cursor = 'pointer'; |
---|
468 | e.stopPropagation(); |
---|
469 | } |
---|
470 | |
---|
471 | return; |
---|
472 | } |
---|
473 | } |
---|
474 | |
---|
475 | canvas.style.cursor = 'default'; |
---|
476 | |
---|
477 | /** |
---|
478 | * Stop the event bubbling |
---|
479 | */ |
---|
480 | e.stopPropagation(); |
---|
481 | |
---|
482 | return false; |
---|
483 | } |
---|
484 | this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false); |
---|
485 | RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func); |
---|
486 | |
---|
487 | |
---|
488 | |
---|
489 | |
---|
490 | |
---|
491 | |
---|
492 | |
---|
493 | |
---|
494 | |
---|
495 | |
---|
496 | |
---|
497 | |
---|
498 | |
---|
499 | } |
---|
500 | |
---|
501 | |
---|
502 | /** |
---|
503 | * Fire the RGraph ondraw event |
---|
504 | */ |
---|
505 | RGraph.FireCustomEvent(this, 'ondraw'); |
---|
506 | } |
---|
507 | |
---|
508 | |
---|
509 | /** |
---|
510 | * Draws the charts axes |
---|
511 | */ |
---|
512 | RGraph.Waterfall.prototype.DrawAxes = function () |
---|
513 | { |
---|
514 | if (this.Get('chart.noaxes')) { |
---|
515 | return; |
---|
516 | } |
---|
517 | |
---|
518 | this.context.beginPath(); |
---|
519 | this.context.strokeStyle = this.Get('chart.axis.color'); |
---|
520 | this.context.lineWidth = 1; |
---|
521 | |
---|
522 | // Draw the Y axis |
---|
523 | if (this.Get('chart.noyaxis') == false) { |
---|
524 | this.context.moveTo(this.gutterLeft, this.gutterTop); |
---|
525 | this.context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
526 | } |
---|
527 | |
---|
528 | // Draw the X axis |
---|
529 | if (this.Get('chart.noxaxis') == false) { |
---|
530 | this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
531 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); |
---|
532 | } |
---|
533 | |
---|
534 | var numYTicks = this.Get('chart.numyticks'); |
---|
535 | |
---|
536 | // Draw the Y tickmarks |
---|
537 | if (this.Get('chart.noyaxis') == false) { |
---|
538 | |
---|
539 | var yTickGap = (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / numYTicks; |
---|
540 | |
---|
541 | for (y=this.gutterTop; y < (RGraph.GetHeight(this) - this.gutterBottom); y += yTickGap) { |
---|
542 | this.context.moveTo(this.gutterLeft, y); |
---|
543 | this.context.lineTo(this.gutterLeft - 3, y); |
---|
544 | } |
---|
545 | |
---|
546 | /** |
---|
547 | * If the X axis is not being shown, draw an extra tick |
---|
548 | */ |
---|
549 | if (this.Get('chart.noxaxis')) { |
---|
550 | this.context.moveTo(this.gutterLeft - 3, RGraph.GetHeight(this) - this.gutterBottom); |
---|
551 | this.context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | |
---|
556 | // Draw the X tickmarks |
---|
557 | if (this.Get('chart.noxaxis') == false) { |
---|
558 | |
---|
559 | xTickGap = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight ) / this.data.length; |
---|
560 | |
---|
561 | yStart = RGraph.GetHeight(this) - this.gutterBottom; |
---|
562 | yEnd = (RGraph.GetHeight(this) - this.gutterBottom) + 3; |
---|
563 | |
---|
564 | for (x=this.gutterLeft + xTickGap; x<=RGraph.GetWidth(this) - this.gutterRight; x+=xTickGap) { |
---|
565 | this.context.moveTo(x, yStart); |
---|
566 | this.context.lineTo(x, yEnd); |
---|
567 | } |
---|
568 | |
---|
569 | if (this.Get('chart.noyaxis')) { |
---|
570 | this.context.moveTo(this.gutterLeft, yStart); |
---|
571 | this.context.lineTo(this.gutterLeft, yEnd); |
---|
572 | } |
---|
573 | } |
---|
574 | |
---|
575 | /** |
---|
576 | * If the Y axis is not being shown, draw an extra tick |
---|
577 | */ |
---|
578 | if (this.Get('chart.noyaxis') && this.Get('chart.noxaxis') == false) { |
---|
579 | this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
580 | this.context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom + 3); |
---|
581 | } |
---|
582 | |
---|
583 | this.context.stroke(); |
---|
584 | } |
---|
585 | |
---|
586 | |
---|
587 | /** |
---|
588 | * Draws the labels for the graph |
---|
589 | */ |
---|
590 | RGraph.Waterfall.prototype.DrawLabels = function () |
---|
591 | { |
---|
592 | var context = this.context; |
---|
593 | var numYLabels = 5; |
---|
594 | var interval = this.grapharea / numYLabels; |
---|
595 | var font = this.Get('chart.text.font'); |
---|
596 | var size = this.Get('chart.text.size'); |
---|
597 | var color = this.Get('chart.text.color'); |
---|
598 | var units_pre = this.Get('chart.units.pre'); |
---|
599 | var units_post = this.Get('chart.units.post'); |
---|
600 | |
---|
601 | this.context.beginPath(); |
---|
602 | this.context.fillStyle = color; |
---|
603 | |
---|
604 | /** |
---|
605 | * First, draw the Y labels |
---|
606 | */ |
---|
607 | if (this.Get('chart.ylabels')) { |
---|
608 | for (var i=1; i<=numYLabels; ++i) { |
---|
609 | |
---|
610 | RGraph.Text(context, |
---|
611 | font, |
---|
612 | size, |
---|
613 | this.gutterLeft - 5, |
---|
614 | this.canvas.height - this.gutterBottom - (i * interval), |
---|
615 | RGraph.number_format(this, this.scale[i - 1], units_pre, units_post), |
---|
616 | 'center', |
---|
617 | 'right'); |
---|
618 | |
---|
619 | } |
---|
620 | } |
---|
621 | |
---|
622 | |
---|
623 | |
---|
624 | /** |
---|
625 | * Now, draw the X labels |
---|
626 | */ |
---|
627 | if (this.Get('chart.labels').length > 0) { |
---|
628 | |
---|
629 | // Recalculate the interval for the X labels |
---|
630 | interval = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight) / this.Get('chart.labels').length; |
---|
631 | |
---|
632 | var halign = 'center'; |
---|
633 | var angle = this.Get('chart.text.angle'); |
---|
634 | |
---|
635 | if (angle) { |
---|
636 | halign = 'right'; |
---|
637 | angle *= -1; |
---|
638 | } |
---|
639 | |
---|
640 | for (var i=0; i<this.Get('chart.labels').length; ++i) { |
---|
641 | |
---|
642 | var labels = this.Get('chart.labels'); |
---|
643 | |
---|
644 | RGraph.Text(context, |
---|
645 | font, |
---|
646 | size, |
---|
647 | this.gutterLeft - 5 + (i * interval) + (interval / 2),// X |
---|
648 | RGraph.GetHeight(this) - this.gutterBottom + 5 + this.halfTextHeight, // Y |
---|
649 | labels[i], |
---|
650 | 'center', |
---|
651 | halign, |
---|
652 | null, |
---|
653 | angle); |
---|
654 | |
---|
655 | } |
---|
656 | } |
---|
657 | |
---|
658 | this.context.stroke(); |
---|
659 | this.context.fill(); |
---|
660 | } |
---|
661 | |
---|
662 | |
---|
663 | /** |
---|
664 | * Draws the bars on to the chart |
---|
665 | */ |
---|
666 | RGraph.Waterfall.prototype.Drawbars = function () |
---|
667 | { |
---|
668 | var context = this.context; |
---|
669 | var canvas = this.canvas; |
---|
670 | var hmargin = this.Get('chart.hmargin'); |
---|
671 | var runningTotal = 0; |
---|
672 | |
---|
673 | |
---|
674 | for (var i=0; i<this.data.length; ++i) { |
---|
675 | context.beginPath(); |
---|
676 | context.strokeStyle = this.Get('chart.strokestyle'); |
---|
677 | |
---|
678 | var isLast = (i == (this.data.length - 1)); |
---|
679 | var x = this.gutterLeft + hmargin + ((this.graphwidth / this.data.length) * i); |
---|
680 | var y = this.gutterTop + this.grapharea - (i == 0 ? ((this.data[0] / this.max) * this.grapharea) : (this.data[i] > 0 ? ((runningTotal + this.data[i]) / this.max) * this.grapharea : (runningTotal / this.max) * this.grapharea)); |
---|
681 | var w = ((RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight) / this.data.length) - (2 * this.Get('chart.hmargin')); |
---|
682 | var h = (Math.abs(this.data[i]) / this.max) * this.grapharea; |
---|
683 | |
---|
684 | // Color |
---|
685 | context.fillStyle = this.data[i] >= 0 ? this.Get('chart.colors')[0] : this.Get('chart.colors')[1]; |
---|
686 | |
---|
687 | // Last item? Change to the third color |
---|
688 | if (isLast && this.Get('chart.total')) { |
---|
689 | context.fillStyle = this.Get('chart.colors')[2]; |
---|
690 | y = this.gutterTop + this.grapharea - h; |
---|
691 | } |
---|
692 | |
---|
693 | if (this.Get('chart.shadow')) { |
---|
694 | RGraph.SetShadow(this, this.Get('chart.shadow.color'), this.Get('chart.shadow.offsetx'), this.Get('chart.shadow.offsety'), this.Get('chart.shadow.blur')); |
---|
695 | } else { |
---|
696 | RGraph.NoShadow(this); |
---|
697 | } |
---|
698 | |
---|
699 | context.strokeRect(x, y, w, h); |
---|
700 | context.fillRect(x, y, w, h); |
---|
701 | |
---|
702 | this.coords.push([x, y, w, h]); |
---|
703 | |
---|
704 | runningTotal += this.data[i]; |
---|
705 | |
---|
706 | context.stroke(); |
---|
707 | context.fill(); |
---|
708 | } |
---|
709 | |
---|
710 | RGraph.NoShadow(this); |
---|
711 | |
---|
712 | for (var i=1; i<this.coords.length; ++i) { |
---|
713 | context.strokeStyle = 'gray'; |
---|
714 | context.beginPath(); |
---|
715 | if (this.data[i - 1] > 0) { |
---|
716 | context.moveTo(this.coords[i - 1][0] + this.coords[i - 1][2], this.coords[i - 1][1]); |
---|
717 | context.lineTo(this.coords[i - 1][0] + this.coords[i - 1][2] + (2 * hmargin), this.coords[i - 1][1]); |
---|
718 | } else { |
---|
719 | context.moveTo(this.coords[i - 1][0] + this.coords[i - 1][2], this.coords[i - 1][1] + this.coords[i - 1][3]); |
---|
720 | context.lineTo(this.coords[i - 1][0] + this.coords[i - 1][2] + (2 * hmargin), this.coords[i - 1][1] + this.coords[i - 1][3]); |
---|
721 | } |
---|
722 | context.stroke(); |
---|
723 | } |
---|
724 | } |
---|
725 | |
---|
726 | |
---|