使用canvas

了解如何正确使用canvas画布,以及通过canvas绘制图形及动画。

通过本节,你将学会:

快应用的canvas功能由两部分组成,canvas组件和渲染脚本。

canvas组件中,用于绘制图形的部分,称之为画布。

和其他组件一样,在快应用template中添加即可。同时可为其添加需要的样式。

这里需要注意,与HTML中canvas不同的是:

单独的canvas组件仅仅是一个透明矩形,我们需要通过渲染脚本来进一步操作。

首先通过$element和id来获取canvas组件节点,再通过getContext方法创建canvas绘图上下文。

getContext方法的参数目前仅支持'2d',创建的canvas绘图上下文是一个CanvasRenderingContext2D对象。

在后续脚本中操作该对象即可绘制图形。

完整示例代码如下:

如果你想进入页面即渲染canvas,只能在onShow中获取canvas组件节点,绘制图形。

输出效果如图

开始画图之前,需要了解一下画布的坐标系。

如下图所示,坐标系原点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。x轴向右递增,y轴向下递增。

canvas绘图的基本绘制方式之一是填充绘制。

填充是指用指定的内容填满所要绘制的图形,最终生成一个实心的图案。

canvas绘图的另一种基本绘制方式是描边绘制。

描边绘制是指,沿着所要绘制的图形边缘,使用指定的内容进行描绘,最终生成的是空心的图案。

如果既要填充又要描边,则需要分别绘制两次完成最终图案。

矩形,是最基础的形状。canvas提供了三种方法绘制矩形:

与绘制矩形的直接绘制不同,绘制路径需要一些额外的步骤。

为此,我们需要了解以下一些基本方法。

开始一条新路径,这是生成路径的第一步操作。

一条路径本质上是由多段子路径(直线、弧形、等等)组成。而每次调用beginPath之后,子路径清空重置,然后就可以重新绘制新的图形。

闭合当前路径。

closePath()不是必须的操作,相当于绘制一条当前位置到路径起始位置的直线子路径。

描边绘制当前路径。

填充绘制当前路径。

当调用fill()时,当前没有闭合的路径会自动闭合,不需要手动调用closePath()函数。调用stroke()时不会自动闭合。

移动笔触。将当前路径绘制的笔触移动到某个坐标点。

相当于绘制一条真正不可见的子路径。通常用于绘制不连续的路径。

调用beginPath()之后,或者canvas刚创建的时候,当前路径为空,第一条路径绘制命令无论实际上是什么,通常都会被视为moveTo。因此,在开始新路径之后建议通过moveTo指定起始位置。

路径绘制命令是实际绘制路径线条的一些命令。包括有:

这里,我们展示一个组合使用的效果,绘制一个快应用的logo。

drawCanvas(){constcanvas=this.$element('newCanvas')constctx=canvas.getContext('2d')constr=20consth=380constp=Math.PIctx.beginPath()ctx.moveTo(r*2,r)ctx.arc(r*2,r*2,r,-p/2,-p,true)ctx.lineTo(r,h-r*2)ctx.arc(r*2,h-r*2,r,p,p/2,true)ctx.lineTo(h-r*2,h-r)ctx.arc(h-r*2,h-r*2,r,p/2,0,true)ctx.lineTo(h-r,r*2)ctx.arc(h-r*2,r*2,r,0,-p/2,true)ctx.closePath()ctx.stroke()consts=60ctx.beginPath()ctx.moveTo(h/2+s,h/2)ctx.arc(h/2,h/2,s,0,-p/2*3,true)ctx.arc(h/2,h/2+s+s/2,s/2,-p/2,p/2,false)ctx.arc(h/2,h/2,s*2,-p/2*3,0,false)ctx.arc(h/2+s+s/2,h/2,s/2,0,p,false)ctx.moveTo(h/2+s*2,h/2+s+s/2)ctx.arc(h/2+s+s/2,h/2+s+s/2,s/2,0,p*2,false)ctx.moveTo(h/2+s/4*3,h/2+s/2)ctx.arc(h/2+s/2,h/2+s/2,s/4,0,p*2,false)ctx.fill()}实现效果如下

通过刚才的例子,我们学会了绘制图形。

但是我们看到,不管是填充还是描边,画出来的都是简单的黑白图形。如果想要指定描绘的内容,画出更丰富的效果应该如何操作呢?

有两个重要的属性可以做到,fillStyle和strokeStyle。顾名思义,分别是为填充和描边指定样式。

在本章节最初的例子里,其实已经看到上色的基本方法,就是直接用颜色作为指定样式。

ctx.fillStyle='rgb(200,0,0)'ctx.fillRect(20,20,200,200)一旦设置了fillStyle或者strokeStyle的值,新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,需要画完一种样式的图形后,重新设置fillStyle或strokeStyle的值。

