从0开始canvas系列一 --- canvas画布

从0开始canvas系列

从0开始canvas系列一 — canvas画布

从0开始canvas系列二 — 文本和图像

从0开始canvas系列三 — 图像像素级操作

从0开始canvas系列四 — 运动模型

什么是canvas

canvas是HTML5新增的元素,通过javascript脚本来完成图形的绘制。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

简单来说,canvas提供了一张画布,调用getContext属性(可以是2d或者WebGL 3d)定义画笔,通过设置图像的填充或者描边属性,定义图形的绘图方式,完成一次图形的绘制,每次绘制都是已绘制路径作为一个绘制单元

每一次绘制过程可以总结为以下步骤

 //获取画布
const  canvas=document.querySelector('#canvas');
//定义画笔
const ctx=canvas.getContext('2d');
//设置画笔的颜色
ctx.fillStyle='red';
//开启一次绘制路径
ctx.beginPath();
//设置起始坐标
ctx.moveTo(x,y);
//定义绘制图形的形状
ctx.arc(x,y,r,开始弧度,结束弧度,方向);//定义圆弧
//渲染路径
ctx.fill()

怎么用canvas

canvas就是一个画图过程,你在写js代码的时候就是画图的过程,Canvas API提供的就是画图的工具,下面我们就用这个概念我们正式开始canvas的学习之路

canvas画布(纸和笔的准备)

  • canvas画布(画纸)的坐标系和栅格

    • 坐标系是二维,x/y轴
    • x轴往右越大,y轴往下越大
    • 像素为最小单元(栅格),每个像素具有RGBA数据,像素数量等于画布长*宽
      从0开始canvas系列一 --- canvas画布_第1张图片
  • canvas画布(画纸)的大小设置

    • 画布长和宽可以是行间样式
    • 可以通过canvas.width/canvas.height定义
    • 极限尺寸控制再4000内
    • 不要通过css样式设置,会造成图形失真
<canvas id="canvas" width="700" height="800"></canvas>

const  canvas=document.querySelector('#canvas');
canvas.width=300;
canvas.height=150;
  • canvas画笔
    • 2d画笔
    • 3d画笔
//2d画笔
const  ctx=canvas.getContext('2d');
//3d画笔
const  ctx=canvas.getContext('webgl');

canvas绘制图形(画图形)

基本图形

直线
  • lineTo(x,y)
  /*直线:lineTo(x,y); */
  ctx.beginPath();
  ctx.moveTo(50,50);
  ctx.lineTo(400,50);
  ctx.lineTo(400,300);
  ctx.closePath();
  ctx.stroke();

从0开始canvas系列一 --- canvas画布_第2张图片

圆弧
  • arc(x,y,半径,开始弧度,结束弧度,方向)

    方向:true表示顺时针,false表示逆时针

从0开始canvas系列一 --- canvas画布_第3张图片

  ctx.beginPath();
  ctx.arc(300,300,100,0,Math.PI*3/2,true);//顺时针
  ctx.stroke();

  ctx.moveTo(700,300);
  ctx.arc(600,300,100,0,Math.PI*3/2,false);
  ctx.stroke();

从0开始canvas系列一 --- canvas画布_第4张图片

切线圆弧
  • arcTo(x1,y1,x2,y2,半径)

    坐标说明如下

从0开始canvas系列一 --- canvas画布_第5张图片

ctx.beginPath();
ctx.moveTo(50,50);
ctx.arcTo(400,50,400,300,100);
ctx.stroke();
二次贝塞尔曲线

贝塞尔曲线原理

  • quadraCurverTo(cpx1,cpy1,x,y)

    • cpx1/cpy1 表示控制点,x/y表示结束点

    绘图过程如下(p1控制点,p2结束点):

    • 由 P0 至 P1 的连续点 Q0,描述一条线段。

    • 由 P1 至 P2 的连续点 Q1,描述一条线段。

    • 由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。

从0开始canvas系列一 --- canvas画布_第6张图片

ctx.beginPath();
ctx.moveTo(50,50);
ctx.quadraticCurveTo(400,50,400,300);
ctx.stroke();
三次贝塞尔曲线
  • bezierCurverTo(cpx1,cpy1,cpx2,cpy2,x,y)

    • cpx1/cpy1 cpx2/cpy2表示控制点,x/y表示结束点

从0开始canvas系列一 --- canvas画布_第7张图片

ctx.beginPath();
ctx.moveTo(50,50);
ctx.bezierCurveTo(
    400,50,
    400,300,
    800,300
)
ctx.stroke();
矩形
  • 基本矩形

    rect(x,y,w,h)

    • 矩形不需要指定起始点
    ctx.beginPath();
    ctx.rect(50,50,400,200);
    ctx.stroke();
    ctx.fill();
    
  • 填充矩形

    fillRect(x,y,w,h)

  • 描边矩形

    strokeRect(x,y,w,h)

  • 清理矩形(橡皮擦)

    ctx.clearRect(x,y,w,h);

【扩展】路径

