Canvas

Canvas

1.概述

Canvas是HTML5中非常重要的一个更新亮点,画布,替代Flash的!制作动画、制作游戏。渲染效率非常的高,浏览器不需要安装任何的插件就可以渲染这个动画。而Flash需要安装Flash Player这个插件才行。

Canvas适合动态图形绘制。小的动态效果也可以使用过渡或动画属性animation。

echarts图表使用Canvas绘制,https://echarts.apache.org/zh/index.html

1.1. Hello World

canvas是一个标签,有一个默认的宽高,此时注意,如果我们要设置宽度、高度,必须设置在HTML标签上面,而不能设置在CSS上。

注意:

  1. canvas本身布具有绘画功能, 只是一个画布标签, 但是H5提供给js的API具有绘画功能
2.  IE9一下不兼容
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="500" height="500">你的浏览器不支持canvas,请升级</canvas>
  <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    //绘制矩形路径
    ctx.rect(50, 50, 50, 50);//距离画布左上角50 50  宽高50 50,只是路径看不到效果
    //描边
    ctx.stroke();
    //填充
    // ctx.fill()
  </script>

2. 涉及的API

2.1 getContext()

get表示得到,context是上下文的意思。

canvas起初是空白的。为了展示,首先脚本需要找到渲染上下文,然后在它的上面绘制。<canvas> 元素有一个做 getContext() 的方法,这个方法是用来获得渲染上下文和它的绘画功能。getContext()只有一个参数,上下文的格式。

// 首先获取canvas 标签的dom对象
var mycanvas = document.querySelector("canvas");

// 获取上下文对象() 参数是2d绘图
var ctx = canvas.getContext('2d');

ctx对象,非常重要所有的绘制都是ctx的方法。canvas就是画布,功能就是生产画笔,

剩下所有的绘制都是有这支画笔ctx对象的属性来操作

//也就是说所有的绘制API都是ctx的事情,而不是canvas对象
ctx.fillStyle = "blue";
ctx.arc(300,300,100,0,Math.PI * 2,true);
ctx.fill();

2.2 绘制圆形 arc()

绘制圆形 arc(x,y,r,start, end, bol)

bol,是布尔值, 跟绘制圆弧有关

ctx.arc(300,300,100,0,Math.PI * 2,true);
<style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="500" height="500">你的浏览器不支持canvas,请升级</canvas>
  <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    console.log(ctx);
    //绘制一个圆
    ctx.arc(200, 200, 100, 0, Math.PI * 2, true);//绘制圆的路径,圆心位置 圆心位置 半径 起始为0 终止为Math.PI*2 顺时针绘制
    //描边后才可以看到边,之前只是路径
    ctx.strokeStyle = 'blue';//改变描边颜色
    ctx.stroke();
    //改变填充颜色,填充之前定义填充颜色
    ctx.fillStyle = 'red';
    ctx.fill()//填充
  </script>
2.3 绘制矩形 rect()

绘制矩形 rect(x,y,w,h)

ctx.rect(200, 200, 100, 100);
 <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    //绘制矩形路径
    ctx.rect(50, 50, 50, 50);//距离画布左上角50 50  宽高50 50,只是路径看不到效果
    //描边
    ctx.stroke();
    //填充
    // ctx.fill()
  </script>
2.4 stroke()笔触

绘制线条

ctx.stroke()
2.5 fill() 填充
ctx.fill()
2.6 可以合在一起写
  1. strokeRect(x,y,w,h)

  2. fillRect(x,y,w,h)

    参数:

    x,y 为起点的x,y坐标

    w,h 为要绘制矩形的宽高

注意没有strokeArc 和 fillArc 的写法

    ctx.strokeRect(100,100,200,100)//通过描边直接把矩形绘制出来
    ctx.fillRect(200,300,200,100)//填充的时候直接绘制一个矩形
2.7 清除 clearRect()

清除clearRect(x,y,w,h)

ctx.clearRect(250, 250, 30, 30);
ctx.clearRect(300,300,100,100)

清除在绘制有先后属性之分

3. 笔触和填充

Canvas中能够产生颜色的是两个东西,一个叫做笔触(也叫做描边),一个叫做填充。

3.1. 笔触(描边) strokeRect(x,y,w,h)

参数,x,y 左上角起点坐标,w,h为绘制矩形的宽高

3.1.1 笔触的使用:
//笔触
ctx.strokeRect(100,100,300,40);

你会发现只有描边没有填充色

而我们刚学的 fillRect() API绘制的矩形是有填充色的

