H5 canvas学习笔记 | 基本使用 路径 状态

H5 canvas学习笔记

简介

HTML有两个主要的2D图形技术:Canvas和SVG

canvassvg
2D2D
基于JavaScript动态生成使用XML静态描述
不会保留绘制的图形的信息,基于像素点绘制位图,放大会会失真内存中保留绘制的图形的信息,用html标签描绘形状,矢量图放大不会失真
canvas无法对已经绘制的图像进行修改、操作
如果发生修改,需要重绘
svg中每个图形又对应真实的dom节点、svg可以获取到标签进行操作

H5 Canvas就是使用JavaScript来操作Canvas元素(画布)的技术。
①获取Canvas对象(画布)
②获取渲染上下文环境对象context(画笔)
③开始绘制图形

所有canvas图形操作的属性和方法都是基于context对象

Canvas画布/画笔

坐标系是二维x/y轴,像素为最小单元(栅格),每个像素具有RGBA数据,像素数量等于画布长*宽
在这里插入图片描述

  • canvas画布的大小
    • 可以是行间样式
    • 可以通过canvas.width/canvas.height设置和获取画布的大小
  • canvas画笔
    • 2d画笔canvas.getContext('2d')
    • 3d画笔canvas.getContext('webgl')或者canvas.getContext('webgl2')
<body>
    <canvas id="canvas">不支持时的提示文字</canvas>
</body>
<script>
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");  
</script>

1.Canvas标签中的文字是在不支持Canvas标签的浏览器中使用的,因为支持Canvas标签的浏览器会忽略容器中包含的内容正常渲染Canvas标签,而不支持Canvas标签的浏览器则相反,浏览器会忽略容器而显示其中的内容。
2.Canvas标签的默认大小为:300 x 150 (像素)

Canvas路径

在Canvas中,除了矩形,其他所有的Canvas基本图形(适用范围)都是以路径为基础。

方法说明
beginPath()开始一条新路径
closePath()封闭当前路径
isPointInPath(x,y)判断某一个点(x,y)是否存在当前路径内
  • beginPath():新建一条路径,判断是否同一路径的标准是是否使用了beginPath方法
  • closePath():闭合路径,连接起点与终点,封闭当前路径:closePath是指将同一路径的起点和终点连接起来,使其成为一个封闭图形
  • isPointInPath(x,y) :不支持Canvas自带的两个方法strokeRect()fillRect(),只能用rect()

Canvas状态

Canvas基于"状态"来绘制图形,每一次绘制(stroke或者fill),Canvas会检测整个程序定义的所有状态(strokeStyle、fillStyle、lineWidth等)。
①如果开启了一个新路径,则不同路径使用不同的值
②如果没有开启新路径,后面的值会覆盖前面的值

绘图样式必须先于矩形绘制方法之前,把相应参数设置好,canvas再根据已设置的参数来画图。

状态属性

状态包括:填充效果、描边效果、线条效果、文本效果、阴影效果和全局属性

  • 填充效果:fillStyle
  • 描边效果:strokeStyle
  • 线条效果:lineCap、lineJoin、lineWidth、miterLimit
  • 文本效果:font、textAlign、textBaseLine
  • 阴影效果:shawBlu、shadowColor、shadowOffsetX、shadowOffsetY
  • 全局属性:globalAlpha、globalCompositeOperation

globalAlpha属性定义Canvas环境的透明度,默认为1.0,取值范围为0.0~1.0
globalCompositeOperation属性改变图形交叉显示的顺序

属性值说明符号表示
source-over默认值,新图覆盖旧图新图B,旧图A
destination-over旧图A覆盖新图B
copy只显示新图,旧图透明
darker两种图形都显示,在重叠部分颜色由两种图形的颜色值相减后形成
light两种图形都显示,在重叠部分颜色由两种图形的颜色值相加后形成
destination-atop只显示新图与旧图的重叠部分以及新图的其余部分A∩BUB
source-atop只显示新图与旧图的重叠部分以及旧图的其余部分A∩BUA
destination-in只显示旧图中与新图的重叠部分
source-in只显示新图中与旧图重叠的部分
destination-out只显示旧图中与新图不重叠的部分
source-out只显示新图中与旧图不重叠的部分
xor两图都绘制,重叠部分透明

