原生js和canvas实现的 柱状图、饼状图、折线图

来源:互联网 发布:ae 编程 编辑:程序博客网 时间:2024/05/22 05:15
很简单的实现,拷贝就能运行
<html><head lang="en"></head>   <body>      <canvas id="bar" width="450" height="250">      </canvas>      <canvas id="pie" width="450" height="250"></canvas>      <br />      <canvas id="line" width="450" height="250"></canvas>      <canvas id="curve" width="450" height="250"></canvas><script>window.onload = function() {   var bar = document.getElementById("bar"),      data = {         label: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//x轴的标题         dataSets: [{            bDistance: 30, //绘制的边框距离画布边框的距离            bInterval: 20, //两个柱状图之间的距离            values: [300, 50, 100, 50, 80, 150, 120], //对应标签的值            fillColor: "rgba(0,0,255,0.5)" //矩形填充颜色         }, {            txtfont: "14px microsoft yahei",//绘制文本的字体            txtalgin: "center",//文本对齐方式            txtbaseline: "middle"//文本的基线         }, {            fillColor: "black", //矩形填充颜色            xtitle: "订单总数(个)", //x轴标题            ytitle: "星期几" //y轴标题         }]      };   barChart(bar, data); //画柱状图   var pie = document.getElementById("pie"),      datasets = {         colors: ["blue", "yellow", "black", "red", "green"], //颜色         labels: ["第一周", "第二周", "第三周", "第四周", "第五周"], //标签         values: [30, 60, 80, 70, 150], //值         x: 125, //圆心x坐标         y: 125, //圆心y坐标         radius: 100 //半径      };   pieChart(pie, datasets); //画饼状图   var line = document.getElementById("line"),      datas = {         labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//标签         values: [50, 180, 100, 150, 110, 130, 30],//值         txtSet: {//绘制文本设置            txtfont: "14px microsoft yahei",            txtalgin: "center",            txtbaseline: "middle",            txtColor:"#000000"         },         bgSet:{//绘制背景线设置            lineColor:"#C0C0C0",            lineWidth:1,         },         lineColor:"#000000",//折线颜色         circleColor:"blue",//折线上原点颜色         yAxis:{//y轴表示什么,及绘制文本的位置            x:50,            y:11,            title:"完成件数(个)"         }      },      newData = {         labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],         values: [100, 40, 200, 50, 10, 80, 100],         txtSet: {            txtfont: "14px microsoft yahei",            txtalgin: "center",            txtbaseline: "middle",            txtColor:"#000000"         },         bgSet:{            lineColor:"#C0C0C0",            lineWidth:1,         },         lineColor:"blue",         circleColor:"red",         yAxis:{            x:50,            y:11,            title:"完成件数(个)"         }      };   lineChart(line,datas);//画折线图   //lineChart(line,newData);//在同一个canvas画第二条折线图   //curveChart();//绘制曲线   var bg = document.getElementById("curve")   linedata = {      labels: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"],//标签      datas: [115, 35, 210, 100, 300, 220, 40],//数据      xTitle: "月份",//x轴标题      yTitle: "产量(个)",//y轴标题      ctxSets:{         strokeColor:"#C0C0C0",//背景线颜色         lineWidth:1,//线的宽度         txtColor:"#000000",//绘制文本颜色         txtFont:"12px microsoft yahei",//字体         txtAlign:"center",//对齐方式         txtBase:"middle",//基线         lineColor:"blue",//折线颜色         circleColor:"#FF0000"//折线上圆点颜色      }   };   setBg(bg,linedata);//绘制图标背景及折线}//数组sort()排序传的参数为该函数(降序排列),绘制柱状图需要function compare(value1, value2) {      return value2 - value1;   }/*柱状图 * elem:要操作的画布元素 * data:所需格式的数据*/function barChart(elem, data) {      if (elem.getContext) {         var ctx = elem.getContext("2d"),            mywidth = elem.width, //画布的宽高            myheight = elem.height,            bDistance = parseInt(data.dataSets[0].bDistance), //图标边框到画布间距            bInterval = data.dataSets[0].bInterval, //矩形间间距            labels = data.label, //矩形对应标题            len = labels.length,//标签/数据个数            //矩形宽度            bWidth = Math.floor((mywidth - bDistance * 2 - (len + 1) * bInterval) / len),            bheight = myheight - bDistance * 2, //边框高度            values = data.dataSets[0].values, //绘图的值            sortValues = values.slice(0), //基于当前数组中的一个或多个项创建一个新数组(解决了该数组排序原数组也被排序的问题)            serialValues = new Array(); //用于存储序列化后的值         sortValues.sort(compare);         if (sortValues[0] > bheight) {            (function() {               //数值超过边框高度时序列化值               for (var i = 0; i < len; i++) {                  serialValues[i] = values[i] * bheight / sortValues[0];               }            })(); //块级作用域         }         //绘制边框         ctx.beginPath(); //要绘制路径,必须先调用该方法,表示开始绘制新路径         ctx.moveTo(bDistance, bDistance);         ctx.lineTo(bDistance, myheight - bDistance);         ctx.lineTo(mywidth - bDistance, myheight - bDistance);         ctx.stroke(); //把图形绘制到画布上         //绘制矩形,组成条形图         ctx.fillStyle = data.dataSets[0].fillColor;         //绘制文字         ctx.font = data.dataSets[1].txtfont; //字体样式、大小、字体         ctx.textAlign = data.dataSets[1].txtalgin; //文本对齐方式         ctx.textBaseline = data.dataSets[1].txtbaseline; //文本的基线         for (var i = 0; i < len; i++) {            var x = (bInterval + bDistance) + i * (bWidth + bInterval),               y = myheight - serialValues[i] - bDistance,               x1 = x + Math.round(bWidth / 2);            y1 = myheight - bDistance + 15,               y2 = y - 10;            ctx.fillRect(x, y, bWidth, serialValues[i]); //x,y,width,height单位都为px            ctx.fillText(labels[i], x1, y1); //绘制标题文字            ctx.fillText(values[i], x1, y2); //绘制柱状图数据         }         ctx.fillStyle = data.dataSets[2].fillColor;         ctx.fillText(data.dataSets[2].xtitle, 49, 7); //x轴代表什么         ctx.fillText(data.dataSets[2].ytitle, mywidth - bDistance, myheight - bDistance + 15); //y轴代表什么      }   }   //求和,计算百分比(画饼图时需要)function sumFunc(data) {      var sum = 0;      for (var i = 0, len = data.length; i < len; i++) {         sum += data[i];      }      return sum;   }/*饼图 * elem:要操作的画布元素 * data:所需格式的数据*/function pieChart(elem, data) {   if (elem.getContext) {      var ctx = elem.getContext("2d"),         vdata = data.values, //绘图数据         sum = sumFunc(vdata), //对绘图数据求和,用于计算百分比         startangle = 0, //绘制扇形的开始角度         labels = data.labels, //绘图的对应文字         x = data.x, //圆心x坐标         y = data.y, //圆心y坐标         rad = data.radius, //圆半径         x1 = x + rad + 30, //绘制右侧文字和标注的x坐标         y1 = y - rad, //绘制右侧文字和标注的y坐标         endangle; //绘制扇形的结束角度      for (var i = 0, len = vdata.length; i < len; i++) {         //绘制饼图         //计算下一次绘制扇形的结束角度,即根据绘制数据占有总数据和的比例求的弧度         var percent = vdata[i] / sum;         endangle = startangle + Math.PI * 2 * (percent);         ctx.beginPath(); //开始绘制新路径         ctx.fillStyle = data.colors[i]; //绘制颜色         ctx.moveTo(x, y); //移动到圆心(注:画饼图一定要回到圆心,不然会有问题)         ctx.arc(x, y, rad, startangle, endangle, false); //画扇形         //绘制右侧文字和标注         ctx.moveTo(x1, y1); //移动到绘制文字和标注的位置         ctx.fillRect(x1, y1, 30, 14); //绘制矩形表示比列图         //计算四舍五入后的扇形每份的百分比         var perc = (percent * 100).toFixed(2) + "%"; //tofixed()自动四舍五入返回指定小数位数的字符串         //设置绘制文字的属性         ctx.font = "bold 12px microsoft yahei";         ctx.txtalgin = "center";         ctx.textBaseline = "top";         //绘制文字         ctx.fillText(labels[i] + ":" + perc, x1 + 35, y1);         ctx.fill(); //指定颜色填充以上绘制         startangle = endangle; //下一次绘制扇形的开始角度         y1 += 20; //下一次绘制文字和标注的y坐标      }   }}/*绘制折线 elem:操作的元素 data:所需格式数据*/function lineChart(elem, data) {   if (elem.getContext) {      var ctx = elem.getContext("2d"),         labels = data.labels,//数值对应标签         values = data.values,//数值         len = labels.length,//标签/数值个数         elemWidth = elem.width,//画布宽度         elemHeight = elem.height,//画布高度         gridHeight = Math.ceil(elemHeight / 5),//每行之间高度         gridWidth = Math.floor(elemWidth / len),//每列之间看度         actualHeight = 4 * gridHeight + 20;//绘制区域实际高度      //设置绘制直线的属性      ctx.strokeStyle = data.bgSet.lineColor;      ctx.lineWidth = data.bgSet.lineWidth;      //设置绘制文本的属性      ctx.font = data.txtSet.txtfont;      ctx.textAlign = data.txtSet.txtalgin;      ctx.txtbaseline = data.txtSet.txtbaseline;      //绘制背景      //绘制背景横线      ctx.beginPath();      for (var i = 0; i < 5; i++) {         var hgridY = gridHeight * i + 20,            hgridX = gridWidth * len;         ctx.moveTo(0, hgridY);         ctx.lineTo(hgridX, hgridY);      }      ctx.stroke();      //绘制背景的竖线,表示每个label      ctx.beginPath();      for (var j = 0; j < len + 1; j++) {         var vgridX = gridWidth * j,            vgridY = actualHeight;         ctx.moveTo(vgridX, vgridY);         ctx.lineTo(vgridX, vgridY + 10);      }      ctx.stroke();      //绘制标签文字      ctx.fillStyle = data.txtSet.txtColor;      for (var k = 0; k < len; k++) {         var txtX = gridWidth * (k + 0.5),            txtY = actualHeight + 15;         ctx.fillText(labels[k], txtX, txtY);      }      ctx.fill();      //获取画图数据的最大值用于序列换数据      var maxValue = 0,         cData = new Array();      for (var i = 0; i < len; i++) {         if (values[i] > maxValue) {            maxValue = values[i];         }      }      //当最大值大于画布可绘制区域的高度时,对数据进行转化,然后进行画图      if ((4 * gridHeight) < maxValue) {         for (var i = 0; i < len; i++) {            //转换后的数据            cData[i] = values[i] * 4 * gridHeight / maxValue;         }      } else {         cData = values;      }      //绘制折线      ctx.strokeStyle = data.lineColor;      ctx.beginPath();      var pointX = gridWidth / 2,         pointY = actualHeight - cData[0];      ctx.moveTo(pointX, pointY);      for (var i = 1; i < len; i++) {         pointX += gridWidth;         pointY = actualHeight - cData[i];         ctx.lineTo(pointX, pointY);      }      ctx.stroke();      //绘制坐标圆形      ctx.beginPath();      ctx.fillStyle = data.circleColor; //圆点的颜色      for (var i = 0; i < len; i++) {         var circleX = gridWidth / 2 + gridWidth * i,            circleY = actualHeight - cData[i];         ctx.moveTo(circleX, circleY); //假如不每次绘制之前确定开始绘制新路径,可以每次绘制之前移动到新的圆心         ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false);      }      ctx.fill();      //绘制坐标圆形对应的值      ctx.beginPath();      ctx.fillStyle = data.txtSet.txtColor;; //文本颜色      for (var i = 0; i < len; i++) {         var circleX = gridWidth / 2 + gridWidth * i,            circleY = actualHeight - cData[i];         ctx.fillText(values[i], circleX, circleY - 8);      }      ctx.fill();      //绘制y轴代表什么      ctx.fillText(data.yAxis.title, data.yAxis.x, data.yAxis.y);      ctx.fill();   }}function curveChart() {      var elem = document.getElementById("curve");      if (elem.getContext) {         var ctx = elem.getContext("2d");         //       ctx.lineWidth = 2;         ctx.lineCap = "square";         ctx.beginPath();         ctx.moveTo(100, 70);         ctx.bezierCurveTo(120, 150, 150, 150, 200, 60); //三次贝赛尔曲线         ctx.moveTo(40, 100);         ctx.quadraticCurveTo(60, 60, 100, 70); //二次贝塞尔曲线         ctx.moveTo(200, 60);         ctx.arcTo(240, 40, 300, 50, 50); //绘制弧线         ctx.stroke();      }   }   /* 绘制背景    * elem:要操作的元素    * data:所需格式的数据*/function setBg(elem, data) {   if (elem.getContext) {      var ctx = elem.getContext("2d"),//获取元素上下文         startX = 40,//左上角开始绘制的x坐标         startY = 40,//左上角开始绘制的y坐标         labels = data.labels,//对应数据的标签,即列数         cols = labels.length,//数据个数         datas = data.datas,//数据         gWidth = elem.width - 80,//背景总宽度,elem.width为画布宽度         gHeight = elem.height - 80,//背景总长度         pgWidth = gWidth / cols,//背景每个格的宽度         rows = 10,//背景表格行数         pgHeight = gHeight / rows;//背景表格高度      //绘制背景      ctx.beginPath(); //开始绘制新路径      ctx.strokeStyle = data.ctxSets.strokeColor;//描边颜色      ctx.lineWidth = data.ctxSets.lineWidth;//描边线条宽度      //绘制横线      for (var i = 0; i < rows; i++) {         var pY = startX + pgHeight * i;         ctx.moveTo(startX, pY); //移动到绘制的起点         ctx.lineTo(gWidth + startX, pY);      }      //最后一根横线      var pY1 = startY + pgHeight * rows;      ctx.moveTo(startX, pY1); //移动到绘制的起点      ctx.lineTo(gWidth + startX + 20, pY1);      //绘制竖线      //第一根竖线      ctx.moveTo(startX, startY - 20); //移动到绘制的起点      ctx.lineTo(startX, gHeight + startY + 10);      for (var i = 1; i < cols + 1; i++) {         var pX = startX + pgWidth * i;         ctx.moveTo(pX, startY); //移动到绘制的起点         ctx.lineTo(pX, gHeight + startY + 10);      }      ctx.stroke();//把图形绘制到画布上      //绘制文字      ctx.fillStyle = data.ctxSets.txtColor;//填充颜色      ctx.font = data.ctxSets.txtFont;//文本字体      ctx.textAlign = data.ctxSets.txtAlign;//文本对齐方式      ctx.textBaseline = data.ctxSets.txtBase;//文本基线      //绘制横轴文字      for (var i = 0; i < cols; i++) {         var px = startX + pgWidth / 2 + pgWidth * i;         ctx.fillText(labels[i], px, startY + gHeight + 10);      }      //绘制竖轴文字      //判断最大值是否大于行高,确定每行的数值      var maxValue = 0,         newValues = new Array(),         j = 0;      for (var i = 0; i < cols; i++) {         if (datas[i] > maxValue) {            maxValue = datas[i];         }      }      //重新计算每隔数据值及转换值      if (maxValue > gHeight) {         pgValues = maxValue / rows;         for (var i = 0; i < cols; i++) {            newValues[i] = datas[i] * gHeight / maxValue;         }      } else {         pgValues = pgHeight;         newValues = datas;      }      //绘制竖轴文字      for (var i = rows; i >= 0; i--) {         ctx.fillText(pgValues * i, 20, startY + pgHeight * j);         j++;      }      //绘制标题      //x轴标题      ctx.fillText(data.xTitle, gWidth + startX + 15, gHeight + startY + 10);      //y轴标题      ctx.fillText(data.yTitle, startX + 25, startY - 10);      //画图      //绘制折线      ctx.strokeStyle = data.ctxSets.lineColor;;      ctx.beginPath();      var pointX = pgWidth / 2 + startX,         pointY = startY + gHeight - newValues[0];      ctx.moveTo(pointX, pointY);      for (var i = 1; i < cols; i++) {         pointX += pgWidth;         pointY = startY + gHeight - newValues[i];         ctx.lineTo(pointX, pointY);      }      ctx.stroke();      //绘制坐标圆形      ctx.beginPath();      ctx.fillStyle = data.ctxSets.circleColor;; //圆点的颜色      for (var i = 0; i < cols; i++) {         var circleX = pgWidth / 2 + startX + pgWidth * i,            circleY = startY + gHeight - newValues[i];         ctx.moveTo(circleX, circleY); //假如不每次绘制之前确定开始绘制新路径,可以每次绘制之前移动到新的圆心         ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false);      }      ctx.fill();      //绘制坐标圆形对应的值      ctx.beginPath();      ctx.fillStyle = data.ctxSets.txtColor; //文本颜色      for (var i = 0; i < cols; i++) {         var circleX = pgWidth / 2 + startX + pgWidth * i,            circleY = startY + gHeight - newValues[i];         ctx.fillText(datas[i], circleX, circleY - 10);      }      ctx.fill();   }}</script></body></html>
原创粉丝点击