//填充绘制一个矩形,颜色为暗红色ctx.fillStyle='rgb(200,0,0)'ctx.fillRect(20,20,200,200)//描边绘制另一个矩形,边框颜色为半透明蓝色ctx.strokeStyle='rgba(0,0,200,0.5)'ctx.strokeRect(80,80,200,200)canvas的颜色支持各种CSS色彩值。

渐变色对象可以使用createLinearGradient创建线性渐变,然后使用addColorStop上色。

这里要注意的是,渐变色对象的坐标尺寸都是相对画布的。应用了渐变色的图形实际起到的是类似“蒙版”的效果。

线型可设置的项目包括:

顾名思义,线宽就是描边线条的宽度,单位是像素。

这里要注意两点:

线条的宽度会向图形的内部及外部同时延伸,会侵占图形的内部空间。在使用较宽线条时特别需要注意图形内部填充部分是否被过度挤压。常用解决方法可以尝试先描边后填充。

可能会出现的半渲染像素点。例如,绘制一条(1,1)到(1,3),线宽为1px的线段,是在x=1的位置,向左右各延伸0.5px进行绘制。但是由于实际最小绘制单位是一个像素点,那么最终绘制出来的效果将是线宽2px,但是颜色减半的线段,视觉上看就会模糊。常用解决方法,一种是改用偶数的线宽绘制;另一种可以将线段绘制的起始点做适当偏移,例如偏移至(1.5,1)到(1.5,3),左右各延伸0.5px后,正好布满一个像素点,不会出现半像素渲染了。

端点样式决定了线段端点显示的样子。从上至下依次为butt,round和square,其中butt为默认值。

这里要注意的是,round和square会使得线段描绘出来的视觉长度,两端各多出半个线宽,可参考蓝色辅助线。

交点样式决定了图形中两线段连接处所显示的样子。从上至下依次为miter,bevel和round,miter为默认值。

在上图交点样式为miter的展示中,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。

miterLimit属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,交点样式会自动变成了bevel。

drawLineDashCanvas(){constcanvas=this.$element('linedash-canvas')constctx=canvas.getContext('2d')letoffset=0//绘制蚂蚁线setInterval(()=>{offset++if(offset>16){offset=0}ctx.clearRect(0,0,300,300)//设置虚线线段和间隙长度分别为4px2pxctx.setLineDash([4,2])//设置虚线的起始偏移量ctx.lineDashOffset=-offsetctx.strokeRect(10,10,200,200)},20)}运行效果如下

通过学习,我们为刚才绘制的快应用logo添加颜色和样式。

和绘制图形类似,快应用canvas也提供fillText和strokeText两种方法来绘制文字。

可以直接使用符合CSSfont语法的字符串作为文字样式的字体属性。默认值为'10pxsans-serif'。

要注意的是,不同于web,目前快应用还无法引入外部字体文件,对于字体的选择,仅限serif、sans-serif和monosapce。

这两个属性控制了文体相对与绘制定位点的对齐方式。

为了能够在canvas中使用图片,需要使用图像对象来加载图片。

src既可以使用URI来加载本地图片,也使用URL加载网络图片。

为避免图片未加载完成或加载失败导致填充错误,建议在加载成功的回调中进行图片填充操作。

img.onload=()=>{ctx.drawImage(img,0,0)}使用drawImage绘制图片也有3种不同的基本形式,通过不同的参数来控制。

drawImage(image,x,y)其中image是加载的图像对象,x和y是其在目标canvas里的起始坐标。

这种方法会将图片原封不动的绘制在画布上,是最基本的绘制方法。

drawImage(image,x,y,width,height)相对基础方法,多了两个width、height参数,指定了绘制的尺寸。

这种方法会将图片缩放成指定的尺寸后,绘制在画布上。

drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)其中image与基础方法一样,是加载的图像对象。

其它8个参数可以参照下方的图解,前4个是定义图源的切片位置和尺寸,后4个则是定义切片的目标绘制位置和尺寸。

图片不仅仅可以直接绘制在画布中,还可以将图片像渐变色一样,作为绘制图形的样式,在填充和描边绘制中使用。

首先,需要通过createPattern创建图元对象,然后就可以将图元对象作为样式用在图形的绘制中了。

同样,为避免图片未加载完成或加载失败导致填充错误,建议在加载成功的回调中进行操作。

我们不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分(清除区域不仅限于矩形,像clearRect()方法做的那样)以及更多其他操作。

globalCompositeOperation=type

这个属性设定了在画新图形时采用的遮盖策略,其值是一个用于标识不同遮盖方式的字符串。

这是默认设置,并在现有画布上下文之上绘制新图形。

