js图表插件绘制各种类型图表

官网:http://www.bootcss.com/p/chart.js/
中文参考手册:http://www.bootcss.com/p/chart.js/docs/

一、生成折线图 :test.html


<html lang="en">
<head><meta charset="UTF-8"><title>Documenttitle>
head>
<body>
<script src="Chart.js">script>
<canvas id="myChart" width="400" height="400">canvas>
<script>var ctx = document.getElementById("myChart").getContext("2d");var data = {labels : ["January","February","March","April","May","June","July"],datasets : [{fillColor : "rgba(220,220,220,0.5)",strokeColor : "rgba(220,220,220,1)",pointColor : "rgba(220,220,220,1)",pointStrokeColor : "#fff",data : [65,59,90,81,56,55,40]},{fillColor : "rgba(151,187,205,0.5)",strokeColor : "rgba(151,187,205,1)",pointColor : "rgba(151,187,205,1)",pointStrokeColor : "#fff",data : [28,48,40,19,96,27,100]}]};var options={};new Chart(ctx).Line(data,options);
script>
body>
html>

Chart.js 代码:

/*!* Chart.js* http://chartjs.org/** Copyright 2013 Nick Downie* Released under the MIT license* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md*///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 chartvar 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 scaleif (!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; iif(labelTemplateString){calculatedScale.labels.push(tmpl(labelTemplateString,{value:(config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimalPlaces (config.scaleStepWidth))}));}}}scaleHop = maxSize/(calculatedScale.steps);//Wrap in an animation loop wrapperanimationLoop(config,drawScale,drawAllSegments,ctx);function calculateDrawingSizes(){maxSize = (Min([width,height])/2);//Remove whatever is larger - the font size or line width.maxSize -= Max([config.scaleFontSize*0.5,config.scaleLineWidth*0.5]);labelHeight = config.scaleFontSize*2;//If we're drawing the backdrop - add the Y padding to the label height and remove from drawing region.if (config.scaleShowLabelBackdrop){labelHeight += (2 * config.scaleBackdropPaddingY);maxSize -= config.scaleBackdropPaddingY*1.5;}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 drawScale(){for (var i=0; i//If the line object is thereif (config.scaleShowLine){ctx.beginPath();ctx.arc(width/2, height/2, scaleHop * (i + 1), 0, (Math.PI * 2), true);ctx.strokeStyle = config.scaleLineColor;ctx.lineWidth = config.scaleLineWidth;ctx.stroke();}if (config.scaleShowLabels){ctx.textAlign = "center";ctx.font = config.scaleFontStyle + " " + config.scaleFontSize + "px " + config.scaleFontFamily;var label =  calculatedScale.labels[i];//If the backdrop object is within the font objectif (config.scaleShowLabelBackdrop){var textWidth = ctx.measureText(label).width;ctx.fillStyle = config.scaleBackdropColor;ctx.beginPath();ctx.rect(Math.round(width/2 - textWidth/2 - config.scaleBackdropPaddingX),     //XMath.round(height/2 - (scaleHop * (i + 1)) - config.scaleFontSize*0.5 - config.scaleBackdropPaddingY),//YMath.round(textWidth + (config.scaleBackdropPaddingX*2)), //WidthMath.round(config.scaleFontSize + (config.scaleBackdropPaddingY*2)) //Height);ctx.fill();}ctx.textBaseline = "middle";ctx.fillStyle = config.scaleFontColor;ctx.fillText(label,width/2,height/2 - (scaleHop * (i + 1)));}}}function drawAllSegments(animationDecimal){var startAngle = -Math.PI/2,angleStep = (Math.PI*2)/data.length,scaleAnimation = 1,rotateAnimation = 1;if (config.animation) {if (config.animateScale) {scaleAnimation = animationDecimal;}if (config.animateRotate){rotateAnimation = animationDecimal;}}for (var i=0; i2,height/2,scaleAnimation * calculateOffset(data[i].value,calculatedScale,scaleHop),startAngle, startAngle + rotateAnimation*angleStep, false);ctx.lineTo(width/2,height/2);ctx.closePath();ctx.fillStyle = data[i].color;ctx.fill();if(config.segmentShowStroke){ctx.strokeStyle = config.segmentStrokeColor;ctx.lineWidth = config.segmentStrokeWidth;ctx.stroke();}startAngle += rotateAnimation*angleStep;}}function getValueBounds() {var upperValue = Number.MIN_VALUE;var lowerValue = Number.MAX_VALUE;for (var i=0; iif (data[i].value > 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 scaleif (!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; iif(labelTemplateString){calculatedScale.labels.push(tmpl(labelTemplateString,{value:(config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimalPlaces (config.scaleStepWidth))}));}}}scaleHop = maxSize/(calculatedScale.steps);animationLoop(config,drawScale,drawAllDataPoints,ctx);//Radar specific functions.function drawAllDataPoints(animationDecimal){var rotationDegree = (2*Math.PI)/data.datasets[0].data.length;ctx.save();//translate to the centre of the canvas.ctx.translate(width/2,height/2);//We accept multiple data sets for radar charts, so show loop through each setfor (var i=0; i0,animationDecimal*(-1*calculateOffset(data.datasets[i].data[0],calculatedScale,scaleHop)));for (var j=1; j0,animationDecimal*(-1*calculateOffset(data.datasets[i].data[j],calculatedScale,scaleHop)));}ctx.closePath();ctx.fillStyle = data.datasets[i].fillColor;ctx.strokeStyle = data.datasets[i].strokeColor;ctx.lineWidth = config.datasetStrokeWidth;ctx.fill();ctx.stroke();if (config.pointDot){ctx.fillStyle = data.datasets[i].pointColor;ctx.strokeStyle = data.datasets[i].pointStrokeColor;ctx.lineWidth = config.pointDotStrokeWidth;for (var k=0; k0,animationDecimal*(-1*calculateOffset(data.datasets[i].data[k],calculatedScale,scaleHop)),config.pointDotRadius,2*Math.PI,false);ctx.fill();ctx.stroke();}                   }ctx.rotate(rotationDegree);}ctx.restore();}function drawScale(){var rotationDegree = (2*Math.PI)/data.datasets[0].data.length;ctx.save();ctx.translate(width / 2, height / 2);   if (config.angleShowLineOut){ctx.strokeStyle = config.angleLineColor;                    ctx.lineWidth = config.angleLineWidth;for (var h=0; h0].data.length; h++){ctx.rotate(rotationDegree);ctx.beginPath();ctx.moveTo(0,0);ctx.lineTo(0,-maxSize);ctx.stroke();}}for (var i=0; iif(config.scaleShowLine){ctx.strokeStyle = config.scaleLineColor;ctx.lineWidth = config.scaleLineWidth;ctx.moveTo(0,-scaleHop * (i+1));                    for (var j=0; j0].data.length; j++){ctx.rotate(rotationDegree);ctx.lineTo(0,-scaleHop * (i+1));}ctx.closePath();ctx.stroke();           }if (config.scaleShowLabels){                ctx.textAlign = 'center';ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily; ctx.textBaseline = "middle";if (config.scaleShowLabelBackdrop){var textWidth = ctx.measureText(calculatedScale.labels[i]).width;ctx.fillStyle = config.scaleBackdropColor;ctx.beginPath();ctx.rect(Math.round(- textWidth/2 - config.scaleBackdropPaddingX),     //XMath.round((-scaleHop * (i + 1)) - config.scaleFontSize*0.5 - config.scaleBackdropPaddingY),//YMath.round(textWidth + (config.scaleBackdropPaddingX*2)), //WidthMath.round(config.scaleFontSize + (config.scaleBackdropPaddingY*2)) //Height);ctx.fill();}                       ctx.fillStyle = config.scaleFontColor;ctx.fillText(calculatedScale.labels[i],0,-scaleHop*(i+1));}}for (var k=0; k" " + config.pointLabelFontSize+"px " + config.pointLabelFontFamily;ctx.fillStyle = config.pointLabelFontColor;var opposite = Math.sin(rotationDegree*k) * (maxSize + config.pointLabelFontSize);var adjacent = Math.cos(rotationDegree*k) * (maxSize + config.pointLabelFontSize);if(rotationDegree*k == Math.PI || rotationDegree*k == 0){ctx.textAlign = "center";}else if(rotationDegree*k > 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; i" " + config.pointLabelFontSize+"px " + config.pointLabelFontFamily;var textMeasurement = ctx.measureText(data.labels[i]).width;if(textMeasurement>labelLength) 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; ifor (var j=0; jif (data.datasets[i].data[j] > 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; inull,drawPieSegments,ctx);function drawPieSegments (animationDecimal){var cumulativeAngle = -Math.PI/2,scaleAnimation = 1,rotateAnimation = 1;if (config.animation) {if (config.animateScale) {scaleAnimation = animationDecimal;}if (config.animateRotate){rotateAnimation = animationDecimal;}}for (var i=0; ivar segmentAngle = rotateAnimation * ((data[i].value/segmentTotal) * (Math.PI*2));ctx.beginPath();ctx.arc(width/2,height/2,scaleAnimation * pieRadius,cumulativeAngle,cumulativeAngle + segmentAngle);ctx.lineTo(width/2,height/2);ctx.closePath();ctx.fillStyle = data[i].color;ctx.fill();if(config.segmentShowStroke){ctx.lineWidth = config.segmentStrokeWidth;ctx.strokeStyle = config.segmentStrokeColor;ctx.stroke();}cumulativeAngle += segmentAngle;}           }       }var Doughnut = 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 doughnutRadius = Min([height/2,width/2]) - 5;var cutoutRadius = doughnutRadius * (config.percentageInnerCutout/100);for (var i=0; inull,drawPieSegments,ctx);function drawPieSegments (animationDecimal){var cumulativeAngle = -Math.PI/2,scaleAnimation = 1,rotateAnimation = 1;if (config.animation) {if (config.animateScale) {scaleAnimation = animationDecimal;}if (config.animateRotate){rotateAnimation = animationDecimal;}}for (var i=0; ivar segmentAngle = rotateAnimation * ((data[i].value/segmentTotal) * (Math.PI*2));ctx.beginPath();ctx.arc(width/2,height/2,scaleAnimation * doughnutRadius,cumulativeAngle,cumulativeAngle + segmentAngle,false);ctx.arc(width/2,height/2,scaleAnimation * cutoutRadius,cumulativeAngle + segmentAngle,cumulativeAngle,true);ctx.closePath();ctx.fillStyle = data[i].color;ctx.fill();if(config.segmentShowStroke){ctx.lineWidth = config.segmentStrokeWidth;ctx.strokeStyle = config.segmentStrokeColor;ctx.stroke();}cumulativeAngle += segmentAngle;}           }           }var Line = function(data,config,ctx){var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString, valueHop,widestXLabel, xAxisLength,yAxisPosX,xAxisPosY, rotateLabels = 0;calculateDrawingSizes();valueBounds = getValueBounds();//Check and set the scalelabelTemplateString = (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; iif(labelTemplateString){calculatedScale.labels.push(tmpl(labelTemplateString,{value:(config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimalPlaces (config.scaleStepWidth))}));}}}scaleHop = Math.floor(scaleHeight/calculatedScale.steps);calculateXAxisSize();animationLoop(config,drawScale,drawLines,ctx);      function drawLines(animPc){for (var i=0; i0],calculatedScale,scaleHop)))for (var j=1; jif (config.bezierCurve){ctx.bezierCurveTo(xPos(j-0.5),yPos(i,j-1),xPos(j-0.5),yPos(i,j),xPos(j),yPos(i,j));}else{ctx.lineTo(xPos(j),yPos(i,j));}}ctx.stroke();if (config.datasetFill){ctx.lineTo(yAxisPosX + (valueHop*(data.datasets[i].data.length-1)),xAxisPosY);ctx.lineTo(yAxisPosX,xAxisPosY);ctx.closePath();ctx.fillStyle = data.datasets[i].fillColor;ctx.fill();}else{ctx.closePath();}if(config.pointDot){ctx.fillStyle = data.datasets[i].pointColor;ctx.strokeStyle = data.datasets[i].pointStrokeColor;ctx.lineWidth = config.pointDotStrokeWidth;for (var k=0; k0,Math.PI*2,true);ctx.fill();ctx.stroke();}}}function yPos(dataSet,iteration){return xAxisPosY - animPc*(calculateOffset(data.datasets[dataSet].data[iteration],calculatedScale,scaleHop));           }function xPos(iteration){return yAxisPosX + (valueHop * iteration);}}function drawScale(){//X axis linectx.lineWidth = config.scaleLineWidth;ctx.strokeStyle = config.scaleLineColor;ctx.beginPath();ctx.moveTo(width-widestXLabel/2+5,xAxisPosY);ctx.lineTo(width-(widestXLabel/2)-xAxisLength-5,xAxisPosY);ctx.stroke();if (rotateLabels > 0){ctx.save();ctx.textAlign = "right";}else{ctx.textAlign = "center";}ctx.fillStyle = config.scaleFontColor;for (var i=0; iif (rotateLabels > 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 axisctx.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; j3,xAxisPosY - ((j+1) * scaleHop));if (config.scaleShowGridLines){ctx.lineWidth = config.scaleGridLineWidth;ctx.strokeStyle = config.scaleGridLineColor;ctx.lineTo(yAxisPosX + xAxisLength + 5,xAxisPosY - ((j+1) * scaleHop));                 }else{ctx.lineTo(yAxisPosX-0.5,xAxisPosY - ((j+1) * scaleHop));}ctx.stroke();if (config.scaleShowLabels){ctx.fillText(calculatedScale.labels[j],yAxisPosX-8,xAxisPosY - ((j+1) * scaleHop));}}}function calculateXAxisSize(){var longestText = 1;//if we are showing the labelsif (config.scaleShowLabels){ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;for (var i=0; ivar measuredText = ctx.measureText(calculatedScale.labels[i]).width;longestText = (measuredText > longestText)? measuredText : longestText;}//Add a little extra padding from the y axislongestText +=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; ivar textLength = ctx.measureText(data.labels[i]).width;//If the text length is longer - make that equal to longest text!widestXLabel = (textLength > 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 textmaxSize -= 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; ifor (var j=0; jif ( data.datasets[i].data[j] > 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 scalelabelTemplateString = (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; iif(labelTemplateString){calculatedScale.labels.push(tmpl(labelTemplateString,{value:(config.scaleStartValue + (config.scaleStepWidth * i)).toFixed(getDecimalPlaces (config.scaleStepWidth))}));}}}scaleHop = Math.floor(scaleHeight/calculatedScale.steps);calculateXAxisSize();animationLoop(config,drawScale,drawBars,ctx);       function drawBars(animPc){ctx.lineWidth = config.barStrokeWidth;for (var i=0; ifor (var j=0; jvar barOffset = yAxisPosX + config.barValueSpacing + valueHop*j + barWidth*i + config.barDatasetSpacing*i + config.barStrokeWidth*i;ctx.beginPath();ctx.moveTo(barOffset, xAxisPosY);ctx.lineTo(barOffset, xAxisPosY - animPc*calculateOffset(data.datasets[i].data[j],calculatedScale,scaleHop)+(config.barStrokeWidth/2));ctx.lineTo(barOffset + barWidth, xAxisPosY - animPc*calculateOffset(data.datasets[i].data[j],calculatedScale,scaleHop)+(config.barStrokeWidth/2));ctx.lineTo(barOffset + barWidth, xAxisPosY);if(config.barShowStroke){ctx.stroke();}ctx.closePath();ctx.fill();}}}function drawScale(){//X axis linectx.lineWidth = config.scaleLineWidth;ctx.strokeStyle = config.scaleLineColor;ctx.beginPath();ctx.moveTo(width-widestXLabel/2+5,xAxisPosY);ctx.lineTo(width-(widestXLabel/2)-xAxisLength-5,xAxisPosY);ctx.stroke();if (rotateLabels > 0){ctx.save();ctx.textAlign = "right";}else{ctx.textAlign = "center";}ctx.fillStyle = config.scaleFontColor;for (var i=0; iif (rotateLabels > 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 axisctx.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; j3,xAxisPosY - ((j+1) * scaleHop));if (config.scaleShowGridLines){ctx.lineWidth = config.scaleGridLineWidth;ctx.strokeStyle = config.scaleGridLineColor;ctx.lineTo(yAxisPosX + xAxisLength + 5,xAxisPosY - ((j+1) * scaleHop));                 }else{ctx.lineTo(yAxisPosX-0.5,xAxisPosY - ((j+1) * scaleHop));}ctx.stroke();if (config.scaleShowLabels){ctx.fillText(calculatedScale.labels[j],yAxisPosX-8,xAxisPosY - ((j+1) * scaleHop));}}}function calculateXAxisSize(){var longestText = 1;//if we are showing the labelsif (config.scaleShowLabels){ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;for (var i=0; ivar measuredText = ctx.measureText(calculatedScale.labels[i]).width;longestText = (measuredText > longestText)? measuredText : longestText;}//Add a little extra padding from the y axislongestText +=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; ivar textLength = ctx.measureText(data.labels[i]).width;//If the text length is longer - make that equal to longest text!widestXLabel = (textLength > 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 textmaxSize -= 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; ifor (var j=0; jif ( data.datasets[i].data[j] > 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 foreverif (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 fallbackvar 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; i1; i++){labels.push(tmpl(labelTemplateString,{value:(graphMin + (stepValue*i)).toFixed(getDecimalPlaces (stepValue))}));}}return {steps : numberOfSteps,stepValue : stepValue,graphMin : graphMin,labels : labels             }function calculateOrderOfMagnitude(val){return Math.floor(Math.log(val) / Math.LN10);}       }//Max value from arrayfunction Max( array ){return Math.max.apply( Math, array );};//Min value from arrayfunction Min( array ){return Math.min.apply( Math, array );};//Default if undefinedfunction Default(userDeclared,valueIfFalse){if(!userDeclared){return valueIfFalse;} else {return userDeclared;}};//Is a number functionfunction isNumber(n) {return !isNaN(parseFloat(n)) && isFinite(n);}//Apply cap a value at a high or low numberfunction CapValue(valueToCap, maxValue, minValue){if(isNumber(maxValue)) {if( valueToCap > 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 JavaScriptstr.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 userreturn data ? fn( data ) : fn;};
}

二、 直接运行 test.html

这里写图片描述

结束。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部