在这里插入图片描述

状态的保存和恢复
  • 保存当前状态sava()
  • 恢复之前的保存状态restore()

Canvas的状态是存储在栈中的,每次调用save()方法后,当前的状态都会被推送到栈中保存起来。调用restore()方法,栈顶的状态被pop出来。

 const ctx = canvas.getContext('2d');
 ctx.fillStyle = "#cccccc";
 ctx.fillRect(10, 10, 300, 100);
 ctx.save(); // 保存状态
 ctx.fillStyle = "#ee7034";
 ctx.fillRect(10, 150, 300, 100);
 ctx.restore(); // 还原到上次保存的状态
 ctx.fillRect(10, 300, 300, 100);

基本图形stroke/fill

  • strokeStyle属性:设置边框样式
  • stroke():通过线条来绘制图形轮廓,执行描边动作
  • fillStyle属性:设置填充的颜色
  • fill():通过填充路径的内容区域生成实心的图形。如果路径未关闭, fill() 方法会从路径结束点到开始点之间添加一条线,以关闭该路径,然后填充该路径。

直线moveTo()/lineTo()

context对象的moveTo(x1,y1):将画笔移动到(x1,y1)位置,表示直线的起点.。
context对象的lineTo(x2,y2):使用画笔从起点(x1,y1)开始画直线,一直画到终点(x2,y2)

<body>
    <canvas id="canvas"></canvas>
</body>
<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    ctx.moveTo(100,100); //
    ctx.lineTo(100,200); //
    ctx.stroke();//开始绘画
</script>

画多条直线
lineTo方法可以重复调用,默认是以上一次的终点位置作为本次的起点位置。

矩形trokeRect()/fillRect()/clearRect()/react()

矩形也可以使用四条直线来画,不过太复杂了。
Canvas API 给提供了三种绘制矩形的方法。

  • trokeRect(x, y, width, height) 绘制一个矩形的边框
  • fillRect(x, y, width, height) 绘制一个填充的矩形
  • clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明。
    trokeRect(x, y, width, height):绘制矩形边框
  • x和y 是矩形左上角的起点坐标
  • width和height 是矩形的宽高

fillRect(x, y, width, height) 绘制一个填充的矩形

  • x和y 是矩形左上角的起点坐标
  • width和height 是矩形的宽高。

clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明

  • x和y 是矩形左上角的起点坐标
  • width和height 是矩形的宽高

rect(x,y,width,height) 绘制一个矩形,需要调用stroke()fill()方法

绘图样式属性的取值

  • 颜色值
    • 十六进制颜色值#FF0000
    • 颜色关键字red
    • rgb颜色rgb(255,0,0)
    • rgba颜色值rgba(255,0,0,0.8)
  • 渐变色
  • 图案
<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    
    ctx.fillRect(100, 100, 200, 100);
    ctx.strokeRect(300, 300, 200, 100) 
    ctx.clearRect(100, 100, 100, 70);
</script>

在这里插入图片描述

圆弧和圆arc()

arc(x, y, radius, startAngle, endAngle, anticlockwise)

  • x和y为圆心的坐标,radius为半径
  • startAngle为圆弧或圆的开始位置(弧度),endAngle为圆弧或圆的结束位置(弧度)
  • anticlockwise是绘制的方向,默认为false(顺时针方向)
  • 需要结合stroke()函数

在画弧的时候,arc()函数中角的单位是弧度而不是角度。
角度换算为弧度的表达式为:弧度=(Math.PI/180)*角度

