canvas元素
- canvas标签
如果不给 设置 widht、height 属性时,则默认 width为300、height 为 150,单位都是 px。
也可以使用 css 属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现扭曲。
所以,建议永远不要使用 css 属性来设置 的宽高。
<canvas class="box" id="demo1" width="400" height="400"></canvas>
- 替代内容
支持 的浏览器会只渲染 标签,而忽略其中的替代内容。不支持 的浏览器则 会直接渲染替代内容。 - 结束标签
如果结束标签不存在,则文档的其余部分会被认为是替代内容,将不会显示出来。
<canvas class="box" id="demo1" width="400" height="400">
<img src="./html.gif" alt="不支持canvas时替代的图片内容">
</canvas>
渲染上下文+检测浏览器支持性
var canvas = document.getElementById('demo1')
if (canvas.getContext) {
var ctx = canvas.getContext('2d')
alert('支持canvas')
} else {
alert('不支持canvas')
}
绘制矩形
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.fillRect(540, 0, 100, 100)
ctx.strokeRect(660, 0, 200, 100)
ctx.fillStyle = 'rgb(255,0,0)'
ctx.fillRect(0, 0, 200, 100)
ctx.clearRect(50, 50, 30, 30)
ctx.strokeStyle = 'rgb(0,255,0)'
ctx.strokeRect(220, 0, 300, 100)
}
draw()
![在这里插入图片描述](https://img-blog.csdnimg.cn/0e0d2c8e46874637979952f16253afa0.png)
绘制路径
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(50, 50)
ctx.closePath()
ctx.stroke()
ctx.beginPath()
ctx.moveTo(60, 10)
ctx.lineTo(100, 10)
ctx.lineTo(100, 50)
ctx.lineTo(60, 10)
ctx.closePath()
ctx.stroke()
ctx.beginPath()
ctx.moveTo(110, 10)
ctx.lineTo(110, 50)
ctx.lineTo(160, 50)
ctx.lineTo(110, 10)
ctx.closePath()
ctx.fillStyle = 'rgb(0,0,255)'
ctx.fill()
ctx.beginPath()
ctx.arc(200, 30, 30, 0, Math.PI * 2, true)
ctx.closePath()
ctx.strokeStyle = 'rgb(0,255,0)'
ctx.stroke()
ctx.beginPath()
ctx.arc(270, 30, 30, 0, -Math.PI, false)
ctx.closePath()
ctx.strokeStyle = 'rgb(255,0,0)'
ctx.stroke()
ctx.beginPath()
ctx.arc(340, 30, 30, 0, -Math.PI / 2, true)
ctx.closePath()
ctx.strokeStyle = 'rgb(0,200,0)'
ctx.stroke()
ctx.beginPath();
ctx.moveTo(410, 0);
ctx.arcTo(450, 0, 450, 40, 50);
ctx.lineTo(450, 40)
ctx.arcTo(450, 80, 490, 80, 50)
ctx.lineTo(490, 80)
ctx.strokeStyle = 'rgb(100,100,200)'
ctx.stroke();
ctx.beginPath()
ctx.moveTo(500, 50)
ctx.quadraticCurveTo(600, 10, 660, 70)
ctx.strokeStyle = 'rgb(200,200,100)'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(670, 60)
ctx.bezierCurveTo(650, 20, 700, 30, 720, 80)
ctx.strokeStyle = 'rgb(125,125,100)'
ctx.stroke()
}
draw()
![在这里插入图片描述](https://img-blog.csdnimg.cn/68acdf9e2cd3435c8b4e01a96cc0c119.png)
添加样式和颜色
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(50, 50)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(100, 0)
ctx.lineWidth = 10
ctx.stroke()
ctx.beginPath()
ctx.moveTo(100, 0)
ctx.lineTo(150, 50)
ctx.lineWidth = 20
ctx.stroke()
ctx.beginPath()
ctx.moveTo(180, 10)
ctx.lineTo(180, 50)
ctx.lineWidth = 10
ctx.lineCap = 'butt'
ctx.strokeStyle = 'rgb(255,0,0)'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(200, 10)
ctx.lineTo(200, 50)
ctx.lineWidth = 10
ctx.lineCap = 'round'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(220, 10)
ctx.lineTo(220, 50)
ctx.lineWidth = 10
ctx.lineCap = 'square'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(240, 10)
ctx.lineTo(260, 50)
ctx.lineTo(280, 10)
ctx.lineTo(300, 50)
ctx.lineTo(320, 10)
ctx.lineWidth = 10
ctx.strokeStyle = 'rgb(0,255,0)'
ctx.lineJoin = 'round'
ctx.beginPath()
ctx.moveTo(240, 10)
ctx.lineTo(260, 50)
ctx.lineTo(280, 10)
ctx.lineWidth = 10
ctx.strokeStyle = 'rgb(0,255,0)'
ctx.lineJoin = 'round'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(300, 10)
ctx.lineTo(320, 50)
ctx.lineTo(340, 10)
ctx.lineWidth = 10
ctx.lineJoin = 'bevel'
ctx.stroke()
ctx.beginPath()
ctx.moveTo(360, 10)
ctx.lineTo(380, 50)
ctx.lineTo(400, 10)
ctx.lineWidth = 10
ctx.lineJoin = 'miter'
ctx.stroke()
ctx.setLineDash([5, 3])
ctx.lineDashOffset = -0
ctx.strokeStyle = 'rgb(0,0,255)'
ctx.lineWidth = 1
ctx.strokeRect(420, 10, 50, 30)
}
draw()
![在这里插入图片描述](https://img-blog.csdnimg.cn/f2897fabcc094e8986bd7d4ab66094bf.png)
绘制文本
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.font = "30px sans-serif"
ctx.fillText('爱屋及乌', 0, 30)
ctx.strokeText('比翼双飞', 0, 100)
}
draw()
![在这里插入图片描述](https://img-blog.csdnimg.cn/b8ee05f46f734785a82bab5884a1d359.png)
绘制图片
<img src="./pic2.jpeg" width="360" alt=""><br>
<canvas class="box" id="demo1" width="720" height="420">
<img src="./html.gif" alt="不支持canvas时替代的图片内容">
</canvas>
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
var img = new Image()
img.src = './pic2.jpeg'
img.onload = function () {
ctx.drawImage(img, 10, 10, 60, 60, 0, 0, 100, 100)
}
}
draw()
保存状态和恢复
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.fillRect(0, 0, 200, 100)
ctx.save()
ctx.fillStyle = 'rgb(255,0,0)'
ctx.fillRect(210, 0, 200, 100)
ctx.save()
ctx.restore()
ctx.fillRect(420, 0, 200, 100)
ctx.restore()
ctx.fillRect(630, 0, 200, 100)
}
draw()
![在这里插入图片描述](https://img-blog.csdnimg.cn/e3c189c50fc34193b2f6fd207f4f9b1e.png)
变形
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
ctx.transform(1, 1, 0, 1, 0, 0)
ctx.fillStyle = 'rgb(255,0,0)'
ctx.fillRect(0, 0, 100, 100)
}
draw()
合成
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
var types = ['source-over', 'destination-over', 'source-in', 'destination-in', 'source-out', 'destination-out',
'source-atop', 'destination-atop', 'lighter', 'lighten', 'darken', 'xor', 'copy'
]
var i = 0
let interval = setInterval(function () {
if (i == 13) {
i = 0
} else {
i++
}
ctx.fillStyle = 'rgb(255,0,0)'
ctx.fillRect(0, 0, 100, 100)
ctx.globalCompositeOperation = types[i]
ctx.fillStyle = 'rgb(0,255,0)'
ctx.fillRect(50, 50, 100, 100)
}, 1000)
}
draw()
裁剪
function draw() {
var canvas = document.getElementById('demo1')
if (!canvas.getContext) return
var ctx = canvas.getContext('2d')
var img = new Image()
img.onload = function () {
drawImage(ctx, img)
}
img.src = './pic1.jpeg'
}
function drawImage(ctx, img) {
clipStar(ctx)
ctx.drawImage(img, 0, 0)
}
function clipTriangle(ctx) {
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(110, 10)
ctx.lineTo(60, 200)
ctx.lineTo(10, 10)
ctx.closePath()
ctx.clip()
}
function clipRectangle(ctx) {
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(210, 10)
ctx.lineTo(210, 110)
ctx.lineTo(10, 110)
ctx.lineTo(10, 10)
ctx.closePath()
ctx.clip()
}
function clipCircle(ctx) {
ctx.beginPath()
ctx.arc(200, 200, 100, 0, Math.PI * 2, true)
ctx.closePath()
ctx.clip()
}
function clipStar(ctx) {
var n = 0
var dx = 150
var dy = 100
var s = 100
ctx.beginPath()
var x = Math.sin(0)
var y = Math.cos(0)
var dig = (Math.PI / 5) * 4
for (var i = 0; i < 5; i++) {
var x = Math.sin(i * dig)
var y = Math.cos(i * dig)
ctx.lineTo(dx + x * s, dy + y * s)
}
ctx.closePath()
ctx.clip()
}
draw()
动画
function init() {
let canvas = document.getElementById('demo1')
if (!canvas.getContext) return
let ctx = canvas.getContext('2d')
draw(ctx)
}
function draw(ctx) {
requestAnimationFrame(function step() {
drawDial(ctx)
drawAllHands(ctx)
requestAnimationFrame(step)
})
}
function drawAllHands(ctx) {
let time = new Date()
let s = time.getSeconds()
let m = time.getMinutes()
let h = time.getHours()
let pi = Math.PI
let secondAngle = pi / 180 * 6 * s
let minuteAngle = pi / 180 * 6 * m + secondAngle / 60
let hourAngle = pi / 180 * 30 * h + minuteAngle / 12
drawHand(hourAngle, 60, 6, "red", ctx)
drawHand(minuteAngle, 106, 4, "green", ctx)
drawHand(secondAngle, 129, 2, "blue", ctx)
}
function drawHand(angle, len, width, color, ctx) {
ctx.save()
ctx.translate(150, 150)
ctx.rotate(-Math.PI / 2 + angle)
ctx.beginPath()
ctx.moveTo(-4, 0)
ctx.lineTo(len, 0)
ctx.lineWidth = width
ctx.strokeStyle = color
ctx.lineCap = 'round'
ctx.stroke()
ctx.closePath()
ctx.restore()
}
function drawDial(ctx) {
let pi = Math.PI
ctx.clearRect(0, 0, 300, 300)
ctx.save()
ctx.translate(150, 150)
ctx.beginPath()
ctx.arc(0, 0, 148, 0, 2 * pi)
ctx.stroke()
ctx.closePath()
for (let i = 0; i < 60; i++) {
ctx.save()
ctx.rotate(-pi * 2 + i * pi / 30)
ctx.beginPath()
ctx.moveTo(110, 0)
ctx.lineTo(140, 0)
ctx.lineWidth = i % 5 ? 2 : 4
ctx.strokeStyle = i % 5 ? 'blue' : 'red'
ctx.stroke()
ctx.closePath()
ctx.restore()
}
ctx.restore()
}
init()
综合案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>canvas画图</title>
<style>
* {
margin: 0;
padding: 0;
}
.canvas-box {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.demo {
width: 30%;
}
</style>
</head>
<body>
<button class="btn"
onclick="drawRect();drawCircle();drawTest();drawMoveLine();drawMoveLine();drawFlower();drawBezier();drawGradient();drawGradient1();drawTrans();drawComposite();drawShadow();paintImage();drawRepeat();drawClip();drawHandlePx();drawText();drawSave()">
绘制
</button>
<div class="canvas-box">
<canvas class="demo" id="rect"></canvas>
<canvas class="demo" id="circle"></canvas>
<canvas class="demo" id="test"></canvas>
<canvas class="demo" id="moveLine"></canvas>
<canvas class="demo" id="flower"></canvas>
<canvas class="demo" id="bezier"></canvas>
<canvas class="demo" id="gradient"></canvas>
<canvas class="demo" id="gradient1"></canvas>
<canvas class="demo" id="trans"></canvas>
<canvas class="demo" id="composite"></canvas>
<canvas class="demo" id="shadow"></canvas>
<canvas class="demo" id="image"></canvas>
<canvas class="demo" id="repeat"></canvas>
<canvas class="demo" id="clip"></canvas>
<canvas class="demo" id="handlePx"></canvas>
<canvas class="demo" id="text"></canvas>
<canvas class="demo" id="save"></canvas>
</div>
<script>
function drawRect() {
var canvas = document.getElementById('rect')
if (canvas == null) {
return false
}
var context = canvas.getContext('2d')
context.fillStyle = 'red'
context.strokeStyle = 'blue'
context.fillRect(0, 0, 100, 100)
context.strokeRect(120, 0, 100, 100)
context.clearRect(25, 25, 100, 50)
}
function drawCircle() {
var canvas = document.getElementById('circle')
if (canvas == null) {
return false
}
var context = canvas.getContext('2d')
context.beginPath()
context.arc(50, 50, 50, 0, Math.PI * 2, true)
context.closePath()
context.fillStyle = 'rgba(0,255,0,0.25)'
context.fill()
}
function drawTest() {
const canvas = document.getElementById('test')
if (canvas == null) {
return false
}
var context = canvas.getContext('2d')
context.beginPath()
context.arc(0, 50, 50, 0, Math.PI / 2, false)
context.strokeStyle = 'rgba(255,0,0,0.25)'
context.stroke()
context.closePath()
context.beginPath()
context.arc(100, 50, 50, 0, Math.PI / 2, false)
context.strokeStyle = 'rgba(255,0,0,0.25)'
context.stroke()
context.closePath()
}
function drawMoveLine() {
const canvas = document.getElementById('moveLine')
if (canvas == null) {
return false
}
var context = canvas.getContext('2d')
context.strokeStyle = 'red'
context.fillStyle = 'blue'
context.lineTo(0, 100)
context.lineTo(100, 0)
context.stroke()
}
function drawFlower() {
var canvas = document.getElementById('flower')
if (canvas == null) {
return false
}
var context = canvas.getContext('2d')
context.fillStyle = '#EEEEFF'
context.fillRect(0, 0, 200, 400)
var n = 0
var dx = 100
var dy = 75
var s = 50
context.beginPath()
context.fillStyle = 'blue'
context.strokeStyle = 'red'
var x = Math.sin(0)
var y = Math.cos(0)
var dig = (Math.PI / 15) * 11
for (var i = 0; i < 30; i++) {
var x = Math.sin(i * dig)
var y = Math.cos(i * dig)
context.lineTo(dx + x * s, dy + y * s)
}
context.closePath()
context.fill()
context.stroke()
}
function drawBezier() {
const canvas = document.getElementById('bezier')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
context.moveTo(25, 25)
context.bezierCurveTo(25, 25, 75, 25, 75, 75)
context.stroke()
context.quadraticCurveTo(75, 125, 125, 125)
context.stroke()
}
function drawGradient() {
const canvas = document.getElementById('gradient')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
var lg = context.createLinearGradient(0, 0, 0, 300)
lg.addColorStop(0, 'rgb(255,0,0)')
lg.addColorStop(0.5, 'rgb(0,255,0)')
lg.addColorStop(1, 'rgb(0,0,255)')
context.fillStyle = lg
context.fillRect(0, 0, 200, 100)
}
function drawGradient1() {
const canvas = document.getElementById('gradient1')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
var rg = context.createRadialGradient(50, 50, 0, 50, 50, 50)
rg.addColorStop(0.1, 'red')
rg.addColorStop(0.5, 'orange')
rg.addColorStop(1, 'yellow')
context.fillStyle = rg
context.beginPath()
context.arc(50, 50, 50, 0, Math.PI * 2, true)
context.closePath()
context.fill()
}
function drawTrans() {
const canvas = document.getElementById('trans')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
context.save()
context.fillStyle = 'rgb(255,0,0)'
context.fillRect(0, 0, 30, 30)
context.translate(50, 50)
context.scale(0.5, 0.5)
context.rotate(Math.PI / 4)
context.fillRect(0, 0, 50, 50)
context.restore()
context.save()
context.fillStyle = 'rgba(255,0,0,0.5)'
context.scale(0.8, 0.8)
context.rotate(Math.PI / 6)
context.translate(120, 0)
context.fillRect(0, 0, 50, 50)
context.restore()
}
function drawComposite() {
const canvas = document.getElementById('composite')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
const options = new Array(
'source-over',
'destination-over',
'source-in',
'destination-in',
'source-out',
'destination-out',
'source-atop',
'destination-atop',
'lighter',
'xor',
'copy'
)
var i = 0
var interval = setInterval(function () {
if (i == 10) {
i = 0
} else {
i++
}
context.fillStyle = 'blue'
context.fillRect(10, 10, 60, 60)
context.globalCompositeOperation = options[i]
context.beginPath()
context.fillStyle = 'red'
context.arc(60, 60, 30, 0, Math.PI * 2, false)
context.fill()
}, 1000)
}
function drawShadow() {
const canvas = document.getElementById('shadow')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
context.shadowOffsetX = 10
context.shadowOffsetY = 10
context.shadowColor = 'rgba(100,100,100,0.2)'
context.shadowBlur = 1.2
context.fillStyle = 'rgba(255,0,0,0.5)'
context.fillRect(0, 0, 100, 50)
for (var i = 0; i < 3; i++) {
context.translate(30, 30)
createStar(context)
context.fill()
}
}
function createStar(context) {
var n = 0
var dx = 50
var dy = 0
var s = 25
context.beginPath()
context.fillStyle = 'rgba(255,0,0,0.5)'
var x = Math.sin(0)
var y = Math.cos(0)
var dig = (Math.PI / 5) * 4
for (var i = 0; i < 5; i++) {
var x = Math.sin(i * dig)
var y = Math.cos(i * dig)
context.lineTo(dx + x * s, dy + y * s)
}
context.closePath()
}
function paintImage() {
const canvas = document.getElementById('image')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
var image = new Image()
image.src = './html.gif'
context.fillStyle = '#EEEEFF'
context.fillRect(0, 0, 200, 100)
image.onload = function () {
context.drawImage(image, 10, 10, 200, 100, 10, 10, 180, 80)
}
}
function drawRepeat() {
const canvas = document.getElementById('repeat')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
var image = new Image()
image.src = './pet.jpg'
var types = ['no-repeat', 'repeat-x', 'repeat-y', 'repeat']
var i = 0
image.onload = function () {
var interval = setInterval(function () {
context.clearRect(0, 0, 400, 300)
if (i >= 4) {
i = 0
}
var ptrn = context.createPattern(image, types[i])
context.fillStyle = ptrn
context.fillRect(0, 0, 400, 300)
i++
}, 1000)
}
}
function drawClip() {
const canvas = document.getElementById('clip')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
context.fillStyle = 'orange'
context.fillRect(0, 0, 300, 200)
image = new Image()
image.onload = function () {
drawImage(context, image)
}
image.src = './html.gif'
}
function drawImage(context, image) {
createStarClip(context)
context.drawImage(image, 0, 0)
}
function createCircleClip(context) {
context.beginPath()
context.arc(100, 100, 50, 0, Math.PI * 2, true)
context.closePath()
context.clip()
}
function createStarClip(context) {
var n = 0
var dx = 100
var dy = 50
var s = 50
context.beginPath()
var x = Math.sin(0)
var y = Math.cos(0)
var dig = (Math.PI / 5) * 4
for (var i = 0; i < 5; i++) {
var x = Math.sin(i * dig)
var y = Math.cos(i * dig)
context.lineTo(dx + x * s, dy + y * s)
}
context.closePath()
context.clip()
}
function drawHandlePx() {
console.log('drawHandlePx');
}
function drawText() {
const canvas = document.getElementById('text')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
context.fillStyle = '#EEEEFF'
context.fillRect(0, 0, 400, 300)
context.fillStyle = '#00f'
context.font = 'italic 24px sans-serif'
context.textBaseline = 'top'
var text = 'hello world 这是样例文本'
context.fillText(text, 0, 0)
var length = context.measureText(text)
context.fillText('长' + length.width + 'px', 0, 50)
context.font = "bolid 22px sans-serif";
text = "love and peace 测试二";
length = context.measureText(text);
context.strokeText(text, 0, 100);
context.fillText("长" + length.width + "px", 0, 150);
}
function drawSave() {
const canvas = document.getElementById('save')
if (canvas == null) {
return false
}
const context = canvas.getContext('2d')
var rg = context.createRadialGradient(50, 50, 0, 50, 50, 50)
rg.addColorStop(0.1, 'red')
rg.addColorStop(0.5, 'orange')
rg.addColorStop(1, 'yellow')
context.fillStyle = rg
context.shadowOffsetX = 10
context.shadowOffsetY = 10
context.shadowColor = 'rgba(100,100,100,0.5)'
context.shadowBlur = 1.2
context.beginPath()
context.arc(50, 50, 50, 0, Math.PI * 2, true)
context.closePath()
context.fill()
function download() {
let type = 'png'
let img_png_src = canvas.toDataURL('image/png')
let imgData = img_png_src.replace(imgType(type), 'image/octet-stream')
let filename = '图片' + '.' + type
saveFile(imgData, filename)
}
let saveFile = function (data, fileName) {
let save_link = document.createElement('a')
save_link.href = data
save_link.download = fileName
let event = document.createEvent('MouseEvents')
event.initEvent('click', true, false)
save_link.dispatchEvent(event)
}
function imgType(ty) {
let type = ty.toLowerCase().replace(/jpg/i, 'jpeg')
var r = type.match(/png|jpeg|bmp|gif/)[0]
return 'image/' + r
}
download()
}
</script>
</body>
</html>