前端基础学习之h5-canvas入门3-曲线的绘制及绘制完整饼状图

本文详细介绍了canvas的基本概念,包括弧度计算、圆弧和文本绘制方法。通过实例演示了如何使用arc()函数绘制圆弧,以及如何利用text和fillText绘制文本。重点展示了如何结合这些技巧实现饼状图的绘制,从数据统计到图形呈现,覆盖了完整的制作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

canvas直线绘制及绘制完整折线图

canvas一些基础的概念在直线绘制中已经提过。下面主要提曲线和文本绘制,以完成一个完整饼状图的绘制。

(一)曲线的绘制

  • 弧度概念
    • 1 弧度 = 1 r(半径)
    • 圆的周长=2πr
    • 原的总弧度=2π
  • 确定圆心
  • 确定半径
  • 确定圆弧的起始位置和结束位置 (以弧度为单位,0====水平右边)
  • 确定圆弧的绘制方向 默认false 顺时针
  • arc() 圆弧绘制函数
    • x 圆心横坐标
    • y 圆心纵坐标
    • r 半径
    • startAngle 开始角度
    • endAngle 结束角度
    • anticlockwise 是否逆时针方向绘制(默认false表示顺时针;true表示逆时针)

(二)文本的绘制

  • ctx.font = ‘20px 微软雅黑’ 设置字体
  • strokeText(text,x,y,maxWidth) 绘制空心字体
    • text 要绘制的文本
    • x,y 文本绘制的坐标(文本左下角)
    • maxWidth 设置文本最大宽度,可选参数
  • fillText(text,x,y,maxWidth) 绘制实心字体
    • text 要绘制的文本
    • x,y 文本绘制的坐标(文本左下角)
    • maxWidth 设置文本最大宽度,可选参数
  • ctx.textAlign 文本水平对齐方式,相对绘制坐标
    • left
    • center
    • right
    • start 默认
    • end
  • ctx.direction属性css(rtl ltr) start和end于此相关
    • 如果是ltr,start和left表现一致
    • 如果是rtl,start和right表现一致
  • ctx.textBaseline 设置基线(垂直对齐方式 )
    • top 文本的基线处于文本的正上方,并且有一段距离
    • middle 文本的基线处于文本的正中间
    • bottom 文本的基线处于文本的证下方,并且有一段距离
    • hanging 文本的基线处于文本的正上方,并且和文本粘合
    • alphabetic 默认值,基线处于文本的下方,并且穿过文字
    • ideographic 和bottom相似,但是不一样
  • measureText() 获取文本宽度 拿到的是一个带有width的对象 obj.width

