loading

Canvas


Canvas

canvas 是HTML5新出的标签,可以用来做小游戏,特效,作图等,自己并没有作画能力,只能通过Javascript脚本来操控

Canvas标准

http://www.w3c.org/TR/2dcontext/
https://html.spec.whatwg.org/

创建Canvas

创建canvas几个主要的问题:

1.不能通过CSS设置画布的大小,否则会造成画布拉伸变形等问题,只能设置本身自带width、height属性,也可以在js里设置

2.兼容性:对一些不支持的浏览器,可以在标签内输入提示,不支持的浏览器会显示此提示、支持的浏览器会自动忽略掉

3.创建并设置好宽高后,通过js获取,还要设置其getContext,成功返回一个对象后即可作画,这里用js也可判断其是否支持canvas

语法格式:

<canvas width="1024" height="570" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas>
<script>
    var ctx = document.querySelector(".canvas").getContext("2d|3d");
</script>

手册参考网址

线

画布的x、y起点默认在右上角的位置(0,0), 分别对应的最大值是画布的宽和高

绘制线条的函数:

moveTo(x,y) : 开始位置

lineTo(x,y):结束位置

stroke :准备好后,开始画线条

设置线条样式的函数:

lineWidth:设置线条粗细

strokeStyle:设置线条的颜色

lineCap:设置线条首尾处的形状 俗称帽子

lineJoin:设置连接处的样式

miterLimit:内角与外角的距离。默认值是10,此属性只有在lineJoin = “miter”并且有设置线条粗细情况下才有效,且斜接长度大于miterLimit ,线条连接处自动斜切(lineJoin =”bevel”)

另起一条路径的函数:

beginPath:起始一条路径,或重置当前路径

closePath:创建从当前点回到起始点的路径

语法格式:

<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
   var ctx = document.querySelector(".canvas").getContext("2d|3d");
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(700,700);
    ctx.lineTo(100,700);
    ctx.lineTo(100,100);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "green";
    ctx.stroke();
    ctx.closePath();
    
    ctx.beginPath();
    ctx.lineCap = "round" //butt(default) round圆头 square方头
    //lineCap 有时可以填补连接处的空缺
    ctx.moveTo(200,200);
    ctx.lineTo(400,400);
    ctx.lineTo(200,400);
    ctx.lineTo(200,200);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "yellow";
    ctx.stroke();
    ctx.closePath();
</script>
===============================================================
ctx.lineWidth = 15;
DrawStart(ctx, 100, 20, 400, 400, -30);
      ctx.lineJoin = "miter"; //可以设置的样式有:miter(default)、 bevel斜接、 round圆角
      ctx.miterLimit = 7; //如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示。,这里等于7时,边角会以lineJoin的bevel显示,等于8时则会以miter显示
	//斜接长度指的是在两条线交汇处内角和外角之间的距离。


      ctx.stroke();
      function DrawStart(context, R, r, x, y, rotate) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i - rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i - rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i - rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i - rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }

填充

填充函数:

fill :填充当前路径 (注意:如果路径未关闭,那么 fill() 方法会从路径结束点到开始点之间添加一条线,以关闭该路径,然后填充该路径)

填充样式:

fillStyle:填充颜色

语法格式:

<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
   var ctx = document.querySelector(".canvas").getContext("2d|3d");
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(700,700);
    ctx.lineTo(100,700);
    ctx.lineTo(100,100);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "green";
    ctx.stroke();
    ctx.fillStyle = "red";
    ctx.fill()
    ctx.closePath();
    
    ctx.beginPath();
    ctx.moveTo(200,200);
    ctx.lineTo(400,400);
    ctx.lineTo(200,400);
    ctx.lineTo(200,200);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "yellow";
    ctx.stroke();
    ctx.closePath();
</script>

案例:四个正方形组成的大方形

   var ctx = document.querySelector(".canvas").getContext("2d");
let box = [
        {p:[{x:0,y:0},{x:512,y:0},{x:512,y:380},{x:0,y:380},{x:0,y:0}],color:"red"},
        {p:[{x:512,y:0},{x:1024,y:0},{x:1024,y:380},{x:512,y:380},{x:512,y:0}],color:"green"},
        {p:[{x:0,y:380},{x:512,y:380},{x:512,y:760},{x:0,y:760},{x:0,y:380}],color:"blue"},
        {p:[{x:512,y:380},{x:1024,y:380},{x:1024,y:760},{x:512,y:760},{x:512,y:380}],color:"yellow"},
        
      ]
      for(let i=0;i<box.length;i++)
      {
        draw(box[i],ctx);
      }

      function draw(p,c)
      {
        c.beginPath();
          c.moveTo(p.p[0].x,p.p[0].y);
          for(let i=1;i<p.p.length;i++)
          {
            c.lineTo(p.p[i].x,p.p[i].y);
          }
          c.lineWidth = 5;
          c.strokeStyle = p.color;
          c.fillStyle = p.color;
        c.stroke();
        c.fill();
        c.closePath();
      }

注意点:

  1. closePath可以解决闭合图形的空隙问题,也有自动闭合的作用。
  2. 当边框或者填充被遮挡掉的时候,这时可以先填充在画边框,或者先画边框再画线
  3. 后绘制的图形会顶替掉前面的图形

画圆的函数:

arc(x,y,r,start,end,true|false):画圆\弧

arcTo(x1,y1,x2,y2,r):绘制圆弧

语法格式:

 var ctx = document.querySelector(".canvas").getContext("2d");
      var i = 0;
      setInterval(() => {
        i++;
        ctx.fillStyle = "yellow";
        ctx.strokeStyle = "red";
        ctx.beginPath();					   
        ctx.arc(512, 380, 100, 0, Math.PI * 2 - (Math.PI * 2 * i / 30), true);
			//  x    y  半径 开始位置  结束位置                      是否逆时针旋转
        ctx.lineWidth = 10;
        ctx.stroke();
        ctx.fill();
      }, 1);
//顺时针:Math.PI * 2 * i / 30
//逆时针:Math.PI * 2 - (Math.PI * 2 * i / 30)

//使用arcTo绘圆角矩形
var ctx = document.querySelector("canvas").getContext("2d");
      // ctx.translate(200,200)
      // ctx.beginPath();
      // ctx.moveTo(100,0);
      // ctx.arcTo(400,0,400,800,100);
      // ctx.lineTo(400,400);
      // ctx.arcTo(400,500,350,500,100);
      // ctx.lineTo(100,500);
      // ctx.arcTo(0,500,0,450,100);
      // ctx.lineTo(0,100);
      // ctx.arcTo(0,0,100,0,100)
      // ctx.closePath();

      function RoundRect(ctx, width, height, r) 
      {
        ctx.beginPath();
        ctx.moveTo(r, 0);
        ctx.arcTo(width, 0, width, height - r, r);
        ctx.lineTo(width, height);
        ctx.arcTo(width, height + r, width - 50, height + r, r);
        ctx.lineTo(r, height + r);
        ctx.arcTo(0, height + r, 0, height - 50, r);
        ctx.lineTo(0, r);
        ctx.arcTo(0, 0, r, 0, r);
        ctx.closePath();
      }
      RoundRect(ctx, 200, 100, 10);
      ctx.stroke();

矩形

矩形函数:

reac:绘制矩形附带填充和边框

fillRect:绘制只填充的矩形

strokeRect:绘制只带边框的矩形

语法格式:

//  参数:  x , y , width , height  
var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.fillStyle = "red";
      ctx.strokeStyle = "yellow";
      ctx.lineWidth = 5;
      var x = 0;
      ctx.beginPath();
      ctx.rect(100, 100, 300, 300);
      ctx.stroke();
      ctx.fill();

      ctx.beginPath();
      ctx.fillStyle = "rgba(0,255,155,0.5)";
      ctx.strokeStyle = "yellow";
      ctx.fillRect(150, 150, 300, 300);
      ctx.strokeRect(100, 100, 400, 400);

案例:绘制五角星

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800"></canvas>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.lineWidth = 10;
      ctx.beginPath();
      for (var i = 0; i <= 5; i++) {
        ctx.lineTo(
          Math.cos(((18 + 72 * i) / 180) * Math.PI) * 100 + 200,
            		//步骤:先求出角度在转弧度
            		//cos(18deg)*R   sin(18deg)*R
            		//角度转弧度公式:角度/180*r
            		//由于数学中的坐标系与canvas的坐标不同所以y轴要为负
          -Math.sin(((18 + 72 * i) / 180) * Math.PI) * 100 + 200
        );
        ctx.lineTo(
          Math.cos(((54 + 72 * i) / 180) * Math.PI) * 50 + 200,
          -Math.sin(((54 + 72 * i) / 180) * Math.PI) * 50 + 200
        );
      }
      ctx.closePath();
      ctx.stroke();
     =================================================================================
         //五角星封装函数
      DrawStart(ctx, 200, 100, 400, 400 , 30);
      ctx.stroke();
      function DrawStart(context, R, r, x, y,rotate) {
          			  //绘画对象 大圆的半径 小圆半径  x轴 y轴  旋转角度
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i -rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i -rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i -rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i -rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }
    </script>
  </body>
</html>

参考链接:https://www.baidu.com/link?url=3j7UmP9XbkLh0ww6tMOChL_7CATbIoQ15GBatuaJdx2_yCn-jcdshTRF9-l6kMmbONf5cgLEviZEpV4QhjLf2q&wd=&eqid=e9fcd7b0000436fd000000065d2e7488

随机不重复、不切边五角星

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800" class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.fillStyle = "black";
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele);
      end(ele);

      function start(arr) {
        for (var i = 0; i < 200; i++) {
          var flag = true,
            ran = Math.random() * 10 + 10,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
              ran,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          DrawStart(
            ctx,
            arr[i][0],
            arr[i][0] / 2,
            arr[i][1],
            arr[i][2],
            arr[i][3]
          );
          ctx.fill();
          ctx.stroke();
        }
      }
      function DrawStart(context, R, r, x, y, rotate) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i - rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i - rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i - rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i - rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }
    </script>
  </body>
</html>

绘画状态保存与还原

状态的保存与还原可以使操作更加简便,快速,主要作用于将绘画的状态来回快速切换,状态保存,可以保存如:线条的样式、颜色、填充、图形变换等,特别是配合图形变换,两者可以互补长短

状态保存和还原的对应函数:

save:保存当前的状态,以便restore还原

restore:还原到之前sava保存的状态

语法格式:

//这里配合图形变换来演示
//图形变换系列的函数,重复使用是叠加效果,而不是替换,所以使用图形变换+状态保存还原可以更快速简便

//正常方式
  var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.translate(100, 100);
      ctx.fillRect(0, 0, 400, 400);
      ctx.translate(-100, -100);
      ctx.fillStyle = "red";
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();
      //图形变换函数连续使用会进行叠加效果,会影响到下面绘制的图形,为了不影响,必须再次使用变换函数来还原
      
//这里运用了canvas的状态保存还原后,可以更方便使用变换函数
var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.save();
      ctx.translate(100, 100);
      ctx.fillRect(0, 0, 400, 400);
      ctx.restore();
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();

图形变换

图形变换系列函数:

translate(x,y):偏移、移动

rotate(?deg):旋转

scale(sx,sy):缩放

变换矩阵:

transform(a,b,c,d,e,f):图形变换矩阵函数是一个把所有变换效果结于一身的函数,连续使用会造成链集和叠加效果

setTransform(a,b,c,d,e,f):可以重置transform函数,使之前的失效

语法格式:

//改用图形变换函数 translate rotate scale 后的无重复五角星
//scale 会有许多副作用如:边框将会变大、长宽比也好增大、x、y也会随之增大
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800" class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.fillStyle = "black";
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele);
      end(ele);

      function start(arr) {
        for (var i = 0; i < 200; i++) {
          var flag = true,
            ran = Math.random() * 10 + 10,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
              ran,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          ctx.save();
          ctx.beginPath();
          ctx.translate(arr[i][1], arr[i][2]);
          ctx.rotate(arr[i][3]);
          ctx.scale(0.5,0.5)
          DrawStart(ctx, arr[i][0]);
          ctx.fill();
          ctx.stroke();
          ctx.closePath();
          ctx.restore();
        }
      }
      function DrawStart(context, r) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        for (var i = 0; i <= 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i) / 180) * Math.PI) * r,
            -Math.sin(((18 + 72 * i) / 180) * Math.PI) * r
          );
          ctx.lineTo(
            (Math.cos(((54 + 72 * i) / 180) * Math.PI) * r) / 2,
            (-Math.sin(((54 + 72 * i) / 180) * Math.PI) * r) / 2
          );
        }
      }
    </script>
  </body>
</html>


//transform
 var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.save();
      ctx.transform(1.5,0,0,1.5,200,100);
      			a:水平缩放 b:水平倾斜 c:垂直倾斜 d:垂直缩放 e:水平位移 f:垂直位移
      ctx.fillRect(0, 0, 400, 400);
      ctx.restore();
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();

渐变

渐变系列函数:

createLinearGradient(x,y,EndX,EndY):创建渐变

addColorStop(0-1,color) :添加颜色

createRadialGradient(x1,y1,r1,x2,y2,r2):创建一个径向的渐变,整个径向渐变发生在俩个圆中间

语法格式:


var ctx = document.querySelector("canvas").getContext("2d");
      document.querySelector("canvas").width = document.body.clientWidth;
      document.querySelector("canvas").height = document.body.clientHeight;
      //创建渐变对象
      var grd = ctx.createLinearGradient(
        0,   //x
        0,	//y
        0,	//endX
        document.querySelector("canvas").height //endY
        //这里的渐变方向是从上往下
      );
      
      
      //下面的是径向渐变,在定义的两个圆之间产生渐变
      //第一个圆是外圆,内圆则是第二个
      //var grd = 			ctx.createRadialGradient(document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,400,document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,0)
      
      
      //添加颜色,取值范围(0,1),必须有起点,终点
      grd.addColorStop(0, "black");
      grd.addColorStop(1, "#035");
      //最后把渐变对象添加到要应用的样式填充上
      ctx.fillStyle = grd;
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

三角函数讲解

绘制圆形

1角度 = 1* Math.PI/ 180弧度

1弧度 = 1* 180 / Math.PI 角度

arc(x,y,r,0,360,false)

x,y 圆心坐标位置

r 圆半径

0,360