新图形只在与现有画布内容重叠的地方绘制。

新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。

在不与现有画布内容重叠的地方绘制新图形。

在现有的画布内容后面绘制新的图形。

现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。

现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。

现有内容保持在新图形不重叠的地方。

两个重叠图形的颜色是通过颜色值相加来确定的。

只显示新图形。

图像中,那些重叠和正常绘制之外的其他地方是透明的。

已有的内容不受影响。

要取消裁切路径的效果,可以绘制一个和画布等大的矩形裁切路径。

//绘制一个红色矩形ctx.fillStyle='rgb(200,0,0)'ctx.fillRect(20,20,200,200)//使用裁切路径绘制一个圆ctx.beginPath()ctx.arc(120,120,120,0,Math.PI*2,true)ctx.clip()//绘制一个蓝色矩形,超出圆形裁切路径之外的部分无法绘制ctx.fillStyle='rgba(0,0,200)'ctx.fillRect(80,80,200,200)运行效果如下

到目前位置,我们所有的绘制,都是基于标准坐标系来绘制的。

标准坐标系的特点是:

现在介绍的变形,就是改变标准坐标系的方法。

for(leti=0;i<6;i++){ctx.fillRect(0,0,40,40)ctx.translate(50,0)}运行效果如图。

可以看到,虽然每次fillRect绘制的参数没有变化,但是因为坐标系变了,最终绘制出来的就是位置不同的图形。

通过前面的学习,我可以看到,每次图形绘制其实都带着非常丰富的状态。

在绘制复杂图形的时候,就会带来重复获取样式的问题。

如何优化呢?

ctx.save()//保存ctx.restore()//恢复canvas状态就是当前所有样式的一个快照。

save和restore方法是用来保存和恢复canvas状态的。

canvas状态存储在栈中,每次save的时候,当前的状态就被推送到栈中保存。

一个canvas状态包括:

你可以调用任意多次save方法。

每一次调用restore方法,上一个保存的状态就从栈中弹出,所有设定都恢复。

ctx.fillRect(20,20,200,200)//使用默认设置,即黑色样式,绘制一个矩形ctx.save()//保存当前黑色样式的状态ctx.fillStyle='#ff0000'//设置一个填充样式,红色ctx.fillRect(30,30,200,200)//使用红色样式绘制一个矩形ctx.save()//保存当前红色样式的状态ctx.fillStyle='#00ff00'//设置一个新的填充样式,绿色ctx.fillRect(40,40,200,200)//使用绿色样式绘制一个矩形ctx.restore()//取出栈顶的红色样式状态,恢复ctx.fillRect(50,50,200,200)//此时状态为红色样式,绘制一个矩形ctx.restore()//取出栈顶的黑色样式状态,恢复ctx.fillRect(60,60,200,200)//此时状态为黑色样式,绘制一个矩形运行效果如下:

之前我们介绍都是静态图像的绘制,接下来介绍动画的绘制方法。

canvas动画的基本原理并不复杂,就是利用setInterval和setTimeout来逐帧的在画布上绘制图形。

在每一帧绘制的过程中,基本遵循以下步骤。

到目前为止,我们尚未深入了解canvas画布真实像素的原理,事实上,你可以直接通过ImageData对象操纵像素数据,直接读取或将数据数组写入该对象中。

在快应用中ImageData对象是一个普通对象,其中存储着canvas对象真实的像素数据,它包含以下几个属性

data属性返回一个Uint8ClampedArray,它可以被使用作为查看初始像素数据。每个像素用4个1bytes值(按照红,绿,蓝和透明值的顺序;这就是"RGBA"格式)来代表。每个颜色值部份用0至255来代表。每个部份被分配到一个在数组内连续的索引,左上角像素的红色部份在数组的索引0位置。像素从左到右被处理,然后往下,遍历整个数组。

Uint8ClampedArray包含高度×宽度×4bytes数据,索引值从0到(高度×宽度×4)-1

例如,要读取图片中位于第50行,第200列的像素的蓝色部份,你会写以下代码:

constblueComponent=imageData.data[50*(imageData.width*4)+200*4+2]你可能用会使用Uint8ClampedArray.length属性来读取像素数组的大小(以bytes为单位):

constmyImageData=ctx.createImageData(width,height)上面代码创建了一个新的具体特定尺寸的ImageData对象。所有像素被预设为透明黑。

你也可以创建一个被anotherImageData对象指定的相同像素的ImageData对象。这个新的对象像素全部被预设为透明黑。这个并非复制了图片数据。

constmyImageData=ctx.getImageData(left,top,width,height)这个方法会返回一个ImageData对象,它代表了画布区域的对象数据,此画布的四个角落分别表示为(left,top),(left+width,top),(left,top+height),以及(left+width,top+height)四个点。这些坐标点被设定为画布坐标空间元素。

