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