从0度到360度所对应的弧度 (弧度: 角度值*Math.PI/180) true/false 逆时针/顺时针绘图

添加图片、视频、canvas

相关函数:

createPattern(ele,repeat|repeat-x|repeat-y|no-repeat):添加图片、视频、画布到指定的场景

语法格式:

//添加图片
 var ctx = document.querySelector("canvas").getContext("2d");
      var img = new Image();
      img.src = "../newIMg.png";
      img.onload = () => {
        var createImg = ctx.createPattern(img, "repeat");
        ctx.fillStyle = createImg;
        ctx.fillRect(0, 0, 800, 800);
      };
 //添加图片时注意:必须图片加载完后在载入createPattern,否则载入失败
 
 //添加画布
 function createImgCanvas() {
        var c = document.createElement("canvas");
        var ctx = c.getContext("2d");

        c.width = 400;
        c.height = 400;
        ctx.fillStyle = "yellow";
        ctx.transform(1, 0, 0, 1, c.width / 2, c.height / 2);
        DrawStart(ctx, 200);
        ctx.fill();

        return c;
      }
      var ctx = document.querySelector("canvas").getContext("2d");

      document.querySelector("canvas").width = 1400;
      document.querySelector("canvas").height = 1400;
      ctx.fillStyle = ctx.createPattern(createImgCanvas(), "repeat");
      ctx.fillRect(0, 0, 1400, 1400);

案例:绘制圆角矩形

      /*
      	把圆分为4份,顺时针顺序绘制 
      	Math.PI / 2 半圆分1为2
      	Math.PI 一个圆中的一半
      	Math.PI*3/2 || Math.PI*1.5  1个半圆加一个1分为2的半圆
      	Math.PI*2 完整的圆 
      */

var ctx = document.querySelector("canvas").getContext("2d");
      ctx.beginPath();
      ctx.arc(400 - 50, 400 - 50, 50, 0, Math.PI / 2);
      ctx.lineTo(50, 400);
      ctx.arc(50, 400 - 50, 50, Math.PI / 2, Math.PI);
      ctx.lineTo(0, 50);
      ctx.arc(50, 50, 50, Math.PI, (Math.PI * 3) / 2);
      ctx.lineTo(400 - 50, 0);
      ctx.arc(400 - 50, 50, 50, (Math.PI * 3) / 2, Math.PI * 2);
      ctx.closePath();
      ctx.stroke();
      
  //封装函数
  function PathRoundRect(ctx, width, height, r) 
      {
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();
      }
  //升级版
  function PathRoundRect(ctx, width, height, r,optionColor,optionStyle)
      {
        if(r*2>width||r*2>height)return;
        if(optionStyle)
        {
        optionStyle.stroke === true ? (optionColor.stroke ? (ctx.strokeStyle =optionColor.stroke ):null) : null;
        optionStyle.fill === true ?(optionColor.fill ? (ctx.fillStyle =optionColor.fill):null) : null;
        }
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();
      }
   //最终版
    function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
        var flagfill,flagstroke;
        if (r*2 > width || r*2 > height) return;
        if (optionStyle) {
          optionStyle.stroke === true
            ? optionColor.stroke
              ? (ctx.strokeStyle = optionColor.stroke)
              : null
            : null;
          optionStyle.fill === true
            ? optionColor.fill
              ? (ctx.fillStyle = optionColor.fill)
              : null
            : null;
          flagfill = optionColor.fill ?true:false;
          flagstroke = optionColor.stroke ?true:false;
        }
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();

        flagstroke ? ctx.stroke() : null;
        flagfill ? ctx.fill() : null;
      }

案例:2048九宫格

var ctx = document.querySelector("canvas").getContext("2d");
     ctx.translate(800/4,800/4)
     RoundRect(
       ctx,
       480,
       470,
       10,
       { fill: "red", stroke: "green" },
       { fill: true, stroke: true }
     );
     for (var i = 0; i < 4; i++) {
       ctx.save();
       ctx.translate(10, i * 15);
       for (var j = 0; j < 4; j++) {
         ctx.save();
         ctx.translate(j * 120, i * 100 +15);
         RoundRect(
           ctx,
           100,
           100,
           10,
           { fill: "green", stroke: "green" },
           { fill: true, stroke: true }
         );
         ctx.restore();
       }
       ctx.restore();
     }

     function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
       var flagfill, flagstroke;
       if (r > width || r > height) return;
       if (optionStyle) {
         optionStyle.stroke === true
           ? optionColor.stroke
             ? (ctx.strokeStyle = optionColor.stroke)
             : null
           : null;
         optionStyle.fill === true
           ? optionColor.fill
             ? (ctx.fillStyle = optionColor.fill)
             : null
           : null;
         flagfill = optionColor.fill ? true : false;
         flagstroke = optionColor.stroke ? true : false;
       }
       ctx.beginPath();
       ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
       ctx.lineTo(r, height);
       ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
       ctx.lineTo(0, r);
       ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
       ctx.lineTo(width - r, 0);
       ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
       ctx.closePath();

       flagstroke ? ctx.stroke() : null;
       flagfill ? ctx.fill() : null;
     }

案例:绘制弯月

pathMoon(ctx, 2, 300, 300, 200);
     function pathMoon(ctx, d, x, y, r, deg, color) {
       ctx.save();
       ctx.translate(x, y);
       ctx.scale(r, r);
       ctx.rotate(deg || 0);
       ctx.beginPath();
       Moon(d, ctx);
       ctx.fillStyle = color ? color : "yellow";
       ctx.fill();
       ctx.closePath();
       ctx.restore();
       function Moon(d, ctx) {
         ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
         ctx.moveTo(0, -1);
         ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
       }
       function dis(x1, y1, x2, y2) {
         return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
       }
     }

贝塞尔曲线

贝塞尔曲线相关函数:

quadraticCurveTo(x1,y1,x2,y2):二次贝塞尔曲线 一个控制点 1

bezierCurveTo(x1,y1,x2,y2,x3,y3):三次贝塞尔曲线 两个控制点 1 2

//起始点不由函数来定,可以用moveTo等画路径的函数来定