3.1.2 设置笔触的颜色
// 设置笔触颜色
ctx.strokeStyle = 'red';
// ctx.strokeStyle = 'hsl(250,50%,50%)'
// 绘制笔触矩形
ctx.strokeRect(100,100,300,50);

此时你就会发现你绘制的是一个没有填充色,只有红色边框的矩形

3.1.3 绘制笔触的宽度
ctx.lineWidth = 20;   // 设置笔触的宽为20
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    console.log(ctx);
    //绘制一个圆
    ctx.arc(200, 200, 100, 0, Math.PI * 2, true);//绘制圆的路径,圆心位置 圆心位置 半径 起始为0 终止为Math.PI*2 顺时针绘制
    //描边后才可以看到边,之前只是路径
    ctx.strokeStyle = 'blue';//改变描边颜色
    ctx.lineWidth =20;
    ctx.stroke();

3.1.4 笔触绘制线段

划线之前你的先告诉浏览器怎么画

moveTo() 绘制开始位置 lineTo() 画笔移动的下一个位置

ctx.moveTo(100,100);    //将画笔移动到一个位置(先移动到开始点的位置)
ctx.lineTo(300,300);    //用画笔画,此时是抽象的一个线,没有显示在画布上(下一个点的位置)
ctx.stroke();           //划线(告诉浏览器,我说完了,你画吧)

我们可以多次使用lineTo:

告诉浏览器下一个点的位置,来绘制相邻点之间的线段

ctx.moveTo(100,100);    // 将画笔移动到一个位置
ctx.lineTo(300,300);    // 准备绘制从开始点到这个点的线,

ctx.lineTo(300,200);    // 准备绘制从上一个点到这个点的线,
ctx.lineTo(430,180);    // 准备绘制从上一个点到这个点的线,

ctx.stroke();           // 正式开始划线 
<body>
  <canvas id="canvas" width="500" height="500">你的浏览器不支持canvas,请升级</canvas>
  <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth = 20;//笔触宽度
    ctx.strokeStyle='red';
    //绘制线段
    //笔尖不在画布上moveTo
    ctx.moveTo(100, 100)
    //笔尖落在画布上lineTo绘制路径
    ctx.lineTo(200, 200)
    ctx.lineTo(200, 300)
    ctx.lineTo(400, 300)
    //笔触填充
    ctx.stroke()//绘制
  </script>
</body>
3.1.5 闭合路径

而且我们还可以使用closePath() ,来闭合路径

就是浏览器会自动的在开始点moveTo的点和最后一个lineTo的结束点之间绘制一条线

ctx.beginPath();        // 开始准备画线
ctx.moveTo(100,100);    // 将画笔移动到一个位置
ctx.lineTo(300,300);    // 准备绘制从开始点到这个点的线,
ctx.lineTo(300,200);    // 准备绘制从上一个点到这个点的线,
ctx.lineTo(430,180);    // 准备绘制从上一个点到这个点的线,

ctx.closePath();        // 闭合路径(加上就闭合了)

ctx.stroke();           // 正式开始划线 

绘制新的线段

<body>
  <canvas id="canvas" width="500" height="500">你的浏览器不支持canvas,请升级</canvas>
  <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth = 20;//笔触宽度
    ctx.strokeStyle = 'red';
    //绘制线段
    //笔尖不在画布上moveTo
    ctx.moveTo(100, 100)
    //笔尖落在画布上lineTo绘制路径
    ctx.lineTo(200, 200)
    //笔触填充
    ctx.stroke()//绘制
    ctx.moveTo(300, 200)//绘制新的线条
    ctx.lineTo(200, 300)
    ctx.stroke()
  </script>
</body>
3.1.6 绘制新的线条开始(开始新的路径)

可以使用beginPath() 表示开始一个新的路径

ctx.beginPath()
ctx.moveTo(50, 50);
ctx.lineTo(300, 300);
ctx.stroke()

ctx.beginPath()
ctx.lineTo(300, 200);
ctx.lineTo(430, 180);
ctx.stroke()

<body>
  <canvas id="canvas" width="500" height="500">你的浏览器不支持canvas,请升级</canvas>
  <script>
    //仅仅获取画布对象
    let mycanvas = document.getElementById('canvas');
    //通过画布对象获取上下文对象(画笔对象)
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth = 20;//笔触宽度
    ctx.strokeStyle = 'red';   
    ctx.beginPath()//开始一个新路径beginPath() 一段路径
    ctx.moveTo(100, 100)  
    ctx.lineTo(200, 200)   
    ctx.stroke()
    ctx.beginPath()//开始一个新路径beginPath() 一段路径
    ctx.moveTo(300, 200)
    ctx.lineTo(400, 300)
    ctx.stroke()
  </script>
</body>

