JavaScript-canvas(画布)初识、刮刮卡制作、画板
一、canvas初识
Canvas元素的出现,可以说开启的Web世界绘制动画,图形的大门,其功能非常强大,canvas 元素是HTML5中功能最强大的元素,它的能力主要是通过Canvas中的Context(绘图上下文/绘图环境)对象表现出来的。
1.
getContext()
方法是用来获得渲染上下文和它的绘画功能。
2.绘制矩形:
fillRect(x, y, width, height)
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
3.绘制路径:
beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。
stroke()
通过线条来绘制图形轮廓。
fill()
通过填充路径的内容区域生成实心的图形。
4.移动笔触:moveTo(x, y)
将笔触移动到指定的坐标x以及y上。绘制直线路径:lineTo(x, y)
绘制一条从当前位置到指定x以及y位置的直线
5.绘制圆弧路径:
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1, y1, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
角度与弧度的js表达式:radians=(Math.PI/180)*degrees
6.填充颜色:
fillStyle = color
设置图形的填充颜色
strokeStyle = color
设置图形轮廓的颜色
透明度globalAlpha = transparencyValue
这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。
7.线型 Line styles
lineWidth = value
设置线条宽度,宽度为奇数的线并不能精确呈现
lineCap = type
设置线条末端样式。
lineJoin = type
设定线条与线条间接合处的样式。
miterLimit = value
限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
canvas属性速查表:
第一步:引入canvas
<body>
<canvas id="canvas_1" width="600" height="600">
这里面的内容,正常画布是不显示的,
canvas三要素:id唯一标识
width宽height高
canvas仅仅是一个画布标签,要绘制内容必须用js绘制
</canvas>
</body>
第二步:引入canvas
//1、找到画布
var canvas1 = document.querySelector("#canvas_1");
console.log([canvas1])
//2.上下文对象(画笔)
var pencil = canvas1.getContext("2d");
//3.绘制路径
pencil.rect(50,50,300,300);//绘制一个矩形
//4填充
pencil.fillStyle = "pink";
pencil.fill()
//描边,渲染路径
pencil.lineWidth = 20;//设置绘制宽度
pencil.strokeStyle = "salmon";//设置绘制颜色
pencil.stroke()
示例
绘制矩形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas id="canvas_1" width="600" height="600">
这里面的内容,正常画布是不显示的,
canvas三要素:id唯一标识
width宽height高
canvas仅仅是一个画布标签,要绘制内容必须用js绘制
</canvas>
<script>
//1、找到画布
var canvas1 = document.querySelector("#canvas_1");
console.log([canvas1])
//2.上下文对象(画笔)
var pencil = canvas1.getContext("2d");
console.log(pencil);
//3.绘制路径
pencil.rect(50,50,300,300);
//填充
pencil.fillStyle = "pink";
pencil.fill()
//描边,渲染路径
pencil.lineWidth = 20;
pencil.strokeStyle = "salmon";
pencil.stroke()
</script>
</body>
</html>
绘制线条
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas id="canvas_1" width="500" height="500"></canvas>
<script>
var canvas1 = document.querySelector("#canvas_1");
var cvs = canvas1.getContext('2d');
console.log(cvs)
//设置开始路径
cvs.beginPath()
//设置经过某个位置的起点
cvs.moveTo(50,50);
//设置经过某个位置
cvs.lineTo(50,200);
//设置经过某个位置
cvs.lineTo(60,300);
//设置经过某个位置
cvs.lineTo(100,50);
//设置结束路径
cvs.closePath()
//绘制路径
cvs.lineCap = "round";//设置路径经过的边缘为圆角
cvs.lineJoin = "round";
cvs.strokeStyle = "pink";
cvs.lineWidth = 10;
cvs.stroke();
</script>
</body>
</html>
二、绘制文本
绘制文本
cvs.font = "30px 微软雅黑";
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas id="canvas_1" width="500" height="500"></canvas>
<script>
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
//设置阴影
cvs.shadowBlur = 20;
cvs.shadowColor = "skyblue";
cvs.shadowOffsetX = 10;
cvs.shadowOffsetY = 10;
cvs.font = "30px 微软雅黑";
cvs.strokeStyle = "#333";
var x = 500;
setInterval(function(){
cvs.clearRect(0,0,500,500)
x -=3;
if(x<-100){
x=500
}
cvs.strokeText("这也太可爱吧",x,200);
},30)
</script>
</body>
</html>
三、绘制圆图像、视频
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<canvas id="canvas_1" width="600" height="600"></canvas>
<script>
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
//绘制图像cvs.drawImage(图片对象,x位置,y位置)
//绘制图像cvs.drawImage(图片对象,x位置,y位置,宽度,高度)
//绘制图像cvs.drawImage(图片对象,裁剪的位置x,裁剪的位置y,裁剪的宽度,裁剪的高度,x位置,y位置,宽度,高度)
var img = new Image();
img.src = "../js学习/imag/clockbg.png";
img.onload = function() {
cvs.translate(400, 300);
cvs.arc(0, 0, 200, 0, 2 * Math.PI);
cvs.clip();
cvs.drawImage(img, -200, -200, 400, 400);
cvs.strokeStyle = "orange";
cvs.lineWidth = 10;
cvs.stroke();
};
</script>
</body>
</html>
效果图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<video src="../MP3/mda-mke7tdctjt86cnib.mp4" controls="controls" width="400" height=""></video>
<canvas id="canvas" width="600" height="600"></canvas>
<script>
var interid;
var video1 = document.querySelector("video");
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
video1.onplay = function(){
interid = setInterval(function(){
cvs.clearRect(0,0,600,600)
cvs.fillRect(0,0,600,600)
cvs.drawImage(video1,100,70,400,225);
},16)
}
video1.onpause = function(){
clearInterval(interid);
}
</script>
</body>
</html>
四、时钟
save用于保存当前的画布状态,restore将画布状态重置到save保存时的样子。画布状态分为画布的坐标(transform),画布绘制区域(clip),画布中设置的组合方式(globalCompositeOperatio)。当我们在使用transform,clip和globalCompositeOperatio时会改变画布的状态,而这种改变会影响到接下来的画布绘制操作,所以在进行这种操作前需要使用save来对画布进行一次保存,在进行改变状态后的下一步操作中使用restore来重置画布状态。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<canvas id="canvas_1" width="800" height="600"></canvas>
<script>
var img = new Image();
img.src = "../js学习/imag/clockbg.png";
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
img.onload= function(){
xuanranclock();
setInterval(function() {
xuanranclock();
}, 1000);
}
function xuanranclock() {
cvs.clearRect(0, 0, 800, 600);
//绘制表盘
cvs.beginPath();
cvs.arc(400, 300, 200, 0, 2 * Math.PI);
cvs.clip();
cvs.drawImage(img, 200, 100, 400, 400);
cvs.strokeStyle = "orange";
cvs.lineWidth = 10;
cvs.stroke();
cvs.closePath();
//保存一下状态
cvs.save();
//将画布的坐标移动到画布的中央
cvs.translate(400, 300);
cvs.rotate((-2 * Math.PI) / 4);
cvs.save();
//绘制时钟刻度
for (var i = 0; i < 12; i++) {
cvs.rotate((Math.PI * 2) / 12);
cvs.beginPath();
cvs.moveTo(180, 0);
cvs.lineTo(200, 0);
cvs.strokeStyle = "orange";
cvs.stroke();
cvs.closePath();
}
cvs.restore();
cvs.save();
//绘制秒针
for (var i = 0; i < 60; i++) {
cvs.beginPath();
cvs.rotate(Math.PI / 30);
cvs.moveTo(180, 0);
cvs.lineTo(200, 0);
cvs.lineWidth = 2;
cvs.strokeStyle = "orange";
cvs.stroke();
cvs.closePath();
}
cvs.restore();
cvs.save();
var time = new Date();
var hour = time.getHours();
var min = time.getMinutes();
var sec = time.getSeconds();
//如果时间大于12那就直接减去十二
hour = hour > 12 ? hour - 12 : hour;
//绘制秒针
cvs.beginPath();
cvs.rotate(((2 * Math.PI) / 60) * sec);
cvs.moveTo(-20, 0);
cvs.lineTo(170, 0);
cvs.lineWidth = 2;
cvs.strokeStyle = "rgb(135, 197, 248)";
cvs.stroke();
cvs.closePath();
cvs.restore();
cvs.save();
//绘制fen针
cvs.beginPath();
cvs.rotate((2 * Math.PI * min) / 60 + ((2 * Math.PI) / 3600) * sec);
cvs.moveTo(-20, 0);
cvs.lineTo(160, 0);
cvs.lineWidth = 4;
cvs.strokeStyle = "#333";
cvs.stroke();
cvs.closePath();
cvs.restore();
cvs.save();
//绘制时针刻度
cvs.beginPath();
cvs.rotate(
(2 * Math.PI * hour) / 12 +
((2 * Math.PI) / 60 / 12) * min +
((2 * Math.PI) / 12 / 60 / 60) * sec
);
cvs.moveTo(-10, 0);
cvs.lineTo(140, 0);
cvs.lineWidth = 6;
cvs.strokeStyle = " rgb(105, 69, 236)";
cvs.stroke();
cvs.closePath();
cvs.restore();
cvs.beginPath();
//盖子
cvs.arc(0, 0, 10, 0, 2 * Math.PI);
cvs.fillStyle = "black";
cvs.fill();
cvs.closePath();
cvs.restore();
}
</script>
</body>
</html>
效果图
五、刮刮卡制作
预备知识
globalCompositeOperation用于控制源图像在目标图像上的显示方式。
源图像:指你准备绘制到画布上的图像
目标图像:在画布上已经绘制的图像
属性值:
值 | 描述 |
---|---|
source-over | 默认。在目标图像上显示源图像。 |
source-atop | 源图像为透明的,只有源图像与目标图像有交集的地方显示源图像,其他部分透明 |
source-in | 源图像和目标图像都透明,只有源图像和目标图像有交集的地方不透明,且显示源图像 |
source-out | 目标图像透明,源图像不透明,如果目标图像和源图像有交集的话,交集部分的图像透明 |
destination-over | 将源图像绘制在目标图像的下层 |
destination-atop | 目标图像透明,源图像不透明,如果目标图像和源图像有交集的话,在交际部分显示目标图像 |
destination-in | 源图像和目标图像都透明,只有目标图像和源图像交集的部分不透明且显示目标图像 |
destination-out | 目标图像不透明,源图像透明,如果目标图像和源图像有交集的话,交集部分图像透明 |
lighter | 源图像和目标图像一起绘制在画布中,如果两者之间有交集的话颜色会进行叠加 |
copy | 画布上只显示源图像,目标图像都不在画布中显示 |
xor | 源图像和目标图像都在画布中显示,如果两者之间有交集的话,交集部分不显示图像 |
例
<script>
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
cvs.fillStyle = "red";
cvs.fillRect(0,0,200,200);
cvs.fillStyle = "pink";
cvs.fillRect(100,100,200,200);
</script>
效果图
cvs.globalCompositeOperation = "source-over";
cvs.globalCompositeOperation = "source-atop";
cvs.globalCompositeOperation = "source-in";
cvs.globalCompositeOperation = "source-out";
cvs.globalCompositeOperation = "destination-over";
cvs.globalCompositeOperation = "destination-atop";
cvs.globalCompositeOperation = "destination-in";
cvs.globalCompositeOperation = "destination-out";
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<style>
.ggk {
width: 250px;
height: 150px;
position: relative;
}
.content,
#canvas_1 {
width: 250px;
height: 150px;
text-align: center;
line-height: 150px;
position: absolute;
left: 0;
top: 0;
}
</style>
<body>
<div class="ggk">
<div class="content">一等奖</div>
<canvas id="canvas_1" width="250" height="150"></canvas>
</div>
<script>
var isDraw;
var canvas1 = document.querySelector("canvas");
var cvs = canvas1.getContext("2d");
var ggk = document.querySelector("div");
var content = document.querySelector(".content");
cvs.fillStyle = "red";
cvs.fillRect(0, 0, 250, 150);
cvs.font = "30px 微软雅黑";
cvs.fillStyle = "#fff";
cvs.fillText("刮刮卡", 85, 80);
canvas1.onmousemove = function(e) {
if (isDraw) {
var x = e.pageX - ggk.offsetLeft;
var y = e.pageY - ggk.offsetTop;
cvs.globalCompositeOperation = "destination-out"
cvs.arc(x, y, 18, 0, 2 * Math.PI);
cvs.fill();
}
};
canvas1.onmousedown = function(e) {
isDraw = true;
console.log(e);
};
canvas1.onmouseup = function(e) {
isDraw = false;
console.log(e);
};
</script>
</body>
</html>
六、画板练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link rel="stylesheet" href="../css/huaban.css" />
<link rel="stylesheet" href="../js学习//font/hubanfont/iconfont.css" />
</head>
<body>
<div class="tool">
<div class="btn"><span class="iconfont icon-huaban"></span></div>
<div class="btn"><span class="iconfont icon-juxingxuanze"></span></div>
<div class="btn">
<span class="iconfont icon-xingzhuang-tuoyuanxing"></span>
</div>
<div class="btn"><span class="iconfont icon-xianduan"></span></div>
<div class="btn"><input type="color" class="color"></span></div>
<div class="btn"><span class="iconfont icon-bold "></span></div>
<div class="btn"><span class="iconfont icon-xiangpica "></span></div>
<div class="btn"><span class="iconfont icon-xiazai "></span></div>
<div class="btn" hidden><a href="">xiazai</a></div>
</div>
<canvas id="canvas1"></canvas>
<script>
var canvas = document.querySelector("canvas");
var huabiBtn = document.querySelector(".btn:nth-child(1)");
var rectBtn = document.querySelector(".btn:nth-child(2)");
var circleBtn = document.querySelector(".btn:nth-child(3)");
var weightBtn = document.querySelector(".btn:nth-child(4)");
var colorbtnBtn = document.querySelector(".btn:nth-child(5)");
var jiacuBtn = document.querySelector(".btn:nth-child(6)");
var xiangpiBtn = document.querySelector(".btn:nth-child(7)");
var downloadBtn = document.querySelector(".btn:nth-child(8)");
var colorInput = document.querySelector(".color");
var btnList = document.querySelectorAll(".btn");
canvas.setAttribute("width", canvas.offsetWidth);
canvas.setAttribute("height", canvas.offsetHeight);
var cvs = canvas.getContext("2d");
var huanban = {
imgData: null,
beginX: 0,
beginY: 0,
lineWidth:6,
color:"#333",
type: "none",
isDraw: false,
huabiFn: function(e) {
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
cvs.strokeStyle = huanban.color;
cvs.lineTo(x,y);
cvs.lineWidth = huanban.lineWidth;
cvs.stroke();
},
rectFn: function(e) {
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
cvs.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
if(huanban.imgData != null){
cvs.putImageData(huanban.imgData,0,0,0,0,canvas.offsetWidth,canvas.offsetHeight);
}
cvs.beginPath();
cvs.strokeStyle = huanban.color;
cvs.rect(
huanban.beginX,
huanban.beginY,
x - huanban.beginX,
y - huanban.beginY
);
cvs.stroke();
cvs.closePath();
},
circleFn: function(e) {
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
cvs.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
if(huanban.imgData != null){
cvs.putImageData(huanban.imgData,0,0,0,0,canvas.offsetWidth,canvas.offsetHeight);
}
cvs.beginPath();
cvs.strokeStyle = huanban.color;
cvs.arc(
huanban.beginX,
huanban.beginY,
y - huanban.beginY ,0, 2 * Math.PI
);
cvs.stroke();
cvs.closePath();
},
};
function clearclass() {
btnList.forEach(function(item,index){
for(var i=1;i<9;i++){
item.classList.remove("active"+i);
}
})
}
huabiBtn.onclick = function() {
clearclass();
huabiBtn.classList.add("active1");
huanban.type = "huabi";
};
rectBtn.onclick = function() {
clearclass();
rectBtn.classList.add("active2");
huanban.type = "rect";
};
circleBtn.onclick = function() {
clearclass();
circleBtn.classList.add("active3");
huanban.type = "circle";
};
weightBtn.onclick = function() {
clearclass();
weightBtn.classList.add("active4");
};
colorbtnBtn.onclick = function() {
clearclass();
colorbtnBtn.classList.add("active5");
};
colorInput.onchange = function(e){
huanban.color = colorInput.value;
console.log(colorInput.value)
}
jiacuBtn.onclick = function(){
clearclass();
jiacuBtn.classList.add("active6");
}
xiangpiBtn.onclick = function(){
clearclass();
xiangpiBtn.classList.add("active7");
cvs.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
huanban.imgData = null;
}
downloadBtn.onclick = function(){
clearclass();
var hiddenxiazaia = document.querySelector(".btn a");
downloadBtn.classList.add("active8");
huanban.type = "download";
var url = canvas.toDataURL();
hiddenxiazaia.setAttribute("href",url);
hiddenxiazaia.click()
console.log(url)
}
canvas.onmousedown = function(e) {
huanban.isDraw = true;
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
huanban.beginX = x;
huanban.beginY = y;
if (huanban.type == "huabi"){
cvs.beginPath();
cvs.moveTo(x,y);
}
};
canvas.onmousemove = function(e) {
if (huanban.isDraw) {
var strFn = huanban.type + "Fn";
huanban[strFn](e);
}
};
canvas.onmouseup = function() {
huanban.imgData = cvs.getImageData(0,0,canvas.offsetWidth,canvas.offsetHeight);
huanban.isDraw = false;
if (huanban.type == "huabi"){
cvs.closePath();
}
};
</script>
</body>
</html>