├── README.mkdn ├── demo.html ├── demo-multicolor.html ├── demo-animated.html └── awesomechart.js /README.mkdn: -------------------------------------------------------------------------------- 1 | #AwesomeChartJS 2 | 3 | AwesomeChartJS is a small JavaScript chart rendering library based on the HTML 5 canvas. 4 | 5 | ##Chart types 6 | 7 | * Vertical and horizontal bar charts 8 | * Pareto bar charts 9 | * Pie charts (whole or part) 10 | * Exploded pie charts (whole or part) 11 | * Ring/Doughnut charts (whole or part) 12 | 13 | ##Animations 14 | 15 | Now all charts except pareto bar charts can be animated when displayed. 16 | 17 | ##Demo 18 | 19 | Go to demos page 20 | 21 | ##Usage 22 | See demo.html 23 | 24 | ##License 25 | 26 | Copyright (c) 2011 Georgios Migdos 27 | 28 | Source code is available under the terms of the [Apache license v2.0](http://www.apache.org/licenses/LICENSE-2.0). 29 | 30 | 31 | ##Contributors 32 | 33 | * [pkozlowski-opensource](https://github.com/pkozlowski-opensource) 34 | * [barszczmm](https://github.com/barszczmm) 35 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AwesomeChartJS demo 5 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | Your web-browser does not support the HTML 5 canvas element. 53 | 54 | 55 |
56 | 57 |
58 |
59 | 60 | 61 | Your web-browser does not support the HTML 5 canvas element. 62 | 63 | 64 |
65 | 66 |
67 | 68 | 69 | Your web-browser does not support the HTML 5 canvas element. 70 | 71 | 72 |
73 |
74 | 75 |
76 |
77 | 78 | 79 | Your web-browser does not support the HTML 5 canvas element. 80 | 81 | 82 |
83 | 84 |
85 | 86 | 87 | Your web-browser does not support the HTML 5 canvas element. 88 | 89 | 90 |
91 |
92 | 93 |
94 |
95 | 96 | 97 | Your web-browser does not support the HTML 5 canvas element. 98 | 99 | 100 |
101 | 102 |
103 | 104 | 105 | Your web-browser does not support the HTML 5 canvas element. 106 | 107 | 108 |
109 |
110 | 111 |
112 |
113 | 114 | 115 | Your web-browser does not support the HTML 5 canvas element. 116 | 117 | 118 |
119 | 120 |
121 | 122 | 123 | Your web-browser does not support the HTML 5 canvas element. 124 | 125 | 126 |
127 |
128 | 129 |
130 |
131 | 132 | 133 | Your web-browser does not support the HTML 5 canvas element. 134 | 135 | 136 |
137 | 138 |
139 | 140 | 141 | Your web-browser does not support the HTML 5 canvas element. 142 | 143 | 144 |
145 |
146 | 147 |
148 |
149 | 150 | 151 | Your web-browser does not support the HTML 5 canvas element. 152 | 153 | 154 |
155 | 156 |
157 | 158 | 159 | Your web-browser does not support the HTML 5 canvas element. 160 | 161 | 162 |
163 |
164 | 165 | 166 | 167 | 265 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /demo-multicolor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AwesomeChartJS demo 5 | 45 | 46 | 47 | 48 |
49 | 50 | 51 | Your web-browser does not support the HTML 5 canvas element. 52 | 53 | 54 |
55 | 56 |
57 |
58 | 59 | 60 | Your web-browser does not support the HTML 5 canvas element. 61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 | Your web-browser does not support the HTML 5 canvas element. 69 | 70 | 71 |
72 |
73 | 74 |
75 |
76 | 77 | 78 | Your web-browser does not support the HTML 5 canvas element. 79 | 80 | 81 |
82 | 83 |
84 | 85 | 86 | Your web-browser does not support the HTML 5 canvas element. 87 | 88 | 89 |
90 |
91 | 92 |
93 |
94 | 95 | 96 | Your web-browser does not support the HTML 5 canvas element. 97 | 98 | 99 |
100 | 101 |
102 | 103 | 104 | Your web-browser does not support the HTML 5 canvas element. 105 | 106 | 107 |
108 |
109 | 110 |
111 |
112 | 113 | 114 | Your web-browser does not support the HTML 5 canvas element. 115 | 116 | 117 |
118 | 119 |
120 | 121 | 122 | Your web-browser does not support the HTML 5 canvas element. 123 | 124 | 125 |
126 |
127 | 128 |
129 |
130 | 131 | 132 | Your web-browser does not support the HTML 5 canvas element. 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | Your web-browser does not support the HTML 5 canvas element. 141 | 142 | 143 |
144 |
145 | 146 |
147 |
148 | 149 | 150 | Your web-browser does not support the HTML 5 canvas element. 151 | 152 | 153 |
154 | 155 |
156 | 157 | 158 | Your web-browser does not support the HTML 5 canvas element. 159 | 160 | 161 |
162 |
163 | 164 | 165 | 166 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /demo-animated.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AwesomeChartJS demo 5 | 45 | 46 | 47 | 48 |
49 | 50 | 51 | Your web-browser does not support the HTML 5 canvas element. 52 | 53 | 54 |
55 | 56 |
57 |
58 | 59 | 60 | Your web-browser does not support the HTML 5 canvas element. 61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 | Your web-browser does not support the HTML 5 canvas element. 69 | 70 | 71 |
72 |
73 | 74 |
75 |
76 | 77 | 78 | Your web-browser does not support the HTML 5 canvas element. 79 | 80 | 81 |
82 | 83 |
84 | 85 | 86 | Your web-browser does not support the HTML 5 canvas element. 87 | 88 | 89 |
90 |
91 | 92 |
93 |
94 | 95 | 96 | Your web-browser does not support the HTML 5 canvas element. 97 | 98 | 99 |
100 | 101 |
102 | 103 | 104 | Your web-browser does not support the HTML 5 canvas element. 105 | 106 | 107 |
108 |
109 | 110 |
111 |
112 | 113 | 114 | Your web-browser does not support the HTML 5 canvas element. 115 | 116 | 117 |
118 | 119 |
120 | 121 | 122 | Your web-browser does not support the HTML 5 canvas element. 123 | 124 | 125 |
126 |
127 | 128 |
129 |
130 | 131 | 132 | Your web-browser does not support the HTML 5 canvas element. 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | Your web-browser does not support the HTML 5 canvas element. 141 | 142 | 143 |
144 |
145 | 146 |
147 |
148 | 149 | 150 | Your web-browser does not support the HTML 5 canvas element. 151 | 152 | 153 |
154 | 155 |
156 | 157 | 158 | Your web-browser does not support the HTML 5 canvas element. 159 | 160 | 161 |
162 |
163 | 164 | 165 | 166 | 308 | 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /awesomechart.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Georgios Migdos 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | Array.prototype.numericSortReverse = function(data){ 18 | this.sort(function(a, b){ 19 | return data[b] - data[a]; 20 | }); 21 | } 22 | 23 | Array.prototype.max = function() { 24 | var max = this[0]; 25 | var len = this.length; 26 | for (var i = 1; i < len; i++){ 27 | if (this[i] > max){ 28 | max = this[i]; 29 | } 30 | } 31 | return max; 32 | } 33 | 34 | Array.prototype.min = function() { 35 | var min = this[0]; 36 | var len = this.length; 37 | for (var i = 1; i < len; i++){ 38 | if (this[i] < min){ 39 | min = this[i]; 40 | } 41 | } 42 | return min; 43 | } 44 | 45 | function AwesomeChart(canvasElementId){ 46 | var canvas = (typeof canvasElementId === 'string') ? document.getElementById(canvasElementId) : canvasElementId; 47 | this.ctx = canvas.getContext('2d'); 48 | this.width = this.ctx.canvas.width; 49 | this.height = this.ctx.canvas.height; 50 | 51 | this.numberOfDecimals = 0; 52 | 53 | this.proportionalSizes = true; 54 | this.widthSizeFactor = this.width/400; 55 | this.heightSizeFactor = this.height/400; 56 | 57 | this.chartType = 'bar'; 58 | this.randomColors = false; 59 | 60 | this.animate = false; 61 | this.animationFrames = 60; 62 | 63 | this.marginTop = 10; 64 | this.marginBottom = 10; 65 | this.marginLeft = 10; 66 | this.marginRight = 10; 67 | 68 | this.labelMargin = 10; 69 | this.dataValueMargin = 20; 70 | this.titleMargin = 10; 71 | this.yAxisLabelMargin = 5; 72 | 73 | this.data = new Array(); 74 | this.labels = new Array(); 75 | this.colors = new Array(); 76 | this.title = null; 77 | 78 | this.backgroundFillStyle = 'rgba(255,255,255,0)'; 79 | this.borderStrokeStyle = 'rgba(255,255,255,0)'; 80 | this.borderWidth = 1.0; 81 | 82 | this.labelFillStyle = 'rgb(220, 36, 0)'; 83 | this.labelFont = 'sans-serif'; 84 | this.labelFontHeight = 12; 85 | this.labelFontStyle = ''; 86 | 87 | this.dataValueFillStyle = '#333'; 88 | this.dataValueFont = 'sans-serif'; 89 | this.dataValueFontHeight = 15; 90 | this.dataValueFontStyle = ''; 91 | 92 | this.titleFillStyle = '#333'; 93 | this.titleFont = 'sans-serif'; 94 | this.titleFontHeight = 16; 95 | this.titleFontStyle = 'bold'; 96 | 97 | this.yAxisLabelFillStyle = '#333'; 98 | this.yAxisLabelFont = 'sans-serif'; 99 | this.yAxisLabelFontHeight = 10; 100 | this.yAxisLabelFontStyle = ''; 101 | 102 | var lingrad = this.ctx.createLinearGradient(0,0,0,this.height); 103 | lingrad.addColorStop(0.2, '#fdfdfd'); 104 | lingrad.addColorStop(0.8, '#ededed'); 105 | 106 | this.chartBackgroundFillStyle = lingrad; 107 | this.chartBorderStrokeStyle = '#999'; 108 | this.chartBorderLineWidth = 1; 109 | this.chartHorizontalLineStrokeStyle = '#999'; 110 | this.chartHorizontalLineWidth = 1; 111 | this.chartVerticalLineStrokeStyle = '#999'; 112 | this.chartVerticalLineWidth = 1; 113 | 114 | this.chartMarkerSize = 5; 115 | 116 | this.chartPointRadius = 4; 117 | this.chartPointFillStyle = 'rgb(150, 36, 0)'; 118 | 119 | this.chartLineStrokeStyle = 'rgba(150, 36, 0, 0.5)'; 120 | this.chartLineWidth = 2; 121 | 122 | this.barFillStyle = 'rgb(220, 36, 0)'; 123 | this.barStrokeStyle = '#fff'; 124 | this.barBorderWidth = 2.0; 125 | this.barShadowColor = 'rgba(0, 0, 0, 0.5)'; 126 | this.barShadowBlur = 5; 127 | this.barShadowOffsetX = 3.0; 128 | this.barShadowOffsetY = 0.0; 129 | 130 | this.barHGap = 20; 131 | this.barVGap = 20; 132 | 133 | this.explosionOffset = 20; 134 | 135 | this.pieFillStyle = 'rgb(220, 36, 0)'; 136 | this.pieStrokeStyle = '#fff'; 137 | this.pieBorderWidth = 2.0; 138 | this.pieShadowColor = 'rgba(0, 0, 0, 0.5)'; 139 | this.pieShadowBlur = 5; 140 | this.pieShadowOffsetX = 3.0; 141 | this.pieShadowOffsetY = 0.0; 142 | 143 | this.pieStart = 0; 144 | this.pieTotal = null; 145 | 146 | this.generateRandomColor = function(){ 147 | var rgb = new Array(); 148 | for(var i=0; i<3; i++){ 149 | rgb.push(Math.ceil(Math.random()*150 + 50)); 150 | } 151 | return 'rgb('+rgb.join(",")+')'; 152 | } 153 | 154 | /*Set the chart's data in the format: 155 | * 156 | * { 157 | * "label-1": data-value-1, 158 | * "label-2": data-value-2, 159 | * "label-3": data-value-3, 160 | * .... 161 | * "label-N": data-value-N, 162 | * } 163 | * 164 | */ 165 | this.setChartDataFromJSON = function(jsonObj){ 166 | for(var p in jsonObj){ 167 | this.labels.push(p); 168 | this.data.push(jsonObj[p]); 169 | } 170 | } 171 | 172 | 173 | this.draw = function(){ 174 | var context = this.ctx; 175 | context.lineCap = 'round'; 176 | var minFactor = Math.min(this.widthSizeFactor, this.heightSizeFactor); 177 | 178 | if(this.proportionalSizes){ 179 | this.labelMargin = this.labelMargin * this.heightSizeFactor; 180 | this.dataValueMargin = this.dataValueMargin * this.heightSizeFactor; 181 | this.titleMargin = this.titleMargin * this.heightSizeFactor; 182 | this.yAxisLabelMargin = this.yAxisLabelMargin * this.heightSizeFactor; 183 | 184 | this.labelFontHeight = this.labelFontHeight * minFactor; 185 | this.dataValueFontHeight = this.dataValueFontHeight * minFactor; 186 | this.titleFontHeight = this.titleFontHeight * minFactor; 187 | this.yAxisLabelFontHeight = this.yAxisLabelFontHeight * minFactor; 188 | 189 | this.barHGap = this.barHGap * this.widthSizeFactor; 190 | this.barVGap = this.barHGap * this.heightSizeFactor; 191 | this.explosionOffset = this.explosionOffset * minFactor; 192 | } 193 | 194 | if(this.randomColors){ 195 | for(var i=0; i=0){ 354 | context.textBaseline = 'bottom'; 355 | context.fillText(this.labels[i], x + barWidth/2, barBottomY - barHeight - this.labelMargin, barWidth); 356 | }else{ 357 | context.textBaseline = 'top'; 358 | context.fillText(this.labels[i], x + barWidth/2, barBottomY - barHeight + this.labelMargin, barWidth); 359 | } 360 | } 361 | 362 | //Draw the data value: 363 | 364 | context.font = this.dataValueFontStyle + ' ' + this.dataValueFontHeight + 'px '+ this.dataValueFont; 365 | context.fillStyle = this.dataValueFillStyle; 366 | context.textAlign = 'center'; 367 | if(di>=0){ 368 | context.textBaseline = 'bottom'; 369 | context.fillText(di, x + barWidth/2, barBottomY - barHeight - this.labelMargin - this.dataValueMargin, barWidth); 370 | }else{ 371 | context.textBaseline = 'top'; 372 | context.fillText(di, x + barWidth/2, barBottomY - barHeight + this.labelMargin + this.dataValueMargin, barWidth); 373 | } 374 | 375 | 376 | //Update x: 377 | 378 | x = x + barWidth + this.barHGap; 379 | } 380 | } 381 | 382 | 383 | 384 | this.animateBarChart = function() { 385 | var aw = this, 386 | numFrames = this.animationFrames, 387 | currentFrame = 0, 388 | 389 | maxData = this.data.max(), 390 | minData = this.data.min(), 391 | 392 | barMaxTopY = this.marginTop + this.labelMargin + this.labelFontHeight + this.dataValueMargin + this.dataValueFontHeight, 393 | barMinTopY = barBottomY = this.height - this.marginBottom; 394 | 395 | if(this.title!=null){ 396 | barMaxTopY += this.titleFontHeight + this.titleMargin; 397 | } 398 | 399 | if(minData<0){ 400 | barMinTopY = this.height - this.marginBottom - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight; 401 | 402 | barBottomY = barMinTopY + ((this.height - this.marginBottom - barMaxTopY - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight) * minData) / (Math.abs(minData)+maxData); 403 | } 404 | 405 | var chartAreaHeight = barMinTopY - barMaxTopY, 406 | changeOfMarginBottom = 0, 407 | changeOfMarginTop = 0; 408 | 409 | var belowZeroMaxBarHeight = 0; 410 | if(minData<0){ 411 | var maxBarHeight = Math.max(Math.abs(barBottomY - barMaxTopY), Math.abs(barBottomY - barMinTopY)), 412 | maxBarAbsData = Math.max(Math.abs(minData), Math.abs(maxData)); 413 | belowZeroMaxBarHeight = Math.abs(minData * maxBarHeight / maxBarAbsData + this.labelMargin + this.labelFontHeight); 414 | } 415 | 416 | this.marginBottom += belowZeroMaxBarHeight; 417 | if(this.title!=null){ 418 | this.titleMargin += chartAreaHeight - belowZeroMaxBarHeight; 419 | }else{ 420 | this.marginTop += chartAreaHeight - belowZeroMaxBarHeight; 421 | } 422 | changeOfMarginBottom = belowZeroMaxBarHeight / numFrames; 423 | changeOfMarginTop = (chartAreaHeight - belowZeroMaxBarHeight) / numFrames; 424 | 425 | var updateBarChart = function() { 426 | if(currentFrame++ < numFrames) { 427 | 428 | aw.marginBottom -= changeOfMarginBottom; 429 | 430 | if(aw.title!=null){ 431 | aw.titleMargin -= changeOfMarginTop; 432 | }else{ 433 | aw.marginTop -= changeOfMarginTop; 434 | } 435 | 436 | aw.ctx.clearRect(0, 0, aw.width, aw.height); 437 | aw.drawBarChart(); 438 | aw.drawTitleAndBorders(); 439 | 440 | // Standard 441 | if (typeof(window.requestAnimationFrame) == 'function') { 442 | window.requestAnimationFrame(updateBarChart); 443 | 444 | // IE 10+ 445 | } else if (typeof(window.msRequestAnimationFrame) == 'function') { 446 | window.msRequestAnimationFrame(updateBarChart); 447 | 448 | // Chrome 449 | } else if (typeof(window.webkitRequestAnimationFrame) == 'function') { 450 | window.webkitRequestAnimationFrame(updateBarChart); 451 | 452 | // Firefox 453 | } else if (window.mozRequestAnimationFrame) { // Seems rather slow in FF6 - so disabled 454 | window.mozRequestAnimationFrame(updateBarChart); 455 | 456 | // Default fallback to setTimeout 457 | } else { 458 | setTimeout(updateBarChart, 16.6666666); 459 | } 460 | } 461 | } 462 | 463 | updateBarChart(); 464 | 465 | } 466 | 467 | 468 | 469 | this.drawVerticalBarChart = function(){ 470 | var context = this.ctx; 471 | 472 | context.save(); 473 | context.translate(this.width/2, this.height/2); 474 | context.rotate(Math.PI/2); 475 | context.translate(-this.width/2, -this.height/2); 476 | 477 | //Calculate bar size: 478 | 479 | var n = this.data.length; 480 | var maxData = this.data.max(); 481 | var minData = this.data.min(); 482 | 483 | var marginLeft = this.marginLeft; 484 | if(this.title!=null){ 485 | marginLeft += this.titleFontHeight + this.titleMargin; 486 | } 487 | 488 | var barWidth = (this.width - marginLeft - this.marginRight - (n-1) * this.barHGap) / n; 489 | 490 | context.font = this.labelFontStyle + ' ' + this.labelFontHeight + 'px '+ this.labelFont; 491 | var maxLabelWidth = 0; 492 | var labelWidth = 0; 493 | for(var i=0; imaxLabelWidth){ 496 | maxLabelWidth = labelWidth; 497 | } 498 | } 499 | 500 | context.font = this.dataValueFontStyle + ' ' + this.dataValueFontHeight + 'px '+ this.dataValueFont; 501 | var maxDataValueWidth = 0; 502 | var dataValueWidth = 0; 503 | for(var i=0; imaxDataValueWidth){ 506 | maxDataValueWidth = dataValueWidth; 507 | } 508 | } 509 | 510 | var barMaxTopY = this.marginTop + Math.max( (this.labelMargin + maxLabelWidth), (this.dataValueMargin + maxDataValueWidth) ); 511 | 512 | var barMinTopY = this.height - this.marginBottom; 513 | 514 | var barBottomY = this.height - this.marginBottom; 515 | 516 | if(minData<0){ 517 | 518 | barMinTopY = this.height - this.marginBottom - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight; 519 | 520 | barBottomY = barMinTopY + ((this.height - this.marginBottom - barMaxTopY - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight) * minData) / (Math.abs(minData)+maxData); 521 | 522 | } 523 | 524 | 525 | var maxBarHeight = Math.max(Math.abs(barBottomY - barMaxTopY), Math.abs(barBottomY - barMinTopY)); 526 | var maxBarAbsData = Math.max(Math.abs(minData), Math.abs(maxData)); 527 | 528 | var x = marginLeft; 529 | var y = barBottomY; 530 | var barHeight = 0; 531 | 532 | var di = 0; 533 | 534 | for(var i=0; i=0){ 581 | context.textAlign = 'left'; 582 | context.fillText(this.labels[i], this.labelMargin, 0); 583 | }else{ 584 | context.textAlign = 'right'; 585 | context.fillText(this.labels[i], -this.labelMargin, 0); 586 | } 587 | } 588 | 589 | //Draw the data value: 590 | 591 | context.font = this.dataValueFontStyle + ' ' + this.dataValueFontHeight + 'px '+ this.dataValueFont; 592 | context.fillStyle = this.dataValueFillStyle; 593 | context.textBaseline = 'bottom'; 594 | if(di>=0){ 595 | context.textAlign = 'left'; 596 | context.fillText(di, this.labelMargin, 0); 597 | }else{ 598 | context.textAlign = 'right'; 599 | context.fillText(di, -this.labelMargin, 0); 600 | } 601 | 602 | context.restore(); 603 | 604 | //Update x: 605 | 606 | x = x + barWidth + this.barHGap; 607 | } 608 | 609 | context.restore(); 610 | 611 | } 612 | 613 | 614 | 615 | this.animateVerticalBarChart = function() { 616 | var aw = this, 617 | numFrames = this.animationFrames, 618 | currentFrame = 0, 619 | 620 | maxData = this.data.max(), 621 | minData = this.data.min(), 622 | dataLen = this.data.length, 623 | 624 | context = this.ctx, 625 | 626 | marginLeft = this.marginLeft 627 | marginTop = this.marginTop 628 | marginTopCurrent = 0; 629 | 630 | 631 | if(this.title!=null){ 632 | marginLeft += this.titleFontHeight + this.titleMargin; 633 | } 634 | 635 | var barWidth = (this.width - marginLeft - this.marginRight - (dataLen-1) * this.barHGap) / dataLen; 636 | 637 | context.font = this.labelFontStyle + ' ' + this.labelFontHeight + 'px '+ this.labelFont; 638 | var maxLabelWidth = 0; 639 | var labelWidth = 0; 640 | for(var i=0; imaxLabelWidth){ 643 | maxLabelWidth = labelWidth; 644 | } 645 | } 646 | 647 | context.font = this.dataValueFontStyle + ' ' + this.dataValueFontHeight + 'px '+ this.dataValueFont; 648 | var maxDataValueWidth = 0; 649 | var dataValueWidth = 0; 650 | for(var i=0; imaxDataValueWidth){ 653 | maxDataValueWidth = dataValueWidth; 654 | } 655 | } 656 | 657 | var barMaxTopY = this.marginTop + Math.max( (this.labelMargin + maxLabelWidth), (this.dataValueMargin + maxDataValueWidth) ); 658 | 659 | var barMinTopY = this.height - this.marginBottom; 660 | 661 | var barBottomY = this.height - this.marginBottom; 662 | 663 | if(minData<0){ 664 | 665 | barMinTopY = this.height - this.marginBottom - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight; 666 | 667 | barBottomY = barMinTopY + ((this.height - this.marginBottom - barMaxTopY - this.labelMargin - this.labelFontHeight - this.dataValueMargin - this.dataValueFontHeight) * minData) / (Math.abs(minData)+maxData); 668 | 669 | } 670 | 671 | 672 | var maxBarHeight = Math.max(Math.abs(barBottomY - barMaxTopY), Math.abs(barBottomY - barMinTopY)); 673 | var maxBarAbsData = Math.max(Math.abs(minData), Math.abs(maxData)); 674 | 675 | 676 | var belowZeroMaxBarHeight = 0; 677 | if(minData<0){ 678 | belowZeroMaxBarHeight = Math.abs(minData * maxBarHeight / maxBarAbsData); 679 | } 680 | 681 | var chartAreaHeight = maxData * maxBarHeight / maxBarAbsData + belowZeroMaxBarHeight, 682 | changeOfMarginBottom = 0, 683 | changeOfMarginTop = 0; 684 | 685 | this.marginBottom += belowZeroMaxBarHeight; 686 | this.marginTop += chartAreaHeight - belowZeroMaxBarHeight; 687 | changeOfMarginBottom = belowZeroMaxBarHeight / numFrames; 688 | changeOfMarginTop = (chartAreaHeight - belowZeroMaxBarHeight) / numFrames; 689 | 690 | var updateVerticalBarChart = function() { 691 | if(currentFrame++ < numFrames) { 692 | 693 | aw.marginBottom -= changeOfMarginBottom; 694 | aw.marginTop -= changeOfMarginTop; 695 | 696 | aw.ctx.clearRect(0, 0, aw.width, aw.height); 697 | aw.drawVerticalBarChart(); 698 | 699 | marginTopCurrent = aw.marginTop; 700 | aw.marginTop = marginTop; 701 | aw.drawTitleAndBorders(); 702 | aw.marginTop = marginTopCurrent; 703 | 704 | // Standard 705 | if (typeof(window.requestAnimationFrame) == 'function') { 706 | window.requestAnimationFrame(updateVerticalBarChart); 707 | 708 | // IE 10+ 709 | } else if (typeof(window.msRequestAnimationFrame) == 'function') { 710 | window.msRequestAnimationFrame(updateVerticalBarChart); 711 | 712 | // Chrome 713 | } else if (typeof(window.webkitRequestAnimationFrame) == 'function') { 714 | window.webkitRequestAnimationFrame(updateVerticalBarChart); 715 | 716 | // Firefox 717 | } else if (window.mozRequestAnimationFrame) { // Seems rather slow in FF6 - so disabled 718 | window.mozRequestAnimationFrame(updateVerticalBarChart); 719 | 720 | // Default fallback to setTimeout 721 | } else { 722 | setTimeout(updateVerticalBarChart, 16.6666666); 723 | } 724 | } 725 | } 726 | 727 | updateVerticalBarChart(); 728 | 729 | } 730 | 731 | 732 | 733 | this.drawPieChart = function(ring){ 734 | var context = this.ctx; 735 | context.lineWidth = this.pieBorderWidth; 736 | 737 | var dataSum = 0, 738 | dataSumForStartAngle = 0, 739 | dataLen = this.data.length; 740 | 741 | for (var i=0; imaxLabelWidth){ 776 | maxLabelWidth = labelWidth; 777 | } 778 | } 779 | 780 | radius = radius - maxLabelWidth - this.labelMargin; 781 | 782 | var startAngle = this.pieStart* doublePI / dataSumForStartAngle; 783 | var currentAngle = startAngle; 784 | var endAngle = 0; 785 | var incAngleBy = 0; 786 | 787 | for(var i=0; iMath.PI/2) && (mAngle<=3*(Math.PI/2)) ){ 910 | var translateXBy = radius + this.labelMargin + context.measureText(this.labels[i]).width / 2; 911 | context.translate(translateXBy, 0); 912 | context.rotate(Math.PI); 913 | context.translate(-translateXBy, 0); 914 | } 915 | context.textBaseline = 'middle'; 916 | context.fillText(this.labels[i], radius+this.labelMargin, 0); 917 | } 918 | 919 | context.restore(); 920 | currentAngle = endAngle; 921 | } 922 | } 923 | 924 | 925 | 926 | this.drawExplodedPieChart = function(){ 927 | var context = this.ctx; 928 | context.lineWidth = this.pieBorderWidth; 929 | 930 | var dataSum = 0, 931 | dataSumForStartAngle = 0, 932 | dataLen = this.data.length; 933 | 934 | for (var i=0; imaxLabelWidth){ 969 | maxLabelWidth = labelWidth; 970 | } 971 | } 972 | 973 | radius = radius - maxLabelWidth - this.labelMargin; 974 | 975 | var currentAngle = this.pieStart* doublePI / dataSumForStartAngle; 976 | var endAngle = 0; 977 | var incAngleBy = 0; 978 | var halfAngle = 0; 979 | var mAngle = 0; 980 | for(var i=0; iMath.PI/2) && (mAngle<=3*(Math.PI/2)) ){ 1033 | var translateXBy = radius + this.labelMargin + context.measureText(this.labels[i]).width / 2; 1034 | context.translate(translateXBy, 0); 1035 | context.rotate(Math.PI); 1036 | context.translate(-translateXBy, 0); 1037 | } 1038 | context.textBaseline = 'middle'; 1039 | context.fillText(this.labels[i], radius+this.labelMargin, 0); 1040 | } 1041 | 1042 | 1043 | // Restore the context: 1044 | 1045 | context.restore(); 1046 | currentAngle = endAngle; 1047 | 1048 | } 1049 | 1050 | } 1051 | 1052 | 1053 | 1054 | this.animatePieChart = function(pieType){ 1055 | var dataSum = 0, 1056 | pieTotalReal = this.pieTotal, 1057 | aw = this, 1058 | numFrames = this.animationFrames, 1059 | currentFrame = 0, 1060 | pieAreaWidth = this.width - this.marginLeft - this.marginRight, 1061 | pieAreaHeight = this.height - this.marginTop - this.marginBottom, 1062 | marginTop = this.marginTop, 1063 | marginLeft = this.marginLeft; 1064 | 1065 | if(this.title){ 1066 | pieAreaHeight = pieAreaHeight - this.titleFontHeight - this.titleMargin; 1067 | marginTop += this.titleFontHeight + this.titleMargin; 1068 | }; 1069 | 1070 | for(var i=0; imaxYAxisLabelWidth){ 1165 | maxYAxisLabelWidth = yAxisLabelWidth; 1166 | } 1167 | } 1168 | 1169 | var perCentMaxWidth = context.measureText("100%").width; 1170 | 1171 | // Calculate the chart size and position: 1172 | 1173 | var chartWidth = this.width - this.marginLeft - this.marginRight - 2*this.chartMarkerSize - maxYAxisLabelWidth - perCentMaxWidth - 2*this.yAxisLabelMargin; 1174 | var chartHeight = this.height - this.marginTop - this.marginBottom; 1175 | 1176 | var chartTopLeftX = this.marginLeft + this.chartMarkerSize + maxYAxisLabelWidth + this.yAxisLabelMargin; 1177 | var chartTopLeftY = this.marginTop; 1178 | 1179 | 1180 | if(this.title){ 1181 | chartHeight -= this.titleFontHeight + this.titleMargin; 1182 | chartTopLeftY += this.titleFontHeight + this.titleMargin; 1183 | } 1184 | 1185 | 1186 | // Draw the chart's background: 1187 | 1188 | context.save(); 1189 | 1190 | context.translate(chartTopLeftX, chartTopLeftY); 1191 | 1192 | context.fillStyle = this.chartBackgroundFillStyle; 1193 | context.fillRect(0,0,chartWidth,chartHeight); 1194 | 1195 | 1196 | // Draw the markers, horizontal lines, and axis' labels: 1197 | 1198 | var yStep = chartHeight / 10; 1199 | var lineY = 0; 1200 | 1201 | context.lineWidth = this.chartHorizontalLineWidth; 1202 | context.font = this.yAxisLabelFontStyle + ' ' + this.yAxisLabelFontHeight + 'px '+ this.yAxisLabelFont; 1203 | 1204 | for(var i=0; i<=10; i++){ 1205 | lineY = i*yStep; 1206 | 1207 | if( i>0 && i<10){ 1208 | 1209 | context.strokeStyle = this.chartHorizontalLineStrokeStyle; 1210 | context.beginPath(); 1211 | context.moveTo(0,lineY); 1212 | context.lineTo(chartWidth,lineY); 1213 | context.stroke(); 1214 | 1215 | } 1216 | 1217 | context.strokeStyle = this.chartBorderStrokeStyle; 1218 | context.beginPath(); 1219 | context.moveTo(-this.chartMarkerSize,lineY); 1220 | context.lineTo(0,lineY); 1221 | context.stroke(); 1222 | 1223 | context.beginPath(); 1224 | context.moveTo(chartWidth,lineY); 1225 | context.lineTo(chartWidth+this.chartMarkerSize,lineY); 1226 | context.stroke(); 1227 | 1228 | context.fillStyle = this.yAxisLabelFillStyle; 1229 | context.textAlign = 'right'; 1230 | context.textBaseline = 'middle'; 1231 | context.fillText(yAxisValues[10-i], -this.chartMarkerSize-this.yAxisLabelMargin, lineY); 1232 | 1233 | context.textAlign = 'left'; 1234 | context.fillText( ((10-i)*10)+'%', chartWidth+this.chartMarkerSize+this.yAxisLabelMargin, lineY); 1235 | } 1236 | 1237 | // Draw the bars: 1238 | 1239 | context.save(); 1240 | 1241 | context.translate(0, chartHeight); 1242 | 1243 | var barWidth = (chartWidth-2*this.barHGap) / n; 1244 | var barHeight = 0; 1245 | 1246 | var halfBarWidth = barWidth/2; 1247 | 1248 | var y = 0; 1249 | var x = this.barHGap; 1250 | var x1 = x; 1251 | var y1 = 0; 1252 | var x2 = 0; 1253 | var y2 = 0; 1254 | 1255 | for(var i=0; i=0){ 1315 | context.textBaseline = 'bottom'; 1316 | context.fillText(this.labels[indices[i]], x + halfBarWidth, - barHeight - this.labelMargin, barWidth); 1317 | }else{ 1318 | context.textBaseline = 'top'; 1319 | context.fillText(this.labels[indices[i]], x + halfBarWidth, - barHeight + this.labelMargin, barWidth); 1320 | } 1321 | } 1322 | 1323 | // Draw the data value: 1324 | 1325 | context.font = this.dataValueFontStyle + ' ' + this.dataValueFontHeight + 'px '+ this.dataValueFont; 1326 | context.fillStyle = this.dataValueFillStyle; 1327 | context.textAlign = 'center'; 1328 | if(this.data[indices[i]]>=0){ 1329 | context.textBaseline = 'bottom'; 1330 | context.fillText(this.data[indices[i]], x + halfBarWidth, - barHeight - this.labelMargin - this.dataValueMargin, barWidth); 1331 | }else{ 1332 | context.textBaseline = 'top'; 1333 | context.fillText(this.data[indices[i]], x + halfBarWidth, - barHeight + this.labelMargin + this.dataValueMargin, barWidth); 1334 | } 1335 | 1336 | 1337 | // Update x: 1338 | 1339 | x = x + barWidth; 1340 | 1341 | } 1342 | 1343 | // Draw the points: 1344 | 1345 | x = this.barHGap; 1346 | x1 = x; 1347 | y1 = 0; 1348 | x2 = 0; 1349 | y2 = 0; 1350 | 1351 | context.fillStyle = this.chartPointFillStyle; 1352 | context.beginPath(); 1353 | context.arc(x1, y1, this.chartPointRadius, 0, 2*Math.PI, false); 1354 | context.fill(); 1355 | 1356 | for(var i=0; i