可以使用lineWidth属性设置线的宽度

ctx.beginPath();        
ctx.moveTo(100,100);    
ctx.lineTo(300,300);    
ctx.lineTo(300,200);    
ctx.lineTo(430,180);    

ctx.strokeStyle = 'red';// 绘制描边的颜色
ctx.closePath();        // 闭合路径
ctx.lineWidth = '10';   // 绘制线的宽度
ctx.stroke();   

ctx.filStyle = 'skyblue';// 绘制填充颜色
ctx.fill();             // 绘制填充色  
3.1.7 绘制线条的转角

lineJoin : 边界连接点样式,要在画ctx.stroke()之前设置转角

  1. miter(默认值),
  2. round(圆角),
  3. bevel(平角)
ctx.moveTo(50, 50);
ctx.lineTo(300, 300);

ctx.lineTo(300, 200);
ctx.lineTo(430, 180);
ctx.closePath()
ctx.strokeStyle = 'red';
ctx.lineWidth = 20;
ctx.lineJoin = 'round'
ctx.stroke()
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.lineTo(300, 300);
    ctx.lineTo(300, 200);
    ctx.lineTo(430, 180);
    ctx.strokeStyle = 'red';
    ctx.closePath();
    ctx.lineWidth = '10';
    ctx.lineJoin = 'round'//线条转角 
    ctx.stroke();
  </script>
</body>
3.1.8 端点样式

lineCap: 端点样式

  1. butt(默认值),
  2. round(圆角) (宽度左右两边分别多出线高的一半)
  3. square(宽度左右两边分别多出线高的一半)
ctx.moveTo(50, 50);
ctx.lineTo(300, 300);
ctx.strokeStyle = 'red';
ctx.lineWidth = 50;
ctx.lineCap = 'round'
ctx.stroke()
    ctx.beginPath();
    ctx.moveTo(490, 100);
    ctx.lineTo(490, 350);
    ctx.strokeStyle = 'blue';
    ctx.lineCap = 'butt'//默认
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(450, 100);
    ctx.lineTo(450, 350);
    ctx.strokeStyle = 'blue';
    ctx.lineCap = 'round'//圆角,线段宽度左右两端分别多出线高的一半
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(410, 100);
    ctx.lineTo(410, 350);
    ctx.strokeStyle = 'blue';
    ctx.lineCap = 'square'//平角,线段宽度左右两端分别多出线高的一半
    ctx.stroke();   
3.2. 填充 fill()

还可以是用fill()给闭合路径后的闭合区域填充颜色

ctx.beginPath();        // 开始准备画线
ctx.moveTo(100,100);    // 将画笔移动到一个位置
ctx.lineTo(300,300);    // 准备绘制从开始点到这个点的线,
ctx.lineTo(300,200);    // 准备绘制从上一个点到这个点的线,
ctx.lineTo(430,180);    // 准备绘制从上一个点到这个点的线,
ctx.closePath();        // 闭合路径
ctx.stroke();           // 正式开始划线 

ctx.fill();             // 绘制填充色
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.fillStyle = 'red';
    ctx.lineWidth = 10;

    ctx.moveTo(200, 200);
    ctx.lineTo(200, 400);
    ctx.lineTo(400, 400);
    ctx.lineTo(400, 200);
    // ctx.closePath()闭合路径的方法之一  笔触
    // ctx.stroke();
    ctx.fill()//使用填充会自动闭合路径
  </script>
</body>
3.2.1 绘制填充颜色 fillStyle

strokeStyle 属性修改描边颜色

fillStyle 属性修改填充颜色

ctx.beginPath();        
ctx.moveTo(100,100);    
ctx.lineTo(300,300);    
ctx.lineTo(300,200);    
ctx.lineTo(430,180);    

ctx.strokeStyle = 'red';// 绘制描边的颜色
ctx.closePath();        // 闭合路径
ctx.stroke();   

ctx.filStyle = 'skyblue';// 绘制填充颜色
ctx.fill();             // 绘制填充色  

4.弧与圆形

1.1. 绘制弧度及圆形的公式
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)
参数
  1. x,y为圆心的坐标
  2. radius 为圆形的半径
  3. startAngle 为弧度的起始位置,0是正x轴的
  4. endAngle 为弧度的终点位置,
  5. anticlockwise 布尔值,true为逆时针绘制,false为顺时针绘制
注意

canvas中的度数都是弧度制

弧和圆形也是笔触(描边),所以也需要以beginPath()开始

var ctx = mycanvas.getContext('2d');

ctx.beginPath();
ctx.arc(150,150,100,0,2*Math.PI,false);

ctx.arc(200,200,100,0,2,false);

