Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: bower_components/chartnewjs/ChartNew.js

Issue 786953007: npm_modules: Fork bower_components into Polymer 0.4.0 and 0.5.0 versions (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « bower_components/chartnewjs/Add-ins/stats.js ('k') | bower_components/chartnewjs/LICENSE » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 };
OLDNEW
« no previous file with comments | « bower_components/chartnewjs/Add-ins/stats.js ('k') | bower_components/chartnewjs/LICENSE » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698