<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');    
    // 绘制一段圆弧
    ctx.arc(60, 60, 50, 0, Math.PI, false);
    ctx.stroke();
    // 绘制一个圆弧
    ctx.arc(300, 300, 50, 0, Math.PI*2, false);
    ctx.stroke();
</script>

在这里插入图片描述

关闭路径其实并不是必须的,对于新路径其实每次都开启新路径就ok。

<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    // 绘制一段圆弧
    ctx.beginPath() // 开启路径
    ctx.arc(60, 60, 50, 0, Math.PI, false);
    ctx.stroke();
    // 绘制一个圆弧
    ctx.beginPath() // 开启路径
    ctx.arc(300, 300, 50, 0, Math.PI*2, false);
    ctx.stroke();
   
</script>

在这里插入图片描述

<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    ctx.beginPath() 
      ctx.arc(60, 60, 50, 0, Math.PI, false);
      ctx.strokeStyle="pink";
      ctx.closePath() 
      ctx.stroke();
</script>

在这里插入图片描述

椭圆ellipse()

ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)

  • x、y:椭圆的圆心位置
  • radiusX、radiusY:x轴和y轴的半径
  • rotation:椭圆的旋转角度,以弧度表示
  • startAngle:开始绘制点
  • endAngle:结束绘制点
  • anticlockwise:绘制的方向,默认顺时针,可选参数。

贝塞尔曲线

贝塞尔曲线一般用来绘制复杂有规律的图形,通常被用于画曲线。

常见的贝塞尔曲线:起点一般由moveTo()lineTo()提供

  • 二次贝塞尔quadraticCurveTo(cx,cy,x,y)
    • (cx,cy)表示控制点的坐标
    • (x,y)表示结束点的坐标
  • 三次贝塞尔bezierCurveTo(cx1,cy1,cx2,cy2,x,y)
    • (cx1,cy1)表示控制点1
    • (cx2,cy2)表示控制点2
    • 结束点

可以通过二次/三次贝塞尔曲线调试工具查看效果

二次贝塞尔案例

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.moveTo(50, 50);//起点
ctx.quadraticCurveTo(200, 200, 350, 50);//控制点
ctx.stroke();//结束点

在这里插入图片描述

三次贝塞尔案例

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.moveTo(50, 200);
ctx.bezierCurveTo(150, 50, 250, 350, 350, 200);
ctx.stroke();

在这里插入图片描述

线条的操作

  • lineWidth设置当前绘线的粗细,属性值为正数,默认值为1,单位为px
  • lineCap设置线段端点显示的样子。
    • butt:默认值,默认无处理
    • round:每条线的开始处和结尾处都增加一个半圆,半圆的直径为线宽
    • square:每条线的开始处和结尾处都增加一个长方形,长为线宽的一半,高为线宽
  • lineJoin设置两条线条交接处样式
    • miter:默认是尖角
    • round:圆角,圆角所在圆的直径等于线宽
    • bevel:斜角,斜角所在正方形的对角线长等于线宽
  • setLineDash(array)定义线条的虚实样式
    • [虚线长度px,空白长度px,…(重复)]
  • getLineDash() 返回当前虚线设置的样式
  • lineDashOffset 设置虚线样式的起始偏移量

在同一个路径中,状态会被一直使用。所以如果需要定义一个新的线条样式,使用beginPath()方法开启一个新路径。

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
       // lineJoin 值为 miter
       ctx.beginPath()
      ctx.lineWidth = 40;
      ctx.lineJoin='miter'
      ctx.moveTo(50, 20);
      ctx.lineTo(100, 60);
      ctx.lineTo(150, 20);
      ctx.lineTo(200, 60);
      ctx.lineTo(250, 20);
      ctx.stroke();
      ctx.closePath();
      // lineJoin 值为 round
      ctx.beginPath()
      ctx.lineWidth = 40;
      ctx.lineJoin='round'
      ctx.moveTo(50, 100);
      ctx.lineTo(100, 140);
      ctx.lineTo(150, 100);
      ctx.lineTo(200, 140);
      ctx.lineTo(250, 100);
      ctx.stroke();
      ctx.closePath();
      // lineJoin 值为 bevel
      ctx.beginPath()
      ctx.lineWidth = 40;
      ctx.lineJoin='bevel'
      ctx.moveTo(50, 180);
      ctx.lineTo(100, 220);
      ctx.lineTo(150, 180);
      ctx.lineTo(200, 220);
      ctx.lineTo(250, 180);
      ctx.stroke();
      ctx.closePath();

