canvas的学习

在base64和blob笔记里,使用了canvas进行图片压缩,但是画布的基础就是画画

文章来自三期画布基础教程

// 生成画布
var c = document.getElementById("myCanvas");
c.width = 500;
c.height = 500;
// 生成画笔
var ctx = c.getContext("2d");

// 线,闭合线,填充线
ctx.beginPath();  // 开始画
ctx.moveTo(100, 100);  // 画笔移动到
ctx.lineWidth = 2; // 画笔粗细
ctx.lineCap = 'round';  // 线条首尾
ctx.lineJoin = 'round';  // 线条连接处
ctx.lineTo(300,100);  // 画一条线,开始的x是100,结束的x是300,开始的y是100,结束是0
ctx.lineTo(200,200);  // 画笔初始位置是上一个方法执行后的点
ctx.closePath();  // 闭合线,把开始的位置和上一句代码的位置连接起来
ctx.fill();   //写这句就不需要写closePath了,这句是closePath+填充
ctx.stroke();

// 闭合方形
ctx.beginPath();  // 开始画
ctx.strokeStyle = "red";
ctx.globalAlpha = 0.3;//设置全局透明度
ctx.strokeRect(50,50, 200, 200); //绘制边框
ctx.stroke();

// 填充方形
ctx.beginPath();  // 开始画
ctx.fillStyle = "blue"; //设置颜色
ctx.fillRect(50,50, 200, 200); //绘制方块
ctx.stroke();

// 圆
ctx.beginPath();  // 重新开始一笔
ctx.arc(400, 400, 50, 0, Math.PI*2, false); // 绘制圆圈轨迹,最后一个参数是从上半圆还是下半圆
ctx.stroke();

// 气泡聊天窗
ctx.beginPath();
ctx.moveTo(100,130);
ctx.quadraticCurveTo(100,100,130,100);
ctx.lineTo(270,100);
ctx.quadraticCurveTo(300,100,300,130);
ctx.lineTo(300,200);
ctx.quadraticCurveTo(300,230,270,230);
ctx.lineTo(175,230);
ctx.quadraticCurveTo(140,280,100,280);
ctx.quadraticCurveTo(130,280,150,230);
ctx.lineTo(130,230);
ctx.quadraticCurveTo(100,230,100,200);
ctx.closePath();
ctx.stroke();  // 这一笔结束

// 心形
ctx.beginPath();
ctx.moveTo(100,100);
ctx.bezierCurveTo(100,50,170,50,200,100);
ctx.bezierCurveTo(230,50,300,50,300,130);
ctx.bezierCurveTo(300,140,300,210,200,250);
ctx.bezierCurveTo(100,200,100,140,100,130);
ctx.stroke();

// 点
ctx.beginPath();
ctx.fillRect(51+2*16,35,4,4);
ctx.stroke();

//线性渐变
ctx.beginPath();
var lineargradient = ctx.createLinearGradient(0,0,0,140);// 准备调料
lineargradient.addColorStop(0,'#00ABEB');
lineargradient.addColorStop(0.5, "#fff");
lineargradient.addColorStop(0.5, "green");
lineargradient.addColorStop(1,'#fff');
ctx.fillStyle = lineargradient;
ctx.fillRect(10,10,130,130);
ctx.stroke();

/*径向渐变*/
ctx.beginPath();
var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);  // 准备调料
radgrad.addColorStop(0, "#fff");
radgrad.addColorStop(0.9, "green");
radgrad.addColorStop(1, "rgba(255,255,255,0)"); //最后一个颜色最好写成透明的,这样圆圈以外部分会以这个颜色填充
ctx.fillStyle = radgrad;
ctx.fillRect(0,0,150,150);
ctx.stroke();

// 虚线
ctx.beginPath();
ctx.setLineDash([10, 10]); //设置设置虚线的间隔 x1表示虚线自身长度 x2表示间隔长度  默认单位:px
ctx.lineDashOffset = 5; //设置偏移量
ctx.strokeRect(100,100,100,100); //绘制虚线边框
ctx.stroke();