从各个图形的绘制过程中我们可以发现每一个图形绘制过程中都有如下规律:

  1. 首先,创建画图起始点。
  2. 然后,使用画图命令去设置图形。
  3. 最后,通过描边或填充路径区域来渲染图形。

上述三个过程,其实就是一个路径的创建过程

图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。

有关路径的API如下
  • beginPath()

    新建一条路径集合,生成之后,图形绘制命令被指向到路径集合上生成路径。

    当前路径为空,即调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo(),无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。

  • closePath()

    闭合路径之后图形绘制命令又重新指向到上下文中。

  • stroke()

    通过线条来绘制图形轮廓。

  • fill()

    通过填充路径的内容区域生成实心的图形。

    当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()函数。但是调用stroke()时不会自动闭合。

路径和子路径
  • 路径:

    • 路径是子路径的集合
    • 一个上下文对象同时只有一个路径,想要绘制新的路径,就要把当前路径置空。
    • beginPath()方法可以将当前路径置空,也就是将路径恢复到默认状态,让之后绘制的路径不受以前路径的影响。
  • 子路径

    • 子路径是一条只有一个起点的、连续不断开的线
    • moveTo(x,y) 是设置路径起点的方法,也是创建一条新的子路径的方法
    • 路径里的第一条子路径可以无需设置起点,它的起点默认是子路径中的第一个点

两者的关系图

从0开始canvas系列一 --- canvas画布_第8张图片

//beginPath开启一条路径
ctx.beginPath();
//子路径1
ctx.moveTo(190,100);
ctx.arc(100,100,90,0,Math.PI*2);

ctx.beginPath();//加入前后效果如图

//子路径2
ctx.moveTo(400,300);
ctx.arc(300,300,100,0,Math.PI*2);
ctx.stroke();

无beginPath()
从0开始canvas系列一 --- canvas画布_第9张图片
有beginPath()
从0开始canvas系列一 --- canvas画布_第10张图片

图形着色和描边(上色和描边)

注意:着色或者描边实际是在画图前

图形着色

着色分为两部分:fillStyle(内部填充区)和stokeStyle(描边区)

fillStyle(图形填充区)

ctx.fillStyle
是Canvas 2D API 使用内部方式描述颜色和样式的属性。默认值是 #000 (黑色)。

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

ctx.fillStyle = "blue";
ctx.fillRect(10, 10, 100, 100);

fillStyle 使用 for 循环的例子

var ctx = document.getElementById('canvas').getContext('2d');
for (var i=0;i<6;i++){
  for (var j=0;j<6;j++){
    ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
                     Math.floor(255-42.5*j) + ',0)';
    ctx.fillRect(j*25,i*25,25,25);
  }
}

从0开始canvas系列一 --- canvas画布_第11张图片

stokeStyle(描边区)

ctx.stokenStyle是 Canvas 2D API 描述画笔(绘制图形)颜色或者样式的属性。默认值是 #000 (black)。

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

ctx.strokeStyle = "blue";
ctx.strokeRect(10, 10, 100, 100);

stokeStyle 使用 for 循环的例子

var ctx = document.getElementById('canvas').getContext('2d');
for (var i=0;i<6;i++){
  for (var j=0;j<6;j++){
    ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' + 
                      Math.floor(255-42.5*j) + ')';
    ctx.beginPath();
    ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true);
    ctx.stroke();
  }
}

从0开始canvas系列一 --- canvas画布_第12张图片

着色样式

图形的着色方式有三种

  • 纯色
  • 渐变
  • 纹理

对应的代码为

ctx.fillStyle = color;
ctx.fillStyle = gradient;
ctx.fillStyle = pattern;

ctx.strokeStyle = color;
ctx.strokeStyle = gradient;
ctx.strokeStyle = pattern;

color
    DOMString 字符串,可以转换成 CSS <color> 值。
gradient
	CanvasGradient 对象(线性渐变或放射性渐变)。
pattern
	CanvasPattern 对象(可重复的图片)。
  • 纯色
ctx.fillStyle='blue';
ctx.fillStyle='#00acec';
ctx.fillStyle='RGB(255,0,255)';
ctx.fillStyle='RGBA(0,0,255,0.5)';
  • 渐变

    渐变相比纯色,设置起来要相对复杂,需要设置起始和终点坐标和起始颜色,另外你还能在再中间添加点位和颜色

从0开始canvas系列一 --- canvas画布_第13张图片

渐变可分为线性渐变和径向渐变

线性渐变
从0开始canvas系列一 --- canvas画布_第14张图片

径向渐变
从0开始canvas系列一 --- canvas画布_第15张图片
具体设置如下

  1. 设置渐变对象(起始和终点坐标)
//线性渐变  
const gr = ctx.createLinearGradient(x1, y1, x2, y2)
//径向渐变  
const gr = ctx.createRadialGradient(x1, y1, r1, x2, y2, r2)

x1,y1:起始坐标  r1: 开始坐标半径
x2,y2:终点坐标  r2: 终点坐标半径
  1. 定义各个坐标的颜色
gr.addColorStop(position, color)

position:位置,取值0-10代表起始点,1代表终点
color:颜色,纯色
  1. 为样式进行赋值