ctx.arc(150,150,100,2,2,false);
ctx.fill();

ctx.beginPath();
ctx.arc(150,150,100,2,0,true);
ctx.strokeStyle= 'red';
ctx.lineWidth = 2;
ctx.stroke();
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');

    ctx.fillStyle = 'red';
    ctx.lineWidth = 10;

    ctx.beginPath();
    ctx.arc(250, 250, 100, 0, Math.PI * 0.5, false);
    ctx.stroke()

    ctx.beginPath();
    ctx.arc(450, 450, 100, Math.PI * 1.5, Math.PI * 0.5, false);
    ctx.stroke()
  </script>
</body>

5. 绘制曲线

5.1. 绘制弧度曲线

arcTo(x1,y1,x2,y2,r)
x1,y1 坐标一 x2,y2坐标二 r圆弧半径

ctx.moveTo(100, 300)
ctx.arcTo(100, 100, 200, 100, 50)
ctx.stroke()
 <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.beginPath();
    ctx.lineWidth = 10;
    ctx.strokeStyle = 'red';
    ctx.moveTo(100, 300);
    ctx.arcTo(100, 100, 200, 100, 50);//弧线
    ctx.stroke()

    ctx.beginPath();
    ctx.moveTo(150, 200);
    ctx.arcTo(150, 100, 200, 100, 400);
    ctx.stroke()
  </script>
</body>
5.2. 绘制贝塞尔曲线
绘制公式
ctx.quadraticCurveTo(cp1x,cp1y,x,y)
参数
  1. cp1x, cp1y 为贝塞尔曲线的控制点
  2. x,y 为绘制曲线的终点
ctx.beginPath()
ctx.moveTo(100,100);
ctx.quadraticCurveTo(200,100,200,200)
ctx.stroke();
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.beginPath();
    ctx.lineWidth = 10;
    ctx.strokeStyle = 'red';
    ctx.moveTo(100,100);//起点
    //ctx.lineTo(300,100)//终点
    ctx.quadraticCurveTo(150,400,300,100)//一次贝塞尔曲线,贝塞尔控制点(150,400),终点
    ctx.stroke()
5.3. 绘制二次贝塞尔曲线
绘制公式
ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)
参数
  1. cp1x, cp1y 为贝塞尔曲线的第一个控制点
  2. cp2x, cp3y 为贝塞尔曲线的第二个控制点
  3. x,y 为绘制曲线的终点
ctx.beginPath()
ctx.moveTo(100,100);
ctx.bezierCurveTo(200,120,50,150,200,200);
ctx.stroke();
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.beginPath();
    ctx.lineWidth = 10;
    ctx.strokeStyle = 'red';
    ctx.moveTo(100,100);//起点
    // ctx.bezierCurveTo(150,100,300,100,500,100)点都在一条线上的贝塞尔曲线
  
    ctx.bezierCurveTo(150,300,300,-50,500,100)//贝塞尔端点一  贝塞尔端点二 终点
    ctx.stroke()   
  </script>

6. canvas变换

6.1. translate(x,y)

坐标基准点偏移 : 从起始点为基准,移动到当前位置

ctx.translate(100, 100)ctx.arc(100, 100, 50, 0, Math.PI * 2, true)ctx.strokeStyle = 'red';ctx.lineWidth = 5;ctx.stroke()
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth=10;
    ctx.strokeStyle='red';
    
    ctx.translate(100,100);//可以理解为偏移基准点
    ctx.arc(100, 100,50,0,Math.PI*2,true)//元素位置通过基准点与参考点配合确定,调谁都可以
    ctx.stroke();
  </script>
</body>
6.2.rotate(弧度):

旋转 弧度公式 :角度*PI/180

ctx.rotate(Math.PI / 180 * 30)
ctx.rect(200, 200, 100, 100)
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;

ctx.stroke()
 let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth=10;
    ctx.strokeStyle='red';
    ctx.translate(100,100)//基准点
        ctx.rotate(Math.PI/180 *80);//旋转,弧度值转成角度值
    ctx.strokeRect(0,0,100,100)//参考点在自己中心位置
    ctx.strokeRect(-50,-50,100,100)//参考点在自己中心位置

6.3. scale(wb,hb)

缩放比例(缩放canvas绘制的图片)

ctx.scale(1.5, 1.5)
ctx.rect(200, 200, 100, 100)
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;

ctx.stroke()

这里将宽、高、圆心坐标等比缩放

  let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.lineWidth=10;
    ctx.strokeStyle='red';
    ctx.scale(1,0.5);//缩放  基准点 宽 高 线宽都等比例缩放
    ctx.strokeRect(200,200,50,100)