(三)实例

  • 1.体验曲线的绘制
    • 线是由点构成的
    • 曲线可以由数学公式绘制出来
      在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

    //线是由点构成的
    //曲线可以由数学公式画出来
    //公式1: y=6x;
    //公式2: y=(x+2)^2;
    //公式3: y=(x/2-100)^2;
    //公式4: y=sin(x);
    let myCanvas=document.querySelector('canvas');
    let ctx=myCanvas.getContext('2d');

    for(let i=1;i<600;i++){
        let x=i;
        // let y=6*x;
        // let y=Math.pow(x+2,2);
        // let y=Math.pow(x/2-100,2);
        let y=40*Math.sin(x/2)+200;
        ctx.lineTo(x,y);
        ctx.strokeStyle="#479B1E";
        ctx.stroke();
    }
  • 2.使用圆弧绘制函数绘制圆弧
    在这里插入图片描述
    //绘制一个圆心在画布中心 半径为150 右下角半边的圆弧
    let myCanvas=document.querySelector('canvas');
    let ctx=myCanvas.getContext('2d');
    //获取画布的宽高以此来确认圆心
    let canvasWidth=ctx.canvas.width;
    let canvasHeight=ctx.canvas.height;

    //使用函数来绘制圆弧  参数: x,y,r,startAngle,endAngle,direction(圆心,半径,开始弧度,结束弧度,方向)
    //四分之一个圆的弧度===2π/4===π/2
    //函数只是绘制路径
    // ctx.arc(canvasWidth/2,canvasHeight/2,150,0,Math.PI/2);
    //绘制右上角的半边圆弧
    // ctx.arc(canvasWidth/2,canvasHeight/2,150,0,Math.PI*3/2,true);
    //绘制下半边圆弧
    // ctx.arc(canvasWidth/2,canvasHeight/2,150,0,Math.PI);
    //绘制只缺左下角的圆弧
    // ctx.arc(canvasWidth/2,canvasHeight/2,150,Math.PI/2,Math.PI,true);
    ctx.arc(canvasWidth/2,canvasHeight/2,150,Math.PI/2,-Math.PI/4,false);
    ctx.strokeStyle='#479B1E';
    ctx.stroke();
  • 3.绘制扇形
    • 要确定圆心
    • 使用程序自动闭合
      在这里插入图片描述
    let myCanvas=document.querySelector('canvas');
    let ctx= myCanvas.getContext('2d');

    //在中心位置 绘制一个半径为200的 位于右上角的 扇形
    //获取宽高
    let canvasWidth= ctx.canvas.width;
    let canvasHeight= ctx.canvas.height;
    //首先要定起始位置
    ctx.moveTo(canvasWidth/2,canvasHeight/2);
    //绘制弧度
    ctx.arc(canvasWidth/2,canvasHeight/2,200,0,-Math.PI/2,true);
    //使用程序自动闭合
    ctx.closePath();
    ctx.stroke();
    ctx.fill();
  • 4.绘制n等份的颜色随机的圆
    在这里插入图片描述
    let myCanvas = document.querySelector('canvas');
    let ctx = myCanvas.getContext('2d');

    //设置n等分
    let num = 6;
    //那么每一等份的弧度为
    let radian = 2 * Math.PI / num;
    //获取canvas宽高
    let canvasWidth = ctx.canvas.width;
    let canvasHeight = ctx.canvas.height;

    //设置随机颜色
    function getColor() {
        let r = Math.floor(Math.random() * 256);
        let g = Math.floor(Math.random() * 256);
        let b = Math.floor(Math.random() * 256);
        return "rgb(" + r + "," + g + "," + b + ")";
    }

    //遍历等分
    for (let i = 0; i < num; i++) {
        let startRadian = i * radian;
        let endRadian = (i + 1) * radian;
        ctx.beginPath();
        ctx.moveTo(canvasWidth / 2, canvasHeight / 2);
        ctx.arc(canvasWidth / 2, canvasHeight / 2, 200, startRadian, endRadian);
        ctx.fillStyle = getColor();
        ctx.fill();
    }
  • 5.根据数据绘制饼图–统计每个年龄层人数
    在这里插入图片描述
    let myCanvas = document.querySelector('canvas');
    let ctx = myCanvas.getContext('2d');
    //根据数据来绘制饼图
    //统计每个年龄层的人数
    /*
    * 15~20 5
    * 20~25 10
    * 25~30 20
    * 30~35 16
    * 35~40 25
    * */

    //1.设置数据
    let data = [5, 10, 20, 16, 25];
    //2.获取弧度list  每个弧度= 总弧度 * (每个数组/总值)
    let total = data.reduce((previousValue, currentValue, currentIndex, array) => {
        // console.log(previousValue +"=========="+currentValue)
        return previousValue + currentValue;
    });
    //获取canvas宽高
    let canvasWidth = ctx.canvas.width;
    let canvasHeight = ctx.canvas.height;

    //获取随机颜色
    function getColor() {
        let r = Math.floor(Math.random() * 256);
        let g = Math.floor(Math.random() * 256);
        let b = Math.floor(Math.random() * 256);
        return "rgb(" + r + "," + g + "," + b + ")";
    }

    //3.遍历 绘制每个扇形
    let startRadian = 0;
    data.forEach((value, index) => {
        ctx.beginPath();
        ctx.moveTo(canvasWidth / 2, canvasHeight / 2);
        if (index === 0) {
            ctx.arc(canvasWidth / 2, canvasHeight / 2, 200, startRadian, 2 * Math.PI * (value / total));
        } else {
            ctx.arc(canvasWidth / 2, canvasHeight / 2, 200, startRadian, startRadian + 2 * Math.PI * (value / total));
        }
        startRadian = startRadian + 2 * Math.PI * (value / total);
        ctx.fillStyle = getColor();
        ctx.fill();
    })
  • 6.在画布中心绘制文本带下划线
    在这里插入图片描述
    let myCanvas=document.querySelector('canvas');
    let ctx=myCanvas.getContext('2d');

    //在画布中心绘制文本+下划线
    //获取画布宽高
    let canvasWidth=ctx.canvas.width;
    let canvasHeight=ctx.canvas.height;

    //设置文本内容
    let str="春有百花秋有月,夏有凉风冬有雪。";
    //设置文本大小及文本字体
    ctx.font="40px  全新硬笔行书简";
    //设置文本水平对齐方式 以起始坐标为基准 即下面text中的x,y为基准 默认与基线对齐 起始位置在左下角 (矩形绘制起始位置是在左上角)
    //left (默认) center right start end
    ctx.textAlign="center";
    //设置文本垂直对齐方式 top middle bottom
    ctx.textBaseline="middle";
    //绘制空心字体
    // ctx.strokeText(str,canvasWidth/2,canvasHeight/2);
    ctx.fillStyle="#1AC396";
    //绘制实心字体
    ctx.fillText(str,canvasWidth/2,canvasHeight/2);

    //绘制下划线
    //要知道文本的宽度 这样才能确定下划线的开始x和结束x
    ctx.beginPath();
    //测量文本宽度 measureText 拿到的是一个包含宽度的对象
    let textWidth=ctx.measureText(str).width;
    ctx.moveTo(canvasWidth/2-textWidth/2,canvasHeight/2+20);
    ctx.lineTo(canvasWidth/2+textWidth/2,canvasHeight/2+20);
    ctx.strokeStyle="#9CC31A";
    ctx.stroke();
  • 7.绘制完整饼状图
    • 绘制饼图
    • 绘制标题
    • 绘制图例

