Canvas 使用
描述
是一门使用 JavaScript 操作 Canvas 元素的技术
<canvas>
是一个行内元素块(inline-block
)- 一般需要在
<canvas>
元素上指定三个属性id
、width
、height
- 默认宽度(300px),默认高度(150px)
- 如果在
CSS
中定义<canvas>
的宽高,在使用JavaScript
获取元素宽高时得到的是默认宽高而非设置的
- 所有操作均使用
W3C
坐标系,而非数学坐标系
<canvas
width="1000"
height="480"
id="canvas"
style="border: 1px dashed #666"
></canvas>
Canvas 与 SVG
Canvas
使用Javascript
动态生成,SVG
使用XML
静态描述Canvas
基于位图(放大后会失真),SVG
基于矢量图(放大后不会失真)- 如果发生修改,
Canvas
会重绘,SVG
不需要重绘
操作步骤
- 获取
Canvas
对象var myCanvas = document.getElementById('canvas')
- 获取上下文环境对象
context
(所有Canvas
图形操作都是基于context
对象的)var ctx = myCanvas.getContext('2d')
- 开始绘制图形
ctx.stroke()
常用属性
width
获取
Canvas
对象的宽度
var myCanvas = document.getElementById('canvas')
console.log(myCanvas.width)
height
获取
Canvas
对象的高度
var myCanvas = document.getElementById('canvas')
console.log(myCanvas.height)
常用方法
getContext("2d")
获取
Canvas 2D
上下文环境对象
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
toDataURL(type)
获取
Canvas
对象产生的位图的字符串
type
:可选参数,表示输出的MIME
类型,如果被省略,将使用image/png
类型
var myCanvas = document.getElementById('canvas')
var imgUrl = myCanvas.toDataURL()
console.log(imgUrl)
上下文全局属性
globalAlpha
定义 Canvas 环境的透明度,对整个画布都起作用
ctx.globalAlpha = '0.3'
globalCompositeOperation
定义全局图形交叉显示方式
ctx.globalCompositeOperation = 'source-over'
属性值 | 说明 |
---|---|
source-over | 默认值,新图形覆盖旧图形 |
source-atop | 只显示新图形中与旧图形重叠的部分以及旧图形的其余部分,其他部分做透明处理 |
source-in | 只显示新图形中与旧图形重叠部分,其他部分做透明处理 |
source-out | 只显示新图形中与旧图形不重叠部分,其他部分做透明处理 |
destination-over | 与 source-over 相反,旧图形覆盖新图形 |
destination-atop | 只显示旧图形中与新图形重叠的部分以及新图形的其余部分,其他部分做透明处理 |
destination-in | 只显示旧图形中与新图形重叠部分,其他部分做透明处理 |
destination-out | 只显示旧图形中与新图形不重叠部分,其他部分做透明处理 |
lighter | 两种图形都显示,在图形重叠部分,颜色由两种图形的颜色值相加后形成 |
copy | 只显示新图形,旧图形做透明处理 |
xor | 两种图形都绘制,其中重叠部分做透明处理 |
darker | 两种图形都挥之,在重叠部分,颜色由两种图形的颜色值相减后形成 |
直线图形
直线
moveTo(x,y)
将画笔移动到
(x,y)
坐标处,然后开始绘图
ctx.moveTo()
lineTo(x,y)
画笔从起点开始画直线,一直画到
(x,y)
坐标处
- 如果之前未设置起点,则
(x,y)
即为之后绘画起点 - 第一次使用该方法后,画笔自动移动到终点,即
(x,y)
坐标的位置
ctx.lineTo()
stroke()
真正开始绘制直线,其他方法只是用来确定坐标位置
ctx.stroke()
描边矩形
strokeStyle
边框颜色属性,有
颜色值
、渐变色
、图案
三种类型的值
strokeStyle
属性必须在strokeRect()
方法调用前定义,否则无效
ctx.strokeStyle = '#f00'
strokeRect(x,y,w,h)
立即绘制描边矩形,前两个参数为矩形左上角坐标,后两个参数分别为矩形的宽度和高度
填充矩形
fillStyle
填充颜色属性,有
颜色值
、渐变色
、图案
三种类型的值
fillStyle
属性必须在fillRect()
方法调用前定义,否则无效
ctx.fillStyle = '#f00'
fillRect(x,y,w,h)
立即绘制填充矩形,前两个参数为矩形左上角坐标,后两个参数分别为矩形的宽度和高度
ctx.fillRect(50, 50, 100, 100)
rect(x,y,w,h)
绘制矩形的另一种方法
该方法调用之后不会立即绘制,而是在其后调用其他方法来实现绘制描边矩形或填充矩形
// 描边矩形
ctx.strokeStyle = '#f00'
ctx.rect(50, 50, 100, 100)
ctx.stroke()
// 上述代码等价于
ctx.strokeStyle = '#f00'
ctx.strokeRect(50, 50, 100, 100)
// 填充矩形
ctx.fillStyle = '#f00'
ctx.rect(50, 50, 100, 100)
ctx.fill()
// 上述代码等价于
ctx.fillStyle = '#f00'
ctx.fillRect(50, 50, 100, 100)
clearRect(x,y,w,h)
清空指定矩形区域,前两个参数为被清空矩形左上角坐标,后两个参数分别为矩形的宽度和高度
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.clearRect(x, y, w, h)
曲线图形
可以用来绘制圆形或者弧线
语法:
arc(x, y, 半径, 开始角度, 结束角度, anticlockwise)
此方法只是对圆的描述,具体绘制是需要调用
stroke()
或者fill()
方法来进行描边或填充
x
、y
:表示圆心的横纵坐标开始角度、结束角度
:以 弧度 为单位,推荐写法角度数 * Math.PI / 180
(可以方便一眼看出角度值)anticlockwise
:布尔值,默认为false
false
:顺时针绘制true
:逆时针绘制
圆形
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.beginPath()
ctx.arc(50, 50, 50, 0, (180 * Math.PI) / 180, true)
ctx.closePath()
// 描边
ctx.strokeStyle = '#00f'
ctx.stroke()
// 填充
ctx.fillStyle = '#f0f'
ctx.fill()
}
弧线
// 方法一:使用 arc() 函数,不用 closePath() 闭合路径
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.beginPath()
ctx.arc(50, 50, 50, 0, (180 * Math.PI) / 180, true)
ctx.strokeStyle = '#f00'
ctx.stroke()
}
// 方法二:使用 arcTo() 函数,待读...
线条操作
必须使用
beginPath()
方法才能开始新的路径,否则之前定义的状态会被一直使用
lineWidth
定义线条宽度,整数,默认为
1
,默认单位px
ctx.lineWidth = 10
lineCap
定义线条开始出和结束处的线帽样式,定义线帽会使线条稍微变长
butt
:(默认值)无线帽,不做任何处理round
:线条开始处和结尾处都增加一个半圆,半圆的直径为线宽square
:线条开始处和结尾处都增加一个长方形,长方形长度为线宽的一半,高度为线宽
ctx.lineCap = 'round'
lineJoin
定义两个线条交接处样式
miter
:(默认值)线条在交接处延伸至交于一点round
:交接处是一个圆角,远交所在圆的直径等于线宽bevel
:交接处是一个斜角,斜角所在正方形的对角线长等于线宽
ctx.lineJoin = 10
setLineDash(array)
定义线条的虚实样式,参数是一个数组组合,数组元素为线条长度和空白长度的重复排列
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.moveTo(20, 20)
ctx.lineTo(180, 20)
ctx.setLineDash([2, 2])
ctx.stroke()
ctx.beginPath()
ctx.moveTo(20, 40)
ctx.lineTo(180, 40)
ctx.setLineDash([5, 5])
ctx.stroke()
ctx.beginPath()
ctx.moveTo(20, 60)
ctx.lineTo(180, 60)
ctx.setLineDash([10, 5])
ctx.stroke()
ctx.beginPath()
ctx.moveTo(20, 80)
ctx.lineTo(180, 80)
ctx.setLineDash([10, 5, 5, 5])
ctx.stroke()
ctx.beginPath()
ctx.moveTo(20, 100)
ctx.lineTo(180, 100)
ctx.setLineDash([10])
ctx.stroke()
}
文本操作
font
定义字体样式(大小、粗细等)
ctx.font = 'font-style font-weight font-size/line-height font-family'
ctx.font = '30px bold 微软雅黑'
textAlign
定义文本水平对齐方式
start
和end
与阅读方向有关,从左到右阅读,start
对应左边,end
对应右边。从右到左阅读,start
对应右边,end
对应左边
left
和right
始终是指文字的左右方向,与阅读方向无关
start
:文本在指定的横坐标开始end
:文本在指定的横坐标结束left
:文本左对齐(类似于start
)right
:文本右对齐(类似于end
)center
:文本的中心在指定的横坐标
textBaseline
定义文本垂直对齐方式
alphabetic
:(默认)文本基线是普通英文字母的基线top
:文本基线是em
方框的顶端middle
:文本基线是em
方框的中心bottom
:文本基线是em
方块的底端
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var text = '测试'
ctx.font = '20px bold'
ctx.textBaseline = 'alphabetic'
ctx.fillText(text, 20, 60)
var text1 = '文本'
ctx.font = '20px bold'
ctx.textBaseline = 'top'
ctx.fillText(text1, 60, 60)
var text2 = '对齐'
ctx.font = '20px bold'
ctx.textBaseline = 'middle'
ctx.fillText(text1, 100, 60)
var text3 = '方式'
ctx.font = '20px bold'
ctx.textBaseline = 'bottom'
ctx.fillText(text1, 140, 60)
}
fillStyle
定义画笔填充路径的颜色,与
fillText()
配合使用,用于绘制填充文本
x ctx.fillStyle = "#f00"
strokeStyle
定义画笔描边路径的颜色,与
strokeStyle()
配合使用,用于绘制描边文本
ctx.strokeStyle = '#f00'
direction
当前文本方向,此功能某些浏览器尚在开发中,存在兼容性问题
ltr
:文本方向从左向右rtl
:文本方向从右向左inherit
:根据情况继承<canvas>
元素或者Document
ctx.direction = 'ltr' || 'rtl' || 'inherit'
fillText()
绘制填充文本
text
:要绘制的字符串文本x
:要绘制文本的横坐标,也就是文本最 左 边的坐标y
:要绘制文本的纵坐标,也就是文本最 下 边的坐标maxWidth
:可选,表示允许的文本最大宽度,单位px
,如果文本超过maxWidth
会被压缩至maxWidth
的宽度
ctx.fillText(text, 30, 60, 100)
strokeText(text,x,y,maxWidth)
绘制描边文本
text
:要绘制的字符串文本x
:要绘制文本的横坐标,也就是文本最 左 边的坐标y
:要绘制文本的纵坐标,也就是文本最 下 边的坐标maxWidth
:可选,表示允许的文本最大宽度,单位px
,如果文本超过maxWidth
会被压缩至maxWidth
的宽度
ctx.strokeText(text, 30, 60, 100)
measureText()
用于 获取文本长度
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var text = '获取文本宽度'
ctx.fillText(text, 30, 60)
var textWidth = ctx.measureText(text).width
console.log(textWidth)
}
图片操作
必须等图片完全载入后才能开始绘制图片
d:destination,目标图片
s:source,源图片
绘制图片
绘制原大小的图片
drawImage(image, dx, dy)
image
:表示页面中的图片,该图片可以是页面中的img
元素,也可以是JavaScript
创建的Image
对象dx
:表示图片左上角的横坐标dy
:表示图片左上角的纵坐标
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 20, 20)
}
// 或
// var image = document.getElementById('image')
// ctx.drawImage(image, 20, 20)
}
绘制固定大小的图片
drawImage(image, dx, dy, dw, dh)
,用于绘制一张大小和原图不一样的图片
前三个参数同
drawImage(image, dx, dy)
dw
:定义图片的宽度dy
:定义图片的高度
ctx.drawImage(image, 20, 20, 100, 80)
复制固定大小的图片
ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh),用于将图片某一部分复制到 Canvas 中,图像只需要加载一次,可以极大提高页面的加载速度
image
、dx
、dy
、dw
、dh
四个参数同drawImage(image, dx, dy)
sx
:表示源图片被截取部分的横坐标sy
:表示源图片被截取部分的纵坐标sw
:表示源图片被截取部分的宽度sh
:表示源图片被截取部分的高度
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 1939, 1447, 2476, 2056, 20, 20, 190, 140)
console.log(myCanvas.toDataURL())
}
}
平铺图片
createPattren(image, type)
image
:表示被平铺的图片对象或其他 Canvas 元素type
:表示图片的平铺方式repeat
:(默认值)在水平方向和垂直方向同时平铺图片repeat-x
:只在水平方向上平铺图片repeat-y
:只在垂直方向上平铺图片no-repeat
:不平铺(只显示一次)
使用图像平铺
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/pingpu.jpg'
image.onload = function () {
var pattern = ctx.createPattern(image, 'repeat')
ctx.fillStyle = pattern
ctx.fillRect(0, 0, myCanvas.width, myCanvas.height)
}
}
使用 canvas 对象平铺
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var canvas = document.createElement('canvas')
canvas.width = 20
canvas.height = 20
var canvasCtx = canvas.getContext('2d')
canvasCtx.beginPath()
canvasCtx.arc(10, 10, 10, 0, 2 * Math.PI)
canvasCtx.closePath()
canvasCtx.fillStyle = '#f00'
canvasCtx.fill()
var pattern = ctx.createPattern(canvas, 'repeat')
ctx.fillStyle = pattern
ctx.fillRect(0, 0, myCanvas.width, myCanvas.height)
}
在文字上平铺图片
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = document.createElement('img')
image.src = 'img/test.jpg'
image.onload = function () {
var text = '获取文本宽度'
ctx.font = '60px bold'
var pattern = ctx.createPattern(image, 'repeat')
ctx.fillStyle = pattern
ctx.fillText(text, 30, 60)
}
}
切割图片或图形
ctx.clip()
,用于切割图片或为 Canvas 划分一个显示区域不支持
strokeRect()
和fillRect()
方法,只能使用fill()
或rect()
等方法代替
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
// 1. 绘制基本图形
ctx.beginPath()
ctx.arc(100, 100, 100, 0, 2 * Math.PI)
ctx.closePath()
ctx.fillStyle = 'transparent'
ctx.fill()
// 2. 使用 clip() 方法,使得切割区域为上面绘制的基本图形
ctx.clip()
// 3. 绘制图片
var image = document.createElement('img')
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 1939, 1287, 2400, 2400, 0, 0, 200, 200)
}
}
变形操作
变形相关方法必须在
fillRect()
等类似绘画动作之前调用,否则无效
平移
ctx.translate(x, y)
x
:表示在x
轴方向运动的距离(带符号),默认单位px
y
:表示在y
轴方向运动的距离(带符号),默认单位px
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.fillStyle = '#f00'
ctx.translate(50, 50)
ctx.fillRect(0, 0, 50, 50)
}
缩放
ctx.scale(x, y)
,一般情况况下x
、y
值都是正数。取值为0~1
时图像缩小,大于1
时图像放大每一次缩小或放大的依据都是上次的图像,图形缩放时,左上角的坐标及线条宽度等其他属性也会跟着缩放
x
:表示图形在x
轴上的缩放倍数y
:表示图形在y
轴上的缩放倍数
旋转
ctx.rotate((角度 * Math.PI) / 180)
- 参数为旋转的角度,使用弧度表示的(Canvas 所有涉及角度的方法,都是用弧度表示的)
- 旋转的中心为
W3C
坐标系原点
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.fillStyle = '#f00'
ctx.fillRect(50, 50, 50, 50)
ctx.rotate((-45 * Math.PI) / 180)
ctx.fillRect(50, 50, 50, 50)
}
// 改变旋转中心
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var i = 0
var revctWidth = 100
var rectHeight = 100
setInterval(() => {
i++
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
ctx.save()
ctx.translate(myCanvas.width / 2, myCanvas.height / 2)
ctx.rotate(Math.PI * (i / 360))
console.log(i)
ctx.fillStyle = '#f00'
ctx.fillRect(-revctWidth / 2, -rectHeight / 2, revctWidth, rectHeight)
ctx.restore()
}, 1)
}
// 有趣的图形
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.translate(150, 0)
ctx.fillStyle = 'rgba(255,0,0,0.25)'
for (let i = 0; i < 100; i++) {
ctx.translate(25, 25)
ctx.scale(0.95, 0.95)
ctx.rotate((18 * Math.PI) / 180)
ctx.fillRect(0, 0, 100, 50)
}
}
像素操作
获取图片像素数据
getImageData(x, y, width, height),该方法返回的是一个
canvasPixelArray
对象(imgData
),对象中有一个data
属性(imgData.data
),这个属性是一个保存了这张图片像素数据的数组,取值为[r1,g1,b1,a1,r2,g2,b2,a2,r3...]
,每 4 个数存存储着 1 个像素的 RGBA 颜色值
x
、y
:表示所选图片区域左上角的横纵坐标width
、height
:表示所选图片区域的宽度和高度
输出图片像素数据
putImageData(image, x, y),简单来说就是在 Canvas 中显示一张图片
image
:表示重新绘制的图形,就是使用getImageData()
获取的canvasPixelArray
对象x
、y
:表示重新绘制图形左上角的横纵坐标
创建像素区域
createImageData(sw, sh)
按 固定宽高 创建一个像素区域
createImageData(imgData)
按照传入 像素对象 的宽高创建一个像素区域
实例
反转颜色
指颠倒图片的颜色
算法:
255 - 原值
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
data[i + 0] = 255 - data[i + 0]
data[i + 1] = 255 - data[i + 1]
data[i + 2] = 255 - data[i + 2]
// 不需要操作透明度值
}
ctx.putImageData(imgData, 394, 0)
}
}
黑白效果
指将图片变成只含黑白灰的颜色
算法:红绿蓝三通道取平均值,然后让三通道都等于这个值,也可以对三通道加权取平均值
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
var average = (data[i + 0] + data[i + 1] + data[i + 2]) / 3
// 加权
// var average = (data[i + 0]*0.3 + data[i + 1]*0.6 + data[i + 2]*0.1) / 3
data[i + 0] = average
data[i + 1] = average
data[i + 2] = average
}
ctx.putImageData(imgData, 394, 0)
}
}
亮度效果
指让图片变得更亮或者更暗
算法:将红绿蓝三个通道同时加上一个正值(变亮)或一个负值(变暗)
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
var value = 50
data[i + 0] += value
data[i + 1] += value
data[i + 2] += value
}
ctx.putImageData(imgData, 394, 0)
}
}
复古效果
指使一张图片有一种复古的效果
算法:分别取 红、绿、蓝 三个通道的某种加权平均值
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
var r = data[i + 0]
var g = data[i + 1]
var b = data[i + 2]
data[i + 0] = r * 0.39 + g * 0.76 + b * 0.18
data[i + 1] = r * 0.35 + g * 0.68 + b * 0.16
data[i + 2] = r * 0.27 + g * 0.53 + b * 0.13
}
ctx.putImageData(imgData, 394, 0)
}
}
红色蒙版
指让图片呈现一种偏红的效果
算法:将红通道赋值为 红、绿、蓝 三通道的平局值,且将 绿、蓝 两个通道都赋值为
0
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
var average = (data[i + 0] + data[i + 1] + data[i + 2]) / 3
data[i + 0] = average
data[i + 1] = 0
data[i + 2] = 0
}
ctx.putImageData(imgData, 394, 0)
}
}
透明效果
使图片变得透明,只需要改变 alpha 通道的值
不能使用
ctx.globalAlpha
,会对整个 Canvas 其作用
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var image = new Image()
image.src = 'img/test.jpg'
image.onload = function () {
ctx.drawImage(image, 0, 0, 384, 256)
var imgData = ctx.getImageData(0, 0, 384, 256)
var data = imgData.data
for (let i = 0; i < imgData.data.length; i += 4) {
data[i + 3] *= 0.3
}
ctx.putImageData(imgData, 394, 0)
}
}
渐变
线性渐变
使用
createLinearGradient(x1, y1, x2, y2)
和addColorStop(value, color)
配合实现
- 调用
createLinearGradient(x1, y1, x2, y2)
方法创建一个linearGradient
对象- 如果
y1
、y2
相等,则表示沿水平方向从左到右或从右到左的渐变 - 如果
x1
、x2
相等,则表示沿垂直方向从上到下或从下到上的渐变 - 如果
x1
、x2
不相等,且y1
、y2
也不相等,则沿矩形对角线方向渐变
- 如果
- 对得到的
linearGradient
对象调用 n 次addColorStop(value, color)
方法设置颜色 - 将
linearGradient
对象赋值给fillStyle
属性 - 调用
fill()
、fillRect()
、fillText()
等方法绘制颜色渐变
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var gnt = ctx.createLinearGradient(
0,
myCanvas.height,
myCanvas.width,
myCanvas.height
)
gnt.addColorStop(0, '#f00')
gnt.addColorStop(0.2, '#0f0')
gnt.addColorStop(0.4, '#00f')
gnt.addColorStop(0.6, '#ff0')
gnt.addColorStop(0.8, '#f0f')
gnt.addColorStop(1, '#0ff')
ctx.fillStyle = gnt
ctx.fillRect(0, 0, myCanvas.width, myCanvas.height)
}
径向渐变
使用
createRadialGradient(x1, y1, r1, x2, y2, r2)
和addColorStop(value, color)
配合实现
- 调用
createRadialGradient(x1, y1, r1, x2, y2, r2)
方法创建一个radialGradient
对象x1
、y1
:表示渐变开始时圆心的坐标r1
:表示渐变开始时圆的半径x2
、y2
:表示渐变结束时圆心的坐标r2
:表示渐变结束时圆的半径
- 对得到的
radialGradient
对象调用 n 次addColorStop(value, color)
方法设置颜色 - 将
linearGradient
对象赋值给fillStyle
属性 - 调用
fill()
等方法绘制颜色渐变
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.arc(100, 100, 100, 0, (360 * Math.PI) / 180)
var gnt = ctx.createRadialGradient(100, 100, 100, 150, 50, 50)
gnt.addColorStop(0, '#f00')
gnt.addColorStop(0.2, '#0f0')
gnt.addColorStop(0.4, '#00f')
gnt.addColorStop(0.6, '#ff0')
gnt.addColorStop(0.8, '#f0f')
gnt.addColorStop(1, '#0ff')
ctx.fillStyle = gnt
ctx.fill()
}
阴影
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
ctx.fillStyle = '#f00'
ctx.shadowOffsetX = -20
ctx.shadowOffsetY = -20
ctx.shadowBlur = 10
ctx.shadowColor = '#00f'
ctx.fillRect(100, 100, 100, 100)
}
shadowOffsetX
阴影与图形的水平距离,默认值为
0
,大于0
时向右偏移,小于0
时向左偏移
shadowOffsetY
阴影与图形的垂直距离,默认值为
0
,大于0
时向下偏移,小于0
时向上偏移
shadowColor
阴影的颜色,默认为黑色
shadowBlur
阴影的模糊值,默认为
0
,值越大模糊度越强,值越小模糊度越弱
路径
判断是否属于同一条路径的标准是 是否使用了
beginPath()
方法,而不是视觉上是否有首尾相连
beginPath()
开始一条新路径,并且只有使用此方法开会开始一条新路径
- Canvas 是基于 状态 来绘制图形的,每一次绘制前,Canvas 会检查整个程序定义的所有状态(包括
strokeStyle
、fillStyle
、lineWidth
)等- 当一个状态值没有改变时,Canvas 一直使用最初的状态
- 当一个状态发生改变时
- 如果使用
beginPath()
开始一个新路径,则不同的路径使用不同的值 - 如果没有开始新路径,则后面的值会覆盖前面的值,导致路径使用相同属性,绘制出相同的路径
- 如果使用
ctx.beginPath()
closePath()
关闭当前路径,指将同一个路径的起点与终点连接起来,使其成为一个封闭的图形,并不会开始一条新路径
- 首尾相连的路径,一般最后一步使用
closePath()
进行 关闭,否则可能会在连接点处出现缺口
ctx.closePath()
isPointInPath(x, y)
判断某一个点是否存在于当前路径内
该方法不支持
strokeRect()
和fillRect()
,需要用rect()
代替
- 如果点
(x, y)
在当前路径中,则返回true
- 如果点
(x, y)
不在当前路径中,则返回false
状态
save()
和restore()
一般都是成对出现的
save()
保存当前状态
保存的状态包括三种,分别是 绘图状态、剪切状态、变形状态
不能保存路径状态,如果想开始新的路径,必须使用
beginPath()
该方法只能保存状态,不能保存图形,因为 Canvas 只有一个上下文环境,如果要恢复图形,只能清空画布再重绘
ctx.save()
restore()
回复之前保存的状态
ctx.restore()
事件
鼠标事件
键盘事件
循环事件
图形绘制实例
<canvas
id="canvas"
width="300"
height="300"
style="border: 1px dashed #666"
></canvas>
正多边形
/*
* n:正多边形边数
* dx、dy:表示正 n 边形中心点坐标
* size:表示正 n 边形的大小,也就是外接圆半径
*/
function createPolygon(ctx, n, dx, dy, size) {
ctx.beginPath()
var degree = (2 * Math.PI) / n
for (var i = 0; i < n; i++) {
var x = Math.cos(i * degree)
var y = Math.sin(i * degree)
ctx.lineTo(x * size + dx, y * size + dy)
}
ctx.closePath()
}
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var i = 3
var timer = setInterval(() => {
if (i == 100) {
clearInterval(timer)
}
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
createPolygon(ctx, i, 100, 75, 50)
ctx.fillStyle = 'HotPink'
ctx.fill()
i++
}, 200)
}
五角形
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
createStar(ctx, 25, 50)
}
/*
* r1:五角形内接圆半径
* r2:五角形外接圆半径
*/
function createStar(ctx, r1, r2) {
ctx.beginPath()
for (var i = 0; i < 5; i++) {
ctx.lineTo(
Math.cos(((18 + i * 72) * Math.PI) / 180) * r2 + 100,
-Math.sin(((18 + i * 72) * Math.PI) / 180) * r2 + 100
)
ctx.lineTo(
Math.cos(((54 + i * 72) * Math.PI) / 180) * r1 + 100,
-Math.sin(((54 + i * 72) * Math.PI) / 180) * r1 + 100
)
}
ctx.closePath()
ctx.stroke()
}
调色板
window.onload = function () {
var myCanvas = document.getElementById('canvas')
var ctx = myCanvas.getContext('2d')
var r = 255
var g = 0
var b = 0
for (var i = 0; i < 150; i++) {
if (i < 25) {
g += 10
} else if (i > 25 && i < 50) {
r -= 10
} else if (i > 50 && i < 75) {
g -= 10
b += 10
} else if (i > 75 && i < 100) {
r += 10
} else {
b -= 10
}
ctx.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')'
ctx.fillRect(3 * i, 0, 3, myCanvas.height)
}
}