前端笔记 — canvas

一. 基本用法

在HTML中添加<canvas>元素,必须设置width跟height属性

<canvas id="drawing" width="200" height="200">A drawing of something</canvas>

如果浏览器不支持canvas元素,就会显示标签中间的内容
要在画布上绘图,需要取得绘图上下文,调用getContext('2d')就可以取得canvas的2d上下文

let drawing = document.getElementById("drawing")
let context = drawing.getContext("2d")

使用toDataURL方法可以导出canvas上绘制的图像,接受一个参数,图像的MIME类型格式

let imgURL = drawing.toDataURL("image/png") // 将imgURL赋值给一个img元素的src属性就可以显示了

常用的属性控制

  • lineWidth:设置线条的宽度,可以是任意整数
  • lineCap:设置线条末端的形状,butt(平头)、round(圆头)、square(方头)
  • lineJoin:设置线条相交的方式,round(圆交)、斜交(bevel)、miter(斜接)

二.绘制矩形

矩形是唯一一种可以直接在上下文中绘制的形状
与矩形有关的方法包括fillRect()、strokeRect()和clearRect(),这三个方法接受4个参数(x, y, width, height)
fillRect()绘制的矩形会填充指定的颜色,颜色通过fillStyle属性指定

context.fillStyle = 'red'
context.fillRect(10, 10, 50, 50)

strokeRect()绘制的矩形会使用指定的颜色描边,描边颜色通过strokeStyle属性指定

context.strokeStyle = '#ff0000'
context.strokeRect(30, 30, 50, 50)

clearRect()方法用于清除画布上的矩形区域

context.fillStyle = 'green'
context.fillRect(10, 10, 50, 50)
context.fillStyle = 'red'
context.fillRect(30, 30, 50, 50)
context.clearRect(40, 40, 10, 10)

三.绘制路径

要绘制路径,首选必须调用beginPath()方法,表示开始绘制新路径,绘制路径主要有以下方法

  • arc(x, y, radius, startAngle, endAndle, counterclockwise):以(x, y)为圆心绘制一条弧线,半径为radius,起始和结束角度分别为startAngle和endAngle,最后一个参数表示顺时针还是逆时针,false表示顺时针
  • arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2, y2)为止,并且穿过(x1, y1)
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x, y)为止,并且以(c1x, c1y)和(c2x, c2y)为控制点
  • lineTo(x, y):从上一点开始绘制一条直线,到(x, y)为止
  • moveTo(x, y):将绘图游标移动到(x, y),不画线
  • quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x, y)为止,并且以(cx, cy)为控制点
  • rect(x, y, width, height):从点(x, y)开始绘制矩形,宽为width,高为height,这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()绘制的独立矩形

调用closePath()可以将路径的起点与终点连接。路径完成后,可以使用fill()填充,或者使用stroke()描边。最后还可以调用clip(),在路径上创建一个剪切区域

四.绘制文本

绘制文本主要有两个方法,fillText()和strokeText(),这个两个方法接受4个参数:要绘制的文本字符串、x坐标、y坐标和可选的最大像素宽度。这两个方法都以下列3个属性为基础

  • font:表示文本样式、大小及字体,用css中指定字体的格式来指定,例如"bold 10px Arial"
  • textAlign:表示文本的对齐方式。可能值有"start"、"end"、"left"、"right"和"center"。
  • textBaseline:表示文本的基线。可能值有"top"、"hanging"、"middle"、"alphabetic"、"ideographic"和"bottom"

上下文提供了辅助确定文本大小的方法measureText(),这个方法接受一个参数,即要绘制的文本,返回一个TextMetrics对象,这个对象有一个width属性,表示文本的宽度

五.变换

为上下文应用变换,会导致使用不同的变换矩阵应用处理,从而产生不同的结果,可以通过如下方法来修改变换矩阵

  • rotate(angle):围绕原点旋转图像angle弧度
  • scale(scaleX, scaleY):缩放图像,默认值都是1.0
  • translate(x, y):将原点移动到(x, y)
    有两个方法可以追踪上下文的状态变化。save()方法将当前上下文的所有状态存入一个栈结构,restore()方法在保存状态的栈结构中向前返回一级