//二次贝塞尔曲线
		ctx.moveTo(0, 0);
          ctx.quadraticCurveTo(800,400,400,800)
          ctx.stroke()
          
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
   

      var ctx = document.querySelector("canvas").getContext("2d");

      document.querySelector("canvas").width = document.body.clientWidth;
      document.querySelector("canvas").height = document.body.clientHeight;
        ctx.save();
        var grd = ctx.createLinearGradient(0,0,0,document.querySelector("canvas").height);
        grd.addColorStop(0,"black");
        grd.addColorStop(1,"#035");
        ctx.fillStyle = grd;
        ctx.fillRect(0,0,document.querySelector("canvas").width,document.querySelector("canvas").height);
        ctx.restore();
      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele,200);
      end(ele);
      pathMoon(ctx, 2, document.querySelector("canvas").width*0.85, document.querySelector("canvas").height/4,80,0,"#fc1");
      RectLoda(ctx);





      function RectLoda(ctx)
      {
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(0,document.querySelector("canvas").height*0.65);
       
//三次贝塞尔曲线应用       ctx.bezierCurveTo(document.querySelector("canvas").width/2,650,document.querySelector("canvas").width/2,document.querySelector("canvas").height/3,document.querySelector("canvas").width,document.querySelector("canvas").height-200);
        ctx.lineTo(document.querySelector("canvas").width,document.querySelector("canvas").height)
        ctx.lineTo(0,document.querySelector("canvas").height)
       
       
       var bgcolor = ctx.createLinearGradient(0,document.querySelector("canvas").height,0,0);
        bgcolor.addColorStop(0,"#030");
        bgcolor.addColorStop(1,"#580");
        ctx.fillStyle = bgcolor;
        ctx.fill();
        ctx.closePath();
        ctx.restore();
      }
      function pathMoon(ctx, d, x, y, r, deg, color) {
        ctx.save();
        ctx.translate(x, y);
        ctx.scale(r, r);
        ctx.rotate(deg || 0);
        ctx.beginPath();
        Moon(d, ctx);
        ctx.fillStyle = color ? color : "yellow";
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        function Moon(d, ctx) {
          ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
          ctx.moveTo(0, -1);
          ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
        }
        function dis(x1, y1, x2, y2) {
          return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
      }

      function start(arr,num) {
        for (var i = 0; i < num; i++) {
          var flag = true,
            ran = Math.random() * 10 + 5,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              (Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
                ran) *
              0.65,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
            if(x>document.querySelector("canvas").width*0.85&&x<document.querySelector("canvas").width*0.85+80*1.15)
            {
              flag = false;
              
            }
           
          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          ctx.save();
          ctx.beginPath();
          ctx.translate(arr[i][1], arr[i][2]);
          ctx.rotate(arr[i][3]);
          ctx.scale(0.7, 0.7);
          DrawStart(ctx, arr[i][0]);
          ctx.fill();
          ctx.stroke();
          ctx.closePath();
          ctx.restore();
        }
      }

      function DrawStart(ctx, r) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        for (var i = 0; i <= 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i) / 180) * Math.PI) * r,
            -Math.sin(((18 + 72 * i) / 180) * Math.PI) * r
          );
          ctx.lineTo(
            (Math.cos(((54 + 72 * i) / 180) * Math.PI) * r) / 2,
            (-Math.sin(((54 + 72 * i) / 180) * Math.PI) * r) / 2
          );
        }
      }
    </script>
  </body>
</html>

字体

字体绘制相关函数:

font:设置字体样式属性 五个参数依次是font-style(italic oblique)、font-variant(small-caps)、font-weight(bold lighter bolder)、font-size、font-family

fillText(string,x,y,length):绘制带填充字体

strokeText(string,x,y,length):绘制带边框的字体

textAlign:设置字体水平对齐 参数有:right center left

textBaseline:设置字体垂直对齐 参数有:top middle bottom alphabetic(defalut) ideographic hanging

measureText(String).width:获取文本宽度(会根据font设置的字体、字号来决定)

语法格式:

var ctx = document.querySelector(".canvas").getContext("2d");
   var grd = ctx.createLinearGradient(0,0,800,0);
   grd.addColorStop(0,"red");
   grd.addColorStop(0.5,"yellow");
   grd.addColorStop(1,"green");
   ctx.fillStyle = grd;
   ctx.font = "bold 40px 微软雅黑 ";
   ctx.fillText("How are you!",100,100,300);
   //字体可以填充渐变色、图形纹理、另一个画布
   
 ===================================================================
 //只带边框的字体
  var ctx = document.querySelector(".canvas").getContext("2d");
   var grd = ctx.createLinearGradient(0,0,800,0);
   grd.addColorStop(0,"red");
   grd.addColorStop(0.5,"yellow");
   grd.addColorStop(1,"green");
   ctx.lineWidth =2;
   ctx.strokeStyle = grd;
   ctx.font = "bold 40px 微软雅黑 ";
   ctx.strokeText("How are you!",100,100,300);
   ===============================================
  //带纹理的字体
   var ctx = document.querySelector(".canvas").getContext("2d");
     // var grd = ctx.createLinearGradient(0,0,800,0);
     // grd.addColorStop(0,"red");
     // grd.addColorStop(0.5,"yellow");
     // grd.addColorStop(1,"green");
     
     var img = new Image();
     img.src = "../newIMg.png";
     img.onload = function() {
       var pattern = ctx.createPattern(img, "repeat");
       ctx.fillStyle = pattern;
       ctx.strokeStyle = "red";
       ctx.lineWidth =1;
       ctx.font = "bold 40px 微软雅黑 ";
       ctx.strokeText("How are you!", 100, 100, 300);
       ctx.fillText("How are you!", 100, 100, 300);
     };

水平对齐效果:

垂直对齐效果:

案例:水平垂直居中

var ctx = document.querySelector(".canvas").getContext("2d");
     ctx.fillStyle = "red";
     ctx.strokeStyle = "red";
     ctx.moveTo(400, 0);
     ctx.lineTo(400, 800);
     ctx.moveTo(0, 400);
     ctx.lineTo(800, 400);
     ctx.stroke();

     ctx.textAlign = "center";
     ctx.textBaseline = "middle";
     ctx.font = "bold 100px 微软雅黑 ";
     ctx.strokeText("How are you!", 400, 400);

阴影

阴影相关属性:

shadowColor:设置阴影颜色

shadowOffsetX:设置阴影X偏移

shadowOffsetY:设置阴影Y偏移

shadowBlur:设置阴影模糊扩散程度

语法格式:

var ctx = document.querySelector("canvas").getContext("2d");
    ctx.shadowColor = "black";
   ctx.fillStyle = "red"
    var num = 0;
    var flag = true;
    setInterval(function() {
      ctx.shadowOffsetX = -20+num;
    ctx.shadowOffsetY = -20+num;
      num == 100 ? (flag = false) : num == 0 ? (flag = true) : null;
      flag ? num++ : num--;
      ctx.shadowBlur = num;
      ctx.clearRect(0, 0, 800, 800);
      ctx.fillRect(100, 100, 400, 400);
    }, 50);

透明

透明相关函数:

在canvas中要实现透明,可以使用rgba颜色,也可以使用以下方法

globalAlpha:设置透明度 范围(1-0) 全局透明

语法格式:

var ctx = document.querySelector("canvas").getContext("2d");
    var color = ["red","green","yellow","blue","black"]
   for(var i=0;i<200;i++)
   {
     var randomX = Math.random()*800;
     var randomY = Math.random()*800;
     var randomR = Math.random()*30;
    var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);
     ctx.save();
     ctx.beginPath();
     ctx.globalAlpha = 0.7;
     ctx.fillStyle = `rgb(${R},${G},${B})`;
     ctx.arc(randomX,randomY,randomR,0,Math.PI*2);
     ctx.fill();
     ctx.closePath();
     ctx.restore();
   }

遮盖顺序

xx.globalCompositeOperation = “source-over” (默认,后绘制的图形会压在先绘制的图形上) / “destination-over”(先绘制的图形压在后绘制的图形上)

相关属性:

globalCompositeOperation :改变元素显示效果与遮盖顺序

各个参数的实现效果可以参考菜鸟,或有canvas手册的网址,或以下链接

https://blog.csdn.net/fe_dev/article/details/81985367

此链接,有水滴扩散、刮刮卡案例参考

参数:

语法格式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var color = ["red","green","yellow","blue","black"]
      var Balls = [];
     for(var i=0;i<200;i++)
     {
      var randomR = Math.random()*30+10;
       var randomX = Math.random()*(800-randomR*2)+randomR;
       var randomY = Math.random()*(800-randomR*2)+randomR;
      var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);
   
        let balls ={
          x:randomX,
          y:randomY,
          r:randomR,
          color:`rgb(${R},${G},${B})`,
          vx:(Math.random()*5+5)*(Math.pow(-1,Math.floor(Math.random()*100))),
          vy:(Math.random()*5+5)*(Math.pow(-1,Math.floor(Math.random()*100))),
        }
      Balls.push(balls);
     }

     setInterval(()=>{
       draw(ctx)
     },50)

     function draw(ctx)
     {
       ctx.clearRect(0,0,800,800)
       for(let i=0;i<Balls.length;i++)
       {
       ctx.save();
       ctx.beginPath();
      ctx.globalCompositeOperation = "xor";
       ctx.fillStyle = Balls[i].color;
       ctx.arc(Balls[i].x,Balls[i].y,Balls[i].r,0,Math.PI*2);
       ctx.fill();
       ctx.closePath();
       ctx.restore();
       Balls[i].x+=Balls[i].vx;
       Balls[i].y+=Balls[i].vy;
       if(Balls[i].x-Balls[i].r<=0)
       {
         Balls[i].vx = -Balls[i].vx;
          Balls[i].x = Balls[i].r;
       }
       if(Balls[i].x+Balls[i].r >= 800)
       {
         Balls[i].vx = -Balls[i].vx;
         Balls[i].x = 800-Balls[i].r;
       }
       if(Balls[i].y-Balls[i].r<=0)
       {
         Balls[i].vy = -Balls[i].vy;
         Balls[i].y = Balls[i].r;
       }
       if(Balls[i].y+Balls[i].r>=800)
       {
         Balls[i].vy = -Balls[i].vy;
         Balls[i].y = 800-Balls[i].r;
       }
       }
     }
 
    </script>
  </body>
</html>

剪切

相关函数:

clip:相对于上个填充路径做剪切效果

语法格式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var r = 150;
      ctx.fillStyle = "black";
      ctx.fillRect(0, 0, 800, 800);
      ctx.canvas.onmousemove = e => {
        ctx.clearRect(0, 0, 800, 800);
        ctx.beginPath();
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, 800, 800);
        ctx.closePath();

        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = "rgba(255,255,255,1)";
        var x = e.pageX - r <= 0 ? r : e.pageX;
        var y = e.pageY - r <= 0 ? r : e.pageY;
        x = e.pageX + r > 800 ? 800 - r : x;
        y = e.pageY + r > 800 ? 800 - r : y;
        ctx.arc(x, y, r, 0, Math.PI * 2);
        ctx.fill();
        ctx.clip();
        ctx.closePath();

        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.font = "200px bold 微软雅黑";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText("Canvas", 400, 400);
        ctx.closePath();
        ctx.restore();
        document.onkeyup = ev => {
          ev.keyCode === 38 ? (r += 20) : null;
          ev.keyCode === 40 ? (r -= 20) : null;
          if (r >= 390) r = 390;
          ctx.canvas.onmousemove(e);
          return false;
        };
      };
      ctx.canvas.onmouseout = () => {
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, 800, 800);
        document.onkeyup = null;
      };
    </script>
  </body>
</html>

实现剪纸效果

剪纸效果参考非零环绕原侧,自动识别里、外、面,一个面不同时出现顺时针和逆时针就填充,如果同时出现顺时针和逆时针就不填充,这也就说明了图形的绘制方向,会影响其是否填充

语法格式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.beginPath();
      ctx.rect(200, 200, 400, 200);
      drawRect(ctx, 220, 220, 100, 100);
      ctx.arc(400, 270, 50, Math.PI * 2, 0, true);
      Triangle(ctx, 510, 220, 460, 320, 560, 320);
      ctx.closePath();
      ctx.fillStyle = "red";
      ctx.shadowColor = "black";
      ctx.shadowOffsetX = 10;
      ctx.shadowOffsetY = 10;
      ctx.fill();
      function drawRect(ctx, x, y, w, h) {
        ctx.moveTo(x, y);
        ctx.lineTo(x, y + h);
        ctx.lineTo(x + w, y + h);
        ctx.lineTo(x + w, y);
        ctx.lineTo(x, y);
      }
      function Triangle(ctx, x1, y1, x2, y2, x3, y3) {
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.lineTo(x3, y3);
        ctx.lineTo(x1, y1);
      }
    </script>
  </body>
</html>

交互

canvas交互相关函数:

isPointInPath(x,y):检测指定的坐标是否在绘制元素内,只能判断最后一个绘制的封闭路径

语法格式:


//点击填充颜色
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var Balls = [];
      for (var i = 0; i < 10; i++) {
        ctx.beginPath();
        Balls.push({
          x: Math.random() * 800,
          y: Math.random() * 800,
          r: Math.random() * 100
        });
      }
      Draw(ctx);
      function Draw(ctx) {
        for (let i = 0; i < Balls.length; i++) {
          ctx.beginPath();
          ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
          ctx.stroke();
        }

        ctx.canvas.addEventListener("click", function(event) {
          for (let i = 0; i < Balls.length; i++) {
            ctx.beginPath();
            ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
            if (ctx.isPointInPath(event.pageX, event.pageY)) {
              ctx.fillStyle = "yellow";
              ctx.fill();
            }
          }
        });
      }
    </script>
  </body>
</html>


//鼠标滑入填充颜色,滑出清空颜色


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var Balls = [];
      for (var i = 0; i < 10; i++) {
        ctx.beginPath();
        Balls.push({
          x: Math.random() * 800,
          y: Math.random() * 800,
          r: Math.random() * 100
        });
      }
      Draw(ctx);
      function Draw(ctx) {
        for (let i = 0; i < Balls.length; i++) {
          ctx.beginPath();
          ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
          ctx.stroke();
        }

        ctx.canvas.addEventListener("mousemove", function(event) {
          ctx.clearRect(0, 0, 800, 800);
          for (let i = 0; i < Balls.length; i++) {
            ctx.beginPath();
            ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
            if (ctx.isPointInPath(event.pageX, event.pageY)) {
              ctx.fillStyle =
                "rgb(" +
                Math.random() * 255 +
                "," +
                Math.random() * 255 +
                "," +
                Math.random() * 255 +
                ")";
              ctx.fill();
            } else ctx.stroke();
          }
        });
      }
    </script>
  </body>
</html>

