canvas画折线图,并且点击小圆点,动态渲染Y轴

<canvas id="cv"></canvas>
   dataX = [1,2,3,4,5];//x轴数据
   dataY = [50,84,67,21,94];//y轴数据
   reportIdList = [01,02,03,04,05];//点击获取到的小圆圈的id数据
   meanValue= 20;//标准线
   xaxis= 28;//天数
   var cv = document.getElementById("cv");
   if (cv.width  < window.innerWidth){
     cv.width  = window.innerWidth-300;
   }else{
     cv.width=917
   }
   cv.height = 500;
   var ctx = cv.getContext("2d");
   //2、获取画布的宽度和高度
   const WIDTH = cv.width;
   const HEIGHT = cv.height;
   //定义坐标轴相对于画布的内边距
   var padding = 20;//初始化内边距
   var paddingLeft = 50;// 至少大于绘制文字的宽度
   var paddingBottom = 30;// 至少大于绘制文字的高度
   //x轴的天数
   var month = {
       x: paddingLeft,
       y: cv.height - paddingBottom + 5
   };
   var origin = { // 原点坐标值(x轴与y轴交叉点)
       x: paddingLeft,
       y: HEIGHT - paddingBottom
   };
   var axisX = { // X轴的起点坐标值
       x: WIDTH - padding,
       y: HEIGHT - paddingBottom
   };
   var axisY = { // y轴的起点坐标值
       x: paddingLeft,
       y: padding-10
   };
   //封装一个折线图的函数
   var arrowWidth = 10;   //箭头的宽度
   var xLength = cv.width - 2*padding - arrowWidth;    //x轴的长度
   ctx.beginPath();//控制绘制的折线不受坐标轴样式属性的影响
   //绘制坐标轴
   ctx.beginPath();
   ctx.moveTo(axisY.x, axisY.y);
   ctx.lineTo(origin.x, origin.y);
   ctx.lineTo(axisX.x, axisX.y);
   ctx.strokeStyle = '#888A92'
   ctx.stroke();

   //绘制坐标轴的箭头
   ctx.beginPath();
   ctx.moveTo(axisY.x - 5, axisY.y + 10);
   ctx.lineTo(axisY.x, axisY.y);
   ctx.lineTo(axisY.x + 5, axisY.y + 10);
   ctx.strokeStyle = '#888A92'
   ctx.stroke();

   ctx.beginPath();
   ctx.moveTo(axisX.x - 10, axisX.y - 5);
   ctx.lineTo(axisX.x, axisX.y);
   ctx.lineTo(axisX.x - 10, axisX.y + 5);
   ctx.strokeStyle = '#888A92'
   ctx.stroke();
   for (var i = 0; i <= xaxis; i++) {
     ctx.textBaseline = "top";
     ctx.fillText(i, month.x, month.y);
     month.x += (axisX.x - origin.x) / (xaxis+1);
   }
   //绘制y轴
   var max = Math.max.apply(Math, dataY);
   if(max<meanValue) max=meanValue
   let c=parseInt(max / 10)
   var axisVal = (origin.y - axisY.y) / (max /c + 1);
   var money = {
       x: axisY.x - 5,
       y: axisY.y + axisVal-13,
       jin: max
   };
   // 遍历最高值/间隔
   ctx.textAlign = "right";
   for (var i = 0; i < 11; i++) {
     ctx.fillText(parseInt(money.jin), money.x, money.y);
     money.y += axisVal;
     money.jin -= c; 
   }
   //中断(坐标轴和折线的)连接
   ctx.stroke();
   ctx.beginPath();
   for(let i = 0; i <dataX.length; i++){
     //x轴的坐标
     let pointX;
     pointX = (cv.width - 2*padding - 20)/(xaxis+1)*dataX[i]+padding+(axisX.x - origin.x) / (xaxis+1);
     //y轴的坐标
     let pointY = origin.y - (origin.y - (axisY.y + axisVal)) * dataY[i] / max-10;
     ctx.textBaseline = "bottom"
     ctx.textAlign = "center"
     if (i === 0) {
         ctx.moveTo(pointX, pointY);
     } else {
         ctx.lineTo(pointX, pointY);
     }
     ctx.strokeStyle = '#409EFF';
     //绘制线
     ctx.fillText(dataY[i], pointX, pointY,'red');
   }
   ctx.stroke();
   //绘制小圆点
   for(let i = 0; i <dataX.length; i++){
     //x轴的坐标
     let pointX;
     pointX = (cv.width - 2*padding - 20)/(xaxis+1)*dataX[i]+padding+(axisX.x - origin.x) / (xaxis+1);
     //y轴的坐标
     let pointY = origin.y - (origin.y - (axisY.y + axisVal)) * dataY[i] / max-10;
     ctx.beginPath();
     ctx.arc(pointX, pointY,3,0,2*Math.PI);
     if(dataY[i]<meanValue){
       ctx.strokeStyle="#000";
       ctx.fillStyle="#FF3D3D";//填充颜色,默认是黑色
     }else{
       ctx.strokeStyle="#000";
       ctx.fillStyle="#3DABFF";//填充颜色,默认是黑色
      
     }
     ctx.fill();//画实心圆
     ctx.closePath();
   }
   //设置节点数据
   for (let i = 0; i < (dataX.length); i++) {
     //x轴的坐标
     let pointX = (cv.width - 2*padding-20 )/(xaxis+1)*dataX[i]+padding+(axisX.x - origin.x) / (xaxis+1)
     //y轴的坐标
     let pointY = origin.y - (origin.y - (axisY.y + axisVal)) * dataY[i] / max-15;
     ctx.beginPath();
     let xs;
     xs=pointX
     drawText(dataY[i],xs, pointY, 'normal 12px MicrosoftYaHei', '#3DABFF');
     ctx.fill(); 
   }
   ctx.stroke();       // 进行绘制
   if(meanValue){
     // 线
     let y=origin.y - (origin.y - (axisY.y + axisVal)) * meanValue / max-10
     ctx.beginPath();    // 开始绘制
     ctx.lineWidth="2";  // 指定线条宽度
     ctx.strokeStyle="#FF4949"; // 指定线条颜色
     ctx.moveTo(50,y);    // 指定线条的起始点
     ctx.lineTo(878,y);// 指定线条的结束点 
     ctx.stroke();       // 进行绘制
     drawText(meanValue, cv.width-20, y+5, 'normal 12px MicrosoftYaHei', '#FF4949');
   }
   drawText('天数', cv.width/2, cv.height, 'normal 12px MicrosoftYaHei', '#000');
   // 文字
   let name='抗压强度(MPa)'; // 文本内容
   let xs = 15;
   let ys=cv.height/3; // 文字开始的坐标
   let letterSpacing = 5; // 设置字间距
   for(let i = 0; i < name.length; i++){
     const str = name.slice(i,i+1).toString();
     if(str.match(/[A-Za-z0-9]/)&&(ys<576)){ // 非汉字 旋转
         ctx.save();
         ctx.translate(xs+5,ys)
         ctx.rotate(Math.PI/180*90);
         ctx.textBaseline = 'top';
         drawText(str,0,0,'normal 12px MicrosoftYaHei','#000');
         ctx.restore();
         ys+=ctx.measureText(str).width+letterSpacing; // 计算文字宽度
     }else if(str.match(/[\u4E00-\u9FA5]/)&&(ys<576)){
         ctx.save();
         ctx.textBaseline = 'top';
         drawText(str,xs,ys,'normal 12px MicrosoftYaHei','#000');
         ctx.restore();
         ys+=ctx.measureText(str).width+letterSpacing; // 计算文字宽度
     }
   }
   // 文字公共方法
   function drawText(text, x, y, font, color) {
     ctx.font= font;
     ctx.fillStyle= color;
     ctx.fillText(text, x, y);
   }
   // 点击小圆点事件
   cv.addEventListener('click', (event)=>{
     let canvas = cv ;
     //获取用户大大鼠标点击的点位坐标
     var p = {};
     p.x = event.clientX - canvas.getBoundingClientRect().left-32;
     p.y = event.clientY - canvas.getBoundingClientRect().top;//为了兼容IE
     var active='';
     // 求点到圆心的距离,用到了勾股定理
     for(let i = 0; i <dataX.length; i++){
       //x轴的坐标
       let pointX = (cv.width - 2*padding-arrowWidth)/(xaxis+1)*dataX[i]+10;
       //y轴的坐标
       let pointY = origin.y - (origin.y - (axisY.y + axisVal)) * dataY[i] / max-15;
       var dis = Math.sqrt((p.x - pointX) * (p.x - pointX) + (p.y - pointY) * (p.y - pointY));//Math.sqrt()求平方跟
       if((i==0 && dis<=15) || (i!=0 && dis <= 6)){
         active=i
         this.activeArc(active)
       }
     }
   }, false)
  //点击小圆点事件
  activeArc(idx){
    
  },

参考文章:canvas画折线图
相比原文,本文增加了Y轴均分以及点击小圆点事件,并且天和天之间可以有多个数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值