OLD | NEW |
| (Empty) |
1 /* | |
2 * ChartNew.js | |
3 * | |
4 * Vancoppenolle Francois - January 2014 | |
5 * francois.vancoppenolle@favomo.be | |
6 * | |
7 * Source location : http:\\www.favomo.be\graphjs | |
8 * GitHub community : https://github.com/FVANCOP/ChartNew.js | |
9 * | |
10 * This file is an adaptation of the chart.js source developped by Nick Downie (
2013) | |
11 * https://github.com/nnnick/Chart.js | |
12 * | |
13 * new charts | |
14 * | |
15 * horizontalBar | |
16 * horizontalStackedBar | |
17 * | |
18 * Added items : | |
19 * | |
20 * Title | |
21 * Subtitle | |
22 * X Axis Label | |
23 * Y Axis Label | |
24 * Unit Label | |
25 * Y Axis on the right and/or the left | |
26 * Annotates | |
27 * canvas Border | |
28 * Legend | |
29 * Footnote | |
30 * crossText | |
31 * graphMin / graphMax | |
32 * logarithmic y-axis (for line and bar) | |
33 * rotateLabels | |
34 * and lot of others... | |
35 * | |
36 */ | |
37 // non standard functions; | |
38 if (typeof String.prototype.trim !== 'function') { | |
39 String.prototype.trim = function() { | |
40 return this.replace(/^\s+|\s+$/g, ''); | |
41 } | |
42 }; | |
43 if (!Array.prototype.indexOf) { | |
44 Array.prototype.indexOf = function(searchElement /*, fromIndex */ ) { | |
45 "use strict"; | |
46 if (this == null) { | |
47 throw new TypeError(); | |
48 } | |
49 var t = Object(this); | |
50 var len = t.length >>> 0; | |
51 if (len === 0) { | |
52 return -1; | |
53 } | |
54 var n = 0; | |
55 if (arguments.length > 0) { | |
56 n = Number(arguments[1]); | |
57 if (n != n) { // shortcut for verifying if it's NaN | |
58 n = 0; | |
59 } else if (n != 0 && n != Infinity && n != -Infinity) { | |
60 n = (n > 0 || -1) * Math.floor(Math.abs(n)); | |
61 } | |
62 } | |
63 if (n >= len) { | |
64 return -1; | |
65 } | |
66 var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); | |
67 for (; k < len; k++) { | |
68 if (k in t && t[k] === searchElement) { | |
69 return k; | |
70 } | |
71 } | |
72 return -1; | |
73 } | |
74 }; | |
75 var charJSPersonalDefaultOptions = {} | |
76 var charJSPersonalDefaultOptionsLine = {} | |
77 var charJSPersonalDefaultOptionsRadar = {} | |
78 var charJSPersonalDefaultOptionsPolarArea = {} | |
79 var charJSPersonalDefaultOptionsPie = {} | |
80 var charJSPersonalDefaultOptionsDoughnut = {} | |
81 var charJSPersonalDefaultOptionsBar = {} | |
82 var charJSPersonalDefaultOptionsStackedBar = {} | |
83 var charJSPersonalDefaultOptionsHorizontalBar = {} | |
84 var charJSPersonalDefaultOptionsHorizontalStackedBar = {} | |
85 ///////// FUNCTIONS THAN CAN BE USED IN THE TEMPLATES //////////////////
///////////////////////// | |
86 | |
87 function roundToWithThousands(config, num, place) { | |
88 var newval = 1 * unFormat(config, num); | |
89 if (typeof(newval) == "number" && place != "none") { | |
90 if (place <= 0) { | |
91 var roundVal = -place; | |
92 newval = +(Math.round(newval + "e+" + roundVal) + "e-" +
roundVal); | |
93 } else { | |
94 var roundVal = place; | |
95 var divval = "1e+" + roundVal; | |
96 newval = +(Math.round(newval / divval)) * divval; | |
97 } | |
98 } | |
99 newval = fmtChartJS(config, newval, "none"); | |
100 return (newval); | |
101 }; | |
102 | |
103 function unFormat(config, num) { | |
104 if ((config.decimalSeparator != "." || config.thousandSeparator != "") &
& typeof(num) == "string") { | |
105 var v1 = "" + num; | |
106 if (config.thousandSeparator != "") { | |
107 while (v1.indexOf(config.thousandSeparator) >= 0) v1 = "
" + v1.replace(config.thousandSeparator, ""); | |
108 } | |
109 if (config.decimalSeparator != ".") v1 = "" + v1.replace(config.
decimalSeparator, ".") | |
110 // v1=fmtChartJS(config,1*roundToWithThousands(1*v1
,place),"none") | |
111 return 1 * v1; | |
112 } else { | |
113 return num; | |
114 } | |
115 }; | |
116 ///////// ANNOTATE PART OF THE SCRIPT //////////////////////////////////////////
/ | |
117 /*******************************************************************************
* | |
118 Copyright (C) 1999 Thomas Brattli | |
119 This script is made by and copyrighted to Thomas Brattli | |
120 Visit for more great scripts. This may be used freely as long as this msg is int
act! | |
121 I will also appriciate any links you could give me. | |
122 Distributed by Hypergurl | |
123 ********************************************************************************
/ | |
124 var cachebis = {}; | |
125 | |
126 function fmtChartJSPerso(config, value, fmt) { | |
127 switch (fmt) { | |
128 case "SampleJS_Format": | |
129 if (typeof(value) == "number") return_value = "My Format
: " + value.toString() + " $"; | |
130 else return_value = value + "XX"; | |
131 break; | |
132 case "Change_Month": | |
133 if (typeof(value) == "string") return_value = value.toSt
ring() + " 2014"; | |
134 else return_value = value.toString() + "YY"; | |
135 break; | |
136 default: | |
137 return_value = value; | |
138 break; | |
139 } | |
140 return (return_value); | |
141 }; | |
142 | |
143 function fmtChartJS(config, value, fmt) { | |
144 var return_value; | |
145 if (fmt == "notformatted") { | |
146 return_value = value; | |
147 } else if (fmt == "none" && typeof(value) == "number") { | |
148 if (config.roundNumber != "none") { | |
149 if (config.roundNumber <= 0) { | |
150 var roundVal = -config.roundNumber; | |
151 value = +(Math.round(value + "e+" + roundVal) +
"e-" + roundVal); | |
152 } else { | |
153 var roundVal = config.roundNumber; | |
154 var divval = "1e+" + roundVal; | |
155 value = +(Math.round(value / divval)) * divval; | |
156 } | |
157 } | |
158 if (config.decimalSeparator != "." || config.thousandSeparator !
= "") { | |
159 return_value = value.toString().replace(/\./g, config.de
cimalSeparator); | |
160 if (config.thousandSeparator != "") { | |
161 var part1 = return_value; | |
162 var part2 = ""; | |
163 var posdec = part1.indexOf(config.decimalSeparat
or); | |
164 if (posdec >= 0) { | |
165 part2 = part1.substring(posdec + 1, part
1.length); | |
166 part2 = part2.split('').reverse().join('
'); // reverse string | |
167 part1 = part1.substring(0, posdec); | |
168 } | |
169 part1 = part1.toString().replace(/\B(?=(\d{3})+(
?!\d))/g, config.thousandSeparator); | |
170 // part2=part2.toString().replace(/\B(?=(\d{3})+
(?!\d))/g, config.thousandSeparator); | |
171 part2 = part2.split('').reverse().join(''); // r
everse string | |
172 return_value = part1 | |
173 if (part2 != "") return_value = return_value + c
onfig.decimalSeparator + part2; | |
174 } | |
175 } else return_value = value; | |
176 } else if (fmt != "none" && fmt != "notformatted") { | |
177 return_value = fmtChartJSPerso(config, value, fmt); | |
178 } else { | |
179 return_value = value; | |
180 } | |
181 return (return_value); | |
182 }; | |
183 | |
184 function addParameters2Function(data, fctName, fctList) { | |
185 var mathFunctions = { | |
186 mean: { | |
187 data: data.data, | |
188 datasetNr: data.v11 | |
189 }, | |
190 varianz: { | |
191 data: data.data, | |
192 datasetNr: data.v11 | |
193 }, | |
194 stddev: { | |
195 data: data.data, | |
196 datasetNr: data.v11 | |
197 }, | |
198 cv: { | |
199 data: data.data, | |
200 datasetNr: data.v11 | |
201 }, | |
202 median: { | |
203 data: data.data, | |
204 datasetNr: data.v11 | |
205 } | |
206 }; | |
207 // difference to current value (v3) | |
208 dif = false; | |
209 if (fctName.substr(-3) == "Dif") { | |
210 fctName = fctName.substr(0, fctName.length - 3); | |
211 dif = true; | |
212 } | |
213 if (typeof eval(fctName) == "function") { | |
214 var parameter = eval(fctList + "." + fctName); | |
215 if (dif) { | |
216 // difference between v3 (current value) and mat
h function | |
217 return data.v3 - window[fctName](parameter); | |
218 } | |
219 return window[fctName](parameter); | |
220 } | |
221 return; | |
222 } | |
223 //Is a number function | |
224 | |
225 function isNumber(n) { | |
226 return !isNaN(parseFloat(n)) && isFinite(n); | |
227 }; | |
228 | |
229 function tmplbis(str, data) { | |
230 var mathFunctionList = ["mean", "varianz", "stddev", "cv", "median"]; | |
231 var regexMath = new RegExp('<%=((?:(?:.*?)\\W)??)((?:' + mathFunctionLis
t.join('|') + ')(?:Dif)?)\\(([0-9]*?)\\)(.*?)%>', 'g'); | |
232 while (regexMath.test(str)) { | |
233 str = str.replace(regexMath, function($0, $1, $2, $3, $4) { | |
234 if ($3) { | |
235 var rndFac = $3; | |
236 } else { | |
237 var rndFac = 2; | |
238 } | |
239 var value = addParameters2Function(data, $2, "mathFuncti
ons"); | |
240 if (isNumber(value)) { | |
241 return '<%=' + $1 + '' + Math.round(Math.pow(10,
rndFac) * value) / Math.pow(10, rndFac) + '' + $4 + '%>'; | |
242 } | |
243 return '<%= %>'; | |
244 }); | |
245 } | |
246 // Figure out if we're getting a template, or if we need to | |
247 // load the template - and be sure to cache the result. | |
248 // first check if it's can be an id | |
249 var fn = /^[A-Za-z][-A-Za-z0-9_:.]*$/.test(str) ? cachebis[str] = cacheb
is[str] || | |
250 tmplbis(document.getElementById(str).innerHTML) : | |
251 // Generate a reusable function that will serve as a template | |
252 // generator (and which will be cached). | |
253 new Function("obj", | |
254 "var p=[],print=function(){p.push.apply(p,arguments);};"
+ | |
255 // Introduce the data as local variables using with(){} | |
256 "with(obj){p.push('" + | |
257 // Convert the template into pure JavaScript | |
258 str | |
259 .replace(/[\r\n]/g, "\\n") | |
260 .replace(/[\t]/g, " ") | |
261 .split("<%").join("\t") | |
262 .replace(/((^|%>)[^\t]*)'/g, "$1\r") | |
263 .replace(/\t=(.*?)%>/g, "',$1,'") | |
264 .split("\t").join("');") | |
265 .split("%>").join("p.push('") | |
266 .split("\r").join("\\'") + "');}return p.join('');"); | |
267 // Provide some basic currying to the user | |
268 return data ? fn(data) : fn; | |
269 }; | |
270 /** | |
271 * ctx.prototype | |
272 * fillText option for canvas Multiline Support | |
273 * @param text string \n for newline | |
274 * @param x x position | |
275 * @param y y position | |
276 * @param yLevel = "bottom" => last line has this y-Pos [default], = "middle" =>
the middle line has this y-Pos) | |
277 * @param lineHeight lineHeight | |
278 */ | |
279 CanvasRenderingContext2D.prototype.fillTextMultiLine = function(text, x, y, yLev
el, lineHeight) { | |
280 var lines = ("" + text).split("\n"); | |
281 // if its one line => in the middle | |
282 // two lines one above the mid one below etc. | |
283 if (yLevel == "middle") { | |
284 y -= ((lines.length - 1) / 2) * lineHeight; | |
285 } else if (yLevel == "bottom") { // default | |
286 y -= (lines.length - 1) * lineHeight; | |
287 } | |
288 for (var i = 0; i < lines.length; i++) { | |
289 this.fillText(lines[i], x, y); | |
290 y += lineHeight; | |
291 } | |
292 } | |
293 CanvasRenderingContext2D.prototype.measureTextMultiLine = function(text, lineHei
ght) { | |
294 var textWidth = 0; | |
295 var lg; | |
296 var lines = ("" + text).split("\n"); | |
297 var textHeight = lines.length * lineHeight; | |
298 // if its one line => in the middle | |
299 // two lines one above the mid one below etc. | |
300 for (var i = 0; i < lines.length; i++) { | |
301 lg = this.measureText(lines[i]).width; | |
302 if (lg > textWidth) textWidth = lg; | |
303 } | |
304 return { | |
305 textWidth: textWidth, | |
306 textHeight: textHeight | |
307 }; | |
308 } | |
309 cursorDivCreated = false; | |
310 | |
311 function createCursorDiv() { | |
312 if (cursorDivCreated == false) { | |
313 var div = document.createElement('divCursor'); | |
314 div.id = 'divCursor'; | |
315 div.style.position = 'absolute'; | |
316 document.body.appendChild(div); | |
317 cursorDivCreated = true; | |
318 } | |
319 }; | |
320 | |
321 initChartJsResize = false; | |
322 var jsGraphResize = new Array(); | |
323 | |
324 function addResponsiveChart(id,ctx,data,config) { | |
325 initChartResize(); | |
326 var newSize=resizeGraph(ctx,config); | |
327 | |
328 if(typeof ctx.prevWidth != "undefined") { | |
329 resizeCtx(ctx,newSize.newWidth,newSize.newHeight); | |
330 ctx.prevWidth=newSize.newWidth; | |
331 } | |
332 ctx.prevWidth=newSize.newWidth; | |
333 ctx.prevHeight=newSize.newHeight; | |
334 jsGraphResize[jsGraphResize.length]= [id,ctx.tpchart,ctx,data,config]; | |
335 }; | |
336 | |
337 function initChartResize() { | |
338 if(initChartJsResize==false) { | |
339 window.addEventListener("resize", chartJsResize); | |
340 } | |
341 }; | |
342 | |
343 function getMaximumWidth(domNode){ | |
344 var container = domNode.parentNode; | |
345 // TODO = check cross browser stuff with this. | |
346 return container.clientWidth; | |
347 }; | |
348 | |
349 function getMaximumHeight(domNode){ | |
350 var container = domNode.parentNode; | |
351 // TODO = check cross browser stuff with this. | |
352 return container.clientHeight; | |
353 }; | |
354 | |
355 | |
356 function resizeCtx(ctx,newWidth,newHeight) | |
357 { | |
358 if (window.devicePixelRatio) { // Retina devine | |
359 | |
360 ctx.canvas.style.width = newWidth/window.devicePixelRatio + "px"
; | |
361 ctx.canvas.style.height = newHeight/window.devicePixelRatio + "p
x"; | |
362 ctx.canvas.height = newHeight/window.devicePixelRatio * window.d
evicePixelRatio; | |
363 ctx.canvas.width = newWidth/window.devicePixelRatio * window.dev
icePixelRatio; | |
364 ctx.scale(window.devicePixelRatio, window.devicePixelRatio); | |
365 } else { | |
366 ctx.canvas.height = newHeight ; | |
367 ctx.canvas.width = newWidth; | |
368 } | |
369 } | |
370 | |
371 function resizeGraph(ctx,config) { | |
372 if(typeof config.maintainAspectRatio == "undefined")config.maintainAspec
tRatio=true; | |
373 var canvas = ctx.canvas; | |
374 if(typeof ctx.aspectRatio == "undefined") { | |
375 ctx.aspectRatio = canvas.width / canvas.height; | |
376 } | |
377 var newWidth = getMaximumWidth(canvas); | |
378 var newHeight = config.maintainAspectRatio ? newWidth / ctx.aspectRatio
: getMaximumHeight(canvas); | |
379 return { newWidth : parseInt(newWidth), newHeight : parseInt(newHeight)
}; | |
380 }; | |
381 | |
382 | |
383 | |
384 function chartJsResize() { | |
385 for (var i=0;i<jsGraphResize.length;i++) { | |
386 if(typeof jsGraphResize[i][2].firstPass != "undefined") { | |
387 if(jsGraphResize[i][2].firstPass == 5)jsGraphResize[i][2
].firstPass=6; | |
388 } | |
389 subUpdateChart(jsGraphResize[i][2],jsGraphResize[i][3],jsGraphRe
size[i][4]); | |
390 } | |
391 }; | |
392 | |
393 function testRedraw(ctx,data,config) { | |
394 if (ctx.firstPass==2 || ctx.firstPass==4 || ctx.firstPass==9) { | |
395 ctx.firstPass=6; | |
396 subUpdateChart(ctx,data,config) ; | |
397 return true; | |
398 } else { | |
399 ctx.firstPass=5; | |
400 return false; | |
401 } | |
402 } | |
403 | |
404 function updateChart(ctx,data,config,animation,runanimationcompletefunction) { | |
405 if (ctx.firstPass==5) | |
406 { | |
407 ctx.runanimationcompletefunction=runanimationcompletefunction; | |
408 if(animation)ctx.firstPass=0; | |
409 else if (config.responsive) ctx.firstPass=7; | |
410 else ctx.firstPass=7; | |
411 subUpdateChart(ctx,data,config) ; | |
412 | |
413 } | |
414 } | |
415 | |
416 function subUpdateChart(ctx,data,config) { | |
417 // ctx.firstPass==undefined => graph never drawn | |
418 // ctx.firstPass==0 => graph is drawn but need to be redrawn with animat
ion | |
419 // ctx.firstPass==1 => graph is drawn with animation | |
420 // ctx.firstPass==2 => graph is in animation but at the end the graph ne
ed perhaps to be redrawn; | |
421 // ctx.firstPass==3 => graph currently drawing without animation; | |
422 // ctx.firstPass==4 => graph currently drawing without animationb but at
the end, the graph need perhaps to be redrawn; | |
423 // ctx.firstPass==5 => graph is displayed ; | |
424 // ctx.firstPass==6 => graph is displayed but need to be redraw without
animation (because of a resize); | |
425 // ctx.firstPass==7 => graph is displayed but need to be redraw without
responsivity; | |
426 | |
427 | |
428 if(!dynamicFunction(data, config, ctx)) { return; } | |
429 | |
430 if(typeof ctx.firstPass == "undefined") { | |
431 ctx.firstPass=1; | |
432 var newSize=resizeGraph(ctx,config); | |
433 if(config.responsive) { | |
434 resizeCtx(ctx,newSize.newWidth,newSize.newHeight); | |
435 ctx.prevWidth=newSize.newWidth; | |
436 ctx.prevHeight=newSize.newHeight; | |
437 } else { | |
438 ctx.prevWidth=0; | |
439 ctx.prevHeight=0; | |
440 } | |
441 ctx.runanimationcompletefunction=true; | |
442 redrawGraph(ctx,data,config); | |
443 } else if(ctx.firstPass == 0) { | |
444 ctx.firstPass=1; | |
445 var newSize=resizeGraph(ctx,config); | |
446 if(config.responsive) { | |
447 resizeCtx(ctx,newSize.newWidth,newSize.newHeight); | |
448 ctx.prevWidth=newSize.newWidth; | |
449 ctx.prevHeight=newSize.newHeight; | |
450 } else { | |
451 ctx.prevWidth=0; | |
452 ctx.prevHeight=0; | |
453 } | |
454 redrawGraph(ctx,data,config); | |
455 } else if(ctx.firstPass==1 || ctx.firstPass==2) { | |
456 ctx.firstPass=2; | |
457 } else if (ctx.firstPass==3 || ctx.firstPass==4) { | |
458 ctx.firstPass=4; | |
459 } else if(ctx.firstPass==5) { | |
460 ctx.firstPass=1; | |
461 redrawGraph(ctx,data,config); | |
462 } else if(ctx.firstPass==6) { | |
463 var newSize=resizeGraph(ctx,config); | |
464 if (newSize.newWidth!=ctx.prevWidth || newSize.newHeight != ctx.
prevHeight) { | |
465 ctx.firstPass=3; | |
466 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
; | |
467 if(config.responsive) { | |
468 resizeCtx(ctx,newSize.newWidth,newSize.newHeight
); | |
469 ctx.prevWidth=newSize.newWidth; | |
470 ctx.prevHeight=newSize.newHeight; | |
471 } else { | |
472 ctx.prevWidth=0; | |
473 ctx.prevHeight=0; | |
474 } | |
475 redrawGraph(ctx,data,config); | |
476 } else ctx.firstPass=5; | |
477 } else if(ctx.firstPass==7) { | |
478 var newSize=resizeGraph(ctx,config); | |
479 ctx.firstPass=3; | |
480 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); | |
481 if(config.responsive) { | |
482 resizeCtx(ctx,newSize.newWidth,newSize.newHeight); | |
483 ctx.prevWidth=newSize.newWidth; | |
484 ctx.prevHeight=newSize.newHeight; | |
485 } else { | |
486 ctx.prevWidth=0; | |
487 ctx.prevHeight=0; | |
488 } | |
489 redrawGraph(ctx,data,config); | |
490 } | |
491 }; | |
492 | |
493 function redrawGraph(ctx,data,config) { | |
494 var myGraph = new Chart(ctx); | |
495 switch (ctx.tpchart) { | |
496 case "Bar": | |
497 myGraph.Bar(data,config); | |
498 break; | |
499 case "Pie": | |
500 myGraph.Pie(data,config); | |
501 break; | |
502 case "Doughnut": | |
503 myGraph.Doughnut(data,config); | |
504 break; | |
505 case "Radar": | |
506 myGraph.Radar(data,config); | |
507 break; | |
508 case "PolarArea": | |
509 myGraph.PolarArea(data,config); | |
510 break; | |
511 case "HorizontalBar": | |
512 myGraph.HorizontalBar(data,config); | |
513 break; | |
514 case "StackedBar": | |
515 myGraph.StackedBar(data,config); | |
516 break; | |
517 case "HorizontalStackedBar": | |
518 myGraph.HorizontalStackedBar(data,config); | |
519 break; | |
520 case "Line": | |
521 myGraph.Line(data,config); | |
522 break; | |
523 } | |
524 | |
525 | |
526 | |
527 } | |
528 | |
529 | |
530 //Default browsercheck, added to all scripts! | |
531 function checkBrowser() { | |
532 this.ver = navigator.appVersion | |
533 this.dom = document.getElementById ? 1 : 0 | |
534 this.ie5 = (this.ver.indexOf("MSIE 5") > -1 && this.dom) ? 1 : 0; | |
535 this.ie4 = (document.all && !this.dom) ? 1 : 0; | |
536 this.ns5 = (this.dom && parseInt(this.ver) >= 5) ? 1 : 0; | |
537 this.ns4 = (document.layers && !this.dom) ? 1 : 0; | |
538 this.bw = (this.ie5 || this.ie4 || this.ns4 || this.ns5) | |
539 return this | |
540 }; | |
541 bw = new checkBrowser(); | |
542 //Set these variables: | |
543 fromLeft = 10; // How much from the left of the cursor should the div be? | |
544 fromTop = 10; // How much from the top of the cursor should the div be? | |
545 /******************************************************************** | |
546 Initilizes the objects | |
547 *********************************************************************/ | |
548 function cursorInit() { | |
549 scrolled = bw.ns4 || bw.ns5 ? "window.pageYOffset" : "document.body.scro
llTop" | |
550 if (bw.ns4) document.captureEvents(Event.MOUSEMOVE) | |
551 }; | |
552 /******************************************************************** | |
553 Contructs the cursorobjects | |
554 *********************************************************************/ | |
555 function makeCursorObj(obj, nest) { | |
556 createCursorDiv(); | |
557 nest = (!nest) ? '' : 'document.' + nest + '.' | |
558 this.css = bw.dom ? document.getElementById(obj).style : bw.ie4 ? docume
nt.all[obj].style : bw.ns4 ? eval(nest + "document.layers." + obj) : 0; | |
559 this.moveIt = b_moveIt; | |
560 cursorInit(); | |
561 return this | |
562 }; | |
563 | |
564 function b_moveIt(x, y) { | |
565 this.x = x; | |
566 this.y = y; | |
567 this.css.left = this.x + "px"; | |
568 this.css.top = this.y + "px"; | |
569 }; | |
570 | |
571 function isIE() { | |
572 var myNav = navigator.userAgent.toLowerCase(); | |
573 return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1])
: false; | |
574 }; | |
575 | |
576 function mergeChartConfig(defaults, userDefined) { | |
577 var returnObj = {}; | |
578 for (var attrname in defaults) { | |
579 returnObj[attrname] = defaults[attrname]; | |
580 } | |
581 for (var attrname in userDefined) { | |
582 returnObj[attrname] = userDefined[attrname]; | |
583 } | |
584 return returnObj; | |
585 }; | |
586 | |
587 function sleep(ms) { | |
588 var dt = new Date(); | |
589 dt.setTime(dt.getTime() + ms); | |
590 while (new Date().getTime() < dt.getTime()) {}; | |
591 }; | |
592 | |
593 function saveCanvas(ctx, data, config) { | |
594 cvSave = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); | |
595 var saveCanvasConfig = { | |
596 savePng: false, | |
597 annotateDisplay: false, | |
598 animation: false, | |
599 dynamicDisplay: false | |
600 }; | |
601 var savePngConfig = mergeChartConfig(config, saveCanvasConfig); | |
602 savePngConfig.clearRect = false; | |
603 /* And ink them */ | |
604 | |
605 redrawGraph(ctx,data,savePngConfig); | |
606 if (config.savePngOutput == "NewWindow") { | |
607 var image = ctx.canvas.toDataURL(); | |
608 ctx.putImageData(cvSave, 0, 0); | |
609 window.open(image, '_blank'); | |
610 } | |
611 if (config.savePngOutput == "CurrentWindow") { | |
612 var image = ctx.canvas.toDataURL(); | |
613 ctx.putImageData(cvSave, 0, 0); | |
614 window.location.href = image; | |
615 } | |
616 if (config.savePngOutput == "Save") { | |
617 // document.location.href= ctx.canvas.toDataURL("image/
png").replace("image/png", "image/octet-stream"); | |
618 // ctx.putImageData(cvSave,0,0); | |
619 var image = ctx.canvas.toDataURL(); | |
620 var downloadLink = document.createElement("a"); | |
621 downloadLink.href = image; | |
622 downloadLink.download = config.savePngName + ".png"; | |
623 document.body.appendChild(downloadLink); | |
624 downloadLink.click(); | |
625 document.body.removeChild(downloadLink); | |
626 } | |
627 }; | |
628 //if (isIE() < 9 && isIE() != false) { | |
629 if (typeof String.prototype.trim !== 'function') { | |
630 String.prototype.trim = function() { | |
631 return this.replace(/^\s+|\s+$/g, ''); | |
632 } | |
633 }; | |
634 //}; | |
635 var dynamicDisplay = new Array(); | |
636 var dynamicDisplayList = new Array(); | |
637 | |
638 function dynamicFunction(data, config, ctx) { | |
639 | |
640 if (config.dynamicDisplay) { | |
641 if (ctx.canvas.id == "") { | |
642 var cvdate = new Date(); | |
643 var cvmillsec = cvdate.getTime(); | |
644 ctx.canvas.id = "Canvas_" + cvmillsec; | |
645 } | |
646 if (typeof(dynamicDisplay[ctx.canvas.id]) == "undefined") { | |
647 dynamicDisplayList[dynamicDisplayList["length"]] = ctx.c
anvas.id; | |
648 dynamicDisplay[ctx.canvas.id] = [ctx, false, false, data
, config, ctx.canvas]; | |
649 dynamicDisplay[ctx.canvas.id][1] = isScrolledIntoView(ct
x.canvas); | |
650 window.onscroll = scrollFunction; | |
651 } else if (dynamicDisplay[ctx.canvas.id][2] == false) { | |
652 dynamicDisplay[ctx.canvas.id][1] = isScrolledIntoView(ct
x.canvas); | |
653 } | |
654 // if (dynamicDisplay[ctx.canvas.id][1] == false || dynamicDisplay[
ctx.canvas.id][2] == true) { | |
655 if (dynamicDisplay[ctx.canvas.id][1] == false && dynamicDisplay[
ctx.canvas.id][2] == false) { | |
656 return false; | |
657 } | |
658 dynamicDisplay[ctx.canvas.id][2] = true; | |
659 } | |
660 return true; | |
661 }; | |
662 | |
663 function isScrolledIntoView(element) { | |
664 var xPosition = 0; | |
665 var yPosition = 0; | |
666 elem = element; | |
667 while (elem) { | |
668 xPosition += (elem.offsetLeft - elem.scrollLeft + elem.clientLef
t); | |
669 yPosition += (elem.offsetTop - elem.scrollTop + elem.clientTop); | |
670 elem = elem.offsetParent; | |
671 } | |
672 if (xPosition + element.width / 2 >= window.pageXOffset && | |
673 xPosition + element.width / 2 <= window.pageXOffset + window.inn
erWidth && | |
674 yPosition + element.height / 2 >= window.pageYOffset && | |
675 yPosition + element.height / 2 <= window.pageYOffset + window.in
nerHeight | |
676 ) return (true); | |
677 else return false; | |
678 }; | |
679 | |
680 function scrollFunction() { | |
681 for (var i = 0; i < dynamicDisplayList["length"]; i++) { | |
682 if (isScrolledIntoView(dynamicDisplay[dynamicDisplayList[i]][5])
&& dynamicDisplay[dynamicDisplayList[i]][2] == false) { | |
683 dynamicDisplay[dynamicDisplayList[i]][1] = true; | |
684 redrawGraph(dynamicDisplay[dynamicDisplayList[i]][0],dyn
amicDisplay[dynamicDisplayList[i]][3], dynamicDisplay[dynamicDisplayList[i]][4])
; | |
685 } | |
686 } | |
687 }; | |
688 | |
689 var jsGraphAnnotate = new Array(); | |
690 | |
691 function clearAnnotate(ctxid) { | |
692 jsGraphAnnotate[ctxid] = []; | |
693 }; | |
694 | |
695 function getMousePos(canvas, evt) { | |
696 var rect = canvas.getBoundingClientRect(); | |
697 return { | |
698 x: evt.clientX - rect.left, | |
699 y: evt.clientY - rect.top | |
700 }; | |
701 }; | |
702 | |
703 function doMouseAction(config, ctx, event, data, action, funct) { | |
704 | |
705 var onData = false; | |
706 if (action == "annotate") { | |
707 var annotateDIV = document.getElementById('divCursor'); | |
708 var show = false; | |
709 annotateDIV.className = (config.annotateClassName) ? config.anno
tateClassName : ''; | |
710 annotateDIV.style.border = (config.annotateClassName) ? '' : con
fig.annotateBorder; | |
711 annotateDIV.style.padding = (config.annotateClassName) ? '' : co
nfig.annotatePadding; | |
712 annotateDIV.style.borderRadius = (config.annotateClassName) ? ''
: config.annotateBorderRadius; | |
713 annotateDIV.style.backgroundColor = (config.annotateClassName) ?
'' : config.annotateBackgroundColor; | |
714 annotateDIV.style.color = (config.annotateClassName) ? '' : conf
ig.annotateFontColor; | |
715 annotateDIV.style.fontFamily = (config.annotateClassName) ? '' :
config.annotateFontFamily; | |
716 annotateDIV.style.fontSize = (config.annotateClassName) ? '' : c
onfig.annotateFontSize + "pt"; | |
717 annotateDIV.style.fontStyle = (config.annotateClassName) ? '' :
config.annotateFontStyle; | |
718 } | |
719 if (action=="annotate") { | |
720 show=false; | |
721 annotateDIV.style.display = show ? '' : 'none'; | |
722 } | |
723 canvas_pos = getMousePos(ctx.canvas, event); | |
724 for (i = 0; i < jsGraphAnnotate[ctx.ChartNewId]["length"]; i++) { | |
725 if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "ARC") { | |
726 distance = Math.sqrt((canvas_pos.x - jsGraphAnnotate[ctx
.ChartNewId][i][1]) * (canvas_pos.x - jsGraphAnnotate[ctx.ChartNewId][i][1]) + (
canvas_pos.y - jsGraphAnnotate[ctx.ChartNewId][i][2]) * (canvas_pos.y - jsGraphA
nnotate[ctx.ChartNewId][i][2])); | |
727 if (distance > jsGraphAnnotate[ctx.ChartNewId][i][3] &&
distance < jsGraphAnnotate[ctx.ChartNewId][i][4]) { | |
728 angle = Math.acos((canvas_pos.x - jsGraphAnnotat
e[ctx.ChartNewId][i][1]) / distance); | |
729 if (canvas_pos.y < jsGraphAnnotate[ctx.ChartNewI
d][i][2]) angle = -angle; | |
730 while (angle < 0) { | |
731 angle += 2 * Math.PI; | |
732 } | |
733 while (angle > 2 * Math.PI) { | |
734 angle -= 2 * Math.PI; | |
735 } | |
736 if (angle < config.startAngle * (Math.PI / 360))
angle += 2 * Math.PI; | |
737 if ((angle > jsGraphAnnotate[ctx.ChartNewId][i][
5] && angle < jsGraphAnnotate[ctx.ChartNewId][i][6]) || (angle > jsGraphAnnotate
[ctx.ChartNewId][i][5] - 2 * Math.PI && angle < jsGraphAnnotate[ctx.ChartNewId][
i][6] - 2 * Math.PI) || (angle > jsGraphAnnotate[ctx.ChartNewId][i][5] + 2 * Mat
h.PI && angle < jsGraphAnnotate[ctx.ChartNewId][i][6] + 2 * Math.PI)) { | |
738 v1 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][7], config.fmtV1); // V1=Label | |
739 v2 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][8], config.fmtV2); // V2=Data Value | |
740 v3 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][9], config.fmtV3); // V3=Cumulated Value | |
741 v4 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][10], config.fmtV4); // V4=Total Data Value | |
742 v5 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][11], config.fmtV5); // V5=Angle | |
743 v6 = fmtChartJS(config, 100 * jsGraphAnn
otate[ctx.ChartNewId][i][8] / jsGraphAnnotate[ctx.ChartNewId][i][10], config.fmt
V6); // v6=Percentage; | |
744 v6 = roundToWithThousands(config, v6, co
nfig.roundPct); | |
745 v7 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][1], config.fmtV7); // v7=midPointX of arc; | |
746 v8 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][2], config.fmtV8); // v8=midPointY of arc; | |
747 v9 = fmtChartJS(config, jsGraphAnnotate[
ctx.ChartNewId][i][3], config.fmtV9); // v9=radius Minimum; | |
748 v10 = fmtChartJS(config, jsGraphAnnotate
[ctx.ChartNewId][i][4], config.fmtV10); // v10=radius Maximum; | |
749 v11 = fmtChartJS(config, jsGraphAnnotate
[ctx.ChartNewId][i][5], config.fmtV11); // v11=start angle; | |
750 v12 = fmtChartJS(config, jsGraphAnnotate
[ctx.ChartNewId][i][6], config.fmtV12); // v12=stop angle; | |
751 v13 = fmtChartJS(config, jsGraphAnnotate
[ctx.ChartNewId][i][12], config.fmtV13); // v13=position in Data; | |
752 graphPosX = canvas_pos.x; | |
753 graphPosY = canvas_pos.y; | |
754 onData = true; | |
755 if (action == "annotate") { | |
756 dispString = tmplbis(config.anno
tateLabel, { | |
757 config: config, | |
758 v1: v1, | |
759 v2: v2, | |
760 v3: v3, | |
761 v4: v4, | |
762 v5: v5, | |
763 v6: v6, | |
764 v7: v7, | |
765 v8: v8, | |
766 v9: v9, | |
767 v10: v10, | |
768 v11: v11, | |
769 v12: v12, | |
770 v13: v13, | |
771 graphPosX: graphPosX, | |
772 graphPosY: graphPosY | |
773 }); | |
774 annotateDIV.innerHTML = dispStri
ng; | |
775 show = true; | |
776 } else { | |
777 funct(event, ctx, config, data,
{ | |
778 v1: v1, | |
779 v2: v2, | |
780 v3: v3, | |
781 v4: v4, | |
782 v5: v5, | |
783 v6: v6, | |
784 v7: v7, | |
785 v8: v8, | |
786 v9: v9, | |
787 v10: v10, | |
788 v11: v11, | |
789 v12: v12, | |
790 v13: v13, | |
791 graphPosX: graphPosX, | |
792 graphPosY: graphPosY | |
793 }); | |
794 } | |
795 if (action == "annotate") { | |
796 x = bw.ns4 || bw.ns5 ? event.pag
eX : event.x; | |
797 y = bw.ns4 || bw.ns5 ? event.pag
eY : event.y; | |
798 if (bw.ie4 || bw.ie5) y = y + ev
al(scrolled); | |
799 oCursor.moveIt(x + fromLeft, y +
fromTop); | |
800 } | |
801 } | |
802 } | |
803 } else if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "RECT") { | |
804 if (canvas_pos.x > jsGraphAnnotate[ctx.ChartNewId][i][1]
&& canvas_pos.x < jsGraphAnnotate[ctx.ChartNewId][i][3] && canvas_pos.y < jsGra
phAnnotate[ctx.ChartNewId][i][2] && canvas_pos.y > jsGraphAnnotate[ctx.ChartNewI
d][i][4]) { | |
805 v1 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][5], config.fmtV1); // V1=Label1 | |
806 v2 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][6], config.fmtV2); // V2=Label2 | |
807 v3 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][7], config.fmtV3); // V3=Data Value | |
808 v4 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][8], config.fmtV4); // V4=Cumulated Value | |
809 v5 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][9], config.fmtV5); // V5=Total Data Value | |
810 v6 = fmtChartJS(config, 100 * jsGraphAnnotate[ct
x.ChartNewId][i][7] / jsGraphAnnotate[ctx.ChartNewId][i][9], config.fmtV6); // v
6=Percentage; | |
811 v6 = roundToWithThousands(config, v6, config.rou
ndPct); | |
812 v7 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][1], config.fmtV7); // v7=top X of rectangle; | |
813 v8 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][2], config.fmtV8); // v8=top Y of rectangle; | |
814 v9 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][3], config.fmtV9); // v9=bottom X of rectangle; | |
815 v10 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][4], config.fmtV10); // v10=bottom Y of rectangle; | |
816 v11 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][10], config.fmtV11); // v11=position in Dataset; | |
817 v12 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][11], config.fmtV12); // v12=position in Dataset[v11].Data; | |
818 graphPosX = canvas_pos.x; | |
819 graphPosY = canvas_pos.y; | |
820 onData = true; | |
821 if (action == "annotate") { | |
822 dispString = tmplbis(config.annotateLabe
l, { | |
823 config: config, | |
824 v1: v1, | |
825 v2: v2, | |
826 v3: v3, | |
827 v4: v4, | |
828 v5: v5, | |
829 v6: v6, | |
830 v7: v7, | |
831 v8: v8, | |
832 v9: v9, | |
833 v10: v10, | |
834 v11: v11, | |
835 v12: v12, | |
836 graphPosX: graphPosX, | |
837 graphPosY: graphPosY, | |
838 data: data | |
839 }); | |
840 annotateDIV.innerHTML = dispString; | |
841 show = true; | |
842 } else { | |
843 funct(event, ctx, config, data, { | |
844 v1: v1, | |
845 v2: v2, | |
846 v3: v3, | |
847 v4: v4, | |
848 v5: v5, | |
849 v6: v6, | |
850 v7: v7, | |
851 v8: v8, | |
852 v9: v9, | |
853 v10: v10, | |
854 v11: v11, | |
855 v12: v12, | |
856 graphPosX: graphPosX, | |
857 graphPosY: graphPosY | |
858 }); | |
859 } | |
860 if (action == "annotate") { | |
861 x = bw.ns4 || bw.ns5 ? event.pageX : eve
nt.x; | |
862 y = bw.ns4 || bw.ns5 ? event.pageY : eve
nt.y; | |
863 if (bw.ie4 || bw.ie5) y = y + eval(scrol
led); | |
864 oCursor.moveIt(x + fromLeft, y + fromTop
); | |
865 } | |
866 } | |
867 } else if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "POINT") { | |
868 distance = Math.sqrt((canvas_pos.x - jsGraphAnnotate[ctx
.ChartNewId][i][1]) * (canvas_pos.x - jsGraphAnnotate[ctx.ChartNewId][i][1]) + (
canvas_pos.y - jsGraphAnnotate[ctx.ChartNewId][i][2]) * (canvas_pos.y - jsGraphA
nnotate[ctx.ChartNewId][i][2])); | |
869 if (distance < 10) { | |
870 v1 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][3], config.fmtV1); // V1=Label1 | |
871 v2 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][4], config.fmtV2); // V2=Label2 | |
872 v3 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][5], config.fmtV3); // V3=Data Value | |
873 v4 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][6], config.fmtV4); // V4=Difference with Previous line | |
874 v5 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][7], config.fmtV5); // V5=Difference with next line; | |
875 v6 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][8], config.fmtV6); // V6=max; | |
876 v7 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][9], config.fmtV7); // V7=Total; | |
877 v8 = fmtChartJS(config, 100 * jsGraphAnnotate[ct
x.ChartNewId][i][5] / jsGraphAnnotate[ctx.ChartNewId][i][9], config.fmtV8); // v
8=percentage; | |
878 v8 = roundToWithThousands(config, v8, config.rou
ndPct); | |
879 v9 = fmtChartJS(config, jsGraphAnnotate[ctx.Char
tNewId][i][1], config.fmtV9); // v9=pos X of point; | |
880 v10 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][2], config.fmtV10); // v10=pos Y of point; | |
881 v11 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][10], config.fmtV11); // v11=position in Dataset; | |
882 v12 = fmtChartJS(config, jsGraphAnnotate[ctx.Cha
rtNewId][i][11], config.fmtV12); // v12=position in Dataset[v11].Data; | |
883 graphPosX = canvas_pos.x; | |
884 graphPosY = canvas_pos.y; | |
885 onData = true; | |
886 if (action == "annotate") { | |
887 dispString = tmplbis(config.annotateLabe
l, { | |
888 config: config, | |
889 v1: v1, | |
890 v2: v2, | |
891 v3: v3, | |
892 v4: v4, | |
893 v5: v5, | |
894 v6: v6, | |
895 v7: v7, | |
896 v8: v8, | |
897 v9: v9, | |
898 v10: v10, | |
899 v11: v11, | |
900 v12: v12, | |
901 graphPosX: graphPosX, | |
902 graphPosY: graphPosY, | |
903 data: data | |
904 }); | |
905 annotateDIV.innerHTML = dispString; | |
906 show = true; | |
907 } else { | |
908 funct(event, ctx, config, data, { | |
909 v1: v1, | |
910 v2: v2, | |
911 v3: v3, | |
912 v4: v4, | |
913 v5: v5, | |
914 v6: v6, | |
915 v7: v7, | |
916 v8: v8, | |
917 v9: v9, | |
918 v10: v10, | |
919 v11: v11, | |
920 v12: v12, | |
921 graphPosX: graphPosX, | |
922 graphPosY: graphPosY | |
923 }); | |
924 } | |
925 if (action == "annotate") { | |
926 x = bw.ns4 || bw.ns5 ? event.pageX : eve
nt.x; | |
927 y = bw.ns4 || bw.ns5 ? event.pageY : eve
nt.y; | |
928 if (bw.ie4 || bw.ie5) y = y + eval(scrol
led); | |
929 oCursor.moveIt(x + fromLeft, y + fromTop
); | |
930 } | |
931 } | |
932 } | |
933 if (action == "annotate") { | |
934 annotateDIV.style.display = show ? '' : 'none'; | |
935 } | |
936 } | |
937 if (onData == false && action != "annotate") { | |
938 funct(event, ctx, config, data, null); | |
939 } | |
940 }; | |
941 ///////// GRAPHICAL PART OF THE SCRIPT /////////////////////////////////////////
// | |
942 //Define the global Chart Variable as a class. | |
943 window.Chart = function(context) { | |
944 var chart = this; | |
945 //Easing functions adapted from Robert Penner's easing equations | |
946 //http://www.robertpenner.com/easing/ | |
947 var animationOptions = { | |
948 linear: function(t) { | |
949 return t; | |
950 }, | |
951 easeInQuad: function(t) { | |
952 return t * t; | |
953 }, | |
954 easeOutQuad: function(t) { | |
955 return -1 * t * (t - 2); | |
956 }, | |
957 easeInOutQuad: function(t) { | |
958 if ((t /= 1 / 2) < 1) return 1 / 2 * t * t; | |
959 return -1 / 2 * ((--t) * (t - 2) - 1); | |
960 }, | |
961 easeInCubic: function(t) { | |
962 return t * t * t; | |
963 }, | |
964 easeOutCubic: function(t) { | |
965 return 1 * ((t = t / 1 - 1) * t * t + 1); | |
966 }, | |
967 easeInOutCubic: function(t) { | |
968 if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t; | |
969 return 1 / 2 * ((t -= 2) * t * t + 2); | |
970 }, | |
971 easeInQuart: function(t) { | |
972 return t * t * t * t; | |
973 }, | |
974 easeOutQuart: function(t) { | |
975 return -1 * ((t = t / 1 - 1) * t * t * t - 1); | |
976 }, | |
977 easeInOutQuart: function(t) { | |
978 if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t; | |
979 return -1 / 2 * ((t -= 2) * t * t * t - 2); | |
980 }, | |
981 easeInQuint: function(t) { | |
982 return 1 * (t /= 1) * t * t * t * t; | |
983 }, | |
984 easeOutQuint: function(t) { | |
985 return 1 * ((t = t / 1 - 1) * t * t * t * t + 1); | |
986 }, | |
987 easeInOutQuint: function(t) { | |
988 if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t * t; | |
989 return 1 / 2 * ((t -= 2) * t * t * t * t + 2); | |
990 }, | |
991 easeInSine: function(t) { | |
992 return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1; | |
993 }, | |
994 easeOutSine: function(t) { | |
995 return 1 * Math.sin(t / 1 * (Math.PI / 2)); | |
996 }, | |
997 easeInOutSine: function(t) { | |
998 return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1); | |
999 }, | |
1000 easeInExpo: function(t) { | |
1001 return (t == 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1)); | |
1002 }, | |
1003 easeOutExpo: function(t) { | |
1004 return (t == 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1
); | |
1005 }, | |
1006 easeInOutExpo: function(t) { | |
1007 if (t == 0) return 0; | |
1008 if (t == 1) return 1; | |
1009 if ((t /= 1 / 2) < 1) return 1 / 2 * Math.pow(2, 10 * (t
- 1)); | |
1010 return 1 / 2 * (-Math.pow(2, -10 * --t) + 2); | |
1011 }, | |
1012 easeInCirc: function(t) { | |
1013 if (t >= 1) return t; | |
1014 return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1); | |
1015 }, | |
1016 easeOutCirc: function(t) { | |
1017 return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t); | |
1018 }, | |
1019 easeInOutCirc: function(t) { | |
1020 if ((t /= 1 / 2) < 1) return -1 / 2 * (Math.sqrt(1 - t *
t) - 1); | |
1021 return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1); | |
1022 }, | |
1023 easeInElastic: function(t) { | |
1024 var s = 1.70158; | |
1025 var p = 0; | |
1026 var a = 1; | |
1027 if (t == 0) return 0; | |
1028 if ((t /= 1) == 1) return 1; | |
1029 if (!p) p = 1 * .3; | |
1030 if (a < Math.abs(1)) { | |
1031 a = 1; | |
1032 var s = p / 4; | |
1033 } else var s = p / (2 * Math.PI) * Math.asin(1 / a); | |
1034 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t *
1 - s) * (2 * Math.PI) / p)); | |
1035 }, | |
1036 easeOutElastic: function(t) { | |
1037 var s = 1.70158; | |
1038 var p = 0; | |
1039 var a = 1; | |
1040 if (t == 0) return 0; | |
1041 if ((t /= 1) == 1) return 1; | |
1042 if (!p) p = 1 * .3; | |
1043 if (a < Math.abs(1)) { | |
1044 a = 1; | |
1045 var s = p / 4; | |
1046 } else var s = p / (2 * Math.PI) * Math.asin(1 / a); | |
1047 return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) *
(2 * Math.PI) / p) + 1; | |
1048 }, | |
1049 easeInOutElastic: function(t) { | |
1050 var s = 1.70158; | |
1051 var p = 0; | |
1052 var a = 1; | |
1053 if (t == 0) return 0; | |
1054 if ((t /= 1 / 2) == 2) return 1; | |
1055 if (!p) p = 1 * (.3 * 1.5); | |
1056 if (a < Math.abs(1)) { | |
1057 a = 1; | |
1058 var s = p / 4; | |
1059 } else var s = p / (2 * Math.PI) * Math.asin(1 / a); | |
1060 if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1))
* Math.sin((t * 1 - s) * (2 * Math.PI) / p)); | |
1061 return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1
- s) * (2 * Math.PI) / p) * .5 + 1; | |
1062 }, | |
1063 easeInBack: function(t) { | |
1064 var s = 1.70158; | |
1065 return 1 * (t /= 1) * t * ((s + 1) * t - s); | |
1066 }, | |
1067 easeOutBack: function(t) { | |
1068 var s = 1.70158; | |
1069 return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1)
; | |
1070 }, | |
1071 easeInOutBack: function(t) { | |
1072 var s = 1.70158; | |
1073 if ((t /= 1 / 2) < 1) return 1 / 2 * (t * t * (((s *= (1
.525)) + 1) * t - s)); | |
1074 return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t
+ s) + 2); | |
1075 }, | |
1076 easeInBounce: function(t) { | |
1077 return 1 - animationOptions.easeOutBounce(1 - t); | |
1078 }, | |
1079 easeOutBounce: function(t) { | |
1080 if ((t /= 1) < (1 / 2.75)) { | |
1081 return 1 * (7.5625 * t * t); | |
1082 } else if (t < (2 / 2.75)) { | |
1083 return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + .
75); | |
1084 } else if (t < (2.5 / 2.75)) { | |
1085 return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t +
.9375); | |
1086 } else { | |
1087 return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t +
.984375); | |
1088 } | |
1089 }, | |
1090 easeInOutBounce: function(t) { | |
1091 if (t < 1 / 2) return animationOptions.easeInBounce(t *
2) * .5; | |
1092 return animationOptions.easeOutBounce(t * 2 - 1) * .5 +
1 * .5; | |
1093 } | |
1094 }; | |
1095 //Variables global to the chart | |
1096 var width = context.canvas.width; | |
1097 var height = context.canvas.height; | |
1098 //High pixel density displays - multiply the size of the canvas height/w
idth by the device pixel ratio, then scale. | |
1099 if (window.devicePixelRatio) { | |
1100 context.canvas.style.width = width + "px"; | |
1101 context.canvas.style.height = height + "px"; | |
1102 context.canvas.height = height * window.devicePixelRatio; | |
1103 context.canvas.width = width * window.devicePixelRatio; | |
1104 context.scale(window.devicePixelRatio, window.devicePixelRatio); | |
1105 }; | |
1106 this.PolarArea = function(data, options) { | |
1107 chart.PolarArea.defaults = { | |
1108 inGraphDataShow: false, | |
1109 inGraphDataPaddingRadius: 5, | |
1110 inGraphDataPaddingAngle: 0, | |
1111 inGraphDataTmpl: "<%=(v1 == ''? '' : v1+':')+ v2 + ' ('
+ v6 + ' %)'%>", | |
1112 inGraphDataAlign: "off-center", // "right", "center", "l
eft", "off-center" or "to-center" | |
1113 inGraphDataVAlign: "off-center", // "bottom", "center",
"top", "off-center" or "to-center" | |
1114 inGraphDataRotate: 0, // rotateAngle value (0->360) , "i
nRadiusAxis" or "inRadiusAxisRotateLabels" | |
1115 inGraphDataFontFamily: "'Arial'", | |
1116 inGraphDataFontSize: 12, | |
1117 inGraphDataFontStyle: "normal", | |
1118 inGraphDataFontColor: "#666", | |
1119 inGraphDataRadiusPosition: 3, | |
1120 inGraphDataAnglePosition: 2, | |
1121 scaleOverlay: true, | |
1122 scaleOverride: false, | |
1123 scaleOverride2: false, | |
1124 scaleSteps: null, | |
1125 scaleStepWidth: null, | |
1126 scaleStartValue: null, | |
1127 scaleShowLine: true, | |
1128 scaleLineColor: "rgba(0,0,0,.1)", | |
1129 scaleLineWidth: 1, | |
1130 scaleShowLabels: true, | |
1131 scaleShowLabels2: true, | |
1132 scaleLabel: "<%=value%>", | |
1133 scaleFontFamily: "'Arial'", | |
1134 scaleFontSize: 12, | |
1135 scaleFontStyle: "normal", | |
1136 scaleFontColor: "#666", | |
1137 scaleShowLabelBackdrop: true, | |
1138 scaleBackdropColor: "rgba(255,255,255,0.75)", | |
1139 scaleBackdropPaddingY: 2, | |
1140 scaleBackdropPaddingX: 2, | |
1141 segmentShowStroke: true, | |
1142 segmentStrokeColor: "#fff", | |
1143 segmentStrokeWidth: 2, | |
1144 animation: true, | |
1145 animationSteps: 100, | |
1146 animationEasing: "easeOutBounce", | |
1147 animateRotate: true, | |
1148 animateScale: false, | |
1149 onAnimationComplete: null, | |
1150 annotateLabel: "<%=(v1 == ''? '' : v1+':')+ v2 + ' (' +
v6 + ' %)'%>", | |
1151 startAngle: 90 | |
1152 }; | |
1153 chart.PolarArea.defaults = mergeChartConfig(chart.defaults.commo
nOptions, chart.PolarArea.defaults); | |
1154 chart.PolarArea.defaults = mergeChartConfig(chart.PolarArea.defa
ults, charJSPersonalDefaultOptions); | |
1155 chart.PolarArea.defaults = mergeChartConfig(chart.PolarArea.defa
ults, charJSPersonalDefaultOptionsPolarArea); | |
1156 var config = (options) ? mergeChartConfig(chart.PolarArea.defaul
ts, options) : chart.PolarArea.defaults; | |
1157 return new PolarArea(data, config, context); | |
1158 }; | |
1159 this.Radar = function(data, options) { | |
1160 chart.Radar.defaults = { | |
1161 inGraphDataShow: false, | |
1162 inGraphDataPaddingRadius: 5, | |
1163 inGraphDataTmpl: "<%=v3%>", | |
1164 inGraphDataAlign: "off-center", // "right", "center", "l
eft", "off-center" or "to-center" | |
1165 inGraphDataVAlign: "off-center", // "right", "center", "
left", "off-center" or "to-center" | |
1166 inGraphDataRotate: 0, // rotateAngle value (0->360) , "i
nRadiusAxis" or "inRadiusAxisRotateLabels" | |
1167 inGraphDataFontFamily: "'Arial'", | |
1168 inGraphDataFontSize: 12, | |
1169 inGraphDataFontStyle: "normal", | |
1170 inGraphDataFontColor: "#666", | |
1171 inGraphDataRadiusPosition: 3, | |
1172 yAxisMinimumInterval: "none", | |
1173 scaleOverlay: false, | |
1174 scaleOverride: false, | |
1175 scaleOverride2: false, | |
1176 scaleSteps: null, | |
1177 scaleStepWidth: null, | |
1178 scaleStartValue: null, | |
1179 scaleShowLine: true, | |
1180 scaleLineColor: "rgba(0,0,0,.1)", | |
1181 scaleLineWidth: 1, | |
1182 scaleShowLabels: false, | |
1183 scaleShowLabels2: true, | |
1184 scaleLabel: "<%=value%>", | |
1185 scaleFontFamily: "'Arial'", | |
1186 scaleFontSize: 12, | |
1187 scaleFontStyle: "normal", | |
1188 scaleFontColor: "#666", | |
1189 scaleShowLabelBackdrop: true, | |
1190 scaleBackdropColor: "rgba(255,255,255,0.75)", | |
1191 scaleBackdropPaddingY: 2, | |
1192 scaleBackdropPaddingX: 2, | |
1193 angleShowLineOut: true, | |
1194 angleLineColor: "rgba(0,0,0,.1)", | |
1195 angleLineWidth: 1, | |
1196 pointLabelFontFamily: "'Arial'", | |
1197 pointLabelFontStyle: "normal", | |
1198 pointLabelFontSize: 12, | |
1199 pointLabelFontColor: "#666", | |
1200 pointDot: true, | |
1201 pointDotRadius: 3, | |
1202 pointDotStrokeWidth: 1, | |
1203 datasetFill: true, | |
1204 datasetStrokeWidth: 2, | |
1205 animation: true, | |
1206 animationSteps: 60, | |
1207 animationEasing: "easeOutQuart", | |
1208 onAnimationComplete: null, | |
1209 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3%>", | |
1210 startAngle: 90, | |
1211 graphMaximized: false // if true, the graph will not be
centered in the middle of the canvas | |
1212 }; | |
1213 // merge annotate defaults | |
1214 chart.Radar.defaults = mergeChartConfig(chart.defaults.commonOpt
ions, chart.Radar.defaults); | |
1215 chart.Radar.defaults = mergeChartConfig(chart.Radar.defaults, ch
arJSPersonalDefaultOptions); | |
1216 chart.Radar.defaults = mergeChartConfig(chart.Radar.defaults, ch
arJSPersonalDefaultOptionsRadar); | |
1217 var config = (options) ? mergeChartConfig(chart.Radar.defaults,
options) : chart.Radar.defaults; | |
1218 return new Radar(data, config, context); | |
1219 }; | |
1220 this.Pie = function(data, options) { | |
1221 chart.Pie.defaults = { | |
1222 inGraphDataShow: false, | |
1223 inGraphDataPaddingRadius: 5, | |
1224 inGraphDataPaddingAngle: 0, | |
1225 inGraphDataTmpl: "<%=(v1 == ''? '' : v1+':')+ v2 + ' ('
+ v6 + ' %)'%>", | |
1226 inGraphDataAlign: "off-center", // "right", "center", "l
eft", "off-center" or "to-center" | |
1227 inGraphDataVAlign: "off-center", // "bottom", "center",
"top", "off-center" or "to-center" | |
1228 inGraphDataRotate: 0, // rotateAngle value (0->360) , "i
nRadiusAxis" or "inRadiusAxisRotateLabels" | |
1229 inGraphDataFontFamily: "'Arial'", | |
1230 inGraphDataFontSize: 12, | |
1231 inGraphDataFontStyle: "normal", | |
1232 inGraphDataFontColor: "#666", | |
1233 inGraphDataRadiusPosition: 3, | |
1234 inGraphDataAnglePosition: 2, | |
1235 inGraphDataMinimumAngle : 0, | |
1236 segmentShowStroke: true, | |
1237 segmentStrokeColor: "#fff", | |
1238 segmentStrokeWidth: 2, | |
1239 animation: true, | |
1240 animationSteps: 100, | |
1241 animationEasing: "easeOutBounce", | |
1242 animateRotate: true, | |
1243 animateScale: false, | |
1244 onAnimationComplete: null, | |
1245 annotateLabel: "<%=(v1 == ''? '' : v1+':')+ v2 + ' (' +
v6 + ' %)'%>", | |
1246 startAngle: 90, | |
1247 radiusScale: 1 | |
1248 }; | |
1249 // merge annotate defaults | |
1250 chart.Pie.defaults = mergeChartConfig(chart.defaults.commonOptio
ns, chart.Pie.defaults); | |
1251 chart.Pie.defaults = mergeChartConfig(chart.Pie.defaults, charJS
PersonalDefaultOptions); | |
1252 chart.Pie.defaults = mergeChartConfig(chart.Pie.defaults, charJS
PersonalDefaultOptionsPie); | |
1253 var config = (options) ? mergeChartConfig(chart.Pie.defaults, op
tions) : chart.Pie.defaults; | |
1254 return new Pie(data, config, context); | |
1255 }; | |
1256 this.Doughnut = function(data, options) { | |
1257 chart.Doughnut.defaults = { | |
1258 inGraphDataShow: false, | |
1259 inGraphDataPaddingRadius: 5, | |
1260 inGraphDataPaddingAngle: 0, | |
1261 inGraphDataTmpl: "<%=(v1 == ''? '' : v1+':')+ v2 + ' ('
+ v6 + ' %)'%>", | |
1262 inGraphDataAlign: "off-center", // "right", "center", "l
eft", "off-center" or "to-center" | |
1263 inGraphDataVAlign: "off-center", // "bottom", "middle",
"top", "off-center" or "to-center" | |
1264 inGraphDataRotate: 0, // rotateAngle value (0->360) , "i
nRadiusAxis" or "inRadiusAxisRotateLabels" | |
1265 inGraphDataFontFamily: "'Arial'", | |
1266 inGraphDataFontSize: 12, | |
1267 inGraphDataFontStyle: "normal", | |
1268 inGraphDataFontColor: "#666", | |
1269 inGraphDataRadiusPosition: 3, | |
1270 inGraphDataAnglePosition: 2, | |
1271 inGraphDataMinimumAngle : 0, | |
1272 segmentShowStroke: true, | |
1273 segmentStrokeColor: "#fff", | |
1274 segmentStrokeWidth: 2, | |
1275 percentageInnerCutout: 50, | |
1276 animation: true, | |
1277 animationSteps: 100, | |
1278 animationEasing: "easeOutBounce", | |
1279 animateRotate: true, | |
1280 animateScale: false, | |
1281 onAnimationComplete: null, | |
1282 annotateLabel: "<%=(v1 == ''? '' : v1+':')+ v2 + ' (' +
v6 + ' %)'%>", | |
1283 startAngle: 90, | |
1284 radiusScale: 1 | |
1285 }; | |
1286 // merge annotate defaults | |
1287 chart.Doughnut.defaults = mergeChartConfig(chart.defaults.common
Options, chart.Doughnut.defaults); | |
1288 chart.Doughnut.defaults = mergeChartConfig(chart.Doughnut.defaul
ts, charJSPersonalDefaultOptions); | |
1289 chart.Doughnut.defaults = mergeChartConfig(chart.Doughnut.defaul
ts, charJSPersonalDefaultOptionsDoughnut); | |
1290 var config = (options) ? mergeChartConfig(chart.Doughnut.default
s, options) : chart.Doughnut.defaults; | |
1291 return new Doughnut(data, config, context); | |
1292 }; | |
1293 this.Line = function(data, options) { | |
1294 chart.Line.defaults = { | |
1295 inGraphDataShow: false, | |
1296 inGraphDataPaddingX: 3, | |
1297 inGraphDataPaddingY: 3, | |
1298 inGraphDataTmpl: "<%=v3%>", | |
1299 inGraphDataAlign: "left", | |
1300 inGraphDataVAlign: "bottom", | |
1301 inGraphDataRotate: 0, | |
1302 inGraphDataFontFamily: "'Arial'", | |
1303 inGraphDataFontSize: 12, | |
1304 inGraphDataFontStyle: "normal", | |
1305 inGraphDataFontColor: "#666", | |
1306 drawXScaleLine: [{ | |
1307 position: "bottom" | |
1308 }], | |
1309 scaleOverlay: false, | |
1310 scaleOverride: false, | |
1311 scaleOverride2: false, | |
1312 scaleSteps: null, | |
1313 scaleStepWidth: null, | |
1314 scaleStartValue: null, | |
1315 scaleSteps2: null, | |
1316 scaleStepWidth2: null, | |
1317 scaleStartValue2: null, | |
1318 scaleLabel2 : "<%=value%>", | |
1319 scaleLineColor: "rgba(0,0,0,.1)", | |
1320 scaleLineWidth: 1, | |
1321 scaleShowLabels: true, | |
1322 scaleShowLabels2: true, | |
1323 scaleLabel: "<%=value%>", | |
1324 scaleFontFamily: "'Arial'", | |
1325 scaleFontSize: 12, | |
1326 scaleFontStyle: "normal", | |
1327 scaleFontColor: "#666", | |
1328 scaleShowGridLines: true, | |
1329 scaleXGridLinesStep: 1, | |
1330 scaleYGridLinesStep: 1, | |
1331 scaleGridLineColor: "rgba(0,0,0,.05)", | |
1332 scaleGridLineWidth: 1, | |
1333 showYAxisMin: true, // Show the minimum value on Y axis
(in original version, this minimum is not displayed - it can overlap the X label
s) | |
1334 rotateLabels: "smart", // smart <=> 0 degre if space eno
ugh; otherwise 45 degres if space enough otherwise90 degre; | |
1335 // you can force an integer value between 0 and 180 degr
es | |
1336 logarithmic: false, // can be 'fuzzy',true and false ('f
uzzy' => if the gap between min and maximum is big it's using a logarithmic y-Ax
is scale | |
1337 logarithmic2: false, // can be 'fuzzy',true and false ('
fuzzy' => if the gap between min and maximum is big it's using a logarithmic y-A
xis scale | |
1338 scaleTickSizeLeft: 5, | |
1339 scaleTickSizeRight: 5, | |
1340 scaleTickSizeBottom: 5, | |
1341 scaleTickSizeTop: 5, | |
1342 bezierCurve: true, | |
1343 pointDot: true, | |
1344 pointDotRadius: 4, | |
1345 pointDotStrokeWidth: 2, | |
1346 datasetStrokeWidth: 2, | |
1347 datasetFill: true, | |
1348 animation: true, | |
1349 animationSteps: 60, | |
1350 animationEasing: "easeOutQuart", | |
1351 extrapolateMissingData: true, | |
1352 onAnimationComplete: null, | |
1353 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3%>" | |
1354 }; | |
1355 // merge annotate defaults | |
1356 chart.Line.defaults = mergeChartConfig(chart.defaults.commonOpti
ons, chart.Line.defaults); | |
1357 chart.Line.defaults = mergeChartConfig(chart.defaults.xyAxisComm
onOptions, chart.Line.defaults); | |
1358 chart.Line.defaults = mergeChartConfig(chart.Line.defaults, char
JSPersonalDefaultOptions); | |
1359 chart.Line.defaults = mergeChartConfig(chart.Line.defaults, char
JSPersonalDefaultOptionsLine); | |
1360 var config = (options) ? mergeChartConfig(chart.Line.defaults, o
ptions) : chart.Line.defaults; | |
1361 return new Line(data, config, context); | |
1362 }; | |
1363 this.StackedBar = function(data, options) { | |
1364 chart.StackedBar.defaults = { | |
1365 inGraphDataShow: false, | |
1366 inGraphDataPaddingX: 0, | |
1367 inGraphDataPaddingY: -3, | |
1368 inGraphDataTmpl: "<%=v3%>", | |
1369 inGraphDataAlign: "center", | |
1370 inGraphDataVAlign: "top", | |
1371 inGraphDataRotate: 0, | |
1372 inGraphDataFontFamily: "'Arial'", | |
1373 inGraphDataFontSize: 12, | |
1374 inGraphDataFontStyle: "normal", | |
1375 inGraphDataFontColor: "#666", | |
1376 inGraphDataXPosition: 2, | |
1377 inGraphDataYPosition: 3, | |
1378 scaleOverlay: false, | |
1379 scaleOverride: false, | |
1380 scaleOverride2: false, | |
1381 scaleSteps: null, | |
1382 scaleStepWidth: null, | |
1383 scaleStartValue: null, | |
1384 scaleLineColor: "rgba(0,0,0,.1)", | |
1385 scaleLineWidth: 1, | |
1386 scaleShowLabels: true, | |
1387 scaleShowLabels2: true, | |
1388 scaleLabel: "<%=value%>", | |
1389 scaleFontFamily: "'Arial'", | |
1390 scaleFontSize: 12, | |
1391 scaleFontStyle: "normal", | |
1392 scaleFontColor: "#666", | |
1393 scaleShowGridLines: true, | |
1394 scaleXGridLinesStep: 1, | |
1395 scaleYGridLinesStep: 1, | |
1396 scaleGridLineColor: "rgba(0,0,0,.05)", | |
1397 scaleGridLineWidth: 1, | |
1398 showYAxisMin: true, // Show the minimum value on Y axis
(in original version, this minimum is not displayed - it can overlap the X label
s) | |
1399 rotateLabels: "smart", // smart <=> 0 degre if space eno
ugh; otherwise 45 degres if space enough otherwise90 degre; | |
1400 // you can force an integer value between 0 and 180 degr
es | |
1401 scaleTickSizeLeft: 5, | |
1402 scaleTickSizeRight: 5, | |
1403 scaleTickSizeBottom: 5, | |
1404 scaleTickSizeTop: 5, | |
1405 barShowStroke: true, | |
1406 barStrokeWidth: 2, | |
1407 barValueSpacing: 5, | |
1408 barDatasetSpacing: 1, | |
1409 animation: true, | |
1410 animationSteps: 60, | |
1411 animationEasing: "easeOutQuart", | |
1412 onAnimationComplete: null, | |
1413 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3 + '
(' + v6 + ' %)'%>" | |
1414 }; | |
1415 // merge annotate defaults | |
1416 chart.StackedBar.defaults = mergeChartConfig(chart.defaults.comm
onOptions, chart.StackedBar.defaults); | |
1417 chart.StackedBar.defaults = mergeChartConfig(chart.defaults.xyAx
isCommonOptions, chart.StackedBar.defaults); | |
1418 chart.StackedBar.defaults = mergeChartConfig(chart.StackedBar.de
faults, charJSPersonalDefaultOptions); | |
1419 chart.StackedBar.defaults = mergeChartConfig(chart.StackedBar.de
faults, charJSPersonalDefaultOptionsStackedBar); | |
1420 var config = (options) ? mergeChartConfig(chart.StackedBar.defau
lts, options) : chart.StackedBar.defaults; | |
1421 return new StackedBar(data, config, context); | |
1422 }; | |
1423 this.HorizontalStackedBar = function(data, options) { | |
1424 chart.HorizontalStackedBar.defaults = { | |
1425 inGraphDataShow: false, | |
1426 inGraphDataPaddingX: -3, | |
1427 inGraphDataPaddingY: 0, | |
1428 inGraphDataTmpl: "<%=v3%>", | |
1429 inGraphDataAlign: "right", | |
1430 inGraphDataVAlign: "middle", | |
1431 inGraphDataRotate: 0, | |
1432 inGraphDataFontFamily: "'Arial'", | |
1433 inGraphDataFontSize: 12, | |
1434 inGraphDataFontStyle: "normal", | |
1435 inGraphDataFontColor: "#666", | |
1436 inGraphDataXPosition: 3, | |
1437 inGraphDataYPosition: 2, | |
1438 scaleOverlay: false, | |
1439 scaleOverride: false, | |
1440 scaleOverride2: false, | |
1441 scaleSteps: null, | |
1442 scaleStepWidth: null, | |
1443 scaleStartValue: null, | |
1444 scaleLineColor: "rgba(0,0,0,.1)", | |
1445 scaleLineWidth: 1, | |
1446 scaleShowLabels: true, | |
1447 scaleShowLabels2: true, | |
1448 scaleLabel: "<%=value%>", | |
1449 scaleFontFamily: "'Arial'", | |
1450 scaleFontSize: 12, | |
1451 scaleFontStyle: "normal", | |
1452 scaleFontColor: "#666", | |
1453 scaleShowGridLines: true, | |
1454 scaleXGridLinesStep: 1, | |
1455 scaleYGridLinesStep: 1, | |
1456 scaleGridLineColor: "rgba(0,0,0,.05)", | |
1457 scaleGridLineWidth: 1, | |
1458 scaleTickSizeLeft: 5, | |
1459 scaleTickSizeRight: 5, | |
1460 scaleTickSizeBottom: 5, | |
1461 scaleTickSizeTop: 5, | |
1462 showYAxisMin: true, // Show the minimum value on Y axis
(in original version, this minimum is not displayed - it can overlap the X label
s) | |
1463 rotateLabels: "smart", // smart <=> 0 degre if space eno
ugh; otherwise 45 degres if space enough otherwise90 degre; | |
1464 barShowStroke: true, | |
1465 barStrokeWidth: 2, | |
1466 barValueSpacing: 5, | |
1467 barDatasetSpacing: 1, | |
1468 animation: true, | |
1469 animationSteps: 60, | |
1470 animationEasing: "easeOutQuart", | |
1471 onAnimationComplete: null, | |
1472 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3 + '
(' + v6 + ' %)'%>", | |
1473 reverseOrder: false | |
1474 }; | |
1475 // merge annotate defaults | |
1476 chart.HorizontalStackedBar.defaults = mergeChartConfig(chart.def
aults.commonOptions, chart.HorizontalStackedBar.defaults); | |
1477 chart.HorizontalStackedBar.defaults = mergeChartConfig(chart.def
aults.xyAxisCommonOptions, chart.HorizontalStackedBar.defaults); | |
1478 chart.HorizontalStackedBar.defaults = mergeChartConfig(chart.Hor
izontalStackedBar.defaults, charJSPersonalDefaultOptions); | |
1479 chart.HorizontalStackedBar.defaults = mergeChartConfig(chart.Hor
izontalStackedBar.defaults, charJSPersonalDefaultOptionsHorizontalStackedBar); | |
1480 var config = (options) ? mergeChartConfig(chart.HorizontalStacke
dBar.defaults, options) : chart.HorizontalStackedBar.defaults; | |
1481 return new HorizontalStackedBar(data, config, context); | |
1482 }; | |
1483 this.Bar = function(data, options) { | |
1484 chart.Bar.defaults = { | |
1485 inGraphDataShow: false, | |
1486 inGraphDataPaddingX: 0, | |
1487 inGraphDataPaddingY: 3, | |
1488 inGraphDataTmpl: "<%=v3%>", | |
1489 inGraphDataAlign: "center", | |
1490 inGraphDataVAlign: "bottom", | |
1491 inGraphDataRotate: 0, | |
1492 inGraphDataFontFamily: "'Arial'", | |
1493 inGraphDataFontSize: 12, | |
1494 inGraphDataFontStyle: "normal", | |
1495 inGraphDataFontColor: "#666", | |
1496 inGraphDataXPosition: 2, | |
1497 inGraphDataYPosition: 3, | |
1498 scaleOverlay: false, | |
1499 scaleOverride: false, | |
1500 scaleOverride2: false, | |
1501 scaleSteps: null, | |
1502 scaleStepWidth: null, | |
1503 scaleStartValue: null, | |
1504 scaleLineColor: "rgba(0,0,0,.1)", | |
1505 scaleLineWidth: 1, | |
1506 scaleShowLabels: true, | |
1507 scaleShowLabels2: true, | |
1508 scaleLabel: "<%=value%>", | |
1509 scaleFontFamily: "'Arial'", | |
1510 scaleFontSize: 12, | |
1511 scaleFontStyle: "normal", | |
1512 scaleFontColor: "#666", | |
1513 scaleShowGridLines: true, | |
1514 scaleXGridLinesStep: 1, | |
1515 scaleYGridLinesStep: 1, | |
1516 scaleGridLineColor: "rgba(0,0,0,.05)", | |
1517 scaleGridLineWidth: 1, | |
1518 showYAxisMin: true, // Show the minimum value on Y axis
(in original version, this minimum is not displayed - it can overlap the X label
s) | |
1519 rotateLabels: "smart", // smart <=> 0 degre if space eno
ugh; otherwise 45 degres if space enough otherwise90 degre; | |
1520 // you can force an integer value between 0 and 180 degr
es | |
1521 logarithmic: false, // can be 'fuzzy',true and false ('f
uzzy' => if the gap between min and maximum is big it's using a logarithmic y-Ax
is scale | |
1522 logarithmic2: false, // can be 'fuzzy',true and false ('
fuzzy' => if the gap between min and maximum is big it's using a logarithmic y-A
xis scale | |
1523 scaleTickSizeLeft: 5, | |
1524 scaleTickSizeRight: 5, | |
1525 scaleTickSizeBottom: 5, | |
1526 scaleTickSizeTop: 5, | |
1527 barShowStroke: true, | |
1528 barStrokeWidth: 2, | |
1529 barValueSpacing: 5, | |
1530 barDatasetSpacing: 1, | |
1531 barBorderRadius: 0, | |
1532 animation: true, | |
1533 animationSteps: 60, | |
1534 animationEasing: "easeOutQuart", | |
1535 onAnimationComplete: null, | |
1536 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3 + '
(' + v6 + ' %)'%>" | |
1537 }; | |
1538 // merge annotate defaults | |
1539 chart.Bar.defaults = mergeChartConfig(chart.defaults.commonOptio
ns, chart.Bar.defaults); | |
1540 chart.Bar.defaults = mergeChartConfig(chart.defaults.xyAxisCommo
nOptions, chart.Bar.defaults); | |
1541 chart.Bar.defaults = mergeChartConfig(chart.Bar.defaults, charJS
PersonalDefaultOptions); | |
1542 chart.Bar.defaults = mergeChartConfig(chart.Bar.defaults, charJS
PersonalDefaultOptionsBar); | |
1543 var config = (options) ? mergeChartConfig(chart.Bar.defaults, op
tions) : chart.Bar.defaults; | |
1544 return new Bar(data, config, context); | |
1545 }; | |
1546 this.HorizontalBar = function(data, options) { | |
1547 chart.HorizontalBar.defaults = { | |
1548 inGraphDataShow: false, | |
1549 inGraphDataPaddingX: 3, | |
1550 inGraphDataPaddingY: 0, | |
1551 inGraphDataTmpl: "<%=v3%>", | |
1552 inGraphDataAlign: "left", | |
1553 inGraphDataVAlign: "middle", | |
1554 inGraphDataRotate: 0, | |
1555 inGraphDataFontFamily: "'Arial'", | |
1556 inGraphDataFontSize: 12, | |
1557 inGraphDataFontStyle: "normal", | |
1558 inGraphDataFontColor: "#666", | |
1559 inGraphDataXPosition: 3, | |
1560 inGraphDataYPosition: 2, | |
1561 scaleOverlay: false, | |
1562 scaleOverride: false, | |
1563 scaleOverride2: false, | |
1564 scaleSteps: null, | |
1565 scaleStepWidth: null, | |
1566 scaleStartValue: null, | |
1567 scaleLineColor: "rgba(0,0,0,.1)", | |
1568 scaleLineWidth: 1, | |
1569 scaleShowLabels: true, | |
1570 scaleShowLabels2: true, | |
1571 scaleLabel: "<%=value%>", | |
1572 scaleFontFamily: "'Arial'", | |
1573 scaleFontSize: 12, | |
1574 scaleFontStyle: "normal", | |
1575 scaleFontColor: "#666", | |
1576 scaleShowGridLines: true, | |
1577 scaleXGridLinesStep: 1, | |
1578 scaleYGridLinesStep: 1, | |
1579 scaleGridLineColor: "rgba(0,0,0,.05)", | |
1580 scaleGridLineWidth: 1, | |
1581 scaleTickSizeLeft: 5, | |
1582 scaleTickSizeRight: 5, | |
1583 scaleTickSizeBottom: 5, | |
1584 scaleTickSizeTop: 5, | |
1585 showYAxisMin: true, // Show the minimum value on Y axis
(in original version, this minimum is not displayed - it can overlap the X label
s) | |
1586 rotateLabels: "smart", // smart <=> 0 degre if space eno
ugh; otherwise 45 degres if space enough otherwise90 degre; | |
1587 barShowStroke: true, | |
1588 barStrokeWidth: 2, | |
1589 barValueSpacing: 5, | |
1590 barDatasetSpacing: 1, | |
1591 barBorderRadius: 0, | |
1592 animation: true, | |
1593 animationSteps: 60, | |
1594 animationEasing: "easeOutQuart", | |
1595 onAnimationComplete: null, | |
1596 annotateLabel: "<%=(v1 == '' ? '' : v1) + (v1!='' && v2
!='' ? ' - ' : '')+(v2 == '' ? '' : v2)+(v1!='' || v2 !='' ? ':' : '') + v3 + '
(' + v6 + ' %)'%>", | |
1597 reverseOrder: false | |
1598 }; | |
1599 // merge annotate defaults | |
1600 chart.HorizontalBar.defaults = mergeChartConfig(chart.defaults.c
ommonOptions, chart.HorizontalBar.defaults); | |
1601 chart.HorizontalBar.defaults = mergeChartConfig(chart.defaults.x
yAxisCommonOptions, chart.HorizontalBar.defaults); | |
1602 chart.HorizontalBar.defaults = mergeChartConfig(chart.Horizontal
Bar.defaults, charJSPersonalDefaultOptions); | |
1603 chart.HorizontalBar.defaults = mergeChartConfig(chart.Horizontal
Bar.defaults, charJSPersonalDefaultOptionsHorizontalBar); | |
1604 var config = (options) ? mergeChartConfig(chart.HorizontalBar.de
faults, options) : chart.HorizontalBar.defaults; | |
1605 return new HorizontalBar(data, config, context); | |
1606 }; | |
1607 chart.defaults = {}; | |
1608 chart.defaults.commonOptions = { | |
1609 multiGraph: false, | |
1610 clearRect: true, // do not change clearRect options; for interna
l use only | |
1611 dynamicDisplay: false, | |
1612 graphSpaceBefore: 5, | |
1613 graphSpaceAfter: 5, | |
1614 canvasBorders: false, | |
1615 canvasBackgroundColor: "none", | |
1616 canvasBordersWidth: 3, | |
1617 canvasBordersColor: "black", | |
1618 graphTitle: "", | |
1619 graphTitleFontFamily: "'Arial'", | |
1620 graphTitleFontSize: 24, | |
1621 graphTitleFontStyle: "bold", | |
1622 graphTitleFontColor: "#666", | |
1623 graphTitleSpaceBefore: 5, | |
1624 graphTitleSpaceAfter: 5, | |
1625 graphSubTitle: "", | |
1626 graphSubTitleFontFamily: "'Arial'", | |
1627 graphSubTitleFontSize: 18, | |
1628 graphSubTitleFontStyle: "normal", | |
1629 graphSubTitleFontColor: "#666", | |
1630 graphSubTitleSpaceBefore: 5, | |
1631 graphSubTitleSpaceAfter: 5, | |
1632 footNote: "", | |
1633 footNoteFontFamily: "'Arial'", | |
1634 footNoteFontSize: 8, | |
1635 footNoteFontStyle: "bold", | |
1636 footNoteFontColor: "#666", | |
1637 footNoteSpaceBefore: 5, | |
1638 footNoteSpaceAfter: 5, | |
1639 legend : false, | |
1640 showSingleLegend: false, | |
1641 maxLegendCols : 999, | |
1642 legendPosY :4, | |
1643 legendPosX : -2, | |
1644 legendFontFamily: "'Arial'", | |
1645 legendFontSize: 12, | |
1646 legendFontStyle: "normal", | |
1647 legendFontColor: "#666", | |
1648 legendBlockSize: 15, | |
1649 legendBorders: true, | |
1650 legendBordersWidth: 1, | |
1651 legendBordersColors: "#666", | |
1652 legendBordersSpaceBefore: 5, | |
1653 legendBordersSpaceAfter: 5, | |
1654 legendBordersSpaceLeft: 5, | |
1655 legendBordersSpaceRight: 5, | |
1656 legendSpaceBeforeText: 5, | |
1657 legendSpaceAfterText: 5, | |
1658 legendSpaceLeftText: 5, | |
1659 legendSpaceRightText: 5, | |
1660 legendSpaceBetweenTextVertical: 5, | |
1661 legendSpaceBetweenTextHorizontal: 5, | |
1662 legendSpaceBetweenBoxAndText: 5, | |
1663 legendFillColor : "rgba(0,0,0,0)", | |
1664 legendXPadding : 0, | |
1665 legendYPadding : 0, | |
1666 annotateDisplay: false, | |
1667 savePng: false, | |
1668 savePngOutput: "NewWindow", // Allowed values : "NewWindow", "Cu
rrentWindow", "Save" | |
1669 savePngFunction: "mousedown right", | |
1670 savePngBackgroundColor: 'WHITE', | |
1671 annotateFunction: "mousemove", | |
1672 annotateFontFamily: "'Arial'", | |
1673 annotateBorder: 'none', | |
1674 annotateBorderRadius: '2px', | |
1675 annotateBackgroundColor: 'rgba(0,0,0,0.8)', | |
1676 annotateFontSize: 12, | |
1677 annotateFontColor: 'white', | |
1678 annotateFontStyle: "normal", | |
1679 annotatePadding: "3px", | |
1680 annotateClassName: "", | |
1681 crossText: [""], | |
1682 crossTextIter: ["all"], | |
1683 crossTextOverlay: [true], | |
1684 crossTextFontFamily: ["'Arial'"], | |
1685 crossTextFontSize: [12], | |
1686 crossTextFontStyle: ["normal"], | |
1687 crossTextFontColor: ["rgba(220,220,220,1)"], | |
1688 crossTextRelativePosX: [2], | |
1689 crossTextRelativePosY: [2], | |
1690 crossTextBaseline: ["middle"], | |
1691 crossTextAlign: ["center"], | |
1692 crossTextPosX: [0], | |
1693 crossTextPosY: [0], | |
1694 crossTextAngle: [0], | |
1695 crossTextFunction: null, | |
1696 crossImage: [undefined], | |
1697 crossImageIter: ["all"], | |
1698 crossImageOverlay: [true], | |
1699 crossImageRelativePosX: [2], | |
1700 crossImageRelativePosY: [2], | |
1701 crossImageBaseline: ["middle"], | |
1702 crossImageAlign: ["center"], | |
1703 crossImagePosX: [0], | |
1704 crossImagePosY: [0], | |
1705 crossImageAngle: [0], | |
1706 spaceTop: 0, | |
1707 spaceBottom: 0, | |
1708 spaceRight: 0, | |
1709 spaceLeft: 0, | |
1710 decimalSeparator: ".", | |
1711 thousandSeparator: "", | |
1712 roundNumber: "none", | |
1713 roundPct: -1, | |
1714 fmtV1: "none", | |
1715 fmtV2: "none", | |
1716 fmtV3: "none", | |
1717 fmtV4: "none", | |
1718 fmtV5: "none", | |
1719 fmtV6: "none", | |
1720 fmtV7: "none", | |
1721 fmtV8: "none", | |
1722 fmtV9: "none", | |
1723 fmtV10: "none", | |
1724 fmtV11: "none", | |
1725 fmtV12: "none", | |
1726 fmtV13: "none", | |
1727 fmtXLabel: "none", | |
1728 fmtYLabel: "none", | |
1729 fmtYLabel2: "none", | |
1730 fmtLegend: "none", | |
1731 animationStartValue: 0, | |
1732 animationStopValue: 1, | |
1733 animationCount: 1, | |
1734 animationPauseTime: 5, | |
1735 animationBackward: false, | |
1736 animationStartWithDataset: 1, | |
1737 animationStartWithData: 1, | |
1738 animationLeftToRight: false, | |
1739 animationByDataset: false, | |
1740 defaultStrokeColor: "rgba(220,220,220,1)", | |
1741 defaultFillColor: "rgba(220,220,220,0.5)", | |
1742 mouseDownRight: null, | |
1743 mouseDownLeft: null, | |
1744 mouseDownMiddle: null, | |
1745 mouseMove: null, | |
1746 mouseOut: null, | |
1747 mouseWheel : null, | |
1748 savePngName: "canvas", | |
1749 responsive : false, | |
1750 maintainAspectRatio: true | |
1751 }; | |
1752 chart.defaults.xyAxisCommonOptions = { | |
1753 yAxisMinimumInterval: "none", | |
1754 yAxisMinimumInterval2: "none", | |
1755 yScaleLabelsMinimumWidth: 0, | |
1756 xScaleLabelsMinimumWidth: 0, | |
1757 yAxisLeft: true, | |
1758 yAxisRight: false, | |
1759 xAxisBottom: true, | |
1760 xAxisTop: false, | |
1761 xAxisSpaceBetweenLabels: 5, | |
1762 fullWidthGraph: false, | |
1763 yAxisLabel: "", | |
1764 yAxisLabel2: "", | |
1765 yAxisFontFamily: "'Arial'", | |
1766 yAxisFontSize: 16, | |
1767 yAxisFontStyle: "normal", | |
1768 yAxisFontColor: "#666", | |
1769 yAxisLabelSpaceRight: 5, | |
1770 yAxisLabelSpaceLeft: 5, | |
1771 yAxisSpaceRight: 5, | |
1772 yAxisSpaceLeft: 5, | |
1773 xAxisLabel: "", | |
1774 xAxisFontFamily: "'Arial'", | |
1775 xAxisFontSize: 16, | |
1776 xAxisFontStyle: "normal", | |
1777 xAxisFontColor: "#666", | |
1778 xAxisLabelSpaceBefore: 5, | |
1779 xAxisLabelSpaceAfter: 5, | |
1780 xAxisSpaceBefore: 5, | |
1781 xAxisSpaceAfter: 5, | |
1782 yAxisUnit: "", | |
1783 yAxisUnit2: "", | |
1784 yAxisUnitFontFamily: "'Arial'", | |
1785 yAxisUnitFontSize: 8, | |
1786 yAxisUnitFontStyle: "normal", | |
1787 yAxisUnitFontColor: "#666", | |
1788 yAxisUnitSpaceBefore: 5, | |
1789 yAxisUnitSpaceAfter: 5 | |
1790 }; | |
1791 var clear = function(c) { | |
1792 c.clearRect(0, 0, width, height); | |
1793 }; | |
1794 | |
1795 function setting_new_chart_vars(ctx) { | |
1796 | |
1797 if (typeof ctx.ChartNewId === typeof undefined) { | |
1798 ctx.runanimationcompletefunction=true; | |
1799 var cvdate = new Date(); | |
1800 var cvmillsec = cvdate.getTime(); | |
1801 ctx.ChartNewId = ctx.tpchart + '_' + cvmillsec; | |
1802 ctx._eventListeners = {}; | |
1803 } | |
1804 } | |
1805 | |
1806 var PolarArea = function(data, config, ctx) { | |
1807 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, msr, midPosX, midPosY; | |
1808 | |
1809 ctx.tpchart="PolarArea"; | |
1810 setting_new_chart_vars(ctx); | |
1811 if (!dynamicFunction(data, config, ctx)) { | |
1812 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
1813 return; | |
1814 } | |
1815 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
1816 if(!config.multiGraph) { | |
1817 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
1818 subUpdateChart(ctx,data,config); | |
1819 return; | |
1820 } else { ctx.firstPass=1; } | |
1821 } | |
1822 | |
1823 var realStartAngle = config.startAngle * (Math.PI / 180) + 2 * M
ath.PI; | |
1824 while (config.startAngle < 0) { | |
1825 config.startAngle += 360; | |
1826 } | |
1827 while (config.startAngle > 360) { | |
1828 config.startAngle -= 360; | |
1829 } | |
1830 while (realStartAngle < 0) { | |
1831 realStartAngle += 2 * Math.PI; | |
1832 } | |
1833 while (realStartAngle > 2 * Math.PI) { | |
1834 realStartAngle -= 2 * Math.PI; | |
1835 } | |
1836 config.logarithmic = false; | |
1837 config.logarithmic2 = false; | |
1838 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
1839 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
1840 defMouse(ctx, data, config); | |
1841 setRect(ctx, config); | |
1842 valueBounds = getValueBounds(); | |
1843 //Check and set the scale | |
1844 labelTemplateString = (config.scaleShowLabels) ? config.scaleLab
el : ""; | |
1845 if (!config.scaleOverride) { | |
1846 calculatedScale = calculateScale(1, config, valueBounds.
maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minValue, labe
lTemplateString); | |
1847 msr = setMeasures(data, config, ctx, height, width, calc
ulatedScale.labels, null, true, false, false, false, true, "PolarArea"); | |
1848 } else { | |
1849 calculatedScale = { | |
1850 steps: config.scaleSteps, | |
1851 stepValue: config.scaleStepWidth, | |
1852 graphMin: config.scaleStartValue, | |
1853 graphMax: config.scaleStartValue + config.scaleS
teps * config.scaleStepWidth, | |
1854 labels: [] | |
1855 } | |
1856 populateLabels(1, config, labelTemplateString, calculate
dScale.labels, calculatedScale.steps, config.scaleStartValue, calculatedScale.gr
aphMax, config.scaleStepWidth); | |
1857 msr = setMeasures(data, config, ctx, height, width, calc
ulatedScale.labels, null, true, false, false, false, true, "PolarArea"); | |
1858 } | |
1859 midPosX = msr.leftNotUsableSize + (msr.availableWidth / 2); | |
1860 midPosY = msr.topNotUsableSize + (msr.availableHeight / 2); | |
1861 scaleHop = Math.floor(((Min([msr.availableHeight, msr.availableW
idth]) / 2) - 5) / calculatedScale.steps); | |
1862 //Wrap in an animation loop wrapper | |
1863 if(scaleHop > 0) { | |
1864 animationLoop(config, drawScale, drawAllSegments, ctx, m
sr.clrx, msr.clry, msr.clrwidth, msr.clrheight, midPosX, midPosY, midPosX - ((Mi
n([msr.availableHeight, msr.availableWidth]) / 2) - 5), midPosY + ((Min([msr.ava
ilableHeight, msr.availableWidth]) / 2) - 5), data); | |
1865 } else { | |
1866 testRedraw(ctx,data,config); | |
1867 } | |
1868 | |
1869 function drawAllSegments(animationDecimal) { | |
1870 var startAngle = -config.startAngle * (Math.PI / 180) +
2 * Math.PI, | |
1871 cumvalue = 0, | |
1872 angleStep = 0, | |
1873 scaleAnimation = 1, | |
1874 rotateAnimation = 1; | |
1875 angleStep = 0; | |
1876 for (var i = 0; i < data.length; i++) | |
1877 if (!(typeof(data[i].value) == 'undefined')) ang
leStep++; | |
1878 angleStep = (Math.PI * 2) / angleStep; | |
1879 while (startAngle < 0) { | |
1880 startAngle += 2 * Math.PI; | |
1881 } | |
1882 while (startAngle > 2 * Math.PI) { | |
1883 startAngle -= 2 * Math.PI; | |
1884 } | |
1885 if (config.animation) { | |
1886 if (config.animateScale) { | |
1887 scaleAnimation = animationDecimal; | |
1888 } | |
1889 if (config.animateRotate) { | |
1890 rotateAnimation = animationDecimal; | |
1891 } | |
1892 } | |
1893 if (animationDecimal >= 1) { | |
1894 totvalue = 0; | |
1895 for (var i = 0; i < data.length; i++) | |
1896 if (!(typeof(data[i].value) == 'undefine
d')) totvalue += 1 * data[i].value; | |
1897 } | |
1898 for (var i = 0; i < data.length; i++) { | |
1899 correctedRotateAnimation = animationCorrection(r
otateAnimation, data, config, i, -1, 0).mainVal; | |
1900 if (!(typeof(data[i].value) == 'undefined')) { | |
1901 ctx.beginPath(); | |
1902 ctx.arc(midPosX, midPosY, scaleAnimation
* calculateOffset(config.logarithmic, 1 * data[i].value, calculatedScale, scale
Hop), startAngle, startAngle + correctedRotateAnimation * angleStep, false); | |
1903 ctx.lineTo(midPosX, midPosY); | |
1904 ctx.closePath(); | |
1905 if (typeof data[i].color == "function")
ctx.fillStyle = data[i].color("COLOR", data, config, i, -1, animationDecimal, da
ta[i].value, "PolarArea", ctx, midPosX, midPosY, 0, scaleAnimation * calculateOf
fset(config.logarithmic, 1 * data[i].value, calculatedScale, scaleHop)); | |
1906 else ctx.fillStyle = data[i].color; | |
1907 ctx.fill(); | |
1908 startAngle += angleStep; | |
1909 if (config.segmentShowStroke) { | |
1910 ctx.strokeStyle = config.segment
StrokeColor; | |
1911 ctx.lineWidth = config.segmentSt
rokeWidth; | |
1912 ctx.stroke(); | |
1913 } | |
1914 } | |
1915 } | |
1916 if (animationDecimal >= 1) { | |
1917 startAngle -= 2*Math.PI; | |
1918 for (var i = 0; i < data.length; i++) { | |
1919 if (!(typeof(data[i].value) == 'undefine
d')) { | |
1920 cumvalue += 1 * data[i].value; | |
1921 startAngle += angleStep; | |
1922 if (typeof(data[i].title) == "st
ring") lgtxt = data[i].title.trim(); | |
1923 else lgtxt = ""; | |
1924 jsGraphAnnotate[ctx.ChartNewId][
jsGraphAnnotate[ctx.ChartNewId].length] = ["ARC", midPosX, midPosY, 0, calculate
Offset(config.logarithmic, 1 * data[i].value, calculatedScale, scaleHop), startA
ngle - angleStep, startAngle, lgtxt, 1 * data[i].value, cumvalue, totvalue, angl
eStep, i]; | |
1925 if (config.inGraphDataShow) { | |
1926 if (config.inGraphDataAn
glePosition == 1) posAngle = realStartAngle + config.inGraphDataPaddingAngle * (
Math.PI / 180); | |
1927 else if (config.inGraphD
ataAnglePosition == 2) posAngle = realStartAngle - angleStep / 2 + config.inGrap
hDataPaddingAngle * (Math.PI / 180); | |
1928 else if (config.inGraphD
ataAnglePosition == 3) posAngle = realStartAngle - angleStep + config.inGraphDat
aPaddingAngle * (Math.PI / 180); | |
1929 if (config.inGraphDataRa
diusPosition == 1) labelRadius = 0 + config.inGraphDataPaddingRadius; | |
1930 else if (config.inGraphD
ataRadiusPosition == 2) labelRadius = calculateOffset(config.logarithmic, 1 * da
ta[i].value, calculatedScale, scaleHop) / 2 + config.inGraphDataPaddingRadius; | |
1931 else if (config.inGraphD
ataRadiusPosition == 3) labelRadius = calculateOffset(config.logarithmic, 1 * da
ta[i].value, calculatedScale, scaleHop) + config.inGraphDataPaddingRadius; | |
1932 else if (config.inGraphD
ataRadiusPosition == 4) labelRadius = scaleHop * calculatedScale.steps + config.
inGraphDataPaddingRadius; | |
1933 ctx.save() | |
1934 if (config.inGraphDataAl
ign == "off-center") { | |
1935 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "left"; | |
1936 else ctx.textAli
gn = "right"; | |
1937 } else if (config.inGrap
hDataAlign == "to-center") { | |
1938 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "right"; | |
1939 else ctx.textAli
gn = "left"; | |
1940 } else ctx.textAlign = c
onfig.inGraphDataAlign; | |
1941 if (config.inGraphDataVA
lign == "off-center") { | |
1942 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "top"; | |
1943 else ctx.textBas
eline = "bottom"; | |
1944 } else if (config.inGrap
hDataVAlign == "to-center") { | |
1945 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "bottom"; | |
1946 else ctx.textBas
eline = "top"; | |
1947 } else ctx.textBaseline
= config.inGraphDataVAlign; | |
1948 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
1949 ctx.fillStyle = config.i
nGraphDataFontColor; | |
1950 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
1951 config: config, | |
1952 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
1953 v2: fmtChartJS(c
onfig, 1 * data[i].value, config.fmtV2), | |
1954 v3: fmtChartJS(c
onfig, cumvalue, config.fmtV3), | |
1955 v4: fmtChartJS(c
onfig, totvalue, config.fmtV4), | |
1956 v5: fmtChartJS(c
onfig, angleStep, config.fmtV5), | |
1957 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data[i].value / totvalue, config.fmtV6
), config.roundPct), | |
1958 v7: fmtChartJS(c
onfig, midPosX, config.fmtV7), | |
1959 v8: fmtChartJS(c
onfig, midPosY, config.fmtV8), | |
1960 v9: fmtChartJS(c
onfig, 0, config.fmtV9), | |
1961 v10: fmtChartJS(
config, calculateOffset(config.logarithmic, 1 * data[i].value, calculatedScale,
scaleHop), config.fmtV10), | |
1962 v11: fmtChartJS(
config, startAngle - angleStep, config.fmtV11), | |
1963 v12: fmtChartJS(
config, angleStep, config.fmtV12), | |
1964 v13: fmtChartJS(
config, i, config.fmtV13), | |
1965 data: data | |
1966 }); | |
1967 ctx.translate(midPosX +
labelRadius * Math.cos(posAngle), midPosY - labelRadius * Math.sin(posAngle)); | |
1968 if (config.inGraphDataRo
tate == "inRadiusAxis") ctx.rotate(2 * Math.PI - posAngle); | |
1969 else if (config.inGraphD
ataRotate == "inRadiusAxisRotateLabels") { | |
1970 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI / 2 && (posAngle + 2 * Math.PI) % (2 * Ma
th.PI) < 3 * Math.PI / 2) ctx.rotate(3 * Math.PI - posAngle); | |
1971 else ctx.rotate(
2 * Math.PI - posAngle); | |
1972 } else ctx.rotate(config
.inGraphDataRotate * (Math.PI / 180)); | |
1973 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
1974 ctx.restore(); | |
1975 } | |
1976 realStartAngle -= angleStep; | |
1977 } | |
1978 } | |
1979 } | |
1980 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"PolarArea"); | |
1981 }; | |
1982 | |
1983 function drawScale() { | |
1984 for (var i = 0; i < calculatedScale.steps; i++) { | |
1985 //If the line object is there | |
1986 if (config.scaleShowLine) { | |
1987 ctx.beginPath(); | |
1988 ctx.arc(midPosX, midPosY, scaleHop * (i
+ 1), 0, (Math.PI * 2), true); | |
1989 ctx.strokeStyle = config.scaleLineColor; | |
1990 ctx.lineWidth = config.scaleLineWidth; | |
1991 ctx.stroke(); | |
1992 } | |
1993 if (config.scaleShowLabels) { | |
1994 ctx.textAlign = "center"; | |
1995 ctx.font = config.scaleFontStyle + " " +
config.scaleFontSize + "px " + config.scaleFontFamily; | |
1996 var label = calculatedScale.labels[i + 1
]; | |
1997 //If the backdrop object is within the f
ont object | |
1998 if (config.scaleShowLabelBackdrop) { | |
1999 var textWidth = ctx.measureTextM
ultiLine(label, config.scaleFontSize).textWidth; | |
2000 ctx.fillStyle = config.scaleBack
dropColor; | |
2001 ctx.beginPath(); | |
2002 ctx.rect( | |
2003 Math.round(midPosX - tex
tWidth / 2 - config.scaleBackdropPaddingX), //X | |
2004 Math.round(midPosY - (sc
aleHop * (i + 1)) - config.scaleFontSize * 0.5 - config.scaleBackdropPaddingY),
//Y | |
2005 Math.round(textWidth + (
config.scaleBackdropPaddingX * 2)), //Width | |
2006 Math.round(config.scaleF
ontSize + (config.scaleBackdropPaddingY * 2)) //Height | |
2007 ); | |
2008 ctx.fill(); | |
2009 } | |
2010 ctx.textBaseline = "middle"; | |
2011 ctx.fillStyle = config.scaleFontColor; | |
2012 ctx.fillTextMultiLine(label, midPosX, mi
dPosY - (scaleHop * (i + 1)), ctx.textBaseline, config.scaleFontSize); | |
2013 } | |
2014 } | |
2015 }; | |
2016 | |
2017 function getValueBounds() { | |
2018 var upperValue = Number.MIN_VALUE; | |
2019 var lowerValue = Number.MAX_VALUE; | |
2020 for (var i = 0; i < data.length; i++) { | |
2021 if (1 * data[i].value > upperValue) { | |
2022 upperValue = 1 * data[i].value; | |
2023 } | |
2024 if (1 * data[i].value < lowerValue) { | |
2025 lowerValue = 1 * data[i].value; | |
2026 } | |
2027 }; | |
2028 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
2029 upperValue = Max([upperValue * 2, 1]); | |
2030 lowerValue = 0; | |
2031 } | |
2032 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
2033 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
2034 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
2035 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
2036 return { | |
2037 maxValue: upperValue, | |
2038 minValue: lowerValue, | |
2039 maxSteps: maxSteps, | |
2040 minSteps: minSteps | |
2041 }; | |
2042 }; | |
2043 }; | |
2044 var Radar = function(data, config, ctx) { | |
2045 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, msr, midPosX, midPosY; | |
2046 | |
2047 ctx.tpchart="Radar"; | |
2048 setting_new_chart_vars(ctx); | |
2049 if (!dynamicFunction(data, config, ctx)) { | |
2050 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
2051 return; | |
2052 } | |
2053 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
2054 if(!config.multiGraph) { | |
2055 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
2056 subUpdateChart(ctx,data,config); | |
2057 return; | |
2058 } else { ctx.firstPass=1; } | |
2059 } | |
2060 | |
2061 while (config.startAngle < 0) { | |
2062 config.startAngle += 360; | |
2063 } | |
2064 while (config.startAngle > 360) { | |
2065 config.startAngle -= 360; | |
2066 } | |
2067 config.logarithmic = false; | |
2068 config.logarithmic2 = false; | |
2069 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
2070 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
2071 defMouse(ctx, data, config); | |
2072 //If no labels are defined set to an empty array, so referencing
length for looping doesn't blow up. | |
2073 if (!data.labels) data.labels = []; | |
2074 setRect(ctx, config); | |
2075 valueBounds = getValueBounds(); | |
2076 //Check and set the scale | |
2077 labelTemplateString = (config.scaleShowLabels) ? config.scaleLab
el : ""; | |
2078 if (!config.scaleOverride) { | |
2079 calculatedScale = calculateScale(1, config, valueBounds.
maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minValue, labe
lTemplateString); | |
2080 msr = setMeasures(data, config, ctx, height, width, calc
ulatedScale.labels, null, true, false, false, true, config.datasetFill, "Radar")
; | |
2081 } else { | |
2082 calculatedScale = { | |
2083 steps: config.scaleSteps, | |
2084 stepValue: config.scaleStepWidth, | |
2085 graphMin: config.scaleStartValue, | |
2086 graphMax: config.scaleStartValue + config.scaleS
teps * config.scaleStepWidth, | |
2087 labels: [] | |
2088 } | |
2089 populateLabels(1, config, labelTemplateString, calculate
dScale.labels, calculatedScale.steps, config.scaleStartValue, calculatedScale.gr
aphMax, config.scaleStepWidth); | |
2090 msr = setMeasures(data, config, ctx, height, width, calc
ulatedScale.labels, null, true, false, false, true, config.datasetFill, "Radar")
; | |
2091 } | |
2092 | |
2093 | |
2094 calculateDrawingSizes(); | |
2095 midPosY = msr.topNotUsableSize + (msr.availableHeight / 2); | |
2096 scaleHop = maxSize / (calculatedScale.steps); | |
2097 //Wrap in an animation loop wrapper | |
2098 animationLoop(config, drawScale, drawAllDataPoints, ctx, msr.clr
x, msr.clry, msr.clrwidth, msr.clrheight, midPosX, midPosY, midPosX - maxSize, m
idPosY + maxSize, data); | |
2099 //Radar specific functions. | |
2100 function drawAllDataPoints(animationDecimal) { | |
2101 var totvalue = new Array(); | |
2102 var maxvalue = new Array(); | |
2103 var lmaxvalue = new Array(); | |
2104 for (var i = 0; i < data.datasets.length; i++) { | |
2105 lmaxvalue[i] = -999999999; | |
2106 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
2107 totvalue[j] = 0; | |
2108 maxvalue[j] = -999999999; | |
2109 } | |
2110 } | |
2111 for (var i = 0; i < data.datasets.length; i++) { | |
2112 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
2113 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
2114 totvalue[j] += 1 * data.datasets
[i].data[j]; | |
2115 maxvalue[j] = Max([maxvalue[j],
1 * data.datasets[i].data[j]]); | |
2116 lmaxvalue[i] = Max([lmaxvalue[i]
, 1 * data.datasets[i].data[j]]); | |
2117 } | |
2118 } | |
2119 } | |
2120 var rotationDegree = (2 * Math.PI) / data.datasets[0].da
ta.length; | |
2121 ctx.save(); | |
2122 //We accept multiple data sets for radar charts, so show
loop through each set | |
2123 for (var i = 0; i < data.datasets.length; i++) { | |
2124 if (animationDecimal >= 1) { | |
2125 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
2126 else lgtxt = ""; | |
2127 } | |
2128 var fPt = -1; | |
2129 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
2130 var currentAnimPc = animationCorrection(
animationDecimal, data, config, i, j, 1).animVal; | |
2131 if (currentAnimPc > 1) currentAnimPc = c
urrentAnimPc - 1; | |
2132 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
2133 if (fPt == -1) { | |
2134 ctx.beginPath(); | |
2135 ctx.moveTo(midPosX + cur
rentAnimPc * (Math.cos(config.startAngle * Math.PI / 180 - j * rotationDegree) *
calculateOffset(config.logarithmic, data.datasets[i].data[j], calculatedScale,
scaleHop)), midPosY - currentAnimPc * (Math.sin(config.startAngle * Math.PI / 18
0 - j * rotationDegree) * calculateOffset(config.logarithmic, data.datasets[i].d
ata[j], calculatedScale, scaleHop))); | |
2136 fPt = j; | |
2137 } else { | |
2138 ctx.lineTo(midPosX + cur
rentAnimPc * (Math.cos(config.startAngle * Math.PI / 180 - j * rotationDegree) *
calculateOffset(config.logarithmic, data.datasets[i].data[j], calculatedScale,
scaleHop)), midPosY - currentAnimPc * (Math.sin(config.startAngle * Math.PI / 18
0 - j * rotationDegree) * calculateOffset(config.logarithmic, data.datasets[i].d
ata[j], calculatedScale, scaleHop))); | |
2139 } | |
2140 if (animationDecimal >= 1) { | |
2141 if (i == 0) divprev = 0; | |
2142 else divprev = data.data
sets[i].data[j] - data.datasets[i - 1].data[j]; | |
2143 if (i == data.datasets.l
ength - 1) divnext = 0; | |
2144 else divnext = data.data
sets[i + 1].data[j] - data.datasets[i].data[j]; | |
2145 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
2146 else lgtxt2 = ""; | |
2147 jsGraphAnnotate[ctx.Char
tNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["POINT", midPosX + Math.cos(c
onfig.startAngle * Math.PI / 180 - j * rotationDegree) * calculateOffset(config.
logarithmic, data.datasets[i].data[j], calculatedScale, scaleHop), midPosY - Mat
h.sin(config.startAngle * Math.PI / 180 - j * rotationDegree) * calculateOffset(
config.logarithmic, data.datasets[i].data[j], calculatedScale, scaleHop), lgtxt,
lgtxt2, 1 * data.datasets[i].data[j], divprev, divnext, maxvalue[j], totvalue[j
], i, j]; | |
2148 } | |
2149 } | |
2150 } | |
2151 ctx.closePath(); | |
2152 if (config.datasetFill) { | |
2153 if (typeof data.datasets[i].fillColor ==
"function") ctx.fillStyle = data.datasets[i].fillColor("FILLCOLOR", data, confi
g, i, -1, currentAnimPc, -1, "Radar", ctx, midPosX, midPosY, 0, (config.animatio
nLeftToRight ? 1 : currentAnimPc) * (calculateOffset(config.logarithmic, lmaxval
ue[i], calculatedScale, scaleHop))); | |
2154 else if (typeof data.datasets[i].fillCol
or == "string") ctx.fillStyle = data.datasets[i].fillColor; | |
2155 else ctx.fillStyle = config.defaultFillC
olor; | |
2156 } else ctx.fillStyle = "rgba(0,0,0,0)"; | |
2157 if (typeof data.datasets[i].strokeColor == "func
tion") ctx.strokeStyle = data.datasets[i].strokeColor("STROKECOLOR", data, confi
g, i, -1, currentAnimPc, -1, "Radar", ctx, midPosX, midPosY, 0, (config.animatio
nLeftToRight ? 1 : currentAnimPc) * (calculateOffset(config.logarithmic, lmaxval
ue[i], calculatedScale, scaleHop))); | |
2158 else if (typeof data.datasets[i].strokeColor ==
"string") ctx.strokeStyle = data.datasets[i].strokeColor; | |
2159 else ctx.strokeStyle = config.defaultStrokeColor
; | |
2160 ctx.lineWidth = config.datasetStrokeWidth; | |
2161 ctx.fill(); | |
2162 ctx.stroke(); | |
2163 if (config.pointDot && (!config.animationLeftToR
ight || (config.animationLeftToRight && animationDecimal >= 1))) { | |
2164 ctx.beginPath(); | |
2165 if (typeof data.datasets[i].pointColor =
= "function") ctx.fillStyle = data.datasets[i].pointColor("POINTCOLOR", data, co
nfig, i, -1, currentAnimPc, -1, "Radar", ctx, midPosX, midPosY, 0, (config.anima
tionLeftToRight ? 1 : currentAnimPc) * (calculateOffset(config.logarithmic, lmax
value[i], calculatedScale, scaleHop))); | |
2166 else ctx.fillStyle = data.datasets[i].po
intColor; | |
2167 if (typeof data.datasets[i].pointStrokeC
olor == "function") ctx.strokeStyle = data.datasets[i].pointStrokeColor("POINTST
ROKECOLOR", data, config, i, -1, currentAnimPc, -1, "Radar", ctx, midPosX, midPo
sY, 0, (config.animationLeftToRight ? 1 : currentAnimPc) * (calculateOffset(conf
ig.logarithmic, lmaxvalue[i], calculatedScale, scaleHop))); | |
2168 else ctx.strokeStyle = data.datasets[i].
pointStrokeColor; | |
2169 ctx.lineWidth = config.pointDotStrokeWid
th; | |
2170 for (var k = 0; k < data.datasets[i].dat
a.length; k++) { | |
2171 if (!(typeof(data.datasets[i].da
ta[k]) == 'undefined')) { | |
2172 ctx.beginPath(); | |
2173 ctx.arc(midPosX + curren
tAnimPc * (Math.cos(config.startAngle * Math.PI / 180 - k * rotationDegree) * ca
lculateOffset(config.logarithmic, data.datasets[i].data[k], calculatedScale, sca
leHop)), midPosY - currentAnimPc * (Math.sin(config.startAngle * Math.PI / 180 -
k * rotationDegree) * calculateOffset(config.logarithmic, data.datasets[i].data
[k], calculatedScale, scaleHop)), config.pointDotRadius, 2 * Math.PI, false); | |
2174 ctx.fill(); | |
2175 ctx.stroke(); | |
2176 } | |
2177 } | |
2178 } | |
2179 } | |
2180 ctx.restore(); | |
2181 if (animationDecimal >= 1 && config.inGraphDataShow) { | |
2182 for (var i = 0; i < data.datasets.length; i++) { | |
2183 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
2184 else lgtxt = ""; | |
2185 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
2186 if (!(typeof(data.datasets[i].da
ta[j]) == 'undefined')) { | |
2187 if (i == 0) divprev = 0; | |
2188 else divprev = data.data
sets[i].data[j] - data.datasets[i - 1].data[j]; | |
2189 if (i == data.datasets.l
ength - 1) divnext = 0; | |
2190 else divnext = data.data
sets[i + 1].data[j] - data.datasets[i].data[j]; | |
2191 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
2192 else lgtxt2 = ""; | |
2193 ctx.save(); | |
2194 ctx.textAlign = config.i
nGraphDataAlign; | |
2195 ctx.textBaseline = confi
g.inGraphDataVAlign; | |
2196 if (config.inGraphDataAl
ign == "off-center") { | |
2197 if (config.inGra
phDataRotate == "inRadiusAxis" || (config.startAngle * Math.PI / 180 - j * rotat
ionDegree + 4 * Math.PI) % (2 * Math.PI) > 3 * Math.PI / 2 || (config.startAngle
* Math.PI / 180 - j * rotationDegree + 4 * Math.PI) % (2 * Math.PI) <= Math.PI
/ 2) ctx.textAlign = "left"; | |
2198 else ctx.textAli
gn = "right"; | |
2199 } else if (config.inGrap
hDataAlign == "to-center") { | |
2200 if (config.inGra
phDataRotate == "inRadiusAxis" || (config.startAngle * Math.PI / 180 - j * rotat
ionDegree + 4 * Math.PI) % (2 * Math.PI) > 3 * Math.PI / 2 || (config.startAngle
* Math.PI / 180 - j * rotationDegree + 4 * Math.PI) % (2 * Math.PI) < Math.PI /
2) ctx.textAlign = "right"; | |
2201 else ctx.textAli
gn = "left"; | |
2202 } else ctx.textAlign = c
onfig.inGraphDataAlign; | |
2203 if (config.inGraphDataVA
lign == "off-center") { | |
2204 if ((config.star
tAngle * Math.PI / 180 - j * rotationDegree + 4 * Math.PI) % (2 * Math.PI) > Mat
h.PI) ctx.textBaseline = "bottom"; | |
2205 else ctx.textBas
eline = "top"; | |
2206 } else if (config.inGrap
hDataVAlign == "to-center") { | |
2207 if ((config.star
tAngle * Math.PI / 180 - j * rotationDegree + 4 * Math.PI) % (2 * Math.PI) > Mat
h.PI) ctx.textBaseline = "top"; | |
2208 else ctx.textBas
eline = "bottom"; | |
2209 } else ctx.textBaseline
= config.inGraphDataVAlign; | |
2210 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
2211 ctx.fillStyle = config.i
nGraphDataFontColor; | |
2212 var radiusPrt; | |
2213 if (config.inGraphDataRa
diusPosition == 1) radiusPrt = 0 + config.inGraphDataPaddingRadius; | |
2214 else if (config.inGraphD
ataRadiusPosition == 2) radiusPrt = (calculateOffset(config.logarithmic, data.da
tasets[i].data[j], calculatedScale, scaleHop)) / 2 + config.inGraphDataPaddingRa
dius; | |
2215 else if (config.inGraphD
ataRadiusPosition == 3) radiusPrt = (calculateOffset(config.logarithmic, data.da
tasets[i].data[j], calculatedScale, scaleHop)) + config.inGraphDataPaddingRadius
; | |
2216 ctx.translate(midPosX +
Math.cos(config.startAngle * Math.PI / 180 - j * rotationDegree) * radiusPrt, mi
dPosY - Math.sin(config.startAngle * Math.PI / 180 - j * rotationDegree) * radiu
sPrt); | |
2217 if (config.inGraphDataRo
tate == "inRadiusAxis") ctx.rotate(j * rotationDegree); | |
2218 else if (config.inGraphD
ataRotate == "inRadiusAxisRotateLabels") { | |
2219 if ((j * rotatio
nDegree + 2 * Math.PI) % (2 * Math.PI) > Math.PI / 2 && (j * rotationDegree + 2
* Math.PI) % (2 * Math.PI) < 3 * Math.PI / 2) ctx.rotate(3 * Math.PI + j * rotat
ionDegree); | |
2220 else ctx.rotate(
2 * Math.PI + j * rotationDegree); | |
2221 } else ctx.rotate(config
.inGraphDataRotate * (Math.PI / 180)); | |
2222 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
2223 config: config, | |
2224 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
2225 v2: fmtChartJS(c
onfig, lgtxt2, config.fmtV2), | |
2226 v3: fmtChartJS(c
onfig, 1 * data.datasets[i].data[j], config.fmtV3), | |
2227 v4: fmtChartJS(c
onfig, divprev, config.fmtV4), | |
2228 v5: fmtChartJS(c
onfig, divnext, config.fmtV5), | |
2229 v6: fmtChartJS(c
onfig, maxvalue[j], config.fmtV6), | |
2230 v7: fmtChartJS(c
onfig, totvalue[j], config.fmtV7), | |
2231 v8: roundToWithT
housands(config, fmtChartJS(config, 100 * data.datasets[i].data[j] / totvalue[j]
, config.fmtV8), config.roundPct), | |
2232 v9: fmtChartJS(c
onfig, midPosX + Math.cos(config.startAngle * Math.PI / 180 - j * rotationDegree
) * calculateOffset(config.logarithmic, data.datasets[i].data[j], calculatedScal
e, scaleHop), config.fmtV9), | |
2233 v10: fmtChartJS(
config, midPosY - Math.sin(config.startAngle * Math.PI / 180 - j * rotationDegre
e) * calculateOffset(config.logarithmic, data.datasets[i].data[j], calculatedSca
le, scaleHop), config.fmtV10), | |
2234 v11: fmtChartJS(
config, i, config.fmtV11), | |
2235 v12: fmtChartJS(
config, j, config.fmtV12), | |
2236 data: data | |
2237 }); | |
2238 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
2239 ctx.restore(); | |
2240 } | |
2241 } | |
2242 } | |
2243 } | |
2244 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"Radar"); | |
2245 }; | |
2246 | |
2247 function drawScale() { | |
2248 var rotationDegree = (2 * Math.PI) / data.datasets[0].da
ta.length; | |
2249 ctx.save(); | |
2250 ctx.translate(midPosX, midPosY); | |
2251 ctx.rotate((90 - config.startAngle) * Math.PI / 180); | |
2252 if (config.angleShowLineOut) { | |
2253 ctx.strokeStyle = config.angleLineColor; | |
2254 ctx.lineWidth = config.angleLineWidth; | |
2255 for (var h = 0; h < data.datasets[0].data.length
; h++) { | |
2256 ctx.rotate(rotationDegree); | |
2257 ctx.beginPath(); | |
2258 ctx.moveTo(0, 0); | |
2259 ctx.lineTo(0, -maxSize); | |
2260 ctx.stroke(); | |
2261 } | |
2262 } | |
2263 for (var i = 0; i < calculatedScale.steps; i++) { | |
2264 ctx.beginPath(); | |
2265 if (config.scaleShowLine) { | |
2266 ctx.strokeStyle = config.scaleLineColor; | |
2267 ctx.lineWidth = config.scaleLineWidth; | |
2268 ctx.moveTo(0, -scaleHop * (i + 1)); | |
2269 for (var j = 0; j < data.datasets[0].dat
a.length; j++) { | |
2270 ctx.rotate(rotationDegree); | |
2271 ctx.lineTo(0, -scaleHop * (i + 1
)); | |
2272 } | |
2273 ctx.closePath(); | |
2274 ctx.stroke(); | |
2275 } | |
2276 } | |
2277 ctx.rotate(-(90 - config.startAngle) * Math.PI / 180); | |
2278 if (config.scaleShowLabels) { | |
2279 for (var i = 0; i < calculatedScale.steps; i++)
{ | |
2280 ctx.textAlign = 'center'; | |
2281 ctx.font = config.scaleFontStyle + " " +
config.scaleFontSize + "px " + config.scaleFontFamily; | |
2282 ctx.textBaseline = "middle"; | |
2283 if (config.scaleShowLabelBackdrop) { | |
2284 var textWidth = ctx.measureTextM
ultiLine(calculatedScale.labels[i + 1], config.scaleFontSize).textWidth; | |
2285 ctx.fillStyle = config.scaleBack
dropColor; | |
2286 ctx.beginPath(); | |
2287 ctx.rect( | |
2288 Math.round(Math.cos(conf
ig.startAngle * Math.PI / 180) * (scaleHop * (i + 1)) - textWidth / 2 - config.s
caleBackdropPaddingX), //X | |
2289 Math.round((-Math.sin(co
nfig.startAngle * Math.PI / 180) * scaleHop * (i + 1)) - config.scaleFontSize *
0.5 - config.scaleBackdropPaddingY), //Y | |
2290 Math.round(textWidth + (
config.scaleBackdropPaddingX * 2)), //Width | |
2291 Math.round(config.scaleF
ontSize + (config.scaleBackdropPaddingY * 2)) //Height | |
2292 ); | |
2293 ctx.fill(); | |
2294 } | |
2295 ctx.fillStyle = config.scaleFontColor; | |
2296 ctx.fillTextMultiLine(calculatedScale.la
bels[i + 1], Math.cos(config.startAngle * Math.PI / 180) * (scaleHop * (i + 1)),
-Math.sin(config.startAngle * Math.PI / 180) * scaleHop * (i + 1), ctx.textBase
line, config.scaleFontSize); | |
2297 } | |
2298 } | |
2299 for (var k = 0; k < data.labels.length; k++) { | |
2300 ctx.font = config.pointLabelFontStyle + " " + co
nfig.pointLabelFontSize + "px " + config.pointLabelFontFamily; | |
2301 ctx.fillStyle = config.pointLabelFontColor; | |
2302 var opposite = Math.sin((90 - config.startAngle)
* Math.PI / 180 + rotationDegree * k) * (maxSize + config.pointLabelFontSize); | |
2303 var adjacent = Math.cos((90 - config.startAngle)
* Math.PI / 180 + rotationDegree * k) * (maxSize + config.pointLabelFontSize); | |
2304 var vangle = (90 - config.startAngle) * Math.PI
/ 180 + rotationDegree * k; | |
2305 while (vangle < 0) vangle = vangle + 2 * Math.PI
; | |
2306 while (vangle > 2 * Math.PI) vangle = vangle - 2
* Math.PI; | |
2307 if (vangle == Math.PI || vangle == 0) { | |
2308 ctx.textAlign = "center"; | |
2309 } else if (vangle > Math.PI) { | |
2310 ctx.textAlign = "right"; | |
2311 } else { | |
2312 ctx.textAlign = "left"; | |
2313 } | |
2314 ctx.textBaseline = "middle"; | |
2315 ctx.fillTextMultiLine(data.labels[k], opposite,
-adjacent, ctx.textBaseline, config.pointLabelFontSize); | |
2316 } | |
2317 ctx.restore(); | |
2318 }; | |
2319 | |
2320 function calculateDrawingSizes() { | |
2321 var midX, mxlb, maxL, maxR, iter, nbiter, prevMaxSize, p
revMidX; | |
2322 var rotationDegree = (2 * Math.PI) / data.datasets[0].da
ta.length; | |
2323 var rotateAngle = config.startAngle * Math.PI / 180; | |
2324 // Compute range for Mid Point of graph | |
2325 ctx.font = config.pointLabelFontStyle + " " + config.poi
ntLabelFontSize + "px " + config.pointLabelFontFamily; | |
2326 if (!config.graphMaximized) { | |
2327 maxR = msr.availableWidth / 2; | |
2328 maxL = msr.availableWidth / 2; | |
2329 nbiter = 1; | |
2330 } else { | |
2331 maxR = msr.availableWidth / 2; | |
2332 maxL = msr.availableWidth / 2; | |
2333 nbiter = 40; | |
2334 for (var i = 0; i < data.labels.length; i++) { | |
2335 var textMeasurement = ctx.measureTextMul
tiLine(data.labels[i], config.scaleFontSize).textWidth + ctx.measureTextMultiLin
e(data.labels[i], config.scaleFontSize).textHeight; | |
2336 mxlb = (msr.availableWidth - textMeasure
ment) / (1 + Math.abs(Math.cos(rotateAngle))); | |
2337 if ((rotateAngle < Math.PI / 2 && rotate
Angle > -Math.PI / 2) || rotateAngle > 3 * Math.PI / 2) { | |
2338 if (mxlb < maxR) maxR = mxlb; | |
2339 } else if (Math.cos(rotateAngle) != 0) { | |
2340 if (mxlb < maxL) maxL = mxlb; | |
2341 } | |
2342 rotateAngle -= rotationDegree; | |
2343 } | |
2344 } | |
2345 // compute max Radius and midPoint in that range | |
2346 prevMaxSize = 0; | |
2347 prevMidX = 0; | |
2348 midPosX = maxR + msr.rightNotUsableSize; | |
2349 for (midX = maxR, iter = 0; iter < nbiter; ++iter, midX
+= (msr.availableWidth - maxL - maxR) / nbiter) { | |
2350 maxSize = Max([midX, msr.availableWidth - midX])
; | |
2351 var rotateAngle = config.startAngle * Math.PI /
180; | |
2352 mxlb = msr.available; | |
2353 for (var i = 0; i < data.labels.length; i++) { | |
2354 var textMeasurement = ctx.measureTextMul
tiLine(data.labels[i], config.scaleFontSize).textWidth + ctx.measureTextMultiLin
e(data.labels[i], config.scaleFontSize).textHeight; | |
2355 if ((rotateAngle < Math.PI / 2 && rotate
Angle > -Math.PI / 2) || rotateAngle > 3 * Math.PI / 2) { | |
2356 mxlb = ((msr.availableWidth - mi
dX) - textMeasurement) / Math.abs(Math.cos(rotateAngle)); | |
2357 } else if (Math.cos(rotateAngle != 0)) { | |
2358 mxlb = (midX - textMeasurement)
/ Math.abs(Math.cos(rotateAngle)); | |
2359 } | |
2360 if (mxlb < maxSize) maxSize = mxlb; | |
2361 if (Math.sin(rotateAngle) * msr.availabl
eHeight / 2 > msr.availableHeight / 2 - config.scaleFontSize * 2) { | |
2362 mxlb = Math.sin(rotateAngle) * m
sr.availableHeight / 2 - 1.5 * config.scaleFontSize; | |
2363 if (mxlb < maxSize) maxSize = mx
lb; | |
2364 } | |
2365 rotateAngle -= rotationDegree; | |
2366 } | |
2367 if (maxSize > prevMaxSize) { | |
2368 prevMaxSize = maxSize; | |
2369 midPosX = midX + msr.rightNotUsableSize; | |
2370 } | |
2371 } | |
2372 maxSize = prevMaxSize - config.scaleFontSize / 2; | |
2373 //If the label height is less than 5, set it to 5 so we
don't have lines on top of each other. | |
2374 labelHeight = Default(labelHeight, 5); | |
2375 }; | |
2376 | |
2377 function getValueBounds() { | |
2378 var upperValue = Number.MIN_VALUE; | |
2379 var lowerValue = Number.MAX_VALUE; | |
2380 for (var i = 0; i < data.datasets.length; i++) { | |
2381 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
2382 if (1 * data.datasets[i].data[j] > upper
Value) { | |
2383 upperValue = 1 * data.datasets[i
].data[j] | |
2384 } | |
2385 if (1 * data.datasets[i].data[j] < lower
Value) { | |
2386 lowerValue = 1 * data.datasets[i
].data[j] | |
2387 } | |
2388 } | |
2389 } | |
2390 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
2391 upperValue = Max([upperValue * 2, 1]); | |
2392 lowerValue = 0; | |
2393 } | |
2394 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
2395 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
2396 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
2397 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
2398 return { | |
2399 maxValue: upperValue, | |
2400 minValue: lowerValue, | |
2401 maxSteps: maxSteps, | |
2402 minSteps: minSteps | |
2403 }; | |
2404 } | |
2405 }; | |
2406 | |
2407 | |
2408 var Pie = function(data, config, ctx) { | |
2409 | |
2410 var segmentTotal = 0; | |
2411 var msr, midPieX, midPieY, pieRadius; | |
2412 | |
2413 ctx.tpchart="Pie"; | |
2414 setting_new_chart_vars(ctx); | |
2415 if (!dynamicFunction(data, config, ctx)) { | |
2416 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
2417 return; | |
2418 } | |
2419 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
2420 if(!config.multiGraph) { | |
2421 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
2422 subUpdateChart(ctx,data,config); | |
2423 return; | |
2424 } else { ctx.firstPass=1; } | |
2425 } | |
2426 | |
2427 while (config.startAngle < 0) { | |
2428 config.startAngle += 360; | |
2429 } | |
2430 while (config.startAngle > 360) { | |
2431 config.startAngle -= 360; | |
2432 } | |
2433 config.logarithmic = false; | |
2434 config.logarithmic2 = false; | |
2435 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
2436 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
2437 defMouse(ctx, data, config); | |
2438 //In case we have a canvas that is not a square. Minus 5 pixels
as padding round the edge. | |
2439 setRect(ctx, config); | |
2440 msr = setMeasures(data, config, ctx, height, width, "none", null
, true, false, false, false, true, "Pie"); | |
2441 // midPieX = msr.leftNotUsableSize + (msr.availableWidth
/ 2); | |
2442 // midPieY = msr.topNotUsableSize + (msr.availableHeight
/ 2); | |
2443 // pieRadius = Min([msr.availableHeight / 2, msr.availabl
eWidth / 2]) - 5; | |
2444 for (var i = 0; i < data.length; i++) { | |
2445 if (!(typeof(data[i].value) == 'undefined')) segmentTota
l += 1 * data[i].value; | |
2446 } | |
2447 calculateDrawingSize(); | |
2448 if(pieRadius > 0) { | |
2449 animationLoop(config, null, drawPieSegments, ctx, msr.cl
rx, msr.clry, msr.clrwidth, msr.clrheight, midPieX, midPieY, midPieX - pieRadius
, midPieY + pieRadius, data); | |
2450 } else { | |
2451 testRedraw(ctx,data,config); | |
2452 } | |
2453 function drawPieSegments(animationDecimal) { | |
2454 var cumulativeAngle = -config.startAngle * (Math.PI / 18
0) + 2 * Math.PI, | |
2455 cumvalue = 0, | |
2456 scaleAnimation = 1, | |
2457 rotateAnimation = 1; | |
2458 var realCumulativeAngle = config.startAngle * (Math.PI /
180) + 2 * Math.PI; | |
2459 while (cumulativeAngle < 0) { | |
2460 cumulativeAngle += 2 * Math.PI; | |
2461 } | |
2462 while (cumulativeAngle > 2 * Math.PI) { | |
2463 cumulativeAngle -= 2 * Math.PI; | |
2464 } | |
2465 while (realCumulativeAngle < 0) { | |
2466 realCumulativeAngle += 2 * Math.PI; | |
2467 } | |
2468 while (realCumulativeAngle > 2 * Math.PI) { | |
2469 realCumulativeAngle -= 2 * Math.PI; | |
2470 } | |
2471 if (config.animation) { | |
2472 if (config.animateScale) { | |
2473 scaleAnimation = animationDecimal; | |
2474 } | |
2475 if (config.animateRotate) { | |
2476 rotateAnimation = animationDecimal; | |
2477 } | |
2478 } | |
2479 if (animationDecimal >= 1) { | |
2480 totvalue = 0; | |
2481 for (var i = 0; i < data.length; i++) | |
2482 if (!(typeof(data[i].value) == 'undefine
d')) totvalue += 1 * data[i].value; | |
2483 } | |
2484 for (var i = 0; i < data.length; i++) { | |
2485 correctedRotateAnimation = animationCorrection(r
otateAnimation, data, config, i, -1, 0).mainVal; | |
2486 if (!(typeof(data[i].value) == 'undefined')) { | |
2487 var segmentAngle = correctedRotateAnimat
ion * ((1 * data[i].value / segmentTotal) * (Math.PI * 2)); | |
2488 if (segmentAngle >= Math.PI * 2) segment
Angle = Math.PI * 2 - 0.001; // bug on Android when segmentAngle is >= 2*PI; | |
2489 ctx.beginPath(); | |
2490 ctx.arc(midPieX, midPieY, scaleAnimation
* pieRadius, cumulativeAngle, cumulativeAngle + segmentAngle); | |
2491 ctx.lineTo(midPieX, midPieY); | |
2492 ctx.closePath(); | |
2493 if (typeof data[i].color == "function")
ctx.fillStyle = data[i].color("COLOR", data, config, i, -1, animationDecimal, da
ta[i].value, "Pie", ctx, midPieX, midPieY, 0, scaleAnimation * pieRadius); | |
2494 else ctx.fillStyle = data[i].color; | |
2495 ctx.fill(); | |
2496 cumulativeAngle += segmentAngle; | |
2497 cumvalue += 1 * data[i].value; | |
2498 if (config.segmentShowStroke) { | |
2499 ctx.lineWidth = config.segmentSt
rokeWidth; | |
2500 ctx.strokeStyle = config.segment
StrokeColor; | |
2501 ctx.stroke(); | |
2502 } | |
2503 } | |
2504 } | |
2505 if (animationDecimal >= 1) { | |
2506 cumulativeAngle-=2*Math.PI; | |
2507 for (var i = 0; i < data.length; i++) { | |
2508 correctedRotateAnimation = animationCorr
ection(rotateAnimation, data, config, i, -1, 0).mainVal; | |
2509 if (!(typeof(data[i].value) == 'undefine
d')) { | |
2510 var segmentAngle = correctedRota
teAnimation * ((1 * data[i].value / segmentTotal) * (Math.PI * 2)); | |
2511 if (segmentAngle >= Math.PI * 2)
segmentAngle = Math.PI * 2 - 0.001; // bug on Android when segmentAngle is >= 2
*PI; | |
2512 cumulativeAngle += segmentAngle; | |
2513 cumvalue += 1 * data[i].value; | |
2514 if (typeof(data[i].title) == "st
ring") lgtxt = data[i].title.trim(); | |
2515 else lgtxt = ""; | |
2516 jsGraphAnnotate[ctx.ChartNewId][
jsGraphAnnotate[ctx.ChartNewId].length] = ["ARC", midPieX, midPieY, 0, pieRadius
, cumulativeAngle - segmentAngle, cumulativeAngle, lgtxt, 1 * data[i].value, cum
value, totvalue, segmentAngle, i]; | |
2517 if (config.inGraphDataShow && se
gmentAngle >= (Math.PI/180) * config.inGraphDataMinimumAngle) { | |
2518 if (config.inGraphDataAn
glePosition == 1) posAngle = realCumulativeAngle + config.inGraphDataPaddingAngl
e * (Math.PI / 180); | |
2519 else if (config.inGraphD
ataAnglePosition == 2) posAngle = realCumulativeAngle - segmentAngle / 2 + confi
g.inGraphDataPaddingAngle * (Math.PI / 180); | |
2520 else if (config.inGraphD
ataAnglePosition == 3) posAngle = realCumulativeAngle - segmentAngle + config.in
GraphDataPaddingAngle * (Math.PI / 180); | |
2521 if (config.inGraphDataRa
diusPosition == 1) labelRadius = 0 + config.inGraphDataPaddingRadius; | |
2522 else if (config.inGraphD
ataRadiusPosition == 2) labelRadius = pieRadius / 2 + config.inGraphDataPaddingR
adius; | |
2523 else if (config.inGraphD
ataRadiusPosition == 3) labelRadius = pieRadius + config.inGraphDataPaddingRadiu
s; | |
2524 ctx.save(); | |
2525 if (config.inGraphDataAl
ign == "off-center") { | |
2526 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "left"; | |
2527 else ctx.textAli
gn = "right"; | |
2528 } else if (config.inGrap
hDataAlign == "to-center") { | |
2529 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "right"; | |
2530 else ctx.textAli
gn = "left"; | |
2531 } else ctx.textAlign = c
onfig.inGraphDataAlign; | |
2532 if (config.inGraphDataVA
lign == "off-center") { | |
2533 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "top"; | |
2534 else ctx.textBas
eline = "bottom"; | |
2535 } else if (config.inGrap
hDataVAlign == "to-center") { | |
2536 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "bottom"; | |
2537 else ctx.textBas
eline = "top"; | |
2538 } else ctx.textBaseline
= config.inGraphDataVAlign; | |
2539 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
2540 ctx.fillStyle = config.i
nGraphDataFontColor; | |
2541 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
2542 config: config, | |
2543 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
2544 v2: fmtChartJS(c
onfig, 1 * data[i].value, config.fmtV2), | |
2545 v3: fmtChartJS(c
onfig, cumvalue, config.fmtV3), | |
2546 v4: fmtChartJS(c
onfig, totvalue, config.fmtV4), | |
2547 v5: fmtChartJS(c
onfig, segmentAngle, config.fmtV5), | |
2548 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data[i].value / totvalue, config.fmtV6
), config.roundPct), | |
2549 v7: fmtChartJS(c
onfig, midPieX, config.fmtV7), | |
2550 v8: fmtChartJS(c
onfig, midPieY, config.fmtV8), | |
2551 v9: fmtChartJS(c
onfig, 0, config.fmtV9), | |
2552 v10: fmtChartJS(
config, pieRadius, config.fmtV10), | |
2553 v11: fmtChartJS(
config, cumulativeAngle - segmentAngle, config.fmtV11), | |
2554 v12: fmtChartJS(
config, cumulativeAngle, config.fmtV12), | |
2555 v13: fmtChartJS(
config, i, config.fmtV13), | |
2556 data: data | |
2557 }); | |
2558 ctx.translate(midPieX +
labelRadius * Math.cos(posAngle), midPieY - labelRadius * Math.sin(posAngle)); | |
2559 if (config.inGraphDataRo
tate == "inRadiusAxis") ctx.rotate(2 * Math.PI - posAngle); | |
2560 else if (config.inGraphD
ataRotate == "inRadiusAxisRotateLabels") { | |
2561 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI / 2 && (posAngle + 2 * Math.PI) % (2 * Ma
th.PI) < 3 * Math.PI / 2) ctx.rotate(3 * Math.PI - posAngle); | |
2562 else ctx.rotate(
2 * Math.PI - posAngle); | |
2563 } else ctx.rotate(config
.inGraphDataRotate * (Math.PI / 180)); | |
2564 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
2565 ctx.restore(); | |
2566 } | |
2567 realCumulativeAngle -= segmentAn
gle; | |
2568 } | |
2569 } | |
2570 | |
2571 } | |
2572 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"Pie"); | |
2573 }; | |
2574 | |
2575 function calculateDrawingSize() { | |
2576 var lgtxt; | |
2577 var cumulativeAngle = -config.startAngle * (Math.PI / 18
0) + 2 * Math.PI, | |
2578 cumvalue = 0; | |
2579 while (cumulativeAngle < 0) { | |
2580 cumulativeAngle += 2 * Math.PI; | |
2581 } | |
2582 while (cumulativeAngle > 2 * Math.PI) { | |
2583 cumulativeAngle -= 2 * Math.PI; | |
2584 } | |
2585 midPieX = msr.leftNotUsableSize + (msr.availableWidth /
2); | |
2586 midPieY = msr.topNotUsableSize + (msr.availableHeight /
2); | |
2587 pieRadius = Min([msr.availableHeight / 2, msr.availableW
idth / 2]) - 5; | |
2588 // Computerange Pie Radius | |
2589 if (config.inGraphDataShow && config.inGraphDataRadiusPo
sition == 3 && config.inGraphDataAlign == "off-center" && config.inGraphDataRota
te == 0) { | |
2590 pieRadius = Min([msr.availableHeight / 2, msr.av
ailableWidth / 2]) - config.inGraphDataFontSize - config.inGraphDataPaddingRadiu
s - 5; | |
2591 var realCumulativeAngle = config.startAngle * (M
ath.PI / 180) + 2 * Math.PI; | |
2592 while (realCumulativeAngle < 0) { | |
2593 realCumulativeAngle += 2 * Math.PI; | |
2594 } | |
2595 while (realCumulativeAngle > 2 * Math.PI) { | |
2596 realCumulativeAngle -= 2 * Math.PI; | |
2597 } | |
2598 var totvalue = 0; | |
2599 for (var i = 0; i < data.length; i++) | |
2600 if (!(typeof(data[i].value) == 'undefine
d')) totvalue += 1 * data[i].value; | |
2601 ctx.font = config.inGraphDataFontStyle + ' ' + c
onfig.inGraphDataFontSize + 'px ' + config.inGraphDataFontFamily; | |
2602 var cumvalue = 0; | |
2603 var posAngle; | |
2604 for (var i = 0; i < data.length; i++) { | |
2605 if (!(typeof(data[i].value) == 'undefine
d')) { | |
2606 cumvalue += 1 * data[i].value; | |
2607 var segmentAngle = (1 * data[i].
value / segmentTotal) * (Math.PI * 2); | |
2608 cumulativeAngle += segmentAngle; | |
2609 if (config.inGraphDataAnglePosit
ion == 1) posAngle = realCumulativeAngle + config.inGraphDataPaddingAngle * (Mat
h.PI / 180); | |
2610 else if (config.inGraphDataAngle
Position == 2) posAngle = realCumulativeAngle - segmentAngle / 2 + config.inGrap
hDataPaddingAngle * (Math.PI / 180); | |
2611 else if (config.inGraphDataAngle
Position == 3) posAngle = realCumulativeAngle - segmentAngle + config.inGraphDat
aPaddingAngle * (Math.PI / 180); | |
2612 realCumulativeAngle -= segmentAn
gle; | |
2613 if (typeof(data[i].title) == "st
ring") lgtxt = data[i].title.trim(); | |
2614 else lgtxt = ""; | |
2615 var dispString = tmplbis(config.
inGraphDataTmpl, { | |
2616 config: config, | |
2617 v1: fmtChartJS(config, l
gtxt, config.fmtV1), | |
2618 v2: fmtChartJS(config, 1
* data[i].value, config.fmtV2), | |
2619 v3: fmtChartJS(config, c
umvalue, config.fmtV3), | |
2620 v4: fmtChartJS(config, t
otvalue, config.fmtV4), | |
2621 v5: fmtChartJS(config, s
egmentAngle, config.fmtV5), | |
2622 v6: roundToWithThousands
(config, fmtChartJS(config, 100 * data[i].value / totvalue, config.fmtV6), confi
g.roundPct), | |
2623 v7: fmtChartJS(config, m
idPieX, config.fmtV7), | |
2624 v8: fmtChartJS(config, m
idPieY, config.fmtV8), | |
2625 v9: fmtChartJS(config, 0
, config.fmtV9), | |
2626 v10: fmtChartJS(config,
pieRadius, config.fmtV10), | |
2627 v11: fmtChartJS(config,
cumulativeAngle - segmentAngle, config.fmtV11), | |
2628 v12: fmtChartJS(config,
cumulativeAngle, config.fmtV12), | |
2629 v13: fmtChartJS(config,
i, config.fmtV13), | |
2630 data: data | |
2631 }); | |
2632 var textMeasurement = ctx.measur
eText(dispString).width; | |
2633 var MaxRadiusX = Math.abs((msr.a
vailableWidth / 2 - textMeasurement) / Math.cos(posAngle)) - config.inGraphDataP
addingRadius - 5; | |
2634 if (MaxRadiusX < pieRadius) pieR
adius = MaxRadiusX; | |
2635 } | |
2636 } | |
2637 } | |
2638 pieRadius = pieRadius * config.radiusScale; | |
2639 }; | |
2640 }; | |
2641 var Doughnut = function(data, config, ctx) { | |
2642 var segmentTotal = 0; | |
2643 var msr, midPieX, midPieY, doughnutRadius; | |
2644 | |
2645 ctx.tpchart="Doughnut"; | |
2646 setting_new_chart_vars(ctx); | |
2647 if (!dynamicFunction(data, config, ctx)) { | |
2648 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
2649 return; | |
2650 } | |
2651 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
2652 if(!config.multiGraph) { | |
2653 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
2654 subUpdateChart(ctx,data,config); | |
2655 return; | |
2656 } else { ctx.firstPass=1; } | |
2657 } | |
2658 | |
2659 var realCumulativeAngle = config.startAngle * (Math.PI / 180) +
2 * Math.PI; | |
2660 while (config.startAngle < 0) { | |
2661 config.startAngle += 360; | |
2662 } | |
2663 while (config.startAngle > 360) { | |
2664 config.startAngle -= 360; | |
2665 } | |
2666 while (realCumulativeAngle < 0) { | |
2667 realCumulativeAngle += 2 * Math.PI; | |
2668 } | |
2669 while (realCumulativeAngle > 2 * Math.PI) { | |
2670 realCumulativeAngle -= 2 * Math.PI; | |
2671 } | |
2672 config.logarithmic = false; | |
2673 config.logarithmic2 = false; | |
2674 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
2675 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
2676 defMouse(ctx, data, config); | |
2677 setRect(ctx, config); | |
2678 msr = setMeasures(data, config, ctx, height, width, "none", null
, true, false, false, false, true, "Doughnut"); | |
2679 calculateDrawingSize(); | |
2680 var cutoutRadius = doughnutRadius * (config.percentageInnerCutou
t / 100); | |
2681 for (var i = 0; i < data.length; i++) { | |
2682 if (!(typeof(data[i].value) == 'undefined')) segmentTota
l += 1 * data[i].value; | |
2683 } | |
2684 if(doughnutRadius > 0) { | |
2685 animationLoop(config, null, drawPieSegments, ctx, msr.cl
rx, msr.clry, msr.clrwidth, msr.clrheight, midPieX, midPieY, midPieX - doughnutR
adius, midPieY + doughnutRadius, data); | |
2686 } else { | |
2687 testRedraw(ctx,data,config); | |
2688 } | |
2689 | |
2690 | |
2691 function drawPieSegments(animationDecimal) { | |
2692 var cumulativeAngle = -config.startAngle * (Math.PI / 18
0) + 2 * Math.PI, | |
2693 cumvalue = 0, | |
2694 scaleAnimation = 1, | |
2695 rotateAnimation = 1; | |
2696 while (cumulativeAngle < 0) { | |
2697 cumulativeAngle += 2 * Math.PI; | |
2698 } | |
2699 while (cumulativeAngle > 2 * Math.PI) { | |
2700 cumulativeAngle -= 2 * Math.PI; | |
2701 } | |
2702 if (config.animation) { | |
2703 if (config.animateScale) { | |
2704 scaleAnimation = animationDecimal; | |
2705 } | |
2706 if (config.animateRotate) { | |
2707 rotateAnimation = animationDecimal; | |
2708 } | |
2709 } | |
2710 if (animationDecimal >= 1) { | |
2711 totvalue = 0; | |
2712 for (var i = 0; i < data.length; i++) | |
2713 if (!(typeof(data[i].value) == 'undefine
d')) totvalue += 1 * data[i].value; | |
2714 } | |
2715 for (var i = 0; i < data.length; i++) { | |
2716 correctedRotateAnimation = animationCorrection(r
otateAnimation, data, config, i, -1, 0).mainVal; | |
2717 if (!(typeof(data[i].value) == 'undefined')) { | |
2718 var segmentAngle = correctedRotateAnimat
ion * ((1 * data[i].value / segmentTotal) * (Math.PI * 2)); | |
2719 if (segmentAngle >= Math.PI * 2) segment
Angle = Math.PI * 2 - 0.001; // but on Android when segmentAngle is >= 2*PI; | |
2720 ctx.beginPath(); | |
2721 ctx.arc(midPieX, midPieY, scaleAnimation
* doughnutRadius, cumulativeAngle, cumulativeAngle + segmentAngle, false); | |
2722 ctx.arc(midPieX, midPieY, scaleAnimation
* cutoutRadius, cumulativeAngle + segmentAngle, cumulativeAngle, true); | |
2723 ctx.closePath(); | |
2724 if (typeof data[i].color == "function")
ctx.fillStyle = data[i].color("COLOR", data, config, i, -1, animationDecimal, da
ta[i].value, "Doughnut", ctx, midPieX, midPieY, scaleAnimation * cutoutRadius, s
caleAnimation * doughnutRadius); | |
2725 else ctx.fillStyle = data[i].color; | |
2726 ctx.fill(); | |
2727 cumulativeAngle += segmentAngle; | |
2728 cumvalue += 1 * data[i].value; | |
2729 if (config.segmentShowStroke) { | |
2730 ctx.lineWidth = config.segmentSt
rokeWidth; | |
2731 ctx.strokeStyle = config.segment
StrokeColor; | |
2732 ctx.stroke(); | |
2733 } | |
2734 } | |
2735 } | |
2736 if (animationDecimal >= 1) { | |
2737 cumulativeAngle-=2*Math.PI; | |
2738 for (var i = 0; i < data.length; i++) { | |
2739 correctedRotateAnimation = animationCorr
ection(rotateAnimation, data, config, i, -1, 0).mainVal; | |
2740 if (!(typeof(data[i].value) == 'undefine
d')) { | |
2741 var segmentAngle = correctedRota
teAnimation * ((1 * data[i].value / segmentTotal) * (Math.PI * 2)); | |
2742 if (segmentAngle >= Math.PI * 2)
segmentAngle = Math.PI * 2 - 0.001; // but on Android when segmentAngle is >= 2
*PI; | |
2743 cumulativeAngle += segmentAngle; | |
2744 cumvalue += 1 * data[i].value; | |
2745 if (typeof(data[i].title) == "st
ring") lgtxt = data[i].title.trim(); | |
2746 else lgtxt = ""; | |
2747 jsGraphAnnotate[ctx.ChartNewId][
jsGraphAnnotate[ctx.ChartNewId].length] = ["ARC", midPieX, midPieY, cutoutRadius
, doughnutRadius, cumulativeAngle - segmentAngle, cumulativeAngle, lgtxt, 1 * da
ta[i].value, cumvalue, totvalue, segmentAngle, i]; | |
2748 if (config.inGraphDataShow && se
gmentAngle >= (Math.PI/180) * config.inGraphDataMinimumAngle) { | |
2749 if (config.inGraphDataAn
glePosition == 1) posAngle = realCumulativeAngle + config.inGraphDataPaddingAngl
e * (Math.PI / 180); | |
2750 else if (config.inGraphD
ataAnglePosition == 2) posAngle = realCumulativeAngle - segmentAngle / 2 + confi
g.inGraphDataPaddingAngle * (Math.PI / 180); | |
2751 else if (config.inGraphD
ataAnglePosition == 3) posAngle = realCumulativeAngle - segmentAngle + config.in
GraphDataPaddingAngle * (Math.PI / 180); | |
2752 if (config.inGraphDataRa
diusPosition == 1) labelRadius = cutoutRadius + config.inGraphDataPaddingRadius; | |
2753 else if (config.inGraphD
ataRadiusPosition == 2) labelRadius = cutoutRadius + (doughnutRadius - cutoutRad
ius) / 2 + config.inGraphDataPaddingRadius; | |
2754 else if (config.inGraphD
ataRadiusPosition == 3) labelRadius = doughnutRadius + config.inGraphDataPadding
Radius; | |
2755 ctx.save(); | |
2756 if (config.inGraphDataAl
ign == "off-center") { | |
2757 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "left"; | |
2758 else ctx.textAli
gn = "right"; | |
2759 } else if (config.inGrap
hDataAlign == "to-center") { | |
2760 if (config.inGra
phDataRotate == "inRadiusAxis" || (posAngle + 2 * Math.PI) % (2 * Math.PI) > 3 *
Math.PI / 2 || (posAngle + 2 * Math.PI) % (2 * Math.PI) < Math.PI / 2) ctx.text
Align = "right"; | |
2761 else ctx.textAli
gn = "left"; | |
2762 } else ctx.textAlign = c
onfig.inGraphDataAlign; | |
2763 if (config.inGraphDataVA
lign == "off-center") { | |
2764 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "top"; | |
2765 else ctx.textBas
eline = "bottom"; | |
2766 } else if (config.inGrap
hDataVAlign == "to-center") { | |
2767 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI) ctx.textBaseline = "bottom"; | |
2768 else ctx.textBas
eline = "top"; | |
2769 } else ctx.textBaseline
= config.inGraphDataVAlign; | |
2770 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
2771 ctx.fillStyle = config.i
nGraphDataFontColor; | |
2772 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
2773 config: config, | |
2774 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
2775 v2: fmtChartJS(c
onfig, 1 * data[i].value, config.fmtV2), | |
2776 v3: fmtChartJS(c
onfig, cumvalue, config.fmtV3), | |
2777 v4: fmtChartJS(c
onfig, totvalue, config.fmtV4), | |
2778 v5: fmtChartJS(c
onfig, segmentAngle, config.fmtV5), | |
2779 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data[i].value / totvalue, config.fmtV6
), config.roundPct), | |
2780 v7: fmtChartJS(c
onfig, midPieX, config.fmtV7), | |
2781 v8: fmtChartJS(c
onfig, midPieY, config.fmtV8), | |
2782 v9: fmtChartJS(c
onfig, cutoutRadius, config.fmtV9), | |
2783 v10: fmtChartJS(
config, doughnutRadius, config.fmtV10), | |
2784 v11: fmtChartJS(
config, cumulativeAngle - segmentAngle, config.fmtV11), | |
2785 v12: fmtChartJS(
config, cumulativeAngle, config.fmtV12), | |
2786 v13: fmtChartJS(
config, i, config.fmtV13) | |
2787 }); | |
2788 ctx.translate(midPieX +
labelRadius * Math.cos(posAngle), midPieY - labelRadius * Math.sin(posAngle)); | |
2789 if (config.inGraphDataRo
tate == "inRadiusAxis") ctx.rotate(2 * Math.PI - posAngle); | |
2790 else if (config.inGraphD
ataRotate == "inRadiusAxisRotateLabels") { | |
2791 if ((posAngle +
2 * Math.PI) % (2 * Math.PI) > Math.PI / 2 && (posAngle + 2 * Math.PI) % (2 * Ma
th.PI) < 3 * Math.PI / 2) ctx.rotate(3 * Math.PI - posAngle); | |
2792 else ctx.rotate(
2 * Math.PI - posAngle); | |
2793 } else ctx.rotate(config
.inGraphDataRotate * (Math.PI / 180)); | |
2794 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
2795 ctx.restore(); | |
2796 } | |
2797 realCumulativeAngle -= segmentAn
gle; | |
2798 } | |
2799 } | |
2800 } | |
2801 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"Doughnut"); | |
2802 }; | |
2803 | |
2804 function calculateDrawingSize() { | |
2805 var lgtxt; | |
2806 var cumulativeAngle = -config.startAngle * (Math.PI / 18
0) + 2 * Math.PI, | |
2807 cumvalue = 0; | |
2808 while (cumulativeAngle < 0) { | |
2809 cumulativeAngle += 2 * Math.PI; | |
2810 } | |
2811 while (cumulativeAngle > 2 * Math.PI) { | |
2812 cumulativeAngle -= 2 * Math.PI; | |
2813 } | |
2814 midPieX = msr.leftNotUsableSize + (msr.availableWidth /
2); | |
2815 midPieY = msr.topNotUsableSize + (msr.availableHeight /
2); | |
2816 doughnutRadius = Min([msr.availableHeight / 2, msr.avail
ableWidth / 2]) - 5; | |
2817 // Computerange Pie Radius | |
2818 if (config.inGraphDataShow && config.inGraphDataRadiusPo
sition == 3 && config.inGraphDataAlign == "off-center" && config.inGraphDataRota
te == 0) { | |
2819 doughnutRadius = Min([msr.availableHeight / 2, m
sr.availableWidth / 2]) - config.inGraphDataFontSize - config.inGraphDataPadding
Radius - 5; | |
2820 var realCumulativeAngle = config.startAngle * (M
ath.PI / 180) + 2 * Math.PI; | |
2821 while (realCumulativeAngle < 0) { | |
2822 realCumulativeAngle += 2 * Math.PI; | |
2823 } | |
2824 while (realCumulativeAngle > 2 * Math.PI) { | |
2825 realCumulativeAngle -= 2 * Math.PI; | |
2826 } | |
2827 var totvalue = 0; | |
2828 for (var i = 0; i < data.length; i++) | |
2829 if (!(typeof(data[i].value) == 'undefine
d')) totvalue += 1 * data[i].value; | |
2830 ctx.font = config.inGraphDataFontStyle + ' ' + c
onfig.inGraphDataFontSize + 'px ' + config.inGraphDataFontFamily; | |
2831 var posAngle; | |
2832 var cumulativeAngle = 0; | |
2833 for (var i = 0; i < data.length; i++) { | |
2834 if (!(typeof(data[i].value) == 'undefine
d')) { | |
2835 cumvalue += 1 * data[i].value; | |
2836 var segmentAngle = (1 * data[i].
value / segmentTotal) * (Math.PI * 2); | |
2837 cumulativeAngle += segmentAngle; | |
2838 if (config.inGraphDataAnglePosit
ion == 1) posAngle = realCumulativeAngle + config.inGraphDataPaddingAngle * (Mat
h.PI / 180); | |
2839 else if (config.inGraphDataAngle
Position == 2) posAngle = realCumulativeAngle - segmentAngle / 2 + config.inGrap
hDataPaddingAngle * (Math.PI / 180); | |
2840 else if (config.inGraphDataAngle
Position == 3) posAngle = realCumulativeAngle - segmentAngle + config.inGraphDat
aPaddingAngle * (Math.PI / 180); | |
2841 realCumulativeAngle -= segmentAn
gle; | |
2842 if (typeof(data[i].title) == "st
ring") lgtxt = data[i].title.trim(); | |
2843 else lgtxt = ""; | |
2844 var dispString = tmplbis(config.
inGraphDataTmpl, { | |
2845 config: config, | |
2846 v1: fmtChartJS(config, l
gtxt, config.fmtV1), | |
2847 v2: fmtChartJS(config, 1
* data[i].value, config.fmtV2), | |
2848 v3: fmtChartJS(config, c
umvalue, config.fmtV3), | |
2849 v4: fmtChartJS(config, t
otvalue, config.fmtV4), | |
2850 v5: fmtChartJS(config, s
egmentAngle, config.fmtV5), | |
2851 v6: roundToWithThousands
(config, fmtChartJS(config, 100 * data[i].value / totvalue, config.fmtV6), confi
g.roundPct), | |
2852 v7: fmtChartJS(config, m
idPieX, config.fmtV7), | |
2853 v8: fmtChartJS(config, m
idPieY, config.fmtV8), | |
2854 v9: fmtChartJS(config, c
utoutRadius, config.fmtV9), | |
2855 v10: fmtChartJS(config,
doughnutRadius, config.fmtV10), | |
2856 v11: fmtChartJS(config,
cumulativeAngle - segmentAngle, config.fmtV11), | |
2857 v12: fmtChartJS(config,
cumulativeAngle, config.fmtV12), | |
2858 v13: fmtChartJS(config,
i, config.fmtV13), | |
2859 data: data | |
2860 }); | |
2861 var textMeasurement = ctx.measur
eText(dispString).width; | |
2862 var MaxRadiusX = Math.abs((msr.a
vailableWidth / 2 - textMeasurement) / Math.cos(posAngle)) - config.inGraphDataP
addingRadius - 5; | |
2863 if (MaxRadiusX < doughnutRadius)
doughnutRadius = MaxRadiusX; | |
2864 } | |
2865 } | |
2866 } | |
2867 doughnutRadius = doughnutRadius * config.radiusScale; | |
2868 }; | |
2869 }; | |
2870 var Line = function(data, config, ctx) { | |
2871 var maxSize, scaleHop, scaleHop2, calculatedScale, calculatedSca
le2, labelHeight, scaleHeight, valueBounds, labelTemplateString, labelTemplateSt
ring2; | |
2872 var valueHop, widestXLabel, xAxisLength, yAxisPosX, xAxisPosY, r
otateLabels = 0, | |
2873 msr; | |
2874 var zeroY = 0; | |
2875 var zeroY2 = 0; | |
2876 var offsets = []; | |
2877 ctx.tpchart="Line"; | |
2878 setting_new_chart_vars(ctx); | |
2879 if (!dynamicFunction(data, config, ctx)) { | |
2880 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
2881 return; | |
2882 } | |
2883 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
2884 if(!config.multiGraph) { | |
2885 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
2886 subUpdateChart(ctx,data,config); | |
2887 return; | |
2888 } else { ctx.firstPass=1; } | |
2889 } | |
2890 | |
2891 // adapt data when length is 1; | |
2892 var mxlgt = 0; | |
2893 for (var i = 0; i < data.datasets.length; i++) mxlgt = Max([mxlg
t, data.datasets[i].data.length]); | |
2894 if (mxlgt == 1) { | |
2895 if (typeof(data.labels[0]) == "string") data.labels = ["
", data.labels[0], ""]; | |
2896 for (var i = 0; i < data.datasets.length; i++) { | |
2897 if (typeof(data.datasets[i].data[0] != "undefine
d")) data.datasets[i].data = [undefined, data.datasets[i].data[0], undefined]; | |
2898 } | |
2899 } | |
2900 | |
2901 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
2902 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
2903 defMouse(ctx, data, config); | |
2904 setRect(ctx, config); | |
2905 msr = setMeasures(data, config, ctx, height, width, "nihil", [""
], false, false, true, true, config.datasetFill, "Line"); | |
2906 valueBounds = getValueBounds(); | |
2907 // true or fuzzy (error for negativ values (included 0)) | |
2908 if (config.logarithmic !== false) { | |
2909 if (valueBounds.minValue <= 0) { | |
2910 config.logarithmic = false; | |
2911 } | |
2912 } | |
2913 if (config.logarithmic2 !== false) { | |
2914 if (valueBounds.minValue2 <= 0) { | |
2915 config.logarithmic2 = false; | |
2916 } | |
2917 } | |
2918 // Check if logarithmic is meanigful | |
2919 var OrderOfMagnitude = calculateOrderOfMagnitude(Math.pow(10, ca
lculateOrderOfMagnitude(valueBounds.maxValue) + 1)) - calculateOrderOfMagnitude(
Math.pow(10, calculateOrderOfMagnitude(valueBounds.minValue))); | |
2920 if ((config.logarithmic == 'fuzzy' && OrderOfMagnitude < 4) || c
onfig.scaleOverride) { | |
2921 config.logarithmic = false; | |
2922 } | |
2923 // Check if logarithmic is meanigful | |
2924 var OrderOfMagnitude2 = calculateOrderOfMagnitude(Math.pow(10, c
alculateOrderOfMagnitude(valueBounds.maxValue2) + 1)) - calculateOrderOfMagnitud
e(Math.pow(10, calculateOrderOfMagnitude(valueBounds.minValue2))); | |
2925 if ((config.logarithmic2 == 'fuzzy' && OrderOfMagnitude2 < 4) ||
config.scaleOverride2) { | |
2926 config.logarithmic2 = false; | |
2927 } | |
2928 //Check and set the scale | |
2929 labelTemplateString = (config.scaleShowLabels) ? config.scaleLab
el : ""; | |
2930 labelTemplateString2 = (config.scaleShowLabels2) ? config.scaleL
abel2 : ""; | |
2931 if (!config.scaleOverride) { | |
2932 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
2933 calculatedScale = calculateScale(1, config, valu
eBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minVal
ue, labelTemplateString); | |
2934 } | |
2935 } else { | |
2936 calculatedScale = { | |
2937 steps: config.scaleSteps, | |
2938 stepValue: config.scaleStepWidth, | |
2939 graphMin: config.scaleStartValue, | |
2940 graphMax: config.scaleStartValue + config.scaleS
teps * config.scaleStepWidth, | |
2941 labels: [] | |
2942 } | |
2943 populateLabels(1, config, labelTemplateString, calculate
dScale.labels, calculatedScale.steps, config.scaleStartValue, calculatedScale.gr
aphMax, config.scaleStepWidth); | |
2944 } | |
2945 | |
2946 if (valueBounds.dbAxis) { | |
2947 if (!config.scaleOverride2) { | |
2948 if(valueBounds.maxSteps>0 && valueBounds.minStep
s>0) { | |
2949 calculatedScale2 = calculateScale(2, con
fig, valueBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue2, valueBou
nds.minValue2, labelTemplateString); | |
2950 } | |
2951 } else { | |
2952 calculatedScale2 = { | |
2953 steps: config.scaleSteps2, | |
2954 stepValue: config.scaleStepWidth2, | |
2955 graphMin: config.scaleStartValue2, | |
2956 graphMax: config.scaleStartValue2 + conf
ig.scaleSteps2 * config.scaleStepWidth2, | |
2957 labels: [] | |
2958 } | |
2959 populateLabels(2, config, labelTemplateString2,
calculatedScale2.labels, calculatedScale2.steps, config.scaleStartValue2, calcul
atedScale2.graphMax, config.scaleStepWidth2); | |
2960 } | |
2961 } else { | |
2962 calculatedScale2 = { | |
2963 steps: 0, | |
2964 stepValue: 0, | |
2965 graphMin: 0, | |
2966 graphMax: 0, | |
2967 labels: null | |
2968 } | |
2969 } | |
2970 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
2971 msr = setMeasures(data, config, ctx, height, width, calc
ulatedScale.labels, calculatedScale2.labels, false, false, true, true, config.da
tasetFill, "Line"); | |
2972 var prevHeight=msr.availableHeight; | |
2973 msr.availableHeight = msr.availableHeight - config.scale
TickSizeBottom - config.scaleTickSizeTop; | |
2974 msr.availableWidth = msr.availableWidth - config.scaleTi
ckSizeLeft - config.scaleTickSizeRight; | |
2975 scaleHop = Math.floor(msr.availableHeight / calculatedSc
ale.steps); | |
2976 scaleHop2 = Math.floor(msr.availableHeight / calculatedS
cale2.steps); | |
2977 valueHop = Math.floor(msr.availableWidth / (data.labels.
length - 1)); | |
2978 if (valueHop == 0 || config.fullWidthGraph) valueHop = (
msr.availableWidth / (data.labels.length - 1)); | |
2979 msr.clrwidth = msr.clrwidth - (msr.availableWidth - (dat
a.labels.length - 1) * valueHop); | |
2980 msr.availableWidth = (data.labels.length - 1) * valueHop
; | |
2981 msr.availableHeight = (calculatedScale.steps) * scaleHop
; | |
2982 msr.xLabelPos+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
2983 msr.clrheight+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
2984 yAxisPosX = msr.leftNotUsableSize + config.scaleTickSize
Left; | |
2985 xAxisPosY = msr.topNotUsableSize + msr.availableHeight +
config.scaleTickSizeTop; | |
2986 drawLabels(); | |
2987 if (valueBounds.minValue < 0) { | |
2988 zeroY = calculateOffset(config.logarithmic, 0, c
alculatedScale, scaleHop); | |
2989 } | |
2990 if (valueBounds.minValue2 < 0) { | |
2991 zeroY2 = calculateOffset(config.logarithmic2, 0,
calculatedScale2, scaleHop2); | |
2992 } | |
2993 for (var i = 0; i < data.datasets.length; i++) { | |
2994 offsets[i] = []; | |
2995 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
2996 if (data.datasets[i].axis == 2) { | |
2997 offsets[i][j] = (calculateOffset
(config.logarithmic2, data.datasets[i].data[j], calculatedScale2, scaleHop2) - z
eroY2); | |
2998 } else { | |
2999 offsets[i][j] = (calculateOffset
(config.logarithmic, data.datasets[i].data[j], calculatedScale, scaleHop) - zero
Y); | |
3000 } | |
3001 } | |
3002 } | |
3003 animationLoop(config, drawScale, drawLines, ctx, msr.clr
x, msr.clry, msr.clrwidth, msr.clrheight, yAxisPosX + msr.availableWidth / 2, xA
xisPosY - msr.availableHeight / 2, yAxisPosX, xAxisPosY, data); | |
3004 } else { | |
3005 testRedraw(ctx,data,config); | |
3006 } | |
3007 | |
3008 | |
3009 function drawLines(animPc) { | |
3010 drawLinesDataset(1, animPc, data, config, ctx, offsets,
{ | |
3011 xAxisPosY: xAxisPosY, | |
3012 yAxisPosX: yAxisPosX, | |
3013 valueHop: valueHop, | |
3014 nbValueHop: data.labels.length - 1, | |
3015 scaleHop: scaleHop, | |
3016 zeroY: zeroY, | |
3017 calculatedScale: calculatedScale, | |
3018 logarithmic: config.logarithmic | |
3019 }); | |
3020 drawLinesDataset(2, animPc, data, config, ctx, offsets,
{ | |
3021 xAxisPosY: xAxisPosY, | |
3022 yAxisPosX: yAxisPosX, | |
3023 valueHop: valueHop, | |
3024 nbValueHop: data.labels.length - 1, | |
3025 scaleHop: scaleHop2, | |
3026 zeroY: zeroY2, | |
3027 calculatedScale: calculatedScale2, | |
3028 logarithmic: config.logarithmic2 | |
3029 }); | |
3030 | |
3031 | |
3032 if (animPc >= 1) { | |
3033 if (typeof drawMath == "function") { | |
3034 drawMath(ctx, config, data, msr, { | |
3035 xAxisPosY: xAxisPosY, | |
3036 yAxisPosX: yAxisPosX, | |
3037 valueHop: valueHop, | |
3038 scaleHop: scaleHop, | |
3039 zeroY: zeroY, | |
3040 calculatedScale: calculatedScale
, | |
3041 calculateOffset: calculateOffset | |
3042 }); | |
3043 } | |
3044 } | |
3045 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"Line"); | |
3046 }; | |
3047 | |
3048 function drawScale() { | |
3049 //X axis line | |
3050 // if the xScale should be drawn | |
3051 if (config.drawXScaleLine !== false) { | |
3052 for (var s = 0; s < config.drawXScaleLine.length
; s++) { | |
3053 // get special lineWidth and lineColor f
or this xScaleLine | |
3054 ctx.lineWidth = config.drawXScaleLine[s]
.lineWidth ? config.drawXScaleLine[s].lineWidth : config.scaleLineWidth; | |
3055 ctx.strokeStyle = config.drawXScaleLine[
s].lineColor ? config.drawXScaleLine[s].lineColor : config.scaleLineColor; | |
3056 ctx.beginPath(); | |
3057 var yPosXScale; | |
3058 switch (config.drawXScaleLine[s].positio
n) { | |
3059 case "bottom": | |
3060 yPosXScale = xAxisPosY; | |
3061 break; | |
3062 case "top": | |
3063 yPosXScale = xAxisPosY -
msr.availableHeight - config.scaleTickSizeTop; | |
3064 break; | |
3065 case "0": | |
3066 case 0: | |
3067 // check if zero exists | |
3068 if (zeroY != 0) { | |
3069 yPosXScale = xAx
isPosY - zeroY; | |
3070 } | |
3071 break; | |
3072 } | |
3073 // draw the scale line | |
3074 ctx.moveTo(yAxisPosX - config.scaleTickS
izeLeft, yPosXScale); | |
3075 ctx.lineTo(yAxisPosX + msr.availableWidt
h + config.scaleTickSizeRight, yPosXScale); | |
3076 ctx.stroke(); | |
3077 } | |
3078 } | |
3079 for (var i = 0; i < data.labels.length; i++) { | |
3080 ctx.beginPath(); | |
3081 ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY +
config.scaleTickSizeBottom); | |
3082 ctx.lineWidth = config.scaleGridLineWidth; | |
3083 ctx.strokeStyle = config.scaleGridLineColor; | |
3084 //Check i isnt 0, so we dont go over the Y axis
twice. | |
3085 if (config.scaleShowGridLines && i > 0 && i % co
nfig.scaleXGridLinesStep == 0) { | |
3086 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY - msr.availableHeight - config.scaleTickSizeTop); | |
3087 } else { | |
3088 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY); | |
3089 } | |
3090 ctx.stroke(); | |
3091 } | |
3092 //Y axis | |
3093 ctx.lineWidth = config.scaleLineWidth; | |
3094 ctx.strokeStyle = config.scaleLineColor; | |
3095 ctx.beginPath(); | |
3096 ctx.moveTo(yAxisPosX, xAxisPosY + config.scaleTickSizeBo
ttom); | |
3097 ctx.lineTo(yAxisPosX, xAxisPosY - msr.availableHeight -
config.scaleTickSizeTop); | |
3098 ctx.stroke(); | |
3099 for (var j = 0; j < calculatedScale.steps; j++) { | |
3100 ctx.beginPath(); | |
3101 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft,
xAxisPosY - ((j + 1) * scaleHop)); | |
3102 ctx.lineWidth = config.scaleGridLineWidth; | |
3103 ctx.strokeStyle = config.scaleGridLineColor; | |
3104 if (config.scaleShowGridLines && j % config.scal
eYGridLinesStep == 0) { | |
3105 ctx.lineTo(yAxisPosX + msr.availableWidt
h + config.scaleTickSizeRight, xAxisPosY - ((j + 1) * scaleHop)); | |
3106 } else { | |
3107 ctx.lineTo(yAxisPosX, xAxisPosY - ((j +
1) * scaleHop)); | |
3108 } | |
3109 ctx.stroke(); | |
3110 } | |
3111 }; | |
3112 | |
3113 function drawLabels() { | |
3114 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
3115 //X Labels | |
3116 if (config.xAxisTop || config.xAxisBottom) { | |
3117 ctx.textBaseline = "top"; | |
3118 if (msr.rotateLabels > 90) { | |
3119 ctx.save(); | |
3120 ctx.textAlign = "left"; | |
3121 } else if (msr.rotateLabels > 0) { | |
3122 ctx.save(); | |
3123 ctx.textAlign = "right"; | |
3124 } else { | |
3125 ctx.textAlign = "center"; | |
3126 } | |
3127 ctx.fillStyle = config.scaleFontColor; | |
3128 if (config.xAxisBottom) { | |
3129 for (var i = 0; i < data.labels.length;
i++) { | |
3130 ctx.save(); | |
3131 if (msr.rotateLabels > 0) { | |
3132 ctx.translate(yAxisPosX
+ i * valueHop - msr.highestXLabel / 2, msr.xLabelPos); | |
3133 ctx.rotate(-(msr.rotateL
abels * (Math.PI / 180))); | |
3134 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), 0, 0, ctx.textBaseline, conf
ig.scaleFontSize); | |
3135 } else { | |
3136 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), yAxisPosX + i * valueHop, ms
r.xLabelPos, ctx.textBaseline, config.scaleFontSize); | |
3137 } | |
3138 ctx.restore(); | |
3139 } | |
3140 } | |
3141 } | |
3142 //Y Labels | |
3143 ctx.textAlign = "right"; | |
3144 ctx.textBaseline = "middle"; | |
3145 for (var j = ((config.showYAxisMin) ? -1 : 0); j < calcu
latedScale.steps; j++) { | |
3146 if (config.scaleShowLabels) { | |
3147 if (config.yAxisLeft) { | |
3148 ctx.textAlign = "right"; | |
3149 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX - (config.scaleTickSizeLeft + config.yAxisSpaceRi
ght), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline, config.scaleFontSize); | |
3150 } | |
3151 if (config.yAxisRight && !valueBounds.db
Axis) { | |
3152 ctx.textAlign = "left"; | |
3153 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX + msr.availableWidth + (config.scaleTickSizeRight
+ config.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline,
config.scaleFontSize); | |
3154 } | |
3155 } | |
3156 } | |
3157 if (config.yAxisRight && valueBounds.dbAxis) { | |
3158 for (var j = ((config.showYAxisMin) ? -1 : 0); j
< calculatedScale2.steps; j++) { | |
3159 if (config.scaleShowLabels) { | |
3160 ctx.textAlign = "left"; | |
3161 ctx.fillTextMultiLine(calculated
Scale2.labels[j + 1], yAxisPosX + msr.availableWidth + (config.scaleTickSizeRigh
t + config.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop2), ctx.textBaseline
, config.scaleFontSize); | |
3162 } | |
3163 } | |
3164 } | |
3165 }; | |
3166 | |
3167 function getValueBounds() { | |
3168 var upperValue = Number.MIN_VALUE; | |
3169 var lowerValue = Number.MAX_VALUE; | |
3170 var upperValue2 = Number.MIN_VALUE; | |
3171 var lowerValue2 = Number.MAX_VALUE; | |
3172 var secondAxis = false; | |
3173 var firstAxis = false; | |
3174 for (var i = 0; i < data.datasets.length; i++) { | |
3175 var mathFctName = data.datasets[i].drawMathDevia
tion; | |
3176 var mathValueHeight = 0; | |
3177 if (typeof eval(mathFctName) == "function") { | |
3178 var parameter = { | |
3179 data: data, | |
3180 datasetNr: i | |
3181 }; | |
3182 mathValueHeight = window[mathFctName](pa
rameter); | |
3183 } | |
3184 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3185 if (data.datasets[i].axis == 2) { | |
3186 secondAxis = true; | |
3187 if (1 * data.datasets[i].data[j]
+ mathValueHeight > upperValue2) { | |
3188 upperValue2 = 1 * data.d
atasets[i].data[j] + mathValueHeight | |
3189 }; | |
3190 if (1 * data.datasets[i].data[j]
- mathValueHeight < lowerValue2) { | |
3191 lowerValue2 = 1 * data.d
atasets[i].data[j] - mathValueHeight | |
3192 }; | |
3193 } else { | |
3194 firstAxis = true; | |
3195 if (1 * data.datasets[i].data[j]
+ mathValueHeight > upperValue) { | |
3196 upperValue = 1 * data.da
tasets[i].data[j] + mathValueHeight | |
3197 }; | |
3198 if (1 * data.datasets[i].data[j]
- mathValueHeight < lowerValue) { | |
3199 lowerValue = 1 * data.da
tasets[i].data[j] - mathValueHeight | |
3200 }; | |
3201 } | |
3202 } | |
3203 }; | |
3204 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
3205 upperValue = Max([upperValue * 2, 1]); | |
3206 lowerValue = 0; | |
3207 } | |
3208 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
3209 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
3210 if (secondAxis) { | |
3211 if (Math.abs(upperValue2 - lowerValue2) < 0.0000
0001) { | |
3212 upperValue2 = Max([upperValue2 * 2, 1]); | |
3213 lowerValue2 = 0; | |
3214 } | |
3215 if (!isNaN(config.graphMin2)) lowerValue2 = conf
ig.graphMin2; | |
3216 if (!isNaN(config.graphMax2)) upperValue2 = conf
ig.graphMax2; | |
3217 } | |
3218 if (!firstAxis && secondAxis) { | |
3219 upperValue = upperValue2; | |
3220 lowerValue = lowerValue2; | |
3221 } | |
3222 labelHeight = config.scaleFontSize; | |
3223 scaleHeight = msr.availableHeight; | |
3224 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
3225 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
3226 return { | |
3227 maxValue: upperValue, | |
3228 minValue: lowerValue, | |
3229 maxValue2: upperValue2, | |
3230 minValue2: lowerValue2, | |
3231 dbAxis: secondAxis, | |
3232 maxSteps: maxSteps, | |
3233 minSteps: minSteps | |
3234 }; | |
3235 }; | |
3236 }; | |
3237 var StackedBar = function(data, config, ctx) { | |
3238 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, valueHop, widestXLabel, xAxisLength, yAxisPo
sX, xAxisPosY, barWidth, rotateLabels = 0, | |
3239 msr; | |
3240 ctx.tpchart="StackedBar"; | |
3241 setting_new_chart_vars(ctx); | |
3242 if (!dynamicFunction(data, config, ctx)) { | |
3243 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
3244 return; | |
3245 } | |
3246 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
3247 if(!config.multiGraph) { | |
3248 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
3249 subUpdateChart(ctx,data,config); | |
3250 return; | |
3251 } else { ctx.firstPass=1; } | |
3252 } | |
3253 | |
3254 config.logarithmic = false; | |
3255 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
3256 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
3257 defMouse(ctx, data, config); | |
3258 setRect(ctx, config); | |
3259 msr = setMeasures(data, config, ctx, height, width, "nihil", [""
], true, false, true, true, true, "StackedBar"); | |
3260 valueBounds = getValueBounds(); | |
3261 | |
3262 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
3263 //Check and set the scale | |
3264 labelTemplateString = (config.scaleShowLabels) ? config.
scaleLabel : ""; | |
3265 if (!config.scaleOverride) { | |
3266 calculatedScale = calculateScale(1, config, valu
eBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minVal
ue, labelTemplateString); | |
3267 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, false, true, true, true, "StackedBar"); | |
3268 } else { | |
3269 calculatedScale = { | |
3270 steps: config.scaleSteps, | |
3271 stepValue: config.scaleStepWidth, | |
3272 graphMin: config.scaleStartValue, | |
3273 labels: [] | |
3274 } | |
3275 for (var i = 0; i <= calculatedScale.steps; i++)
{ | |
3276 if (labelTemplateString) { | |
3277 calculatedScale.labels.push(tmpl
(labelTemplateString, { | |
3278 value: fmtChartJS(config
, 1 * ((config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimal
Places(config.scaleStepWidth))), config.fmtYLabel) | |
3279 })); | |
3280 } | |
3281 } | |
3282 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, false, true, true, true, "StackedBar"); | |
3283 } | |
3284 | |
3285 var prevHeight=msr.availableHeight; | |
3286 | |
3287 msr.availableHeight = msr.availableHeight - config.scale
TickSizeBottom - config.scaleTickSizeTop; | |
3288 msr.availableWidth = msr.availableWidth - config.scaleTi
ckSizeLeft - config.scaleTickSizeRight; | |
3289 scaleHop = Math.floor(msr.availableHeight / calculatedSc
ale.steps); | |
3290 valueHop = Math.floor(msr.availableWidth / (data.labels.
length)); | |
3291 if (valueHop == 0 || config.fullWidthGraph) valueHop = (
msr.availableWidth / data.labels.length); | |
3292 msr.clrwidth = msr.clrwidth - (msr.availableWidth - ((da
ta.labels.length) * valueHop)); | |
3293 msr.availableWidth = (data.labels.length) * valueHop; | |
3294 msr.availableHeight = (calculatedScale.steps) * scaleHop
; | |
3295 msr.xLabelPos+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
3296 msr.clrheight+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
3297 | |
3298 yAxisPosX = msr.leftNotUsableSize + config.scaleTickSize
Left; | |
3299 xAxisPosY = msr.topNotUsableSize + msr.availableHeight +
config.scaleTickSizeTop; | |
3300 barWidth = (valueHop - config.scaleGridLineWidth * 2 - (
config.barValueSpacing * 2) - (config.barDatasetSpacing * data.datasets.length -
1) - (config.barStrokeWidth / 2) - 1); | |
3301 if(barWidth>=0 && barWidth<=1)barWidth=1; | |
3302 if(barWidth<0 && barWidth>=-1)barWidth=-1; | |
3303 | |
3304 drawLabels(); | |
3305 animationLoop(config, drawScale, drawBars, ctx, msr.clrx
, msr.clry, msr.clrwidth, msr.clrheight, yAxisPosX + msr.availableWidth / 2, xAx
isPosY - msr.availableHeight / 2, yAxisPosX, xAxisPosY, data); | |
3306 } else { | |
3307 testRedraw(ctx,data,config); | |
3308 } | |
3309 function drawBars(animPc) { | |
3310 ctx.lineWidth = config.barStrokeWidth; | |
3311 var tempp = new Array(data.datasets.length); | |
3312 var tempn = new Array(data.datasets.length); | |
3313 var cumvalue = new Array(); | |
3314 var totvalue = new Array(); | |
3315 for (var i = 0; i < data.datasets.length; i++) { | |
3316 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3317 cumvalue[j] = 0; | |
3318 totvalue[j] = 0; | |
3319 } | |
3320 } | |
3321 for (var i = 0; i < data.datasets.length; i++) { | |
3322 for (var j = 0; j < data.datasets[i].data.length
; j++) | |
3323 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
3324 totvalue[j] += 1 * data.datasets
[i].data[j]; | |
3325 } | |
3326 } | |
3327 for (var i = 0; i < data.datasets.length; i++) { | |
3328 if (animPc >= 1) { | |
3329 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
3330 else lgtxt = ""; | |
3331 } | |
3332 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3333 var currentAnimPc = animationCorrection(
animPc, data, config, i, j, 1).animVal; | |
3334 if (currentAnimPc > 1) currentAnimPc = c
urrentAnimPc - 1; | |
3335 if (i == 0) { | |
3336 tempp[j]=0; | |
3337 tempn[j]=0; | |
3338 zeroY= calculateOffset(config.l
ogarithmic, 0 , calculatedScale, scaleHop); | |
3339 } | |
3340 var barOffset = yAxisPosX + config.barVa
lueSpacing + valueHop * j; | |
3341 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined') && 1*data.datasets[i].data[j] != 0 ) { | |
3342 if (1*data.datasets[i].data[j]<0
) { | |
3343 var botval=tempp[j]; | |
3344 var topval=tempp[j]+1*da
ta.datasets[i].data[j] ; | |
3345 } else { | |
3346 var botval=tempn[j]; | |
3347 var topval=tempn[j]+1*da
ta.datasets[i].data[j] ; | |
3348 } | |
3349 if(config.animationByDataset) { | |
3350 var botBar=xAxisPosY - c
alculateOffset(config.logarithmic, botval , calculatedScale, scaleHop); | |
3351 var topBar=xAxisPosY -
calculateOffset(config.logarithmic, topval , calculatedScale, scaleHop); | |
3352 topBar=botBar+currentAni
mPc*(topBar-botBar); | |
3353 } else { | |
3354 var botBar=xAxisPosY -
calculateOffset(config.logarithmic, currentAnimPc* botval , calculatedScale, sca
leHop); | |
3355 var topBar=xAxisPosY -
calculateOffset(config.logarithmic, currentAnimPc*topval , calculatedScale, scal
eHop); | |
3356 | |
3357 } | |
3358 ctx.fillStyle = config.defaultFi
llColor; | |
3359 if (typeof data.datasets[i].fill
Color == "function") ctx.fillStyle = data.datasets[i].fillColor("FILLCOLOR", dat
a, config, i, j, currentAnimPc, 1 * data.datasets[i].data[j], "StackedBar", ctx,
barOffset, botBar , barOffset + barWidth, topBar); | |
3360 else if (typeof(data.datasets[i]
.fillColor) == "string") { | |
3361 ctx.fillStyle = data.dat
asets[i].fillColor; | |
3362 } else if (typeof(data.datasets[
i].fillColor) == "object") { | |
3363 if (typeof(data.datasets
[i].fillColor[0]) == "string") { | |
3364 ctx.fillStyle =
data.datasets[i].fillColor[Min([data.datasets[i].fillColor.length - 1, j])]; | |
3365 } | |
3366 } | |
3367 ctx.strokeStyle = config.default
StrokeColor; | |
3368 if (typeof data.datasets[i].stro
keColor == "function") ctx.strokeStyle = data.datasets[i].strokeColor("STROKECOL
OR", data, config, i, j, currentAnimPc, 1 * data.datasets[i].data[j], "StackedBa
r", ctx, barOffset, botBar, barOffset + barwidth, topBar); | |
3369 else if (typeof(data.datasets[i]
.strokeColor) == "string") { | |
3370 ctx.strokeStyle = data.d
atasets[i].strokeColor; | |
3371 } else if (typeof(data.datasets[
i].strokeColor) == "object") { | |
3372 if (typeof(data.datasets
[i].strokeColor[0]) == "string") { | |
3373 ctx.strokeStyle
= data.datasets[i].strokeColor[Min([data.datasets[i].strokeColor.length - 1, j])
]; | |
3374 } | |
3375 } | |
3376 | |
3377 if(currentAnimPc !=0) { | |
3378 ctx.beginPath(); | |
3379 ctx.moveTo(barOffset, bo
tBar); | |
3380 ctx.lineTo(barOffset, to
pBar); | |
3381 ctx.lineTo(barOffset + b
arWidth, topBar); | |
3382 ctx.lineTo(barOffset + b
arWidth, botBar); | |
3383 if (config.barShowStroke
) ctx.stroke(); | |
3384 ctx.closePath(); | |
3385 ctx.fill(); | |
3386 cumvalue[j] += 1 * data.
datasets[i].data[j]; | |
3387 if (animPc >= 1) { | |
3388 if (typeof(data.
labels[j]) == "string") lgtxt2 = data.labels[j].trim(); | |
3389 else lgtxt2 = ""
; | |
3390 // jsGraphAnnotate[
ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", barOffset, xA
xisPosY - yStart[j] + 1, barOffset + barWidth, barheight , lgtxt, lgtxt2, 1 * da
ta.datasets[i].data[j], cumvalue[j], totvalue[j], i, j]; | |
3391 if (1*data.datas
ets[i].data[j]<0) { | |
3392 jsGraphA
nnotate[ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", barOf
fset, topBar, barOffset + barWidth, botBar , lgtxt, lgtxt2, 1 * data.datasets[i]
.data[j], cumvalue[j], totvalue[j], i, j]; | |
3393 } else { | |
3394 jsGraphA
nnotate[ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", barOf
fset, botBar, barOffset + barWidth, topBar , lgtxt, lgtxt2, 1 * data.datasets[i]
.data[j], cumvalue[j], totvalue[j], i, j]; | |
3395 } | |
3396 } | |
3397 } | |
3398 if (1*data.datasets[i].data[j]<0
) { | |
3399 tempp[j]=tempp[j]+1*data
.datasets[i].data[j] ; | |
3400 } else { | |
3401 tempn[j]=tempn[j]+1*data
.datasets[i].data[j] ; | |
3402 } | |
3403 } | |
3404 } | |
3405 } | |
3406 if (animPc >= 1 && config.inGraphDataShow) { | |
3407 var yPos = 0, | |
3408 xPos = 0; | |
3409 for (var i = 0; i < data.datasets.length; i++) { | |
3410 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
3411 cumvalue[j] = 0; | |
3412 } | |
3413 } | |
3414 for (var i = 0; i < data.datasets.length; i++) { | |
3415 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
3416 else lgtxt = ""; | |
3417 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
3418 if (i == 0) { | |
3419 tempp[j]=0; | |
3420 tempn[j]=0; | |
3421 zeroY= calculateOffset(
config.logarithmic, 0 , calculatedScale, scaleHop); | |
3422 } | |
3423 if (!(typeof(data.datasets[i].da
ta[j]) == 'undefined')) { | |
3424 if (1*data.datasets[i].d
ata[j]<0) { | |
3425 var botval=tempp
[j]; | |
3426 var topval=tempp
[j]+1*data.datasets[i].data[j] ; | |
3427 } else { | |
3428 var botval=tempn
[j]; | |
3429 var topval=tempn
[j]+1*data.datasets[i].data[j] ; | |
3430 } | |
3431 var botBar=xAxisPosY - c
alculateOffset(config.logarithmic, botval , calculatedScale, scaleHop); | |
3432 var topBar=xAxisPosY -
calculateOffset(config.logarithmic, topval , calculatedScale, scaleHop); | |
3433 ctx.save(); | |
3434 ctx.textAlign = config.i
nGraphDataAlign; | |
3435 ctx.textBaseline = confi
g.inGraphDataVAlign; | |
3436 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
3437 ctx.fillStyle = config.i
nGraphDataFontColor; | |
3438 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
3439 else lgtxt2 = ""; | |
3440 cumvalue[j] += 1 + data.
datasets[i].data[j]; | |
3441 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
3442 config: config, | |
3443 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
3444 v2: fmtChartJS(c
onfig, lgtxt2, config.fmtV2), | |
3445 v3: fmtChartJS(c
onfig, 1 * data.datasets[i].data[j], config.fmtV3), | |
3446 v4: fmtChartJS(c
onfig, cumvalue[j], config.fmtV4), | |
3447 v5: fmtChartJS(c
onfig, totvalue[j], config.fmtV5), | |
3448 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data.datasets[i].data[j] / totvalue[j]
, config.fmtV6), config.roundPct), | |
3449 v7: fmtChartJS(c
onfig, barOffset, config.fmtV7), | |
3450 v8: fmtChartJS(c
onfig, xAxisPosY, config.fmtV8), | |
3451 v9: fmtChartJS(c
onfig, barOffset + barWidth, config.fmtV9), | |
3452 v10: fmtChartJS(
config, xAxisPosY - calculateOffset(config.logarithmic, data.datasets[i].data[j]
, calculatedScale, scaleHop) + (config.barStrokeWidth / 2), config.fmtV10), | |
3453 v11: fmtChartJS(
config, i, config.fmtV11), | |
3454 v12: fmtChartJS(
config, j, config.fmtV12), | |
3455 data: data | |
3456 }); | |
3457 var barOffset = yAxisPos
X + config.barValueSpacing + valueHop * j; | |
3458 ctx.beginPath(); | |
3459 ctx.beginPath(); | |
3460 yPos = 0; | |
3461 xPos = 0; | |
3462 if (config.inGraphDataXP
osition == 1) { | |
3463 xPos = barOffset
+ config.inGraphDataPaddingX; | |
3464 } else if (config.inGrap
hDataXPosition == 2) { | |
3465 xPos = barOffset
+ barWidth / 2 + config.inGraphDataPaddingX; | |
3466 } else if (config.inGrap
hDataXPosition == 3) { | |
3467 xPos = barOffset
+ barWidth + config.inGraphDataPaddingX; | |
3468 } | |
3469 if (config.inGraphDataYP
osition == 1) { | |
3470 yPos = botBar -
config.inGraphDataPaddingY; | |
3471 } else if (config.inGrap
hDataYPosition == 2) { | |
3472 yPos = topBar -
(botbar-topbar)/2 - config.inGraphDataPaddingY; | |
3473 } else if (config.inGrap
hDataYPosition == 3) { | |
3474 yPos = topBar -
config.inGraphDataPaddingY; | |
3475 } | |
3476 if(yPos>msr.topNotUsable
Size) { | |
3477 ctx.translate(xP
os, yPos); | |
3478 ctx.rotate(confi
g.inGraphDataRotate * (Math.PI / 180)); | |
3479 ctx.fillTextMult
iLine(dispString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
3480 } | |
3481 ctx.restore(); | |
3482 if (1*data.datasets[i].d
ata[j]<0) { | |
3483 tempp[j]=tempp[j
]+1*data.datasets[i].data[j] ; | |
3484 } else { | |
3485 tempn[j]=tempn[j
]+1*data.datasets[i].data[j] ; | |
3486 } | |
3487 } | |
3488 } | |
3489 } | |
3490 } | |
3491 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"StackedBar"); | |
3492 }; | |
3493 | |
3494 function drawScale() { | |
3495 //X axis line
| |
3496 ctx.lineWidth = config.scaleLineWidth; | |
3497 ctx.strokeStyle = config.scaleLineColor; | |
3498 ctx.beginPath(); | |
3499 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft, xAxisPo
sY); | |
3500 ctx.lineTo(yAxisPosX + msr.availableWidth + config.scale
TickSizeRight, xAxisPosY); | |
3501 ctx.stroke(); | |
3502 for (var i = 0; i < data.labels.length; i++) { | |
3503 ctx.beginPath(); | |
3504 ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY +
config.scaleTickSizeBottom); | |
3505 ctx.lineWidth = config.scaleGridLineWidth; | |
3506 ctx.strokeStyle = config.scaleGridLineColor; | |
3507 //Check i isnt 0, so we dont go over the Y axis
twice. | |
3508 if (config.scaleShowGridLines && i > 0 && i % co
nfig.scaleXGridLinesStep == 0) { | |
3509 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY - msr.availableHeight - config.scaleTickSizeTop); | |
3510 } else { | |
3511 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY); | |
3512 } | |
3513 ctx.stroke(); | |
3514 } | |
3515 //Y axis | |
3516 ctx.lineWidth = config.scaleLineWidth; | |
3517 ctx.strokeStyle = config.scaleLineColor; | |
3518 ctx.beginPath(); | |
3519 ctx.moveTo(yAxisPosX, xAxisPosY + config.scaleTickSizeBo
ttom); | |
3520 ctx.lineTo(yAxisPosX, xAxisPosY - msr.availableHeight -
config.scaleTickSizeTop); | |
3521 ctx.stroke(); | |
3522 for (var j = ((config.showYAxisMin) ? -1 : 0); j < calcu
latedScale.steps; j++) { | |
3523 ctx.beginPath(); | |
3524 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft,
xAxisPosY - ((j + 1) * scaleHop)); | |
3525 ctx.lineWidth = config.scaleGridLineWidth; | |
3526 ctx.strokeStyle = config.scaleGridLineColor; | |
3527 if (config.scaleShowGridLines && j % config.scal
eYGridLinesStep == 0) { | |
3528 ctx.lineTo(yAxisPosX + msr.availableWidt
h + config.scaleTickSizeRight, xAxisPosY - ((j + 1) * scaleHop)); | |
3529 } else { | |
3530 ctx.lineTo(yAxisPosX, xAxisPosY - ((j +
1) * scaleHop)); | |
3531 } | |
3532 ctx.stroke(); | |
3533 } | |
3534 }; | |
3535 | |
3536 function drawLabels() { | |
3537 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
3538 //X axis labels
| |
3539 if (config.xAxisTop || config.xAxisBottom) { | |
3540 ctx.textBaseline = "top"; | |
3541 if (msr.rotateLabels > 90) { | |
3542 ctx.save(); | |
3543 ctx.textAlign = "left"; | |
3544 } else if (msr.rotateLabels > 0) { | |
3545 ctx.save(); | |
3546 ctx.textAlign = "right"; | |
3547 } else { | |
3548 ctx.textAlign = "center"; | |
3549 } | |
3550 ctx.fillStyle = config.scaleFontColor; | |
3551 if (config.xAxisBottom) { | |
3552 for (var i = 0; i < data.labels.length;
i++) { | |
3553 ctx.save(); | |
3554 if (msr.rotateLabels > 0) { | |
3555 ctx.translate(yAxisPosX
+ i * valueHop + (barWidth / 2) - msr.highestXLabel / 2, msr.xLabelPos); | |
3556 ctx.rotate(-(msr.rotateL
abels * (Math.PI / 180))); | |
3557 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), 0, 0, ctx.textBaseline, conf
ig.scaleFontSize); | |
3558 } else { | |
3559 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), yAxisPosX + i * valueHop + (
barWidth / 2), msr.xLabelPos, ctx.textBaseline, config.scaleFontSize); | |
3560 } | |
3561 ctx.restore(); | |
3562 } | |
3563 } | |
3564 } | |
3565 //Y axis | |
3566 ctx.textAlign = "right"; | |
3567 ctx.textBaseline = "middle"; | |
3568 for (var j = ((config.showYAxisMin) ? -1 : 0); j < calcu
latedScale.steps; j++) { | |
3569 if (config.scaleShowLabels) { | |
3570 if (config.yAxisLeft) { | |
3571 ctx.textAlign = "right"; | |
3572 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX - (config.scaleTickSizeLeft + config.yAxisSpaceRi
ght), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline, config.scaleFontSize); | |
3573 } | |
3574 if (config.yAxisRight) { | |
3575 ctx.textAlign = "left"; | |
3576 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX + msr.availableWidth + (config.scaleTickSizeRight
+ config.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline,
config.scaleFontSize); | |
3577 } | |
3578 } | |
3579 } | |
3580 }; | |
3581 | |
3582 function getValueBounds() { | |
3583 var upperValue = Number.MIN_VALUE; | |
3584 var lowerValue = Number.MAX_VALUE; | |
3585 var minvl = new Array(data.datasets.length); | |
3586 var maxvl = new Array(data.datasets.length); | |
3587 for (var i = 0; i < data.datasets.length; i++) { | |
3588 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3589 var k = i; | |
3590 var tempp = 0; | |
3591 var tempn = 0; | |
3592 if (!(typeof(data.datasets[0].data[j]) =
= 'undefined')) { | |
3593 if(1 * data.datasets[0].data[j]
> 0) { | |
3594 tempp += 1 * data.datase
ts[0].data[j]; | |
3595 if (tempp > upperValue)
{ | |
3596 upperValue = tem
pp; | |
3597 }; | |
3598 if (tempp < lowerValue)
{ | |
3599 lowerValue = tem
pp; | |
3600 }; | |
3601 } else { | |
3602 tempn += 1 * data.datase
ts[0].data[j]; | |
3603 if (tempn > upperValue)
{ | |
3604 upperValue = tem
pn; | |
3605 }; | |
3606 if (tempn < lowerValue)
{ | |
3607 lowerValue = tem
pn; | |
3608 }; | |
3609 } | |
3610 } | |
3611 while (k > 0) { //get max of stacked dat
a | |
3612 if (!(typeof(data.datasets[k].da
ta[j]) == 'undefined')) { | |
3613 if(1 * data.datasets[k].
data[j] > 0) { | |
3614 tempp += 1 * dat
a.datasets[k].data[j]; | |
3615 if (tempp > uppe
rValue) { | |
3616 upperVal
ue = tempp; | |
3617 }; | |
3618 if (tempp < lowe
rValue) { | |
3619 lowerVal
ue = tempp; | |
3620 }; | |
3621 } else { | |
3622 tempn += 1 * dat
a.datasets[k].data[j]; | |
3623 if (tempn > uppe
rValue) { | |
3624 upperVal
ue = tempn; | |
3625 }; | |
3626 if (tempn < lowe
rValue) { | |
3627 lowerVal
ue = tempn; | |
3628 }; | |
3629 } | |
3630 } | |
3631 k--; | |
3632 } | |
3633 } | |
3634 }; | |
3635 // AJOUT CHANGEMENT | |
3636 | |
3637 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
3638 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
3639 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
3640 upperValue = Max([upperValue * 2, 1]); | |
3641 lowerValue = 0; | |
3642 } | |
3643 labelHeight = config.scaleFontSize; | |
3644 scaleHeight = msr.availableHeight; | |
3645 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
3646 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
3647 return { | |
3648 maxValue: upperValue, | |
3649 minValue: lowerValue, | |
3650 maxSteps: maxSteps, | |
3651 minSteps: minSteps | |
3652 }; | |
3653 }; | |
3654 }; | |
3655 /** | |
3656 * Reverse the data structure for horizontal charts | |
3657 * - reverse labels and every array inside datasets | |
3658 * @param {object} data datasets and labels for the chart | |
3659 * @return return the reversed data | |
3660 */ | |
3661 function reverseData(data) { | |
3662 data.labels = data.labels.reverse(); | |
3663 for (var i = 0; i < data.datasets.length; i++) { | |
3664 for (var key in data.datasets[i]) { | |
3665 if (Array.isArray(data.datasets[i][key])) { | |
3666 data.datasets[i][key] = data.datasets[i]
[key].reverse(); | |
3667 } | |
3668 } | |
3669 } | |
3670 return data; | |
3671 } | |
3672 var HorizontalStackedBar = function(data, config, ctx) { | |
3673 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, valueHop, widestXLabel, xAxisLength, yAxisPo
sX, xAxisPosY, barWidth, rotateLabels = 0, | |
3674 msr; | |
3675 | |
3676 ctx.tpchart="HorizontalStackedBar"; | |
3677 setting_new_chart_vars(ctx); | |
3678 | |
3679 if (!dynamicFunction(data, config, ctx)) { | |
3680 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
3681 return; | |
3682 } | |
3683 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
3684 if(!config.multiGraph) { | |
3685 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
3686 subUpdateChart(ctx,data,config); | |
3687 return; | |
3688 } else { ctx.firstPass=1; } | |
3689 } | |
3690 | |
3691 if (config.reverseOrder && typeof ctx.reversed == "undefined") { | |
3692 ctx.reversed=true; | |
3693 data = reverseData(data); | |
3694 } | |
3695 | |
3696 | |
3697 config.logarithmic = false; | |
3698 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
3699 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
3700 defMouse(ctx, data, config); | |
3701 setRect(ctx, config); | |
3702 msr = setMeasures(data, config, ctx, height, width, "nihil", [""
], true, true, true, true, true, "HorizontalStackedBar"); | |
3703 valueBounds = getValueBounds(); | |
3704 | |
3705 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
3706 //Check and set the scale | |
3707 labelTemplateString = (config.scaleShowLabels) ? config.
scaleLabel : ""; | |
3708 if (!config.scaleOverride) { | |
3709 calculatedScale = calculateScale(1, config, valu
eBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minVal
ue, labelTemplateString); | |
3710 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, true, true, true, true, "HorizontalStack
edBar"); | |
3711 } else { | |
3712 calculatedScale = { | |
3713 steps: config.scaleSteps, | |
3714 stepValue: config.scaleStepWidth, | |
3715 graphMin: config.scaleStartValue, | |
3716 labels: [] | |
3717 } | |
3718 for (var i = 0; i <= calculatedScale.steps; i++)
{ | |
3719 if (labelTemplateString) { | |
3720 calculatedScale.labels.push(tmpl
(labelTemplateString, { | |
3721 value: fmtChartJS(config
, 1 * ((config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimal
Places(config.scaleStepWidth))), config.fmtYLabel) | |
3722 })); | |
3723 } | |
3724 } | |
3725 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, true, true, true, true, "HorizontalStack
edBar"); | |
3726 } | |
3727 msr.availableHeight = msr.availableHeight - config.scale
TickSizeBottom - config.scaleTickSizeTop; | |
3728 msr.availableWidth = msr.availableWidth - config.scaleTi
ckSizeLeft - config.scaleTickSizeRight; | |
3729 scaleHop = Math.floor(msr.availableHeight / data.labels.
length); | |
3730 valueHop = Math.floor(msr.availableWidth / (calculatedSc
ale.steps)); | |
3731 if (valueHop == 0 || config.fullWidthGraph) valueHop = (
msr.availableWidth / (calculatedScale.steps)); | |
3732 msr.clrwidth = msr.clrwidth - (msr.availableWidth - (cal
culatedScale.steps * valueHop)); | |
3733 msr.availableWidth = (calculatedScale.steps) * valueHop; | |
3734 msr.availableHeight = (data.labels.length) * scaleHop; | |
3735 yAxisPosX = msr.leftNotUsableSize + config.scaleTickSize
Left; | |
3736 xAxisPosY = msr.topNotUsableSize + msr.availableHeight +
config.scaleTickSizeTop; | |
3737 barWidth = (scaleHop - config.scaleGridLineWidth * 2 - (
config.barValueSpacing * 2) - (config.barDatasetSpacing * data.datasets.length -
1) - (config.barStrokeWidth / 2) - 1); | |
3738 if(barWidth>=0 && barWidth<=1)barWidth=1; | |
3739 if(barWidth<0 && barWidth>=-1)barWidth=-1; | |
3740 drawLabels(); | |
3741 animationLoop(config, drawScale, drawBars, ctx, msr.clrx
, msr.clry, msr.clrwidth, msr.clrheight, yAxisPosX + msr.availableWidth / 2, xAx
isPosY - msr.availableHeight / 2, yAxisPosX, xAxisPosY, data); | |
3742 } else { | |
3743 testRedraw(ctx,data,config); | |
3744 } | |
3745 function HorizontalCalculateOffset(val, calculatedScale, scaleHo
p) { | |
3746 var outerValue = calculatedScale.steps * calculatedScale
.stepValue; | |
3747 var adjustedValue = val - calculatedScale.graphMin; | |
3748 var scalingFactor = CapValue(adjustedValue / outerValue,
1, 0); | |
3749 return (scaleHop * calculatedScale.steps) * scalingFacto
r; | |
3750 }; | |
3751 | |
3752 function drawBars(animPc) { | |
3753 ctx.lineWidth = config.barStrokeWidth; | |
3754 var tempp = new Array(data.datasets.length); | |
3755 var tempn = new Array(data.datasets.length); | |
3756 var cumvalue = new Array(); | |
3757 var totvalue = new Array(); | |
3758 for (var i = 0; i < data.datasets.length; i++) { | |
3759 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3760 cumvalue[j] = 0; | |
3761 totvalue[j] = 0; | |
3762 } | |
3763 } | |
3764 for (var i = 0; i < data.datasets.length; i++) { | |
3765 for (var j = 0; j < data.datasets[i].data.length
; j++) | |
3766 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
3767 totvalue[j] += 1 * data.datasets
[i].data[j]; | |
3768 } | |
3769 } | |
3770 for (var i = 0; i < data.datasets.length; i++) { | |
3771 if (animPc >= 1) { | |
3772 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
3773 else lgtxt = ""; | |
3774 } | |
3775 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
3776 var currentAnimPc = animationCorrection(
animPc, data, config, i, j, 1).animVal; | |
3777 if (currentAnimPc > 1) currentAnimPc = c
urrentAnimPc - 1; | |
3778 if (i == 0) { | |
3779 tempp[j]=0; | |
3780 tempn[j]=0; | |
3781 zeroY= HorizontalCalculateOffse
t(0 , calculatedScale, scaleHop); | |
3782 } | |
3783 var barOffset = xAxisPosY + config.barVa
lueSpacing - scaleHop * (j + 1); | |
3784 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined') && 1*data.datasets[i].data[j] != 0 ) { | |
3785 if (1*data.datasets[i].data[j]<0
) { | |
3786 var botval=tempp[j]; | |
3787 var topval=tempp[j]+1*da
ta.datasets[i].data[j] ; | |
3788 } else { | |
3789 var botval=tempn[j]; | |
3790 var topval=tempn[j]+1*da
ta.datasets[i].data[j] ; | |
3791 } | |
3792 if(config.animationByDataset) { | |
3793 var botBar=yAxisPosX + H
orizontalCalculateOffset(botval , calculatedScale, valueHop); | |
3794 var topBar=yAxisPosX + H
orizontalCalculateOffset(topval , calculatedScale, valueHop); | |
3795 topBar=botBar+currentAni
mPc*(topBar-botBar); | |
3796 } else { | |
3797 var botBar=yAxisPosX + H
orizontalCalculateOffset( currentAnimPc* botval , calculatedScale, valueHop); | |
3798 var topBar=yAxisPosX + H
orizontalCalculateOffset( currentAnimPc*topval , calculatedScale, valueHop); | |
3799 | |
3800 } | |
3801 ctx.fillStyle = config.defaultFi
llColor; | |
3802 if (typeof data.datasets[i].fill
Color == "function") ctx.fillStyle = data.datasets[i].fillColor("FILLCOLOR", dat
a, config, i, j, currentAnimPc, 1 * data.datasets[i].data[j], "HorizontalStacked
Bar", ctx, botBar, barOffset, topBar, barOffset + barWidth); | |
3803 else if (typeof(data.datasets[i]
.fillColor) == "string") { | |
3804 ctx.fillStyle = data.dat
asets[i].fillColor; | |
3805 } else if (typeof(data.datasets[
i].fillColor) == "object") { | |
3806 if (typeof(data.datasets
[i].fillColor[0]) == "string") { | |
3807 ctx.fillStyle =
data.datasets[i].fillColor[Min([data.datasets[i].fillColor.length - 1, j])]; | |
3808 } | |
3809 } | |
3810 ctx.strokeStyle = config.default
StrokeColor; | |
3811 if (typeof data.datasets[i].stro
keColor == "function") ctx.strokeStyle = data.datasets[i].strokeColor("STROKECOL
OR", data, config, i, j, currentAnimPc, 1 * data.datasets[i].data[j], ctx, "Hori
zontalStackedBar", ctx, botBar, barOffset, topBar, barOffset + barWidth); | |
3812 else if (typeof(data.datasets[i]
.strokeColor) == "string") { | |
3813 ctx.strokeStyle = data.d
atasets[i].strokeColor; | |
3814 } else if (typeof(data.datasets[
i].strokeColor) == "object") { | |
3815 if (typeof(data.datasets
[i].strokeColor[0]) == "string") { | |
3816 ctx.strokeStyle
= data.datasets[i].strokeColor[Min([data.datasets[i].strokeColor.length - 1, j])
]; | |
3817 } | |
3818 } | |
3819 if(currentAnimPc !=0) { | |
3820 ctx.beginPath(); | |
3821 ctx.moveTo(botBar, barOf
fset); | |
3822 ctx.lineTo(topBar, barOf
fset); | |
3823 ctx.lineTo(topBar, barOf
fset + barWidth); | |
3824 ctx.lineTo(botBar, barOf
fset + barWidth); | |
3825 ctx.lineTo(botBar, barOf
fset); | |
3826 if (config.barShowStroke
) ctx.stroke(); | |
3827 ctx.closePath(); | |
3828 ctx.fill(); | |
3829 cumvalue[j] += 1 * data.
datasets[i].data[j]; | |
3830 if (animPc >= 1) { | |
3831 if (typeof(data.
labels[j]) == "string") lgtxt2 = data.labels[j].trim(); | |
3832 else lgtxt2 = ""
; | |
3833 if (1*data.datas
ets[i].data[j]<0) { | |
3834 jsGraphA
nnotate[ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", topBa
r, barOffset + barWidth, botBar, barOffset, lgtxt, lgtxt2, 1 * data.datasets[i].
data[j], cumvalue[j], totvalue[j], i, j]; | |
3835 } else { | |
3836 jsGraphA
nnotate[ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", botBa
r, barOffset + barWidth, topBar, barOffset, lgtxt, lgtxt2, 1 * data.datasets[i].
data[j], cumvalue[j], totvalue[j], i, j]; | |
3837 } | |
3838 } | |
3839 } | |
3840 if (1*data.datasets[i].data[j]<0
) { | |
3841 tempp[j]=tempp[j]+1*data
.datasets[i].data[j] ; | |
3842 } else { | |
3843 tempn[j]=tempn[j]+1*data
.datasets[i].data[j] ; | |
3844 } | |
3845 } | |
3846 } | |
3847 } | |
3848 if (animPc >= 1 && config.inGraphDataShow) { | |
3849 var yPos = 0, | |
3850 xPos = 0; | |
3851 for (var i = 0; i < data.datasets.length; i++) { | |
3852 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
3853 cumvalue[j] = 0; | |
3854 } | |
3855 } | |
3856 for (var i = 0; i < data.datasets.length; i++) { | |
3857 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
3858 else lgtxt = ""; | |
3859 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
3860 if (i == 0) { | |
3861 tempp[j]=0; | |
3862 tempn[j]=0; | |
3863 zeroY= HorizontalCalcul
ateOffset(0 , calculatedScale, scaleHop); | |
3864 } | |
3865 if (!(typeof(data.datasets[i].da
ta[j]) == 'undefined')) { | |
3866 if (1*data.datasets[i].d
ata[j]<0) { | |
3867 var botval=tempp
[j]; | |
3868 var topval=tempp
[j]+1*data.datasets[i].data[j] ; | |
3869 } else { | |
3870 var botval=tempn
[j]; | |
3871 var topval=tempn
[j]+1*data.datasets[i].data[j] ; | |
3872 } | |
3873 var botBar=yAxisPosX + H
orizontalCalculateOffset(botval , calculatedScale, valueHop); | |
3874 var topBar=yAxisPosX + H
orizontalCalculateOffset(topval , calculatedScale, valueHop); | |
3875 ctx.save(); | |
3876 ctx.textAlign = config.i
nGraphDataAlign; | |
3877 ctx.textBaseline = confi
g.inGraphDataVAlign; | |
3878 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
3879 ctx.fillStyle = config.i
nGraphDataFontColor; | |
3880 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
3881 else lgtxt2 = ""; | |
3882 var barOffset = xAxisPos
Y + config.barValueSpacing - scaleHop * (j + 1); | |
3883 cumvalue[j] += data.data
sets[i].data[j]; | |
3884 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
3885 config: config, | |
3886 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
3887 v2: fmtChartJS(c
onfig, lgtxt2, config.fmtV2), | |
3888 v3: fmtChartJS(c
onfig, 1 * data.datasets[i].data[j], config.fmtV3), | |
3889 v4: fmtChartJS(c
onfig, cumvalue[j], config.fmtV4), | |
3890 v5: fmtChartJS(c
onfig, totvalue[j], config.fmtV5), | |
3891 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data.datasets[i].data[j] / totvalue[j]
, config.fmtV6), config.roundPct), | |
3892 v7: fmtChartJS(c
onfig, yAxisPosX, config.fmtV7), | |
3893 v8: fmtChartJS(c
onfig, barOffset + barWidth, config.fmtV8), | |
3894 v9: fmtChartJS(c
onfig, yAxisPosX + HorizontalCalculateOffset(data.datasets[i].data[j], calculate
dScale, valueHop) + (config.barStrokeWidth / 2), config.fmtV9), | |
3895 v10: fmtChartJS(
config, barOffset, config.fmtV10), | |
3896 v11: fmtChartJS(
config, i, config.fmtV11), | |
3897 v12: fmtChartJS(
config, j, config.fmtV12), | |
3898 data: data | |
3899 }); | |
3900 ctx.beginPath(); | |
3901 yPos = 0; | |
3902 xPos = 0; | |
3903 if (config.inGraphDataXP
osition == 1) { | |
3904 xPos = botBar +
config.inGraphDataPaddingX; | |
3905 } else if (config.inGrap
hDataXPosition == 2) { | |
3906 xPos = botBar +
(topBar-botBar)/2 + config.inGraphDataPaddingX; | |
3907 } else if (config.inGrap
hDataXPosition == 3) { | |
3908 xPos = topBar +
config.inGraphDataPaddingX; | |
3909 } | |
3910 if (config.inGraphDataYP
osition == 1) { | |
3911 yPos = barOffset
+ barWidth - config.inGraphDataPaddingY; | |
3912 } else if (config.inGrap
hDataYPosition == 2) { | |
3913 yPos = barOffset
+ barWidth / 2 - config.inGraphDataPaddingY; | |
3914 } else if (config.inGrap
hDataYPosition == 3) { | |
3915 yPos = barOffset
- config.inGraphDataPaddingY; | |
3916 } | |
3917 if(xPos<=msr.availableWi
dth+msr.leftNotUsableSize) { | |
3918 ctx.translate(xP
os, yPos); | |
3919 ctx.rotate(confi
g.inGraphDataRotate * (Math.PI / 180)); | |
3920 ctx.fillTextMult
iLine(dispString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
3921 ctx.restore(); | |
3922 } | |
3923 if (1*data.datasets[i].d
ata[j]<0) { | |
3924 tempp[j]=tempp[j
]+1*data.datasets[i].data[j] ; | |
3925 } else { | |
3926 tempn[j]=tempn[j
]+1*data.datasets[i].data[j] ; | |
3927 } | |
3928 } | |
3929 } | |
3930 } | |
3931 } | |
3932 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"HorizontalStackedBar"); | |
3933 }; | |
3934 | |
3935 function drawScale() { | |
3936 //X axis line
| |
3937 ctx.lineWidth = config.scaleLineWidth; | |
3938 ctx.strokeStyle = config.scaleLineColor; | |
3939 ctx.beginPath(); | |
3940 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft, xAxisPo
sY); | |
3941 ctx.lineTo(yAxisPosX + msr.availableWidth, xAxisPosY); | |
3942 ctx.stroke(); | |
3943 for (var i = ((config.showYAxisMin) ? -1 : 0); i < calcu
latedScale.steps; i++) { | |
3944 if (i >= 0) { | |
3945 ctx.beginPath(); | |
3946 ctx.moveTo(yAxisPosX + i * valueHop, xAx
isPosY + config.scaleTickSizeBottom); | |
3947 ctx.lineWidth = config.scaleGridLineWidt
h; | |
3948 ctx.strokeStyle = config.scaleGridLineCo
lor; | |
3949 //Check i isnt 0, so we dont go over the
Y axis twice. | |
3950 if (config.scaleShowGridLines && i > 0 &
& i % config.scaleXGridLinesStep == 0) { | |
3951 ctx.lineTo(yAxisPosX + i * value
Hop, xAxisPosY - msr.availableHeight - config.scaleTickSizeTop); | |
3952 } else { | |
3953 ctx.lineTo(yAxisPosX + i * value
Hop, xAxisPosY); | |
3954 } | |
3955 ctx.stroke(); | |
3956 } | |
3957 } | |
3958 //Y axis | |
3959 ctx.lineWidth = config.scaleLineWidth; | |
3960 ctx.strokeStyle = config.scaleLineColor; | |
3961 ctx.beginPath(); | |
3962 ctx.moveTo(yAxisPosX, xAxisPosY + config.scaleTickSizeBo
ttom); | |
3963 ctx.lineTo(yAxisPosX, xAxisPosY - msr.availableHeight -
config.scaleTickSizeTop); | |
3964 ctx.stroke(); | |
3965 for (var j = 0; j < data.labels.length; j++) { | |
3966 ctx.beginPath(); | |
3967 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft,
xAxisPosY - ((j + 1) * scaleHop)); | |
3968 ctx.lineWidth = config.scaleGridLineWidth; | |
3969 ctx.strokeStyle = config.scaleGridLineColor; | |
3970 if (config.scaleShowGridLines && j % config.scal
eYGridLinesStep == 0) { | |
3971 ctx.lineTo(yAxisPosX + msr.availableWidt
h, xAxisPosY - ((j + 1) * scaleHop)); | |
3972 } else { | |
3973 ctx.lineTo(yAxisPosX, xAxisPosY - ((j +
1) * scaleHop)); | |
3974 } | |
3975 ctx.stroke(); | |
3976 } | |
3977 }; | |
3978 | |
3979 function drawLabels() { | |
3980 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
3981 //X axis line
| |
3982 if (config.scaleShowLabels && (config.xAxisTop || config
.xAxisBottom)) { | |
3983 ctx.textBaseline = "top"; | |
3984 if (msr.rotateLabels > 90) { | |
3985 ctx.save(); | |
3986 ctx.textAlign = "left"; | |
3987 } else if (msr.rotateLabels > 0) { | |
3988 ctx.save(); | |
3989 ctx.textAlign = "right"; | |
3990 } else { | |
3991 ctx.textAlign = "center"; | |
3992 } | |
3993 ctx.fillStyle = config.scaleFontColor; | |
3994 if (config.xAxisBottom) { | |
3995 for (var i = ((config.showYAxisMin) ? -1
: 0); i < calculatedScale.steps; i++) { | |
3996 ctx.save(); | |
3997 if (msr.rotateLabels > 0) { | |
3998 ctx.translate(yAxisPosX
+ (i + 1) * valueHop - msr.highestXLabel / 2, msr.xLabelPos); | |
3999 ctx.rotate(-(msr.rotateL
abels * (Math.PI / 180))); | |
4000 ctx.fillTextMultiLine(ca
lculatedScale.labels[i + 1], 0, 0, ctx.textBaseline, config.scaleFontSize); | |
4001 } else { | |
4002 ctx.fillTextMultiLine(ca
lculatedScale.labels[i + 1], yAxisPosX + ((i + 1) * valueHop), msr.xLabelPos, ct
x.textBaseline, config.scaleFontSize); | |
4003 } | |
4004 ctx.restore(); | |
4005 } | |
4006 } | |
4007 } | |
4008 //Y axis | |
4009 ctx.textAlign = "right"; | |
4010 ctx.textBaseline = "middle"; | |
4011 for (var j = 0; j < data.labels.length; j++) { | |
4012 if (config.yAxisLeft) { | |
4013 ctx.textAlign = "right"; | |
4014 ctx.fillTextMultiLine(fmtChartJS(config,
data.labels[j], config.fmtXLabel), yAxisPosX - (config.scaleTickSizeLeft + conf
ig.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop) + barWidth / 2, ctx.textBa
seline, config.scaleFontSize); | |
4015 } | |
4016 if (config.yAxisRight) { | |
4017 ctx.textAlign = "left"; | |
4018 ctx.fillTextMultiLine(fmtChartJS(config,
data.labels[j], config.fmtXLabel), yAxisPosX + msr.availableWidth + (config.sca
leTickSizeRight + config.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop) + ba
rWidth / 2, ctx.textBaseline, config.scaleFontSize); | |
4019 } | |
4020 } | |
4021 }; | |
4022 | |
4023 function getValueBounds() { | |
4024 var upperValue = Number.MIN_VALUE; | |
4025 var lowerValue = Number.MAX_VALUE; | |
4026 var minvl = new Array(data.datasets.length); | |
4027 var maxvl = new Array(data.datasets.length); | |
4028 for (var i = 0; i < data.datasets.length; i++) { | |
4029 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4030 var k = i; | |
4031 var tempp = 0; | |
4032 var tempn = 0; | |
4033 if (!(typeof(data.datasets[0].data[j]) =
= 'undefined')) { | |
4034 if(1 * data.datasets[0].data[j]
> 0) { | |
4035 tempp += 1 * data.datase
ts[0].data[j]; | |
4036 if (tempp > upperValue)
{ | |
4037 upperValue = tem
pp; | |
4038 }; | |
4039 if (tempp < lowerValue)
{ | |
4040 lowerValue = tem
pp; | |
4041 }; | |
4042 } else { | |
4043 tempn += 1 * data.datase
ts[0].data[j]; | |
4044 if (tempn > upperValue)
{ | |
4045 upperValue = tem
pn; | |
4046 }; | |
4047 if (tempn < lowerValue)
{ | |
4048 lowerValue = tem
pn; | |
4049 }; | |
4050 } | |
4051 } | |
4052 while (k > 0) { //get max of stacked dat
a | |
4053 if (!(typeof(data.datasets[k].da
ta[j]) == 'undefined')) { | |
4054 if(1 * data.datasets[k].
data[j] > 0) { | |
4055 tempp += 1 * dat
a.datasets[k].data[j]; | |
4056 if (tempp > uppe
rValue) { | |
4057 upperVal
ue = tempp; | |
4058 }; | |
4059 if (tempp < lowe
rValue) { | |
4060 lowerVal
ue = tempp; | |
4061 }; | |
4062 } else { | |
4063 tempn += 1 * dat
a.datasets[k].data[j]; | |
4064 if (tempn > uppe
rValue) { | |
4065 upperVal
ue = tempn; | |
4066 }; | |
4067 if (tempn < lowe
rValue) { | |
4068 lowerVal
ue = tempn; | |
4069 }; | |
4070 } | |
4071 } | |
4072 k--; | |
4073 } | |
4074 } | |
4075 }; | |
4076 // AJOUT CHANGEMENT | |
4077 | |
4078 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
4079 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
4080 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
4081 upperValue = Max([upperValue * 2, 1]); | |
4082 lowerValue = 0; | |
4083 } | |
4084 labelHeight = config.scaleFontSize; | |
4085 scaleHeight = msr.availableHeight; | |
4086 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
4087 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
4088 return { | |
4089 maxValue: upperValue, | |
4090 minValue: lowerValue, | |
4091 maxSteps: maxSteps, | |
4092 minSteps: minSteps | |
4093 }; | |
4094 | |
4095 | |
4096 }; | |
4097 }; | |
4098 var Bar = function(data, config, ctx) { | |
4099 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, valueHop, widestXLabel, xAxisLength, yAxisPo
sX, xAxisPosY, barWidth, rotateLabels = 0, | |
4100 msr; | |
4101 var offsets = []; | |
4102 | |
4103 ctx.tpchart="Bar"; | |
4104 setting_new_chart_vars(ctx); | |
4105 | |
4106 if (!dynamicFunction(data, config, ctx)) { | |
4107 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
4108 return; | |
4109 } | |
4110 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
4111 if(!config.multiGraph) { | |
4112 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
4113 subUpdateChart(ctx,data,config); | |
4114 return; | |
4115 } else { ctx.firstPass=1; } | |
4116 } | |
4117 | |
4118 // for BarLineCharts | |
4119 var nrOfBars = data.datasets.length; | |
4120 var nrOfLines = 0; | |
4121 var lineDatasets = []; | |
4122 var barDatasets = []; | |
4123 for (var i = 0; i < data.datasets.length; i++) { | |
4124 if (data.datasets[i].type == "Line") { | |
4125 nrOfLines++; | |
4126 lineDatasets.push(i); | |
4127 } else { | |
4128 barDatasets.push(i); | |
4129 } | |
4130 } | |
4131 // change the order (at first all bars then the lines) (form of
BubbleSort) | |
4132 var bufferDataset, l = 0; | |
4133 for (var i = data.datasets.length - 1; i >= 0; i--) { | |
4134 if (lineDatasets.indexOf(i) >= 0) { | |
4135 l++; | |
4136 for (var b = i; b < data.datasets.length - l; b+
+) { | |
4137 bufferDataset = data.datasets[b + 1]; | |
4138 data.datasets[b + 1] = data.datasets[b]; | |
4139 data.datasets[b] = bufferDataset; | |
4140 } | |
4141 } | |
4142 } | |
4143 nrOfBars -= nrOfLines; | |
4144 | |
4145 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
4146 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
4147 defMouse(ctx, data, config); | |
4148 setRect(ctx, config); | |
4149 | |
4150 msr = setMeasures(data, config, ctx, height, width, "nihil", [""
], true, false, true, true, true, "Bar"); | |
4151 valueBounds = getValueBounds(); | |
4152 | |
4153 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
4154 | |
4155 // true or fuzzy (error for negativ values (included 0)) | |
4156 if (config.logarithmic !== false) { | |
4157 if (valueBounds.minValue <= 0) { | |
4158 config.logarithmic = false; | |
4159 } | |
4160 } | |
4161 // Check if logarithmic is meanigful | |
4162 var OrderOfMagnitude = calculateOrderOfMagnitude(Math.po
w(10, calculateOrderOfMagnitude(valueBounds.maxValue) + 1)) - calculateOrderOfMa
gnitude(Math.pow(10, calculateOrderOfMagnitude(valueBounds.minValue))); | |
4163 if ((config.logarithmic == 'fuzzy' && OrderOfMagnitude <
4) || config.scaleOverride) { | |
4164 config.logarithmic = false; | |
4165 } | |
4166 //Check and set the scale | |
4167 labelTemplateString = (config.scaleShowLabels) ? config.
scaleLabel : ""; | |
4168 if (!config.scaleOverride) { | |
4169 calculatedScale = calculateScale(1, config, valu
eBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minVal
ue, labelTemplateString); | |
4170 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, false, true, true, true, "Bar"); | |
4171 } else { | |
4172 calculatedScale = { | |
4173 steps: config.scaleSteps, | |
4174 stepValue: config.scaleStepWidth, | |
4175 graphMin: config.scaleStartValue, | |
4176 graphMax: config.scaleStartValue + confi
g.scaleSteps * config.scaleStepWidth, | |
4177 labels: [] | |
4178 } | |
4179 populateLabels(1, config, labelTemplateString, c
alculatedScale.labels, calculatedScale.steps, config.scaleStartValue, calculated
Scale.graphMax, config.scaleStepWidth); | |
4180 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, false, true, true, true, "Bar"); | |
4181 } | |
4182 | |
4183 var prevHeight=msr.availableHeight; | |
4184 | |
4185 | |
4186 | |
4187 msr.availableHeight = msr.availableHeight - config.scale
TickSizeBottom - config.scaleTickSizeTop; | |
4188 msr.availableWidth = msr.availableWidth - config.scaleTi
ckSizeLeft - config.scaleTickSizeRight; | |
4189 scaleHop = Math.floor(msr.availableHeight / calculatedSc
ale.steps); | |
4190 valueHop = Math.floor(msr.availableWidth / (data.labels.
length)); | |
4191 if (valueHop == 0 || config.fullWidthGraph) valueHop = (
msr.availableWidth / data.labels.length); | |
4192 msr.clrwidth = msr.clrwidth - (msr.availableWidth - ((da
ta.labels.length) * valueHop)); | |
4193 msr.availableWidth = (data.labels.length) * valueHop; | |
4194 msr.availableHeight = (calculatedScale.steps) * scaleHop
; | |
4195 msr.xLabelPos+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
4196 msr.clrheight+=(config.scaleTickSizeBottom + config.scal
eTickSizeTop - (prevHeight-msr.availableHeight)); | |
4197 | |
4198 yAxisPosX = msr.leftNotUsableSize + config.scaleTickSize
Left; | |
4199 xAxisPosY = msr.topNotUsableSize + msr.availableHeight +
config.scaleTickSizeTop; | |
4200 barWidth = (valueHop - config.scaleGridLineWidth * 2 - (
config.barValueSpacing * 2) - (config.barDatasetSpacing * nrOfBars - 1) - ((conf
ig.barStrokeWidth / 2) * nrOfBars - 1)) / nrOfBars; | |
4201 if(barWidth>=0 && barWidth<=1)barWidth=1; | |
4202 if(barWidth<0 && barWidth>=-1)barWidth=-1; | |
4203 var zeroY = 0; | |
4204 if (valueBounds.minValue < 0) { | |
4205 var zeroY = calculateOffset(config.logarithmic,
0, calculatedScale, scaleHop); | |
4206 } | |
4207 for (var i = 0; i < data.datasets.length; i++) { | |
4208 offsets[i] = []; | |
4209 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4210 offsets[i][j] = (calculateOffset(config.
logarithmic, data.datasets[i].data[j], calculatedScale, scaleHop) - zeroY); | |
4211 } | |
4212 } | |
4213 drawLabels(); | |
4214 animationLoop(config, drawScale, drawBars, ctx, msr.clrx
, msr.clry, msr.clrwidth, msr.clrheight, yAxisPosX + msr.availableWidth / 2, xAx
isPosY - msr.availableHeight / 2, yAxisPosX, xAxisPosY, data); | |
4215 } else { | |
4216 testRedraw(ctx,data,config); | |
4217 } | |
4218 function drawBars(animPc) { | |
4219 var t1, t2, t3; | |
4220 var cumvalue = new Array(); | |
4221 var totvalue = new Array(); | |
4222 for (var i = 0; i < data.datasets.length; i++) { | |
4223 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4224 cumvalue[j] = 0; | |
4225 totvalue[j] = 0; | |
4226 } | |
4227 } | |
4228 for (var i = 0; i < data.datasets.length; i++) { | |
4229 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4230 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
4231 totvalue[j] += 1 * data.datasets
[i].data[j]; | |
4232 } | |
4233 } | |
4234 } | |
4235 ctx.lineWidth = config.barStrokeWidth; | |
4236 for (var i = 0; i < data.datasets.length; i++) { | |
4237 if (data.datasets[i].type == "Line") { | |
4238 var lineData = { | |
4239 datasets: [], | |
4240 labels: data.labels | |
4241 }; | |
4242 lineData.datasets.push(data.datasets[i])
; | |
4243 lineConfig = mergeChartConfig(config, { | |
4244 datasetFill: data.datasets[i].fi
ll | |
4245 }); | |
4246 drawLinesDataset(1, animPc, lineData, li
neConfig, ctx, offsets, { | |
4247 xAxisPosY: xAxisPosY, | |
4248 yAxisPosX: yAxisPosX + config.ba
rValueSpacing + | |
4249 (barWidth + config.barDa
tasetSpacing / 2 + config.barStrokeWidth) * nrOfBars / 2, | |
4250 valueHop: valueHop, | |
4251 scaleHop: scaleHop, | |
4252 nbValueHop: data.labels.length, | |
4253 zeroY: zeroY, | |
4254 calculatedScale: calculatedScale
, | |
4255 logarithmic: config.logarithmic | |
4256 }); | |
4257 continue; // next dataset | |
4258 } | |
4259 if (animPc >= 1) { | |
4260 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
4261 else lgtxt = ""; | |
4262 } | |
4263 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4264 var currentAnimPc = animationCorrection(
animPc, data, config, i, j, 1).animVal; | |
4265 if (currentAnimPc > 1) currentAnimPc = c
urrentAnimPc - 1; | |
4266 var barOffset = yAxisPosX + config.barVa
lueSpacing + valueHop * j + barWidth * i + config.barDatasetSpacing * i + config
.barStrokeWidth * i; | |
4267 var barHeight = currentAnimPc * (calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, scal
eHop) - zeroY) + (config.barStrokeWidth / 2); | |
4268 ctx.fillStyle = config.defaultFillColor; | |
4269 if (typeof data.datasets[i].fillColor ==
"function") { | |
4270 ctx.fillStyle = data.datasets[i]
.fillColor("FILLCOLOR", data, config, i, j, currentAnimPc, 1 * data.datasets[i].
data[j], "Bar", ctx, barOffset, xAxisPosY - zeroY , barOffset + barWidth, xAxisP
osY - zeroY - barHeight); | |
4271 } else if (typeof(data.datasets[i].fillC
olor) == "string") { | |
4272 ctx.fillStyle = data.datasets[i]
.fillColor; | |
4273 } else if (typeof(data.datasets[i].fillC
olor) == "object") { | |
4274 if (typeof(data.datasets[i].fill
Color[0]) == "string") { | |
4275 ctx.fillStyle = data.dat
asets[i].fillColor[Min([data.datasets[i].fillColor.length - 1, j])]; | |
4276 } | |
4277 } | |
4278 ctx.strokeStyle = config.defaultStrokeCo
lor; | |
4279 if (typeof data.datasets[i].strokeColor
== "function") { | |
4280 ctx.strokeStyle = data.datasets[
i].strokeColor("STROKECOLOR", data, config, i, j, CurrentAnimPc, 1 * data.datase
ts[i].data[j], "Bar", ctx, barOffset, xAxisPosY - zeroY - barHeight, barOffset +
barWidth, xAxisPosY - zeroY); | |
4281 } else if (typeof(data.datasets[i].strok
eColor) == "string") { | |
4282 ctx.strokeStyle = data.datasets[
i].strokeColor; | |
4283 } else if (typeof(data.datasets[i].strok
eColor) == "object") { | |
4284 if (typeof(data.datasets[i].stro
keColor[0]) == "string") { | |
4285 ctx.strokeStyle = data.d
atasets[i].strokeColor[Min([data.datasets[i].strokeColor.length - 1, j])]; | |
4286 } | |
4287 } | |
4288 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
4289 roundRect(ctx, barOffset, xAxisP
osY - zeroY, barWidth, barHeight, config.barShowStroke, config.barBorderRadius); | |
4290 cumvalue[j] += 1 * data.datasets
[i].data[j]; | |
4291 if (animPc >= 1) { | |
4292 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
4293 else lgtxt2 = ""; | |
4294 t1 = xAxisPosY - zeroY; | |
4295 t2 = xAxisPosY - calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, scal
eHop) + (config.barStrokeWidth / 2); | |
4296 if (t1 < t2) { | |
4297 t3 = t1; | |
4298 t1 = t2; | |
4299 t2 = t3 | |
4300 } | |
4301 jsGraphAnnotate[ctx.Char
tNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", barOffset, t1, barOff
set + barWidth, t2, lgtxt, lgtxt2, | |
4302 1 * data.dataset
s[i].data[j], cumvalue[j], totvalue[j], i, j | |
4303 ]; | |
4304 } | |
4305 } | |
4306 } | |
4307 } | |
4308 if (animPc >= 1 && config.inGraphDataShow) { | |
4309 for (var i = 0; i < data.datasets.length; i++) { | |
4310 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
4311 cumvalue[j] = 0; | |
4312 } | |
4313 } | |
4314 for (var i = 0; i < data.datasets.length; i++) { | |
4315 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
4316 else lgtxt = ""; | |
4317 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
4318 if (data.datasets[i].type == "Li
ne") { // no inGraphDataShow for lines again (is inside drawLinesDataset) | |
4319 continue; | |
4320 } | |
4321 if (!(typeof(data.datasets[i].da
ta[j]) == 'undefined')) { | |
4322 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
4323 ctx.save(); | |
4324 ctx.textAlign = config.i
nGraphDataAlign; | |
4325 ctx.textBaseline = confi
g.inGraphDataVAlign; | |
4326 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
4327 ctx.fillStyle = config.i
nGraphDataFontColor; | |
4328 var barOffset = yAxisPos
X + config.barValueSpacing + valueHop * j + barWidth * i + config.barDatasetSpac
ing * i + config.barStrokeWidth * i; | |
4329 t1 = xAxisPosY - zeroY; | |
4330 t2 = xAxisPosY - calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, scal
eHop) + (config.barStrokeWidth / 2); | |
4331 ctx.beginPath(); | |
4332 var yPos = 0, | |
4333 xPos = 0; | |
4334 if (config.inGraphDataXP
osition == 1) { | |
4335 xPos = barOffset
+ config.inGraphDataPaddingX; | |
4336 } else if (config.inGrap
hDataXPosition == 2) { | |
4337 xPos = barOffset
+ barWidth / 2 + config.inGraphDataPaddingX; | |
4338 } else if (config.inGrap
hDataXPosition == 3) { | |
4339 xPos = barOffset
+ barWidth + config.inGraphDataPaddingX; | |
4340 } | |
4341 if (config.inGraphDataYP
osition == 1) { | |
4342 yPos = xAxisPosY
- zeroY - config.inGraphDataPaddingY; | |
4343 } else if (config.inGrap
hDataYPosition == 2) { | |
4344 yPos = xAxisPosY
- (calculateOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculated
Scale, scaleHop) + | |
4345 (config.
barStrokeWidth / 2)) / 2 - config.inGraphDataPaddingY; | |
4346 } else if (config.inGrap
hDataYPosition == 3) { | |
4347 yPos = xAxisPosY
- calculateOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedS
cale, scaleHop) + | |
4348 (config.
barStrokeWidth / 2) - config.inGraphDataPaddingY; | |
4349 } | |
4350 ctx.translate(xPos, yPos
); | |
4351 cumvalue[j] += 1 * data.
datasets[i].data[j]; | |
4352 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
4353 config: config, | |
4354 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
4355 v2: fmtChartJS(c
onfig, lgtxt2, config.fmtV2), | |
4356 v3: fmtChartJS(c
onfig, 1 * data.datasets[i].data[j], config.fmtV3), | |
4357 v4: fmtChartJS(c
onfig, cumvalue[j], config.fmtV4), | |
4358 v5: fmtChartJS(c
onfig, totvalue[j], config.fmtV5), | |
4359 v6: roundToWithT
housands(config, fmtChartJS(config, | |
4360 100 * da
ta.datasets[i].data[j] / totvalue[j], config.fmtV6), config.roundPct), | |
4361 v7: fmtChartJS(c
onfig, barOffset, config.fmtV7), | |
4362 v8: fmtChartJS(c
onfig, t1, config.fmtV8), | |
4363 v9: fmtChartJS(c
onfig, barOffset + barWidth, config.fmtV9), | |
4364 v10: fmtChartJS(
config, t2, config.fmtV10), | |
4365 v11: fmtChartJS(
config, i, config.fmtV11), | |
4366 v12: fmtChartJS(
config, j, config.fmtV12), | |
4367 data: data | |
4368 }); | |
4369 ctx.rotate(config.inGrap
hDataRotate * (Math.PI / 180)); | |
4370 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
4371 ctx.restore(); | |
4372 } | |
4373 } | |
4374 } | |
4375 } | |
4376 if (animPc >= 1) { | |
4377 if (typeof drawMath == "function") { | |
4378 drawMath(ctx, config, data, msr, { | |
4379 xAxisPosY: xAxisPosY, | |
4380 yAxisPosX: yAxisPosX, | |
4381 valueHop: valueHop, | |
4382 scaleHop: scaleHop, | |
4383 zeroY: zeroY, | |
4384 calculatedScale: calculatedScale
, | |
4385 calculateOffset: calculateOffset
, | |
4386 barWidth: barWidth | |
4387 }); | |
4388 } | |
4389 } | |
4390 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"Bar"); | |
4391 }; | |
4392 | |
4393 function roundRect(ctx, x, y, w, h, stroke, radius) { | |
4394 ctx.beginPath(); | |
4395 ctx.moveTo(x + radius, y); | |
4396 ctx.lineTo(x + w - radius, y); | |
4397 ctx.quadraticCurveTo(x + w, y, x + w, y); | |
4398 ctx.lineTo(x + w, y - h + radius); | |
4399 ctx.quadraticCurveTo(x + w, y - h, x + w - radius, y - h
); | |
4400 ctx.lineTo(x + radius, y - h); | |
4401 ctx.quadraticCurveTo(x, y - h, x, y - h + radius); | |
4402 ctx.lineTo(x, y); | |
4403 ctx.quadraticCurveTo(x, y, x + radius, y); | |
4404 if (stroke) ctx.stroke(); | |
4405 ctx.closePath(); | |
4406 ctx.fill(); | |
4407 }; | |
4408 | |
4409 function drawScale() { | |
4410 //X axis line
| |
4411 ctx.lineWidth = config.scaleLineWidth; | |
4412 ctx.strokeStyle = config.scaleLineColor; | |
4413 ctx.beginPath(); | |
4414 | |
4415 | |
4416 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft, xAxisPo
sY); | |
4417 ctx.lineTo(yAxisPosX + msr.availableWidth + config.scale
TickSizeRight, xAxisPosY); | |
4418 ctx.stroke(); | |
4419 for (var i = 0; i < data.labels.length; i++) { | |
4420 ctx.beginPath(); | |
4421 ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY +
config.scaleTickSizeBottom); | |
4422 ctx.lineWidth = config.scaleGridLineWidth; | |
4423 ctx.strokeStyle = config.scaleGridLineColor; | |
4424 //Check i isnt 0, so we dont go over the Y axis
twice. | |
4425 if (config.scaleShowGridLines && i > 0 && i % co
nfig.scaleXGridLinesStep == 0) { | |
4426 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY - msr.availableHeight - config.scaleTickSizeTop); | |
4427 } else { | |
4428 ctx.lineTo(yAxisPosX + i * valueHop, xAx
isPosY); | |
4429 } | |
4430 ctx.stroke(); | |
4431 } | |
4432 //Y axis | |
4433 ctx.lineWidth = config.scaleLineWidth; | |
4434 ctx.strokeStyle = config.scaleLineColor; | |
4435 ctx.beginPath(); | |
4436 ctx.moveTo(yAxisPosX, xAxisPosY + config.scaleTickSizeBo
ttom); | |
4437 ctx.lineTo(yAxisPosX, xAxisPosY - msr.availableHeight -
config.scaleTickSizeTop); | |
4438 ctx.stroke(); | |
4439 for (var j = 0; j < calculatedScale.steps; j++) { | |
4440 ctx.beginPath(); | |
4441 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft,
xAxisPosY - ((j + 1) * scaleHop)); | |
4442 ctx.lineWidth = config.scaleGridLineWidth; | |
4443 ctx.strokeStyle = config.scaleGridLineColor; | |
4444 if (config.scaleShowGridLines && j % config.scal
eYGridLinesStep == 0) { | |
4445 ctx.lineTo(yAxisPosX + msr.availableWidt
h + config.scaleTickSizeRight, xAxisPosY - ((j + 1) * scaleHop)); | |
4446 } else { | |
4447 ctx.lineTo(yAxisPosX, xAxisPosY - ((j +
1) * scaleHop)); | |
4448 } | |
4449 ctx.stroke(); | |
4450 } | |
4451 }; | |
4452 | |
4453 function drawLabels() { | |
4454 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
4455 //X axis line
| |
4456 if (config.xAxisTop || config.xAxisBottom) { | |
4457 ctx.textBaseline = "top"; | |
4458 if (msr.rotateLabels > 90) { | |
4459 ctx.save(); | |
4460 ctx.textAlign = "left"; | |
4461 } else if (msr.rotateLabels > 0) { | |
4462 ctx.save(); | |
4463 ctx.textAlign = "right"; | |
4464 } else { | |
4465 ctx.textAlign = "center"; | |
4466 } | |
4467 ctx.fillStyle = config.scaleFontColor; | |
4468 if (config.xAxisBottom) { | |
4469 for (var i = 0; i < data.labels.length;
i++) { | |
4470 ctx.save(); | |
4471 if (msr.rotateLabels > 0) { | |
4472 | |
4473 ctx.translate(yAxisPosX
+ i * valueHop + (valueHop / 2) - msr.highestXLabel / 2, msr.xLabelPos); | |
4474 ctx.rotate(-(msr.rotateL
abels * (Math.PI / 180))); | |
4475 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), 0, 0, ctx.textBaseline, conf
ig.scaleFontSize); | |
4476 } else { | |
4477 ctx.fillTextMultiLine(fm
tChartJS(config, data.labels[i], config.fmtXLabel), yAxisPosX + i * valueHop + (
valueHop / 2), msr.xLabelPos, ctx.textBaseline, config.scaleFontSize); | |
4478 } | |
4479 ctx.restore(); | |
4480 } | |
4481 } | |
4482 } | |
4483 //Y axis | |
4484 ctx.textAlign = "right"; | |
4485 ctx.textBaseline = "middle"; | |
4486 for (var j = ((config.showYAxisMin) ? -1 : 0); j < calcu
latedScale.steps; j++) { | |
4487 if (config.scaleShowLabels) { | |
4488 if (config.yAxisLeft) { | |
4489 ctx.textAlign = "right"; | |
4490 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX - (config.scaleTickSizeLeft + config.yAxisSpaceRi
ght), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline, config.scaleFontSize); | |
4491 } | |
4492 if (config.yAxisRight) { | |
4493 ctx.textAlign = "left"; | |
4494 ctx.fillTextMultiLine(calculated
Scale.labels[j + 1], yAxisPosX + msr.availableWidth + (config.scaleTickSizeRight
+ config.yAxisSpaceRight), xAxisPosY - ((j + 1) * scaleHop), ctx.textBaseline,
config.scaleFontSize); | |
4495 } | |
4496 } | |
4497 } | |
4498 }; | |
4499 | |
4500 function getValueBounds() { | |
4501 var upperValue = Number.MIN_VALUE; | |
4502 var lowerValue = Number.MAX_VALUE; | |
4503 for (var i = 0; i < data.datasets.length; i++) { | |
4504 var mathFctName = data.datasets[i].drawMathDevia
tion; | |
4505 var mathValueHeight = 0; | |
4506 if (typeof eval(mathFctName) == "function") { | |
4507 var parameter = { | |
4508 data: data, | |
4509 datasetNr: i | |
4510 }; | |
4511 mathValueHeight = window[mathFctName](pa
rameter); | |
4512 } | |
4513 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4514 if (1 * data.datasets[i].data[j] + mathV
alueHeight > upperValue) { | |
4515 upperValue = 1 * data.datasets[i
].data[j] + mathValueHeight | |
4516 }; | |
4517 if (1 * data.datasets[i].data[j] - mathV
alueHeight < lowerValue) { | |
4518 lowerValue = 1 * data.datasets[i
].data[j] - mathValueHeight | |
4519 }; | |
4520 } | |
4521 }; | |
4522 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
4523 upperValue = Max([upperValue * 2, 1]); | |
4524 lowerValue = 0; | |
4525 } | |
4526 // AJOUT CHANGEMENT | |
4527 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
4528 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
4529 labelHeight = config.scaleFontSize; | |
4530 scaleHeight = msr.availableHeight; | |
4531 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
4532 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
4533 return { | |
4534 maxValue: upperValue, | |
4535 minValue: lowerValue, | |
4536 maxSteps: maxSteps, | |
4537 minSteps: minSteps | |
4538 }; | |
4539 }; | |
4540 }; | |
4541 var HorizontalBar = function(data, config, ctx) { | |
4542 var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight
, valueBounds, labelTemplateString, valueHop, widestXLabel, xAxisLength, yAxisPo
sX, xAxisPosY, barWidth, rotateLabels = 0, | |
4543 msr; | |
4544 ctx.tpchart="HorizontalBar"; | |
4545 setting_new_chart_vars(ctx); | |
4546 | |
4547 if (!dynamicFunction(data, config, ctx)) { | |
4548 if(config.responsive && typeof ctx.firstPass == "undefin
ed") { if(!config.multiGraph) { addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); } } | |
4549 return; | |
4550 } | |
4551 if(config.responsive && typeof ctx.firstPass == "undefined") { | |
4552 if(!config.multiGraph) { | |
4553 addResponsiveChart(ctx.ChartNewId,ctx,data,confi
g); | |
4554 subUpdateChart(ctx,data,config); | |
4555 return; | |
4556 } else { ctx.firstPass=1; } | |
4557 } | |
4558 | |
4559 if (config.reverseOrder && typeof ctx.reversed == "undefined") { | |
4560 ctx.reversed=true; | |
4561 data = reverseData(data); | |
4562 } | |
4563 | |
4564 if (typeof jsGraphAnnotate[ctx.ChartNewId] == "undefined") jsGra
phAnnotate[ctx.ChartNewId] = new Array(); | |
4565 else if (!config.multiGraph) clearAnnotate(ctx.ChartNewId); | |
4566 | |
4567 defMouse(ctx, data, config); | |
4568 setRect(ctx, config); | |
4569 | |
4570 msr = setMeasures(data, config, ctx, height, width, "nihil", [""
], true, true, true, true, true, "StackedBar"); | |
4571 valueBounds = getValueBounds(); | |
4572 | |
4573 if(valueBounds.maxSteps>0 && valueBounds.minSteps>0) { | |
4574 //Check and set the scale | |
4575 labelTemplateString = (config.scaleShowLabels) ? config.
scaleLabel : ""; | |
4576 if (!config.scaleOverride) { | |
4577 calculatedScale = calculateScale(1, config, valu
eBounds.maxSteps, valueBounds.minSteps, valueBounds.maxValue, valueBounds.minVal
ue, labelTemplateString); | |
4578 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, true, true, true, true, "HorizontalBar")
; | |
4579 } else { | |
4580 calculatedScale = { | |
4581 steps: config.scaleSteps, | |
4582 stepValue: config.scaleStepWidth, | |
4583 graphMin: config.scaleStartValue, | |
4584 graphMax: config.scaleStartValue + confi
g.scaleSteps * config.scaleStepWidth, | |
4585 labels: [] | |
4586 } | |
4587 populateLabels(1, config, labelTemplateString, c
alculatedScale.labels, calculatedScale.steps, config.scaleStartValue, calculated
Scale.graphMax, config.scaleStepWidth); | |
4588 msr = setMeasures(data, config, ctx, height, wid
th, calculatedScale.labels, null, true, true, true, true, true, "HorizontalBar")
; | |
4589 } | |
4590 msr.availableHeight = msr.availableHeight - config.scale
TickSizeBottom - config.scaleTickSizeTop; | |
4591 msr.availableWidth = msr.availableWidth - config.scaleTi
ckSizeLeft - config.scaleTickSizeRight; | |
4592 scaleHop = Math.floor(msr.availableHeight / data.labels.
length); | |
4593 valueHop = Math.floor(msr.availableWidth / (calculatedSc
ale.steps)); | |
4594 if (valueHop == 0 || config.fullWidthGraph) valueHop = (
msr.availableWidth / calculatedScale.steps); | |
4595 msr.clrwidth = msr.clrwidth - (msr.availableWidth - (cal
culatedScale.steps * valueHop)); | |
4596 msr.availableWidth = (calculatedScale.steps) * valueHop; | |
4597 msr.availableHeight = (data.labels.length) * scaleHop; | |
4598 yAxisPosX = msr.leftNotUsableSize + config.scaleTickSize
Left; | |
4599 xAxisPosY = msr.topNotUsableSize + msr.availableHeight +
config.scaleTickSizeTop; | |
4600 barWidth = (scaleHop - config.scaleGridLineWidth * 2 - (
config.barValueSpacing * 2) - (config.barDatasetSpacing * data.datasets.length -
1) - ((config.barStrokeWidth / 2) * data.datasets.length - 1)) / data.datasets.
length; | |
4601 if(barWidth>=0 && barWidth<=1)barWidth=1; | |
4602 if(barWidth<0 && barWidth>=-1)barWidth=-1; | |
4603 var zeroY = 0; | |
4604 if (valueBounds.minValue < 0) { | |
4605 var zeroY = calculateOffset(config.logarithmic,
0, calculatedScale, valueHop); | |
4606 } | |
4607 drawLabels(); | |
4608 animationLoop(config, drawScale, drawBars, ctx, msr.clrx
, msr.clry, msr.clrwidth, msr.clrheight, yAxisPosX + msr.availableWidth / 2, xAx
isPosY - msr.availableHeight / 2, yAxisPosX, xAxisPosY, data); | |
4609 } else { | |
4610 testRedraw(ctx,data,config); | |
4611 } | |
4612 | |
4613 function drawBars(animPc) { | |
4614 var cumvalue = new Array(); | |
4615 var totvalue = new Array(); | |
4616 for (var i = 0; i < data.datasets.length; i++) { | |
4617 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4618 cumvalue[j] = 0; | |
4619 totvalue[j] = 0; | |
4620 } | |
4621 } | |
4622 for (var i = 0; i < data.datasets.length; i++) { | |
4623 for (var j = 0; j < data.datasets[i].data.length
; j++) | |
4624 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) totvalue[j] += 1 * data.datasets[i].data[j]; | |
4625 } | |
4626 ctx.lineWidth = config.barStrokeWidth; | |
4627 for (var i = 0; i < data.datasets.length; i++) { | |
4628 if (animPc >= 1) { | |
4629 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
4630 else lgtxt = ""; | |
4631 } | |
4632 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4633 var currentAnimPc = animationCorrection(
animPc, data, config, i, j, 1).animVal; | |
4634 if (currentAnimPc > 1) currentAnimPc = c
urrentAnimPc - 1; | |
4635 var barOffset = xAxisPosY + config.barVa
lueSpacing - scaleHop * (j + 1) + barWidth * i + config.barDatasetSpacing * i +
config.barStrokeWidth * i; | |
4636 var barHeight = currentAnimPc * (calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, valu
eHop) - zeroY) + (config.barStrokeWidth / 2); | |
4637 ctx.fillStyle = config.defaultFillColor; | |
4638 if (typeof data.datasets[i].fillColor ==
"function") ctx.fillStyle = data.datasets[i].fillColor("FILLCOLOR", data, confi
g, i, j, currentAnimPc, 1 * data.datasets[i].data[j], "HorizontalBar", ctx, yAxi
sPosX+zeroY, barOffset, yAxisPosX + zeroY + barHeight, barOffset + barWidth); | |
4639 else if (typeof(data.datasets[i].fillCol
or) == "string") { | |
4640 ctx.fillStyle = data.datasets[i]
.fillColor; | |
4641 } else if (typeof(data.datasets[i].fillC
olor) == "object") { | |
4642 if (typeof(data.datasets[i].fill
Color[0]) == "string") { | |
4643 ctx.fillStyle = data.dat
asets[i].fillColor[Min([data.datasets[i].fillColor.length - 1, j])]; | |
4644 } | |
4645 } | |
4646 ctx.strokeStyle = config.defaultStrokeCo
lor; | |
4647 if (typeof data.datasets[i].strokeColor
== "function") ctx.strokeStyle = data.datasets[i].strokeColor("STROKECOLOR", dat
a, config, i, j, currentAnimPc, 1 * data.datasets[i].data[j], "HorizontalBar", c
tx, yAxisPosX, barOffset, yAxisPosX + barHeight, barOffset + barWidth); | |
4648 else if (typeof(data.datasets[i].strokeC
olor) == "string") { | |
4649 ctx.strokeStyle = data.datasets[
i].strokeColor; | |
4650 } else if (typeof(data.datasets[i].strok
eColor) == "object") { | |
4651 if (typeof(data.datasets[i].stro
keColor[0]) == "string") { | |
4652 ctx.strokeStyle = data.d
atasets[i].strokeColor[Min([data.datasets[i].strokeColor.length - 1, j])]; | |
4653 } | |
4654 } | |
4655 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
4656 roundRect(ctx, barOffset, yAxisP
osX+zeroY, barWidth, barHeight, config.barShowStroke, config.barBorderRadius, 0)
; | |
4657 cumvalue[j] += 1 * data.datasets
[i].data[j]; | |
4658 if (animPc >= 1) { | |
4659 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
4660 else lgtxt2 = ""; | |
4661 t1 = yAxisPosX + zeroY; | |
4662 t2 = yAxisPosX + calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, valu
eHop) + (config.barStrokeWidth / 2) | |
4663 if (t1 > t2) { | |
4664 t3 = t1; | |
4665 t1 = t2; | |
4666 t2 = t3 | |
4667 } | |
4668 jsGraphAnnotate[ctx.Char
tNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["RECT", t1, barOffset + barWi
dth, t2, barOffset, lgtxt, lgtxt2, 1 * data.datasets[i].data[j], cumvalue[j], to
tvalue[j], i, j]; | |
4669 } | |
4670 } | |
4671 } | |
4672 } | |
4673 if (animPc >= 1 && config.inGraphDataShow) { | |
4674 for (var i = 0; i < data.datasets.length; i++) { | |
4675 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
4676 cumvalue[j] = 0; | |
4677 } | |
4678 } | |
4679 for (var i = 0; i < data.datasets.length; i++) { | |
4680 if (typeof(data.datasets[i].title) == "s
tring") lgtxt = data.datasets[i].title.trim(); | |
4681 else lgtxt = ""; | |
4682 for (var j = 0; j < data.datasets[i].dat
a.length; j++) { | |
4683 if (!(typeof(data.datasets[i].da
ta[j]) == 'undefined')) { | |
4684 if (typeof(data.labels[j
]) == "string") lgtxt2 = data.labels[j].trim(); | |
4685 ctx.save(); | |
4686 ctx.textAlign = config.i
nGraphDataAlign; | |
4687 ctx.textBaseline = confi
g.inGraphDataVAlign; | |
4688 ctx.font = config.inGrap
hDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + config.inGraphDataFo
ntFamily; | |
4689 ctx.fillStyle = config.i
nGraphDataFontColor; | |
4690 var barOffset = xAxisPos
Y + config.barValueSpacing - scaleHop * (j + 1) + barWidth * i + config.barDatas
etSpacing * i + config.barStrokeWidth * i; | |
4691 t1 = yAxisPosX + zeroY; | |
4692 t2 = yAxisPosX + calcula
teOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedScale, valu
eHop) + (config.barStrokeWidth / 2) | |
4693 if (t1 > t2) { | |
4694 t3 = t1; | |
4695 t1 = t2; | |
4696 t2 = t3 | |
4697 } | |
4698 ctx.beginPath(); | |
4699 var yPos = 0, | |
4700 xPos = 0; | |
4701 if (config.inGraphDataYP
osition == 1) { | |
4702 yPos = barOffset
- config.inGraphDataPaddingY + barWidth; | |
4703 } else if (config.inGrap
hDataYPosition == 2) { | |
4704 yPos = barOffset
+ barWidth / 2 - config.inGraphDataPaddingY; | |
4705 } else if (config.inGrap
hDataYPosition == 3) { | |
4706 yPos = barOffset
- config.inGraphDataPaddingY; | |
4707 } | |
4708 if (config.inGraphDataXP
osition == 1) { | |
4709 xPos = yAxisPosX
+ zeroY + config.inGraphDataPaddingX; | |
4710 } else if (config.inGrap
hDataXPosition == 2) { | |
4711 xPos = yAxisPosX
+ (calculateOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculated
Scale, valueHop) + (config.barStrokeWidth / 2)) / 2 + config.inGraphDataPaddingX
; | |
4712 } else if (config.inGrap
hDataXPosition == 3) { | |
4713 xPos = yAxisPosX
+ calculateOffset(config.logarithmic, 1 * data.datasets[i].data[j], calculatedS
cale, valueHop) + (config.barStrokeWidth / 2) + config.inGraphDataPaddingX; | |
4714 } | |
4715 ctx.translate(xPos, yPos
); | |
4716 cumvalue[j] += 1 * data.
datasets[i].data[j]; | |
4717 var dispString = tmplbis
(config.inGraphDataTmpl, { | |
4718 config: config, | |
4719 v1: fmtChartJS(c
onfig, lgtxt, config.fmtV1), | |
4720 v2: fmtChartJS(c
onfig, lgtxt2, config.fmtV2), | |
4721 v3: fmtChartJS(c
onfig, 1 * data.datasets[i].data[j], config.fmtV3), | |
4722 v4: fmtChartJS(c
onfig, cumvalue[j], config.fmtV4), | |
4723 v5: fmtChartJS(c
onfig, totvalue[j], config.fmtV5), | |
4724 v6: roundToWithT
housands(config, fmtChartJS(config, 100 * data.datasets[i].data[j] / totvalue[j]
, config.fmtV6), config.roundPct), | |
4725 v7: fmtChartJS(c
onfig, t1, config.fmtV7), | |
4726 v8: fmtChartJS(c
onfig, barOffset + barWidth, config.fmtV8), | |
4727 v9: fmtChartJS(c
onfig, t2, config.fmtV9), | |
4728 v10: fmtChartJS(
config, barOffset, config.fmtV10), | |
4729 v11: fmtChartJS(
config, i, config.fmtV11), | |
4730 v12: fmtChartJS(
config, j, config.fmtV12), | |
4731 data: data | |
4732 }); | |
4733 ctx.rotate(config.inGrap
hDataRotate * (Math.PI / 180)); | |
4734 ctx.fillTextMultiLine(di
spString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
4735 ctx.restore(); | |
4736 } | |
4737 } | |
4738 } | |
4739 } | |
4740 if(msr.legendMsr.dispLegend)drawLegend(msr.legendMsr,dat
a,config,ctx,"HorizontalBar"); | |
4741 }; | |
4742 | |
4743 function roundRect(ctx, x, y, w, h, stroke, radius, zeroY) { | |
4744 ctx.beginPath(); | |
4745 ctx.moveTo(y + zeroY, x + radius); | |
4746 ctx.lineTo(y + zeroY, x + w - radius); | |
4747 ctx.quadraticCurveTo(y + zeroY, x + w, y + zeroY, x + w)
; | |
4748 ctx.lineTo(y + h - radius, x + w); | |
4749 ctx.quadraticCurveTo(y + h, x + w, y + h, x + w - radius
); | |
4750 ctx.lineTo(y + h, x + radius); | |
4751 ctx.quadraticCurveTo(y + h, x, y + h - radius, x); | |
4752 ctx.lineTo(y + zeroY, x); | |
4753 ctx.quadraticCurveTo(y + zeroY, x, y + zeroY, x + radius
); | |
4754 if (stroke) ctx.stroke(); | |
4755 ctx.closePath(); | |
4756 ctx.fill(); | |
4757 }; | |
4758 | |
4759 function drawScale() { | |
4760 //X axis line
| |
4761 ctx.lineWidth = config.scaleLineWidth; | |
4762 ctx.strokeStyle = config.scaleLineColor; | |
4763 ctx.beginPath(); | |
4764 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft, xAxisPo
sY); | |
4765 ctx.lineTo(yAxisPosX + msr.availableWidth + config.scale
TickSizeRight, xAxisPosY); | |
4766 ctx.stroke(); | |
4767 for (var i = ((config.showYAxisMin) ? -1 : 0); i < calcu
latedScale.steps; i++) { | |
4768 if (i >= 0) { | |
4769 ctx.beginPath(); | |
4770 ctx.moveTo(yAxisPosX + i * valueHop, xAx
isPosY + config.scaleTickSizeBottom); | |
4771 ctx.lineWidth = config.scaleGridLineWidt
h; | |
4772 ctx.strokeStyle = config.scaleGridLineCo
lor; | |
4773 //Check i isnt 0, so we dont go over the
Y axis twice. | |
4774 if (config.scaleShowGridLines && i > 0 &
& i % config.scaleXGridLinesStep == 0) { | |
4775 ctx.lineTo(yAxisPosX + i * value
Hop, xAxisPosY - msr.availableHeight - config.scaleTickSizeTop); | |
4776 } else { | |
4777 ctx.lineTo(yAxisPosX + i * value
Hop, xAxisPosY); | |
4778 } | |
4779 ctx.stroke(); | |
4780 } | |
4781 } | |
4782 //Y axis | |
4783 ctx.lineWidth = config.scaleLineWidth; | |
4784 ctx.strokeStyle = config.scaleLineColor; | |
4785 ctx.beginPath(); | |
4786 ctx.moveTo(yAxisPosX, xAxisPosY + config.scaleTickSizeBo
ttom); | |
4787 ctx.lineTo(yAxisPosX, xAxisPosY - msr.availableHeight -
config.scaleTickSizeTop); | |
4788 ctx.stroke(); | |
4789 for (var j = 0; j < data.labels.length; j++) { | |
4790 ctx.beginPath(); | |
4791 ctx.moveTo(yAxisPosX - config.scaleTickSizeLeft,
xAxisPosY - ((j + 1) * scaleHop)); | |
4792 ctx.lineWidth = config.scaleGridLineWidth; | |
4793 ctx.strokeStyle = config.scaleGridLineColor; | |
4794 if (config.scaleShowGridLines && j % config.scal
eYGridLinesStep == 0) { | |
4795 ctx.lineTo(yAxisPosX + msr.availableWidt
h + config.scaleTickSizeRight, xAxisPosY - ((j + 1) * scaleHop)); | |
4796 } else { | |
4797 ctx.lineTo(yAxisPosX, xAxisPosY - ((j +
1) * scaleHop)); | |
4798 } | |
4799 ctx.stroke(); | |
4800 } | |
4801 }; | |
4802 | |
4803 function drawLabels() { | |
4804 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
4805 //X axis line
| |
4806 if (config.scaleShowLabels && (config.xAxisTop || config
.xAxisBottom)) { | |
4807 ctx.textBaseline = "top"; | |
4808 if (msr.rotateLabels > 90) { | |
4809 ctx.save(); | |
4810 ctx.textAlign = "left"; | |
4811 } else if (msr.rotateLabels > 0) { | |
4812 ctx.save(); | |
4813 ctx.textAlign = "right"; | |
4814 } else { | |
4815 ctx.textAlign = "center"; | |
4816 } | |
4817 ctx.fillStyle = config.scaleFontColor; | |
4818 if (config.xAxisBottom) { | |
4819 for (var i = ((config.showYAxisMin) ? -1
: 0); i < calculatedScale.steps; i++) { | |
4820 ctx.save(); | |
4821 if (msr.rotateLabels > 0) { | |
4822 ctx.translate(yAxisPosX
+ (i + 1) * valueHop - msr.highestXLabel / 2, msr.xLabelPos); | |
4823 ctx.rotate(-(msr.rotateL
abels * (Math.PI / 180))); | |
4824 ctx.fillTextMultiLine(ca
lculatedScale.labels[i + 1], 0, 0, ctx.textBaseline, config.scaleFontSize); | |
4825 } else { | |
4826 ctx.fillTextMultiLine(ca
lculatedScale.labels[i + 1], yAxisPosX + (i + 1) * valueHop, msr.xLabelPos, ctx.
textBaseline, config.scaleFontSize); | |
4827 } | |
4828 ctx.restore(); | |
4829 } | |
4830 } | |
4831 } | |
4832 //Y axis | |
4833 ctx.textAlign = "right"; | |
4834 ctx.textBaseline = "middle"; | |
4835 for (var j = 0; j < data.labels.length; j++) { | |
4836 if (config.yAxisLeft) { | |
4837 ctx.textAlign = "right"; | |
4838 ctx.fillTextMultiLine(fmtChartJS(config,
data.labels[j], config.fmtXLabel), yAxisPosX - (config.scaleTickSizeLeft + conf
ig.yAxisSpaceRight), xAxisPosY - (j * scaleHop) - scaleHop / 2, ctx.textBaseline
, config.scaleFontSize); | |
4839 } | |
4840 if (config.yAxisRight) { | |
4841 ctx.textAlign = "left"; | |
4842 ctx.fillTextMultiLine(fmtChartJS(config,
data.labels[j], config.fmtXLabel), yAxisPosX + msr.availableWidth + (config.sca
leTickSizeRight + config.yAxisSpaceRight), xAxisPosY - (j * scaleHop) - scaleHop
/ 2, ctx.textBaseline, config.scaleFontSize); | |
4843 } | |
4844 } | |
4845 }; | |
4846 | |
4847 function getValueBounds() { | |
4848 var upperValue = Number.MIN_VALUE; | |
4849 var lowerValue = Number.MAX_VALUE; | |
4850 for (var i = 0; i < data.datasets.length; i++) { | |
4851 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
4852 if (1 * data.datasets[i].data[j] > upper
Value) { | |
4853 upperValue = 1 * data.datasets[i
].data[j] | |
4854 }; | |
4855 if (1 * data.datasets[i].data[j] < lower
Value) { | |
4856 lowerValue = 1 * data.datasets[i
].data[j] | |
4857 }; | |
4858 } | |
4859 }; | |
4860 if (Math.abs(upperValue - lowerValue) < 0.00000001) { | |
4861 upperValue = Max([upperValue * 2, 1]); | |
4862 lowerValue = 0; | |
4863 } | |
4864 // AJOUT CHANGEMENT | |
4865 if (!isNaN(config.graphMin)) lowerValue = config.graphMi
n; | |
4866 if (!isNaN(config.graphMax)) upperValue = config.graphMa
x; | |
4867 | |
4868 labelHeight = config.scaleFontSize; | |
4869 scaleHeight = msr.availableHeight; | |
4870 | |
4871 var maxSteps = Math.floor((scaleHeight / (labelHeight *
0.66))); | |
4872 var minSteps = Math.floor((scaleHeight / labelHeight * 0
.5)); | |
4873 return { | |
4874 maxValue: upperValue, | |
4875 minValue: lowerValue, | |
4876 maxSteps: maxSteps, | |
4877 minSteps: minSteps | |
4878 }; | |
4879 }; | |
4880 }; | |
4881 | |
4882 function calculateOffset(logarithmic, val, calculatedScale, scaleHop) { | |
4883 if (!logarithmic) { // no logarithmic scale | |
4884 var outerValue = calculatedScale.steps * calculatedScale
.stepValue; | |
4885 var adjustedValue = val - calculatedScale.graphMin; | |
4886 var scalingFactor = CapValue(adjustedValue / outerValue,
1, 0); | |
4887 return (scaleHop * calculatedScale.steps) * scalingFacto
r; | |
4888 } else { // logarithmic scale | |
4889 return CapValue(log10(val) * scaleHop - calculateOrderOf
Magnitude(calculatedScale.graphMin) * scaleHop, undefined, 0); | |
4890 } | |
4891 }; | |
4892 | |
4893 function animationLoop(config, drawScale, drawData, ctx, clrx, clry, clr
width, clrheight, midPosX, midPosY, borderX, borderY, data) { | |
4894 var cntiter = 0; | |
4895 var animationCount = 1; | |
4896 var multAnim = 1; | |
4897 if (config.animationStartValue < 0 || config.animationStartValue
> 1) config.animation.StartValue = 0; | |
4898 if (config.animationStopValue < 0 || config.animationStopValue >
1) config.animation.StopValue = 1; | |
4899 if (config.animationStopValue < config.animationStartValue) conf
ig.animationStopValue = config.animationStartValue; | |
4900 if (isIE() < 9 && isIE() != false) config.animation = false; | |
4901 var animFrameAmount = (config.animation) ? 1 / CapValue(config.a
nimationSteps, Number.MAX_VALUE, 1) : 1, | |
4902 easingFunction = animationOptions[config.animationEasing
], | |
4903 percentAnimComplete = (config.animation) ? 0 : 1; | |
4904 if (config.animation && config.animationStartValue > 0 && config
.animationStartValue <= 1) { | |
4905 while (percentAnimComplete < config.animationStartValue)
{ | |
4906 cntiter++; | |
4907 percentAnimComplete += animFrameAmount; | |
4908 } | |
4909 } | |
4910 var beginAnim = cntiter; | |
4911 var beginAnimPct = percentAnimComplete; | |
4912 if (typeof drawScale !== "function") drawScale = function() {}; | |
4913 if (config.clearRect) requestAnimFrame(animLoop); | |
4914 else animLoop(); | |
4915 | |
4916 function animateFrame() { | |
4917 var easeAdjustedAnimationPercent = (config.animation) ?
CapValue(easingFunction(percentAnimComplete), null, 0) : 1; | |
4918 if (1 * cntiter >= 1 * CapValue(config.animationSteps, N
umber.MAX_VALUE, 1) || config.animation == false || ctx.firstPass==3 || ctx.firs
tPass==4 || ctx.firstPass==8 || ctx.firstPass==9) easeAdjustedAnimationPercent =
1; | |
4919 else if (easeAdjustedAnimationPercent >= 1) easeAdjusted
AnimationPercent = 0.9999; | |
4920 if (config.animation && !(isIE() < 9 && isIE() != false)
&& config.clearRect) ctx.clearRect(clrx, clry, clrwidth, clrheight); | |
4921 dispCrossImage(ctx, config, midPosX, midPosY, borderX, b
orderY, false, data, easeAdjustedAnimationPercent, cntiter); | |
4922 dispCrossText(ctx, config, midPosX, midPosY, borderX, bo
rderY, false, data, easeAdjustedAnimationPercent, cntiter); | |
4923 if (config.scaleOverlay) { | |
4924 drawData(easeAdjustedAnimationPercent); | |
4925 drawScale(); | |
4926 } else { | |
4927 drawScale(); | |
4928 drawData(easeAdjustedAnimationPercent); | |
4929 } | |
4930 dispCrossImage(ctx, config, midPosX, midPosY, borderX, b
orderY, true, data, easeAdjustedAnimationPercent, cntiter); | |
4931 dispCrossText(ctx, config, midPosX, midPosY, borderX, bo
rderY, true, data, easeAdjustedAnimationPercent, cntiter); | |
4932 }; | |
4933 | |
4934 function animLoop() { | |
4935 //We need to check if the animation is incomplete (less
than 1), or complete (1). | |
4936 cntiter += multAnim; | |
4937 percentAnimComplete += multAnim * animFrameAmount; | |
4938 if (cntiter == config.animationSteps || config.animation
== false || ctx.firstPass==3 || ctx.firstPass==4 || ctx.firstPass==8 || ctx.fir
stPass==9) percentAnimComplete = 1; | |
4939 else if (percentAnimComplete >= 1) percentAnimComplete =
0.999; | |
4940 animateFrame(); | |
4941 //Stop the loop continuing forever | |
4942 if (multAnim == -1 && cntiter <= beginAnim) { | |
4943 if (typeof config.onAnimationComplete == "functi
on" && ctx.runanimationcompletefunction==true) config.onAnimationComplete(ctx, c
onfig, data, 0, animationCount + 1); | |
4944 multAnim = 1; | |
4945 requestAnimFrame(animLoop); | |
4946 } else if (percentAnimComplete < config.animationStopVal
ue) { | |
4947 requestAnimFrame(animLoop); | |
4948 } else { | |
4949 if ((animationCount < config.animationCount || c
onfig.animationCount == 0) && (ctx.firstPass ==1 || ctx.firstPass!=2)) { | |
4950 animationCount++; | |
4951 if (config.animationBackward && multAnim
== 1) { | |
4952 percentAnimComplete -= animFrame
Amount; | |
4953 multAnim = -1; | |
4954 } else { | |
4955 multAnim = 1; | |
4956 cntiter = beginAnim - 1; | |
4957 percentAnimComplete = beginAnimP
ct - animFrameAmount; | |
4958 } | |
4959 window.setTimeout(animLoop, config.anima
tionPauseTime*1000); | |
4960 } else { | |
4961 if(!testRedraw(ctx,data,config) ) { | |
4962 if (typeof config.onAnimationCom
plete == "function" && ctx.runanimationcompletefunction==true) { | |
4963 config.onAnimationComple
te(ctx, config, data, 1, animationCount + 1); | |
4964 ctx.runanimationcomplete
function=false; | |
4965 } | |
4966 } | |
4967 } | |
4968 | |
4969 } | |
4970 }; | |
4971 }; | |
4972 //Declare global functions to be called within this namespace here. | |
4973 // shim layer with setTimeout fallback | |
4974 var requestAnimFrame = (function() { | |
4975 return window.requestAnimationFrame || | |
4976 window.webkitRequestAnimationFrame || | |
4977 window.mozRequestAnimationFrame || | |
4978 window.oRequestAnimationFrame || | |
4979 window.msRequestAnimationFrame || | |
4980 function(callback) { | |
4981 window.setTimeout(callback, 1000 / 60); | |
4982 }; | |
4983 })(); | |
4984 | |
4985 function calculateScale(axis, config, maxSteps, minSteps, maxValue, minV
alue, labelTemplateString) { | |
4986 var graphMin, graphMax, graphRange, stepValue, numberOfSteps, va
lueRange, rangeOrderOfMagnitude, decimalNum; | |
4987 var logarithmic, yAxisMinimumInterval; | |
4988 if (axis == 2) { | |
4989 logarithmic = config.logarithmic2; | |
4990 yAxisMinimumInterval = config.yAxisMinimumInterval2; | |
4991 } else { | |
4992 logarithmic = config.logarithmic; | |
4993 yAxisMinimumInterval = config.yAxisMinimumInterval; | |
4994 } | |
4995 if (!logarithmic) { // no logarithmic scale | |
4996 valueRange = maxValue - minValue; | |
4997 rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueR
ange); | |
4998 graphMin = Math.floor(minValue / (1 * Math.pow(10, range
OrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); | |
4999 graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeO
rderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); | |
5000 if (typeof yAxisMinimumInterval == "number") { | |
5001 graphMin = graphMin - (graphMin % yAxisMinimumIn
terval); | |
5002 while (graphMin > minValue) graphMin = graphMin
- yAxisMinimumInterval; | |
5003 if (graphMax % yAxisMinimumInterval > 0.0000001
&& graphMax % yAxisMinimumInterval < yAxisMinimumInterval - 0.0000001) { | |
5004 graphMax = roundScale(config, (1 + Math.
floor(graphMax / yAxisMinimumInterval)) * yAxisMinimumInterval); | |
5005 } | |
5006 while (graphMax < maxValue) graphMax = graphMax
+ yAxisMinimumInterval; | |
5007 } | |
5008 } else { // logarithmic scale | |
5009 var minMag = calculateOrderOfMagnitude(minValue); | |
5010 var maxMag = calculateOrderOfMagnitude(maxValue) + 1; | |
5011 graphMin = Math.pow(10, minMag); | |
5012 graphMax = Math.pow(10, maxMag); | |
5013 rangeOrderOfMagnitude = maxMag - minMag; | |
5014 } | |
5015 graphRange = graphMax - graphMin; | |
5016 stepValue = Math.pow(10, rangeOrderOfMagnitude); | |
5017 numberOfSteps = Math.round(graphRange / stepValue); | |
5018 if (!logarithmic) { // no logarithmic scale | |
5019 //Compare number of steps to the max and min for that si
ze graph, and add in half steps if need be. | |
5020 var stopLoop = false; | |
5021 while (!stopLoop && (numberOfSteps < minSteps || numberO
fSteps > maxSteps)) { | |
5022 if (numberOfSteps < minSteps) { | |
5023 if (typeof yAxisMinimumInterval == "numb
er") { | |
5024 if (stepValue / 2 < yAxisMinimum
Interval) stopLoop = true; | |
5025 } | |
5026 if (!stopLoop) { | |
5027 stepValue /= 2; | |
5028 numberOfSteps = Math.round(graph
Range / stepValue); | |
5029 } | |
5030 } else { | |
5031 stepValue *= 2; | |
5032 numberOfSteps = Math.round(graphRange /
stepValue); | |
5033 } | |
5034 } | |
5035 | |
5036 if (typeof yAxisMinimumInterval == "number") { | |
5037 if (stepValue < yAxisMinimumInterval) { | |
5038 stepValue = yAxisMinimumInterval; | |
5039 numberOfSteps = Math.round(graphRange /
stepValue); | |
5040 } | |
5041 if (stepValue % yAxisMinimumInterval > 0.0000001
&& stepValue % yAxisMinimumInterval < yAxisMinimumInterval - 0.0000001) { | |
5042 if ((2 * stepValue) % yAxisMinimumInterv
al < 0.0000001 || (2 * stepValue) % yAxisMinimumInterval > yAxisMinimumInterval
- 0.0000001) { | |
5043 stepValue = 2 * stepValue; | |
5044 numberOfSteps = Math.round(graph
Range / stepValue); | |
5045 } else { | |
5046 stepValue = roundScale(config, (
1 + Math.floor(stepValue / yAxisMinimumInterval)) * yAxisMinimumInterval); | |
5047 numberOfSteps = Math.round(graph
Range / stepValue); | |
5048 } | |
5049 } | |
5050 } | |
5051 } else { // logarithmic scale | |
5052 numberOfSteps = rangeOrderOfMagnitude; // so scale is 10
,100,1000,... | |
5053 } | |
5054 var labels = []; | |
5055 populateLabels(1, config, labelTemplateString, labels, numberOfS
teps, graphMin, graphMax, stepValue); | |
5056 return { | |
5057 steps: numberOfSteps, | |
5058 stepValue: stepValue, | |
5059 graphMin: graphMin, | |
5060 labels: labels, | |
5061 maxValue: maxValue | |
5062 } | |
5063 }; | |
5064 | |
5065 function calculateScaleOld(config, maxSteps, minSteps, maxValue, minValu
e, labelTemplateString) { | |
5066 var graphMin, graphMax, graphRange, stepValue, numberOfSteps, va
lueRange, rangeOrderOfMagnitude, decimalNum; | |
5067 if (!config.logarithmic) { // no logarithmic scale | |
5068 valueRange = maxValue - minValue; | |
5069 rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueR
ange); | |
5070 graphMin = Math.floor(minValue / (1 * Math.pow(10, range
OrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); | |
5071 graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeO
rderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); | |
5072 if (typeof config.yAxisMinimumInterval == "number") { | |
5073 graphMin = graphMin - (graphMin % config.yAxisMi
nimumInterval); | |
5074 while (graphMin > minValue) graphMin = graphMin
- config.yAxisMinimumInterval; | |
5075 if (graphMax % config.yAxisMinimumInterval > 0.0
000001 && graphMax % config.yAxisMinimumInterval < config.yAxisMinimumInterval -
0.0000001) { | |
5076 graphMax = roundScale(config, (1 + Math.
floor(graphMax / config.yAxisMinimumInterval)) * config.yAxisMinimumInterval); | |
5077 } | |
5078 while (graphMax < maxValue) graphMax = graphMax
+ config.yAxisMinimumInterval; | |
5079 } | |
5080 } else { // logarithmic scale | |
5081 var minMag = calculateOrderOfMagnitude(minValue); | |
5082 var maxMag = calculateOrderOfMagnitude(maxValue) + 1; | |
5083 graphMin = Math.pow(10, minMag); | |
5084 graphMax = Math.pow(10, maxMag); | |
5085 rangeOrderOfMagnitude = maxMag - minMag; | |
5086 } | |
5087 graphRange = graphMax - graphMin; | |
5088 stepValue = Math.pow(10, rangeOrderOfMagnitude); | |
5089 numberOfSteps = Math.round(graphRange / stepValue); | |
5090 if (!config.logarithmic) { // no logarithmic scale | |
5091 //Compare number of steps to the max and min for that si
ze graph, and add in half steps if need be. | |
5092 var stopLoop = false; | |
5093 while (!stopLoop && (numberOfSteps < minSteps || numberO
fSteps > maxSteps)) { | |
5094 if (numberOfSteps < minSteps) { | |
5095 if (typeof config.yAxisMinimumInterval =
= "number") { | |
5096 if (stepValue / 2 < config.yAxis
MinimumInterval) stopLoop = true; | |
5097 } | |
5098 if (!stopLoop) { | |
5099 stepValue /= 2; | |
5100 numberOfSteps = Math.round(graph
Range / stepValue); | |
5101 } | |
5102 } else { | |
5103 stepValue *= 2; | |
5104 numberOfSteps = Math.round(graphRange /
stepValue); | |
5105 } | |
5106 } | |
5107 if (typeof config.yAxisMinimumInterval == "number") { | |
5108 if (stepValue < config.yAxisMinimumInterval) { | |
5109 stepValue = config.yAxisMinimumInterval; | |
5110 numberOfSteps = Math.round(graphRange /
stepValue); | |
5111 } | |
5112 if (stepValue % config.yAxisMinimumInterval > 0.
0000001 && stepValue % config.yAxisMinimumInterval < config.yAxisMinimumInterval
- 0.0000001) { | |
5113 if ((2 * stepValue) % config.yAxisMinimu
mInterval < 0.0000001 || (2 * stepValue) % config.yAxisMinimumInterval > config.
yAxisMinimumInterval - 0.0000001) { | |
5114 stepValue = 2 * stepValue; | |
5115 numberOfSteps = Math.round(graph
Range / stepValue); | |
5116 } else { | |
5117 stepValue = roundScale(config, (
1 + Math.floor(stepValue / config.yAxisMinimumInterval)) * config.yAxisMinimumIn
terval); | |
5118 numberOfSteps = Math.round(graph
Range / stepValue); | |
5119 } | |
5120 } | |
5121 } | |
5122 } else { // logarithmic scale | |
5123 numberOfSteps = rangeOrderOfMagnitude; // so scale is 10
,100,1000,... | |
5124 } | |
5125 var labels = []; | |
5126 populateLabels(1, config, labelTemplateString, labels, numberOfS
teps, graphMin, graphMax, stepValue); | |
5127 return { | |
5128 steps: numberOfSteps, | |
5129 stepValue: stepValue, | |
5130 graphMin: graphMin, | |
5131 labels: labels, | |
5132 maxValue: maxValue | |
5133 } | |
5134 }; | |
5135 | |
5136 function roundScale(config, value) { | |
5137 var scldec = 0; | |
5138 var sscl = "" + config.yAxisMinimumInterval; | |
5139 if (sscl.indexOf(".") > 0) { | |
5140 scldec = sscl.substr(sscl.indexOf(".")).length; | |
5141 } | |
5142 return (Math.round(value * Math.pow(10, scldec)) / Math.pow(10,
scldec)); | |
5143 } | |
5144 | |
5145 function calculateOrderOfMagnitude(val) { | |
5146 return Math.floor(Math.log(val) / Math.LN10); | |
5147 }; | |
5148 //Populate an array of all the labels by interpolating the string. | |
5149 function populateLabels(axis, config, labelTemplateString, labels, numbe
rOfSteps, graphMin, graphMax, stepValue) { | |
5150 var logarithmic; | |
5151 if (axis == 2) { | |
5152 logarithmic = config.logarithmic2; | |
5153 fmtYLabel = config.fmtYLabel2; | |
5154 } else { | |
5155 logarithmic = config.logarithmic; | |
5156 fmtYLabel = config.fmtYLabel; | |
5157 } | |
5158 if (labelTemplateString) { | |
5159 //Fix floating point errors by setting to fixed the on t
he same decimal as the stepValue. | |
5160 if (!logarithmic) { // no logarithmic scale | |
5161 for (var i = 0; i < numberOfSteps + 1; i++) { | |
5162 labels.push(tmpl(labelTemplateString, { | |
5163 value: fmtChartJS(config, 1 * ((
graphMin + (stepValue * i)).toFixed(getDecimalPlaces(stepValue))), fmtYLabel) | |
5164 })); | |
5165 } | |
5166 } else { // logarithmic scale 10,100,1000,... | |
5167 var value = graphMin; | |
5168 for (var i = 0; i < numberOfSteps + 1; i++) { | |
5169 labels.push(tmpl(labelTemplateString, { | |
5170 value: fmtChartJS(config, 1 * va
lue.toFixed(getDecimalPlaces(value)), fmtYLabel) | |
5171 })); | |
5172 value *= 10; | |
5173 } | |
5174 } | |
5175 } | |
5176 }; | |
5177 //Max value from array | |
5178 function Max(array) { | |
5179 return Math.max.apply(Math, array); | |
5180 }; | |
5181 //Min value from array | |
5182 function Min(array) { | |
5183 return Math.min.apply(Math, array); | |
5184 }; | |
5185 //Default if undefined | |
5186 function Default(userDeclared, valueIfFalse) { | |
5187 if (!userDeclared) { | |
5188 return valueIfFalse; | |
5189 } else { | |
5190 return userDeclared; | |
5191 } | |
5192 }; | |
5193 //Apply cap a value at a high or low number | |
5194 function CapValue(valueToCap, maxValue, minValue) { | |
5195 if (isNumber(maxValue)) { | |
5196 if (valueToCap > maxValue) { | |
5197 return maxValue; | |
5198 } | |
5199 } | |
5200 if (isNumber(minValue)) { | |
5201 if (valueToCap < minValue) { | |
5202 return minValue; | |
5203 } | |
5204 } | |
5205 return valueToCap; | |
5206 }; | |
5207 | |
5208 function getDecimalPlaces(num) { | |
5209 var numberOfDecimalPlaces; | |
5210 if (num % 1 != 0) { | |
5211 return num.toString().split(".")[1].length | |
5212 } else { | |
5213 return 0; | |
5214 } | |
5215 }; | |
5216 | |
5217 function mergeChartConfig(defaults, userDefined) { | |
5218 var returnObj = {}; | |
5219 for (var attrname in defaults) { | |
5220 returnObj[attrname] = defaults[attrname]; | |
5221 } | |
5222 for (var attrname in userDefined) { | |
5223 returnObj[attrname] = userDefined[attrname]; | |
5224 } | |
5225 return returnObj; | |
5226 }; | |
5227 //Javascript micro templating by John Resig - source at http://ejohn.org
/blog/javascript-micro-templating/ | |
5228 var cache = {}; | |
5229 | |
5230 function tmpl(str, data) { | |
5231 // Figure out if we're getting a template, or if we need to | |
5232 // load the template - and be sure to cache the result. | |
5233 var fn = !/\W/.test(str) ? | |
5234 cache[str] = cache[str] || | |
5235 tmpl(document.getElementById(str).innerHTML) : | |
5236 // Generate a reusable function that will serve as a tem
plate | |
5237 // generator (and which will be cached). | |
5238 new Function("obj", | |
5239 "var p=[],print=function(){p.push.apply(p,argume
nts);};" + | |
5240 // Introduce the data as local variables using w
ith(){} | |
5241 "with(obj){p.push('" + | |
5242 // Convert the template into pure JavaScript | |
5243 str | |
5244 .replace(/[\r\t\n]/g, " ") | |
5245 .split("<%").join("\t") | |
5246 .replace(/((^|%>)[^\t]*)'/g, "$1\r") | |
5247 .replace(/\t=(.*?)%>/g, "',$1,'") | |
5248 .split("\t").join("');") | |
5249 .split("%>").join("p.push('") | |
5250 .split("\r").join("\\'") + "');}return p.join(''
);"); | |
5251 // Provide some basic currying to the user | |
5252 return data ? fn(data) : fn; | |
5253 }; | |
5254 | |
5255 function dispCrossText(ctx, config, posX, posY, borderX, borderY, overla
y, data, animPC, cntiter) { | |
5256 var i, disptxt, txtposx, txtposy, textAlign, textBaseline; | |
5257 for (i = 0; i < config.crossText.length; i++) { | |
5258 if (config.crossText[i] != "" && config.crossTextOverlay
[Min([i, config.crossTextOverlay.length - 1])] == overlay && ((cntiter == 1 && c
onfig.crossTextIter[Min([i, config.crossTextIter.length - 1])] == "first") || co
nfig.crossTextIter[Min([i, config.crossTextIter.length - 1])] == cntiter || conf
ig.crossTextIter[Min([i, config.crossTextIter.length - 1])] == "all" || (animPC
== 1 && config.crossTextIter[Min([i, config.crossTextIter.length - 1])] == "last
"))) { | |
5259 ctx.save(); | |
5260 ctx.beginPath(); | |
5261 ctx.font = config.crossTextFontStyle[Min([i, con
fig.crossTextFontStyle.length - 1])] + " " + config.crossTextFontSize[Min([i, co
nfig.crossTextFontSize.length - 1])] + "px " + config.crossTextFontFamily[Min([i
, config.crossTextFontFamily.length - 1])]; | |
5262 ctx.fillStyle = config.crossTextFontColor[Min([i
, config.crossTextFontColor.length - 1])]; | |
5263 textAlign = config.crossTextAlign[Min([i, config
.crossTextAlign.length - 1])]; | |
5264 textBaseline = config.crossTextBaseline[Min([i,
config.crossTextBaseline.length - 1])]; | |
5265 txtposx = 1 * config.crossTextPosX[Min([i, confi
g.crossTextPosX.length - 1])]; | |
5266 txtposy = 1 * config.crossTextPosY[Min([i, confi
g.crossTextPosY.length - 1])]; | |
5267 switch (1 * config.crossTextRelativePosX[Min([i,
config.crossTextRelativePosX.length - 1])]) { | |
5268 case 0: | |
5269 if (textAlign == "default") text
Align = "left"; | |
5270 break; | |
5271 case 1: | |
5272 txtposx += borderX; | |
5273 if (textAlign == "default") text
Align = "right"; | |
5274 break; | |
5275 case 2: | |
5276 txtposx += posX; | |
5277 if (textAlign == "default") text
Align = "center"; | |
5278 break; | |
5279 case -2: | |
5280 txtposx += context.canvas.width
/ 2; | |
5281 if (textAlign == "default") text
Align = "center"; | |
5282 break; | |
5283 case 3: | |
5284 txtposx += txtposx + 2 * posX -
borderX; | |
5285 if (textAlign == "default") text
Align = "left"; | |
5286 break; | |
5287 case 4: | |
5288 // posX=width; | |
5289 txtposx += context.canvas.width; | |
5290 if (textAlign == "default") text
Align = "right"; | |
5291 break; | |
5292 default: | |
5293 txtposx += posX; | |
5294 if (textAlign == "default") text
Align = "center"; | |
5295 break; | |
5296 } | |
5297 switch (1 * config.crossTextRelativePosY[Min([i,
config.crossTextRelativePosY.length - 1])]) { | |
5298 case 0: | |
5299 if (textBaseline == "default") t
extBaseline = "top"; | |
5300 break; | |
5301 case 3: | |
5302 txtposy += borderY; | |
5303 if (textBaseline == "default") t
extBaseline = "top"; | |
5304 break; | |
5305 case 2: | |
5306 txtposy += posY; | |
5307 if (textBaseline == "default") t
extBaseline = "middle"; | |
5308 break; | |
5309 case -2: | |
5310 txtposy += context.canvas.height
/ 2; | |
5311 if (textBaseline == "default") t
extBaseline = "middle"; | |
5312 break; | |
5313 case 1: | |
5314 txtposy += txtposy + 2 * posY -
borderY; | |
5315 if (textBaseline == "default") t
extBaseline = "bottom"; | |
5316 break; | |
5317 case 4: | |
5318 txtposy += context.canvas.height
; | |
5319 if (textBaseline == "default") t
extBaseline = "bottom"; | |
5320 break; | |
5321 default: | |
5322 txtposy += posY; | |
5323 if (textBaseline == "default") t
extBaseline = "middle"; | |
5324 break; | |
5325 } | |
5326 ctx.textAlign = textAlign; | |
5327 ctx.textBaseline = textBaseline; | |
5328 ctx.translate(1 * txtposx, 1 * txtposy); | |
5329 ctx.rotate(Math.PI * config.crossTextAngle[Min([
i, config.crossTextAngle.length - 1])] / 180); | |
5330 if (config.crossText[i].substring(0, 1) == "%")
{ | |
5331 if (typeof config.crossTextFunction == "
function") disptxt = config.crossTextFunction(i, config.crossText[i], ctx, confi
g, posX, posY, borderX, borderY, overlay, data, animPC); | |
5332 } else disptxt = config.crossText[i]; | |
5333 ctx.fillTextMultiLine(disptxt, 0, 0, ctx.textBas
eline, config.crossTextFontSize[Min([i, config.crossTextFontSize.length - 1])]); | |
5334 ctx.stroke(); | |
5335 ctx.restore(); | |
5336 } | |
5337 } | |
5338 }; | |
5339 | |
5340 function dispCrossImage(ctx, config, posX, posY, borderX, borderY, overl
ay, data, animPC, cntiter) { | |
5341 var i, disptxt, imageposx, imageposy, imageAlign, imageBaseline; | |
5342 for (i = 0; i < config.crossImage.length; i++) { | |
5343 if (typeof config.crossImage[i] != "undefined" && config
.crossImageOverlay[Min([i, config.crossImageOverlay.length - 1])] == overlay &&
((cntiter == -1 && config.crossImageIter[Min([i, config.crossImageIter.length -
1])] == "background") || (cntiter == 1 && config.crossImageIter[Min([i, config.c
rossImageIter.length - 1])] == "first") || config.crossImageIter[Min([i, config.
crossImageIter.length - 1])] == cntiter || (cntiter != -1 && config.crossImageIt
er[Min([i, config.crossImageIter.length - 1])] == "all") || (animPC == 1 && conf
ig.crossImageIter[Min([i, config.crossImageIter.length - 1])] == "last"))) { | |
5344 ctx.save(); | |
5345 ctx.beginPath(); | |
5346 imageAlign = config.crossImageAlign[Min([i, conf
ig.crossImageAlign.length - 1])]; | |
5347 imageBaseline = config.crossImageBaseline[Min([i
, config.crossImageBaseline.length - 1])]; | |
5348 imageposx = 1 * config.crossImagePosX[Min([i, co
nfig.crossImagePosX.length - 1])]; | |
5349 imageposy = 1 * config.crossImagePosY[Min([i, co
nfig.crossImagePosY.length - 1])]; | |
5350 switch (1 * config.crossImageRelativePosX[Min([i
, config.crossImageRelativePosX.length - 1])]) { | |
5351 case 0: | |
5352 if (imageAlign == "default") ima
geAlign = "left"; | |
5353 break; | |
5354 case 1: | |
5355 imageposx += borderX; | |
5356 if (imageAlign == "default") ima
geAlign = "right"; | |
5357 break; | |
5358 case 2: | |
5359 imageposx += posX; | |
5360 if (imageAlign == "default") ima
geAlign = "center"; | |
5361 break; | |
5362 case -2: | |
5363 imageposx += context.canvas.widt
h / 2; | |
5364 if (imageAlign == "default") ima
geAlign = "center"; | |
5365 break; | |
5366 case 3: | |
5367 imageposx += imageposx + 2 * pos
X - borderX; | |
5368 if (imageAlign == "default") ima
geAlign = "left"; | |
5369 break; | |
5370 case 4: | |
5371 // posX=width; | |
5372 imageposx += context.canvas.widt
h; | |
5373 if (imageAlign == "default") ima
geAlign = "right"; | |
5374 break; | |
5375 default: | |
5376 imageposx += posX; | |
5377 if (imageAlign == "default") ima
geAlign = "center"; | |
5378 break; | |
5379 } | |
5380 switch (1 * config.crossImageRelativePosY[Min([i
, config.crossImageRelativePosY.length - 1])]) { | |
5381 case 0: | |
5382 if (imageBaseline == "default")
imageBaseline = "top"; | |
5383 break; | |
5384 case 3: | |
5385 imageposy += borderY; | |
5386 if (imageBaseline == "default")
imageBaseline = "top"; | |
5387 break; | |
5388 case 2: | |
5389 imageposy += posY; | |
5390 if (imageBaseline == "default")
imageBaseline = "middle"; | |
5391 break; | |
5392 case -2: | |
5393 imageposy += context.canvas.heig
ht / 2; | |
5394 if (imageBaseline == "default")
imageBaseline = "middle"; | |
5395 break; | |
5396 case 1: | |
5397 imageposy += imageposy + 2 * pos
Y - borderY; | |
5398 if (imageBaseline == "default")
imageBaseline = "bottom"; | |
5399 break; | |
5400 case 4: | |
5401 imageposy += context.canvas.heig
ht; | |
5402 if (imageBaseline == "default")
imageBaseline = "bottom"; | |
5403 break; | |
5404 default: | |
5405 imageposy += posY; | |
5406 if (imageBaseline == "default")
imageBaseline = "middle"; | |
5407 break; | |
5408 } | |
5409 var imageWidth = config.crossImage[i].width; | |
5410 switch (imageAlign) { | |
5411 case "left": | |
5412 break; | |
5413 case "right": | |
5414 imageposx -= imageWidth; | |
5415 break; | |
5416 case "center": | |
5417 imageposx -= (imageWidth / 2); | |
5418 break; | |
5419 default: | |
5420 break; | |
5421 } | |
5422 var imageHeight = config.crossImage[i].height; | |
5423 switch (imageBaseline) { | |
5424 case "top": | |
5425 break; | |
5426 case "bottom": | |
5427 imageposy -= imageHeight; | |
5428 break; | |
5429 case "middle": | |
5430 imageposy -= (imageHeight / 2); | |
5431 break; | |
5432 default: | |
5433 break; | |
5434 } | |
5435 ctx.translate(1 * imageposx, 1 * imageposy); | |
5436 ctx.rotate(Math.PI * config.crossImageAngle[Min(
[i, config.crossImageAngle.length - 1])] / 180); | |
5437 ctx.drawImage(config.crossImage[i], 0, 0); | |
5438 // ctx.stroke(); | |
5439 ctx.restore(); | |
5440 } | |
5441 } | |
5442 }; | |
5443 //**********************************************************************
****************** | |
5444 function setMeasures(data, config, ctx, height, width, ylabels, ylabels2
, reverseLegend, reverseAxis, drawAxis, drawLegendOnData, legendBox, typegraph)
{ | |
5445 if (config.canvasBackgroundColor != "none") ctx.canvas.style.bac
kground = config.canvasBackgroundColor; | |
5446 var borderWidth = 0; | |
5447 var xAxisLabelPos = 0; | |
5448 var graphTitleHeight = 0; | |
5449 var graphTitlePosY = 0; | |
5450 var graphSubTitleHeight = 0; | |
5451 var graphSubTitlePosY = 0; | |
5452 var footNoteHeight = 0; | |
5453 var footNotePosY = 0; | |
5454 var yAxisUnitHeight = 0; | |
5455 var yAxisUnitPosY = 0; | |
5456 var widestLegend = 0; | |
5457 var nbeltLegend = 0; | |
5458 var nbLegendLines = 0; | |
5459 var nbLegendCols = 0; | |
5460 var spaceLegendHeight = 0; | |
5461 var xFirstLegendTextPos = 0; | |
5462 var yFirstLegendTextPos = 0; | |
5463 var xLegendBorderPos = 0; | |
5464 var yLegendBorderPos = 0; | |
5465 var yAxisLabelWidth = 0; | |
5466 var yAxisLabelPosLeft = 0; | |
5467 var yAxisLabelPosRight = 0; | |
5468 var xAxisLabelHeight = 0; | |
5469 var xLabelHeight = 0; | |
5470 var widestXLabel = 1; | |
5471 var highestXLabel = 1; | |
5472 var widestYLabel = 0; | |
5473 var highestYLabel = 1; | |
5474 var widestYLabel2 = 0; | |
5475 var highestYLabel2 = 1; | |
5476 var leftNotUsableSize = 0; | |
5477 var rightNotUsableSize = 0; | |
5478 var rotateLabels = 0; | |
5479 var xLabelPos = 0; | |
5480 var legendBorderWidth = 0; | |
5481 var legendBorderHeight = 0; | |
5482 | |
5483 ctx.widthAtSetMeasures=width; | |
5484 ctx.heightAtSetMeasures=height; | |
5485 | |
5486 // Borders | |
5487 if (config.canvasBorders) borderWidth = config.canvasBordersWidt
h; | |
5488 // compute widest X label | |
5489 if (drawAxis) { | |
5490 ctx.font = config.scaleFontStyle + " " + config.scaleFon
tSize + "px " + config.scaleFontFamily; | |
5491 for (var i = 0; i < data.labels.length; i++) { | |
5492 var textMsr = ctx.measureTextMultiLine(fmtChartJ
S(config, data.labels[i], config.fmtXLabel), config.scaleFontSize); | |
5493 //If the text length is longer - make that equal
to longest text! | |
5494 widestXLabel = (textMsr.textWidth > widestXLabel
) ? textMsr.textWidth : widestXLabel; | |
5495 highestXLabel = (textMsr.textHeight > highestXLa
bel) ? textMsr.textHeight : highestXLabel; | |
5496 } | |
5497 if (widestXLabel < config.xScaleLabelsMinimumWidth) { | |
5498 widestXLabel = config.xScaleLabelsMinimumWidth; | |
5499 } | |
5500 } | |
5501 // compute Y Label Width | |
5502 if (drawAxis) { | |
5503 widestYLabel = 1; | |
5504 if (ylabels != null && ylabels != "nihil") { | |
5505 ctx.font = config.scaleFontStyle + " " + config.
scaleFontSize + "px " + config.scaleFontFamily; | |
5506 for (var i = ylabels.length - 1; i >= 0; i--) { | |
5507 if (typeof(ylabels[i]) == "string") { | |
5508 if (ylabels[i].trim() != "") { | |
5509 var textMsr = ctx.measur
eTextMultiLine(fmtChartJS(config, ylabels[i], config.fmtYLabel), config.scaleFon
tSize); | |
5510 //If the text length is
longer - make that equal to longest text! | |
5511 widestYLabel = (textMsr.
textWidth > widestYLabel) ? textMsr.textWidth : widestYLabel; | |
5512 highestYLabel = (textMsr
.textHeight > highestYLabel) ? textMsr.textHeight : highestYLabel; | |
5513 } | |
5514 } | |
5515 } | |
5516 } | |
5517 if (widestYLabel < config.yScaleLabelsMinimumWidth) { | |
5518 widestYLabel = config.yScaleLabelsMinimumWidth; | |
5519 } | |
5520 widestYLabel2 = 1; | |
5521 if (ylabels2 != null && config.yAxisRight) { | |
5522 ctx.font = config.scaleFontStyle + " " + config.
scaleFontSize + "px " + config.scaleFontFamily; | |
5523 for (var i = ylabels2.length - 1; i >= 0; i--) { | |
5524 if (typeof(ylabels2[i]) == "string") { | |
5525 if (ylabels2[i].trim() != "") { | |
5526 var textMsr = ctx.measur
eTextMultiLine(fmtChartJS(config, ylabels2[i], config.fmtYLabel2), config.scaleF
ontSize); | |
5527 //If the text length is
longer - make that equal to longest text! | |
5528 widestYLabel2 = (textMsr
.textWidth > widestYLabel2) ? textMsr.textWidth : widestYLabel2; | |
5529 highestYLabel2 = (textMs
r.textHeight > highestYLabel2) ? textMsr.textHeight : highestYLabel2; | |
5530 } | |
5531 } | |
5532 } | |
5533 } else { | |
5534 widestYLabel2 = widestYLabel; | |
5535 } | |
5536 if (widestYLabel2 < config.yScaleLabelsMinimumWidth) { | |
5537 widestYLabel2 = config.yScaleLabelsMinimumWidth; | |
5538 } | |
5539 } | |
5540 // yAxisLabel | |
5541 leftNotUsableSize = borderWidth + config.spaceLeft | |
5542 rightNotUsableSize = borderWidth + config.spaceRight; | |
5543 if (drawAxis) { | |
5544 if (typeof(config.yAxisLabel) != "undefined") { | |
5545 if (config.yAxisLabel.trim() != "") { | |
5546 yAxisLabelWidth = (config.yAxisFontSize
+ config.yAxisLabelSpaceLeft + config.yAxisLabelSpaceRight); | |
5547 yAxisLabelPosLeft = borderWidth + config
.spaceLeft + config.yAxisLabelSpaceLeft + config.yAxisFontSize; | |
5548 yAxisLabelPosRight = width - borderWidth
- config.spaceRight - config.yAxisLabelSpaceLeft - config.yAxisFontSize; | |
5549 } | |
5550 } | |
5551 if (config.yAxisLeft) { | |
5552 if (reverseAxis == false) leftNotUsableSize = bo
rderWidth + config.spaceLeft + yAxisLabelWidth + widestYLabel + config.yAxisSpac
eLeft + config.yAxisSpaceRight; | |
5553 else leftNotUsableSize = borderWidth + config.sp
aceLeft + yAxisLabelWidth + widestXLabel + config.yAxisSpaceLeft + config.yAxisS
paceRight; | |
5554 } | |
5555 if (config.yAxisRight) { | |
5556 if (reverseAxis == false) rightNotUsableSize = b
orderWidth + config.spaceRight + yAxisLabelWidth + widestYLabel2 + config.yAxisS
paceLeft + config.yAxisSpaceRight; | |
5557 else rightNotUsableSize = borderWidth + config.s
paceRight + yAxisLabelWidth + widestXLabel + config.yAxisSpaceLeft + config.yAxi
sSpaceRight; | |
5558 } | |
5559 } | |
5560 availableWidth = width - leftNotUsableSize - rightNotUsableSize; | |
5561 // Title | |
5562 if (config.graphTitle.trim() != "") { | |
5563 graphTitleHeight = (config.graphTitleFontSize + config.g
raphTitleSpaceBefore + config.graphTitleSpaceAfter); | |
5564 graphTitlePosY = borderWidth + config.spaceTop + graphTi
tleHeight - config.graphTitleSpaceAfter; | |
5565 } | |
5566 // subTitle | |
5567 if (config.graphSubTitle.trim() != "") { | |
5568 graphSubTitleHeight = (config.graphSubTitleFontSize + co
nfig.graphSubTitleSpaceBefore + config.graphSubTitleSpaceAfter); | |
5569 graphSubTitlePosY = borderWidth + config.spaceTop + grap
hTitleHeight + graphSubTitleHeight - config.graphSubTitleSpaceAfter; | |
5570 } | |
5571 // yAxisUnit | |
5572 if (drawAxis) { | |
5573 if (config.yAxisUnit.trim() != "") { | |
5574 yAxisUnitHeight = (config.yAxisUnitFontSize + co
nfig.yAxisUnitSpaceBefore + config.yAxisUnitSpaceAfter); | |
5575 yAxisUnitPosY = borderWidth + config.spaceTop +
graphTitleHeight + graphSubTitleHeight + yAxisUnitHeight - config.yAxisUnitSpace
After; | |
5576 } | |
5577 } | |
5578 topNotUsableSize = borderWidth + config.spaceTop + graphTitleHei
ght + graphSubTitleHeight + yAxisUnitHeight + config.graphSpaceBefore; | |
5579 // footNote | |
5580 if (typeof(config.footNote) != "undefined") { | |
5581 if (config.footNote.trim() != "") { | |
5582 footNoteHeight = (config.footNoteFontSize + conf
ig.footNoteSpaceBefore + config.footNoteSpaceAfter); | |
5583 footNotePosY = height - config.spaceBottom - bor
derWidth - config.footNoteSpaceAfter; | |
5584 } | |
5585 } | |
5586 | |
5587 // xAxisLabel | |
5588 if (drawAxis) { | |
5589 if (typeof(config.xAxisLabel) != "undefined") { | |
5590 if (config.xAxisLabel.trim() != "") { | |
5591 xAxisLabelHeight = (config.xAxisFontSize
+ config.xAxisLabelSpaceBefore + config.xAxisLabelSpaceAfter); | |
5592 xAxisLabelPos = height - borderWidth - c
onfig.spaceBottom - footNoteHeight - config.xAxisLabelSpaceAfter; | |
5593 } | |
5594 } | |
5595 } | |
5596 | |
5597 bottomNotUsableHeightWithoutXLabels = borderWidth + config.space
Bottom + footNoteHeight + xAxisLabelHeight + config.graphSpaceAfter; | |
5598 | |
5599 // compute space for Legend | |
5600 if (typeof(config.legend) != "undefined") { | |
5601 if (config.legend == true) { | |
5602 ctx.font = config.legendFontStyle + " " + config
.legendFontSize + "px " + config.legendFontFamily; | |
5603 if (drawLegendOnData) { | |
5604 for (var i = data.datasets.length - 1; i
>= 0; i--) { | |
5605 if (typeof(data.datasets[i].titl
e) == "string") { | |
5606 if (data.datasets[i].tit
le.trim() != "") { | |
5607 nbeltLegend++; | |
5608 var textLength =
ctx.measureText(fmtChartJS(config, data.datasets[i].title, config.fmtLegend)).w
idth; | |
5609 //If the text le
ngth is longer - make that equal to longest text! | |
5610 widestLegend = (
textLength > widestLegend) ? textLength : widestLegend; | |
5611 } | |
5612 } | |
5613 } | |
5614 } else { | |
5615 for (var i = data.length - 1; i >= 0; i-
-) { | |
5616 if (typeof(data[i].title) == "st
ring") { | |
5617 if (data[i].title.trim()
!= "") { | |
5618 nbeltLegend++; | |
5619 var textLength =
ctx.measureText(fmtChartJS(config, data[i].title, config.fmtLegend)).width; | |
5620 //If the text le
ngth is longer - make that equal to longest text! | |
5621 widestLegend = (
textLength > widestLegend) ? textLength : widestLegend; | |
5622 } | |
5623 } | |
5624 } | |
5625 } | |
5626 if (nbeltLegend > 1 || (nbeltLegend == 1 && conf
ig.showSingleLegend)) { | |
5627 widestLegend += config.legendBlockSize +
config.legendSpaceBetweenBoxAndText; | |
5628 if(config.legendPosY==1 || config.legend
PosY==2 || config.legendPosY==3) { | |
5629 availableLegendWidth = available
Width- config.legendSpaceLeftText - config.legendSpaceRightText; | |
5630 } else { | |
5631 availableLegendWidth = width - c
onfig.spaceLeft - config.spaceRight - 2 * (borderWidth) - config.legendSpaceLeft
Text - config.legendSpaceRightText; | |
5632 } | |
5633 if (config.legendBorders == true) availa
bleLegendWidth -= 2 * (config.legendBordersWidth) - config.legendBordersSpaceLef
t - config.legendBordersSpaceRight; | |
5634 maxLegendOnLine = Min([Math.floor((avail
ableLegendWidth + config.legendSpaceBetweenTextHorizontal) / (widestLegend + con
fig.legendSpaceBetweenTextHorizontal)),config.maxLegendCols]); | |
5635 nbLegendLines = Math.ceil(nbeltLegend /
maxLegendOnLine); | |
5636 nbLegendCols = Math.ceil(nbeltLegend / n
bLegendLines); | |
5637 | |
5638 var legendHeight = nbLegendLines * (conf
ig.legendFontSize + config.legendSpaceBetweenTextVertical) - config.legendSpaceB
etweenTextVertical + config.legendSpaceBeforeText + config.legendSpaceAfterText; | |
5639 if (config.legendBorders == true) { | |
5640 // legendHeight += 2 * config.legen
dBordersWidth + config.legendBordersSpaceBefore + config.legendBordersSpaceAfter
; | |
5641 } | |
5642 | |
5643 switch (config.legendPosY) { | |
5644 case 0: | |
5645 xFirstLegendTextPos = co
nfig.spaceLeft + (width - config.spaceLeft - config.spaceRight - nbLegendCols *
(widestLegend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBet
weenTextHorizontal) / 2; | |
5646 spaceLegendHeight = lege
ndHeight; | |
5647 if (config.legendBorders
== true) { | |
5648 yLegendBorderPos
= topNotUsableSize + config.legendBordersSpaceBefore + (config.legendBordersWid
th/2); | |
5649 yFirstLegendText
Pos = yLegendBorderPos + (config.legendBordersWidth/2) + config.legendSpaceBefo
reText+config.legendFontSize; | |
5650 spaceLegendHeigh
t += 2 * config.legendBordersWidth + config.legendBordersSpaceBefore + config.le
gendBordersSpaceAfter; | |
5651 xLegendBorderPos
= Math.floor(xFirstLegendTextPos - config.legendSpaceLeftText - (config.legendB
ordersWidth / 2)); | |
5652 legendBorderHeig
ht = Math.ceil(spaceLegendHeight - config.legendBordersWidth) - config.legendBor
dersSpaceBefore - config.legendBordersSpaceAfter; | |
5653 legendBorderWidt
h = Math.ceil(nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizo
ntal)) - config.legendSpaceBetweenTextHorizontal + config.legendBordersWidth + c
onfig.legendSpaceRightText + config.legendSpaceLeftText; | |
5654 } else { | |
5655 yFirstLegendText
Pos = topNotUsableSize + config.legendBordersSpaceBefore + (config.legendBorders
Width/2); | |
5656 } | |
5657 if(yAxisUnitHeight>0) { | |
5658 yAxisUnitPosY+=s
paceLegendHeight; | |
5659 if(config.legend
Borders==true)yLegendBorderPos-=yAxisUnitHeight; | |
5660 yFirstLegendText
Pos-=yAxisUnitHeight; | |
5661 } | |
5662 topNotUsableSize += spac
eLegendHeight; | |
5663 break; | |
5664 case 1: | |
5665 spaceLegendHeight = lege
ndHeight; | |
5666 xFirstLegendTextPos = co
nfig.spaceLeft + (width - config.spaceLeft - config.spaceRight - nbLegendCols *
(widestLegend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBet
weenTextHorizontal) / 2; | |
5667 yFirstLegendTextPos = to
pNotUsableSize + config.legendSpaceBeforeText+config.legendFontSize; | |
5668 if (config.legendBorders
== true) { | |
5669 yFirstLegendText
Pos += config.legendBordersSpaceBefore+config.legendBordersWidth; | |
5670 yLegendBorderPos
= yFirstLegendTextPos - config.legendSpaceBeforeText - config.legendFontSize -
(config.legendBordersWidth /2 ); | |
5671 spaceLegendHeigh
t += 2 * config.legendBordersWidth + config.legendBordersSpaceBefore + config.le
gendBordersSpaceAfter; | |
5672 xLegendBorderPos
= Math.floor(xFirstLegendTextPos - config.legendSpaceLeftText - (config.legendB
ordersWidth / 2)); | |
5673 legendBorderHeig
ht = Math.ceil(spaceLegendHeight - config.legendBordersWidth) - config.legendBor
dersSpaceBefore - config.legendBordersSpaceAfter; | |
5674 legendBorderWidt
h = Math.ceil(nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizo
ntal)) - config.legendSpaceBetweenTextHorizontal + config.legendBordersWidth + c
onfig.legendSpaceRightText + config.legendSpaceLeftText; | |
5675 } | |
5676 break; | |
5677 case 2: | |
5678 spaceLegendHeight = lege
ndHeight; | |
5679 xFirstLegendTextPos = co
nfig.spaceLeft + (width - config.spaceLeft - config.spaceRight - nbLegendCols *
(widestLegend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBet
weenTextHorizontal) / 2; | |
5680 yFirstLegendTextPos = to
pNotUsableSize + (height - topNotUsableSize - bottomNotUsableHeightWithoutXLabel
s - spaceLegendHeight) /2 + config.legendSpaceBeforeText+config.legendFontSize; | |
5681 if (config.legendBorders
== true) { | |
5682 yFirstLegendText
Pos += config.legendBordersSpaceBefore - config.legendBordersSpaceAfter; | |
5683 yLegendBorderPos
= yFirstLegendTextPos - config.legendSpaceBeforeText - config.legendFontSize -
(config.legendBordersWidth /2 ); | |
5684 spaceLegendHeigh
t += 2 * config.legendBordersWidth + config.legendBordersSpaceBefore + config.le
gendBordersSpaceAfter; | |
5685 xLegendBorderPos
= Math.floor(xFirstLegendTextPos - config.legendSpaceLeftText - (config.legendB
ordersWidth / 2)); | |
5686 legendBorderHeig
ht = Math.ceil(spaceLegendHeight - config.legendBordersWidth) - config.legendBor
dersSpaceBefore - config.legendBordersSpaceAfter; | |
5687 legendBorderWidt
h = Math.ceil(nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizo
ntal)) - config.legendSpaceBetweenTextHorizontal + config.legendBordersWidth + c
onfig.legendSpaceRightText + config.legendSpaceLeftText; | |
5688 } | |
5689 break; | |
5690 case 3: | |
5691 spaceLegendHeight = lege
ndHeight; | |
5692 xFirstLegendTextPos = co
nfig.spaceLeft + (width - config.spaceLeft - config.spaceRight - nbLegendCols *
(widestLegend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBet
weenTextHorizontal) / 2; | |
5693 availableHeight = height
- topNotUsableSize - bottomNotUsableHeightWithoutXLabels; | |
5694 yFirstLegendTextPos = to
pNotUsableSize + availableHeight - spaceLegendHeight + config.legendSpaceBeforeT
ext+config.legendFontSize; | |
5695 if (config.legendBorders
== true) { | |
5696 yFirstLegendText
Pos -= (config.legendBordersSpaceAfter+config.legendBordersWidth); | |
5697 yLegendBorderPos
= yFirstLegendTextPos - config.legendSpaceBeforeText - config.legendFontSize -
(config.legendBordersWidth /2 ); | |
5698 spaceLegendHeigh
t += 2 * config.legendBordersWidth + config.legendBordersSpaceBefore + config.le
gendBordersSpaceAfter; | |
5699 xLegendBorderPos
= Math.floor(xFirstLegendTextPos - config.legendSpaceLeftText - (config.legendB
ordersWidth / 2)); | |
5700 legendBorderHeig
ht = Math.ceil(spaceLegendHeight - config.legendBordersWidth) - config.legendBor
dersSpaceBefore - config.legendBordersSpaceAfter; | |
5701 legendBorderWidt
h = Math.ceil(nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizo
ntal)) - config.legendSpaceBetweenTextHorizontal + config.legendBordersWidth + c
onfig.legendSpaceRightText + config.legendSpaceLeftText; | |
5702 } | |
5703 break; | |
5704 default: | |
5705 spaceLegendHeight = lege
ndHeight; | |
5706 yFirstLegendTextPos = he
ight - borderWidth - config.spaceBottom - footNoteHeight - spaceLegendHeight + c
onfig.legendSpaceBeforeText + config.legendFontSize; | |
5707 xFirstLegendTextPos = co
nfig.spaceLeft + (width - config.spaceLeft - config.spaceRight - nbLegendCols *
(widestLegend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBet
weenTextHorizontal) / 2; | |
5708 if (config.legendBorders
== true) { | |
5709 spaceLegendHeigh
t += 2 * config.legendBordersWidth + config.legendBordersSpaceBefore + config.le
gendBordersSpaceAfter; | |
5710 yFirstLegendText
Pos -= (config.legendBordersWidth + config.legendBordersSpaceAfter); | |
5711 yLegendBorderPos
= Math.floor(height - borderWidth - config.spaceBottom - footNoteHeight - space
LegendHeight + (config.legendBordersWidth / 2) + config.legendBordersSpaceBefore
); | |
5712 xLegendBorderPos
= Math.floor(xFirstLegendTextPos - config.legendSpaceLeftText - (config.legendB
ordersWidth / 2)); | |
5713 legendBorderHeig
ht = Math.ceil(spaceLegendHeight - config.legendBordersWidth) - config.legendBor
dersSpaceBefore - config.legendBordersSpaceAfter; | |
5714 legendBorderWidt
h = Math.ceil(nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizo
ntal)) - config.legendSpaceBetweenTextHorizontal + config.legendBordersWidth + c
onfig.legendSpaceRightText + config.legendSpaceLeftText; | |
5715 } | |
5716 xAxisLabelPos -= spaceLe
gendHeight; | |
5717 // xLabelPos -= spaceLegend
Height; | |
5718 bottomNotUsableHeightWit
houtXLabels +=spaceLegendHeight; | |
5719 break; | |
5720 } | |
5721 var fullLegendWidth=config.legendSpaceRi
ghtText + nbLegendCols * (widestLegend + config.legendSpaceBetweenTextHorizontal
) - config.legendSpaceBetweenTextHorizontal +config.legendSpaceLeftText; | |
5722 if (config.legendBorders == true) { | |
5723 fullLegendWidth+=2*config.legend
BordersWidth+config.legendBordersSpaceLeft+config.legendBordersSpaceRight; | |
5724 } | |
5725 | |
5726 switch (config.legendPosX) { | |
5727 case 0: | |
5728 xFirstLegendTextPos = co
nfig.spaceLeft + config.canvasBorders * config.canvasBordersWidth + config.legen
dSpaceLeftText; | |
5729 if (config.legendBorders
== true) { | |
5730 xFirstLegendText
Pos += config.legendBordersWidth+config.legendBordersSpaceLeft; | |
5731 xLegendBorderPos
= config.spaceLeft + config.canvasBorders * config.canvasBordersWidth + config.
legendBordersSpaceLeft; | |
5732 } | |
5733 if(config.legendPosY>=1
&& config.legendPosY <=3) { | |
5734 leftNotUsableSiz
e+=fullLegendWidth; | |
5735 yAxisLabelPosLef
t+=fullLegendWidth; | |
5736 } | |
5737 break; | |
5738 case 1: | |
5739 xFirstLegendTextPos = le
ftNotUsableSize + config.legendSpaceLeftText; | |
5740 if (config.legendBorders
== true) { | |
5741 xLegendBorderPos
= xFirstLegendTextPos; | |
5742 xFirstLegendText
Pos += config.legendBordersWidth+config.legendBordersSpaceLeft; | |
5743 } | |
5744 break; | |
5745 case 2: | |
5746 xFirstLegendTextPos = le
ftNotUsableSize + (width - rightNotUsableSize - leftNotUsableSize)/2 - (config.l
egendSpaceLeftText-config.legendSpaceRightText) - (nbLegendCols * (widestLegend
+ config.legendSpaceBetweenTextHorizontal) - config.legendSpaceBetweenTextHorizo
ntal) / 2; | |
5747 if (config.legendBorders
== true) { | |
5748 xFirstLegendText
Pos -= (config.legendBordersWidth + config.legendBordersSpaceRight); | |
5749 xLegendBorderPos
= xFirstLegendTextPos - config.legendBordersWidth/2 - config.legendSpaceLeftTex
t ; | |
5750 } | |
5751 break; | |
5752 case 3: | |
5753 | |
5754 xFirstLegendTextPos = wi
dth - rightNotUsableSize - config.legendSpaceRightText - nbLegendCols * (widestL
egend + config.legendSpaceBetweenTextHorizontal) + config.legendSpaceBetweenText
Horizontal / 2; | |
5755 if (config.legendBorders
== true) { | |
5756 xFirstLegendText
Pos -= (config.legendBordersWidth + config.legendBordersSpaceRight); | |
5757 xLegendBorderPos
= xFirstLegendTextPos - config.legendBordersWidth/2 - config.legendSpaceLeftTex
t ; | |
5758 } | |
5759 break; | |
5760 case 4: | |
5761 xFirstLegendTextPos = wi
dth - config.spaceRight - config.canvasBorders * config.canvasBordersWidth - con
fig.legendSpaceRightText - nbLegendCols * (widestLegend + config.legendSpaceBetw
eenTextHorizontal) + config.legendSpaceBetweenTextHorizontal / 2; | |
5762 if (config.legendBorders
== true) { | |
5763 xFirstLegendText
Pos -= (config.legendBordersWidth+config.legendBordersSpaceRight); | |
5764 xLegendBorderPos
= xFirstLegendTextPos - config.legendBordersSpaceLeft - config.legendBordersWid
th/2; | |
5765 } | |
5766 if(config.legendPosY>=1
&& config.legendPosY <=3) { | |
5767 rightNotUsableSi
ze+=fullLegendWidth; | |
5768 yAxisLabelPosRig
ht-=fullLegendWidth; | |
5769 } | |
5770 break; | |
5771 | |
5772 default: | |
5773 break; | |
5774 } | |
5775 if(config.legendBorders==true) { | |
5776 yLegendBorderPos+=config.legendY
Padding; | |
5777 xLegendBorderPos+=config.legendX
Padding; | |
5778 | |
5779 } | |
5780 yFirstLegendTextPos+=config.legendYPaddi
ng; | |
5781 xFirstLegendTextPos+=config.legendXPaddi
ng; | |
5782 | |
5783 } | |
5784 } | |
5785 } | |
5786 xLabelWidth = 0; | |
5787 bottomNotUsableHeightWithXLabels = bottomNotUsableHeightWithoutX
Labels; | |
5788 if (drawAxis && (config.xAxisBottom || config.xAxisTop)) { | |
5789 if (reverseAxis == false) { | |
5790 var widestLabel = widestXLabel; | |
5791 var highestLabel = highestXLabel; | |
5792 nblab = data.labels.length; | |
5793 } else { | |
5794 var widestLabel = widestYLabel; | |
5795 var highestLabel = highestYLabel; | |
5796 nblab = ylabels.length; | |
5797 } | |
5798 if (config.rotateLabels == "smart") { | |
5799 rotateLabels = 0; | |
5800 if ((availableWidth + config.xAxisSpaceBetweenLa
bels) / nblab < (widestLabel + config.xAxisSpaceBetweenLabels)) { | |
5801 rotateLabels = 45; | |
5802 if (availableWidth / nblab < Math.abs(Ma
th.cos(rotateLabels * Math.PI / 180) * widestLabel)) { | |
5803 rotateLabels = 90; | |
5804 } | |
5805 } | |
5806 } else { | |
5807 rotateLabels = config.rotateLabels | |
5808 if (rotateLabels < 0) rotateLabels = 0; | |
5809 if (rotateLabels > 180) rotateLabels = 180; | |
5810 } | |
5811 if (rotateLabels > 90) rotateLabels += 180; | |
5812 xLabelHeight = Math.abs(Math.sin(rotateLabels * Math.PI
/ 180) * widestLabel) + Math.abs(Math.sin((rotateLabels + 90) * Math.PI / 180) *
highestLabel) + config.xAxisSpaceBefore + config.xAxisSpaceAfter; | |
5813 xLabelPos = height - borderWidth - config.spaceBottom -
footNoteHeight - xAxisLabelHeight - (xLabelHeight - config.xAxisSpaceBefore) - c
onfig.graphSpaceAfter; | |
5814 xLabelWidth = Math.abs(Math.cos(rotateLabels * Math.PI /
180) * widestLabel) + Math.abs(Math.cos((rotateLabels + 90) * Math.PI / 180) *
highestLabel); | |
5815 leftNotUsableSize = Max([leftNotUsableSize, borderWidth
+ config.spaceLeft + xLabelWidth / 2]); | |
5816 rightNotUsableSize = Max([rightNotUsableSize, borderWidt
h + config.spaceRight + xLabelWidth / 2]); | |
5817 availableWidth = width - leftNotUsableSize - rightNotUsa
bleSize; | |
5818 if (config.legend && config.xAxisBottom && config.legend
PosY==4) { | |
5819 xLabelPos-=spaceLegendHeight; | |
5820 } | |
5821 bottomNotUsableHeightWithXLabels = bottomNotUsableHeight
WithoutXLabels + xLabelHeight ; | |
5822 } else { | |
5823 availableWidth = width - leftNotUsableSize - rightNotUsa
bleSize; | |
5824 } | |
5825 | |
5826 availableHeight = height - topNotUsableSize - bottomNotUsableHei
ghtWithXLabels; | |
5827 | |
5828 // ----------------------- DRAW EXTERNAL ELEMENTS --------------
----------------------------------- | |
5829 dispCrossImage(ctx, config, width / 2, height / 2, width / 2, he
ight / 2, false, data, -1, -1); | |
5830 if (ylabels != "nihil") { | |
5831 // Draw Borders | |
5832 if (borderWidth > 0) { | |
5833 ctx.save(); | |
5834 ctx.beginPath(); | |
5835 ctx.lineWidth = 2 * borderWidth; | |
5836 ctx.strokeStyle = config.canvasBordersColor; | |
5837 ctx.moveTo(0, 0); | |
5838 ctx.lineTo(0, height); | |
5839 ctx.lineTo(width, height); | |
5840 ctx.lineTo(width, 0); | |
5841 ctx.lineTo(0, 0); | |
5842 ctx.stroke(); | |
5843 ctx.restore(); | |
5844 } | |
5845 // Draw Graph Title | |
5846 if (graphTitleHeight > 0) { | |
5847 ctx.save(); | |
5848 ctx.beginPath(); | |
5849 ctx.font = config.graphTitleFontStyle + " " + co
nfig.graphTitleFontSize + "px " + config.graphTitleFontFamily; | |
5850 ctx.fillStyle = config.graphTitleFontColor; | |
5851 ctx.textAlign = "center"; | |
5852 ctx.textBaseline = "bottom"; | |
5853 ctx.translate(config.spaceLeft + (width - config
.spaceLeft - config.spaceRight) / 2, graphTitlePosY); | |
5854 ctx.fillText(config.graphTitle, 0, 0); | |
5855 ctx.stroke(); | |
5856 ctx.restore(); | |
5857 } | |
5858 // Draw Graph Sub-Title | |
5859 if (graphSubTitleHeight > 0) { | |
5860 ctx.save(); | |
5861 ctx.beginPath(); | |
5862 ctx.font = config.graphSubTitleFontStyle + " " +
config.graphSubTitleFontSize + "px " + config.graphSubTitleFontFamily; | |
5863 ctx.fillStyle = config.graphSubTitleFontColor; | |
5864 ctx.textAlign = "center"; | |
5865 ctx.textBaseline = "bottom"; | |
5866 ctx.translate(config.spaceLeft + (width - config
.spaceLeft - config.spaceRight) / 2, graphSubTitlePosY); | |
5867 ctx.fillText(config.graphSubTitle, 0, 0); | |
5868 ctx.stroke(); | |
5869 ctx.restore(); | |
5870 } | |
5871 // Draw Y Axis Unit | |
5872 if (yAxisUnitHeight > 0) { | |
5873 if (config.yAxisLeft) { | |
5874 ctx.save(); | |
5875 ctx.beginPath(); | |
5876 ctx.font = config.yAxisUnitFontStyle + "
" + config.yAxisUnitFontSize + "px " + config.yAxisUnitFontFamily; | |
5877 ctx.fillStyle = config.yAxisUnitFontColo
r; | |
5878 ctx.textAlign = "center"; | |
5879 ctx.textBaseline = "bottom"; | |
5880 ctx.translate(leftNotUsableSize, yAxisUn
itPosY); | |
5881 ctx.fillText(config.yAxisUnit, 0, 0); | |
5882 ctx.stroke(); | |
5883 ctx.restore(); | |
5884 } | |
5885 if (config.yAxisRight) { | |
5886 if (config.yAxisUnit2 == '') config.yAxi
sUnit2 = config.yAxisUnit; | |
5887 ctx.save(); | |
5888 ctx.beginPath(); | |
5889 ctx.font = config.yAxisUnitFontStyle + "
" + config.yAxisUnitFontSize + "px " + config.yAxisUnitFontFamily; | |
5890 ctx.fillStyle = config.yAxisUnitFontColo
r; | |
5891 ctx.textAlign = "center"; | |
5892 ctx.textBaseline = "bottom"; | |
5893 ctx.translate(width - rightNotUsableSize
, yAxisUnitPosY); | |
5894 ctx.fillText(config.yAxisUnit2, 0, 0); | |
5895 ctx.stroke(); | |
5896 ctx.restore(); | |
5897 } | |
5898 } | |
5899 // Draw Y Axis Label | |
5900 if (yAxisLabelWidth > 0) { | |
5901 if (config.yAxisLeft) { | |
5902 ctx.save(); | |
5903 ctx.beginPath(); | |
5904 ctx.font = config.yAxisFontStyle + " " +
config.yAxisFontSize + "px " + config.yAxisFontFamily; | |
5905 ctx.fillStyle = config.yAxisFontColor; | |
5906 ctx.textAlign = "center"; | |
5907 ctx.textBaseline = "bottom"; | |
5908 ctx.translate(yAxisLabelPosLeft, topNotU
sableSize + (availableHeight / 2)); | |
5909 ctx.rotate(-(90 * (Math.PI / 180))); | |
5910 ctx.fillText(config.yAxisLabel, 0, 0); | |
5911 ctx.stroke(); | |
5912 ctx.restore(); | |
5913 } | |
5914 if (config.yAxisRight) { | |
5915 if (config.yAxisLabel2 == '') config.yAx
isLabel2 = config.yAxisLabel; | |
5916 ctx.save(); | |
5917 ctx.beginPath(); | |
5918 ctx.font = config.yAxisFontStyle + " " +
config.yAxisFontSize + "px " + config.yAxisFontFamily; | |
5919 ctx.fillStyle = config.yAxisFontColor; | |
5920 ctx.textAlign = "center"; | |
5921 ctx.textBaseline = "bottom"; | |
5922 ctx.translate(yAxisLabelPosRight, topNot
UsableSize + (availableHeight / 2)); | |
5923 ctx.rotate(+(90 * (Math.PI / 180))); | |
5924 ctx.fillText(config.yAxisLabel2, 0, 0); | |
5925 ctx.stroke(); | |
5926 ctx.restore(); | |
5927 } | |
5928 } | |
5929 // Draw X Axis Label | |
5930 if (xAxisLabelHeight > 0) { | |
5931 if (config.xAxisBottom) { | |
5932 ctx.save(); | |
5933 ctx.beginPath(); | |
5934 ctx.font = config.xAxisFontStyle + " " +
config.xAxisFontSize + "px " + config.xAxisFontFamily; | |
5935 ctx.fillStyle = config.xAxisFontColor; | |
5936 ctx.textAlign = "center"; | |
5937 ctx.textBaseline = "bottom"; | |
5938 ctx.translate(leftNotUsableSize + (avail
ableWidth / 2), xAxisLabelPos); | |
5939 ctx.fillText(config.xAxisLabel, 0, 0); | |
5940 ctx.stroke(); | |
5941 ctx.restore(); | |
5942 } | |
5943 } | |
5944 // Draw Legend | |
5945 | |
5946 if (nbeltLegend > 1 || (nbeltLegend == 1 && config.showS
ingleLegend)) { | |
5947 var legendMsr={dispLegend : true, xLegendBorderP
os : xLegendBorderPos, | |
5948 yLegendBorderPos : yLegendBorderPos,
legendBorderWidth : legendBorderWidth, legendBorderHeight : legendBorderHeight, | |
5949 nbLegendCols: nbLegendCols, xFirstLeg
endTextPos : xFirstLegendTextPos , yFirstLegendTextPos : yFirstLegendTextPos, | |
5950 drawLegendOnData : drawLegendOnData,
reverseLegend : reverseLegend, legendBox : legendBox, widestLegend : widestLegen
d }; | |
5951 if(config.legendPosY==0 || config.legendPosY==4)
{ | |
5952 drawLegend(legendMsr,data,config,ctx,typ
egraph); | |
5953 var legendMsr={dispLegend : false}; | |
5954 } | |
5955 } else { | |
5956 var legendMsr={dispLegend : false }; | |
5957 } | |
5958 // Draw FootNote | |
5959 if (config.footNote.trim() != "") { | |
5960 ctx.save(); | |
5961 ctx.font = config.footNoteFontStyle + " " + conf
ig.footNoteFontSize + "px " + config.footNoteFontFamily; | |
5962 ctx.fillStyle = config.footNoteFontColor; | |
5963 ctx.textAlign = "center"; | |
5964 ctx.textBaseline = "bottom"; | |
5965 ctx.translate(leftNotUsableSize + (availableWidt
h / 2), footNotePosY); | |
5966 ctx.fillText(config.footNote, 0, 0); | |
5967 ctx.stroke(); | |
5968 ctx.restore(); | |
5969 } | |
5970 } | |
5971 clrx = leftNotUsableSize; | |
5972 clrwidth = availableWidth; | |
5973 clry = topNotUsableSize; | |
5974 clrheight = availableHeight; | |
5975 return { | |
5976 leftNotUsableSize: leftNotUsableSize, | |
5977 rightNotUsableSize: rightNotUsableSize, | |
5978 availableWidth: availableWidth, | |
5979 topNotUsableSize: topNotUsableSize, | |
5980 bottomNotUsableHeightWithoutXLabels: bottomNotUsableHeig
htWithoutXLabels, | |
5981 bottomNotUsableHeightWithXLabels: bottomNotUsableHeightW
ithXLabels, | |
5982 availableHeight: availableHeight, | |
5983 widestXLabel: widestXLabel, | |
5984 highestXLabel: highestXLabel, | |
5985 widestYLabel: widestYLabel, | |
5986 widestYLabel2: widestYLabel2, | |
5987 highestYLabel: highestYLabel, | |
5988 rotateLabels: rotateLabels, | |
5989 xLabelPos: xLabelPos, | |
5990 clrx: clrx, | |
5991 clry: clry, | |
5992 clrwidth: clrwidth, | |
5993 clrheight: clrheight, | |
5994 legendMsr : legendMsr | |
5995 }; | |
5996 }; | |
5997 // Function for additionalLine (BarLine|Line) | |
5998 function drawLinesDataset(axis, animPc, data, config, ctx, offsets, vars
) { | |
5999 var xAxisPosY = vars.xAxisPosY; | |
6000 var yAxisPosX = vars.yAxisPosX; | |
6001 var valueHop = vars.valueHop; | |
6002 var nbValueHop = vars.nbValueHop; | |
6003 var scaleHop = vars.scaleHop; | |
6004 var zeroY = vars.zeroY; | |
6005 var calculatedScale = vars.calculatedScale; | |
6006 var logarithmic = vars.logarithmic; | |
6007 var currentAnimPc = animationCorrection(animPc, data, config, 0,
0, 0); | |
6008 var totvalue = new Array(); | |
6009 var maxvalue = new Array(); | |
6010 var lmaxvalue = new Array(); | |
6011 var lminvalue = new Array(); | |
6012 for (var i = 0; i < data.datasets.length; i++) { | |
6013 lmaxvalue[i] = -999999999; | |
6014 lminvalue[i] = 999999999; | |
6015 if ((axis == 2 && data.datasets[i].axis == 2) || (axis !
= 2 && data.datasets[i].axis != 2)) { | |
6016 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
6017 totvalue[j] = 0; | |
6018 maxvalue[j] = -999999999; | |
6019 } | |
6020 } | |
6021 } | |
6022 currentAnimPc.mainVal = 1; | |
6023 for (var i = 0; i < data.datasets.length; i++) { | |
6024 if ((axis == 2 && data.datasets[i].axis == 2) || (axis !
= 2 && data.datasets[i].axis != 2)) { | |
6025 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
6026 totvalue[j] += data.datasets[i].data[j]; | |
6027 maxvalue[j] = Max([maxvalue[j], data.dat
asets[i].data[j]]); | |
6028 lmaxvalue[i] = Max([lmaxvalue[i], yPos(i
, j)]); | |
6029 lminvalue[i] = Min([lminvalue[i], yPos(i
, j)]); | |
6030 } | |
6031 } | |
6032 } | |
6033 for (var i = 0; i < data.datasets.length; i++) { | |
6034 if ((axis == 2 && data.datasets[i].axis == 2) || (axis !
= 2 && data.datasets[i].axis != 2)) { | |
6035 var prevpt = -1; | |
6036 var frstpt = -1; | |
6037 if (typeof data.datasets[i].strokeColor == "func
tion") { | |
6038 ctx.strokeStyle = data.datasets[i].strok
eColor("STROKECOLOR", data, config, i, -1, animPc, -1, "Line", ctx, yAxisPosX, l
maxvalue[i], yAxisPosX + valueHop * (data.datasets[i].data.length - 1), lmaxvalu
e[i] - ((config.animationLeftToRight) ? 1 : 1*currentAnimPc.mainVal) * (lmaxvalu
e[i] - lminvalue[i])); | |
6039 } else if (typeof data.datasets[i].strokeColor =
= "string") { | |
6040 ctx.strokeStyle = data.datasets[i].strok
eColor; | |
6041 } else ctx.strokeStyle = config.defaultStrokeCol
or; | |
6042 ctx.lineWidth = config.datasetStrokeWidth; | |
6043 ctx.beginPath(); | |
6044 var prevAnimPc; | |
6045 var prevXpos; | |
6046 prevAnimPc = 0; | |
6047 prevnotempty = 0; | |
6048 for (var j = 0; j < data.datasets[i].data.length
; j++) { | |
6049 var xposj = xPos(i, j, data); | |
6050 currentAnimPc = animationCorrection(anim
Pc, data, config, i, j, 0); | |
6051 if (currentAnimPc.mainVal == 0 && prevAn
imPc > 0) { | |
6052 ctx.stroke(); | |
6053 ctx.strokeStyle = "rgba(0,0,0,0)
"; | |
6054 // ctx.lineWidth =0.01;
| |
6055 ctx.lineTo(prevXpos, xAxisPosY -
zeroY); | |
6056 } | |
6057 prevAnimPc = currentAnimPc.mainVal; | |
6058 if (currentAnimPc.mainVal >= 1) { | |
6059 if (typeof(data.datasets[i].titl
e) == "string") lgtxt = data.datasets[i].title.trim(); | |
6060 else lgtxt = ""; | |
6061 } | |
6062 if (!(typeof(data.datasets[i].data[j]) =
= 'undefined')) { | |
6063 prevXpos = xPos(i, j, data); | |
6064 if (prevpt == -1) { | |
6065 ctx.moveTo(xposj, yPos(i
, j)); | |
6066 frstpt = j; | |
6067 } else { | |
6068 if (config.bezierCurve)
{ | |
6069 ctx.bezierCurveT
o(xPos(i, j - (j - prevpt) / 2, data), yPos(i, prevpt), xPos(i, j - (j - prevpt)
/ 2, data), yPos(i, j), xPos(i, j, data), yPos(i, j)); | |
6070 } else { | |
6071 ctx.lineTo(xPos(
i, j, data), yPos(i, j)); | |
6072 } | |
6073 } | |
6074 if ((typeof(data.datasets[i].dat
a[j + 1]) !== 'undefined') || (true == config.extrapolateMissingData)) { | |
6075 if (currentAnimPc.subVal
> 0) { | |
6076 // next not miss
ing value | |
6077 nxtnotmiss = -1; | |
6078 for (t = j + 1;
t < data.datasets[i].data["length"] && nxtnotmiss == -1; t++) { | |
6079 if (!(ty
peof(data.datasets[i].data[t]) == 'undefined')) nxtnotmiss = t; | |
6080 } | |
6081 if (nxtnotmiss !
= -1) { | |
6082 prevXpos
= xPos(i, j + currentAnimPc.subVal, data); | |
6083 if (conf
ig.bezierCurve) { | |
6084
ctx.bezierCurveTo(xPos(i, j + currentAnimPc.subVal / 2, data), yPos(i, j), xPos(
i, j + currentAnimPc.subVal / 2, data), yPos(i, nxtnotmiss), xPos(i, j + current
AnimPc.subVal, data), yPos(i, nxtnotmiss)); | |
6085 } else { | |
6086
ctx.lineTo(xPos(i, j + currentAnimPc.subVal, data), yPos(i, j + 1)); | |
6087 } | |
6088 } | |
6089 } | |
6090 prevpt = j; | |
6091 if (animPc >= 1) { | |
6092 if (i == 0) divp
rev = data.datasets[i].data[j]; | |
6093 else divprev = d
ata.datasets[i].data[j] - data.datasets[i - 1].data[j]; | |
6094 if (i == data.da
tasets.length - 1) divnext = data.datasets[i].data[j]; | |
6095 else divnext = d
ata.datasets[i].data[j] - data.datasets[i + 1].data[j]; | |
6096 lgtxt2 = ""; | |
6097 if (typeof data.
datasets[i].xPos != "undefined") { | |
6098 if (!(ty
peof data.datasets[i].xPos[j] == "undefined")) lgtxt2 = data.datasets[i].xPos[j]
; | |
6099 } | |
6100 if (lgtxt2 == ""
&& !(typeof(data.labels[j]) == "undefined")) lgtxt2 = data.labels[j]; | |
6101 if (typeof lgtxt
2 == "string") lgtxt2 = lgtxt2.trim(); | |
6102 jsGraphAnnotate[
ctx.ChartNewId][jsGraphAnnotate[ctx.ChartNewId].length] = ["POINT", xPos(i, j, d
ata), yPos(i, j), lgtxt, lgtxt2, 1 * data.datasets[i].data[j], divprev, divnext,
maxvalue[j], totvalue[j], i, j]; | |
6103 if (config.inGra
phDataShow) { | |
6104 ctx.save
(); | |
6105 ctx.text
Align = config.inGraphDataAlign; | |
6106 ctx.text
Baseline = config.inGraphDataVAlign; | |
6107 ctx.font
= config.inGraphDataFontStyle + ' ' + config.inGraphDataFontSize + 'px ' + conf
ig.inGraphDataFontFamily; | |
6108 ctx.fill
Style = config.inGraphDataFontColor; | |
6109 var dotX
= yAxisPosX + (valueHop * k), | |
6110
dotY = xAxisPosY - currentAnimPc.mainVal * (calculateOffset(logarithmic, data.da
tasets[i].data[j], calculatedScale, scaleHop)), | |
6111
paddingTextX = config.inGraphDataPaddingX, | |
6112
paddingTextY = config.inGraphDataPaddingY; | |
6113 var disp
String = tmplbis(config.inGraphDataTmpl, { | |
6114
config: config, | |
6115
v1: fmtChartJS(config, lgtxt, config.fmtV1), | |
6116
v2: fmtChartJS(config, lgtxt2, config.fmtV2), | |
6117
v3: fmtChartJS(config, 1 * data.datasets[i].data[j], config.fmtV3), | |
6118
v4: fmtChartJS(config, divprev, config.fmtV4), | |
6119
v5: fmtChartJS(config, divnext, config.fmtV5), | |
6120
v6: fmtChartJS(config, maxvalue[j], config.fmtV6), | |
6121
v7: fmtChartJS(config, totvalue[j], config.fmtV7), | |
6122
v8: roundToWithThousands(config, fmtChartJS(config, 100 * data.datasets[i].data[
j] / totvalue[j], config.fmtV8), config.roundPct), | |
6123
v9: fmtChartJS(config, yAxisPosX + (valueHop * k), config.fmtV9), | |
6124
v10: fmtChartJS(config, xAxisPosY - (calculateOffset(logarithmic, data.datasets[
i].data[j], calculatedScale, scaleHop)), config.fmtV10), | |
6125
v11: fmtChartJS(config, i, config.fmtV11), | |
6126
v12: fmtChartJS(config, j, config.fmtV12), | |
6127
data: data | |
6128 }); | |
6129 ctx.tran
slate(xPos(i, j, data) + paddingTextX, yPos(i, j) - paddingTextY); | |
6130 ctx.rota
te(config.inGraphDataRotate * (Math.PI / 180)); | |
6131 ctx.fill
TextMultiLine(dispString, 0, 0, ctx.textBaseline, config.inGraphDataFontSize); | |
6132 ctx.rest
ore(); | |
6133 } | |
6134 } | |
6135 } | |
6136 } else { | |
6137 if (false == config.extrapolateM
issingData) { | |
6138 ctx.stroke(); | |
6139 if (config.datasetFill)
{ | |
6140 ctx.lineTo(prevX
pos, xAxisPosY - zeroY); | |
6141 ctx.lineTo(xPos(
i, frstpt, data), xAxisPosY - zeroY); | |
6142 ctx.lineTo(xPos(
i, frstpt, data), yPos(i, frstpt)); | |
6143 ctx.closePath(); | |
6144 if (typeof data.
datasets[i].fillColor == "function") ctx.fillStyle = data.datasets[i].fillColor(
"FILLCOLOR", data, config, i, -1, currentAnimPc.mainVal, -1, "Line", ctx, yAxisP
osX, lmaxvalue[i], yAxisPosX + valueHop * (data.datasets[i].data.length - 1), lm
axvalue[i] - ((config.animationLeftToRight) ? 1 : 1*currentAnimPc.mainVal) * (lm
axvalue[i] - lminvalue[i])); | |
6145 else if (typeof
data.datasets[i].fillColor == "string") ctx.fillStyle = data.datasets[i].fillCol
or; | |
6146 else ctx.fillSty
le = config.defaultFillColor; | |
6147 ctx.fill(); | |
6148 } | |
6149 ctx.beginPath(); | |
6150 prevpt = -1; | |
6151 frstpt = -1; | |
6152 prevAnimPc = 0; | |
6153 prevnotempty = 0; | |
6154 } else { | |
6155 if (currentAnimPc.subVal
> 0) { | |
6156 nxtnotmiss = -1; | |
6157 for (t = j + 1;
t < data.datasets[i].data["length"] && nxtnotmiss == -1; t++) { | |
6158 if (!(ty
peof(data.datasets[i].data[t]) == 'undefined')) nxtnotmiss = t; | |
6159 } | |
6160 if ((typeof(data
.datasets[i].data[j]) !== 'undefined') || (true == config.extrapolateMissingData
)) { | |
6161 if (nxtn
otmiss != -1) { | |
6162
prevXpos = xPos(i, j + currentAnimPc.subVal, data); | |
6163
if (config.bezierCurve) { | |
6164
ctx.bezierCurveTo(xPos(i, prevpt + (j + currentAnimPc.subVal - prevpt) /
2, data), yPos(i, prevpt), xPos(i, prevpt + (j + currentAnimPc.subVal - prevpt)
/ 2, data), yPos(i, nxtnotmiss), xPos(i, j + currentAnimPc.subVal, data), yPos(
i, nxtnotmiss)); | |
6165
} else { | |
6166
ctx.lineTo(xPos(i, j + currentAnimPc.subVal, data), yPos(i, j + 1)); | |
6167
} | |
6168 } | |
6169 } | |
6170 } | |
6171 } | |
6172 } | |
6173 } | |
6174 ctx.stroke(); | |
6175 if (config.datasetFill) { | |
6176 // ctx.line
To(yAxisPosX + (valueHop * (data.datasets[i].data.length - 1)), xAxisPosY - zero
Y); | |
6177 ctx.lineTo(prevXpos, xAxisPosY - zeroY); | |
6178 ctx.lineTo(xPos(i, frstpt, data), xAxisP
osY - zeroY); | |
6179 ctx.lineTo(xPos(i, frstpt, data), yPos(i
, frstpt)); | |
6180 ctx.closePath(); | |
6181 if (typeof data.datasets[i].fillColor ==
"function") { ctx.fillStyle = data.datasets[i].fillColor("FILLCOLOR", data, con
fig, i, -1, currentAnimPc.mainVal, -1, "Line", ctx, yAxisPosX, lmaxvalue[i], yAx
isPosX + valueHop * (data.datasets[i].data.length - 1), lmaxvalue[i] - ((config.
animationLeftToRight) ? 1 : 1*currentAnimPc.mainVal) * (lmaxvalue[i] - lminvalue
[i])); } | |
6182 else if (typeof data.datasets[i].fillCol
or == "string") ctx.fillStyle = data.datasets[i].fillColor; | |
6183 else ctx.fillStyle = config.defaultFillC
olor; | |
6184 ctx.fill(); | |
6185 } else { | |
6186 ctx.closePath(); | |
6187 } | |
6188 if (config.pointDot) { | |
6189 if (typeof data.datasets[i].pointColor =
= "function") ctx.fillStyle = data.datasets[i].pointColor("POINTCOLOR", data, co
nfig, i, -1, animPc, -1, "Line", ctx, yAxisPosX, lmaxvalue[i], yAxisPosX + value
Hop * (data.datasets[i].data.length - 1), lmaxvalue[i] - ((config.animationLeftT
oRight) ? 1 : 1*currentAnimPc.mainVal) * (lmaxvalue[i] - lminvalue[i])); | |
6190 else ctx.fillStyle = data.datasets[i].po
intColor; | |
6191 if (typeof data.datasets[i].pointStrokeC
olor == "function") ctx.strokeStyle = data.datasets[i].pointStrokeColor("POINTST
ROKECOLOR", data, config, i, -1, animPc, -1, "Line", ctx, yAxisPosX, lmaxvalue[i
], yAxisPosX + valueHop * (data.datasets[i].data.length - 1), lmaxvalue[i] - ((c
onfig.animationLeftToRight) ? 1 : 1*currentAnimPc.mainVal) * (lmaxvalue[i] - lmi
nvalue[i])); | |
6192 else ctx.strokeStyle = data.datasets[i].
pointStrokeColor; | |
6193 ctx.lineWidth = config.pointDotStrokeWid
th; | |
6194 for (var k = 0; k < data.datasets[i].dat
a.length; k++) { | |
6195 if (!(typeof(data.datasets[i].da
ta[k]) == 'undefined')) { | |
6196 var currentAnimPc = anim
ationCorrection(animPc, data, config, i, k, 0); | |
6197 if (currentAnimPc.mainVa
l > 0 || !config.animationLeftToRight) { | |
6198 ctx.beginPath(); | |
6199 ctx.arc(xPos(i,
k, data), yPos(i, k), config.pointDotRadius, 0, Math.PI * 2, true); | |
6200 ctx.fill(); | |
6201 ctx.stroke(); | |
6202 } | |
6203 } | |
6204 } | |
6205 } | |
6206 } | |
6207 }; | |
6208 | |
6209 function yPos(dataSet, iteration) { | |
6210 return xAxisPosY - zeroY - currentAnimPc.mainVal * (calc
ulateOffset(logarithmic, data.datasets[dataSet].data[iteration], calculatedScale
, scaleHop) - zeroY); | |
6211 }; | |
6212 | |
6213 function xPos(ival, iteration, data) { | |
6214 if (typeof data.datasets[ival].xPos == "object") { | |
6215 if (!(typeof data.datasets[ival].xPos[Math.floor
(iteration + 0.0001)] == "undefined")) { | |
6216 var width = valueHop * nbValueHop; | |
6217 var deb = (typeof data.xBegin != "undefi
ned") ? data.xBegin : 1 * data.labels[0]; | |
6218 var fin = (typeof data.xEnd != "undefine
d") ? data.xEnd : 1 * data.labels[data.labels.length - 1]; | |
6219 if (fin <= deb) fin = deb + 100; | |
6220 if (1 * data.datasets[ival].xPos[Math.fl
oor(iteration + 0.0001)] >= deb && data.datasets[ival].xPos[Math.floor(iteration
+ 0.0001)] <= fin) { | |
6221 var p1 = yAxisPosX + width * ((1
* data.datasets[ival].xPos[Math.floor(iteration + 0.0001)] - deb) / (fin - deb)
); | |
6222 var p2 = p1; | |
6223 if (Math.abs(iteration - Math.fl
oor(iteration + 0.0001)) > 0.0001) { | |
6224 var tt = iteration + Mat
h.floor(iteration + 0.0001); | |
6225 var p2 = xPos(ival, Math
.ceil(iteration - 0.0001), data); | |
6226 } | |
6227 return p1 + (iteration - Math.fl
oor(iteration + 0.0001)) * (p2 - p1); | |
6228 } | |
6229 } | |
6230 } | |
6231 return yAxisPosX + (valueHop * iteration); | |
6232 }; | |
6233 }; | |
6234 | |
6235 function log10(val) { | |
6236 return Math.log(val) / Math.LN10; | |
6237 }; | |
6238 | |
6239 function setRect(ctx, config) { | |
6240 if (config.clearRect) { | |
6241 if (!config.multiGraph) { | |
6242 clear(ctx); | |
6243 ctx.clearRect(0, 0, width, height); | |
6244 } | |
6245 } else { | |
6246 clear(ctx); | |
6247 ctx.clearRect(0, 0, width, height); | |
6248 | |
6249 ctx.fillStyle = config.savePngBackgroundColor; | |
6250 ctx.strokeStyle = config.savePngBackgroundColor; | |
6251 ctx.beginPath(); | |
6252 ctx.moveTo(0, 0); | |
6253 ctx.lineTo(0, ctx.canvas.height); | |
6254 ctx.lineTo(ctx.canvas.width, ctx.canvas.height); | |
6255 ctx.lineTo(ctx.canvas.width, 0); | |
6256 ctx.lineTo(0, 0); | |
6257 ctx.stroke(); | |
6258 ctx.fill(); | |
6259 } | |
6260 }; | |
6261 | |
6262 function defMouse(ctx, data, config) { | |
6263 if (config.annotateDisplay == true) { | |
6264 if (cursorDivCreated == false) oCursor = new makeCursorO
bj('divCursor'); | |
6265 if (isIE() < 9 && isIE() != false) ctx.canvas.attachEven
t("on" + config.annotateFunction.split(' ')[0], function(event) { | |
6266 if ((config.annotateFunction.split(' ')[1] == "l
eft" && event.which == 1) || | |
6267 (config.annotateFunction.split(' ')[1] =
= "middle" && event.which == 2) || | |
6268 (config.annotateFunction.split(' ')[1] =
= "right" && event.which == 3) || | |
6269 (typeof(config.annotateFunction.split('
')[1]) != "string")) doMouseAction(config, ctx, event, data, "annotate", config.
mouseDownRight) | |
6270 }); | |
6271 else ctx.canvas.addEventListener(config.annotateFunction
.split(' ')[0], function(event) { | |
6272 if ((config.annotateFunction.split(' ')[1] == "l
eft" && event.which == 1) || | |
6273 (config.annotateFunction.split(' ')[1] =
= "middle" && event.which == 2) || | |
6274 (config.annotateFunction.split(' ')[1] =
= "right" && event.which == 3) || | |
6275 (typeof(config.annotateFunction.split('
')[1]) != "string")) doMouseAction(config, ctx, event, data, "annotate", config.
mouseDownRight) | |
6276 }, false); | |
6277 } | |
6278 if (config.savePng) { | |
6279 if (isIE() < 9 && isIE() != false) ctx.canvas.attachEven
t("on" + config.savePngFunction.split(' ')[0], function(event) { | |
6280 if ((config.savePngFunction.split(' ')[1] == "le
ft" && event.which == 1) || | |
6281 (config.savePngFunction.split(' ')[1] ==
"middle" && event.which == 2) || | |
6282 (config.savePngFunction.split(' ')[1] ==
"right" && event.which == 3) || | |
6283 (typeof(config.savePngFunction.split(' '
)[1]) != "string")) saveCanvas(ctx, data, config); | |
6284 }); | |
6285 else ctx.canvas.addEventListener(config.savePngFunction.
split(' ')[0], function(event) { | |
6286 if ((config.savePngFunction.split(' ')[1] == "le
ft" && event.which == 1) || | |
6287 (config.savePngFunction.split(' ')[1] ==
"middle" && event.which == 2) || | |
6288 (config.savePngFunction.split(' ')[1] ==
"right" && event.which == 3) || | |
6289 (typeof(config.savePngFunction.split(' '
)[1]) != "string")) saveCanvas(ctx, data, config); | |
6290 }, false); | |
6291 } | |
6292 | |
6293 if (isIE() < 9 && isIE() != false) ctx.canvas.attachEvent("onmou
sewheel", function(event) { | |
6294 if (cursorDivCreated) document.getElementById('divCursor
').style.display = 'none'; | |
6295 }); | |
6296 else ctx.canvas.addEventListener("DOMMouseScroll", function(even
t) { | |
6297 if (cursorDivCreated) document.getElementById('divCursor
').style.display = 'none'; | |
6298 }, false); | |
6299 | |
6300 | |
6301 | |
6302 function add_event_listener(type, func, chk) | |
6303 { | |
6304 if(typeof func != 'function') | |
6305 return; | |
6306 | |
6307 function do_func(event) { | |
6308 if (chk == null || chk(event)) doMouseAction(con
fig,ctx,event,data,"mouseaction",func); | |
6309 }; | |
6310 | |
6311 var hash = type+' '+func.name; | |
6312 if(hash in ctx._eventListeners) { | |
6313 if(ctx.canvas.removeEventListener) | |
6314 ctx.canvas.removeEventListener(type, ctx
._eventListeners[hash]); | |
6315 else if(ctx.canvas.detachEvent) | |
6316 ctx.canvas.detachEvent(type, ctx._eventL
isteners[hash]); | |
6317 } | |
6318 | |
6319 ctx._eventListeners[hash] = do_func; | |
6320 | |
6321 if(ctx.canvas.addEventListener) { | |
6322 if(type=="mousewheel") type="DOMMouseScroll"; | |
6323 ctx.canvas.addEventListener(type, do_func, false
); | |
6324 } else if(ctx.canvas.attachEvent) { | |
6325 ctx.canvas.attachEvent("on"+type, do_func); | |
6326 } | |
6327 }; | |
6328 | |
6329 add_event_listener("mousedown", config.mouseDownLeft, function(e
) { return e.which == 1; }); | |
6330 add_event_listener("mousedown", config.mouseDownMiddle, function
(e) { return e.which == 2; }); | |
6331 add_event_listener("mousedown", config.mouseDownRight, function(
e) { return e.which == 3; }); | |
6332 add_event_listener("mousemove", config.mouseMove); | |
6333 add_event_listener("mouseout", config.mouseOut); | |
6334 add_event_listener("mousewheel", config.mouseWheel); | |
6335 }; | |
6336 }; | |
6337 | |
6338 function animationCorrection(animationValue, data, config, vdata, vsubdata, addo
ne) { | |
6339 var animValue = animationValue; | |
6340 var animSubValue = 0; | |
6341 if (vsubdata != -1) { | |
6342 if (animValue < 1 && (vdata < (config.animationStartWithDataset
- 1) && (config.animationStartWithDataset - 1) != -1)) { | |
6343 animValue = 1; | |
6344 } | |
6345 if (animValue < 1 && (vsubdata < (config.animationStartWithData
- 1) && (config.animationStartWithData - 1) != -1)) { | |
6346 animValue = 1; | |
6347 } | |
6348 var totreat = 1; | |
6349 var newAnimationValue = animationValue; | |
6350 if (animValue < 1 && config.animationByDataset) { | |
6351 animValue = 0; | |
6352 totreat = 0; | |
6353 var startDataset = (config.animationStartWithDataset - 1
); | |
6354 if ((config.animationStartWithDataset - 1) == -1) startD
ataset = 0 | |
6355 var nbstepsperdatasets = config.animationSteps / (data.d
atasets.length - startDataset); | |
6356 if (animationValue >= (vdata - startDataset + 1) * nbste
psperdatasets / config.animationSteps) animValue = 1; | |
6357 else if (animationValue >= (vdata - startDataset) * nbst
epsperdatasets / config.animationSteps) { | |
6358 var redAnimationValue = animationValue - (vdata
- startDataset) * nbstepsperdatasets / config.animationSteps; | |
6359 if (!config.animationLeftToRight) { | |
6360 animValue = redAnimationValue * (data.da
tasets.length - startDataset); | |
6361 } else { | |
6362 newAnimationValue = redAnimationValue *
(data.datasets.length - startDataset); | |
6363 } | |
6364 totreat = 1; | |
6365 } | |
6366 } | |
6367 if (totreat == 1 && animValue < 1 && config.animationLeftToRight
) { | |
6368 animValue = 0; | |
6369 var startSub = (config.animationStartWithData - 1); | |
6370 if ((config.animationStartWithData - 1) == -1) startSub
= 0 | |
6371 var nbstepspervalue = config.animationSteps / (data.data
sets[vdata].data.length - startSub - 1 + addone); | |
6372 if (newAnimationValue >= (vsubdata - startSub) * nbsteps
pervalue / config.animationSteps) { | |
6373 animValue = 1; | |
6374 if (newAnimationValue <= (vsubdata + 1 - startSu
b) * nbstepspervalue / config.animationSteps) { | |
6375 animSubValue = (data.datasets[vdata].dat
a.length - startSub - 1) * (newAnimationValue - ((vsubdata - startSub) * nbsteps
pervalue / config.animationSteps)); | |
6376 } | |
6377 } | |
6378 } | |
6379 } else { | |
6380 if (animValue < 1 && (vdata < (config.animationStartWithData - 1
))) { | |
6381 animValue = 1; | |
6382 } | |
6383 } | |
6384 return { | |
6385 mainVal: animValue, | |
6386 subVal: animSubValue, | |
6387 animVal: animValue + animSubValue | |
6388 }; | |
6389 }; | |
6390 | |
6391 | |
6392 function drawLegend(legendMsr,data,config,ctx,typegraph) { | |
6393 if (config.legendBorders == true) { | |
6394 ctx.save(); | |
6395 ctx.beginPath(); | |
6396 ctx.lineWidth = config.legendBordersWidth; | |
6397 ctx.strokeStyle = config.legendBordersColors; | |
6398 ctx.moveTo(legendMsr.xLegendBorderPos, legendMsr.yLegendBorderPo
s); | |
6399 ctx.lineTo(legendMsr.xLegendBorderPos, legendMsr.yLegendBorderPo
s + legendMsr.legendBorderHeight); | |
6400 ctx.lineTo(legendMsr.xLegendBorderPos + legendMsr.legendBorderWi
dth, legendMsr.yLegendBorderPos + legendMsr.legendBorderHeight); | |
6401 ctx.lineTo(legendMsr.xLegendBorderPos + legendMsr.legendBorderWi
dth, legendMsr.yLegendBorderPos); | |
6402 ctx.lineTo(legendMsr.xLegendBorderPos, legendMsr.yLegendBorderPo
s); | |
6403 ctx.lineTo(legendMsr.xLegendBorderPos + legendMsr.legendBorderWi
dth, legendMsr.yLegendBorderPos); | |
6404 ctx.lineTo(legendMsr.xLegendBorderPos, legendMsr.yLegendBorderPo
s); | |
6405 ctx.lineTo(legendMsr.xLegendBorderPos, legendMsr.yLegendBorderPo
s + legendMsr.legendBorderHeight); | |
6406 ctx.stroke(); | |
6407 ctx.closePath(); | |
6408 ctx.fillStyle = "rgba(0,0,0,0)"; // config.legendFillColor; | |
6409 ctx.fillStyle = config.legendFillColor; | |
6410 ctx.fill(); | |
6411 ctx.restore(); | |
6412 } | |
6413 nbcols = legendMsr.nbLegendCols - 1; | |
6414 ypos = legendMsr.yFirstLegendTextPos - (config.legendFontSize + config.l
egendSpaceBetweenTextVertical); | |
6415 xpos = 0; | |
6416 if (legendMsr.drawLegendOnData) fromi = data.datasets.length; | |
6417 else fromi = data.length; | |
6418 for (var i = fromi - 1; i >= 0; i--) { | |
6419 orderi = i; | |
6420 if (legendMsr.reverseLegend) { | |
6421 if (legendMsr.drawLegendOnData) orderi = data.datasets.l
ength - i - 1; | |
6422 else orderi = data.length - i - 1; | |
6423 } | |
6424 if (legendMsr.drawLegendOnData) tpof = typeof(data.datasets[orde
ri].title); | |
6425 else tpof = typeof(data[orderi].title) | |
6426 if (tpof == "string") { | |
6427 if (legendMsr.drawLegendOnData) lgtxt = fmtChartJS(confi
g, data.datasets[orderi].title, config.fmtLegend).trim(); | |
6428 else lgtxt = fmtChartJS(config, data[orderi].title, conf
ig.fmtLegend).trim(); | |
6429 if (lgtxt != "") { | |
6430 nbcols++; | |
6431 if (nbcols == legendMsr.nbLegendCols) { | |
6432 nbcols = 0; | |
6433 xpos = legendMsr.xFirstLegendTextPos; | |
6434 ypos += config.legendFontSize + config.l
egendSpaceBetweenTextVertical; | |
6435 } else { | |
6436 xpos += legendMsr.widestLegend + config.
legendSpaceBetweenTextHorizontal; | |
6437 } | |
6438 ctx.save(); | |
6439 ctx.beginPath(); | |
6440 if (legendMsr.drawLegendOnData) { | |
6441 if (typeof data.datasets[orderi].strokeC
olor == "function") ctx.strokeStyle = data.datasets[orderi].strokeColor("STROKEC
OLOR", data, config, orderi, -1, 1, -1, typegraph, ctx, -1, -1, -1, -1); | |
6442 else if (typeof data.datasets[orderi].st
rokeColor == "string") ctx.strokeStyle = data.datasets[orderi].strokeColor; | |
6443 else ctx.strokeStyle = config.defaultStr
okeColor; | |
6444 } else { | |
6445 if (typeof data[orderi].color == "functi
on") ctx.strokeStyle = data[orderi].color("COLOR", data, config, orderi, -1, 1,
data[orderi].value, typegraph, ctx, 1, 1, 1, 1); | |
6446 else if (typeof data[orderi].color == "s
tring") ctx.strokeStyle = data[orderi].color; | |
6447 else ctx.strokeStyle = config.defaultStr
okeColor; | |
6448 } | |
6449 if (legendMsr.legendBox) { | |
6450 ctx.lineWidth = 1; | |
6451 ctx.moveTo(xpos, ypos); | |
6452 ctx.lineTo(xpos + config.legendBlockSize
, ypos); | |
6453 ctx.lineTo(xpos + config.legendBlockSize
, ypos - config.legendFontSize); | |
6454 ctx.lineTo(xpos, ypos - config.legendFon
tSize); | |
6455 ctx.lineTo(xpos, ypos); | |
6456 ctx.closePath(); | |
6457 if (legendMsr.drawLegendOnData) { | |
6458 if (typeof data.datasets[orderi]
.fillColor == "function") ctx.fillStyle = data.datasets[orderi].fillColor("LEGEN
DFILLCOLOR", data, config, orderi, -1, 1, -1, typegraph, ctx, xpos, ypos, xpos +
config.legendBlockSize, ypos - config.legendFontSize); | |
6459 else if (typeof data.datasets[or
deri].fillColor == "string") ctx.fillStyle = data.datasets[orderi].fillColor; | |
6460 else ctx.fillStyle = config.defa
ultFillColor; | |
6461 } else { | |
6462 if (typeof data[orderi].color ==
"function") ctx.fillStyle = data[orderi].color("LEGENDFILLCOLOR", data, config,
orderi, -1, 1, -1, typegraph, ctx, xpos, ypos - config.legendFontSize, xpos + c
onfig.legendBlockSize, ypos); | |
6463 else if (typeof data[orderi].col
or == "string") ctx.fillStyle = data[orderi].color; | |
6464 else ctx.fillStyle = config.defa
ultFillColor; | |
6465 } | |
6466 ctx.fill(); | |
6467 } else { | |
6468 ctx.lineWidth = config.legendColorIndica
torStrokeWidth ? | |
6469 config.legendColorIndicatorStrok
eWidth : config.datasetStrokeWidth; | |
6470 if (config.legendColorIndicatorStrokeWid
th && config.legendColorIndicatorStrokeWidth > config.legendFontSize) { | |
6471 ctx.lineWidth = config.legendFon
tSize; | |
6472 } | |
6473 ctx.moveTo(xpos + 2, ypos - (config.lege
ndFontSize / 2)); | |
6474 ctx.lineTo(xpos + 2 + config.legendBlock
Size, ypos - (config.legendFontSize / 2)); | |
6475 } | |
6476 ctx.stroke(); | |
6477 ctx.restore(); | |
6478 ctx.save(); | |
6479 ctx.beginPath(); | |
6480 ctx.font = config.legendFontStyle + " " + config
.legendFontSize + "px " + config.legendFontFamily; | |
6481 ctx.fillStyle = config.legendFontColor; | |
6482 ctx.textAlign = "left"; | |
6483 ctx.textBaseline = "bottom"; | |
6484 ctx.translate(xpos + config.legendBlockSize + co
nfig.legendSpaceBetweenBoxAndText, ypos); | |
6485 ctx.fillText(lgtxt, 0, 0); | |
6486 ctx.stroke(); | |
6487 ctx.restore(); | |
6488 } | |
6489 } | |
6490 } | |
6491 }; | |
OLD | NEW |