JS操作canvas

<canvas>元素本身并不可见,它只是创建了一个绘图表面并向客户端js暴露了强大的绘图API。

1  <canvas> 与图形

为优化图片质量,不要在HTML中使用width和height属性设置画布的屏幕大小。而要使用CSS的样式属性width和height来设置画布在屏幕上的预期大小。然后在JS开始绘制前,再将画布对象的width和heigh属性设置为CSS像素乘以window.devicePixelRatio。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<canvas width="100" height="100" id="canvas1"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px"></canvas>
</body>
</html>
<script>
    let canvas2 = document.querySelector("#canvas2");

    canvas2.width = 100 * window.devicePixelRatio;
    canvas2.height = 100 * window.devicePixelRatio;
</script>

图 代码实现效果

1.1 save()、restore()与beginPath()

beginPath() 开始一条路径或重置当前路径,表示重新开始一个新的路径内容。

<script>
    let context = document.querySelector("#canvasId").getContext("2d");

    context.rect(0,0,30,30);
    context.fillStyle = "green";
    context.fill();
    // 缺失 content.beginPath() 那么上面的矩形fillStyle颜色
    // 始终是在beginPath出现之前设置的fillStyle,即"red";
    context.rect(40,40,30,30);
    context.fillStyle = "red";
    context.fill();

    context.beginPath(); // 重新开始路径内容
    context.rect(80,80,30,30);
    context.fillStyle = "blue";
    context.fill();
</script>

图 beginPath演示效果图

save()方法把当前的图形状态(不包括当前定义的路径和当前的点)推到一个保存到状态栈中,而restore()方法则从该栈中弹出状态。

<script>
  let context = document.querySelector("#canvasId").getContext("2d");
  context.fillStyle = "green";
  context.fillRect(0,0,50,50);
  context.save(); //保存fillStyle等状态信息
  context.fillStyle = "red";
  context.fillRect(60,0,50,50);
  context.save();
  context.restore(); // red
  context.fillRect(120,0,50,50);
  context.restore(); // green
  context.fillRect(180,0,50,50);
</script>

图 store() 演示效果图

1.2 渐变色

需要将fillStyle(或strokeStyle)设置为CanvasGradient对象。上下文有两个方法用于创建这个对象:

1)createLinearGradient(),参数是定义一条直线的两个点的坐标,颜色将在这条直线的方向上渐变。

2)createRadialGradient(),需要指定两个圆心和半径(着两个圆不一定是同心圆),小圆内部区域或大圆外部区域将被实色填充,这两个区域之间的部分则会以渐变色填充。

在创建这个对象后,必须调用该对象的addColorStop()方法定义渐变色。第一个参数是一个介于0.0和1.0之间的数值,第二个参数是一个CSS颜色说明。至少必须调用这个方法两次。

<script>
    let canvas = document.querySelector("#canvasId");
    canvas.width = 300 * window.devicePixelRatio;
    canvas.height = 200 * window.devicePixelRatio;
    let context = canvas.getContext("2d");
    context.rect(0,0,130,150);
    let canvasGradient = context.createLinearGradient(30,20, 130,150);
    context.fillStyle = canvasGradient;
    canvasGradient.addColorStop(0,"red");
    canvasGradient.addColorStop(1,"blue");
    context.fill();

    context.beginPath(); // 开始新路径
    context.rect(140,0,200,200);
    let radial = context.createRadialGradient(240,100,50,240,100,100);
    context.fillStyle = radial;
    radial.addColorStop(0, "yellow");
    radial.addColorStop(1,"green");
    context.fill();
</script>

图 渐变色实现效果

1.3 坐标系转换

translate()方法简单地向左、右、上、下移动坐标系原点。rotate()方法按照指定角度旋转坐标轴。scale()方法沿x轴或y轴拉伸或压缩距离(给scale()方法传入一个负缩放因子会围绕原点反转坐标轴,就好像镜子里的倒影一样)。

<script>
    let context = document.querySelector("#canvasId").getContext("2d");

    (function scaleTest() {
        context.translate(100,0);
        drawTrapezoid("green")
        context.scale(-1,1);
        drawTrapezoid("red")
    }());

    function drawTrapezoid(color) {
        context.beginPath();
        context.moveTo(0,20);
        context.lineTo(0,170);
        context.lineTo(-70,150);
        context.lineTo(-70,70);
        context.closePath();
        context.fillStyle = color;
        context.fill();
        context.save();
    }
</script>

图 scale 实现效果图

《JavaScript权威指南》中的科赫雪花代码:

<script>
    let canvas = document.querySelector("#canvasId");
    canvas.width = 500 * window.devicePixelRatio;
    canvas.height = 500 * window.devicePixelRatio;
    let c = canvas.getContext("2d");
    let deg = Math.PI / 180;

    function snowflake(n,x,y,len) {
        c.save();
        c.translate(x,y);
        c.moveTo(0,0);
        leg(n);
        c.rotate(-120 * deg);
        leg(n);
        c.rotate(-120 * deg);
        leg(n);
        c.closePath();
        c.restore();

        function leg(n) {
            c.save();
            if (n === 0) {
                c.lineTo(len,0);
            } else {
                c.scale(1/3,1/3);
                leg(n-1);
                c.rotate(60 * deg);
                leg(n-1);
                c.rotate(-120 * deg);
                leg(n-1);
                c.rotate(60 * deg);
                leg(n-1);
            }
            c.restore();
            c.translate(len,0);
        }
    }

    snowflake(0,25,125,125);
    snowflake(1,175,125,125);
    snowflake(2,325,125,125);
    snowflake(3,475,125,125);
    snowflake(4,625,125,125);
    c.stroke();
</script>

图 科赫雪花实现效果

1.4 剪切

clip()方法定义一个剪切区域,定义后,这个区域外部将不会被绘制。它的作用是遮罩,用来隐藏没有遮罩的部分。

<script>
    const context = document.querySelector("#canvasId").getContext("2d");
    context.fillStyle = "red";
    context.arc(100,100,100,0,Math.PI * 2,true);
    context.fill();
    context.clip();
    context.beginPath();
    context.fillStyle = "blue";
    context.arc(200,100,100,0,Math.PI * 2, true);
    context.fill();
    context.beginPath();
    context.fillStyle = "green";
    context.arc(100,200,100,0,Math.PI * 2, true);
    context.fill();;
</script>

图 clip()演示效果图

1.5 像素操作

context的getImageDate()方法返回一个ImageData对象,表示画布中某矩形区域中包含的原始像素(包括R、G、B和A组件)。createImageData()创建空的ImageData对象,ImageData对象中的像素是可写的。putImageData()方法则是把像素复制到画布中。

<script>
    let canvas = document.querySelector("#canvasId");
    canvas.width = 300 * window.devicePixelRatio;
    canvas.height = 300 * window.devicePixelRatio;
    let context = canvas.getContext("2d");
    context.fillStyle = "#008000";
    context.arc(100,100,100,0,Math.PI,true);
    context.fill();
    let imageData = context.getImageData(0,0,200,200);
    let width = imageData.width,height = imageData.height;
    let data = imageData.data; // 每个像素占用4个连续字节,分别是R、G、B和A
    for (let pos = 0; pos < data.length; pos+=4) {
        if (data[pos + 1] === 128) {
            data[pos] = 255;
            data[pos + 1] = 0; //G
            data[pos + 2] = 0; // B
            data[pos + 3] = 255; // A
        }
    }
    context.putImageData(imageData,210,0);
</script>

图 像素操作演示效果图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值