你可以用putImageData()方法去对场景进行像素数据的写入。

ctx.putImageData(myImageData,dx,dy)dx和dy参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标。

例如,为了在场景内左上角绘制myImageData代表的图片,你可以写如下的代码:

setGray(){constcanvas=this.$element('new-canvas')constctx=canvas.getContext('2d')constcanvasW=380constcanvasH=380//得到场景像素数据constimageData=ctx.getImageData(0,0,380,380)constdata=imageData.datafor(leti=0;i

了解canvas的特点,现在就可以实现基本组件无法实现的视觉效果。

THE END
1.免费设计在线平面设计工具借助海量免费模板、图片和字体等,轻松创建一切设计。使用零门槛拖拽式编辑器,设计从构想变为现实。简单点击几下,下载或分享设计。 为公众号、抖音、小红书等宣传渠道制作引人入胜的视觉物料,并用Canva可画完成一键发布。 浏览模板 备受全球亿万用户喜爱 1.35亿+ https://www.canva.cn/free/
2.Canva可画在线设计协作平台平面设计作图软件在线设计协作平台Canva可画提供了海量的设计模板,涵盖海报、简历、名片、Logo、PPT、手抄报、二维码、Banner等数十种平面设计场景,更有千款中英文字体及千万张正版图片素材可供使用。精彩设计,随时随地!http://canva.me/
3.Canva可画在线设计协作平台平面设计作图软件在线设计协作平台Canva可画提供了海量的设计模板,涵盖海报、简历、名片、Logo、PPT、手抄报、二维码、Banner等数十种平面设计场景,更有千款中英文字体及千万张正版图片素材可供使用。精彩设计,随时随地!http://www.canva.co/
4.Canva可画StatusWelcome to Canva可画's home for real-time and historical data on system performance.http://canvastatus.cn/
5.Joinourmissiontoempowertheworldtodesign.Canva工作地点 我们是一个全球化的团队,在世界上许多地方都设有办公室,我们支持现场办公和远程办公。 查看所有工作地点 澳大利亚 (69 个在招职位) [View] 澳大利亚 美国 (9 个在招职位) [View] 美国 新西兰 (14 个在招职位) [View] 新西兰 英国 (9 个在招职位) https://www.lifeatcanva.com/zh
6.Canvas:网页上的画布canvas可画网页版Canvas 提供了一个空白的“画布”,通过JavaScript控制,可以在此基础上绘制各种图形、动画甚至是游戏界面。本文将详细介绍 Canvas 的各个方面,包括其基础知识、核心功能以及如何运用这些知识来创建丰富多样的视觉效果。 一、Canvas基础 1.1 定义与初始化 Canvas 是一个 HTML 元素,用于在网页上显示图形内容。要使用 https://blog.csdn.net/chaosweet/article/details/143704806
7.使用canvas来绘制图形既然我们已经设置了 canvas 环境,我们可以深入了解如何在 canvas 上绘制。到本文的最后,你将学会如何绘制矩形,三角形,直线,圆弧和曲线,变得熟悉这些基本的形状。绘制物体到 Canvas 前,需掌握路径,我们看看到底怎么做。http://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes
8.NVIDIACanvasApp:TurnSimpleBrushstrokesintoRealisticUse AI to turn simple brushstrokes into realistic landscape images. Create backgrounds quickly, or speed up your concept exploration so you can spend more time visualizing ideas.https://www.nvidia.com/en-us/studio/canvas/
9.Canvas在线画图插件canvas可编辑拖拽画板。Canvas在线画图插件网页特效,js特效Canvas在线画图插件源码,实用的前端网页js插件,jquery特效,jquery插件下载Canvas在线画图插件网页特效,网页小部件js代码就上bootstrap模板库https://www.bootstrapmb.com/tag/zaixianhuatu
10.使用画布绘制自定义图形(Canvas)显示图形onReady(event: () => void)是Canvas组件初始化完成时的事件回调,调用该事件后,可获取Canvas组件的确定宽高,进一步使用CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象调用相关API进行图形绘制。 Canvas(this.context) .width('100%') .height('100%') .backgroundColor('#https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/arkts-drawing-customization-on-canvas-0000001453684976-V2
11.盘点20个优秀的画布Canvas开源项目Signature Pad 是一个基于 Canvas 实现的签名库 Rough.js 基于 Canvas 的可以绘制出粗略的手绘风格的图形库。 Fabric.js是一个强大且简单的Javascript HTML5 Canvas库。 uCharts 是一款高性能的前端应用图表库 SpriteJS 是一款由360奇舞团开源的跨终端 canvas 绘图框架 https://www.51cto.com/article/756396.html