示例:

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

ctx.beginPath();
ctx.translate(160,30);
ctx.fillStyle = "#00ff00";
ctx.fillRect(0,0,100,50);

for (var i=0;i<50 ;i++ ){
    ctx.translate(25,25);
    ctx.scale(0.9,0.9);//缩放,针对后面要绘制的图形进行缩放(在前面绘制的那个图形的基础上进行缩放)
    ctx.rotate(Math.PI/10);
    ctx.fillRect(0,0,100,50);
}

7. 保存与恢复路径

7.1. 保存路径 save()

保存之前的路径状态

7.2.恢复路径 restore()
ctx.save()
ctx.scale(3, 2)
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 100, 20)
ctx.restore()


ctx.beginPath()
ctx.fillRect(0, 50, 100, 20)

会封闭一个独立路径 不会对外边的区域产生影响

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      margin: 50px auto;
      background-color: #fff;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let mycanvas = document.getElementById('canvas');
    let ctx = mycanvas.getContext('2d');
    ctx.strokeStyle = 'blue';
    ctx.beginPath();
    ctx.save()//保存之前的的路径状态
    ctx.strokeStyle = 'red';
    ctx.lineWidth = 10;

    ctx.moveTo(100, 100);
    ctx.lineTo(300, 100);
    ctx.stroke()
    ctx.beginPath()
    ctx.restore() //恢复之前保存的路径状态
    ctx.moveTo(100, 200);
    ctx.lineTo(300, 200);
    ctx.stroke()
  </script>

8 绘制图片

8.1. 绘制图片
8.1.1 创建图片对象,获取图片

图片预加载,获取图片文件

const img = new Image();
img.src = '../1.jpg'
8.1.2 onload事件,当图片加载完成执行绘制
img.onload = function(){}
8.1.3 图片加载完成后将图片绘制在画布上

ctx.drawImage(image, dx, dy, dWidth, dHeight);

绘制图片(图片对象,画布坐标x,画布坐标y,绘制显示图片宽度,绘制显示图片高度)

const img = new Image();
img.src = '../1.jpg';
img.onload = function () {
    ctx.drawImage(this, 0, 0, 100, 300)
}
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let img = new Image();//创建图片对象
    img.src = './imgs/11.jpg';
    img.onload = function () {//加载就会触发onload事件
      ctx.drawImage(this, 20, 20, 300, 300);//画图片
    }
  </script>
</body>
8.1.4 切图

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

参数:

  1. image 绘制到上下文的元素

  2. sx 可选

    需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 X 轴坐标。

  3. sy 可选

    需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 Y 轴坐标。

  4. sWidth 可选

    需要绘制到目标上下文中的,image的矩形(裁剪)选择框的宽度。

  5. sHeight 可选

    需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。

  6. dx

    image的左上角在目标canvas上 X 轴坐标。

  7. dy

    image的左上角在目标canvas上 Y 轴坐标。

  8. dWidth 可选

    image在目标canvas上绘制的宽度。

  9. dHeight 可选

    image在目标canvas上绘制的高度。 允许对绘制的image进行缩放。

const img = new Image();
img.src = '../1.jpg';
img.onload = function () {
    ctx.drawImage(this, 50, 50, 500, 500, 100, 100, 100, 100)
}
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let img = new Image();//创建图片对象
    img.src = './imgs/11.jpg';
    img.onload = function () {//加载就会触发onload事件
      ctx.drawImage(this, 20, 20, 300, 300);//画图片
      ctx.drawImage(this, 50, 50, 100, 100, 20, 350, 300, 300);//可以做放大镜
    }
  </script>
</body>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #f3f3f3;
    }

    #canvas {
      /*canvas虽然默认宽高300X150,但它是个行元素inline*/
      display: block;
      /*变块才能居中*/
      background-color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let img = new Image();//创建图片对象
    img.src = './imgs/11.jpg';
    img.onload = function () {//加载就会触发onload事件
      ctx.drawImage(this, 20, 20, 300, 300);//画图片
      canvas.onmousemove = function (e) {
        console.log(e);
        let sX = e.clientX - 50;
        let sY = e.clientY - 50;
        ctx.drawImage(img, sX, sY, 100, 100, 20, 350, 300, 300);
      }
    }
  </script>
</body>
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let img = new Image();//创建图片对象
    img.src = './imgs/11.jpg';
    img.onload = function () {//图片加载就会触发onload事件
      //创建背景图片填充资源
      let bg = ctx.createPattern(this, 'repeat')
      ctx.fillStyle = bg;//填充背景资源
      ctx.fillRect(0, 0, 500, 500)//填充一个矩形
    }
  </script>
