canvas菜鸟入门(附demo实战)

4,082 阅读5分钟

1.什么是canvas

1-1 定义

canvas英文翻译为画布,作为一种html5的标签,canvas主要功能是绘画.也就是说使用canvas可以用javasccript在网页上绘制图像,可以精确控制每一个像素.

1-2 用途

(1) 动画,游戏开发 (2) 可视化数据,如echarts图表等 (3) banner广告

2.canvas基础

canvas是常规的html闭合标签,可以设置 width 和 height 属性,单位是 px ,不设置时默认为 300*150 . ie9 以上才支持 canvas, 其他 chrome、ff、苹果浏览器等都支持.

<canvas id="cavasEle">
  你的浏览器不支持canvas,请升级浏览器.浏览器不支持,显示此行文本
</canvas>

canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。有以下关键概念:

(1) Context:

Canvas 的上下文、绘制环境。Context是javascript操作canvas的入口,使用canvas.getContext('2d')获取.

let canvas = document.getElementById('cavasEle'); 
canvas.width = 1200;
canvas.height = 900;
let ctx = canvas.getContext('2d'); 
(2) 坐标系:

canvas 坐标系,从最左上角 0,0 开始。x 向右增大, y 向下增大

(3) 绘制直线

像我们在一张纸上绘制一条直线一样,首先将笔触放在绘制起点,然后开始绘制,直至直线终点,代码表示如下:

// 简单线条
// 设置直线状态 起点 终点 宽度 颜色
ctx.moveTo(100, 100);
ctx.lineTo(100, 700);
ctx.lineWidth = 3;

// 开始绘制  stroke 笔画 绘制线条
ctx.strokeStyle = "red";
ctx.stroke();

// 线条相连成为形状
ctx.moveTo(200, 200);
ctx.lineTo(700, 700);
ctx.lineTo(200, 700);
ctx.lineTo(200, 200);

// 开始绘制  stroke 笔画 绘制线条
ctx.strokeStyle = "rgb(0,0,0)";
ctx.stroke(); // 描边
(4)路径开启与闭合

上面代码操作我们绘制了一条红色的直线和黑色的三角形,但是绘制结果却是两个黑色的,这是由于canvas是基于状态的绘制,在上一个绘制状态没有结束之前,下一次绘制将继承上一次的绘制状态.我们就需要路径开启和闭合工具来对两个不同操作进行隔离.

开始路径:ctx.beginPath(); 每次执行此方法,表示重新绘制一个路径,跟之前的绘制的墨迹可以进行分开样式设置和管理。

闭合路径:ctx.closePath();

ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(100, 700);
ctx.closePath();

// 开始绘制  stroke 笔画 绘制线条
ctx.lineWidth = 3;
ctx.strokeStyle = "red";
ctx.stroke();

// 线条相连成为形状
ctx.beginPath();
ctx.moveTo(200, 200);
ctx.lineTo(700, 700);
ctx.lineTo(200, 700);
ctx.lineTo(200, 200);
ctx.closePath();

// 开始绘制  stroke 笔画 绘制线条
ctx.strokeStyle = "rgb(0,0,0)";
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill()

要点代码总结:

// 划线
context.moveTo()  // 移动画笔位置
context.lineTo()
context.beginPath()
context.closePath()
// 样式设置
context.lineWidth // 线宽
context.strokeStyle // 描边
context.fillStyle  // 填充
// 绘制
context.stroke()
context.fill()
(5)七巧板的绘制实例

绘制之前首先要知道七巧板各个形状的坐标位置,整理如图所示:

代码如下:

let tangram = [
    {p:[{x:0,y:0},{x:800,y:0},{x:400,y:400}],color:"#caff67"},
    {p:[{x:0,y:0},{x:400,y:400},{x:0,y:800}],color:"#67becf"},
    {p:[{x:800,y:0},{x:800,y:400},{x:600,y:600},{x:600,y:200}],color:"#ef3d61"},
    {p:[{x:600,y:200},{x:600,y:600},{x:400,y:400}],color:"#f9f51a"},
    {p:[{x:400,y:400},{x:600,y:600},{x:400,y:800},{x:200,y:600}],color:"#a594c0"},
    {p:[{x:200,y:600},{x:400,y:800},{x:0,y:800}],color:"#fa8ecc"},
    {p:[{x:800,y:400},{x:800,y:800},{x:400,y:800}],color:"#f6ca29"},
];
let canvas = document.getElementById('cavasEle'); 
canvas.width = 1200;
canvas.height = 900;
let ctx = canvas.getContext('2d');
function drawTangram () {
    for(let i=0; i<tangram.length; i++){
        let piece = tangram[i];
        ctx.beginPath();
        ctx.moveTo(piece.p[0].x, piece.p[0].y);
        for(let j=1; j<piece.p.length; j++){
            ctx.lineTo(piece.p[j].x, piece.p[j].y);
        }
        ctx.closePath();
        ctx.fillStyle = piece.color;
        ctx.stroke();
        ctx.fill()
    }
}
drawTangram();