在这里插入图片描述

渐变

线性渐变

  1. createLinearGradient(x1, y1, x2, y2) 创建LinearGradient渐变对象,参数分别为渐变的起点坐标和终点坐标。
  2. 渐变对象的实例addColorStop(offset, color)添加渐变的颜色,color为颜色,offset表示渐变位置的偏移量(百分比:0~1)。第一次表示渐变的开始颜色,第二次调用表示结束,第三次以上一次结束为起点进行渐变,依次类推。
  3. 将LinearGradient渐变对象赋值给fillStyle属性
  4. 进行绘图fill()fillRect()图形渐变、fillText()文字渐变
gradient1.addColorStop(0, "#00ff00");
gradient1.addColorStop(1, "#ff0000");
ctx.fillStyle = gradient1
ctx.fillRect(0,0,200,200)

径向渐变
ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)参数分别为开始圆的坐标(x0,y0)和半径r0以及结束圆的坐标(x1,y1)和半径r1

图像

Canvas中想绘制图案效果,需要用createPattern(image, type) 方法来实现

  • Image 参数可以是一个 Image 对象,也可以是一个 canvas 对象
  • Type 为图案绘制的类型,可用的类型分别有:repeat,repeat-x,repeat-y 和 no-repeat。
// 获取绘图上下文
const ctx = canvas.getContext('2d');
// 创建一个 image对象
const img = new Image();
img.src = "./image.png";
img.onload = function() {
// 图片加载完以后
// 创建图案
const ptrn = ctx.createPattern(img, 'no-repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 500, 500);
}

绘制文本

canvas 中提供了两种方法来渲染文本①描边②填充

  • ctx.strokeText(text, x, y, maxWidth)
    • text绘制的文案
    • x、y文本的起始位置
    • maxWidth可选参数,最大宽度。当文案大于最大宽度时不是裁剪或者换行,而是缩小字体。
  • ctx.fillText(text, x, y, maxWidth)
    • text绘制的文案
    • x、y文本的起始位置
    • maxWidth可选参数,最大宽度。当文案大于最大宽度时不是裁剪或者换行,而是缩小字体。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.font = "50px serif"; // 设置文案大小和字体
ctx.strokeText("Canvas", 100, 100);
ctx.fillText("Canvas", 100, 100);

文本样式

  • font属性:绘制文案大小和字体,默认”10px sans-serif“
  • textAlign属性:文本对齐的方式。可选值为:left、right、center、start(默认)和end。
  • direction属性:文本的方向。可选值为:ltr(从左向右)、rtl(从右向左)、inherit(根据情况继承 Canvas元素或者 Document ,默认)
  • textBaseline属性:基线对齐选项,决定文字垂直方向的对齐方式。可选值为:top、hanging、middle、alphabetic(默认)、ideographic和bottom。

direction 属性会对 textAlign 属性产生影响。如果 direction 属性设置为 ltr,则textAlign属性的 left 和 start 的效果相同,right 和 end 的效果相同,如果 direction 属性设置为 rtl,则 textAlign属性的 left 和 end 的效果相同,right 和 start 的效果相同。

阴影

  • shadowOffsetX、shadowOffsetY设定阴影在 X 和 Y 轴的延伸距离,不受变换矩阵影响。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
  • shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,不受变换矩阵的影响,默认为 0。
  • shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。

图片操作

drawImage()

drawImage可以将图片导入Canvas进行平铺、切割、像素处理等操作。
必须等图片载入完成后开始绘制

drawImage()的用法有三种,根据不同的传参实现不同的功能。

  • image:绘制到上下文(页面)的图片,可以是页面中的img元素,也可以是JavaScript创建的image对象。
  • sx、sy(source):裁剪框的左上角X轴坐标和Y轴坐标
  • sWidth、sHeight:裁剪框的宽度和高度。
  • dx、dy(destination):绘制到上下文(页面)的元素,在上下文中(页面)左上角的X轴坐标和Y轴坐标。
  • dWidth、dHeight:绘制到上下文(页面)的元素,在上下文(页面)中绘制的宽度和高度。如果不说明,在绘制时image宽度和高度不会缩放。

绘制
drawImage(image,dx,dy):单纯的绘制功能,可以绘制图片、视频和别的Canvas对象等。

//从javaScript动态创建
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image(); //创建image对象
    img.src = '';
    //图片载入完成后开始绘制
    img.onload = function(){
        ctx.drawImage(img, 0, 0);
}
//来自img元素,优点在于JavaScript执行时图片已经加载完成,一般会使用css隐藏图片元素,可以避免在DOM中再显示一次图片

缩放
drawImage(image, dx, dy, dWidth, dHeight):dWidth和dHeight可以控制绘制元素的大小。

裁剪
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)可以裁剪图片后绘制