// 文字
ctx.shadowOffsetX = 2;  //阴影x方向偏移量
ctx.shadowOffsetY = 2;  //阴影y方向偏移量
ctx.shadowBlur = 5;  //阴影模糊度
ctx.shadowColor = "rgba(0,0,0,0.5)";  //阴影颜色
ctx.font = "20px Times New Roman";
ctx.fillStyle = "black";
ctx.fillText("Sample String", 5, 30);

//  save和restore,保存画布的状态
ctx.fillStyle = "darkblue";
ctx.lineWidth = 1;
ctx.fillRect(0,0,150,150);
ctx.save();    //第一次保存 保存了  fillStyle "darkblue"
ctx.fillStyle = "#09f";
ctx.fillRect(15,15,120,120);
ctx.save();    //第二次保存 保存了  fillStyle "#09f"
ctx.fillStyle = "#fff";
ctx.fillRect(30,30,90,90);
ctx.restore();  //恢复到第二次保存的状态
ctx.fillRect(45,45,60,60);
ctx.restore();  //恢复到第一次保存的状态
ctx.fillRect(60,60,30,30);

//先画一个路径然后裁剪
ctx.clip();

// 偏移
ctx.transform(水平方向的移动,竖直方向的移动);
ctx.transform(水平方向的缩放,水平方向的偏移,竖直方向的偏移,竖直方向的缩放,水平方向的移动,竖直方向的移动);
ctx.scale(0.4,0.4); // 缩放
ctx.rotate(-Math.PI/2);  // 角度,参数是pi

// 橡皮擦
ctx.clearRect(50,50, 200, 200);  //清除范围,这里清除的是方块,如果要清除方块描边的话,需要把范围扩大

// 画图,参数有三种填发,2个,4个,8个
sx,开始剪切的 x 坐标位置。
sy,开始剪切的 y 坐标位置。
swidth,被剪切图像的宽度。
sheight,被剪切图像的高度。
x,在画布上放置图像的 x 坐标位置。
y,在画布上放置图像的 y 坐标位置。
width,要使用的图像的宽度。(伸展或缩小图像)
height,要使用的图像的高度。(伸展或缩小图像)
ctx.drawImage(img,x,y);
ctx.drawImage(img,x,y,width,height);
ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

封装一个划线的方法

function drawLine(sx, sy, ex, ey){
    ctx.beginPath();
    ctx.moveTo(sx,sy);
    ctx.lineTo(ex,ey);
    ctx.stroke();
    ctx.closePath();
}

一像素画笔

function draw(){
    // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线
    ctx.translate(0.5,0.5);  
    ctx.lineWidth = 1;
    drawLine(50, 50, 100, 50);  // 上面的划线方法
    ctx.translate(-0.5,-0.5);  // 还原位置
}

动画效果

// 计时器和清除计时器就不说了

//  动画专用的计时器
var nextAnimation = ""
function draw(){
   nextAnimation = window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw); // 执行
window.cancelAnimationFrame(nextAnimation); // 把下一帧清除就等于停止递归

画布事件

var mousePosition = {};
var mouseTimer = null;
canvas.addEventListener("mousemove",function(e){
    e = e || window.event;
    if( e.layerX || e.layerX==0 ){
        mousePosition.x = e.layerX;
        mousePosition.y = e.layerY;
    }else if( e.offsetX || e.offsetX==0 ){
        mousePosition.x = e.offsetX;
        mousePosition.y = e.offsetY;
    }

    clearTimeout(mouseTimer);
    mouseTimer = setTimeout(function(){
        // 清空画布
        ctx.clearRect(0,0,canvas.width, canvas.height);
        drawBarAnimate(true);
    },10);
});

function drawBarAnimate(mouseMove){
   // for循环去生成方块
   drawRect(x, y, X, Y,mouseMove)
}

// 绘制方块
function drawRect( x, y, X, Y, mouseMove ){
    ctx.beginPath();
    ctx.rect( x, y, X, Y );
    // 判断参数的两个值是否在当前的 beginPath 和 closePath 的绘制区域内
    if(mouseMove && ctx.isPointInPath(mousePosition.x, mousePosition.y)){ 
        ctx.fillStyle = "green";
    }else{
        ctx.fillStyle = "red";
    }
    ctx.fill();
    ctx.closePath();
}
原文地址:https://www.cnblogs.com/pengdt/p/12303977.html