ctx.fillStyle = gr;
ctx.stokeStyle = gr;

线性渐变demo

  const canvas=document.getElementById('canvas');
  //canvas 充满窗口
  canvas.width=window.innerWidth;
  canvas.height=window.innerHeight;

  //画笔-上下文对象
  const ctx=canvas.getContext('2d');

  /*
  1.建立渐变对象,定义渐变的区域
  */
  const gr=ctx.createLinearGradient(50,50,450,450);

  /*
  2.为渐变添加颜色节点
  */
  gr.addColorStop(0,'red');
  gr.addColorStop(0.5,'yellow');
  gr.addColorStop(1,'#00acec');

  /*
  3.为样式赋值
  */
  ctx.fillStyle=gr;

  /*
  4.绘图
  */
  ctx.fillRect(50,50,400,400);

从0开始canvas系列一 --- canvas画布_第16张图片

径向渐变demo

  const canvas=document.getElementById('canvas');
  //canvas 充满窗口
  canvas.width=window.innerWidth;
  canvas.height=window.innerHeight;

  //画笔-上下文对象
  const ctx=canvas.getContext('2d');

  /*
  1.建立渐变对象,定义渐变的区域
  */
  const gr=ctx.createRadialGradient(
      300,300,20,
      400,300,200
  )

  /*
  2.为渐变添加颜色节点
  */
  gr.addColorStop(0,'red');
  gr.addColorStop(0.5,'yellow');
  gr.addColorStop(1,'#00acec');

  /*
  3.为样式赋值
  */
  ctx.fillStyle=gr;

  /*
  4.绘图
  */
  ctx.fillRect(50,50,600,600);

从0开始canvas系列一 --- canvas画布_第17张图片

  • 纹理

纹理就是将图片重复填充,其设置方法和渐变步骤类似

  1. 设置纹理对象

const pt = ctx.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat");

  1. 为样式进行赋值

ctx.fillStyle=pt

纹理demo

  const img=new Image();
  img.src='./images/floor.jpg';
  img.onload=function(){
      const pt=ctx.createPattern(img,'repeat');
      ctx.fillStyle=pt;
      ctx.fillRect(0,0,canvas.width,canvas.height);
  }

从0开始canvas系列一 --- canvas画布_第18张图片

图形描边

  • strokeStyle/lineWidth

    描边的颜色和宽度

    //上文已经讲过
    ctx.strokeStyle = color 
    
    ctx.lineWidth = value
    value:描述线段宽度的数字。 0、 负数、 InfinityNaN 会被忽略
    
  • lineCap

    描边端点样式

     ctx.save();
     ctx.lineCap='butt/round/square';
     ctx.beginPath();
     ctx.moveTo(50,50);
     ctx.lineTo(400,50);
     ctx.stroke();
     ctx.restore();
     
     lineCap 描边端点样式
     *   butt 没有端点,默认
     *   round 圆形端点
     *   square 方形端点
    

butt
在这里插入图片描述
round
在这里插入图片描述

square
在这里插入图片描述

  • lineJoin

    拐角类型

      ctx.save();
      ctx.lineJoin='miter/round/bevel';
      ctx.beginPath();
      ctx.moveTo(50,50);
      ctx.lineTo(400,50);
      ctx.lineTo(200,150);
      ctx.stroke();
      ctx.restore();
      
      lineJoin 拐角类型
      *   miter 尖角
      *   round 圆角
      *   bevel 切角
    

miter
在这里插入图片描述

round
在这里插入图片描述
bevel
在这里插入图片描述

  • setLineDash
ctx.setLineDash(segments)

segments
一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。 
数组中的数据只是代表每条虚实线的长度,和虚实线交替出现没有关系

ctx.setLineDash([60,90])

在这里插入图片描述

ctx.setLineDash([60,90,120])
在这里插入图片描述

  • 投影

位置:shadowOffsetX , shadowOffsetY

模糊度:shadowBlur

颜色:shadowColor

    ctx.shadowColor='#000';
    ctx.shadowOffsetY=30;
    ctx.shadowOffsetX=30;
    ctx.shadowBlur=30;
    ctx.beginPath();
    ctx.arc(300,200,100,0,Math.PI*2);
    ctx.fillStyle='#93abff';
    ctx.fill();

segments
一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。
数组中的数据只是代表每条虚实线的长度,和虚实线交替出现没有关系


`ctx.setLineDash([60,90])`
[外链图片转存中...(img-wTlH25Bt-1649603649709)]

`ctx.setLineDash([60,90,120])`
[外链图片转存中...(img-95vYi8Q1-1649603649710)]

- 投影

 位置:shadowOffsetX , shadowOffsetY
        
 模糊度:shadowBlur
        
 颜色:shadowColor

```js
    ctx.shadowColor='#000';
    ctx.shadowOffsetY=30;
    ctx.shadowOffsetX=30;
    ctx.shadowBlur=30;
    ctx.beginPath();
    ctx.arc(300,200,100,0,Math.PI*2);
    ctx.fillStyle='#93abff';
    ctx.fill();

在这里插入图片描述

你可能感兴趣的:(canvas,javascript)