案例:小球滚动(面向对象+控制面板)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
      .canvasBox {
        width: 800px;
        height: 800px;
        position: relative;
      }
      .canvasBox > .SetupPanel {
        width: 300px;
        height: 200px;
        background: #99b4e487;
        border-radius: 30px;
        position: absolute;
        left: 0;
        top: 0;
        color: white;
      }
      .canvasBox > .SetupPanel > h1 {
        text-align: center;
        line-height: 25px;
      }
      .canvasBox > .SetupPanel > a {
        float: left;
        color: #478aff87;
        background: #e5eeff;
        border-radius: 5px;
        padding: 10px 0;
        margin: 3px 0;
        text-decoration: none;
        text-align: center;
        line-height: 15px;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="canvasBox">
      <canvas class="canvas" width="800" height="800"></canvas>
      <div class="SetupPanel">
        <h1>控制面板</h1>
        <a href="javascript:void(0)">点击停止</a>
        <a href="javascript:void(0)">点击切换背景颜色</a>
        <a href="javascript:void(0)">点击切换覆盖模式</a>
      </div>
    </div>
    <script src="../node/jquery.js"></script>
    <script>
      class Animate {
        constructor(canvas) {
          this.canvas = document.querySelector(canvas);
          this.ctx = this.canvas.getContext("2d");
          this.initAttr();
          this.initDraw();
          this.initEvent();
        }
        initAttr() {
          this.color = ["red", "green", "yellow", "blue", "black"];
          this.bgcolor = null;
          this.Balls = [];
          this.flag = true;
          this.module = ["xor", "lighter", null];
          this.option = null;
          this.time = null;
        }
        initEvent() {
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[0].onclick = () => {
            if (this.flag) {
              clearInterval(this.time);
              this.flag = false;
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].innerHTML = "点击开始";
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].style.background = "red";
            } else {
              this.time = setInterval(() => {
                this.draw(this.bgcolor);
              }, 50);
              this.flag = true;
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].innerHTML = "点击停止";
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].style.background = "";
            }
          };
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[1].onclick = () => {
            this.bgcolor = this.color[
              parseInt(Math.random() * this.color.length - 1)
            ];
          };
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[2].onclick = () => {
            this.option = this.module[
              Math.ceil(Math.random() * this.module.length - 1)
            ];
          };
        }
        initDraw() {
          for (let i = 0; i < 200; i++) {
            let randomR = Math.random() * 30 + 10;
            let randomX = Math.random() * (800 - randomR * 2) + randomR;
            let randomY = Math.random() * (800 - randomR * 2) + randomR;
            let R = Math.floor(Math.random() * 255),
              G = Math.floor(Math.random() * 255),
              B = Math.floor(Math.random() * 255);

            let balls = {
              x: randomX,
              y: randomY,
              r: randomR,
              color: `rgb(${R},${G},${B})`,
              vx:
                (Math.random() * 5 + 5) *
                Math.pow(-1, Math.floor(Math.random() * 100)),
              vy:
                (Math.random() * 5 + 5) *
                Math.pow(-1, Math.floor(Math.random() * 100))
            };
            this.Balls.push(balls);
          }
        }
        draw(bgcolor) {
          this.ctx.clearRect(0, 0, 800, 800);

          this.bgDraw(bgcolor);
          for (let i = 0; i < this.Balls.length; i++) {
            this.ctx.save();
            this.ctx.beginPath();
            this.ctx.globalCompositeOperation = this.option;
            this.ctx.fillStyle = this.Balls[i].color;
            this.ctx.arc(
              this.Balls[i].x,
              this.Balls[i].y,
              this.Balls[i].r,
              0,
              Math.PI * 2
            );
            this.ctx.fill();
            this.ctx.closePath();
            this.ctx.restore();
            this.Balls[i].x += this.Balls[i].vx;
            this.Balls[i].y += this.Balls[i].vy;
            if (this.Balls[i].x - this.Balls[i].r <= 0) {
              this.Balls[i].vx = -this.Balls[i].vx;
              this.Balls[i].x = this.Balls[i].r;
            }
            if (this.Balls[i].x + this.Balls[i].r >= 800) {
              this.Balls[i].vx = -this.Balls[i].vx;
              this.Balls[i].x = 800 - this.Balls[i].r;
            }
            if (this.Balls[i].y - this.Balls[i].r <= 0) {
              this.Balls[i].vy = -this.Balls[i].vy;
              this.Balls[i].y = this.Balls[i].r;
            }
            if (this.Balls[i].y + this.Balls[i].r >= 800) {
              this.Balls[i].vy = -this.Balls[i].vy;
              this.Balls[i].y = 800 - this.Balls[i].r;
            }
          }
        }
        bgDraw(bgcolor) {
          this.ctx.beginPath();
          this.ctx.fillStyle = bgcolor;
          this.ctx.fillRect(0, 0, 800, 800);
          this.ctx.closePath();
        }
      }

      //初始化对象
      let animate = new Animate("canvas");
      var ctx = animate.ctx;
      //开始执行动画
      animate.time = setInterval(() => {
        animate.draw(animate.bgcolor);
      }, 50);
    </script>
  </body>
</html>

清除

清除也称重绘,在动画应用当中是不可分割的,动画是一帧一帧的播放,中间少不了清除的步骤,否则将达不到动画的播放帧数标准

清除画布相关函数:

clearRect(startX,startY,endX,endY):清除参数指定范围内绘制的元素

语法格式:

ctx.clearRect(0,0,canvas.width,canvas.height);

扩充Canvas 2d方法

在有些时候,我们自定义的函数,不能像canvas自带的函数一样,不用传入绘制上下午对象,而我们自定义的必须把绘制对象传入函数里才可以使用,那么有没有方法可以解决呢,在canvas实例对象的原型上添加方法即可

语法格式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
      .canvasBox {
        width: 800px;
        height: 800px;
        position: relative;
      }
      .canvasBox > .SetupPanel {
        width: 300px;
        height: 200px;
        background: #99b4e487;
        border-radius: 30px;
        position: absolute;
        left: 0;
        top: 0;
        color: white;
      }
      .canvasBox > .SetupPanel > h1 {
        text-align: center;
        line-height: 25px;
      }
      .canvasBox > .SetupPanel > a {
        float: left;
        color: #478aff87;
        background: #e5eeff;
        border-radius: 5px;
        padding: 10px 0;
        margin: 3px 0;
        text-decoration: none;
        text-align: center;
        line-height: 15px;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="canvasBox">
      <canvas class="canvas" width="800" height="800"></canvas>
    </div>
    <script src="../node/jquery.js"></script>
    <script>
      let ctx = document.querySelector(".canvas").getContext("2d");
      ctx.__proto__.fillStar = function(r)  
      
      //ctx.__proto__ === CanvasRenderingContext2D.prototype
      
      {
          this.beginPath();
        for(let i=0;i<=5;i++)
        {
          this.lineTo(
            Math.cos((18+i*72)/180*Math.PI)*r+this.lastMoveTo.x,
            -Math.sin((18+i*72)/180*Math.PI)*r+this.lastMoveTo.y
          );
          this.lineTo(
            Math.cos((54+i*72)/180*Math.PI)*r/2+this.lastMoveTo.x,
            -Math.sin((54+i*72)/180*Math.PI)*r/2+this.lastMoveTo.y
          );
        }
          this.closePath();
          this.fill();
      }
      ctx.lastMoveTo = {};
      CanvasRenderingContext2D.prototype.oldMoveTo = CanvasRenderingContext2D.prototype.moveTo;
      CanvasRenderingContext2D.prototype.moveTo = function(x,y)
      {
        this.oldMoveTo(x,y);
        this.lastMoveTo.x = x;
        this.lastMoveTo.y = y;
      }
      ctx.moveTo(400,400)
      ctx.fillStar(100);
    </script>
  </body>
</html>

图像处理

图像不同于图形,图像是位图是由无数个彩色像素点组成,图形是点线面结合而成,两者的处理方式也不相同,所干涉的区域也不相同

图形处理相关函数:

drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh) :导入指定图片到canvas当中。 九个参数 首个是图片资源,s开头的是原图像的参数,d开头的是指在canvas绘制的参数