效果如下图:

(6)绘制形状文字
6-1 绘制圆与弧
context.arc(centerx,                    // 圆心x坐标
            centery,                    // 圆心y坐标
            radius,                     // 圆半径
            startingAngle,              // 起始角度
            endingAngle,                // 结束角度
            anticlockwise = false);     // 顺时针:false  逆时针 true

// demo
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = "red";
ctx.arc(50, 50, 20, 0, 1.5*Math.PI);
ctx.stroke();

ctxCircle.beginPath();
ctxCircle.arc(90, 50, 20, 0, 1.5*Math.PI, true);
ctx.strokeStyle = "black";
ctxCircle.stroke();
注意: 绘制圆弧时不需要closePath(); 否则会连成一个闭环,为了防止两次绘制样式污染,每次绘制前执行beginPath()即可
6-2 绘制矩形
// (1)  两步绘制
context.rect(x,      // 绘制起点x坐标
            y,       // 绘制起点y坐标
            width,   // 矩形宽
            height); // 矩形高
// x, y是矩形左上角坐标
context.stroke();

// (2) 描边矩形
context.strokeRect(x, y, width, height)

// (3) 填充矩形
context.fillRect(x, y, width, height)

// 清除矩形   清除某个矩形内的绘制的内容,相当于橡皮擦
context.clearRect(x, y, width, hegiht);
6-3 绘制文字

文字样式设置与css相同

context.moveTo(300, 300);
context.fillStyle = 'purple'; //设置填充颜色为紫色
context.font = '20px "微软雅黑"'; //设置字体
context.textBaseline = 'bottom'; //设置字体底线对齐绘制基线
context.textAlign = 'left'; //设置字体对齐的方式
context.strokeText( "hello", 360, 250 ); // 在画布上绘制文本(无填充)
context.fillText('hello world', 660, 250); // 填充文字
let text1 = context.measureText('hello')  // 返回包含指定文本宽度的对象
console.log(text1)
let text2 = context.measureText('hello world')
console.log(text2)
(7)小球运动动画绘制

要用canvas做一个小球运动的动画效果,首选需要知道小球的运动轨迹,这就需要用到我们以前学到的物理学知识,简略的小球运动示意图如下:

代码如下:

// data:
let runBallConfig = {
        ballRadius: 20,
        startX: 30,
        startY: 30,
        vx: 5,
        vy: 0,
        g: 2,
}
// js:
let canvasBall = this.$refs.canvasBall;
canvasBall.width = 1200;
canvasBall.height = 400;
ctxBall = canvasBall.getContext("2d");
drawRunBall(runBallConfig.startX, runBallConfig.startY);
setInterval(()=>{
    updateBall();
},50)

updateBall(){
    runBallConfig.startX += runBallConfig.vx
    runBallConfig.startY += runBallConfig.vy
    runBallConfig.vy += runBallConfig.g
    drawRunBall(runBallConfig.startX, runBallConfig.startY);
    // 临界判断
    if(runBallConfig.startY >= 400 - runBallConfig.ballRadius){
        runBallConfig.startY = 400 - runBallConfig.ballRadius;  // 落地
        runBallConfig.vy = - (runBallConfig.vy) * 0.5;   // 摩擦阻力系数0.5
    }
},
drawRunBall(x, y){
    ctxBall.clearRect(0, 0, 1200, 400);
    ctxBall.beginPath();
    ctxBall.lineWidth = 3;
    ctxBall.strokeStyle = "red";
    ctxBall.arc(x, y, runBallConfig.ballRadius, 0, 2*Math.PI);
    ctxBall.stroke();
    ctxBall.fillStyle = "red";
    ctxBall.fill()
},
(8)绘制图片
// 图片绘制
context.drawImage(img, x, y, width, height);
//img为绘制图片的dom对象,x、y为绘制的左上角坐标.
//width, height 绘制图片的宽高
// 图片裁剪
context.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);
// sx, sy 裁剪的xy坐标
// swidth, sheight 裁剪图片的xy
(9) 折线图demo 与 饼状图demo

git地址:github.com/aicai0/test…

如有问题,欢迎探讨,如果满意,请手动点赞,谢谢!🙏

及时获取更多姿势,请您关注!!