欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

canvas绘制曲线图

程序员文章站 2022-05-30 09:25:41
...

canvas绘制曲线图

/**

  • moveTo() 是Canvas 2D API 将一个新的子路径的起始点移动到(x,y)坐标的方法

  • CanvasRenderingContext2D.lineTo()是

  • Canvas 2D API 使用直线连接子路径的终点到(x,y)做标的方法(并不会真正地绘制)。

  • 使用beginPath() 绘制路径的起始点, 使用moveTo()移动画笔,

  • 使用stroke()方法真正的画线

  • 定义和用法:

  • fillText()方法在画布上绘制填色的文本。文本的默认颜色是黑色。

  • 提示:请使用 font 属性来定义字体和字号,并使用fillStyle属性以另一种颜色/渐变来渲染文本。

  • JavaScript 语法:

  • context.fillText(text,x,y,maxWidth);

  • 参数值

  • 参数 描述

  • text 规定在画布上输出的文本。

  • x 开始绘制文本的x坐标位置(相对于画布)。

  • y 开始绘制文本的y坐标位置(相对于画布)。

  • maxWidth 可选。允许的最大文本宽度,以像素计。

  • fillStyle属性来设置用于填充绘图的颜色、渐变或模式

  • strokeStyle 设置描边样式 接收所有颜色类型

  • values为一个数组,从中获取values数组中的最大值

  • var max = Math.max.apply(Math,values);

  • 从中获取values数组中的最小值

  • var min = Math.min.apply(Math,values);

  • PI就是圆周率π,PI是弧度制的π,也就是180°
    所以,Math.PI = 3.14 = 180°

  • const定义的变量不可以修改,而且必须初始化。

  • var定义的变量可以修改,如果不初始化会输出undefined,不会报错。

  • let是块级作用域,函数内部使用let定义后,对函数外部无影响。

  • @param json

  • @returns
    */
    function lenCanvasCT(json){

    var canvas_lens_ct = document.getElementById(‘canvas_lens_ct’);
    // 获取上下文;'2d’建立一个CanvasRenderingContext2D对象代表一个二维渲染上下文。
    var context = canvas_lens_ct.getContext(“2d”);

    //2、获取画布的宽度和高度
    const WIDTH = canvas_lens_ct.width;
    const HEIGHT = canvas_lens_ct.height;

    //3、定义坐标轴相对于画布的内边距
    var padding = 20; //初始化内边距
    var paddingLeft = 50; //至少大于绘制文字的宽度
    var paddingBottom = 70; //至少大于绘制文字的高度
    //4、定义绘制坐标轴的关键点的坐标值;以下这个方式是对象字面量表法,与JsonObject相类似;axis轴线的意思
    var axisY = { //y轴的起点坐标值
    x: paddingLeft,
    y: padding
    };
    var origin = { //原点坐标值(x轴与y轴交叉点)
    x: paddingLeft,
    y: HEIGHT - paddingBottom
    }
    var axisX = { //x轴的起点坐标值
    x: WIDTH - padding,
    y: HEIGHT - paddingBottom
    }

    //绘制坐标轴;axisY:y轴的起点坐标值;orgin:原点坐标值(x轴与y轴交叉点);axisX:x轴的起点坐标值
    context.beginPath();
    context.moveTo(axisY.x, axisY.y); //y轴的起点坐标值开始;Canvas 2D API 将一个新的子路径的起始点移动到(x,y)坐标的方法
    context.lineTo(origin.x, origin.y); //到原点坐标值(x轴与y轴交叉点),竖线
    context.lineTo(axisX.x, axisX.y); //到x轴的起点坐标值,横线
    context.stroke(); //真正的绘制画线

    //绘制坐标轴的箭头;y轴箭头
    context.beginPath();
    context.moveTo(axisY.x - 5, axisY.y + 10);
    context.lineTo(axisY.x, axisY.y); //y轴的起点坐标值
    context.lineTo(axisY.x + 5, axisY.y + 10);
    context.stroke();
    //x轴箭头
    context.beginPath();
    context.moveTo(axisX.x - 10, axisX.y - 5);
    context.lineTo(axisX.x, axisX.y); //x轴的起点坐标
    context.lineTo(axisX.x - 10, axisX.y + 5);
    context.stroke();

    //病例量表平均T分,顶部线
    context.beginPath();
    context.moveTo(WIDTH/3-70, axisY.y);
    context.lineTo(WIDTH/3-50, axisY.y);
    context.strokeStyle = ‘#55aa00’; //绿色
    context.stroke();
    //绘制实心圆点
    context.fillStyle = ‘#55aa00’;
    context.beginPath();
    context.arc(WIDTH/3-60,axisY.y,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();

    //心理症状T分;顶部线
    context.beginPath();
    context.moveTo(WIDTH/2-50, axisY.y);
    context.lineTo(WIDTH/2-30, axisY.y);
    context.strokeStyle = ‘#aa0000’; //红色
    context.stroke();
    //绘制实心圆点
    context.fillStyle = ‘#aa0000’;
    context.beginPath();
    context.arc(WIDTH/2-40,axisY.y,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();

    //装好装坏因子T分;顶部线
    context.beginPath();
    context.moveTo(WIDTH-WIDTH/3-30, axisY.y);
    context.lineTo(WIDTH-WIDTH/3-10, axisY.y);
    context.strokeStyle = ‘#0055aa’; //蓝色
    context.stroke();
    //绘制实心圆点
    context.fillStyle = ‘#0055aa’;
    context.beginPath();
    context.arc(WIDTH-WIDTH/3-20,axisY.y,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();

    //绘制文字;#55aa00绿色;红色#aa0000;#0055aa蓝色;黑色#030303;
    context.fillStyle = ‘#030303’;
    context.strokeStyle = ‘#030303’;
    context.font = ‘13px 宋体’;
    //(参数:要写的字,x坐标,y坐标);context.fillText(‘要写的文字’, 100, 100);
    context.fillText(‘T分’, axisY.x-5, axisY.y-10);
    context.fillText(‘测查日期’, axisX.x-35, HEIGHT - paddingBottom + axisY.y);
    //病例量表平均T分;绿色
    context.fillStyle = ‘#55aa00’;
    context.strokeStyle = ‘#55aa00’;
    context.font = ‘13px 宋体’;
    context.fillText(‘病例量表平均T分’, WIDTH/3-50, axisY.y);
    //心理症状T分;红色
    context.fillStyle = ‘#aa0000’;
    context.strokeStyle = ‘#aa0000’;
    context.font = ‘13px 宋体’;
    context.fillText(‘心理症状T分’, WIDTH/2-30, axisY.y);
    //装好装坏因子T分;蓝色
    context.fillStyle = ‘#0055aa’;
    context.strokeStyle = ‘#0055aa’;
    context.font = ‘13px 宋体’;
    context.fillText(‘装好装坏因子T分’, WIDTH-WIDTH/3-10, axisY.y);
    //恢复原来颜色;黑色
    context.fillStyle = ‘#030303’;
    context.strokeStyle = ‘#030303’;

    //得到数组对象;resultIds即rids数组的长度是多少就加载多少个;即jasMd == json.length-2
    var jasMd = json[json.length-1].jasMd;
    var iave = []; //病例量表平均T分 集合数组
    var mentT = []; //心理症状(总)T分 集合数组
    var gdbd = []; //装好-装坏因子T分 集合数组
    var xsurd = []; //测查日期 集合数组
    //json得到的第1个json[0]对象[object Object]是常数,最后一个json[json.length-1]对象[object Object]对象是MD.DAT文件中所需要的内容数据
    for (var i = 1; i < json.length-1; i++) {
    //console.log(‘json’+i+’:’+json[i]); //得到对应对象
    var japct = json[i].japct;
    var pct1 = japct[0].pctrp; //报告1
    var pct2 = japct[1].pctrp; //报告2
    var pct4 = japct[3].pctrp; //报告4
    mentT.push(pct4[0].jopct); //心理症状(总)T分
    gdbd.push(pct2[91].jopct); //装好装坏因子T分
    xsurd.push(pct1[15].jopct); //测查日期
    var jaMd = jasMd[i-1].jaMd;
    iave.push(jaMd[3].joMd); //病例量表平均T分
    }
    console.log(‘病例量表平均T分iave:’+iave+’–心理症状(总)T分mentT:’+mentT+’–装好-装坏因子T分gdbd:’+gdbd); //可得到具体数组数据

    //存储x轴的值
    var pointsX = [];
    //7、绘制坐标轴的刻度(x轴的测查日期和y轴的总分);x轴的测查日期
    var surveyDay = {
    x: paddingLeft,
    y: HEIGHT - paddingBottom + 5
    }

    //x轴测查日期
    for (var i = 0; i < xsurd.length; i++) {
    context.font = ‘16px’;
    context.textBaseline = ‘top’;
    if(xsurd.length < 9){
    //测查日期数小于9时
    context.fillText(xsurd[i] + ‘日’, surveyDay.x, surveyDay.y);
    }else{
    //测查日期数大于9时,字体竖直排列
    context.fillTextVertical(xsurd[i] + ‘日’, surveyDay.x, surveyDay.y);
    }
    pointsX.push(surveyDay.x);
    surveyDay.x += (axisX.x - origin.x) / xsurd.length;
    }

    //var scoY = (origin.y - axisY.y) / (max / hg + 1); //hg10:y轴划分值;100/10+1;hgap10:最高值间隔
    var scoY = (origin.y-axisY.y)/11; //即单元格高
    var score = {
    x: axisY.x - 5,
    y: axisY.y + scoY,
    fen: 100
    }
    context.textAlign = ‘right’;
    //y轴间隔分数
    for (var i = 0; i <= 10; i++) {
    context.font = ‘16px 宋体’;
    context.fillText(score.fen + ‘分’,score.x, score.y);
    score.y += scoY;
    score.fen -= 10;
    }
    //x轴刻度
    for (var i = 1; i <= 20; i++) {
    context.beginPath();
    context.moveTo(axisY.x, axisY.y+(i+1)scoY/2);
    context.lineTo(axisY.x-5, axisY.y+(i+1)scoY/2);
    context.stroke(); //真正的绘制画线
    }
    //y轴刻度
    for (var i = 0; i < xsurd.length; i++) {
    console.log(‘surveyDay.x:’+surveyDay.x);
    context.moveTo(pointsX[i], axisX.y);
    context.lineTo(pointsX[i], axisX.y+5);
    context.stroke(); //真正的绘制画线
    }
    /

    • var iave = []; //病例量表平均T分 集合数组
      var mentT = []; //心理症状(总)T分 集合数组
      var gdbd = []; //装好-装坏因子T分 集合数组
      */
      //绘制折线;var iave = []; //病例量表平均T分 集合数组
      context.beginPath();
      for (let i = 0; i < iave.length; i++) {
      //x轴的坐标
      let pointX = pointsX[i];
      //y轴的坐标
      let pointY = origin.y - (origin.y - (axisY.y + scoY)) * iave[i] / 100;
      context.fillStyle = ‘#55aa00’;
      if(i === 0){
      // context.textBaseline = ‘’;
      context.textAlign = ‘right’
      context.moveTo(pointX, pointY);
      context.fillText(iave[i]+‘分’, pointX+35, pointY);
      }else{
      context.textBaseline = ‘bottom’;
      context.textAlign = ‘center’;
      context.lineTo(pointX, pointY);
      context.setLineDash([10,10]); //设置虚线
      context.fillText(iave[i]+‘分’, pointX, pointY);
      }
      context.font = ‘16px’;
      }
      context.strokeStyle = ‘#55aa00’; //#55aa00绿色
      context.stroke();

    //绘制小圆点
    for (let i = 0; i < iave.length; i++) {
    //x轴的坐标
    let pointX = pointsX[i];
    //y轴的坐标
    let pointY = origin.y - (origin.y - (axisY.y +scoY)) * iave[i] / 100;
    context.fillStyle = ‘#55aa00’; //#55aa00绿色;红色#aa0000
    context.beginPath();
    context.arc(pointX,pointY,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();
    }

    //折线var mentT = []; //心理症状(总)T分 集合数组
    context.beginPath();
    for (let i = 0; i < mentT.length; i++) {
    //x轴的坐标
    let pointX = pointsX[i];
    //y轴的坐标
    let pointY = origin.y - (origin.y - (axisY.y + scoY)) * mentT[i] / 100;
    context.fillStyle = ‘#aa0000’;
    if(i === 0){
    // context.textBaseline = ‘’;
    context.textAlign = ‘right’
    context.moveTo(pointX, pointY);
    context.fillText(mentT[i]+‘分’, pointX+35, pointY);
    }else{
    context.textBaseline = ‘bottom’;
    context.textAlign = ‘center’;
    context.lineTo(pointX, pointY);
    //context.setLineDash([10,10]); //设置虚线
    context.fillText(mentT[i]+‘分’, pointX, pointY);
    }
    context.font = ‘16px’;
    }
    context.strokeStyle = ‘#aa0000’; //#55aa00绿色
    context.stroke();

    //绘制小圆点
    for (let i = 0; i < mentT.length; i++) {
    //x轴的坐标
    let pointX = pointsX[i];
    //y轴的坐标
    let pointY = origin.y - (origin.y - (axisY.y +scoY)) * mentT[i] / 100;
    context.fillStyle = ‘#aa0000’; //#55aa00绿色;红色#aa0000
    context.beginPath();
    context.arc(pointX,pointY,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();
    }

    //折线:var gdbd = []; //装好-装坏因子T分 集合数组
    context.beginPath();
    for (let i = 0; i < gdbd.length; i++) {
    //x轴的坐标
    let pointX = pointsX[i];
    //y轴的坐标
    let pointY = origin.y - (origin.y - (axisY.y + scoY)) * gdbd[i] / 100;
    context.fillStyle = ‘#0055aa’;
    if(i === 0){
    // context.textBaseline = ‘’;
    context.textAlign = ‘right’
    context.moveTo(pointX, pointY);
    context.fillText(gdbd[i]+‘分’, pointX+35, pointY);
    }else{
    context.textBaseline = ‘bottom’;
    context.textAlign = ‘center’;
    context.lineTo(pointX, pointY);
    context.setLineDash([1,0]); //恢复实线
    context.fillText(gdbd[i]+‘分’, pointX, pointY);
    }
    context.font = ‘16px’;
    }
    context.strokeStyle = ‘#0055aa’; //#0055aa蓝色;#55aa00绿色
    context.stroke();

    //绘制小圆点
    for (let i = 0; i < gdbd.length; i++) {
    //x轴的坐标
    let pointX = pointsX[i];
    //y轴的坐标
    let pointY = origin.y - (origin.y - (axisY.y +scoY)) * gdbd[i] / 100;
    context.fillStyle = ‘#0055aa’; //#0055aa蓝色;#55aa00绿色;红色#aa0000
    context.beginPath();
    context.arc(pointX,pointY,4,0,2*Math.PI); //创建弧/曲线(用于创建圆形或部分圆);半径为4的实心圆
    context.fill();
    }

    //打印显示,canvas本身不显示,用img替换
    canvas_lens_ct.style.display = ‘none’;
    var img_len_ct = document.getElementById(‘img_len_ct’);
    img_len_ct.src = canvas_lens_ct.toDataURL();
    img_len_ct.style.display = ‘block’;
    }

/**

  • @author zhangxinxu(.com)

  • @licence MIT

  • @description http://www.zhangxinxu.com/wordpress/?p=7362

  • canvas日期竖直排列;js混合计算逐字排列

  • values为一个数组,从中获取values数组中的最大值

    • var max = Math.max.apply(Math,values);
    • 从中获取values数组中的最小值
    • var min = Math.min.apply(Math,values);
      */
      CanvasRenderingContext2D.prototype.fillTextVertical = function (text, x, y) {
      var context = this;
      var canvas = context.canvas;

    var arrText = text.split(’’);
    var arrWidth = arrText.map(function (letter){
    return context.measureText(letter).width;
    });

    var align = context.textAlign;
    var baseline = context.textBaseline;

    if(align == ‘left’){
    x = x + Math.max.apply(null, arrWidth) / 2;
    }else if(align == ‘right’){
    x = x - Math.max.apply(null, arrWidth) / 2;
    }
    if(baseline == ‘bottom’ || baseline == ‘alphabetic’ || baseline == ‘ideographic’){
    y = y -arrWidth[0] / 2;
    }else if (baseline == ‘top’ || baseline == ‘hanging’){
    y = y + arrWidth[0] / 2;
    }

    context.textAlign = ‘center’;
    context.textBaseline = ‘middle’;

    //开始逐字绘制
    arrText.forEach(function (letter, index){
    //确定下一个字符的纵坐标位置
    var letterWidth = arrWidth[index];

      // 旋转90度
      context.translate(x, y);
      context.rotate(90 * Math.PI /180);
      context.translate(-x, -y);
      context.fillText(letter, x, y);
      
      // 旋转坐标系还原成初始态
      context.setTransform(1, 0, 0, 1, 0, 0);
      // 确定下一个字符的纵坐标位置
      var letterWidth = arrWidth[index];
      y = y + letterWidth;
    

    });
    // 水平垂直对齐方式还原
    context.textAlign = align;
    context.textBaseline = baseline;
    }