From a9dcf88378a1e626fc4cf58c8708053ffbe89cf7 Mon Sep 17 00:00:00 2001 From: Nick Downie Date: Sun, 17 Mar 2013 23:57:50 +0000 Subject: [PATCH] First commit. Version 0.1 Examples of the six charts that can be created, and the Chart.js library. --- .gitignore | 2 + Chart.js | 1433 ++++++++++++++++++++++++++++++++++++++++++++++++ Chart.min.js | 40 ++ bar.html | 39 ++ doughnut.html | 46 ++ line.html | 43 ++ pie.html | 38 ++ polarArea.html | 44 ++ radar.html | 43 ++ readme.md | 8 + sixup.html | 155 ++++++ 11 files changed, 1891 insertions(+) create mode 100644 .gitignore create mode 100755 Chart.js create mode 100644 Chart.min.js create mode 100644 bar.html create mode 100644 doughnut.html create mode 100644 line.html create mode 100644 pie.html create mode 100755 polarArea.html create mode 100644 radar.html create mode 100644 readme.md create mode 100644 sixup.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9bea4330f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/Chart.js b/Chart.js new file mode 100755 index 000000000..08f726363 --- /dev/null +++ b/Chart.js @@ -0,0 +1,1433 @@ +//Define the global Chart Variable as a class. +var Chart = function(context){ + + var chart = this; + + + //Easing functions adapted from Robert Penner's easing equations + //http://www.robertpenner.com/easing/ + + var animationOptions = { + linear : function (t){ + return t; + }, + easeInQuad: function (t) { + return t*t; + }, + easeOutQuad: function (t) { + return -1 *t*(t-2); + }, + easeInOutQuad: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t; + return -1/2 * ((--t)*(t-2) - 1); + }, + easeInCubic: function (t) { + return t*t*t; + }, + easeOutCubic: function (t) { + return 1*((t=t/1-1)*t*t + 1); + }, + easeInOutCubic: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t; + return 1/2*((t-=2)*t*t + 2); + }, + easeInQuart: function (t) { + return t*t*t*t; + }, + easeOutQuart: function (t) { + return -1 * ((t=t/1-1)*t*t*t - 1); + }, + easeInOutQuart: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t*t; + return -1/2 * ((t-=2)*t*t*t - 2); + }, + easeInQuint: function (t) { + return 1*(t/=1)*t*t*t*t; + }, + easeOutQuint: function (t) { + return 1*((t=t/1-1)*t*t*t*t + 1); + }, + easeInOutQuint: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t*t*t; + return 1/2*((t-=2)*t*t*t*t + 2); + }, + easeInSine: function (t) { + return -1 * Math.cos(t/1 * (Math.PI/2)) + 1; + }, + easeOutSine: function (t) { + return 1 * Math.sin(t/1 * (Math.PI/2)); + }, + easeInOutSine: function (t) { + return -1/2 * (Math.cos(Math.PI*t/1) - 1); + }, + easeInExpo: function (t) { + return (t==0) ? 1 : 1 * Math.pow(2, 10 * (t/1 - 1)); + }, + easeOutExpo: function (t) { + return (t==1) ? 1 : 1 * (-Math.pow(2, -10 * t/1) + 1); + }, + easeInOutExpo: function (t) { + if (t==0) return 0; + if (t==1) return 1; + if ((t/=1/2) < 1) return 1/2 * Math.pow(2, 10 * (t - 1)); + return 1/2 * (-Math.pow(2, -10 * --t) + 2); + }, + easeInCirc: function (t) { + if (t>=1) return t; + return -1 * (Math.sqrt(1 - (t/=1)*t) - 1); + }, + easeOutCirc: function (t) { + return 1 * Math.sqrt(1 - (t=t/1-1)*t); + }, + easeInOutCirc: function (t) { + if ((t/=1/2) < 1) return -1/2 * (Math.sqrt(1 - t*t) - 1); + return 1/2 * (Math.sqrt(1 - (t-=2)*t) + 1); + }, + easeInElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); + }, + easeOutElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*1-s)*(2*Math.PI)/p ) + 1; + }, + easeInOutElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1/2)==2) return 1; if (!p) p=1*(.3*1.5); + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )*.5 + 1; + }, + easeInBack: function (t) { + var s = 1.70158; + return 1*(t/=1)*t*((s+1)*t - s); + }, + easeOutBack: function (t) { + var s = 1.70158; + return 1*((t=t/1-1)*t*((s+1)*t + s) + 1); + }, + easeInOutBack: function (t) { + var s = 1.70158; + if ((t/=1/2) < 1) return 1/2*(t*t*(((s*=(1.525))+1)*t - s)); + return 1/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2); + }, + easeInBounce: function (t) { + return 1 - animationOptions.easeOutBounce (1-t); + }, + easeOutBounce: function (t) { + if ((t/=1) < (1/2.75)) { + return 1*(7.5625*t*t); + } else if (t < (2/2.75)) { + return 1*(7.5625*(t-=(1.5/2.75))*t + .75); + } else if (t < (2.5/2.75)) { + return 1*(7.5625*(t-=(2.25/2.75))*t + .9375); + } else { + return 1*(7.5625*(t-=(2.625/2.75))*t + .984375); + } + }, + easeInOutBounce: function (t) { + if (t < 1/2) return animationOptions.easeInBounce (t*2) * .5; + return animationOptions.easeOutBounce (t*2-1) * .5 + 1*.5; + } + }; + + //Variables global to the chart + var width = context.canvas.width; + var height = context.canvas.height; + + + //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. + if (window.devicePixelRatio) { + context.canvas.style.width = width + "px"; + context.canvas.style.height = height + "px"; + context.canvas.height = height * window.devicePixelRatio; + context.canvas.width = width * window.devicePixelRatio; + context.scale(window.devicePixelRatio, window.devicePixelRatio); + } + + this.PolarArea = function(data,options){ + + chart.PolarArea.defaults = { + scaleOverlay : true, + scaleOverride : false, + scaleSteps : null, + scaleStepWidth : null, + scaleStartValue : null, + scaleShowLine : true, + scaleLineColor : "rgba(0,0,0,.1)", + scaleLineWidth : 1, + scaleShowLabels : true, + scaleLabel : "<%=value%>", + scaleFontFamily : "'Arial'", + scaleFontSize : 12, + scaleFontStyle : "normal", + scaleFontColor : "#666", + scaleShowLabelBackdrop : true, + scaleBackdropColor : "rgba(255,255,255,0.75)", + scaleBackdropPaddingY : 2, + scaleBackdropPaddingX : 2, + segmentShowStroke : true, + segmentStrokeColor : "#fff", + segmentStrokeWidth : 2, + animation : true, + animationSteps : 100, + animationEasing : "easeOutBounce", + animateRotate : true, + animateScale : false, + onAnimationComplete : null + }; + + var config = (options)? mergeChartConfig(chart.PolarArea.defaults,options) : chart.PolarArea.defaults; + + return new PolarArea(data,config,context); + }; + + this.Radar = function(data,options){ + + chart.Radar.defaults = { + scaleOverlay : false, + scaleOverride : false, + scaleSteps : null, + scaleStepWidth : null, + scaleStartValue : null, + scaleShowLine : true, + scaleLineColor : "rgba(0,0,0,.1)", + scaleLineWidth : 1, + scaleShowLabels : false, + scaleLabel : "<%=value%>", + scaleFontFamily : "'Arial'", + scaleFontSize : 12, + scaleFontStyle : "normal", + scaleFontColor : "#666", + scaleShowLabelBackdrop : true, + scaleBackdropColor : "rgba(255,255,255,0.75)", + scaleBackdropPaddingY : 2, + scaleBackdropPaddingX : 2, + angleShowLineOut : true, + angleLineColor : "rgba(0,0,0,.1)", + angleLineWidth : 1, + pointLabelFontFamily : "'Arial'", + pointLabelFontStyle : "normal", + pointLabelFontSize : 12, + pointLabelFontColor : "#666", + pointDot : true, + pointDotRadius : 3, + pointDotStrokeWidth : 1, + datasetStroke : true, + datasetStrokeWidth : 2, + datasetFill : true, + animation : true, + animationSteps : 60, + animationEasing : "easeOutQuart", + onAnimationComplete : null + }; + + var config = (options)? mergeChartConfig(chart.Radar.defaults,options) : chart.Radar.defaults; + + return new Radar(data,config,context); + }; + + this.Pie = function(data,options){ + chart.Pie.defaults = { + segmentShowStroke : true, + segmentStrokeColor : "#fff", + segmentStrokeWidth : 2, + animation : true, + animationSteps : 100, + animationEasing : "easeOutBounce", + animateRotate : true, + animateScale : false, + onAnimationComplete : null + }; + + var config = (options)? mergeChartConfig(chart.Pie.defaults,options) : chart.Pie.defaults; + + return new Pie(data,config,context); + }; + + this.Doughnut = function(data,options){ + + chart.Doughnut.defaults = { + segmentShowStroke : true, + segmentStrokeColor : "#fff", + segmentStrokeWidth : 2, + percentageInnerCutout : 50, + animation : true, + animationSteps : 100, + animationEasing : "easeOutBounce", + animateRotate : true, + animateScale : false, + onAnimationComplete : null + }; + + var config = (options)? mergeChartConfig(chart.Doughnut.defaults,options) : chart.Doughnut.defaults; + + return new Doughnut(data,config,context); + + }; + + this.Line = function(data,options){ + + chart.Line.defaults = { + scaleOverlay : false, + scaleOverride : false, + scaleSteps : null, + scaleStepWidth : null, + scaleStartValue : null, + scaleLineColor : "rgba(0,0,0,.1)", + scaleLineWidth : 1, + scaleShowLabels : true, + scaleLabel : "<%=value%>", + scaleFontFamily : "'Arial'", + scaleFontSize : 12, + scaleFontStyle : "normal", + scaleFontColor : "#666", + scaleShowGridLines : true, + scaleGridLineColor : "rgba(0,0,0,.05)", + scaleGridLineWidth : 1, + bezierCurve : true, + pointDot : true, + pointDotRadius : 4, + pointDotStrokeWidth : 2, + datasetStroke : true, + datasetStrokeWidth : 2, + datasetFill : true, + animation : true, + animationSteps : 60, + animationEasing : "easeOutQuart", + onAnimationComplete : null + }; + var config = (options) ? mergeChartConfig(chart.Line.defaults,options) : chart.Line.defaults; + + return new Line(data,config,context); + } + + this.Bar = function(data,options){ + chart.Bar.defaults = { + scaleOverlay : false, + scaleOverride : false, + scaleSteps : null, + scaleStepWidth : null, + scaleStartValue : null, + scaleLineColor : "rgba(0,0,0,.1)", + scaleLineWidth : 1, + scaleShowLabels : true, + scaleLabel : "<%=value%>", + scaleFontFamily : "'Arial'", + scaleFontSize : 12, + scaleFontStyle : "normal", + scaleFontColor : "#666", + scaleShowGridLines : true, + scaleGridLineColor : "rgba(0,0,0,.05)", + scaleGridLineWidth : 1, + barShowStroke : true, + barStrokeWidth : 2, + barValueSpacing : 5, + barDatasetSpacing : 1, + animation : true, + animationSteps : 60, + animationEasing : "easeOutQuart", + onAnimationComplete : null + }; + var config = (options) ? mergeChartConfig(chart.Bar.defaults,options) : chart.Bar.defaults; + + return new Bar(data,config,context); + } + + var clear = function(c){ + c.clearRect(0, 0, width, height); + }; + + var PolarArea = function(data,config,ctx){ + var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString; + + + calculateDrawingSizes(); + + valueBounds = getValueBounds(); + + labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null; + + //Check and set the scale + if (!config.scaleOverride){ + + calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); + } + else { + calculatedScale = { + steps : config.scaleSteps, + stepValue : config.scaleStepWidth, + graphMin : config.scaleStartValue, + labels : [] + } + for (var i=0; i upperValue) {upperValue = data[i].value;} + if (data[i].value < lowerValue) {lowerValue = data[i].value;} + }; + + var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); + var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); + + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + + + } + } + + var Radar = function (data,config,ctx) { + var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString; + + //If no labels are defined set to an empty array, so referencing length for looping doesn't blow up. + if (!data.labels) data.labels = []; + + calculateDrawingSizes(); + + var valueBounds = getValueBounds(); + + labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null; + + //Check and set the scale + if (!config.scaleOverride){ + + calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); + } + else { + calculatedScale = { + steps : config.scaleSteps, + stepValue : config.scaleStepWidth, + graphMin : config.scaleStartValue, + labels : [] + } + for (var i=0; i Math.PI){ + ctx.textAlign = "right"; + } + else{ + ctx.textAlign = "left"; + } + + ctx.textBaseline = "middle"; + + ctx.fillText(data.labels[k],opposite,-adjacent); + + } + ctx.restore(); + }; + function calculateDrawingSizes(){ + maxSize = (Min([width,height])/2); + + labelHeight = config.scaleFontSize*2; + + var labelLength = 0; + for (var i=0; ilabelLength) labelLength = textMeasurement; + } + + //Figure out whats the largest - the height of the text or the width of what's there, and minus it from the maximum usable size. + maxSize -= Max([labelLength,((config.pointLabelFontSize/2)*1.5)]); + + maxSize -= config.pointLabelFontSize; + maxSize = CapValue(maxSize, null, 0); + scaleHeight = maxSize; + //If the label height is less than 5, set it to 5 so we don't have lines on top of each other. + labelHeight = Default(labelHeight,5); + }; + function getValueBounds() { + var upperValue = Number.MIN_VALUE; + var lowerValue = Number.MAX_VALUE; + + for (var i=0; i upperValue){upperValue = data.datasets[i].data[j]} + if (data.datasets[i].data[j] < lowerValue){lowerValue = data.datasets[i].data[j]} + } + } + + var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); + var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); + + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + + + } + } + + var Pie = function(data,config,ctx){ + var segmentTotal = 0; + + //In case we have a canvas that is not a square. Minus 5 pixels as padding round the edge. + var pieRadius = Min([height/2,width/2]) - 5; + + for (var i=0; i 0){ + ctx.save(); + ctx.textAlign = "right"; + } + else{ + ctx.textAlign = "center"; + } + ctx.fillStyle = config.scaleFontColor; + for (var i=0; i 0){ + ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize); + ctx.rotate(-(rotateLabels * (Math.PI/180))); + ctx.fillText(data.labels[i], 0,0); + ctx.restore(); + } + + else{ + ctx.fillText(data.labels[i], yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize+3); + } + + ctx.beginPath(); + ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY+3); + + //Check i isnt 0, so we dont go over the Y axis twice. + if(config.scaleShowGridLines && i>0){ + ctx.lineWidth = config.scaleGridLineWidth; + ctx.strokeStyle = config.scaleGridLineColor; + ctx.lineTo(yAxisPosX + i * valueHop, 5); + } + else{ + ctx.lineTo(yAxisPosX + i * valueHop, xAxisPosY+3); + } + ctx.stroke(); + } + + //Y axis + ctx.lineWidth = config.scaleLineWidth; + ctx.strokeStyle = config.scaleLineColor; + ctx.beginPath(); + ctx.moveTo(yAxisPosX,xAxisPosY+5); + ctx.lineTo(yAxisPosX,5); + ctx.stroke(); + + ctx.textAlign = "right"; + ctx.textBaseline = "middle"; + for (var j=0; j longestText)? measuredText : longestText; + } + //Add a little extra padding from the y axis + longestText +=10; + } + xAxisLength = width - longestText - widestXLabel; + valueHop = Math.floor(xAxisLength/(data.labels.length-1)); + + yAxisPosX = width-widestXLabel/2-xAxisLength; + xAxisPosY = scaleHeight + config.scaleFontSize/2; + } + function calculateDrawingSizes(){ + maxSize = height; + + //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees. + ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily; + widestXLabel = 1; + for (var i=0; i widestXLabel)? textLength : widestXLabel; + } + if (width/data.labels.length < widestXLabel){ + rotateLabels = 45; + if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){ + rotateLabels = 90; + maxSize -= widestXLabel; + } + else{ + maxSize -= Math.sin(rotateLabels) * widestXLabel; + } + } + else{ + maxSize -= config.scaleFontSize; + } + + //Add a little padding between the x line and the text + maxSize -= 5; + + + labelHeight = config.scaleFontSize; + + maxSize -= labelHeight; + //Set 5 pixels greater than the font size to allow for a little padding from the X axis. + + scaleHeight = maxSize; + + //Then get the area above we can safely draw on. + + } + function getValueBounds() { + var upperValue = Number.MIN_VALUE; + var lowerValue = Number.MAX_VALUE; + for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] }; + if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] }; + } + }; + + var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); + var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); + + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + + + } + + + } + + var Bar = function(data,config,ctx){ + var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString, valueHop,widestXLabel, xAxisLength,yAxisPosX,xAxisPosY,barWidth, rotateLabels = 0; + + calculateDrawingSizes(); + + valueBounds = getValueBounds(); + //Check and set the scale + labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : ""; + if (!config.scaleOverride){ + + calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString); + } + else { + calculatedScale = { + steps : config.scaleSteps, + stepValue : config.scaleStepWidth, + graphMin : config.scaleStartValue, + labels : [] + } + for (var i=0; i 0){ + ctx.save(); + ctx.textAlign = "right"; + } + else{ + ctx.textAlign = "center"; + } + ctx.fillStyle = config.scaleFontColor; + for (var i=0; i 0){ + ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize); + ctx.rotate(-(rotateLabels * (Math.PI/180))); + ctx.fillText(data.labels[i], 0,0); + ctx.restore(); + } + + else{ + ctx.fillText(data.labels[i], yAxisPosX + i*valueHop + valueHop/2,xAxisPosY + config.scaleFontSize+3); + } + + ctx.beginPath(); + ctx.moveTo(yAxisPosX + (i+1) * valueHop, xAxisPosY+3); + + //Check i isnt 0, so we dont go over the Y axis twice. + ctx.lineWidth = config.scaleGridLineWidth; + ctx.strokeStyle = config.scaleGridLineColor; + ctx.lineTo(yAxisPosX + (i+1) * valueHop, 5); + ctx.stroke(); + } + + //Y axis + ctx.lineWidth = config.scaleLineWidth; + ctx.strokeStyle = config.scaleLineColor; + ctx.beginPath(); + ctx.moveTo(yAxisPosX,xAxisPosY+5); + ctx.lineTo(yAxisPosX,5); + ctx.stroke(); + + ctx.textAlign = "right"; + ctx.textBaseline = "middle"; + for (var j=0; j longestText)? measuredText : longestText; + } + //Add a little extra padding from the y axis + longestText +=10; + } + xAxisLength = width - longestText - widestXLabel; + valueHop = Math.floor(xAxisLength/(data.labels.length)); + + barWidth = (valueHop - config.scaleGridLineWidth*2 - (config.barValueSpacing*2) - (config.barDatasetSpacing*data.datasets.length-1) - ((config.barStrokeWidth/2)*data.datasets.length-1))/data.datasets.length; + + yAxisPosX = width-widestXLabel/2-xAxisLength; + xAxisPosY = scaleHeight + config.scaleFontSize/2; + } + function calculateDrawingSizes(){ + maxSize = height; + + //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees. + ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily; + widestXLabel = 1; + for (var i=0; i widestXLabel)? textLength : widestXLabel; + } + if (width/data.labels.length < widestXLabel){ + rotateLabels = 45; + if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){ + rotateLabels = 90; + maxSize -= widestXLabel; + } + else{ + maxSize -= Math.sin(rotateLabels) * widestXLabel; + } + } + else{ + maxSize -= config.scaleFontSize; + } + + //Add a little padding between the x line and the text + maxSize -= 5; + + + labelHeight = config.scaleFontSize; + + maxSize -= labelHeight; + //Set 5 pixels greater than the font size to allow for a little padding from the X axis. + + scaleHeight = maxSize; + + //Then get the area above we can safely draw on. + + } + function getValueBounds() { + var upperValue = Number.MIN_VALUE; + var lowerValue = Number.MAX_VALUE; + for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] }; + if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] }; + } + }; + + var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66))); + var minSteps = Math.floor((scaleHeight / labelHeight*0.5)); + + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + + + } + } + + function calculateOffset(val,calculatedScale,scaleHop){ + var outerValue = calculatedScale.steps * calculatedScale.stepValue; + var adjustedValue = val - calculatedScale.graphMin; + var scalingFactor = CapValue(adjustedValue/outerValue,1,0); + return (scaleHop*calculatedScale.steps) * scalingFactor; + } + + function animationLoop(config,drawScale,drawData,ctx){ + var animFrameAmount = (config.animation)? 1/CapValue(config.animationSteps,Number.MAX_VALUE,1) : 1, + easingFunction = animationOptions[config.animationEasing], + percentAnimComplete =(config.animation)? 0 : 1; + + + + if (typeof drawScale !== "function") drawScale = function(){}; + + requestAnimFrame(animLoop); + + function animateFrame(){ + var easeAdjustedAnimationPercent =(config.animation)? CapValue(easingFunction(percentAnimComplete),null,0) : 1; + clear(ctx); + if(config.scaleOverlay){ + drawData(easeAdjustedAnimationPercent); + drawScale(); + } else { + drawScale(); + drawData(easeAdjustedAnimationPercent); + } + } + function animLoop(){ + //We need to check if the animation is incomplete (less than 1), or complete (1). + percentAnimComplete += animFrameAmount; + animateFrame(); + //Stop the loop continuing forever + if (percentAnimComplete <= 1){ + requestAnimFrame(animLoop); + } + else{ + if (typeof config.onAnimationComplete == "function") config.onAnimationComplete(); + } + + } + + } + + //Declare global functions to be called within this namespace here. + + + // shim layer with setTimeout fallback + var requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { + window.setTimeout(callback, 1000 / 60); + }; + })(); + + function calculateScale(drawingHeight,maxSteps,minSteps,maxValue,minValue,labelTemplateString){ + var graphMin,graphMax,graphRange,stepValue,numberOfSteps,valueRange,rangeOrderOfMagnitude,decimalNum; + + valueRange = maxValue - minValue; + + rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange); + + graphMin = Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); + + graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude); + + graphRange = graphMax - graphMin; + + stepValue = Math.pow(10, rangeOrderOfMagnitude); + + numberOfSteps = Math.round(graphRange / stepValue); + + //Compare number of steps to the max and min for that size graph, and add in half steps if need be. + while(numberOfSteps < minSteps || numberOfSteps > maxSteps) { + if (numberOfSteps < minSteps){ + stepValue /= 2; + numberOfSteps = Math.round(graphRange/stepValue); + } + else{ + stepValue *=2; + numberOfSteps = Math.round(graphRange/stepValue); + } + }; + + + + //Create an array of all the labels by interpolating the string. + + var labels = []; + + if(labelTemplateString){ + //Fix floating point errors by setting to fixed the on the same decimal as the stepValue. + for (var i=1; i maxValue ) { + return maxValue; + } + } + if(isNumber(minValue)){ + if ( valueToCap < minValue ){ + return minValue; + } + } + return valueToCap; + } + function getDecimalPlaces (num){ + var numberOfDecimalPlaces; + if (num%1!=0){ + return num.toString().split(".")[1].length + } + else{ + return 0; + } + + } + + function mergeChartConfig(defaults,userDefined){ + var returnObj = {}; + for (var attrname in defaults) { returnObj[attrname] = defaults[attrname]; } + for (var attrname in userDefined) { returnObj[attrname] = userDefined[attrname]; } + return returnObj; + } + + //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/ + var cache = {}; + + function tmpl(str, data){ + // Figure out if we're getting a template, or if we need to + // load the template - and be sure to cache the result. + var fn = !/\W/.test(str) ? + cache[str] = cache[str] || + tmpl(document.getElementById(str).innerHTML) : + + // Generate a reusable function that will serve as a template + // generator (and which will be cached). + new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + + // Introduce the data as local variables using with(){} + "with(obj){p.push('" + + + // Convert the template into pure JavaScript + str + .replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + + // Provide some basic currying to the user + return data ? fn( data ) : fn; + }; +} + + + diff --git a/Chart.min.js b/Chart.min.js new file mode 100644 index 000000000..e4de2a1cd --- /dev/null +++ b/Chart.min.js @@ -0,0 +1,40 @@ +var Chart=function(s){function v(a,c,b){a=B((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,d){function l(){f+=g;var m=a.animation?B(h(f),null,0):1;d.clearRect(0,0,q,u);a.scaleOverlay?(b(m),c()):(c(),b(m));if(1>=f)E(l);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var g=a.animation?1/B(a.animationSteps,Number.MAX_VALUE,1):1,h=C[a.animationEasing],f=a.animation?0:1;"function"!==typeof c&&(c=function(){});E(l)}function D(a,c,b,d,l,g){var h;a= +Math.floor(Math.log(d-l)/Math.LN10);l=Math.floor(l/(1*Math.pow(10,a)))*Math.pow(10,a);h=Math.ceil(d/(1*Math.pow(10,a)))*Math.pow(10,a)-l;d=Math.pow(10,a);for(a=Math.round(h/d);ac;)d=ac?c:!isNaN(parseFloat(b))&&isFinite(b)&&a)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?b(c):b}var r= +this,C={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?0.5*a*a*a* +a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==a?1:1* +(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,d=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);da?-0.5*d*Math.pow(2,10*(a-=1))* +Math.sin((1*a-c)*2*Math.PI/b):0.5*d*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-C.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*a+0.75): +a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*C.easeInBounce(2*a):0.5*C.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0, +scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce", +animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?z(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)", +scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?z(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a, +c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?z(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1, +onAnimationComplete:null};var b=c?z(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0, +pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?z(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'", +scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?z(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var d,l,g,h,f,m,j,e,k;f=Math.min.apply(Math,[q,u])/2;f-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]); +e=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(e+=2*c.scaleBackdropPaddingY,f-=1.5*c.scaleBackdropPaddingY);k=f;e=e?e:5;d=Number.MIN_VALUE;l=Number.MAX_VALUE;for(g=0;gd&&(d=a[g].value),a[g].valuek&&(k=l);f-=Math.max.apply(Math,[k,1.5*(c.pointLabelFontSize/ +2)]);f-=c.pointLabelFontSize;k=f=B(f,null,0);e=e?e:5;d=Number.MIN_VALUE;l=Number.MAX_VALUE;for(g=0;gd&&(d=a.datasets[g].data[h]),a.datasets[g].data[h]Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[e],g,-h)}b.restore()},function(d){var e= +2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);b.rotate(e);for(var f=0;ft?d:t;q/a.labels.lengthd&&(d=a.datasets[g].data[h]),a.datasets[g].data[h]e?l:e;e+=10}r=q-e-t;k=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=f+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0t?d:t;q/a.labels.lengthd&&(d=a.datasets[g].data[h]),a.datasets[g].data[h]e?l:e;e+=10}r=q-e-t;k=Math.floor(r/a.labels.length);s=(k-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=f+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor; +b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0 + + + Bar Chart + + + + + + + + + + + diff --git a/doughnut.html b/doughnut.html new file mode 100644 index 000000000..db9fcf7ec --- /dev/null +++ b/doughnut.html @@ -0,0 +1,46 @@ + + + + Doughnut Chart + + + + + + + + + + + diff --git a/line.html b/line.html new file mode 100644 index 000000000..1dd08d48d --- /dev/null +++ b/line.html @@ -0,0 +1,43 @@ + + + + Line Chart + + + + + + + + + + + diff --git a/pie.html b/pie.html new file mode 100644 index 000000000..dd8371671 --- /dev/null +++ b/pie.html @@ -0,0 +1,38 @@ + + + + Radar Chart + + + + + + + + + + + diff --git a/polarArea.html b/polarArea.html new file mode 100755 index 000000000..81375a59b --- /dev/null +++ b/polarArea.html @@ -0,0 +1,44 @@ + + + + Polar Area Chart + + + + + + + + + + + diff --git a/radar.html b/radar.html new file mode 100644 index 000000000..2690cff5b --- /dev/null +++ b/radar.html @@ -0,0 +1,43 @@ + + + + Radar Chart + + + + + + + + + + + diff --git a/readme.md b/readme.md new file mode 100644 index 000000000..653d5570e --- /dev/null +++ b/readme.md @@ -0,0 +1,8 @@ +Chart.js +======= +*Simple HTML5 Charts using the tag* [chartjs.org](http://www.chartjs.org) + + +Documentation +------- +You can find documentation at [chartjs.org/docs](http://www.chartjs.org/docs). \ No newline at end of file diff --git a/sixup.html b/sixup.html new file mode 100644 index 000000000..1d36f273f --- /dev/null +++ b/sixup.html @@ -0,0 +1,155 @@ + + + + Doughnut Chart + + + + + +
+ + + + + + +
+ + + + +