六.绘制图像

如果想把一副图像绘制到画布上,可以使用drawImage()方法,调用这个方法时,可以使用三种不同的参数组合,最简单的方式是传入一个<img>元素,以及绘制该图像的起点x和y坐标

let image = document.images[0] // 获取文档中的第一幅图像
context.drawImage(image, 10, 10) // 将图像绘制到画布上,起点为(10, 10),大小与原始大小一样

可以多传入两个参数,表示目标宽度和高度

context.drawImage(image, 10, 10, 100, 100) // 绘制的图像大小为100x100像素

还可以把图像中的某个区域绘制到上下文中,需要传入9个参数:要绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度

context.drawImage(image, 50, 50, 80, 80, 10, 10, 50, 50)

除了给drawImage()方法传入<img>元素外,还可以传入另一个<canvas>元素作为其第一个参数。结合drawImage()和其他方法,可以对图像进行各种基本操作,操作的结果可以通过toDataURL()方法获得,toDataURL()是canvas的方法而不是上下文的方法

七.阴影

上下文会根据以下几个属性,自动为形状或路径绘制阴影,需要在绘制路径之前设置

  • shadowColor:阴影颜色,默认为黑色
  • shadowOffsetX:形状或路径x轴方向的阴影偏移量,默认为0
  • shadowOffsetY:形状或路径y轴方向的阴影偏移量,默认为0
  • shadowBlur:模糊的像素数,默认0,即不模糊

八.渐变

渐变有CanvasGradient实例表示,要创建一个新的线性渐变,可以调用createLinearGradient()方法,接受4个参数:startX、startY、endX、endY。创建渐变后,使用addColorStop()方法来指定色标,接受两个参数:色标位置和css颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字

let gradient = context.createLinearGradient(30, 30, 70, 70)
gradient.addColorStop(0, 'white')
gradient.addColorStop(1, 'black')

表示从一个画布上的点(30, 30)到点(70, 70)的渐变。起点的色标是白色,终点的色标是黑色。然后可以把fillStyle或者strokeStyle设置为这个对象,从而使用渐变来绘制形状或描边

要创建径向渐变,可以使用createRadialGradient()方法,接受6个参数,对应着两个圆的圆心和半径

九.模式

模式其实就是重复的图像,可以用来填充或描边图像,使用createPattern()方法并传入两个参数:一个<img>元素和一个表示如何重复图像的字符串。其中第二个参数的值与css的background-repeat属性值相同,包括“repeat”、“repeat-x”、“repeat-y”和“no-repeat”

模式与渐变一样,都是从画布的原点(0, 0)开始的,将填充样式设置为模式对象,只表示在某个特定的区域内显示重复的图像,而不是要从某个位置开始绘制重复图像

十.使用图像数据

上下文可以通过getImageData(x, y, width, height)取得原始图像数据

let imageData = context.getImageData(10, 5, 50, 50) // 取得左上角坐标为(10, 5),大小为50x50像素的区域的图像数据

这里返回的对象是ImageData的实例,每个ImageData对象都有三个属性:width、height和data。其中data是一个数组,保存着图像中每一个像素的数据。

在data数组中,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度。因此第一个像素的数据保存在数组的第0到第3个元素中,数组中的每个元素的值都介于0到255之间(包括0和255)
putImageData()方法可以将imageData表示的图像绘制到画布上

十一.合成

globalAlpha:用于指定所有绘制的透明度,是一个介于0到1之间的值,默认值为1
如果所有的后续操作都要基于相同的透明度,可以先把globalAlpha设置为适当的值,然后绘制

globalCompositionOperation:表示后绘制的图形怎样与先绘制的图形结合,可能的值如下

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

推荐阅读更多精彩内容

  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,658评论 2 32
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    Looog阅读 3,932评论 3 40
  • 最基本的使用创建一个画布所有的操作都在画布的context上面canvas是基于状态而不是基于对象的,比如说颜色都...
    亲爱的孟良阅读 1,647评论 0 4
  • HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.<canvas>...
    joker731阅读 517评论 0 0
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,472评论 16 22