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 line chart constructor |
---|
19 | * |
---|
20 | * @param object canvas The cxanvas object |
---|
21 | * @param array data The chart data |
---|
22 | * @param array ... Other lines to plot |
---|
23 | */ |
---|
24 | RGraph.Line = function (id) |
---|
25 | { |
---|
26 | // Get the canvas and context objects |
---|
27 | this.id = id; |
---|
28 | this.canvas = document.getElementById(id); |
---|
29 | this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; |
---|
30 | this.canvas.__object__ = this; |
---|
31 | this.type = 'line'; |
---|
32 | this.max = 0; |
---|
33 | this.coords = []; |
---|
34 | this.coords2 = []; |
---|
35 | this.coords.key = []; |
---|
36 | this.hasnegativevalues = false; |
---|
37 | this.isRGraph = true; |
---|
38 | |
---|
39 | |
---|
40 | |
---|
41 | /** |
---|
42 | * Compatibility with older browsers |
---|
43 | */ |
---|
44 | RGraph.OldBrowserCompat(this.context); |
---|
45 | |
---|
46 | |
---|
47 | // Various config type stuff |
---|
48 | this.properties = { |
---|
49 | 'chart.background.barcolor1': 'rgba(0,0,0,0)', |
---|
50 | 'chart.background.barcolor2': 'rgba(0,0,0,0)', |
---|
51 | 'chart.background.grid': 1, |
---|
52 | 'chart.background.grid.width': 1, |
---|
53 | 'chart.background.grid.hsize': 25, |
---|
54 | 'chart.background.grid.vsize': 25, |
---|
55 | 'chart.background.grid.color': '#ddd', |
---|
56 | 'chart.background.grid.vlines': true, |
---|
57 | 'chart.background.grid.hlines': true, |
---|
58 | 'chart.background.grid.border': true, |
---|
59 | 'chart.background.grid.autofit': false, |
---|
60 | 'chart.background.grid.autofit.align': false, |
---|
61 | 'chart.background.grid.autofit.numhlines': 7, |
---|
62 | 'chart.background.grid.autofit.numvlines': 20, |
---|
63 | 'chart.background.hbars': null, |
---|
64 | 'chart.background.image': null, |
---|
65 | 'chart.labels': null, |
---|
66 | 'chart.labels.ingraph': null, |
---|
67 | 'chart.labels.above': false, |
---|
68 | 'chart.labels.above.size': 8, |
---|
69 | 'chart.xtickgap': 20, |
---|
70 | 'chart.smallxticks': 3, |
---|
71 | 'chart.largexticks': 5, |
---|
72 | 'chart.ytickgap': 20, |
---|
73 | 'chart.smallyticks': 3, |
---|
74 | 'chart.largeyticks': 5, |
---|
75 | 'chart.linewidth': 1.01, |
---|
76 | 'chart.colors': ['red', '#0f0', '#00f', '#f0f', '#ff0', '#0ff'], |
---|
77 | 'chart.hmargin': 0, |
---|
78 | 'chart.tickmarks.dot.color': 'white', |
---|
79 | 'chart.tickmarks': null, |
---|
80 | 'chart.tickmarks.linewidth': null, |
---|
81 | 'chart.ticksize': 3, |
---|
82 | 'chart.gutter.left': 25, |
---|
83 | 'chart.gutter.right': 25, |
---|
84 | 'chart.gutter.top': 25, |
---|
85 | 'chart.gutter.bottom': 25, |
---|
86 | 'chart.tickdirection': -1, |
---|
87 | 'chart.yaxispoints': 5, |
---|
88 | 'chart.fillstyle': null, |
---|
89 | 'chart.xaxispos': 'bottom', |
---|
90 | 'chart.yaxispos': 'left', |
---|
91 | 'chart.xticks': null, |
---|
92 | 'chart.text.size': 10, |
---|
93 | 'chart.text.angle': 0, |
---|
94 | 'chart.text.color': 'black', |
---|
95 | 'chart.text.font': 'Verdana', |
---|
96 | 'chart.ymin': null, |
---|
97 | 'chart.ymax': null, |
---|
98 | 'chart.title': '', |
---|
99 | 'chart.title.background': null, |
---|
100 | 'chart.title.hpos': null, |
---|
101 | 'chart.title.vpos': 0.5, |
---|
102 | 'chart.title.xaxis': '', |
---|
103 | 'chart.title.yaxis': '', |
---|
104 | 'chart.title.xaxis.pos': 0.25, |
---|
105 | 'chart.title.yaxis.pos': 0.25, |
---|
106 | 'chart.shadow': false, |
---|
107 | 'chart.shadow.offsetx': 2, |
---|
108 | 'chart.shadow.offsety': 2, |
---|
109 | 'chart.shadow.blur': 3, |
---|
110 | 'chart.shadow.color': 'rgba(0,0,0,0.5)', |
---|
111 | 'chart.tooltips': null, |
---|
112 | 'chart.tooltips.effect': 'fade', |
---|
113 | 'chart.tooltips.css.class': 'RGraph_tooltip', |
---|
114 | 'chart.tooltips.highlight': true, |
---|
115 | 'chart.highlight.stroke': '#999', |
---|
116 | 'chart.highlight.fill': 'white', |
---|
117 | 'chart.stepped': false, |
---|
118 | 'chart.key': [], |
---|
119 | 'chart.key.background': 'white', |
---|
120 | 'chart.key.position': 'graph', |
---|
121 | 'chart.key.halign': null, |
---|
122 | 'chart.key.shadow': false, |
---|
123 | 'chart.key.shadow.color': '#666', |
---|
124 | 'chart.key.shadow.blur': 3, |
---|
125 | 'chart.key.shadow.offsetx': 2, |
---|
126 | 'chart.key.shadow.offsety': 2, |
---|
127 | 'chart.key.position.gutter.boxed': true, |
---|
128 | 'chart.key.position.x': null, |
---|
129 | 'chart.key.position.y': null, |
---|
130 | 'chart.key.color.shape': 'square', |
---|
131 | 'chart.key.rounded': true, |
---|
132 | 'chart.key.linewidth': 1, |
---|
133 | 'chart.key.interactive': false, |
---|
134 | 'chart.contextmenu': null, |
---|
135 | 'chart.ylabels': true, |
---|
136 | 'chart.ylabels.count': 5, |
---|
137 | 'chart.ylabels.inside': false, |
---|
138 | 'chart.ylabels.invert': false, |
---|
139 | 'chart.xlabels.inside': false, |
---|
140 | 'chart.xlabels.inside.color': 'rgba(255,255,255,0.5)', |
---|
141 | 'chart.noaxes': false, |
---|
142 | 'chart.noyaxis': false, |
---|
143 | 'chart.noxaxis': false, |
---|
144 | 'chart.noendxtick': false, |
---|
145 | 'chart.units.post': '', |
---|
146 | 'chart.units.pre': '', |
---|
147 | 'chart.scale.decimals': null, |
---|
148 | 'chart.scale.point': '.', |
---|
149 | 'chart.scale.thousand': ',', |
---|
150 | 'chart.crosshairs': false, |
---|
151 | 'chart.crosshairs.color': '#333', |
---|
152 | 'chart.annotatable': false, |
---|
153 | 'chart.annotate.color': 'black', |
---|
154 | 'chart.axesontop': false, |
---|
155 | 'chart.filled': false, |
---|
156 | 'chart.filled.range': false, |
---|
157 | 'chart.filled.accumulative': true, |
---|
158 | 'chart.variant': null, |
---|
159 | 'chart.axis.color': 'black', |
---|
160 | 'chart.zoom.factor': 1.5, |
---|
161 | 'chart.zoom.fade.in': true, |
---|
162 | 'chart.zoom.fade.out': true, |
---|
163 | 'chart.zoom.hdir': 'right', |
---|
164 | 'chart.zoom.vdir': 'down', |
---|
165 | 'chart.zoom.frames': 15, |
---|
166 | 'chart.zoom.delay': 33, |
---|
167 | 'chart.zoom.shadow': true, |
---|
168 | 'chart.zoom.mode': 'canvas', |
---|
169 | 'chart.zoom.thumbnail.width': 75, |
---|
170 | 'chart.zoom.thumbnail.height': 75, |
---|
171 | 'chart.zoom.background': true, |
---|
172 | 'chart.zoom.action': 'zoom', |
---|
173 | 'chart.backdrop': false, |
---|
174 | 'chart.backdrop.size': 30, |
---|
175 | 'chart.backdrop.alpha': 0.2, |
---|
176 | 'chart.resizable': false, |
---|
177 | 'chart.resize.handle.adjust': [0,0], |
---|
178 | 'chart.resize.handle.background': null, |
---|
179 | 'chart.adjustable': false, |
---|
180 | 'chart.noredraw': false, |
---|
181 | 'chart.outofbounds': false, |
---|
182 | 'chart.chromefix': true, |
---|
183 | 'chart.draw.delegate': null |
---|
184 | } |
---|
185 | |
---|
186 | /** |
---|
187 | * Change null arguments to empty arrays |
---|
188 | */ |
---|
189 | for (var i=1; i<arguments.length; ++i) { |
---|
190 | if (typeof(arguments[i]) == 'null' || !arguments[i]) { |
---|
191 | arguments[i] = []; |
---|
192 | } |
---|
193 | } |
---|
194 | |
---|
195 | |
---|
196 | /** |
---|
197 | * Store the original data. Thiss also allows for giving arguments as one big array. |
---|
198 | */ |
---|
199 | this.original_data = []; |
---|
200 | |
---|
201 | for (var i=1; i<arguments.length; ++i) { |
---|
202 | if (arguments[1] && typeof(arguments[1]) == 'object' && arguments[1][0] && typeof(arguments[1][0]) == 'object' && arguments[1][0].length) { |
---|
203 | |
---|
204 | var tmp = []; |
---|
205 | |
---|
206 | for (var i=0; i<arguments[1].length; ++i) { |
---|
207 | tmp[i] = RGraph.array_clone(arguments[1][i]); |
---|
208 | } |
---|
209 | |
---|
210 | for (var j=0; j<tmp.length; ++j) { |
---|
211 | this.original_data[j] = RGraph.array_clone(tmp[j]); |
---|
212 | } |
---|
213 | |
---|
214 | } else { |
---|
215 | this.original_data[i - 1] = RGraph.array_clone(arguments[i]); |
---|
216 | } |
---|
217 | } |
---|
218 | |
---|
219 | // Check for support |
---|
220 | if (!this.canvas) { |
---|
221 | alert('[LINE] Fatal error: no canvas support'); |
---|
222 | return; |
---|
223 | } |
---|
224 | |
---|
225 | /** |
---|
226 | * Store the data here as one big array |
---|
227 | */ |
---|
228 | this.data_arr = []; |
---|
229 | |
---|
230 | for (var i=1; i<arguments.length; ++i) { |
---|
231 | for (var j=0; j<arguments[i].length; ++j) { |
---|
232 | this.data_arr.push(arguments[i][j]); |
---|
233 | } |
---|
234 | } |
---|
235 | |
---|
236 | |
---|
237 | /** |
---|
238 | * Set the .getShape commonly named method |
---|
239 | */ |
---|
240 | this.getShape = this.getPoint; |
---|
241 | } |
---|
242 | |
---|
243 | |
---|
244 | /** |
---|
245 | * An all encompassing accessor |
---|
246 | * |
---|
247 | * @param string name The name of the property |
---|
248 | * @param mixed value The value of the property |
---|
249 | */ |
---|
250 | RGraph.Line.prototype.Set = function (name, value) |
---|
251 | { |
---|
252 | // Consolidate the tooltips |
---|
253 | if (name == 'chart.tooltips') { |
---|
254 | |
---|
255 | var tooltips = []; |
---|
256 | |
---|
257 | for (var i=1; i<arguments.length; i++) { |
---|
258 | if (typeof(arguments[i]) == 'object' && arguments[i][0]) { |
---|
259 | for (var j=0; j<arguments[i].length; j++) { |
---|
260 | tooltips.push(arguments[i][j]); |
---|
261 | } |
---|
262 | |
---|
263 | } else if (typeof(arguments[i]) == 'function') { |
---|
264 | tooltips = arguments[i]; |
---|
265 | |
---|
266 | } else { |
---|
267 | tooltips.push(arguments[i]); |
---|
268 | } |
---|
269 | } |
---|
270 | |
---|
271 | // Because "value" is used further down at the end of this function, set it to the expanded array os tooltips |
---|
272 | value = tooltips; |
---|
273 | } |
---|
274 | |
---|
275 | /** |
---|
276 | * Reverse the tickmarks to make them correspond to the right line |
---|
277 | */ |
---|
278 | if (name == 'chart.tickmarks' && typeof(value) == 'object' && value) { |
---|
279 | value = RGraph.array_reverse(value); |
---|
280 | } |
---|
281 | |
---|
282 | /** |
---|
283 | * Inverted Y axis should show the bottom end of the scale |
---|
284 | */ |
---|
285 | if (name == 'chart.ylabels.invert' && value && this.Get('chart.ymin') == null) { |
---|
286 | this.Set('chart.ymin', 0); |
---|
287 | } |
---|
288 | |
---|
289 | /** |
---|
290 | * If (buggy) Chrome and the linewidth is 1, change it to 1.01 |
---|
291 | */ |
---|
292 | if (name == 'chart.linewidth' && navigator.userAgent.match(/Chrome/)) { |
---|
293 | if (value == 1) { |
---|
294 | value = 1.01; |
---|
295 | |
---|
296 | } else if (RGraph.is_array(value)) { |
---|
297 | for (var i=0; i<value.length; ++i) { |
---|
298 | if (typeof(value[i]) == 'number' && value[i] == 1) { |
---|
299 | value[i] = 1.01; |
---|
300 | } |
---|
301 | } |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | /** |
---|
306 | * Check for xaxispos |
---|
307 | */ |
---|
308 | if (name == 'chart.xaxispos' ) { |
---|
309 | if (value != 'bottom' && value != 'center' && value != 'top') { |
---|
310 | alert('[LINE] (' + this.id + ') chart.xaxispos should be top, center or bottom. Tried to set it to: ' + value + ' Changing it to center'); |
---|
311 | value = 'center'; |
---|
312 | } |
---|
313 | } |
---|
314 | |
---|
315 | this.properties[name] = value; |
---|
316 | } |
---|
317 | |
---|
318 | |
---|
319 | /** |
---|
320 | * An all encompassing accessor |
---|
321 | * |
---|
322 | * @param string name The name of the property |
---|
323 | */ |
---|
324 | RGraph.Line.prototype.Get = function (name) |
---|
325 | { |
---|
326 | return this.properties[name]; |
---|
327 | } |
---|
328 | |
---|
329 | |
---|
330 | /** |
---|
331 | * The function you call to draw the line chart |
---|
332 | */ |
---|
333 | RGraph.Line.prototype.Draw = function () |
---|
334 | { |
---|
335 | // MUST be the first thing done! |
---|
336 | if (typeof(this.Get('chart.background.image')) == 'string' && !this.__background_image__) { |
---|
337 | RGraph.DrawBackgroundImage(this); |
---|
338 | return; |
---|
339 | } |
---|
340 | |
---|
341 | /** |
---|
342 | * Fire the onbeforedraw event |
---|
343 | */ |
---|
344 | RGraph.FireCustomEvent(this, 'onbeforedraw'); |
---|
345 | |
---|
346 | /** |
---|
347 | * Clear all of this canvases event handlers (the ones installed by RGraph) |
---|
348 | */ |
---|
349 | RGraph.ClearEventListeners(this.id); |
---|
350 | |
---|
351 | /** |
---|
352 | * This is new in May 2011 and facilitates indiviual gutter settings, |
---|
353 | * eg chart.gutter.left |
---|
354 | */ |
---|
355 | this.gutterLeft = this.Get('chart.gutter.left'); |
---|
356 | this.gutterRight = this.Get('chart.gutter.right'); |
---|
357 | this.gutterTop = this.Get('chart.gutter.top'); |
---|
358 | this.gutterBottom = this.Get('chart.gutter.bottom'); |
---|
359 | |
---|
360 | |
---|
361 | /** |
---|
362 | * Check for Chrome 6 and shadow |
---|
363 | * |
---|
364 | * TODO Remove once it's been fixed (for a while) |
---|
365 | * SEARCH TAGS: CHROME FIX SHADOW BUG |
---|
366 | */ |
---|
367 | if ( this.Get('chart.shadow') |
---|
368 | && navigator.userAgent.match(/Chrome/) |
---|
369 | && this.Get('chart.linewidth') <= 1 |
---|
370 | && this.Get('chart.chromefix') |
---|
371 | && this.Get('chart.shadow.blur') > 0) { |
---|
372 | alert('[RGRAPH WARNING] Chrome has a shadow bug, meaning you should increase the linewidth to at least 1.01'); |
---|
373 | } |
---|
374 | |
---|
375 | |
---|
376 | // Reset the data back to that which was initially supplied |
---|
377 | this.data = RGraph.array_clone(this.original_data); |
---|
378 | |
---|
379 | |
---|
380 | // Reset the max value |
---|
381 | this.max = 0; |
---|
382 | |
---|
383 | /** |
---|
384 | * Reverse the datasets so that the data and the labels tally |
---|
385 | */ |
---|
386 | this.data = RGraph.array_reverse(this.data); |
---|
387 | |
---|
388 | if (this.Get('chart.filled') && !this.Get('chart.filled.range') && this.data.length > 1 && this.Get('chart.filled.accumulative')) { |
---|
389 | |
---|
390 | var accumulation = []; |
---|
391 | |
---|
392 | for (var set=0; set<this.data.length; ++set) { |
---|
393 | for (var point=0; point<this.data[set].length; ++point) { |
---|
394 | this.data[set][point] = Number(accumulation[point] ? accumulation[point] : 0) + this.data[set][point]; |
---|
395 | accumulation[point] = this.data[set][point]; |
---|
396 | } |
---|
397 | } |
---|
398 | } |
---|
399 | |
---|
400 | /** |
---|
401 | * Get the maximum Y scale value |
---|
402 | */ |
---|
403 | if (this.Get('chart.ymax')) { |
---|
404 | |
---|
405 | this.max = this.Get('chart.ymax'); |
---|
406 | this.min = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0; |
---|
407 | |
---|
408 | this.scale = [ |
---|
409 | ( ((this.max - this.min) * (1/5)) + this.min).toFixed(this.Get('chart.scale.decimals')), |
---|
410 | ( ((this.max - this.min) * (2/5)) + this.min).toFixed(this.Get('chart.scale.decimals')), |
---|
411 | ( ((this.max - this.min) * (3/5)) + this.min).toFixed(this.Get('chart.scale.decimals')), |
---|
412 | ( ((this.max - this.min) * (4/5)) + this.min).toFixed(this.Get('chart.scale.decimals')), |
---|
413 | this.max.toFixed(this.Get('chart.scale.decimals')) |
---|
414 | ]; |
---|
415 | |
---|
416 | // Check for negative values |
---|
417 | if (!this.Get('chart.outofbounds')) { |
---|
418 | for (dataset=0; dataset<this.data.length; ++dataset) { |
---|
419 | for (var datapoint=0; datapoint<this.data[dataset].length; datapoint++) { |
---|
420 | |
---|
421 | // Check for negative values |
---|
422 | this.hasnegativevalues = (this.data[dataset][datapoint] < 0) || this.hasnegativevalues; |
---|
423 | } |
---|
424 | } |
---|
425 | } |
---|
426 | |
---|
427 | } else { |
---|
428 | |
---|
429 | this.min = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0; |
---|
430 | |
---|
431 | // Work out the max Y value |
---|
432 | for (dataset=0; dataset<this.data.length; ++dataset) { |
---|
433 | for (var datapoint=0; datapoint<this.data[dataset].length; datapoint++) { |
---|
434 | |
---|
435 | this.max = Math.max(this.max, this.data[dataset][datapoint] ? Math.abs(parseFloat(this.data[dataset][datapoint])) : 0); |
---|
436 | |
---|
437 | // Check for negative values |
---|
438 | if (!this.Get('chart.outofbounds')) { |
---|
439 | this.hasnegativevalues = (this.data[dataset][datapoint] < 0) || this.hasnegativevalues; |
---|
440 | } |
---|
441 | } |
---|
442 | } |
---|
443 | |
---|
444 | // 20th April 2009 - moved out of the above loop |
---|
445 | this.scale = RGraph.getScale(Math.abs(parseFloat(this.max)), this); |
---|
446 | this.max = this.scale[4] ? this.scale[4] : 0; |
---|
447 | |
---|
448 | if (this.Get('chart.ymin')) { |
---|
449 | this.scale[0] = ((this.max - this.Get('chart.ymin')) * (1/5)) + this.Get('chart.ymin'); |
---|
450 | this.scale[1] = ((this.max - this.Get('chart.ymin')) * (2/5)) + this.Get('chart.ymin'); |
---|
451 | this.scale[2] = ((this.max - this.Get('chart.ymin')) * (3/5)) + this.Get('chart.ymin'); |
---|
452 | this.scale[3] = ((this.max - this.Get('chart.ymin')) * (4/5)) + this.Get('chart.ymin'); |
---|
453 | this.scale[4] = ((this.max - this.Get('chart.ymin')) * (5/5)) + this.Get('chart.ymin'); |
---|
454 | } |
---|
455 | |
---|
456 | if (typeof(this.Get('chart.scale.decimals')) == 'number') { |
---|
457 | this.scale[0] = Number(this.scale[0]).toFixed(this.Get('chart.scale.decimals')); |
---|
458 | this.scale[1] = Number(this.scale[1]).toFixed(this.Get('chart.scale.decimals')); |
---|
459 | this.scale[2] = Number(this.scale[2]).toFixed(this.Get('chart.scale.decimals')); |
---|
460 | this.scale[3] = Number(this.scale[3]).toFixed(this.Get('chart.scale.decimals')); |
---|
461 | this.scale[4] = Number(this.scale[4]).toFixed(this.Get('chart.scale.decimals')); |
---|
462 | } |
---|
463 | } |
---|
464 | |
---|
465 | /** |
---|
466 | * Setup the context menu if required |
---|
467 | */ |
---|
468 | if (this.Get('chart.contextmenu')) { |
---|
469 | RGraph.ShowContext(this); |
---|
470 | } |
---|
471 | |
---|
472 | /** |
---|
473 | * Reset the coords array otherwise it will keep growing |
---|
474 | */ |
---|
475 | this.coords = []; |
---|
476 | |
---|
477 | /** |
---|
478 | * Work out a few things. They need to be here because they depend on things you can change before you |
---|
479 | * call Draw() but after you instantiate the object |
---|
480 | */ |
---|
481 | this.grapharea = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom; |
---|
482 | this.halfgrapharea = this.grapharea / 2; |
---|
483 | this.halfTextHeight = this.Get('chart.text.size') / 2; |
---|
484 | |
---|
485 | // Check the combination of the X axis position and if there any negative values |
---|
486 | // |
---|
487 | // 19th Dec 2010 - removed for Opera since it can be reported incorrectly whn there |
---|
488 | // are multiple graphs on the page |
---|
489 | if (this.Get('chart.xaxispos') == 'bottom' && this.hasnegativevalues && navigator.userAgent.indexOf('Opera') == -1) { |
---|
490 | alert('[LINE] You have negative values and the X axis is at the bottom. This is not good...'); |
---|
491 | } |
---|
492 | |
---|
493 | if (this.Get('chart.variant') == '3d') { |
---|
494 | RGraph.Draw3DAxes(this); |
---|
495 | } |
---|
496 | |
---|
497 | // Progressively Draw the chart |
---|
498 | RGraph.background.Draw(this); |
---|
499 | |
---|
500 | /** |
---|
501 | * Draw any horizontal bars that have been defined |
---|
502 | */ |
---|
503 | if (this.Get('chart.background.hbars') && this.Get('chart.background.hbars').length > 0) { |
---|
504 | RGraph.DrawBars(this); |
---|
505 | } |
---|
506 | |
---|
507 | if (this.Get('chart.axesontop') == false) { |
---|
508 | this.DrawAxes(); |
---|
509 | } |
---|
510 | |
---|
511 | /** |
---|
512 | * Handle the appropriate shadow color. This now facilitates an array of differing |
---|
513 | * shadow colors |
---|
514 | */ |
---|
515 | var shadowColor = this.Get('chart.shadow.color'); |
---|
516 | |
---|
517 | if (typeof(shadowColor) == 'object') { |
---|
518 | shadowColor = RGraph.array_reverse(RGraph.array_clone(this.Get('chart.shadow.color'))); |
---|
519 | } |
---|
520 | |
---|
521 | |
---|
522 | for (var i=(this.data.length - 1), j=0; i>=0; i--, j++) { |
---|
523 | |
---|
524 | this.context.beginPath(); |
---|
525 | |
---|
526 | /** |
---|
527 | * Turn on the shadow if required |
---|
528 | */ |
---|
529 | if (this.Get('chart.shadow') && !this.Get('chart.filled')) { |
---|
530 | |
---|
531 | /** |
---|
532 | * Accommodate an array of shadow colors as well as a single string |
---|
533 | */ |
---|
534 | if (typeof(shadowColor) == 'object' && shadowColor[i - 1]) { |
---|
535 | this.context.shadowColor = shadowColor[i]; |
---|
536 | } else if (typeof(shadowColor) == 'object') { |
---|
537 | this.context.shadowColor = shadowColor[0]; |
---|
538 | } else if (typeof(shadowColor) == 'string') { |
---|
539 | this.context.shadowColor = shadowColor; |
---|
540 | } |
---|
541 | |
---|
542 | this.context.shadowBlur = this.Get('chart.shadow.blur'); |
---|
543 | this.context.shadowOffsetX = this.Get('chart.shadow.offsetx'); |
---|
544 | this.context.shadowOffsetY = this.Get('chart.shadow.offsety'); |
---|
545 | |
---|
546 | } else if (this.Get('chart.filled') && this.Get('chart.shadow')) { |
---|
547 | alert('[LINE] Shadows are not permitted when the line is filled'); |
---|
548 | } |
---|
549 | |
---|
550 | /** |
---|
551 | * Draw the line |
---|
552 | */ |
---|
553 | |
---|
554 | if (this.Get('chart.fillstyle')) { |
---|
555 | if (typeof(this.Get('chart.fillstyle')) == 'object' && this.Get('chart.fillstyle')[j]) { |
---|
556 | var fill = this.Get('chart.fillstyle')[j]; |
---|
557 | |
---|
558 | } else if (typeof(this.Get('chart.fillstyle')) == 'string') { |
---|
559 | var fill = this.Get('chart.fillstyle'); |
---|
560 | |
---|
561 | } else { |
---|
562 | alert('[LINE] Warning: chart.fillstyle must be either a string or an array with the same number of elements as you have sets of data'); |
---|
563 | } |
---|
564 | } else if (this.Get('chart.filled')) { |
---|
565 | var fill = this.Get('chart.colors')[j]; |
---|
566 | |
---|
567 | } else { |
---|
568 | var fill = null; |
---|
569 | } |
---|
570 | |
---|
571 | /** |
---|
572 | * Figure out the tickmark to use |
---|
573 | */ |
---|
574 | if (this.Get('chart.tickmarks') && typeof(this.Get('chart.tickmarks')) == 'object') { |
---|
575 | var tickmarks = this.Get('chart.tickmarks')[i]; |
---|
576 | } else if (this.Get('chart.tickmarks') && typeof(this.Get('chart.tickmarks')) == 'string') { |
---|
577 | var tickmarks = this.Get('chart.tickmarks'); |
---|
578 | } else if (this.Get('chart.tickmarks') && typeof(this.Get('chart.tickmarks')) == 'function') { |
---|
579 | var tickmarks = this.Get('chart.tickmarks'); |
---|
580 | } else { |
---|
581 | var tickmarks = null; |
---|
582 | } |
---|
583 | |
---|
584 | |
---|
585 | this.DrawLine(this.data[i], |
---|
586 | this.Get('chart.colors')[j], |
---|
587 | fill, |
---|
588 | this.GetLineWidth(j), |
---|
589 | tickmarks, |
---|
590 | this.data.length - i - 1); |
---|
591 | |
---|
592 | this.context.stroke(); |
---|
593 | } |
---|
594 | |
---|
595 | |
---|
596 | |
---|
597 | |
---|
598 | |
---|
599 | |
---|
600 | |
---|
601 | |
---|
602 | |
---|
603 | |
---|
604 | |
---|
605 | |
---|
606 | |
---|
607 | /** |
---|
608 | * If tooltips are defined, handle them |
---|
609 | */ |
---|
610 | if (this.Get('chart.tooltips') && (this.Get('chart.tooltips').length || typeof(this.Get('chart.tooltips')) == 'function')) { |
---|
611 | |
---|
612 | // Need to register this object for redrawing |
---|
613 | if (this.Get('chart.tooltips.highlight')) { |
---|
614 | RGraph.Register(this); |
---|
615 | } |
---|
616 | |
---|
617 | canvas_onmousemove_func = function (e) |
---|
618 | { |
---|
619 | e = RGraph.FixEventObject(e); |
---|
620 | |
---|
621 | var canvas = e.target; |
---|
622 | var context = canvas.getContext('2d'); |
---|
623 | var obj = canvas.__object__; |
---|
624 | var point = obj.getPoint(e); |
---|
625 | |
---|
626 | if (obj.Get('chart.tooltips.highlight')) { |
---|
627 | RGraph.Register(obj); |
---|
628 | } |
---|
629 | |
---|
630 | if ( point |
---|
631 | && typeof(point[0]) == 'object' |
---|
632 | && typeof(point[1]) == 'number' |
---|
633 | && typeof(point[2]) == 'number' |
---|
634 | && typeof(point[3]) == 'number' |
---|
635 | ) { |
---|
636 | |
---|
637 | // point[0] is the graph object |
---|
638 | var xCoord = point[1]; |
---|
639 | var yCoord = point[2]; |
---|
640 | var idx = point[3]; |
---|
641 | |
---|
642 | if ((obj.Get('chart.tooltips')[idx] || typeof(obj.Get('chart.tooltips')) == 'function')) { |
---|
643 | |
---|
644 | // Get the tooltip text |
---|
645 | if (typeof(obj.Get('chart.tooltips')) == 'function') { |
---|
646 | var text = obj.Get('chart.tooltips')(idx); |
---|
647 | |
---|
648 | } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[idx]) == 'function') { |
---|
649 | var text = obj.Get('chart.tooltips')[idx](idx); |
---|
650 | |
---|
651 | } else if (typeof(obj.Get('chart.tooltips')) == 'object') { |
---|
652 | var text = String(obj.Get('chart.tooltips')[idx]); |
---|
653 | } else { |
---|
654 | var text = ''; |
---|
655 | } |
---|
656 | |
---|
657 | |
---|
658 | // No tooltip text - do nada |
---|
659 | if (text.match(/^id:(.*)$/) && RGraph.getTooltipText(text).substring(0,3) == 'id:') { |
---|
660 | return; |
---|
661 | } |
---|
662 | |
---|
663 | // Chnage the pointer to a hand |
---|
664 | canvas.style.cursor = 'pointer'; |
---|
665 | |
---|
666 | /** |
---|
667 | * If the tooltip is the same one as is currently visible (going by the array index), don't do squat and return. |
---|
668 | */ |
---|
669 | if ( RGraph.Registry.Get('chart.tooltip') |
---|
670 | && RGraph.Registry.Get('chart.tooltip').__index__ == idx |
---|
671 | && RGraph.Registry.Get('chart.tooltip').__canvas__.id == canvas.id) { |
---|
672 | |
---|
673 | return; |
---|
674 | } |
---|
675 | |
---|
676 | /** |
---|
677 | * Redraw the graph |
---|
678 | */ |
---|
679 | if (obj.Get('chart.tooltips.highlight')) { |
---|
680 | // Redraw the graph |
---|
681 | RGraph.Redraw(); |
---|
682 | } |
---|
683 | |
---|
684 | // SHOW THE CORRECT TOOLTIP |
---|
685 | RGraph.Tooltip(canvas, text, e.pageX, e.pageY, idx); |
---|
686 | |
---|
687 | // Store the tooltip index on the tooltip object |
---|
688 | RGraph.Registry.Get('chart.tooltip').__index__ = Number(idx); |
---|
689 | |
---|
690 | /** |
---|
691 | * This converts idx into the index that is not greater than the |
---|
692 | * number of items in the data array |
---|
693 | */ |
---|
694 | while (idx >= obj.data[0].length) { |
---|
695 | idx -= obj.data[0].length |
---|
696 | } |
---|
697 | |
---|
698 | RGraph.Registry.Get('chart.tooltip').__index2__ = idx; |
---|
699 | |
---|
700 | /** |
---|
701 | * Highlight the graph |
---|
702 | */ |
---|
703 | if (obj.Get('chart.tooltips.highlight')) { |
---|
704 | context.beginPath(); |
---|
705 | context.moveTo(xCoord, yCoord); |
---|
706 | context.arc(xCoord, yCoord, 2, 0, 6.28, 0); |
---|
707 | context.strokeStyle = obj.Get('chart.highlight.stroke'); |
---|
708 | context.fillStyle = obj.Get('chart.highlight.fill'); |
---|
709 | context.stroke(); |
---|
710 | context.fill(); |
---|
711 | } |
---|
712 | |
---|
713 | e.stopPropagation(); |
---|
714 | return; |
---|
715 | } |
---|
716 | } |
---|
717 | |
---|
718 | /** |
---|
719 | * Not over a hotspot? |
---|
720 | */ |
---|
721 | canvas.style.cursor = 'default'; |
---|
722 | } |
---|
723 | this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false); |
---|
724 | RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func); |
---|
725 | |
---|
726 | // TODO COMBINED LINE BAR ONCLICK HANDLER |
---|
727 | // ONLY INSTALL IF THERE IS A BAR CHART |
---|
728 | |
---|
729 | //canvas_onclick_func = function (e) |
---|
730 | //{ |
---|
731 | // p(666) |
---|
732 | //} |
---|
733 | //this.canvas.addEventListener('click', canvas_onclick_func, false); |
---|
734 | //RGraph.AddEventListener(this.id, 'click', canvas_onclick_func); |
---|
735 | } |
---|
736 | |
---|
737 | |
---|
738 | |
---|
739 | |
---|
740 | |
---|
741 | |
---|
742 | |
---|
743 | |
---|
744 | |
---|
745 | |
---|
746 | |
---|
747 | |
---|
748 | |
---|
749 | |
---|
750 | /** |
---|
751 | * If the axes have been requested to be on top, do that |
---|
752 | */ |
---|
753 | if (this.Get('chart.axesontop')) { |
---|
754 | this.DrawAxes(); |
---|
755 | } |
---|
756 | |
---|
757 | /** |
---|
758 | * Draw the labels |
---|
759 | */ |
---|
760 | this.DrawLabels(); |
---|
761 | |
---|
762 | /** |
---|
763 | * Draw the range if necessary |
---|
764 | */ |
---|
765 | this.DrawRange(); |
---|
766 | |
---|
767 | // Draw a key if necessary |
---|
768 | if (this.Get('chart.key').length) { |
---|
769 | RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.colors')); |
---|
770 | } |
---|
771 | |
---|
772 | /** |
---|
773 | * Draw " above" labels if enabled |
---|
774 | */ |
---|
775 | if (this.Get('chart.labels.above')) { |
---|
776 | this.DrawAboveLabels(); |
---|
777 | } |
---|
778 | |
---|
779 | /** |
---|
780 | * Draw the "in graph" labels |
---|
781 | */ |
---|
782 | RGraph.DrawInGraphLabels(this); |
---|
783 | |
---|
784 | /** |
---|
785 | * Draw crosschairs |
---|
786 | */ |
---|
787 | RGraph.DrawCrosshairs(this); |
---|
788 | |
---|
789 | /** |
---|
790 | * If the canvas is annotatable, do install the event handlers |
---|
791 | */ |
---|
792 | if (this.Get('chart.annotatable')) { |
---|
793 | RGraph.Annotate(this); |
---|
794 | } |
---|
795 | |
---|
796 | /** |
---|
797 | * Redraw the lines if a filled range is on the cards |
---|
798 | */ |
---|
799 | if (this.Get('chart.filled') && this.Get('chart.filled.range') && this.data.length == 2) { |
---|
800 | |
---|
801 | this.context.beginPath(); |
---|
802 | var len = this.coords.length / 2; |
---|
803 | this.context.lineWidth = this.Get('chart.linewidth'); |
---|
804 | this.context.strokeStyle = this.Get('chart.colors')[0]; |
---|
805 | |
---|
806 | for (var i=0; i<len; ++i) { |
---|
807 | if (i == 0) { |
---|
808 | this.context.moveTo(this.coords[i][0], this.coords[i][1]); |
---|
809 | } else { |
---|
810 | this.context.lineTo(this.coords[i][0], this.coords[i][1]); |
---|
811 | } |
---|
812 | } |
---|
813 | |
---|
814 | this.context.stroke(); |
---|
815 | |
---|
816 | |
---|
817 | this.context.beginPath(); |
---|
818 | |
---|
819 | if (this.Get('chart.colors')[1]) { |
---|
820 | this.context.strokeStyle = this.Get('chart.colors')[1]; |
---|
821 | } |
---|
822 | |
---|
823 | for (var i=this.coords.length - 1; i>=len; --i) { |
---|
824 | if (i == (this.coords.length - 1) ) { |
---|
825 | this.context.moveTo(this.coords[i][0], this.coords[i][1]); |
---|
826 | } else { |
---|
827 | this.context.lineTo(this.coords[i][0], this.coords[i][1]); |
---|
828 | } |
---|
829 | } |
---|
830 | |
---|
831 | this.context.stroke(); |
---|
832 | } else if (this.Get('chart.filled') && this.Get('chart.filled.range')) { |
---|
833 | alert('[LINE] You must have only two sets of data for a filled range chart'); |
---|
834 | } |
---|
835 | |
---|
836 | /** |
---|
837 | * This bit shows the mini zoom window if requested |
---|
838 | */ |
---|
839 | if (this.Get('chart.zoom.mode') == 'thumbnail') { |
---|
840 | RGraph.ShowZoomWindow(this); |
---|
841 | } |
---|
842 | |
---|
843 | /** |
---|
844 | * This function enables the zoom in area mode |
---|
845 | */ |
---|
846 | if (this.Get('chart.zoom.mode') == 'area') { |
---|
847 | RGraph.ZoomArea(this); |
---|
848 | } |
---|
849 | |
---|
850 | /** |
---|
851 | * This function enables resizing |
---|
852 | */ |
---|
853 | if (this.Get('chart.resizable')) { |
---|
854 | RGraph.AllowResizing(this); |
---|
855 | } |
---|
856 | |
---|
857 | /** |
---|
858 | * This function enables adjustments |
---|
859 | */ |
---|
860 | if (this.Get('chart.adjustable')) { |
---|
861 | RGraph.AllowAdjusting(this); |
---|
862 | } |
---|
863 | |
---|
864 | /** |
---|
865 | * Fire the RGraph ondraw event |
---|
866 | */ |
---|
867 | RGraph.FireCustomEvent(this, 'ondraw'); |
---|
868 | } |
---|
869 | |
---|
870 | |
---|
871 | /** |
---|
872 | * Draws the axes |
---|
873 | */ |
---|
874 | RGraph.Line.prototype.DrawAxes = function () |
---|
875 | { |
---|
876 | // Don't draw the axes? |
---|
877 | if (this.Get('chart.noaxes')) { |
---|
878 | return; |
---|
879 | } |
---|
880 | |
---|
881 | // Turn any shadow off |
---|
882 | RGraph.NoShadow(this); |
---|
883 | |
---|
884 | this.context.lineWidth = 1; |
---|
885 | this.context.strokeStyle = this.Get('chart.axis.color'); |
---|
886 | this.context.beginPath(); |
---|
887 | |
---|
888 | // Draw the X axis |
---|
889 | if (this.Get('chart.noxaxis') == false) { |
---|
890 | if (this.Get('chart.xaxispos') == 'center') { |
---|
891 | this.context.moveTo(this.gutterLeft, (this.grapharea / 2) + this.gutterTop); |
---|
892 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, (this.grapharea / 2) + this.gutterTop); |
---|
893 | } else if (this.Get('chart.xaxispos') == 'top') { |
---|
894 | this.context.moveTo(this.gutterLeft, this.gutterTop); |
---|
895 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, this.gutterTop); |
---|
896 | } else { |
---|
897 | this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
898 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); |
---|
899 | } |
---|
900 | } |
---|
901 | |
---|
902 | // Draw the Y axis |
---|
903 | if (this.Get('chart.noyaxis') == false) { |
---|
904 | if (this.Get('chart.yaxispos') == 'left') { |
---|
905 | this.context.moveTo(this.gutterLeft, this.gutterTop); |
---|
906 | this.context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom ); |
---|
907 | } else { |
---|
908 | this.context.moveTo(RGraph.GetWidth(this) - this.gutterRight, this.gutterTop); |
---|
909 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); |
---|
910 | } |
---|
911 | } |
---|
912 | |
---|
913 | /** |
---|
914 | * Draw the X tickmarks |
---|
915 | */ |
---|
916 | if (this.Get('chart.noxaxis') == false) { |
---|
917 | |
---|
918 | var xTickInterval = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight) / (this.Get('chart.xticks') ? this.Get('chart.xticks') : (this.data[0].length - 1)); |
---|
919 | |
---|
920 | for (x=this.gutterLeft + (this.Get('chart.yaxispos') == 'left' ? xTickInterval : 0); x<=(RGraph.GetWidth(this) - this.gutterRight + 1 ); x+=xTickInterval) { |
---|
921 | |
---|
922 | if (this.Get('chart.yaxispos') == 'right' && x >= (RGraph.GetWidth(this) - this.gutterRight - 1) ) { |
---|
923 | break; |
---|
924 | } |
---|
925 | |
---|
926 | // If the last tick is not desired... |
---|
927 | if (this.Get('chart.noendxtick')) { |
---|
928 | if (this.Get('chart.yaxispos') == 'left' && x >= (RGraph.GetWidth(this) - this.gutterRight)) { |
---|
929 | break; |
---|
930 | } else if (this.Get('chart.yaxispos') == 'right' && x == this.gutterLeft) { |
---|
931 | continue; |
---|
932 | } |
---|
933 | } |
---|
934 | |
---|
935 | var yStart = this.Get('chart.xaxispos') == 'center' ? (this.gutterTop + (this.grapharea / 2)) - 3 : RGraph.GetHeight(this) - this.gutterBottom; |
---|
936 | var yEnd = this.Get('chart.xaxispos') == 'center' ? yStart + 6 : RGraph.GetHeight(this) - this.gutterBottom - (x % 60 == 0 ? this.Get('chart.largexticks') * this.Get('chart.tickdirection') : this.Get('chart.smallxticks') * this.Get('chart.tickdirection')); |
---|
937 | |
---|
938 | if (this.Get('chart.xaxispos') == 'top') { |
---|
939 | yStart = this.gutterTop - 3; |
---|
940 | yEnd = this.gutterTop; |
---|
941 | } |
---|
942 | |
---|
943 | this.context.moveTo(x, yStart); |
---|
944 | this.context.lineTo(x, yEnd); |
---|
945 | } |
---|
946 | |
---|
947 | // Draw an extra tickmark if there is no X axis, but there IS a Y axis |
---|
948 | } else if (this.Get('chart.noyaxis') == false) { |
---|
949 | if (this.Get('chart.yaxispos') == 'left') { |
---|
950 | this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); |
---|
951 | this.context.lineTo(this.gutterLeft - this.Get('chart.smallyticks'), RGraph.GetHeight(this) - this.gutterBottom); |
---|
952 | } else { |
---|
953 | this.context.moveTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); |
---|
954 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight + this.Get('chart.smallyticks'), RGraph.GetHeight(this) - this.gutterBottom); |
---|
955 | } |
---|
956 | } |
---|
957 | |
---|
958 | /** |
---|
959 | * Draw the Y tickmarks |
---|
960 | */ |
---|
961 | if (this.Get('chart.noyaxis') == false) { |
---|
962 | var counter = 0; |
---|
963 | var adjustment = 0; |
---|
964 | |
---|
965 | if (this.Get('chart.yaxispos') == 'right') { |
---|
966 | adjustment = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight); |
---|
967 | } |
---|
968 | |
---|
969 | // X axis at the center |
---|
970 | if (this.Get('chart.xaxispos') == 'center') { |
---|
971 | var interval = (this.grapharea / 10); |
---|
972 | var lineto = (this.Get('chart.yaxispos') == 'left' ? this.gutterLeft : RGraph.GetWidth(this) - this.gutterRight + this.Get('chart.smallyticks')); |
---|
973 | |
---|
974 | // Draw the upper halves Y tick marks |
---|
975 | for (y=this.gutterTop; y < (this.grapharea / 2) + this.gutterTop; y+=interval) { |
---|
976 | this.context.moveTo((this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - this.Get('chart.smallyticks') : RGraph.GetWidth(this) - this.gutterRight), y); |
---|
977 | this.context.lineTo(lineto, y); |
---|
978 | } |
---|
979 | |
---|
980 | // Draw the lower halves Y tick marks |
---|
981 | for (y=this.gutterTop + (this.halfgrapharea) + interval; y <= this.grapharea + this.gutterTop; y+=interval) { |
---|
982 | this.context.moveTo((this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - this.Get('chart.smallyticks') : RGraph.GetWidth(this) - this.gutterRight), y); |
---|
983 | this.context.lineTo(lineto, y); |
---|
984 | } |
---|
985 | |
---|
986 | // X axis at the top |
---|
987 | } else if (this.Get('chart.xaxispos') == 'top') { |
---|
988 | var interval = (this.grapharea / 10); |
---|
989 | var lineto = (this.Get('chart.yaxispos') == 'left' ? this.gutterLeft : RGraph.GetWidth(this) - this.gutterRight + this.Get('chart.smallyticks')); |
---|
990 | |
---|
991 | // Draw the Y tick marks |
---|
992 | for (y=this.gutterTop + interval; y <=this.grapharea + this.gutterTop; y+=interval) { |
---|
993 | this.context.moveTo((this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - this.Get('chart.smallyticks') : RGraph.GetWidth(this) - this.gutterRight), y); |
---|
994 | this.context.lineTo(lineto, y); |
---|
995 | } |
---|
996 | |
---|
997 | // If there's no X axis draw an extra tick |
---|
998 | if (this.Get('chart.noxaxis')) { |
---|
999 | this.context.moveTo((this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - this.Get('chart.smallyticks') : RGraph.GetWidth(this) - this.gutterRight), this.gutterTop); |
---|
1000 | this.context.lineTo(lineto, this.gutterTop); |
---|
1001 | } |
---|
1002 | |
---|
1003 | // X axis at the bottom |
---|
1004 | } else { |
---|
1005 | var lineto = (this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - this.Get('chart.smallyticks') : this.canvas.width - this.gutterRight + this.Get('chart.smallyticks')); |
---|
1006 | |
---|
1007 | for (y=this.gutterTop; y < (this.canvas.height - this.gutterBottom) && counter < 10; y+=( (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 10) ) { |
---|
1008 | |
---|
1009 | this.context.moveTo(this.gutterLeft + adjustment, y); |
---|
1010 | this.context.lineTo(lineto, y); |
---|
1011 | |
---|
1012 | var counter = counter +1; |
---|
1013 | } |
---|
1014 | } |
---|
1015 | |
---|
1016 | // Draw an extra X tickmark |
---|
1017 | } else if (this.Get('chart.noxaxis') == false) { |
---|
1018 | |
---|
1019 | if (this.Get('chart.yaxispos') == 'left') { |
---|
1020 | this.context.moveTo(this.gutterLeft, this.Get('chart.xaxispos') == 'top' ? this.gutterTop : RGraph.GetHeight(this) - this.gutterBottom); |
---|
1021 | this.context.lineTo(this.gutterLeft, this.Get('chart.xaxispos') == 'top' ? this.gutterTop - this.Get('chart.smallxticks') : RGraph.GetHeight(this) - this.gutterBottom + this.Get('chart.smallxticks')); |
---|
1022 | } else { |
---|
1023 | this.context.moveTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); |
---|
1024 | this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom + this.Get('chart.smallxticks')); |
---|
1025 | } |
---|
1026 | } |
---|
1027 | |
---|
1028 | this.context.stroke(); |
---|
1029 | } |
---|
1030 | |
---|
1031 | |
---|
1032 | /** |
---|
1033 | * Draw the text labels for the axes |
---|
1034 | */ |
---|
1035 | RGraph.Line.prototype.DrawLabels = function () |
---|
1036 | { |
---|
1037 | this.context.strokeStyle = 'black'; |
---|
1038 | this.context.fillStyle = this.Get('chart.text.color'); |
---|
1039 | this.context.lineWidth = 1; |
---|
1040 | |
---|
1041 | // Turn off any shadow |
---|
1042 | RGraph.NoShadow(this); |
---|
1043 | |
---|
1044 | // This needs to be here |
---|
1045 | var font = this.Get('chart.text.font'); |
---|
1046 | var text_size = this.Get('chart.text.size'); |
---|
1047 | var context = this.context; |
---|
1048 | var canvas = this.canvas; |
---|
1049 | |
---|
1050 | // Draw the Y axis labels |
---|
1051 | if (this.Get('chart.ylabels') && this.Get('chart.ylabels.specific') == null) { |
---|
1052 | |
---|
1053 | var units_pre = this.Get('chart.units.pre'); |
---|
1054 | var units_post = this.Get('chart.units.post'); |
---|
1055 | var xpos = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : RGraph.GetWidth(this) - this.gutterRight + 5; |
---|
1056 | var align = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left'; |
---|
1057 | |
---|
1058 | var numYLabels = this.Get('chart.ylabels.count'); |
---|
1059 | var bounding = false; |
---|
1060 | var bgcolor = this.Get('chart.ylabels.inside') ? this.Get('chart.ylabels.inside.color') : null; |
---|
1061 | |
---|
1062 | |
---|
1063 | /** |
---|
1064 | * If the Y labels are inside the Y axis, invert the alignment |
---|
1065 | */ |
---|
1066 | if (this.Get('chart.ylabels.inside') == true && align == 'left') { |
---|
1067 | xpos -= 10; |
---|
1068 | align = 'right'; |
---|
1069 | bounding = true; |
---|
1070 | |
---|
1071 | |
---|
1072 | } else if (this.Get('chart.ylabels.inside') == true && align == 'right') { |
---|
1073 | xpos += 10; |
---|
1074 | align = 'left'; |
---|
1075 | bounding = true; |
---|
1076 | } |
---|
1077 | |
---|
1078 | |
---|
1079 | |
---|
1080 | if (this.Get('chart.xaxispos') == 'center') { |
---|
1081 | var half = this.grapharea / 2; |
---|
1082 | |
---|
1083 | if (numYLabels == 1 || numYLabels == 3 || numYLabels == 5) { |
---|
1084 | // Draw the upper halves labels |
---|
1085 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (0/5) * half ) + this.halfTextHeight, RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1086 | |
---|
1087 | if (numYLabels == 5) { |
---|
1088 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (1/5) * half ) + this.halfTextHeight, RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1089 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (3/5) * half ) + this.halfTextHeight, RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1090 | } |
---|
1091 | |
---|
1092 | if (numYLabels >= 3) { |
---|
1093 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (2/5) * half ) + this.halfTextHeight, RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1094 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (4/5) * half ) + this.halfTextHeight, RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1095 | } |
---|
1096 | |
---|
1097 | // Draw the lower halves labels |
---|
1098 | if (numYLabels >= 3) { |
---|
1099 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (6/5) * half ) + this.halfTextHeight, '-' + RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1100 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (8/5) * half ) + this.halfTextHeight, '-' + RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1101 | } |
---|
1102 | |
---|
1103 | if (numYLabels == 5) { |
---|
1104 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (7/5) * half ) + this.halfTextHeight, '-' + RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1105 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (9/5) * half ) + this.halfTextHeight, '-' + RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1106 | } |
---|
1107 | |
---|
1108 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + ( (10/5) * half ) + this.halfTextHeight, '-' + RGraph.number_format(this, (this.scale[4] == '1.0' ? '1.0' : this.scale[4]), units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1109 | |
---|
1110 | } else if (numYLabels == 10) { |
---|
1111 | |
---|
1112 | // 10 Y labels |
---|
1113 | var interval = (this.grapharea / numYLabels) / 2; |
---|
1114 | |
---|
1115 | for (var i=0; i<numYLabels; ++i) { |
---|
1116 | // This draws the upper halves labels |
---|
1117 | RGraph.Text(context,font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((i/20) * (this.grapharea) ), RGraph.number_format(this, ((this.scale[4] / numYLabels) * (numYLabels - i)).toFixed((this.Get('chart.scale.decimals'))),units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1118 | |
---|
1119 | // And this draws the lower halves labels |
---|
1120 | RGraph.Text(context, font, text_size, xpos, |
---|
1121 | |
---|
1122 | this.gutterTop + this.halfTextHeight + ((i/20) * this.grapharea) + (this.grapharea / 2) + (this.grapharea / 20), |
---|
1123 | |
---|
1124 | '-' + RGraph.number_format(this, (this.scale[4] - ((this.scale[4] / numYLabels) * (numYLabels - i - 1))).toFixed((this.Get('chart.scale.decimals'))),units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1125 | } |
---|
1126 | |
---|
1127 | } else { |
---|
1128 | alert('[LINE SCALE] The number of Y labels must be 1/3/5/10'); |
---|
1129 | } |
---|
1130 | |
---|
1131 | // Draw the lower limit if chart.ymin is specified |
---|
1132 | if (typeof(this.Get('chart.ymin')) == 'number') { |
---|
1133 | RGraph.Text(context, font, text_size, xpos, RGraph.GetHeight(this) / 2, RGraph.number_format(this, this.Get('chart.ymin').toFixed(this.Get('chart.scale.decimals')), units_pre, units_post), 'center', align, bounding, null, bgcolor); |
---|
1134 | } |
---|
1135 | |
---|
1136 | // No X axis - so draw 0 |
---|
1137 | if (this.Get('chart.noxaxis') == true) { |
---|
1138 | RGraph.Text(context,font,text_size,xpos,this.gutterTop + ( (5/5) * half ) + this.halfTextHeight,'0',null, align, bounding, null, bgcolor); |
---|
1139 | } |
---|
1140 | |
---|
1141 | // X axis at the top |
---|
1142 | } else if (this.Get('chart.xaxispos') == 'top') { |
---|
1143 | |
---|
1144 | var scale = RGraph.array_reverse(this.scale); |
---|
1145 | |
---|
1146 | /** |
---|
1147 | * Accommodate reversing the Y labels |
---|
1148 | */ |
---|
1149 | if (this.Get('chart.ylabels.invert')) { |
---|
1150 | |
---|
1151 | scale = RGraph.array_reverse(scale); |
---|
1152 | |
---|
1153 | this.context.translate(0, this.grapharea * -0.2); |
---|
1154 | if (typeof(this.Get('chart.ymin')) == null) { |
---|
1155 | this.Set('chart.ymin', 0); |
---|
1156 | } |
---|
1157 | } |
---|
1158 | |
---|
1159 | if (numYLabels == 1 || numYLabels == 3 || numYLabels == 5) { |
---|
1160 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((1/5) * (this.grapharea ) ), '-' + RGraph.number_format(this, scale[4], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1161 | |
---|
1162 | if (numYLabels == 5) { |
---|
1163 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((4/5) * (this.grapharea) ), '-' + RGraph.number_format(this, scale[1], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1164 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((2/5) * (this.grapharea) ), '-' + RGraph.number_format(this, scale[3], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1165 | } |
---|
1166 | |
---|
1167 | if (numYLabels >= 3) { |
---|
1168 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((3/5) * (this.grapharea ) ), '-' + RGraph.number_format(this, scale[2], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1169 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((5/5) * (this.grapharea) ), '-' + RGraph.number_format(this, scale[0], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1170 | } |
---|
1171 | |
---|
1172 | } else if (numYLabels == 10) { |
---|
1173 | |
---|
1174 | // 10 Y labels |
---|
1175 | var interval = (this.grapharea / numYLabels) / 2; |
---|
1176 | |
---|
1177 | for (var i=0; i<numYLabels; ++i) { |
---|
1178 | |
---|
1179 | RGraph.Text(context,font,text_size,xpos,(2 * interval) + this.gutterTop + this.halfTextHeight + ((i/10) * (this.grapharea) ),'-' + RGraph.number_format(this,(scale[0] - (((scale[0] - this.min) / numYLabels) * (numYLabels - i - 1))).toFixed((this.Get('chart.scale.decimals'))),units_pre,units_post),null,align,bounding,null,bgcolor); |
---|
1180 | } |
---|
1181 | |
---|
1182 | } else { |
---|
1183 | alert('[LINE SCALE] The number of Y labels must be 1/3/5/10'); |
---|
1184 | } |
---|
1185 | |
---|
1186 | |
---|
1187 | /** |
---|
1188 | * Accommodate translating back after reversing the labels |
---|
1189 | */ |
---|
1190 | if (this.Get('chart.ylabels.invert')) { |
---|
1191 | this.context.translate(0, 0 - (this.grapharea * -0.2)); |
---|
1192 | } |
---|
1193 | |
---|
1194 | // Draw the lower limit if chart.ymin is specified |
---|
1195 | if (typeof(this.Get('chart.ymin')) == 'number') { |
---|
1196 | RGraph.Text(context,font,text_size,xpos,this.Get('chart.ylabels.invert') ? this.canvas.height - this.gutterBottom : this.gutterTop,'-' + RGraph.number_format(this, this.Get('chart.ymin').toFixed(this.Get('chart.scale.decimals')), units_pre, units_post),'center',align,bounding,null,bgcolor); |
---|
1197 | } |
---|
1198 | |
---|
1199 | } else { |
---|
1200 | |
---|
1201 | /** |
---|
1202 | * Accommodate reversing the Y labels |
---|
1203 | */ |
---|
1204 | if (this.Get('chart.ylabels.invert')) { |
---|
1205 | this.scale = RGraph.array_reverse(this.scale); |
---|
1206 | this.context.translate(0, this.grapharea * 0.2); |
---|
1207 | if (typeof(this.Get('chart.ymin')) == null) { |
---|
1208 | this.Set('chart.ymin', 0); |
---|
1209 | } |
---|
1210 | } |
---|
1211 | |
---|
1212 | if (numYLabels == 1 || numYLabels == 3 || numYLabels == 5) { |
---|
1213 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((0/5) * (this.grapharea ) ), RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1214 | |
---|
1215 | if (numYLabels == 5) { |
---|
1216 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((3/5) * (this.grapharea) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1217 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((1/5) * (this.grapharea) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1218 | } |
---|
1219 | |
---|
1220 | if (numYLabels >= 3) { |
---|
1221 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((2/5) * (this.grapharea ) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1222 | RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + ((4/5) * (this.grapharea) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, bounding, null, bgcolor); |
---|
1223 | } |
---|
1224 | |
---|
1225 | } else if (numYLabels == 10) { |
---|
1226 | |
---|
1227 | // 10 Y labels |
---|
1228 | var interval = (this.grapharea / numYLabels) / 2; |
---|
1229 | |
---|
1230 | for (var i=0; i<numYLabels; ++i) { |
---|
1231 | RGraph.Text(context,font,text_size,xpos,this.gutterTop + this.halfTextHeight + ((i/10) * (this.grapharea) ),RGraph.number_format(this,((((this.scale[4] - this.min) / numYLabels) * (numYLabels - i)) + this.min).toFixed((this.Get('chart.scale.decimals'))),units_pre,units_post),null,align,bounding,null,bgcolor); |
---|
1232 | } |
---|
1233 | |
---|
1234 | } else { |
---|
1235 | alert('[LINE SCALE] The number of Y labels must be 1/3/5/10'); |
---|
1236 | } |
---|
1237 | |
---|
1238 | |
---|
1239 | /** |
---|
1240 | * Accommodate translating back after reversing the labels |
---|
1241 | */ |
---|
1242 | if (this.Get('chart.ylabels.invert')) { |
---|
1243 | this.context.translate(0, 0 - (this.grapharea * 0.2)); |
---|
1244 | } |
---|
1245 | |
---|
1246 | // Draw the lower limit if chart.ymin is specified |
---|
1247 | if (typeof(this.Get('chart.ymin')) == 'number') { |
---|
1248 | RGraph.Text(context,font,text_size,xpos,this.Get('chart.ylabels.invert') ? this.gutterTop : RGraph.GetHeight(this) - this.gutterBottom,RGraph.number_format(this, this.Get('chart.ymin').toFixed(this.Get('chart.scale.decimals')), units_pre, units_post),'center',align,bounding,null,bgcolor); |
---|
1249 | } |
---|
1250 | } |
---|
1251 | |
---|
1252 | // No X axis - so draw 0 |
---|
1253 | if ( this.Get('chart.noxaxis') == true |
---|
1254 | && this.Get('chart.ymin') == null |
---|
1255 | ) { |
---|
1256 | |
---|
1257 | RGraph.Text(context,font,text_size,xpos,this.Get('chart.xaxispos') == 'top' ? this.gutterTop + this.halfTextHeight: (RGraph.GetHeight(this) - this.gutterBottom + this.halfTextHeight),'0',null, align, bounding, null, bgcolor); |
---|
1258 | } |
---|
1259 | |
---|
1260 | } else if (this.Get('chart.ylabels') && typeof(this.Get('chart.ylabels.specific')) == 'object') { |
---|
1261 | |
---|
1262 | // A few things |
---|
1263 | var gap = this.grapharea / this.Get('chart.ylabels.specific').length; |
---|
1264 | var halign = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left'; |
---|
1265 | var bounding = false; |
---|
1266 | var bgcolor = null; |
---|
1267 | var ymin = this.Get('chart.ymin') != null && this.Get('chart.ymin'); |
---|
1268 | |
---|
1269 | // Figure out the X coord based on the position of the axis |
---|
1270 | if (this.Get('chart.yaxispos') == 'left') { |
---|
1271 | var x = this.gutterLeft - 5; |
---|
1272 | |
---|
1273 | if (this.Get('chart.ylabels.inside')) { |
---|
1274 | x += 10; |
---|
1275 | halign = 'left'; |
---|
1276 | bounding = true; |
---|
1277 | bgcolor = 'rgba(255,255,255,0.5)'; |
---|
1278 | } |
---|
1279 | |
---|
1280 | } else if (this.Get('chart.yaxispos') == 'right') { |
---|
1281 | var x = this.canvas.width - this.gutterRight + 5; |
---|
1282 | |
---|
1283 | if (this.Get('chart.ylabels.inside')) { |
---|
1284 | x -= 10; |
---|
1285 | halign = 'right'; |
---|
1286 | bounding = true; |
---|
1287 | bgcolor = 'rgba(255,255,255,0.5)'; |
---|
1288 | } |
---|
1289 | } |
---|
1290 | |
---|
1291 | |
---|
1292 | // Draw the labels |
---|
1293 | if (this.Get('chart.xaxispos') == 'center') { |
---|
1294 | |
---|
1295 | // Draw the top halfs labels |
---|
1296 | for (var i=0; i<this.Get('chart.ylabels.specific').length; ++i) { |
---|
1297 | var y = this.gutterTop + (this.grapharea / ((this.Get('chart.ylabels.specific').length ) * 2) * i); |
---|
1298 | |
---|
1299 | if (ymin && ymin > 0) { |
---|
1300 | var y = ((this.grapharea / 2) / (this.Get('chart.ylabels.specific').length - (ymin ? 1 : 0)) ) * i; |
---|
1301 | y += this.gutterTop; |
---|
1302 | } |
---|
1303 | |
---|
1304 | RGraph.Text(context, font, text_size,x,y,String(this.Get('chart.ylabels.specific')[i]), 'center', halign, bounding, 0, bgcolor); |
---|
1305 | } |
---|
1306 | |
---|
1307 | // Now reverse the labels and draw the bottom half |
---|
1308 | var reversed_labels = RGraph.array_reverse(this.Get('chart.ylabels.specific')); |
---|
1309 | |
---|
1310 | // Draw the bottom halfs labels |
---|
1311 | for (var i=0; i<reversed_labels.length; ++i) { |
---|
1312 | var y = (this.grapharea / 2) + this.gutterTop + ((this.grapharea / (reversed_labels.length * 2) ) * (i + 1)); |
---|
1313 | |
---|
1314 | if (ymin && ymin > 0) { |
---|
1315 | var y = ((this.grapharea / 2) / (reversed_labels.length - (ymin ? 1 : 0)) ) * i; |
---|
1316 | y += this.gutterTop; |
---|
1317 | y += (this.grapharea / 2); |
---|
1318 | } |
---|
1319 | |
---|
1320 | RGraph.Text(context, font, text_size,x,y,String(reversed_labels[i]), 'center', halign, bounding, 0, bgcolor); |
---|
1321 | } |
---|
1322 | |
---|
1323 | } else if (this.Get('chart.xaxispos') == 'top') { |
---|
1324 | |
---|
1325 | // Reverse the labels and draw |
---|
1326 | var reversed_labels = RGraph.array_reverse(this.Get('chart.ylabels.specific')); |
---|
1327 | |
---|
1328 | // Draw the bottom halfs labels |
---|
1329 | for (var i=0; i<reversed_labels.length; ++i) { |
---|
1330 | |
---|
1331 | var y = ((this.grapharea / (reversed_labels.length - (ymin ? 1 : 0)) ) * (i + (ymin ? 0 : 1))); |
---|
1332 | y = y + this.gutterTop; |
---|
1333 | |
---|
1334 | RGraph.Text(context, font, text_size,x,y,String(reversed_labels[i]), 'center', halign, bounding, 0, bgcolor); |
---|
1335 | } |
---|
1336 | |
---|
1337 | } else { |
---|
1338 | for (var i=0; i<this.Get('chart.ylabels.specific').length; ++i) { |
---|
1339 | var y = this.gutterTop + ((this.grapharea / (this.Get('chart.ylabels.specific').length - (ymin ? 1 : 0) )) * i); |
---|
1340 | RGraph.Text(context, font, text_size,x,y,String(this.Get('chart.ylabels.specific')[i]), 'center', halign, bounding, 0, bgcolor); |
---|
1341 | } |
---|
1342 | } |
---|
1343 | } |
---|
1344 | |
---|
1345 | // Draw the X axis labels |
---|
1346 | if (this.Get('chart.labels') && this.Get('chart.labels').length > 0) { |
---|
1347 | |
---|
1348 | |
---|
1349 | var yOffset = 13; |
---|
1350 | var bordered = false; |
---|
1351 | var bgcolor = null; |
---|
1352 | |
---|
1353 | if (this.Get('chart.xlabels.inside')) { |
---|
1354 | yOffset = -5; |
---|
1355 | bordered = true; |
---|
1356 | bgcolor = this.Get('chart.xlabels.inside.color'); |
---|
1357 | } |
---|
1358 | |
---|
1359 | /** |
---|
1360 | * Text angle |
---|
1361 | */ |
---|
1362 | var angle = 0; |
---|
1363 | var valign = null; |
---|
1364 | var halign = 'center'; |
---|
1365 | |
---|
1366 | if (typeof(this.Get('chart.text.angle')) == 'number' && this.Get('chart.text.angle') > 0) { |
---|
1367 | angle = -1 * this.Get('chart.text.angle'); |
---|
1368 | valign = 'center'; |
---|
1369 | halign = 'right'; |
---|
1370 | yOffset = 10; |
---|
1371 | |
---|
1372 | if (this.Get('chart.xaxispos') == 'top') { |
---|
1373 | yOffset = 10; |
---|
1374 | } |
---|
1375 | } |
---|
1376 | |
---|
1377 | this.context.fillStyle = this.Get('chart.text.color'); |
---|
1378 | var numLabels = this.Get('chart.labels').length; |
---|
1379 | |
---|
1380 | for (i=0; i<numLabels; ++i) { |
---|
1381 | |
---|
1382 | // Changed 8th Nov 2010 to be not reliant on the coords |
---|
1383 | //if (this.Get('chart.labels')[i] && this.coords && this.coords[i] && this.coords[i][0]) { |
---|
1384 | if (this.Get('chart.labels')[i]) { |
---|
1385 | |
---|
1386 | var labelX = ((RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight - (2 * this.Get('chart.hmargin'))) / (numLabels - 1) ) * i; |
---|
1387 | labelX += this.gutterLeft + this.Get('chart.hmargin'); |
---|
1388 | |
---|
1389 | /** |
---|
1390 | * Account for an unrelated number of labels |
---|
1391 | */ |
---|
1392 | if (this.Get('chart.labels').length != this.data[0].length) { |
---|
1393 | labelX = this.gutterLeft + this.Get('chart.hmargin') + ((RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight - (2 * this.Get('chart.hmargin'))) * (i / (this.Get('chart.labels').length - 1))); |
---|
1394 | } |
---|
1395 | |
---|
1396 | // This accounts for there only being one point on the chart |
---|
1397 | if (!labelX) { |
---|
1398 | labelX = this.gutterLeft + this.Get('chart.hmargin'); |
---|
1399 | } |
---|
1400 | |
---|
1401 | if (this.Get('chart.xaxispos') == 'top' && this.Get('chart.text.angle') > 0) { |
---|
1402 | halign = 'left'; |
---|
1403 | } |
---|
1404 | |
---|
1405 | RGraph.Text(context, |
---|
1406 | font, |
---|
1407 | text_size, |
---|
1408 | labelX, |
---|
1409 | (this.Get('chart.xaxispos') == 'top') ? this.gutterTop - yOffset - (this.Get('chart.xlabels.inside') ? -22 : 0) : (RGraph.GetHeight(this) - this.gutterBottom) + yOffset, |
---|
1410 | String(this.Get('chart.labels')[i]), |
---|
1411 | valign, |
---|
1412 | halign, |
---|
1413 | bordered, |
---|
1414 | angle, |
---|
1415 | bgcolor); |
---|
1416 | } |
---|
1417 | } |
---|
1418 | |
---|
1419 | } |
---|
1420 | |
---|
1421 | this.context.stroke(); |
---|
1422 | this.context.fill(); |
---|
1423 | } |
---|
1424 | |
---|
1425 | |
---|
1426 | /** |
---|
1427 | * Draws the line |
---|
1428 | */ |
---|
1429 | RGraph.Line.prototype.DrawLine = function (lineData, color, fill, linewidth, tickmarks, index) |
---|
1430 | { |
---|
1431 | var penUp = false; |
---|
1432 | var yPos = null; |
---|
1433 | var xPos = 0; |
---|
1434 | this.context.lineWidth = 1; |
---|
1435 | var lineCoords = []; |
---|
1436 | |
---|
1437 | // Work out the X interval |
---|
1438 | var xInterval = (this.canvas.width - (2 * this.Get('chart.hmargin')) - this.gutterLeft - this.gutterRight) / (lineData.length - 1); |
---|
1439 | |
---|
1440 | // Loop thru each value given, plotting the line |
---|
1441 | for (i=0; i<lineData.length; i++) { |
---|
1442 | |
---|
1443 | var data_point = lineData[i]; |
---|
1444 | |
---|
1445 | |
---|
1446 | yPos = this.canvas.height - (((data_point - (data_point > 0 ? this.Get('chart.ymin') : (-1 * this.Get('chart.ymin')))) / (this.max - this.min) ) * this.grapharea); |
---|
1447 | yPos = (this.grapharea / (this.max - this.min)) * (data_point - this.min); |
---|
1448 | yPos = this.canvas.height - yPos; |
---|
1449 | |
---|
1450 | /** |
---|
1451 | * This skirts an annoying JS rounding error |
---|
1452 | * SEARCH TAGS: JS ROUNDING ERROR DECIMALS |
---|
1453 | */ |
---|
1454 | if (data_point == this.max) { |
---|
1455 | yPos = Math.round(yPos); |
---|
1456 | } |
---|
1457 | |
---|
1458 | if (this.Get('chart.ylabels.invert')) { |
---|
1459 | yPos -= this.gutterBottom; |
---|
1460 | yPos -= this.gutterTop; |
---|
1461 | yPos = this.canvas.height - yPos; |
---|
1462 | } |
---|
1463 | |
---|
1464 | // Make adjustments depending on the X axis position |
---|
1465 | if (this.Get('chart.xaxispos') == 'center') { |
---|
1466 | yPos = (yPos - this.gutterBottom - this.gutterTop) / 2; |
---|
1467 | yPos = yPos + this.gutterTop; |
---|
1468 | |
---|
1469 | // TODO Check this |
---|
1470 | } else if (this.Get('chart.xaxispos') == 'top') { |
---|
1471 | |
---|
1472 | yPos = (this.grapharea / (this.max - this.min)) * (Math.abs(data_point) - this.min); |
---|
1473 | yPos += this.gutterTop; |
---|
1474 | |
---|
1475 | if (this.Get('chart.ylabels.invert')) { |
---|
1476 | yPos -= this.gutterTop; |
---|
1477 | yPos = this.grapharea - yPos; |
---|
1478 | yPos += this.gutterTop; |
---|
1479 | } |
---|
1480 | |
---|
1481 | } else if (this.Get('chart.xaxispos') == 'bottom') { |
---|
1482 | // TODO |
---|
1483 | yPos -= this.gutterBottom; // Without this the line is out of place due to the gutter |
---|
1484 | } |
---|
1485 | |
---|
1486 | |
---|
1487 | |
---|
1488 | // Null data points, and a special case for this bug:http://dev.rgraph.net/tests/ymin.html |
---|
1489 | if ( lineData[i] == null |
---|
1490 | || (this.Get('chart.xaxispos') == 'bottom' && lineData[i] < this.min && !this.Get('chart.outofbounds')) |
---|
1491 | || (this.Get('chart.xaxispos') == 'center' && lineData[i] < (-1 * this.max) && !this.Get('chart.outofbounds'))) { |
---|
1492 | |
---|
1493 | yPos = null; |
---|
1494 | } |
---|
1495 | |
---|
1496 | // Not always very noticeable, but it does have an effect |
---|
1497 | // with thick lines |
---|
1498 | this.context.lineCap = 'round'; |
---|
1499 | this.context.lineJoin = 'round'; |
---|
1500 | |
---|
1501 | // Plot the line if we're at least on the second iteration |
---|
1502 | if (i > 0) { |
---|
1503 | xPos = xPos + xInterval; |
---|
1504 | } else { |
---|
1505 | xPos = this.Get('chart.hmargin') + this.gutterLeft; |
---|
1506 | } |
---|
1507 | |
---|
1508 | /** |
---|
1509 | * Add the coords to an array |
---|
1510 | */ |
---|
1511 | this.coords.push([xPos, yPos]); |
---|
1512 | lineCoords.push([xPos, yPos]); |
---|
1513 | } |
---|
1514 | |
---|
1515 | this.context.stroke(); |
---|
1516 | |
---|
1517 | // Store the coords in another format, indexed by line number |
---|
1518 | this.coords2[index] = lineCoords; |
---|
1519 | |
---|
1520 | /** |
---|
1521 | * For IE only: Draw the shadow ourselves as ExCanvas doesn't produce shadows |
---|
1522 | */ |
---|
1523 | if (RGraph.isIE8() && this.Get('chart.shadow')) { |
---|
1524 | this.DrawIEShadow(lineCoords, this.context.shadowColor); |
---|
1525 | } |
---|
1526 | |
---|
1527 | /** |
---|
1528 | * Now draw the actual line [FORMERLY SECOND] |
---|
1529 | */ |
---|
1530 | this.context.beginPath(); |
---|
1531 | this.context.strokeStyle = 'rgba(240,240,240,0.9)'; // Almost transparent - changed on 10th May 2010 |
---|
1532 | //this.context.strokeStyle = fill; |
---|
1533 | if (fill) this.context.fillStyle = fill; |
---|
1534 | |
---|
1535 | var isStepped = this.Get('chart.stepped'); |
---|
1536 | var isFilled = this.Get('chart.filled'); |
---|
1537 | |
---|
1538 | |
---|
1539 | for (var i=0; i<lineCoords.length; ++i) { |
---|
1540 | |
---|
1541 | xPos = lineCoords[i][0]; |
---|
1542 | yPos = lineCoords[i][1]; |
---|
1543 | var set = index; |
---|
1544 | |
---|
1545 | var prevY = (lineCoords[i - 1] ? lineCoords[i - 1][1] : null); |
---|
1546 | var isLast = (i + 1) == lineCoords.length; |
---|
1547 | |
---|
1548 | /** |
---|
1549 | * This nullifys values which are out-of-range |
---|
1550 | */ |
---|
1551 | if (prevY < this.gutterTop || prevY > (RGraph.GetHeight(this) - this.gutterBottom) ) { |
---|
1552 | penUp = true; |
---|
1553 | } |
---|
1554 | |
---|
1555 | if (i == 0 || penUp || !yPos || !prevY || prevY < this.gutterTop) { |
---|
1556 | |
---|
1557 | if (this.Get('chart.filled') && !this.Get('chart.filled.range')) { |
---|
1558 | this.context.moveTo(xPos + 1, this.canvas.height - this.gutterBottom - (this.Get('chart.xaxispos') == 'center' ? (this.canvas.height - this.gutterTop - this.gutterBottom) / 2 : 0) -1); |
---|
1559 | this.context.lineTo(xPos + 1, yPos); |
---|
1560 | |
---|
1561 | } else { |
---|
1562 | this.context.moveTo(xPos, yPos); |
---|
1563 | } |
---|
1564 | |
---|
1565 | if (yPos == null) { |
---|
1566 | penUp = true; |
---|
1567 | } else { |
---|
1568 | penUp = false; |
---|
1569 | } |
---|
1570 | |
---|
1571 | } else { |
---|
1572 | |
---|
1573 | // Draw the stepped part of stepped lines |
---|
1574 | if (isStepped) { |
---|
1575 | this.context.lineTo(xPos, lineCoords[i - 1][1]); |
---|
1576 | } |
---|
1577 | |
---|
1578 | if ((yPos >= this.gutterTop && yPos <= (RGraph.GetHeight(this) - this.gutterBottom)) || this.Get('chart.outofbounds') ) { |
---|
1579 | |
---|
1580 | if (isLast && this.Get('chart.filled') && !this.Get('chart.filled.range') && this.Get('chart.yaxispos') == 'right') { |
---|
1581 | xPos -= 1; |
---|
1582 | } |
---|
1583 | |
---|
1584 | |
---|
1585 | // Added 8th September 2009 |
---|
1586 | if (!isStepped || !isLast) { |
---|
1587 | this.context.lineTo(xPos, yPos); |
---|
1588 | |
---|
1589 | if (isFilled && lineCoords[i+1] && lineCoords[i+1][1] == null) { |
---|
1590 | this.context.lineTo(xPos, RGraph.GetHeight(this) - this.gutterBottom); |
---|
1591 | } |
---|
1592 | |
---|
1593 | // Added August 2010 |
---|
1594 | } else if (isStepped && isLast) { |
---|
1595 | this.context.lineTo(xPos,yPos); |
---|
1596 | } |
---|
1597 | |
---|
1598 | |
---|
1599 | penUp = false; |
---|
1600 | } else { |
---|
1601 | penUp = true; |
---|
1602 | } |
---|
1603 | } |
---|
1604 | } |
---|
1605 | |
---|
1606 | if (this.Get('chart.filled') && !this.Get('chart.filled.range')) { |
---|
1607 | var fillStyle = this.Get('chart.fillstyle'); |
---|
1608 | |
---|
1609 | this.context.lineTo(xPos, RGraph.GetHeight(this) - this.gutterBottom - 1 - + (this.Get('chart.xaxispos') == 'center' ? (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2 : 0)); |
---|
1610 | this.context.fillStyle = fill; |
---|
1611 | |
---|
1612 | this.context.fill(); |
---|
1613 | this.context.beginPath(); |
---|
1614 | } |
---|
1615 | |
---|
1616 | /** |
---|
1617 | * FIXME this may need removing when Chrome is fixed |
---|
1618 | * SEARCH TAGS: CHROME SHADOW BUG |
---|
1619 | */ |
---|
1620 | if (navigator.userAgent.match(/Chrome/) && this.Get('chart.shadow') && this.Get('chart.chromefix') && this.Get('chart.shadow.blur') > 0) { |
---|
1621 | |
---|
1622 | for (var i=lineCoords.length - 1; i>=0; --i) { |
---|
1623 | if ( |
---|
1624 | typeof(lineCoords[i][1]) != 'number' |
---|
1625 | || (typeof(lineCoords[i+1]) == 'object' && typeof(lineCoords[i+1][1]) != 'number') |
---|
1626 | ) { |
---|
1627 | this.context.moveTo(lineCoords[i][0],lineCoords[i][1]); |
---|
1628 | } else { |
---|
1629 | this.context.lineTo(lineCoords[i][0],lineCoords[i][1]); |
---|
1630 | } |
---|
1631 | } |
---|
1632 | } |
---|
1633 | |
---|
1634 | this.context.stroke(); |
---|
1635 | |
---|
1636 | |
---|
1637 | if (this.Get('chart.backdrop')) { |
---|
1638 | this.DrawBackdrop(lineCoords, color); |
---|
1639 | } |
---|
1640 | |
---|
1641 | // Now redraw the lines with the correct line width |
---|
1642 | this.RedrawLine(lineCoords, color, linewidth); |
---|
1643 | |
---|
1644 | this.context.stroke(); |
---|
1645 | |
---|
1646 | // Draw the tickmarks |
---|
1647 | for (var i=0; i<lineCoords.length; ++i) { |
---|
1648 | |
---|
1649 | i = Number(i); |
---|
1650 | |
---|
1651 | if (isStepped && i == (lineCoords.length - 1)) { |
---|
1652 | this.context.beginPath(); |
---|
1653 | //continue; |
---|
1654 | } |
---|
1655 | |
---|
1656 | if ( |
---|
1657 | ( |
---|
1658 | tickmarks != 'endcircle' |
---|
1659 | && tickmarks != 'endsquare' |
---|
1660 | && tickmarks != 'filledendsquare' |
---|
1661 | && tickmarks != 'endtick' |
---|
1662 | && tickmarks != 'endtriangle' |
---|
1663 | && tickmarks != 'arrow' |
---|
1664 | && tickmarks != 'filledarrow' |
---|
1665 | ) |
---|
1666 | || (i == 0 && tickmarks != 'arrow' && tickmarks != 'filledarrow') |
---|
1667 | || i == (lineCoords.length - 1) |
---|
1668 | ) { |
---|
1669 | |
---|
1670 | var prevX = (i <= 0 ? null : lineCoords[i - 1][0]); |
---|
1671 | var prevY = (i <= 0 ? null : lineCoords[i - 1][1]); |
---|
1672 | |
---|
1673 | this.DrawTick(lineData, lineCoords[i][0], lineCoords[i][1], color, false, prevX, prevY, tickmarks, i); |
---|
1674 | |
---|
1675 | // Draws tickmarks on the stepped bits of stepped charts. Takend out 14th July 2010 |
---|
1676 | // |
---|
1677 | //if (this.Get('chart.stepped') && lineCoords[i + 1] && this.Get('chart.tickmarks') != 'endsquare' && this.Get('chart.tickmarks') != 'endcircle' && this.Get('chart.tickmarks') != 'endtick') { |
---|
1678 | // this.DrawTick(lineCoords[i + 1][0], lineCoords[i][1], color); |
---|
1679 | //} |
---|
1680 | } |
---|
1681 | } |
---|
1682 | |
---|
1683 | // Draw something off canvas to skirt an annoying bug |
---|
1684 | this.context.beginPath(); |
---|
1685 | this.context.arc(RGraph.GetWidth(this) + 50000, RGraph.GetHeight(this) + 50000, 2, 0, 6.38, 1); |
---|
1686 | } |
---|
1687 | |
---|
1688 | |
---|
1689 | /** |
---|
1690 | * This functions draws a tick mark on the line |
---|
1691 | * |
---|
1692 | * @param xPos int The x position of the tickmark |
---|
1693 | * @param yPos int The y position of the tickmark |
---|
1694 | * @param color str The color of the tickmark |
---|
1695 | * @param bool Whether the tick is a shadow. If it is, it gets offset by the shadow offset |
---|
1696 | */ |
---|
1697 | RGraph.Line.prototype.DrawTick = function (lineData, xPos, yPos, color, isShadow, prevX, prevY, tickmarks, index) |
---|
1698 | { |
---|
1699 | // If the yPos is null - no tick |
---|
1700 | if ((yPos == null || yPos > (this.canvas.height - this.gutterBottom) || yPos < this.gutterTop) && !this.Get('chart.outofbounds')) { |
---|
1701 | return; |
---|
1702 | } |
---|
1703 | |
---|
1704 | this.context.beginPath(); |
---|
1705 | |
---|
1706 | var offset = 0; |
---|
1707 | |
---|
1708 | // Reset the stroke and lineWidth back to the same as what they were when the line was drawm |
---|
1709 | // UPDATE 28th July 2011 - the line width is now set to 1 |
---|
1710 | this.context.lineWidth = this.Get('chart.tickmarks.linewidth') ? this.Get('chart.tickmarks.linewidth') : this.Get('chart.linewidth'); |
---|
1711 | this.context.strokeStyle = isShadow ? this.Get('chart.shadow.color') : this.context.strokeStyle; |
---|
1712 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : this.context.strokeStyle; |
---|
1713 | |
---|
1714 | // Cicular tick marks |
---|
1715 | if ( tickmarks == 'circle' |
---|
1716 | || tickmarks == 'filledcircle' |
---|
1717 | || tickmarks == 'endcircle') { |
---|
1718 | |
---|
1719 | if (tickmarks == 'circle'|| tickmarks == 'filledcircle' || (tickmarks == 'endcircle') ) { |
---|
1720 | this.context.beginPath(); |
---|
1721 | this.context.arc(xPos + offset, yPos + offset, this.Get('chart.ticksize'), 0, 360 / (180 / Math.PI), false); |
---|
1722 | |
---|
1723 | if (tickmarks == 'filledcircle') { |
---|
1724 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : this.context.strokeStyle; |
---|
1725 | } else { |
---|
1726 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : 'white'; |
---|
1727 | } |
---|
1728 | |
---|
1729 | this.context.stroke(); |
---|
1730 | this.context.fill(); |
---|
1731 | } |
---|
1732 | |
---|
1733 | // Halfheight "Line" style tick marks |
---|
1734 | } else if (tickmarks == 'halftick') { |
---|
1735 | this.context.beginPath(); |
---|
1736 | this.context.moveTo(xPos, yPos); |
---|
1737 | this.context.lineTo(xPos, yPos + this.Get('chart.ticksize')); |
---|
1738 | |
---|
1739 | this.context.stroke(); |
---|
1740 | |
---|
1741 | // Tick style tickmarks |
---|
1742 | } else if (tickmarks == 'tick') { |
---|
1743 | this.context.beginPath(); |
---|
1744 | this.context.moveTo(xPos, yPos - this.Get('chart.ticksize')); |
---|
1745 | this.context.lineTo(xPos, yPos + this.Get('chart.ticksize')); |
---|
1746 | |
---|
1747 | this.context.stroke(); |
---|
1748 | |
---|
1749 | // Endtick style tickmarks |
---|
1750 | } else if (tickmarks == 'endtick') { |
---|
1751 | this.context.beginPath(); |
---|
1752 | this.context.moveTo(xPos, yPos - this.Get('chart.ticksize')); |
---|
1753 | this.context.lineTo(xPos, yPos + this.Get('chart.ticksize')); |
---|
1754 | |
---|
1755 | this.context.stroke(); |
---|
1756 | |
---|
1757 | // "Cross" style tick marks |
---|
1758 | } else if (tickmarks == 'cross') { |
---|
1759 | this.context.beginPath(); |
---|
1760 | this.context.moveTo(xPos - this.Get('chart.ticksize'), yPos - this.Get('chart.ticksize')); |
---|
1761 | this.context.lineTo(xPos + this.Get('chart.ticksize'), yPos + this.Get('chart.ticksize')); |
---|
1762 | this.context.moveTo(xPos + this.Get('chart.ticksize'), yPos - this.Get('chart.ticksize')); |
---|
1763 | this.context.lineTo(xPos - this.Get('chart.ticksize'), yPos + this.Get('chart.ticksize')); |
---|
1764 | |
---|
1765 | this.context.stroke(); |
---|
1766 | |
---|
1767 | |
---|
1768 | // Triangle style tick marks |
---|
1769 | } else if (tickmarks == 'triangle' || tickmarks == 'filledtriangle' || tickmarks == 'endtriangle') { |
---|
1770 | this.context.beginPath(); |
---|
1771 | |
---|
1772 | if (tickmarks == 'filledtriangle') { |
---|
1773 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : this.context.strokeStyle; |
---|
1774 | } else { |
---|
1775 | this.context.fillStyle = 'white'; |
---|
1776 | } |
---|
1777 | |
---|
1778 | this.context.moveTo(xPos - this.Get('chart.ticksize'), yPos + this.Get('chart.ticksize')); |
---|
1779 | this.context.lineTo(xPos, yPos - this.Get('chart.ticksize')); |
---|
1780 | this.context.lineTo(xPos + this.Get('chart.ticksize'), yPos + this.Get('chart.ticksize')); |
---|
1781 | this.context.closePath(); |
---|
1782 | |
---|
1783 | this.context.stroke(); |
---|
1784 | this.context.fill(); |
---|
1785 | |
---|
1786 | |
---|
1787 | // A white bordered circle |
---|
1788 | } else if (tickmarks == 'borderedcircle' || tickmarks == 'dot') { |
---|
1789 | this.context.lineWidth = 1; |
---|
1790 | this.context.strokeStyle = this.Get('chart.tickmarks.dot.color'); |
---|
1791 | this.context.fillStyle = this.Get('chart.tickmarks.dot.color'); |
---|
1792 | |
---|
1793 | // The outer white circle |
---|
1794 | this.context.beginPath(); |
---|
1795 | this.context.arc(xPos, yPos, this.Get('chart.ticksize'), 0, 360 / (180 / Math.PI), false); |
---|
1796 | this.context.closePath(); |
---|
1797 | |
---|
1798 | |
---|
1799 | this.context.fill(); |
---|
1800 | this.context.stroke(); |
---|
1801 | |
---|
1802 | // Now do the inners |
---|
1803 | this.context.beginPath(); |
---|
1804 | this.context.fillStyle = color; |
---|
1805 | this.context.strokeStyle = color; |
---|
1806 | this.context.arc(xPos, yPos, this.Get('chart.ticksize') - 2, 0, 360 / (180 / Math.PI), false); |
---|
1807 | |
---|
1808 | this.context.closePath(); |
---|
1809 | |
---|
1810 | this.context.fill(); |
---|
1811 | this.context.stroke(); |
---|
1812 | |
---|
1813 | } else if ( tickmarks == 'square' |
---|
1814 | || tickmarks == 'filledsquare' |
---|
1815 | || (tickmarks == 'endsquare') |
---|
1816 | || (tickmarks == 'filledendsquare') ) { |
---|
1817 | |
---|
1818 | this.context.fillStyle = 'white'; |
---|
1819 | this.context.strokeStyle = this.context.strokeStyle; // FIXME Is this correct? |
---|
1820 | |
---|
1821 | this.context.beginPath(); |
---|
1822 | this.context.strokeRect(xPos - this.Get('chart.ticksize'), yPos - this.Get('chart.ticksize'), this.Get('chart.ticksize') * 2, this.Get('chart.ticksize') * 2); |
---|
1823 | |
---|
1824 | // Fillrect |
---|
1825 | if (tickmarks == 'filledsquare' || tickmarks == 'filledendsquare') { |
---|
1826 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : this.context.strokeStyle; |
---|
1827 | this.context.fillRect(xPos - this.Get('chart.ticksize'), yPos - this.Get('chart.ticksize'), this.Get('chart.ticksize') * 2, this.Get('chart.ticksize') * 2); |
---|
1828 | |
---|
1829 | } else if (tickmarks == 'square' || tickmarks == 'endsquare') { |
---|
1830 | this.context.fillStyle = isShadow ? this.Get('chart.shadow.color') : 'white'; |
---|
1831 | this.context.fillRect((xPos - this.Get('chart.ticksize')) + 1, (yPos - this.Get('chart.ticksize')) + 1, (this.Get('chart.ticksize') * 2) - 2, (this.Get('chart.ticksize') * 2) - 2); |
---|
1832 | } |
---|
1833 | |
---|
1834 | this.context.stroke(); |
---|
1835 | this.context.fill(); |
---|
1836 | |
---|
1837 | /** |
---|
1838 | * FILLED arrowhead |
---|
1839 | */ |
---|
1840 | } else if (tickmarks == 'filledarrow') { |
---|
1841 | |
---|
1842 | var x = Math.abs(xPos - prevX); |
---|
1843 | var y = Math.abs(yPos - prevY); |
---|
1844 | |
---|
1845 | if (yPos < prevY) { |
---|
1846 | var a = Math.atan(x / y) + 1.57; |
---|
1847 | } else { |
---|
1848 | var a = Math.atan(y / x) + 3.14; |
---|
1849 | } |
---|
1850 | |
---|
1851 | this.context.beginPath(); |
---|
1852 | this.context.moveTo(xPos, yPos); |
---|
1853 | this.context.arc(xPos, yPos, 7, a - 0.5, a + 0.5, false); |
---|
1854 | this.context.closePath(); |
---|
1855 | |
---|
1856 | this.context.stroke(); |
---|
1857 | this.context.fill(); |
---|
1858 | |
---|
1859 | /** |
---|
1860 | * Arrow head, NOT filled |
---|
1861 | */ |
---|
1862 | } else if (tickmarks == 'arrow') { |
---|
1863 | |
---|
1864 | var x = Math.abs(xPos - prevX); |
---|
1865 | var y = Math.abs(yPos - prevY); |
---|
1866 | |
---|
1867 | if (yPos < prevY) { |
---|
1868 | var a = Math.atan(x / y) + 1.57; |
---|
1869 | } else { |
---|
1870 | var a = Math.atan(y / x) + 3.14; |
---|
1871 | } |
---|
1872 | |
---|
1873 | this.context.beginPath(); |
---|
1874 | this.context.moveTo(xPos, yPos); |
---|
1875 | this.context.arc(xPos, yPos, 7, a - 0.5 - (document.all ? 0.1 : 0.01), a - 0.4, false); |
---|
1876 | |
---|
1877 | this.context.moveTo(xPos, yPos); |
---|
1878 | this.context.arc(xPos, yPos, 7, a + 0.5 + (document.all ? 0.1 : 0.01), a + 0.5, true); |
---|
1879 | |
---|
1880 | |
---|
1881 | this.context.stroke(); |
---|
1882 | |
---|
1883 | /** |
---|
1884 | * Custom tick drawing function |
---|
1885 | */ |
---|
1886 | } else if (typeof(tickmarks) == 'function') { |
---|
1887 | tickmarks(this, lineData, lineData[index], index, xPos, yPos, color, prevX, prevY); |
---|
1888 | } |
---|
1889 | } |
---|
1890 | |
---|
1891 | |
---|
1892 | /** |
---|
1893 | * Draws a filled range if necessary |
---|
1894 | */ |
---|
1895 | RGraph.Line.prototype.DrawRange = function () |
---|
1896 | { |
---|
1897 | /** |
---|
1898 | * Fill the range if necessary |
---|
1899 | */ |
---|
1900 | if (this.Get('chart.filled.range') && this.Get('chart.filled')) { |
---|
1901 | this.context.beginPath(); |
---|
1902 | this.context.fillStyle = this.Get('chart.fillstyle'); |
---|
1903 | this.context.strokeStyle = this.Get('chart.fillstyle'); |
---|
1904 | this.context.lineWidth = 1; |
---|
1905 | var len = (this.coords.length / 2); |
---|
1906 | |
---|
1907 | for (var i=0; i<len; ++i) { |
---|
1908 | if (i == 0) { |
---|
1909 | this.context.moveTo(this.coords[i][0], this.coords[i][1]) |
---|
1910 | } else { |
---|
1911 | this.context.lineTo(this.coords[i][0], this.coords[i][1]) |
---|
1912 | } |
---|
1913 | } |
---|
1914 | |
---|
1915 | for (var i=this.coords.length - 1; i>=len; --i) { |
---|
1916 | this.context.lineTo(this.coords[i][0], this.coords[i][1]) |
---|
1917 | } |
---|
1918 | this.context.stroke(); |
---|
1919 | this.context.fill(); |
---|
1920 | } |
---|
1921 | } |
---|
1922 | |
---|
1923 | |
---|
1924 | /** |
---|
1925 | * Redraws the line with the correct line width etc |
---|
1926 | * |
---|
1927 | * @param array coords The coordinates of the line |
---|
1928 | */ |
---|
1929 | RGraph.Line.prototype.RedrawLine = function (coords, color, linewidth) |
---|
1930 | { |
---|
1931 | if (this.Get('chart.noredraw')) { |
---|
1932 | return; |
---|
1933 | } |
---|
1934 | |
---|
1935 | this.context.beginPath(); |
---|
1936 | this.context.strokeStyle = (typeof(color) == 'object' && color ? color[0] : color); |
---|
1937 | this.context.lineWidth = linewidth; |
---|
1938 | |
---|
1939 | var len = coords.length; |
---|
1940 | var width = RGraph.GetWidth(this); |
---|
1941 | var height = RGraph.GetHeight(this); |
---|
1942 | var penUp = false; |
---|
1943 | |
---|
1944 | for (var i=0; i<len; ++i) { |
---|
1945 | |
---|
1946 | var xPos = coords[i][0]; |
---|
1947 | var yPos = coords[i][1]; |
---|
1948 | |
---|
1949 | if (i > 0) { |
---|
1950 | var prevX = coords[i - 1][0]; |
---|
1951 | var prevY = coords[i - 1][1]; |
---|
1952 | } |
---|
1953 | |
---|
1954 | |
---|
1955 | if (( |
---|
1956 | (i == 0 && coords[i]) |
---|
1957 | || (yPos < this.gutterTop) |
---|
1958 | || (prevY < this.gutterTop) |
---|
1959 | || (yPos > (height - this.gutterBottom)) |
---|
1960 | || (i > 0 && prevX > (width - this.gutterRight)) |
---|
1961 | || (i > 0 && prevY > (height - this.gutterBottom)) |
---|
1962 | || prevY == null |
---|
1963 | || penUp == true |
---|
1964 | ) && (!this.Get('chart.outofbounds') || yPos == null || prevY == null) ) { |
---|
1965 | |
---|
1966 | this.context.moveTo(coords[i][0], coords[i][1]); |
---|
1967 | |
---|
1968 | penUp = false; |
---|
1969 | |
---|
1970 | } else { |
---|
1971 | |
---|
1972 | if (this.Get('chart.stepped') && i > 0) { |
---|
1973 | this.context.lineTo(coords[i][0], coords[i - 1][1]); |
---|
1974 | } |
---|
1975 | |
---|
1976 | // Don't draw the last bit of a stepped chart. Now DO |
---|
1977 | //if (!this.Get('chart.stepped') || i < (coords.length - 1)) { |
---|
1978 | this.context.lineTo(coords[i][0], coords[i][1]); |
---|
1979 | //} |
---|
1980 | penUp = false; |
---|
1981 | } |
---|
1982 | } |
---|
1983 | |
---|
1984 | /** |
---|
1985 | * If two colors are specified instead of one, go over the up bits |
---|
1986 | */ |
---|
1987 | if (this.Get('chart.colors.alternate') && typeof(color) == 'object' && color[0] && color[1]) { |
---|
1988 | for (var i=1; i<len; ++i) { |
---|
1989 | |
---|
1990 | var prevX = coords[i - 1][0]; |
---|
1991 | var prevY = coords[i - 1][1]; |
---|
1992 | |
---|
1993 | this.context.beginPath(); |
---|
1994 | this.context.strokeStyle = color[coords[i][1] < prevY ? 0 : 1]; |
---|
1995 | this.context.lineWidth = this.Get('chart.linewidth'); |
---|
1996 | this.context.moveTo(prevX, prevY); |
---|
1997 | this.context.lineTo(coords[i][0], coords[i][1]); |
---|
1998 | this.context.stroke(); |
---|
1999 | } |
---|
2000 | } |
---|
2001 | } |
---|
2002 | |
---|
2003 | |
---|
2004 | /** |
---|
2005 | * This function is used by MSIE only to manually draw the shadow |
---|
2006 | * |
---|
2007 | * @param array coords The coords for the line |
---|
2008 | */ |
---|
2009 | RGraph.Line.prototype.DrawIEShadow = function (coords, color) |
---|
2010 | { |
---|
2011 | var offsetx = this.Get('chart.shadow.offsetx'); |
---|
2012 | var offsety = this.Get('chart.shadow.offsety'); |
---|
2013 | |
---|
2014 | this.context.lineWidth = this.Get('chart.linewidth'); |
---|
2015 | this.context.strokeStyle = color; |
---|
2016 | this.context.beginPath(); |
---|
2017 | |
---|
2018 | for (var i=0; i<coords.length; ++i) { |
---|
2019 | if (i == 0) { |
---|
2020 | this.context.moveTo(coords[i][0] + offsetx, coords[i][1] + offsety); |
---|
2021 | } else { |
---|
2022 | this.context.lineTo(coords[i][0] + offsetx, coords[i][1] + offsety); |
---|
2023 | } |
---|
2024 | } |
---|
2025 | |
---|
2026 | this.context.stroke(); |
---|
2027 | } |
---|
2028 | |
---|
2029 | |
---|
2030 | /** |
---|
2031 | * Draw the backdrop |
---|
2032 | */ |
---|
2033 | RGraph.Line.prototype.DrawBackdrop = function (coords, color) |
---|
2034 | { |
---|
2035 | var size = this.Get('chart.backdrop.size'); |
---|
2036 | this.context.lineWidth = size; |
---|
2037 | this.context.globalAlpha = this.Get('chart.backdrop.alpha'); |
---|
2038 | this.context.strokeStyle = color; |
---|
2039 | this.context.lineJoin = 'miter'; |
---|
2040 | |
---|
2041 | this.context.beginPath(); |
---|
2042 | this.context.moveTo(coords[0][0], coords[0][1]); |
---|
2043 | for (var j=1; j<coords.length; ++j) { |
---|
2044 | this.context.lineTo(coords[j][0], coords[j][1]); |
---|
2045 | } |
---|
2046 | |
---|
2047 | this.context.stroke(); |
---|
2048 | |
---|
2049 | // Reset the alpha value |
---|
2050 | this.context.globalAlpha = 1; |
---|
2051 | this.context.lineJoin = 'round'; |
---|
2052 | RGraph.NoShadow(this); |
---|
2053 | } |
---|
2054 | |
---|
2055 | |
---|
2056 | /** |
---|
2057 | * Returns the linewidth |
---|
2058 | */ |
---|
2059 | RGraph.Line.prototype.GetLineWidth = function (i) |
---|
2060 | { |
---|
2061 | var linewidth = this.Get('chart.linewidth'); |
---|
2062 | |
---|
2063 | if (typeof(linewidth) == 'number') { |
---|
2064 | return linewidth; |
---|
2065 | |
---|
2066 | } else if (typeof(linewidth) == 'object') { |
---|
2067 | if (linewidth[i]) { |
---|
2068 | return linewidth[i]; |
---|
2069 | } else { |
---|
2070 | return linewidth[0]; |
---|
2071 | } |
---|
2072 | |
---|
2073 | alert('[LINE] Error! chart.linewidth should be a single number or an array of one or more numbers'); |
---|
2074 | } |
---|
2075 | } |
---|
2076 | |
---|
2077 | |
---|
2078 | /** |
---|
2079 | * The getPoint() method - used to get the point the mouse is currently over, if any |
---|
2080 | * |
---|
2081 | * @param object e The event object |
---|
2082 | */ |
---|
2083 | RGraph.Line.prototype.getPoint = function (e) |
---|
2084 | { |
---|
2085 | var canvas = e.target; |
---|
2086 | var obj = canvas.__object__; |
---|
2087 | var context = obj.context; |
---|
2088 | var mouseXY = RGraph.getMouseXY(e); |
---|
2089 | var mouseX = mouseXY[0]; |
---|
2090 | var mouseY = mouseXY[1]; |
---|
2091 | |
---|
2092 | for (var i=0; i<obj.coords.length; ++i) { |
---|
2093 | |
---|
2094 | var xCoord = obj.coords[i][0]; |
---|
2095 | var yCoord = obj.coords[i][1]; |
---|
2096 | |
---|
2097 | if ( mouseX <= (xCoord + 5) |
---|
2098 | && mouseX >= (xCoord - 5) |
---|
2099 | && mouseY <= (yCoord + 5) |
---|
2100 | && mouseY >= (yCoord - 5) |
---|
2101 | ) { |
---|
2102 | |
---|
2103 | return [obj, xCoord, yCoord, i]; |
---|
2104 | } |
---|
2105 | } |
---|
2106 | } |
---|
2107 | |
---|
2108 | |
---|
2109 | /** |
---|
2110 | * Draws the above line labels |
---|
2111 | */ |
---|
2112 | RGraph.Line.prototype.DrawAboveLabels = function () |
---|
2113 | { |
---|
2114 | var context = this.context; |
---|
2115 | var size = this.Get('chart.labels.above.size'); |
---|
2116 | var font = this.Get('chart.text.font'); |
---|
2117 | var units_pre = this.Get('chart.units.pre'); |
---|
2118 | var units_post = this.Get('chart.units.post'); |
---|
2119 | |
---|
2120 | context.beginPath(); |
---|
2121 | |
---|
2122 | // Don't need to check that chart.labels.above is enabled here, it's been done already |
---|
2123 | for (var i=0; i<this.coords.length; ++i) { |
---|
2124 | var coords = this.coords[i]; |
---|
2125 | |
---|
2126 | RGraph.Text(context, font, size, coords[0], coords[1] - 5 - size, RGraph.number_format(this, this.data_arr[i], units_pre, units_post), 'center', 'center', true, null, 'rgba(255, 255, 255, 0.7)'); |
---|
2127 | } |
---|
2128 | |
---|
2129 | context.fill(); |
---|
2130 | } |
---|