canvas图表详解系列(4):动态散点图
本章建议学习时间4小时
学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记)
学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步骤,本次讲解散点图。
演示地址: https://sutianbinde.github.io/charts/%E6%95%A3%E7%82%B9%E5%9B%BE-%E9%AB%98%E6%B8%85.html
源文件下载地址:https://github.com/sutianbinde/charts
散点图
散点图是比较好看的图表了,我们的案例展示效果如下
功能:图表可以根据数据自动变换比例,绘制点的时候有由小到大的动画,绘制平均值线条,鼠标移入到对应模块会实现颜色变化,并且显示当前项的详细信息。
实现步骤
--新建Html文件,写入总方法和数据,这次我们的代码和上几个图有所不同,我们只给定容器,而canvas通过js生成
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="chart" height="400" width="700" style="margin:50px"></div> <script type="text/javascript"> function goChart(cBox,dataArr,textArr){ } var dataArr = [[174.0, 65.6], [175.3, 71.8], [193.5, 80.7], [186.5, 72.6], [187.2, 78.8], [181.5, 74.8], [184.0, 86.4], [184.5, 78.4], [175.0, 62.0], [184.0, 81.6], [180.0, 76.6], [177.8, 83.6], [192.0, 90.0], [176.0, 74.6], [174.0, 71.0], [184.0, 79.6], [192.7, 93.8], [171.5, 70.0], [173.0, 72.4], [176.0, 85.9], [176.0, 78.8], [180.5, 77.8], [172.7, 66.2], [176.0, 86.4], [173.5, 81.8], [178.0, 89.6], [180.3, 82.8], [180.3, 76.4], [164.5, 63.2], [173.0, 60.9], [183.5, 74.8], [175.5, 70.0], [188.0, 72.4], [189.2, 84.1], [172.8, 69.1], [170.0, 59.5], [182.0, 67.2], [170.0, 61.3], [177.8, 68.6], [184.2, 80.1], [186.7, 87.8], [171.4, 84.7], [172.7, 73.4], [175.3, 72.1], [180.3, 82.6], [182.9, 88.7], [188.0, 84.1], [177.2, 94.1], [172.1, 74.9], [167.0, 59.1], [169.5, 75.6], [174.0, 86.2], [172.7, 75.3], [182.2, 87.1], [164.1, 55.2], [163.0, 57.0], [171.5, 61.4], [184.2, 76.8], [174.0, 86.8], [174.0, 72.2], [177.0, 71.6], [186.0, 84.8], [167.0, 68.2], [171.8, 66.1], [182.0, 72.0], [167.0, 64.6], [177.8, 74.8], [164.5, 70.0], [192.0, 101.6], [175.5, 63.2], [171.2, 79.1], [181.6, 78.9], [167.4, 67.7], [181.1, 66.0], [177.0, 68.2], [174.5, 63.9], [177.5, 72.0], [170.5, 56.8], [182.4, 74.5], [197.1, 90.9], [180.1, 93.0], [175.5, 80.9], [180.6, 72.7], [184.4, 68.0], [175.5, 70.9], [180.6, 72.5], [177.0, 72.5], [177.1, 83.4], [181.6, 75.5], [176.5, 73.0], [175.0, 70.2], [174.0, 73.4], [165.1, 70.5], [177.0, 68.9], [192.0, 102.3], [176.5, 68.4], [169.4, 65.9], [182.1, 75.7], [179.8, 84.5], [175.3, 87.7], [184.9, 86.4], [177.3, 73.2], [167.4, 53.9], [178.1, 72.0], [168.9, 55.5], [157.2, 58.4], [180.3, 83.2], [170.2, 72.7], [177.8, 64.1], [172.7, 72.3], [165.1, 65.0], [186.7, 86.4], [165.1, 65.0], [174.0, 88.6], [175.3, 84.1], [185.4, 66.8], [177.8, 75.5], [180.3, 93.2], [180.3, 82.7], [177.8, 58.0], [177.8, 79.5], [177.8, 78.6], [177.8, 71.8], [177.8, 116.4], [163.8, 72.2], [188.0, 83.6], [198.1, 85.5], [175.3, 90.9], [166.4, 85.9], [190.5, 89.1], [166.4, 75.0], [177.8, 77.7], [179.7, 86.4], [172.7, 90.9], [190.5, 73.6], [185.4, 76.4], [168.9, 69.1], [167.6, 84.5], [175.3, 64.5], [170.2, 69.1], [190.5, 108.6], [177.8, 86.4], [190.5, 80.9], [177.8, 87.7], [184.2, 94.5], [176.5, 80.2], [177.8, 72.0], [180.3, 71.4], [171.4, 72.7], [172.7, 84.1], [172.7, 76.8], [177.8, 63.6], [177.8, 80.9], [182.9, 80.9], [170.2, 85.5], [167.6, 68.6], [175.3, 67.7], [165.1, 66.4], [185.4, 102.3], [181.6, 70.5], [172.7, 95.9], [190.5, 84.1], [179.1, 87.3], [175.3, 71.8], [170.2, 65.9], [193.0, 95.9], [171.4, 91.4], [177.8, 81.8], [177.8, 96.8], [167.6, 69.1], [167.6, 82.7], [180.3, 75.5], [182.9, 79.5], [176.5, 73.6], [186.7, 91.8], [188.0, 84.1], [188.0, 85.9], [177.8, 81.8], [174.0, 82.5], [177.8, 80.5], [171.4, 70.0], [185.4, 81.8], [185.4, 84.1], [188.0, 90.5], [188.0, 91.4], [182.9, 89.1], [176.5, 85.0], [175.3, 69.1], [175.3, 73.6], [188.0, 80.5], [188.0, 82.7], [175.3, 86.4], [170.5, 67.7], [179.1, 92.7], [177.8, 93.6], [175.3, 70.9], [182.9, 75.0], [170.8, 93.2], [188.0, 93.2], [180.3, 77.7], [177.8, 61.4], [185.4, 94.1], [168.9, 75.0], [185.4, 83.6], [180.3, 85.5], [174.0, 73.9], [167.6, 66.8], [182.9, 87.3], [160.0, 72.3], [180.3, 88.6], [167.6, 75.5], [186.7, 101.4], [175.3, 91.1], [175.3, 67.3], [175.9, 77.7], [175.3, 81.8], [179.1, 75.5], [181.6, 84.5], [177.8, 76.6], [182.9, 85.0], [177.8, 102.5], [184.2, 77.3], [179.1, 71.8], [176.5, 87.9], [188.0, 94.3], [174.0, 70.9], [167.6, 64.5], [170.2, 77.3], [167.6, 72.3], [188.0, 87.3], [174.0, 80.0], [176.5, 82.3], [180.3, 73.6], [167.6, 74.1], [188.0, 85.9], [180.3, 73.2], [167.6, 76.3], [183.0, 65.9], [183.0, 90.9], [179.1, 89.1], [170.2, 62.3], [177.8, 82.7], [179.1, 79.1], [190.5, 98.2], [177.8, 84.1], [180.3, 83.2], [180.3, 83.2] ]; /* * 参数1 :需要显示canvas的dom (非canvas标签,需要指定height和width) * 参数2:二维数据 [0]横轴 [1]纵轴 * 参数3:横轴名称 纵轴名称 * */ goChart(document.getElementById("chart"),dataArr,["身 高","体 重"]) </script> </body> </html>
--在 goChart方法中定义需要使用的变量 并获取 canvas上下文
// 声明所需变量 var canvas,ctx; // 图表属性 var cWidth, cHeight, cMargin, cSpace; var originX, originY; // 柱状图属性 var bMargin, tobalBars, bWidth, maxXValue, maxYValue, minXValue, minYValue; var totalNomber; var yAverage, minTrueYValue, maxTrueYValue; // 运动相关变量 var ctr, numctr, speed; //鼠标移动 var mousePosition = {}; // 创建canvas并获得canvas上下文 canvas = document.createElement("canvas"); if(canvas && canvas.getContext){ ctx = canvas.getContext("2d"); } canvas.innerHTML = "你的浏览器不支持HTML5 canvas"; cBox.appendChild(canvas);
--初始化图表(接着上一步的代码写在 goChart方法中 )
initChart(); // 图表初始化 // 图表初始化 function initChart(){ // 图表信息 cMargin = 60; cSpace = 80; //将canvas扩大2倍,然后缩小,以适应高清屏幕 canvas.width = cBox.getAttribute("width")* 2 ; canvas.height = cBox.getAttribute("height")* 2; canvas.style.height = canvas.height/2 + "px"; canvas.style.width = canvas.width/2 + "px"; cHeight = canvas.height - cMargin*2 - cSpace; cWidth = canvas.width - cMargin*2 - cSpace; originX = cMargin + cSpace; originY = cMargin + cHeight; // 柱状图信息 bMargin = canvas.width/40; tobalBars = dataArr.length; bWidth = parseInt( cWidth/tobalBars - bMargin ); maxXValue = 0; maxYValue = 0; var xArr = []; var yArr = []; for(var i=0; i<dataArr.length; i++){ xArr.push( dataArr[i][0] ); yArr.push( dataArr[i][1] ); } yAverage = ( eval(yArr.join("+"))/yArr.length ).toFixed(2); var addNb = parseInt(yAverage/10); //用于在轴前后加空白 minXValue = Math.min.apply(null,xArr); //求最小值 minXValue = parseInt(Math.max(minXValue-addNb, 0)); //如果减去addNb后小于零,就取零 maxXValue = parseInt(Math.max.apply(null,xArr)+addNb); //用于轴的显示,所以取整 minYValue = minTrueYValue = Math.min.apply(null,yArr); minYValue = parseInt(Math.max(minYValue-addNb, 0)); maxTrueYValue = Math.max.apply(null,yArr); maxYValue = parseInt(maxTrueYValue+addNb); totalNomber = 5; // 运动相关 ctr = 1; numctr = 50; speed = 1.5; }
--绘制坐标轴,以及纵横方向的线条(接着上一步的代码写在 goChart方法中 )
实现效果如下
drawLineLabelMarkers(); // 绘制图表轴、标签和标记 // 绘制图表轴、标签和标记 function drawLineLabelMarkers(){ ctx.translate(0.5,0.5); // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线 ctx.font = "24px Arial"; ctx.lineWidth = 2; ctx.fillStyle = "#000"; ctx.strokeStyle = "#000"; // y轴 drawLine(originX, originY, originX, cMargin); // x轴 drawLine(originX, originY, originX+cWidth, originY); // 绘制标记 drawMarkers(); ctx.translate(-0.5,-0.5); // 还原位置 } // 画线的方法 function drawLine(x, y, X, Y){ ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(X, Y); ctx.stroke(); ctx.closePath(); } // 绘制标记 function drawMarkers(){ ctx.strokeStyle = "#E0E0E0"; // 绘制 y var oneYVal = (maxYValue-minYValue)/totalNomber; ctx.textAlign = "right"; for(var i=0; i<=totalNomber; i++){ var markerVal = parseInt(i*oneYVal+minYValue); var xMarker = originX-10; var yMarker = parseInt( originY-cHeight*(markerVal-minYValue)/(maxYValue-minYValue) ); ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字 if(i>0){ drawLine(originX+2, yMarker, originX+cWidth, yMarker); } } // 绘制 x var oneXVal = (maxXValue-minXValue)/totalNomber; ctx.textAlign = "center"; for(var i=0; i<=totalNomber; i++){ var markerVal = parseInt(i*oneXVal+minXValue); var xMarker = parseInt( originX+cWidth*(markerVal-minXValue)/(maxXValue-minXValue)); var yMarker = originY+30; ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字 if(i>0){ drawLine(xMarker, cMargin, xMarker, originY-2); } } // 绘制标题 y ctx.save(); ctx.rotate(-Math.PI/2); ctx.fillText(textArr[1], -canvas.height/2, cSpace-10); ctx.restore(); // 绘制标题 x ctx.fillText(textArr[0], originX+cWidth/2, originY+cSpace/2+30); };
--绘制散点图动画(接着上一步的代码写在 goChart方法中 )
此处里面有对鼠标移动的处理,大家看到有mouseMove 的地方先搁置,写到后边就知道用处了
drawChartAnimate(); // 绘制柱状图的动画 //绘制动画图 function drawChartAnimate(mouseMove){ var ifTip = false; var tipArr = null; for(var i=0; i<dataArr.length; i++){ ctx.fillStyle = "rgba(46,199,201,0.5)"; var oX = originX+cWidth*(dataArr[i][0]-minXValue)/(maxXValue-minXValue); var oY = originY - cHeight*(dataArr[i][1]-minYValue)/(maxYValue-minYValue); ctx.beginPath(); ctx.arc(oX,oY,8*ctr/numctr,0, Math.PI*2,true); if(!ifTip && mouseMove && ctx.isPointInPath(mousePosition.x*2, mousePosition.y*2)){ //如果是鼠标移动的到柱状图上,重新绘制图表 ctx.fillStyle = "rgba(46,199,201,1)"; //是否绘制提示 ifTip = true; tipArr = dataArr[i]; }else{ ctx.fillStyle = "rgba(46,199,201,0.5)"; } ctx.fill(); } //绘制平均值线 drawAverageLine(); //绘制提示 ifTip && drawTips(mousePosition.x*2, mousePosition.y*2,tipArr[0],tipArr[1]); if(ctr<numctr){ ctr++; setTimeout(function(){ ctx.clearRect(0,0,canvas.width, canvas.height); drawLineLabelMarkers(); drawChartAnimate(); }, speed*=1.08); } } //绘制平均值线 function drawAverageLine(){ ctx.beginPath(); var yNb = originY-cHeight*(yAverage-minYValue)/(maxYValue-minYValue); var xNb = originX+cWidth*ctr/numctr+cMargin/2; ctx.moveTo(originX+2,yNb); ctx.lineTo(xNb,yNb); //设置虚线 ctx.save(); ctx.lineWidth = 4; ctx.strokeStyle = ctx.fillStyle = "#2ec7c9"; ctx.setLineDash([10]); ctx.stroke(); //绘制三角 ctx.beginPath(); ctx.moveTo(xNb,yNb); ctx.lineTo(xNb-5,yNb-8); ctx.lineTo(xNb+12,yNb); ctx.lineTo(xNb-5,yNb+8); ctx.fill(); //绘制文本 ctx.font = "24px Arial"; ctx.fillText(yAverage, xNb-10,yNb-10); //还原 ctx.restore(); } //绘制提示框 function drawTips(oX,oY,xVal,yVal){ ctx.save(); ctx.beginPath(); ctx.fillStyle = "rgba(0,0,0,0.5)"; var H = 100; roundedRect(ctx,oX+10,oY-H/2,2*H,H,5); ctx.fillStyle = "#fff"; ctx.fillText(textArr[1]+":"+yVal, oX+H,oY-H/10); ctx.fillText(textArr[0]+":"+xVal, oX+H,oY+H/4); ctx.restore(); } //绘制圆角矩形的方法 function roundedRect(ctx,x,y,width,height,radius){ ctx.moveTo(x,x+radius); ctx.beginPath(); ctx.lineTo(x,y+height-radius); ctx.quadraticCurveTo(x,y+height,x+radius,y+height); ctx.lineTo(x+width-radius, y+height); ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); ctx.lineTo(x+width,y+radius); ctx.quadraticCurveTo(x+width,y,x+width-radius,y); ctx.lineTo(x+radius,y); ctx.quadraticCurveTo(x,y,x,y+radius); ctx.closePath(); ctx.fill(); }
--监听鼠标移动,以实现移动到当前项作颜色变化(接着上一步的代码写在 goChart方法中 )
//检测鼠标移动 var mouseTimer = null; canvas.addEventListener("mousemove",function(e){ e = e || window.event; if( e.offsetX || e.offsetX==0 ){ mousePosition.x = e.offsetX; mousePosition.y = e.offsetY; }else if( e.layerX || e.layerX==0 ){ mousePosition.x = e.layerX; mousePosition.y = e.layerY; } clearTimeout(mouseTimer); mouseTimer = setTimeout(function(){ ctx.clearRect(0,0,canvas.width, canvas.height); drawLineLabelMarkers(); drawChartAnimate(true); },10); });
--点击图表刷新(接着上一步的代码写在 goChart方法中 )
//点击刷新图表 canvas.onclick = function(){ initChart(); // 图表初始化 drawLineLabelMarkers(); // 绘制图表轴、标签和标记 drawChartAnimate(); // 绘制折线图的动画 };
这样我们整个代码就编写完成了,为了代码更便于阅读,我们可以将所有方法放到后面,把调用方法的代码放到前面,经过调整的全部代码如下
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="chart" height="400" width="700" style="margin:50px"></div> <script type="text/javascript"> function goChart(cBox,dataArr,textArr){ // 声明所需变量 var canvas,ctx; // 图表属性 var cWidth, cHeight, cMargin, cSpace; var originX, originY; // 柱状图属性 var bMargin, tobalBars, bWidth, maxXValue, maxYValue, minXValue, minYValue; var totalNomber; var yAverage, minTrueYValue, maxTrueYValue; // 运动相关变量 var ctr, numctr, speed; //鼠标移动 var mousePosition = {}; // 创建canvas并获得canvas上下文 canvas = document.createElement("canvas"); if(canvas && canvas.getContext){ ctx = canvas.getContext("2d"); } canvas.innerHTML = "你的浏览器不支持HTML5 canvas"; cBox.appendChild(canvas); initChart(); // 图表初始化 drawLineLabelMarkers(); // 绘制图表轴、标签和标记 drawChartAnimate(); // 绘制柱状图的动画 //检测鼠标移动 var mouseTimer = null; canvas.addEventListener("mousemove",function(e){ e = e || window.event; if( e.offsetX || e.offsetX==0 ){ mousePosition.x = e.offsetX; mousePosition.y = e.offsetY; }else if( e.layerX || e.layerX==0 ){ mousePosition.x = e.layerX; mousePosition.y = e.layerY; } clearTimeout(mouseTimer); mouseTimer = setTimeout(function(){ ctx.clearRect(0,0,canvas.width, canvas.height); drawLineLabelMarkers(); drawChartAnimate(true); },10); }); //点击刷新图表 canvas.onclick = function(){ initChart(); // 图表初始化 drawLineLabelMarkers(); // 绘制图表轴、标签和标记 drawChartAnimate(); // 绘制折线图的动画 }; // 图表初始化 function initChart(){ // 图表信息 cMargin = 60; cSpace = 80; //将canvas扩大2倍,然后缩小,以适应高清屏幕 canvas.width = cBox.getAttribute("width")* 2 ; canvas.height = cBox.getAttribute("height")* 2; canvas.style.height = canvas.height/2 + "px"; canvas.style.width = canvas.width/2 + "px"; cHeight = canvas.height - cMargin*2 - cSpace; cWidth = canvas.width - cMargin*2 - cSpace; originX = cMargin + cSpace; originY = cMargin + cHeight; // 柱状图信息 bMargin = canvas.width/40; tobalBars = dataArr.length; bWidth = parseInt( cWidth/tobalBars - bMargin ); maxXValue = 0; maxYValue = 0; var xArr = []; var yArr = []; for(var i=0; i<dataArr.length; i++){ xArr.push( dataArr[i][0] ); yArr.push( dataArr[i][1] ); } yAverage = ( eval(yArr.join("+"))/yArr.length ).toFixed(2); var addNb = parseInt(yAverage/10); //用于在轴前后加空白 minXValue = Math.min.apply(null,xArr); //求最小值 minXValue = parseInt(Math.max(minXValue-addNb, 0)); //如果减去addNb后小于零,就取零 maxXValue = parseInt(Math.max.apply(null,xArr)+addNb); //用于轴的显示,所以取整 minYValue = minTrueYValue = Math.min.apply(null,yArr); minYValue = parseInt(Math.max(minYValue-addNb, 0)); maxTrueYValue = Math.max.apply(null,yArr); maxYValue = parseInt(maxTrueYValue+addNb); totalNomber = 5; // 运动相关 ctr = 1; numctr = 50; speed = 1.5; } // 绘制图表轴、标签和标记 function drawLineLabelMarkers(){ ctx.translate(0.5,0.5); // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线 ctx.font = "24px Arial"; ctx.lineWidth = 2; ctx.fillStyle = "#000"; ctx.strokeStyle = "#000"; // y轴 drawLine(originX, originY, originX, cMargin); // x轴 drawLine(originX, originY, originX+cWidth, originY); // 绘制标记 drawMarkers(); ctx.translate(-0.5,-0.5); // 还原位置 } // 画线的方法 function drawLine(x, y, X, Y){ ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(X, Y); ctx.stroke(); ctx.closePath(); } // 绘制标记 function drawMarkers(){ ctx.strokeStyle = "#E0E0E0"; // 绘制 y var oneYVal = (maxYValue-minYValue)/totalNomber; ctx.textAlign = "right"; for(var i=0; i<=totalNomber; i++){ var markerVal = parseInt(i*oneYVal+minYValue); var xMarker = originX-10; var yMarker = parseInt( originY-cHeight*(markerVal-minYValue)/(maxYValue-minYValue) ); ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字 if(i>0){ drawLine(originX+2, yMarker, originX+cWidth, yMarker); } } // 绘制 x var oneXVal = (maxXValue-minXValue)/totalNomber; ctx.textAlign = "center"; for(var i=0; i<=totalNomber; i++){ var markerVal = parseInt(i*oneXVal+minXValue); var xMarker = parseInt( originX+cWidth*(markerVal-minXValue)/(maxXValue-minXValue)); var yMarker = originY+30; ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字 if(i>0){ drawLine(xMarker, cMargin, xMarker, originY-2); } } // 绘制标题 y ctx.save(); ctx.rotate(-Math.PI/2); ctx.fillText(textArr[1], -canvas.height/2, cSpace-10); ctx.restore(); // 绘制标题 x ctx.fillText(textArr[0], originX+cWidth/2, originY+cSpace/2+30); }; //绘制动画图 function drawChartAnimate(mouseMove){ var ifTip = false; var tipArr = null; for(var i=0; i<dataArr.length; i++){ ctx.fillStyle = "rgba(46,199,201,0.5)"; var oX = originX+cWidth*(dataArr[i][0]-minXValue)/(maxXValue-minXValue); var oY = originY - cHeight*(dataArr[i][1]-minYValue)/(maxYValue-minYValue); ctx.beginPath(); ctx.arc(oX,oY,8*ctr/numctr,0, Math.PI*2,true); if(!ifTip && mouseMove && ctx.isPointInPath(mousePosition.x*2, mousePosition.y*2)){ //如果是鼠标移动的到柱状图上,重新绘制图表 ctx.fillStyle = "rgba(46,199,201,1)"; //是否绘制提示 ifTip = true; tipArr = dataArr[i]; }else{ ctx.fillStyle = "rgba(46,199,201,0.5)"; } ctx.fill(); } //绘制平均值线 drawAverageLine(); //绘制提示 ifTip && drawTips(mousePosition.x*2, mousePosition.y*2,tipArr[0],tipArr[1]); if(ctr<numctr){ ctr++; setTimeout(function(){ ctx.clearRect(0,0,canvas.width, canvas.height); drawLineLabelMarkers(); drawChartAnimate(); }, speed*=1.08); } } //绘制平均值线 function drawAverageLine(){ ctx.beginPath(); var yNb = originY-cHeight*(yAverage-minYValue)/(maxYValue-minYValue); var xNb = originX+cWidth*ctr/numctr+cMargin/2; ctx.moveTo(originX+2,yNb); ctx.lineTo(xNb,yNb); //设置虚线 ctx.save(); ctx.lineWidth = 4; ctx.strokeStyle = ctx.fillStyle = "#2ec7c9"; ctx.setLineDash([10]); ctx.stroke(); //绘制三角 ctx.beginPath(); ctx.moveTo(xNb,yNb); ctx.lineTo(xNb-5,yNb-8); ctx.lineTo(xNb+12,yNb); ctx.lineTo(xNb-5,yNb+8); ctx.fill(); //绘制文本 ctx.font = "24px Arial"; ctx.fillText(yAverage, xNb-10,yNb-10); //还原 ctx.restore(); } //绘制提示框 function drawTips(oX,oY,xVal,yVal){ ctx.save(); ctx.beginPath(); ctx.fillStyle = "rgba(0,0,0,0.5)"; var H = 100; roundedRect(ctx,oX+10,oY-H/2,2*H,H,5); ctx.fillStyle = "#fff"; ctx.fillText(textArr[1]+":"+yVal, oX+H,oY-H/10); ctx.fillText(textArr[0]+":"+xVal, oX+H,oY+H/4); ctx.restore(); } //绘制圆角矩形的方法 function roundedRect(ctx,x,y,width,height,radius){ ctx.moveTo(x,x+radius); ctx.beginPath(); ctx.lineTo(x,y+height-radius); ctx.quadraticCurveTo(x,y+height,x+radius,y+height); ctx.lineTo(x+width-radius, y+height); ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); ctx.lineTo(x+width,y+radius); ctx.quadraticCurveTo(x+width,y,x+width-radius,y); ctx.lineTo(x+radius,y); ctx.quadraticCurveTo(x,y,x,y+radius); ctx.closePath(); ctx.fill(); } } var dataArr = [[174.0, 65.6], [175.3, 71.8], [193.5, 80.7], [186.5, 72.6], [187.2, 78.8], [181.5, 74.8], [184.0, 86.4], [184.5, 78.4], [175.0, 62.0], [184.0, 81.6], [180.0, 76.6], [177.8, 83.6], [192.0, 90.0], [176.0, 74.6], [174.0, 71.0], [184.0, 79.6], [192.7, 93.8], [171.5, 70.0], [173.0, 72.4], [176.0, 85.9], [176.0, 78.8], [180.5, 77.8], [172.7, 66.2], [176.0, 86.4], [173.5, 81.8], [178.0, 89.6], [180.3, 82.8], [180.3, 76.4], [164.5, 63.2], [173.0, 60.9], [183.5, 74.8], [175.5, 70.0], [188.0, 72.4], [189.2, 84.1], [172.8, 69.1], [170.0, 59.5], [182.0, 67.2], [170.0, 61.3], [177.8, 68.6], [184.2, 80.1], [186.7, 87.8], [171.4, 84.7], [172.7, 73.4], [175.3, 72.1], [180.3, 82.6], [182.9, 88.7], [188.0, 84.1], [177.2, 94.1], [172.1, 74.9], [167.0, 59.1], [169.5, 75.6], [174.0, 86.2], [172.7, 75.3], [182.2, 87.1], [164.1, 55.2], [163.0, 57.0], [171.5, 61.4], [184.2, 76.8], [174.0, 86.8], [174.0, 72.2], [177.0, 71.6], [186.0, 84.8], [167.0, 68.2], [171.8, 66.1], [182.0, 72.0], [167.0, 64.6], [177.8, 74.8], [164.5, 70.0], [192.0, 101.6], [175.5, 63.2], [171.2, 79.1], [181.6, 78.9], [167.4, 67.7], [181.1, 66.0], [177.0, 68.2], [174.5, 63.9], [177.5, 72.0], [170.5, 56.8], [182.4, 74.5], [197.1, 90.9], [180.1, 93.0], [175.5, 80.9], [180.6, 72.7], [184.4, 68.0], [175.5, 70.9], [180.6, 72.5], [177.0, 72.5], [177.1, 83.4], [181.6, 75.5], [176.5, 73.0], [175.0, 70.2], [174.0, 73.4], [165.1, 70.5], [177.0, 68.9], [192.0, 102.3], [176.5, 68.4], [169.4, 65.9], [182.1, 75.7], [179.8, 84.5], [175.3, 87.7], [184.9, 86.4], [177.3, 73.2], [167.4, 53.9], [178.1, 72.0], [168.9, 55.5], [157.2, 58.4], [180.3, 83.2], [170.2, 72.7], [177.8, 64.1], [172.7, 72.3], [165.1, 65.0], [186.7, 86.4], [165.1, 65.0], [174.0, 88.6], [175.3, 84.1], [185.4, 66.8], [177.8, 75.5], [180.3, 93.2], [180.3, 82.7], [177.8, 58.0], [177.8, 79.5], [177.8, 78.6], [177.8, 71.8], [177.8, 116.4], [163.8, 72.2], [188.0, 83.6], [198.1, 85.5], [175.3, 90.9], [166.4, 85.9], [190.5, 89.1], [166.4, 75.0], [177.8, 77.7], [179.7, 86.4], [172.7, 90.9], [190.5, 73.6], [185.4, 76.4], [168.9, 69.1], [167.6, 84.5], [175.3, 64.5], [170.2, 69.1], [190.5, 108.6], [177.8, 86.4], [190.5, 80.9], [177.8, 87.7], [184.2, 94.5], [176.5, 80.2], [177.8, 72.0], [180.3, 71.4], [171.4, 72.7], [172.7, 84.1], [172.7, 76.8], [177.8, 63.6], [177.8, 80.9], [182.9, 80.9], [170.2, 85.5], [167.6, 68.6], [175.3, 67.7], [165.1, 66.4], [185.4, 102.3], [181.6, 70.5], [172.7, 95.9], [190.5, 84.1], [179.1, 87.3], [175.3, 71.8], [170.2, 65.9], [193.0, 95.9], [171.4, 91.4], [177.8, 81.8], [177.8, 96.8], [167.6, 69.1], [167.6, 82.7], [180.3, 75.5], [182.9, 79.5], [176.5, 73.6], [186.7, 91.8], [188.0, 84.1], [188.0, 85.9], [177.8, 81.8], [174.0, 82.5], [177.8, 80.5], [171.4, 70.0], [185.4, 81.8], [185.4, 84.1], [188.0, 90.5], [188.0, 91.4], [182.9, 89.1], [176.5, 85.0], [175.3, 69.1], [175.3, 73.6], [188.0, 80.5], [188.0, 82.7], [175.3, 86.4], [170.5, 67.7], [179.1, 92.7], [177.8, 93.6], [175.3, 70.9], [182.9, 75.0], [170.8, 93.2], [188.0, 93.2], [180.3, 77.7], [177.8, 61.4], [185.4, 94.1], [168.9, 75.0], [185.4, 83.6], [180.3, 85.5], [174.0, 73.9], [167.6, 66.8], [182.9, 87.3], [160.0, 72.3], [180.3, 88.6], [167.6, 75.5], [186.7, 101.4], [175.3, 91.1], [175.3, 67.3], [175.9, 77.7], [175.3, 81.8], [179.1, 75.5], [181.6, 84.5], [177.8, 76.6], [182.9, 85.0], [177.8, 102.5], [184.2, 77.3], [179.1, 71.8], [176.5, 87.9], [188.0, 94.3], [174.0, 70.9], [167.6, 64.5], [170.2, 77.3], [167.6, 72.3], [188.0, 87.3], [174.0, 80.0], [176.5, 82.3], [180.3, 73.6], [167.6, 74.1], [188.0, 85.9], [180.3, 73.2], [167.6, 76.3], [183.0, 65.9], [183.0, 90.9], [179.1, 89.1], [170.2, 62.3], [177.8, 82.7], [179.1, 79.1], [190.5, 98.2], [177.8, 84.1], [180.3, 83.2], [180.3, 83.2] ]; /* * 参数1 :需要显示canvas的dom (非canvas标签,需要指定height和width) * 参数2:二维数据 [0]横轴 [1]纵轴 * 参数3:横轴名称 纵轴名称 * */ goChart(document.getElementById("chart"),dataArr,["身 高","体 重"]) </script> </body> </html>
好了,今天就讲到这里,希望大家把代码都自己敲一遍。
关注公众号,博客更新即可收到推送