</body>
8.2. 填充背景
8.2.1 createPattern(img,平铺方式)

参数: 平铺方式:repeat,repeat-x,repeat-y,no-repeat

const img = new Image();
img.src = '../1.jpg';
img.onload = function () {
    const bg = ctx.createPattern(img, 'no-repeat');
    ctx.fillStyle = bg;
    ctx.fillRect(100, 100, 300, 200)
}
8.3. 颜色渐变
8.3.1 线性渐变:createLinearGradient(x1,y1,x2,y2)
x1,y1起始坐标点

x2,y2结束坐标点
8.3.2 径向渐变:createRadialGradient(x1,y1,r1,x2,y2,r2)
x1,y1,r1内圆坐标及半径

x2,y2,r2外圆坐标及半径
8.3.3 addColorStop(位置,颜色)
位置:渐变点  0-1之间 可多个

例子,

线性渐变

let color = ctx.createLinearGradient(0, 0, 500, 500);
color.addColorStop(0, 'pink');
color.addColorStop(0.5, 'yellow')
color.addColorStop(1, 'deeppink')

ctx.fillStyle = color;
ctx.fillRect(0, 0, 500, 500)
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let color = ctx.createLinearGradient(0, 0, 500, 500)//渐变颜色对象
    color.addColorStop(0, 'red')//添加颜色
    color.addColorStop(.5, 'yellow')
    color.addColorStop(1, 'blue')
    ctx.fillStyle = color;//用渐变颜色填充
    ctx.fillRect(0, 0, 500, 500)
  </script>
</body>

径向渐变

let color = ctx.createRadialGradient(200, 200, 100, 200, 200, 200);
color.addColorStop(0, 'pink');
color.addColorStop(0.5, 'yellow')
color.addColorStop(1, 'deeppink')

ctx.fillStyle = color;
ctx.fillRect(0, 0, 500, 500)
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    //加载图片
    let color = ctx.createRadialGradient(200,200,50,200,200,300)//渐变颜色对象
    color.addColorStop(0, 'red')//添加颜色
    color.addColorStop(.5, 'yellow')
    color.addColorStop(1, 'blue')
    ctx.fillStyle = color;//用渐变颜色填充
    // ctx.fillRect(0, 0, 500, 500)
    ctx.fillRect(0, 0, 100, 100)
  </script>
</body>

9.绘制文本

9.1. 绘制文本
  1. strokeText(文本,x,y); 绘制空心文本(描边文字)
  2. fillText(文本,x,y); 绘制实心文本(填充文字)
  3. font = "font-size font-family" 注:尺寸 字体缺一不可
  4. textAlign = "";文本左右对齐方式 (参考文字坐标点对齐)
    start center end left right
  5. textBaseline文本上下对齐方式
    alphabetic 默认。文本基线是普通的字母基线。
    top 文本基线是 em 方框的顶端。。
    hanging 文本基线是悬挂基线。
    middle 文本基线是 em 方框的正中。
    ideographic 文本基线是表意基线。
    bottom 文本基线是 em 方框的底端。
let str = 'wuwei'
ctx.font = '50px 宋体'
ctx.textAlign = 'center'
ctx.textBaseline = 'top'
ctx.strokeText(str, 100, 100)
ctx.fillText(str, 100, 200)
9.2. 绘制阴影
  1. shadowOffsetX,shadowOffsetY x轴、y轴偏移
  2. shadowBlur 阴影模糊度
  3. shadowColor 阴影颜色
    默认颜色:rgba(0,0,0,0)
ctx.shadowOffsetX = '10'
ctx.shadowOffsetY = '10'
ctx.shadowBlur = '3'
ctx.shadowColor = 'red'

案例:

body {
    background-color: #000;
}
canvas {
    display: block;
    margin: 100px auto 0;
    border: 1px solid skyblue;
    background-color: #fff;
}
.box{
    width: 360px;
    margin: 10px auto;
}
input{
    width: 50px;
    height: 20px;
    text-align: center;
}
<canvas width="500" height="500"></canvas>
<div class="box">
    <input type="color" id='colorList'>
    <button id='color'>随机颜色</button>
    <input type="text" value='2px' id='storke'>
    <button id='add'>笔触增加</button>
    <button id='reduce'>笔触减小</button>
    <button id="clear">清屏</button>
</div>
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');

var strokeColor = '#000000';
var lineWidth = 2;

colorList.onchange = function () {
    strokeColor = colorList.value;
}