在这里插入图片描述

   //通过面向对象的方式
    //绘制饼状图
    //1.创建构造函数
    //2.设置数据
    //3.根据数据绘制饼图
    //4.绘制饼图中每一块扇形的标题
    //5.绘制legend 图例

    //饼状图的构造函数
    let PieChart=function (ctx) {
        //上下文
        this.ctx=ctx || document.querySelector('canvas').getContext('2d');
        //画布的宽
        this.canvasWidth=this.ctx.canvas.width;
        //画布的高
        this.canvasHeight=this.ctx.canvas.height;
        //饼状图的圆心 x0
        this.x0=this.canvasWidth/2+20;
        //饼状图的圆心 y0
        this.y0=this.canvasHeight/2;
        //饼状图的半径r
        this.radius=150;
        //标题超出的长度
        this.exceedLength=20;
        //图例距离边框的间距
        this.space=20;
        //图例之间的间距
        this.legendSpace=10;
        //图例矩形部分的宽
        this.rectW=40;
        //图例矩形部分的高
        this.rectH=20;

    };

    //方法初始化
    PieChart.prototype.init=function(data){
       let total= this.getTotalData(data);
       //绘制饼状图
        this.drawPie(data,total);
    };
    //绘制饼状图
    PieChart.prototype.drawPie=function(data,total){
        let startRadian=0;
        data.forEach((item,index) =>{
            this.ctx.beginPath();
            this.ctx.moveTo(this.x0,this.y0);
            //结束弧度
            let temp=2*Math.PI*(item.value/total);
            let endRadian= startRadian+temp;
            //绘制扇形
            this.ctx.arc(this.x0,this.y0,this.radius,startRadian,endRadian);
            //自动闭合
            this.ctx.closePath();
            //设置填充颜色
            let curColor=this.getColor();
            this.ctx.fillStyle=curColor;
            //填充
            this.ctx.fill();

            //绘制标题
            this.drawTitle(startRadian,temp,curColor,item.name);
            //绘制图例
            this.drawLegend(item,curColor,index);

            //下一个开始弧度
            startRadian=endRadian;
        })
    };
    //绘制标题
    PieChart.prototype.drawTitle=function(startRadian,radian,color,text){
        //绘制标题步骤
        //- 获取弧度
        //-获取斜边边长
        //- 获取标题引导线的x y
        //- 绘制引导线
        //- 绘制下划线
        //- 绘制文本

        //获取弧度 =上一个弧度+现在弧度的一半
        let currentRadian=startRadian+radian/2;
        //获取斜边长
        let bevel=this.radius+this.exceedLength;
        //根据cos获取距离圆心x的横轴距离
        let tX=Math.cos(currentRadian)*bevel;
        //根据sin获取距离圆心y的垂直距离
        let tY=Math.sin(currentRadian)*bevel;
        this.ctx.beginPath();
        this.ctx.moveTo(this.x0,this.y0);
        //引导线的x=x0+tX y=y0+tY;
        let lX=this.x0+tX;
        let lY=this.y0+tY;
        this.ctx.lineTo(lX,lY);
        this.ctx.strokeStyle=color;
        // this.ctx.stroke();
        //绘制下划线 下划线的长度根据标题内容大小设置
        this.ctx.font="14px Microsoft YaHei";
        let txtW=this.ctx.measureText(text).width;
        //判断当前超出的点的x位置是在x的左侧还是右侧,左侧- 右侧+
        this.ctx.textBaseline="bottom";
        if(lX>this.x0){
            //画线
            this.ctx.lineTo(lX+txtW,lY);
            this.ctx.textAlign="left";
            //绘制文字
            this.ctx.fillText(text,lX,lY);
        }else {
            this.ctx.lineTo(lX-txtW,lY);
            //在左侧还需设置字体对齐方式
            this.ctx.textAlign="right";
            //绘制文字
            this.ctx.fillText(text,lX,lY);
        }
        this.ctx.stroke();


    };
    //绘制图例
    PieChart.prototype.drawLegend=function(item,color,index){
        //图例绘制
        //矩形绘制 文字绘制
        let rectY=(index+1)*this.legendSpace+index*this.rectH;
        //矩形绘制
        // this.ctx.rect(this.space,rectY,this.rectW,this.rectH);
        this.ctx.fillRect(this.space,rectY,this.rectW,this.rectH);
        //文字绘制
        this.ctx.textAlign="left";
        this.ctx.textBaseline="middle";
        this.ctx.fillText(item.name,this.space+this.rectW+this.legendSpace,rectY+this.rectH/2);


    };
    //获取随机颜色
    PieChart.prototype.getColor=function(){
        let r=Math.floor(Math.random()*256);
        let g=Math.floor(Math.random()*256);
        let b=Math.floor(Math.random()*256);
        return "rgb("+r+","+g+","+b+")";
    };
    //获取数值总值
    PieChart.prototype.getTotalData=function(data){
       return data.reduce((preValue,currentValue)=>{
            return preValue+currentValue.value
        },0)
    };

    //数据值 包含数值,数值名
    let data=[
        {name:"10~15岁",value:25},
        {name:"15~20岁",value:15},
        {name:"20~25岁",value:20},
        {name:"25~30岁",value:35},
        {name:"30~35岁",value:30},
        {name:"35~40岁",value:45}
    ];
    //初始化
    let pieChart= new PieChart();
    pieChart.init(data);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值