总结canvas基础知识

106 阅读8分钟

canvas

首先来学习看一下基础html结构

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>canvas</title>
    <meta name="description" content="学习canvas">
    <meta name="keywords" content="学习canvas">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=7">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
  </head>
  <body>
    <canvas id="myCanvas" width="500" height="500"></canvas>
    <script type="text/javascript">
        window.onload = function() {
            let canvas = document.getElementById('myCanvas');
            let context = canvas.getContext('2d')
            // 画一个矩形
            context.save(); // 记录状态
            context.fillStyle = 'red'; // 设置填充颜色
            context.fillRect(10,10,100,100); // 画一个矩形
            context.restore(); // 恢复状态
        }
    </script>
  </body>
</html>

常用的方法或名词

  1. save 记录画布当前状态

    context.save();
    
  2. restore 恢复画布状态

    context.restore();
    
  3. fillStyle 设置填充颜色

    context.fillStyle = 'red'; // 支持 #ff0000,颜色单词,rgb
    
  4. fill 填充

    context.save();
    context.beginPath();
    context.moveTo(100,50);
    context.lineTo(150,150);
    context.lineTo(50,150);
    context.closePath();
    context.fill();
    
  5. fillRect 绘制矩形(四个参数,分别是x, y, w, h)

    context.fillRect(0,0,100,100)
    
  6. strokeStyle 设置轮廓颜色

    context.strokeStyle = 'red';
    context.strokeRect(0,0,100,100)
    
  7. stroke 绘制轮廓

    context.save();
    context.beginPath();
    context.moveTo(0,0);
    context.lineTo(120,120);
    context.closePath();
    context.stroke();
    context.restore();
    
  8. strokeRect 绘制矩形轮廓(四个参数,分别是x, y, w, h)

    context.strokeRect(0,0,100,100)
    
  9. lineWidth 轮廓宽度

    context.lineWidth = 6;
    
  10. beginPath/ closePath 开始与闭合路径

    context.save();
    context.beginPath(); // 开始一段新的路径的标志
    context.moveTo(0,0);
    context.lineTo(120,120);
    context.closePath(); // 闭合路径,它会试图从当前路径的终点连一条路径到起点,让整个路径闭合起来。但是,这并不意味着它之后的路径就是新路径了
    context.stroke();
    context.restore();
    
  11. moveTo 起点(两个参数, 分别是x,y)

  12. lineTo 终点或途经点(两个参数, 分别是x,y)

  13. arc 绘制圆形(六个参数, 分别是 x, y, radius(圆弧半径), startAngle开始角度,endAngle 结束角度,anticlockwise 是否逆时针绘制(布尔值))

    context.beginPath(); // 开始路径
    context.arc(230, 90, 50, 0, Math.PI * 2, false); // 绘制一个圆形
    context.closePath();
    context.fill(); // 填充
    
    // 注意: 角度换算弧度
    // let degress = 1; // 1 角度
    // let radians = degress * (Math.PI / 180); // 0.0175弧度
    // 1角度 等于 0.0175弧度
    // fillRect 绘制填充
    // strokeRect 绘制轮廓
    // fill 填充
    // stroke 轮廓
    
  14. font字体大小,字体类型

    context.font = '30px "宋体"'
    
  15. strokeText 字体轮廓 (三个参数,分别是:内容,x, y)

    context.strokeText('内容主体', 100, 100)
    
  16. fillText 字体填充 (三个参数,分别是:内容,x, y)

    context.fillText('内容', 50, 50);
    
  17. clearRect 清除指定画布(四个参数, 分别是:x,y,w,h)

    context.clearRect(0,0,100,100)
    
  18. translate平移(平移的是原点,后面的x,y是相对于平移之后的点作为原点计算x,y)(两个参数,分别是:x,y)

    context.save();
    context.fillRect(100,100,100,100);
    context.translate(100, 100);
    context.strokeRect(110,110, 100,100);
    context.restore();
    
  19. scale缩放(缩放倍数,两个参数,分别是:x, y的倍数)

    context.save();
    context.strokeRect(0,0,100,100);
    context.scale(0.5, 0.5);
    context.strokeRect(0,0,100,100);
    context.restore();
    
  20. rotate旋转(旋转原点,一个参数,为:弧度 Math.PI)

    context.save();
    context.strokeRect(200,0,100,100);
    context.rotate(Math.PI/4);
    context.strokeRect(200,0,100,100);
    context.restore();
    
  21. transform / setTransform 设置矩阵 (六个参数,分别是: a, b, c, d, e, f) 矩阵格式:

    a (默认值1)c(默认值0)e(默认值0)
    b(默认值0)d(默认值1)f(默认值0)
    001

    等同于(下面表格)

    x轴缩放x轴倾斜x轴平移
    y轴倾斜y轴缩放y轴平移
    001
    context.setTransform(1,0,0,1,0,0); // 将矩阵重置为单位矩阵
    
    context.save();
    let xScale = Math.cos(0.7854);
    let ySkew = -Math.sin(0.7854);
    let xSkew = Math.sin(0.7854);
    let yScale = Math.cos(0.7854);
    let xTrans = 200;
    let yTrans = 200;
    context.transform(xScale, ySkew, xSkew, yScale, xTrans, yTrans)
    context.fillRect(-50, -50, 100, 100)
    context.restore();
    
  22. globalAlpha 全局阿尔法值(取值范围: 0.0 ~ 1.0, 默认为 1.0)

    context.save();
    context.fillStyle = 'red';
    context.fillRect(0,0,100,100);
    context.globalAlpha = 0.5;
    context.fillStyle = 'green'
    context.fillRect(60, 0, 100, 100);
    context.restore();
    
  23. globalCompositeOperation 全局合成参数

    说明
    source-over默认值, 表示绘制的图形(源)将画在现有画布(目标)之上
    destination-over表示目标绘制在源之上, 与source-over相反
    source-atop将源绘制在目标之上,但是在重叠区域上两者都是不透明的,绘制在其他位置的目标是不透明的,但源是透明的
    destination-atop目标绘制在源之上,其中在重叠区域上两者都是不透明的,但绘制在其他位置是不透明的,而目标变成透明, 与source-atop相反
    source-in在源与目标重叠的区域只绘制源,而不重叠的部分都变成透明的(个人理解:取相交的部分,展示优先级是源)
    destination-in与source-in相反,在源于目标重叠的区域保留目标,而不重复的部分变成透明(个人理解:取相交部分,展示优先级是目标)
    source-out在与目标不重复的区域上绘制源,其他部分都变成透明的(个人理解:取源不相交的部分展示)
    destination-out与source-out相反,在与目标不重复的区域上保留目标,其他部分都变成透明的(个人理解:取目标不相交的部分展示)
    lighter这个值与顺序无关,如果源与目标重叠,就将这两者的颜色值相加,得到的颜色值的最大取值为255, 也就是白色
    copy这个值与顺序无关, 只绘制源,覆盖掉目标
    xor(异或)这个值与顺序无关,只绘制出不重复的源于目标区域,所有重叠的部分都变成透明的
    context.save();
    context.fillStyle = 'green';
    context.fillRect(400,10,100,100);
    context.globalCompositeOperation = 'source-out';
    context.fillStyle = 'yellow';
    context.fillRect(450,10,100,100);
    context.restore();
    
  24. shadowBlur阴影模糊(默认为0)

    context.shadowBlur = 20;
    
  25. shadowColor 阴影颜色(支持 #ff0000,颜色单词, rgb, rgba)

    context.shadowColor = 'red';
    
  26. shadowOffsetX 阴影x轴偏移 / shadowOffsetY 阴影y轴偏移

    context.save();
    context.fillRect(10,10,100,100);
    context.shadowBlur = 0;
    context.shadowColor = 'rgba(0,0,0,0.2)';
    context.shadowOffsetX = 10;
    context.shadowOffsetY = 10;
    context.fillRect(10, 200, 100, 100);
    context.restore();
    
  27. createLinearGradient 线性渐变(四个参数,分别是:渐变起点x,y、渐变终点x,y)

    let gradient = context.createLinearGradient(0,0,0,500);
    // addColorStop 第一个参数 颜色的偏移值(0表示渐变起点, 1表示终点), 第二个参数 偏移的颜色值
    gradient.addColorStop(0, 'rgb(0,0,0)');
    gradient.addColorStop(1, 'rgb(255,255,255)');
    context.fillStyle = gradient;
    context.globalCompositeOperation = 'destination-over';
    context.fillRect(0,0,600,500);
    
  28. createRadialGradient 放射渐变(6个参数 前3个参数描述一个圆(开始圆), 后3个参数描述另一个圆(结束圆))

    // 例: 光晕的效果(开始圆和结束圆放在同一个位置)
    let radial = context.createRadialGradient(300,300,0, 300,300, 300);
    // addColorStop 第一个参数 颜色的偏移值(0表示渐变起点, 1表示终点), 第二个参数 偏移的颜色值
    radial.addColorStop(0, 'rgb(0,0,0)');
    radial.addColorStop(1, 'rgb(150,150,150)');
    
    context.fillStyle = radial;
    context.globalCompositeOperation = 'destination-over';
    context.fillRect(0,0, 600, 500);
    
  29. quadraticCurveTo创建二次贝塞尔曲线(四个参数: 控制点的x,y坐标值, 以及目标点的 x,y 值)

    context.save();
    context.lineWidth = 6;
    context.beginPath();
    context.moveTo(50,250);
    context.quadraticCurveTo(250, 100, 450,250);
    context.stroke();
    context.restore();
    
  30. bezierCurveTo创建三次贝塞尔曲线(六个参数: 第一个控制点x,y坐标,第二控制点的x,y坐标, 目标点 x,y坐标)

    context.save();
    context.lineWidth = 6;
    context.beginPath();
    context.moveTo(50,250);
    context.bezierCurveTo(150,50,350,450,450,250);
    context.stroke();
    context.restore();
    
  31. toDataURL 导出图像(特殊的,用dom操作)

    const data = document.getElementById('myCanvas').toDataURL();
    // data 为base64的字符,需要自行转换
    let img = document.createElement('img')
    img.src = data;
    img.style.width = '120px';
    img.style.height = '130px';
    document.body.appendChild(img);
    
  32. drawImage 加载图像(至少三个参数,最多九个参数) 三个参数: 图片实例(img), x(坐标), y(坐标) ---- 不做任何处理 五个参数: 图片实例(img), x(坐标), y(坐标), width(图像展示宽度), height(图像展示高度) ---- 图像调整大小 九个参数:图片实例(img),x(图片剪切原点),y(图片剪切原点), width(图片剪切宽度), height(图片剪切高度) ,x(图片实际绘制原点),y(图片实际绘制原点), width(图片实际绘制宽度), height(图片实际绘制高度) --- 图像剪切大小

    let img = new Image();
    img.src = './img/1.png';
    img.onload = function() {
        // 加载图片
        // context.drawImage(img, 0, 0); // 不做任何处理
        // 加载调整图片尺寸
        let bi = img.width / img.height;
        context.drawImage(img, 0,0, 500, 500/bi);
        // 裁剪图像
        // context.drawImage(img, 0,0, 500, 500, 0, 0, 500, 500)
    }
    // 解释: 500 为画布的大小,可以动态获取,例子这里固定了
    
  33. getImageData 访问像素 (四个参数,分别是:x,y w, h)(访问像素区域的x,y坐标点, 以及像素区域宽高范围)

    // 主要留意: getImageData方法返回三个参数:data, width, height; data属性,为一个数组, 每四个组成一个rgba颜色
    // 经典例子 --- 取色器
    let img = new Image();
    img.src = './img/1.png';
    img.onload = function() {
        context.drawImage(img, 0, 0, 500, 500/(img.width/img.height))
    }
    
    canvas.addEventListener('click', function(e) {
        let canvasX = Math.floor(e.pageX - canvas.offsetLeft);
        let canvasY = Math.floor(e.pageY - canvas.offsetTop);
    
        let imgData = context.getImageData(canvasX, canvasY, 1, 1);
        let pixel = imgData.data;
        let pixelColor = `rgba(${pixel[0]},${pixel[1]},${pixel[2]},${pixel[3]})`;
        document.body.style.background = pixelColor
    })
    
  34. createImageData 创建图像 (两个参数, 分别是: w, h) (图像的宽高)

    // createImageData 方法返回三个参数, data, width, height,主要关注data参数
    let imgData = context.createImageData(200, 200);
    let pixels = imgData.data;
    
    console.log(pixels, 'pixels');
    
    let numPixels = imgData.width*imgData.height;
    
    // 绘制红色
    for(let i = 0; i < numPixels; i++) {
        pixels[i*4] = 255;
        pixels[i*4 + 1] = 0;
        pixels[i*4 + 2] = 0;
        pixels[i*4 + 3] = 255;
    }
    
    // 这里讲上面更改了data的数组应用到画布上,不然不生效
    context.putImageData(imgData, 0, 0);
    
    
    // 随机绘制像素
    for(let i = 0; i < numPixels; i++) {
        pixels[i*4] = Math.floor(Math.random()*255); // 红
        pixels[i*4 + 1] = Math.floor(Math.random()*255); // 绿
        pixels[i*4 + 2] = Math.floor(Math.random()*255); // 蓝
        pixels[i*4 + 3] = Math.floor(Math.random()*255); // 透明度
    }
    
    context.putImageData(imgData, 250, 0);
    
  35. putImageData 绘制更改的图像(三个参数: imgData, x , y)

    let imgData = context.createImageData(200, 200);
    let pixels = imgData.data;
    let numPixels = imgData.width*imgData.height;
    // 绘制红色
    for(let i = 0; i < numPixels; i++) {
        pixels[i*4] = 255;
        pixels[i*4 + 1] = 0;
        pixels[i*4 + 2] = 0;
        pixels[i*4 + 3] = 255;
    }
    
    // 这里讲上面更改了data的数组应用到画布上
    context.putImageData(imgData, 0, 0);