color.onclick = function () {
    strokeColor = '#' + Math.random().toString(16).slice(2, 8);
    colorList.value = strokeColor;
}
add.onclick = function () {
    if (lineWidth >= 10) return;
    lineWidth += 2;
    storke.value = lineWidth + 'px'

}
reduce.onclick = function () {
    if (lineWidth <= 2) return;
    lineWidth -= 2;
    storke.value = lineWidth + 'px'
}



canvas.onmousedown = function (ev) {
    ev = ev || window.event;
    var This = this;
    var x = ev.clientX - this.offsetLeft;
    var y = ev.clientY - this.offsetTop;
    ctx.strokeStyle = strokeColor;
    ctx.lineWidth = lineWidth;
    ctx.beginPath();
    ctx.moveTo(x, y);
    document.onmousemove = function (ev) {
        ev = ev || window.event;
        var x = ev.clientX - This.offsetLeft;
        var y = ev.clientY - This.offsetTop;
        ctx.lineTo(x, y);
        ctx.stroke();

    }
    document.onmouseup = function () {
        this.onmousemove = null;
        this.onmouseup = null
    }
}
clear.onclick = function () {
    console.log(1)
    ctx.clearRect(0, 0, 500, 500)

}
<body>
  <canvas id="canvas" width="700" height="600">你的浏览器不支持canvas,请升级</canvas>
  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    let str = 'hello world';
    ctx.font = '50px 微软雅黑'
    ctx.textAlign = 'left'
    ctx.textBaseline = 'top'
    ctx.shadowOffsetX = '10'//水平偏移
    ctx.shadowOffsetY = '10'//垂直偏移
    ctx.shadowBlur = '3'//模糊
    ctx.shadowColor = 'red'//颜色
    ctx.strokeText(str, 50, 200)//空心文字

    let str2 = '你好呀';
    ctx.font = '50px 微软雅黑'
    ctx.textAlign = 'left'
    ctx.textBaseline = 'middle'
    ctx.fillText(str2, 400, 200)//实心文字
  </script>
</body>

10.API使用总结

10.1. canvas标签
<canvas width="" height="" id="">
    您的浏览器不支持canvas,请更换浏览器!
</canvas>

默认宽度300px,默认高度 150px

10.2. canvas绘图环境设置
getContext("2d"); 目前支持2d绘图环境
10.3. 绘图路径:
  1. beginPath() :开始路径
  2. closePath():闭合路径
  3. moveTo(x,y):将触笔移动到x,y点
  4. lineTo(x,y):绘制到x,y点
  5. stroke(): 触笔方法 画线 默认为黑色
  6. fill():填充方法
  7. rect(x,y,w,h):矩形路径
  8. save():保存路径
  9. restore():恢复路径
10.4. 绘制矩形:
  1. fillRect(x,y,w,h) 填充实心矩形
  2. strokeRect(x,y,w,h) 绘制空心矩形
  3. clearRect(x,y,w,h) 清除矩形选区
10.5. 设置绘图样式:
  1. fillStyle: 填充颜色
  2. strokeStyle: 触笔颜色
  3. lineWidth: 触笔宽度(线宽)
10.6. 图形边界样式:
  1. lineJoin : 边界连接点样式
    miter(默认值),round(圆角),bevel(斜角)
  2. lineCap: 端点样式
    butt(默认值),round(圆角),square(高度多出线宽一半)
10.7. 绘制圆形:
  1. arc(x,y,r,0,360,false)
    x,y 圆心坐标位置
    r 圆半径
    0,360 从0度到360度 绘制一个圆形(用弧度公式)
    true/false 逆时针/顺时针绘图
10.8. 绘制曲线
  1. arcTo(x1,y1,x2,y2,r)
    x1,y1 坐标一 x2,y2坐标二 r圆弧半斤
  2. quadraticCurveTo(dx,dy,x1,y1)
    贝塞尔曲线:dx,dy控制点 x1,y1结束坐标
  3. bezierCurveTo(dx1,dy1,dx2,dy2,x1,y1)
    贝塞尔曲线:dx1,dy1 控制点一 dx2,dy2控制点二
    x1,y1结束坐标
10.9. canvas变换
  1. translate(x,y)
    坐标基准点偏移 : 从起始点为基准,移动到当前位置
  2. rotate(弧度): 旋转 弧度公式 :角度*PI/180
  3. scale(wb,hb)缩放比例(缩放canvas绘制的图片)
10.10. 绘制图片
  1. 图片预加载,获取图片文件
  2. onload事件,监听图片是否加载完毕,如果加载完毕执行第三步
  3. drawImage(img,x,y,w,h);绘制图片(图片,坐标x,坐标y,宽度,高度)
10.11.设置背景
  1. createPattern(img,平铺方式)
    平铺方式:repeat,repeat-x,repeat-y,no-repeat