语法格式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas
      class="canvas"
      width="800"
      height="800"
      style="border:1px solid blue"
    ></canvas>
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      img.src = "../PHP操作MySQL.png";
      img.onload = () => {
        ctx.drawImage(img, 740, 450, 260, 70, 0, 0, 800, 800);
      };
    </script>
  </body>
</html>

案例:图像放大

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }

input[type=range] {
    -webkit-appearance: none;
    width: 300px;
    border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
    margin-top: 10px;
}
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
} 

input[type=range]::-webkit-slider-runnable-track {
    height: 10px;
    border-radius: 10px; /*将轨道设为圆角的*/
    box-shadow: 0 1px 1px #def3f8, inset 0 .125em .125em #0d1112; /*轨道内置阴影效果*/
}
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 25px;
    width: 25px;
    margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
    background: #ffffff; 
    border-radius: 50%; /*外观设置为圆形*/
    border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
    box-shadow: 0 .125em .125em #3b4547; /*添加底部阴影*/
}

    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>
    <input
      type="range"
      style="display:block;width:100%;"
      max="3.0"
      min="0.5"
      step="0.1"
      value="1"
      class="scale"
    />
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      var scale = document.querySelector(".scale");
      img.src = "../1.jpg";
      img.onload = () => {
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        drawImageByScale(ctx, scale.value, img.width, img.height);

        // scale.onchange = function() {
        //   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        //   drawImageByScale(ctx, scale.value, img.width, img.height);
        // };
        scale.onmousemove = function() {
          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
          drawImageByScale(ctx, scale.value, img.width, img.height);
        };
      };

      function drawImageByScale(ctx, scale, w, h) {
        var imageWidth = w * scale;
        var imageHeight = h * scale;

        let x = ctx.canvas.width / 2 - imageWidth / 2,
          y = ctx.canvas.height / 2 - imageHeight / 2;
        ctx.drawImage(img, x, y, imageWidth, imageHeight);
      }
    </script>
  </body>
</html>
//水印版
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }
      .bottom {
        width: 100%;
        position: fixed;
        bottom: 30px;
      }
      input[type="range"] {
        -webkit-appearance: none;
        width: 300px;
        border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
        margin-top: 10px;
        position: relative;
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
      }

      input[type="range"]::-webkit-slider-runnable-track {
        height: 10px;
        border-radius: 10px; /*将轨道设为圆角的*/
        box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        height: 25px;
        width: 25px;
        margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
        background: #ffffff;
        border-radius: 50%; /*外观设置为圆形*/
        border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
        box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>
    <div class="bottom">
      <input
        type="range"
        style="display:block;width:100%;"
        max="3.0"
        min="0.5"
        step="0.1"
        value="1"
        class="scale"
      />
    </div>
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      var scale = document.querySelector(".scale");
      img.src = "./img.jpg";
      var shuiying = document.createElement("canvas").getContext("2d");
      shuiying.canvas.width = 400;
      shuiying.canvas.height = 100;
      shuiying.font = "bold 50px 微软雅黑";
      shuiying.fillStyle = "white";
      shuiying.textAlign = "center";
      shuiying.textBaseline = "middle";
      shuiying.fillText("xuyuxin", 200, 50, 400);
      img.onload = () => {
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        drawImageByScale(ctx, scale.value, img.width, img.height,shuiying);

        // scale.onchange = function() {
        //   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        //   drawImageByScale(ctx, scale.value, img.width, img.height);
        // };
        scale.onmousemove = function() {
          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

          drawImageByScale(ctx, scale.value, img.width, img.height, shuiying);
        };
      };

      function drawImageByScale(ctx, scale, w, h, c) {
        var imageWidth = w * scale;
        var imageHeight = h * scale;

        let x = ctx.canvas.width / 2 - imageWidth / 2,
          y = ctx.canvas.height / 2 - imageHeight / 2;

        ctx.drawImage(img, x, y, imageWidth, imageHeight);
        if(scale>=1)
        {
        ctxdrawImage(c.canvas, -40, ctx.canvas.height - 100);
        }
        else
        {
        ctx.drawImage(c.canvas, x, imageHeight-50);
        }
      }
    </script>
  </body>
</html>

案例:放大镜

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }
      .bottom {
        width: 100%;
        position: fixed;
        bottom: 30px;
      }
      input[type="range"] {
        -webkit-appearance: none;
        width: 300px;
        border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
        margin-top: 10px;
        position: relative;
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
      }

      input[type="range"]::-webkit-slider-runnable-track {
        height: 10px;
        border-radius: 10px; /*将轨道设为圆角的*/
        box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        height: 25px;
        width: 25px;
        margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
        background: #ffffff;
        border-radius: 50%; /*外观设置为圆形*/
        border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
        box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>

    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var offsetCanvas = document.createElement("canvas").getContext("2d");
      var img = new Image();
      var scale;
      img.src = "./img-lg.jpg";

      img.onload = () => {
        ctx.canvas.width = 1152;
        ctx.canvas.height = 768;

        offsetCanvas.canvas.width = img.width;
        offsetCanvas.canvas.height = img.height;

        scale = offsetCanvas.canvas.width / ctx.canvas.width;
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
        offsetCanvas.drawImage(img, 0, 0);
      };

      ctx.canvas.onmousedown = function(e) {
        var x = e.clientX - this.getBoundingClientRect().left,
            y = e.clientY - this.getBoundingClientRect().top;
          Draw(ctx, true, x, y);

        this.onmousemove = e => {
          var x = e.clientX - this.getBoundingClientRect().left,
            y = e.clientY - this.getBoundingClientRect().top;
          Draw(ctx, true, x, y);
        };
        this.onmouseup = () => {
          ctx.canvas.onmousemove = null;
          Draw(ctx, false);
        };
        this.onmouseout = () => {
          ctx.canvas.onmousemove = null;
          Draw(ctx, false);
        };
      };
      function Draw(ctx, flag, x, y) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
        if (flag) {
          drawImageRect(ctx, x, y);
        }
      }

      function drawImageRect(ctx, x, y) {
        var imageLgX = x * scale,
          imageLgY = y * scale;

        var r = 200;

        var sx = imageLgX - r,
          sy = imageLgY - r;

        var dx = x - r,
          dy = y - r;

        ctx.save();
        ctx.beginPath();
        ctx.arc(x,y,r,0,Math.PI*2);
        ctx.stroke();
        ctx.clip()
        ctx.drawImage(offsetCanvas.canvas, sx, sy, r * 2, r * 2, dx, dy, r * 2, r * 2);
        ctx.closePath();
        ctx.restore();
      }
    </script>
  </body>
</html>

像素处理

相关函数:

getImageData(x,y,w,h):获取指定图像像素数据 返回一个对象,里面有 data像素数据

putImageData(img,dx,dy,dirtx,dirty,dirtw,dirth):输出处理后的图像到指定位置

createImageData(w,h):创建一个空的图像

像素处理算法:

语法格式:

//像素自动变紫
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;float:left"
      width="500"
      height="500"
    ></canvas>
    <canvas
      class="canvas"
      style="border:1px solid blue;float:right"
      width="500"
      height="500"
    ></canvas>
    <div class="btnbox" style="display: block;">
      <a href="javascript:void(0)" onclick="fillter()">fillter</a>
    </div>
    <script>
      var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
      var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
var n =0;
      var imageData;
      var data;
      var img = new Image();
      img.src = "./img.jpg";
      img.onload = function() {
        ctx1.drawImage(img, 0, 0, 500, 500);
      };
      function fillter() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;
        
        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          data[4 * i + 0] += n;
          // data[4 * i + 1] += n;
          data[4 * i + 2] += n;
          // data[4 * i + 3] = Math.ceil(Math.random()*255);
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      setInterval(function(){
        n++;
        if(n===255)
        {
          n=Math.ceil(Math.random()*255)
        }
        fillter(n);
      },1);
    </script>
  </body>
</html>

案例:像素滤镜

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
      .btnbox > a {
        float: left;
        margin: 10px 20px;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" style="float:left" width="500" height="500"></canvas>
    <canvas
      class="canvas"
      style="float:right"
      width="500"
      height="500"
    ></canvas>
    <div class="btnbox" style="display: block;">
      <a href="javascript:void(0)" onclick="grey()">灰度 Grey Effect</a>
      <a href="javascript:void(0)" onclick="black()">黑白 black&white Effect</a>
      <a href="javascript:void(0)" onclick="revers()">反色 revers Effect</a>
      <a href="javascript:void(0)" onclick="Blur()">模糊 blur Effect</a>
      <a href="javascript:void(0)" onclick="mosaice()">马赛克 mosaice Effect</a>
    </div>
    <script>
      var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
      var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
      var imageData;
      var data;
      var img = new Image();
      img.src = "../1.jpg";
      img.onload = function() {
        ctx1.drawImage(img, 0, 0, 500, 500);
      };
      function mosaice() {
        var imgData = ctx1.getImageData(0, 0, 500, 500);
        var data = imgData.data;
        var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
        var tmpData = tmpimgData.data;
        var size = 16,
          totalnum = Math.pow(size, 2);
        for (var i = 0; i < ctx2.canvas.height; i += size) {
          for (var j = 0; j < ctx2.canvas.width; j += size) {
            var totalr = 0,
              totalg = 0,
              totalb = 0;
            for (var dx = 0; dx < size; dx++) {
              for (var dy = 0; dy < size; dy++) {
                let x = i + dx,
                  y = j + dy;
                let p = x * ctx2.canvas.width + y;
                totalr += tmpData[p * 4 + 0];
                totalg += tmpData[p * 4 + 1];
                totalb += tmpData[p * 4 + 2];
              }
            }
            var p = i * ctx2.canvas.width + j;
            var resr = totalr / totalnum;
            var resg = totalg / totalnum;
            var resb = totalb / totalnum;
            for (var dx = 0; dx < size; dx++) {
              for (var dy = 0; dy < size; dy++) {
                var x = dx + i,
                  y = dy + j;
                var p = x * ctx2.canvas.width + y;
                data[4 * p + 0] = resr;
                data[4 * p + 1] = resg;
                data[4 * p + 2] = resb;
              }
            }
          }
        }
        ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
      }
      function revers() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = 255 - data[4 * i + 0],
            g = 255 - data[4 * i + 1],
            b = 255 - data[4 * i + 2];
          data[4 * i + 0] = r;
          data[4 * i + 1] = g;
          data[4 * i + 2] = b;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      function Blur() {
        var imgData = ctx1.getImageData(0, 0, 500, 500);
        var data = imgData.data;
        var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
        var tmpData = tmpimgData.data;
        var blurR = 2,
          totalnum = Math.pow(2 * blurR + 1, 2);
        for (var i = blurR; i < ctx2.canvas.height - blurR; i++) {
          for (var j = blurR; j < ctx2.canvas.width - blurR; j++) {
            var totalr = 0,
              totalg = 0,
              totalb = 0;
            for (var dx = -blurR; dx <= blurR; dx++) {
              for (var dy = -blurR; dy <= blurR; dy++) {
                let x = i + dx,
                  y = j + dy;
                let p = x * ctx2.canvas.width + y;
                totalr += tmpData[p * 4 + 0];
                totalg += tmpData[p * 4 + 1];
                totalb += tmpData[p * 4 + 2];
              }
            }
            var p = i * ctx2.canvas.width + j;
            data[p * 4 + 0] = totalr / totalnum;
            data[p * 4 + 1] = totalg / totalnum;
            data[p * 4 + 2] = totalb / totalnum;
          }
        }
        ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
      }
      function grey() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = data[4 * i + 0],
            g = data[4 * i + 1],
            b = data[4 * i + 2];
          let grey = r * 0.3 + g * 0.59 + b * 0.11;
          data[4 * i + 0] = grey;
          data[4 * i + 1] = grey;
          data[4 * i + 2] = grey;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      function black() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = data[4 * i + 0],
            g = data[4 * i + 1],
            b = data[4 * i + 2];
          let grey = r * 0.3 + g * 0.59 + b * 0.11;
          if (grey > 255 / 2) {
            v = 255;
          } else {
            v = 0;
          }
          data[4 * i + 0] = v;
          data[4 * i + 1] = v;
          data[4 * i + 2] = v;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
    </script>
  </body>
</html>

案例:颜色板

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
      .btnbox > a {
        float: left;
        margin: 10px 20px;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" style="float:left" width="800" height="800"></canvas>

    <div class="btnbox" style="display: block;"></div>
    <script>
      var ctx = document.querySelectorAll(".canvas")[0].getContext("2d");
      var img = ctx.createImageData(800, 800);
      var data = img.data;
      for (var i = 0; i < ctx.canvas.height; i++) {
        for (var j = 0; j < ctx.canvas.width; j++) {
          var p = i * ctx.canvas.width + j;
          data[4 * p + 0] = parseInt(
            Math.pow(Math.cos(Math.atan2(j - 400, i - 400) / 2), 2) * 255
          );
          data[4 * p + 1] = parseInt(
            Math.pow(
              Math.cos(
                Math.atan2(j - 400, i - 400) / 2 - (2 * Math.acos(-1)) / 3
              ),
              2
            ) * 255
          );
          data[4 * p + 2] = parseInt(
            Math.pow(
              Math.cos(
                Math.atan2(j - 400, i - 400) / 2 + (2 * Math.acos(-1)) / 3
              ),
              2
            ) * 255
          );
          data[4 * p + 3] = 255;
        }
      }
      ctx.putImageData(img, 0, 0, 0, 0, 800, 800);
    </script>
  </body>
</html>

文章作者: Jing Hong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jing Hong !
评论
 上一篇
Node Node
Nodejs编程 第0章 Node介绍0.0 回顾 JavaScript *历史及发展 * 1995年 网景公司的布兰登开发; 1997年7月,ECMA组织发布ECMAScript 1.0版; 2007年10月发布3.1版本后不久,ECMA
2019-10-11
下一篇 
HTML5 HTML5
一、H5 拖拽JS 里拖拽三事件, onmousedown onmousemove onmouseup 是实现交互性效果,根据鼠标的移动位置让标签元素联动 而 H5 拖拽也可以实现但更简单,实际例子: 百度图片识别,qq 邮箱文件提交,百度
2019-09-16
  目录