裁剪 clip()

clip() 将当前正在构建的路径转换为当前的裁剪路径,不支持Canvas自带的两个方法strokeRect()fillRect(),只能用rect()

默认情况下,canvas 有一个与它自身一样大的裁剪路径(也就是没有裁剪效果)。现在可以通过clip()来创建一个裁剪路劲(也就有裁剪效果了)。裁剪的作用是遮罩,用来隐藏不需要的部分,所有在路径以外的部分都不会在 canvas 上绘制出来。

裁剪路径不会在 canvas 上绘制东西,永远不受新图形的影响。超过剪切区域的部分不会被显示。

案例
1.绘制基本图形作为裁剪路径
2.使用clip()方法
3.绘制图片

    //1.绘制基本图片,用于裁剪
    ctx.arc(200,200,50,0,360*Math.PI/180,true);
    ctx.stroke();
    //2.创建裁剪路径
    ctx.clip()
    //3.绘制图片
    const img = new Image(); //创建image对象
    img.src = '';
    img.onload = function(){
        ctx.drawImage(img, 0, 0);
    }

像素

getImageData()获取一张图的像素

CanvasRenderingContext2D.getImageData(x,y,width.height) 返回一个 ImageData 对象,用来描述 canvas 区域隐含的像素数据。
这个区域通过矩形表示,x、y为左上角的横纵坐标,width和height表示所选区域的宽度和高度。

const imgData = ctx.getImageData(x, y, width, height);

ImageData 对象会有三个属性

  • height:使用像素描述 ImageData 的实际高度,这个值等于 getImageData() 方法中的参数 height
  • width:使用像素描述 ImageData 的实际高度,这个值等于 getImageData() 方法中的参数 width
  • data:一个一维数组,保存像素数据,每4个数(R红G绿B蓝A透明度)存储1个像素的RGBA颜色值。ImageData.data.length表示一张图的像素总和。
    在这里插入图片描述
    说明
  • getImageData() 方法不允许操作此域名外的图片/视频资源
    • 可以将图片转换成base64编码,直接把base64编码赋值给图片的src属性就可以简单的解决这个问题了。

putImageData()设置一张图的像素

putImageData(image,x,y):image表示重新绘制的图形ImageData对象,x,y分别表示重新绘制的图形左上角的横坐标、纵坐标。

使用场景:通过getImageData获取到imageData后,然后进行处理,再通过putImageData绘制到canvas上,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值