10.12. 颜色渐变
  1. 线性渐变:createLinearGradient(x1,y1,x2,y2)
    x1,y1起始坐标点
    x2,y2结束坐标点
  2. 径向渐变:createRadialGradient(x1,y1,r1,x2,y2,r2)
    x1,y1,r1内圆坐标及半径
    x2,y2,r2外圆坐标及半径
  3. addColorStop(位置,颜色)
    位置:渐变点 0-1之间 可多个
10.13. 绘制文本
  1. strokeText(文本,x,y); 绘制空心文本
  2. fillText(文本,x,y); 绘制实心文本
  3. font = "font-size font-family" 注:尺寸 字体缺一不可
  4. textAlign = "";文本左右对齐方式
    start center end left right
  5. textBaseline文本上下对齐方式
    alphabetic 默认。文本基线是普通的字母基线。
    top 文本基线是 em 方框的顶端。。
    hanging 文本基线是悬挂基线。
    middle 文本基线是 em 方框的正中。
    ideographic 文本基线是表意基线。
    bottom 文本基线是 em 方框的底端。
10.14. 阴影
  1. shadowOffsetX,shadowOffsetY x轴、y轴偏移
  2. shadowBlur 阴影模糊度
  3. shadowColor 阴影颜色
  4. 默认颜色:rgba(0,0,0,0)
画板例子
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      background-color: #000;
    }

    canvas {
      display: block;
      margin: 10px auto 0;
      border: 1px solid skyblue;
      background-color: #fff;
    }

    .box {
      width: 500px;
      margin: 10px auto;
    }

    input {
      width: 50px;
      height: 20px;
      text-align: center;
    }
  </style>
</head>
<body>
  <canvas width="600" height="400"></canvas>
  <div class="box">
    <input type="color" id='colorList'>
    <!--type类型为color表示颜色选择器 -->
    <button id='color'>随机颜色</button>
    <input type="text" value='2px' id='storke' disabled> <!-- input 的阻止页面上手动编辑 disabled -->

    <button id='add'>笔触增加</button>
    <button id='reduce'>笔触减小</button>
    <button id="clear">清屏</button>
  </div>
  <script>
    //获取canvas
    let canvas = document.getElementsByTagName('canvas')[0];
    // 获取上下文对象(画笔)
    let ctx = canvas.getContext('2d');
    //信号量 定义初始画笔的颜色和大小
    let strokeColor = '#000000';//笔触颜色信号量
    let lineWidth = 2;//笔触大小信号量
    //清屏
    clear.onclock = function () {
      ctx.clearRECT(0, 0, 600, 400)
    }
    // 颜色选择
    colorList.onchange = function () {
      strokeColor = this.value;
    }
    //随机颜色
    color.onclick = function () {
      strokeColor = '#' + Math.random().toString(16).substr(2, 6);
      colorList.value = strokeColor//滑条颜色与随机颜色保持一致
    }
    //加减笔触
    add.onclick = function () {
      lineWidth += 2;      //画笔值与页面显示保持一致
      storke.value = lineWidth + 'px';
    }
    reduce.onclick = function () {
      lineWidth -= 2;
      storke.value = lineWidth + 'px';
    }
    //绘制
    canvas.onmousedown = function (ev) {
      ev = ev || window.event//事件对象做兼容
      //获取鼠标按下时距离画布左上端点的距离 x 有
      let x = ev.clientX - this.offsetLeft;//事件对象距离浏览器左边的距离减去canvas距离浏览器左边的距离
      let y = ev.clientY - this.offsetTop;
      //绘制
      ctx.strokeStyle = strokeColor;
      ctx.lineWidth = lineWidth;
      //开启新路径
      ctx.beginPath();
      ctx.moveTo(x, y);//鼠标按下 绘制的坐标就移动到x y位置

      document.onmousemove = function (ev) {
        //使用外部this方法一 let This = this;定义一个大This,将外部this传给里面的This
        //使用外部this方法二 .bind(this)
        //使用外部this方法三 箭头函数 (ev)=>{} 箭头函数没有this,只能向上找this
        ev = ev || window.event;
        let x = ev.clientX - this.offsetLeft;
        let y = ev.clientY - this.offsetTop;
        ctx.lineTo(x, y);
        ctx.stroke();
      }.bind(this)
      //现在的线段是由鼠标拖出来的
      document.onmouseup = function () {//清理事件。鼠标抬起说明画完了,清理默认事件.onmousedown事件是入口不清理
        this.onmousemove = null;
        this.onmouseup = null;
      }
    }
  </script>
</body>

</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容