canvas
套用官方的介绍
HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.
<canvas> 标签只是图形容器,您必须使用脚本来绘制图形。
你可以通过多种方法使用 canvas 绘制路径,盒、圆、字符以及添加图像。
兼容性
image表格中的数字表示支持 <canvas> 元素的第一个浏览器版本号。
基本画图
直线
基本直线
知识点:lineWidth 设置线条宽度
<html>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<style>
html,body,canvas {
margin: 0;
padding: 0;
}
</style>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
</script>
</body>
</html>
ctx.lineWidth = 5; //增
ctx.moveTo(80, 80);
ctx.lineTo(300, 300);
ctx.stroke();
image
三角形
知识点:closePath 不是结束路径,而是关闭路径,它会试图从当前路径的终点连一条路径到起点,让整个路径闭合起来
有了这玩意,就可以做一个标准的三角形,友情提示
可以提高线条宽度,注释ctx.closePath()
看看效果不加
ctx.closePath()
就会出现如下图这样的效果
ctx.lineWidth = 5; //增
ctx.moveTo(80, 80);
ctx.lineTo(300, 300);
ctx.lineTo(100, 350);
ctx.closePath();
ctx.stroke();
image
image
不同颜色的线条
知识点:beginPath
每次stroke都会去找最近的beginPath,然后进行绘制
绘制不同样式的时候条
ctx.lineWidth = 20;
ctx.strokeStyle = 'red';
ctx.moveTo(50, 100);
ctx.lineTo(50, 300);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 10;
ctx.strokeStyle = 'blue';
ctx.moveTo(300, 100);
ctx.lineTo(300, 300);
ctx.stroke();
image
image
这段代码显示的一条红线和蓝线,大家会想,这有什么好说的呢,肯定是这样啊。
接下来我们把第二个的context.stroke()注释起来,你会发现最后的结果只是一条蓝线,因为第一个路径没有stroke()就重新开辟了一个路径,使得只能画了第二个路径的直线,大家是不是发现越来越神奇了呢?
紧接着我把不注释context.stroke(),而把context.beginPath()注释起来,你发现什么了?很奇妙,你发现了一条紫线和蓝线,为什么呢?原来是因为没有开辟新的路径,所以第二个stroke()又重新画了第一条直线,并且用了蓝色,而第一个stroke()已经用红色画了第一条直线了,蓝色和红色的结合就变成了紫色。
你想想,如果把beginPath()和stroke()都注释起来会怎么样呢?两条蓝色的直线,you are good
现在应该是stroke是怎么个画法了吧
曲线
常规圆弧线
参数介绍:(原点x轴,原点y轴,半径,起点,终点,true/false)
true 逆时针 , false 顺时针
ctx.beginPath();
ctx.arc(150, 150, 120, 1.5 * Math.PI, 1 * Math.PI, false); // 顺时针
ctx.stroke();
ctx.closePath();
image
image贝塞尔曲线
二次方贝塞尔曲线
二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
image为建构二次贝塞尔曲线,可以中介点Q0和Q1作为由0至1的t:
由P0至P1的连续点Q0,描述一条线性贝塞尔曲线。
由P1至P2的连续点Q1,描述一条线性贝塞尔曲线。
由Q0至Q1的连续点B(t),描述一条二次贝塞尔曲线。
ctx.strokeStyle ="#FF5D43";
ctx.beginPath();
ctx.moveTo(0,200);
ctx.quadraticCurveTo(75,50,300,200);
ctx.stroke();
// ctx.strokeStyle = '#f0f';
// ctx.beginPath();
// ctx.moveTo(75,50);
// ctx.lineTo(0,200);
// ctx.moveTo(75,50);
// ctx.lineTo(300,200);
// ctx.stroke();
image
image
矩形
基本矩形
ctx.fillStyle = '#FF0000';
ctx.fillRect(0, 220, 100, 100);
image
巧妙利用globalCompositeOperation属性复制一个矩形
globalCompositeOperation属性介绍
source-over 默认。在目标图像上显示源图像。
source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
destination-over 在源图像上方显示目标图像。
destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
lighter 显示源图像 + 目标图像。
copy 显示源图像。忽略目标图像。
xor 使用异或操作对源图像与目标图像进行组合。
ctx.fillStyle="red";
ctx.fillRect(20,20,75,50);
ctx.globalCompositeOperation="source-over";
ctx.fillStyle="blue";
ctx.fillRect(50,50,75,50);
效果图
image
圆
空心圆
ctx.beginPath();
ctx.arc(200,200,50,0,360,false);
ctx.lineWidth=5;
ctx.strokeStyle="green";
ctx.stroke();
效果图
image
实心圆
ctx.beginPath();
ctx.arc(200,100,50,0,360,false);
ctx.fillStyle="red"; //填充颜色,默认是黑色
ctx.fill();
效果图
image
文字
ctx.fillStyle = 'red';
ctx.font = "bold 40px '微软雅黑'"; //设置字体
ctx.fillText('hello world', 10, 40); //设置文本内容
效果图
image
如果你想文本自动换行,下面看具体实现方法
/*
str:要绘制的字符串
canvas:canvas对象
initX:绘制字符串起始x坐标
initY:绘制字符串起始y坐标
lineHeight:字行高,自己定义个值即可
*/
function canvasTextAutoLine(str,canvas,initX,initY,lineHeight){
var ctx = canvas.getContext("2d");
var lineWidth = 0;
var canvasWidth = c.width;
var lastSubStrIndex= 0;
for(let i=0;i<str.length;i++){
lineWidth+=ctx.measureText(str[i]).width;
if(lineWidth>canvasWidth-initX){//减去initX,防止边界出现的问题
ctx.fillText(str.substring(lastSubStrIndex,i),initX,initY);
initY+=lineHeight;
lineWidth=0;
lastSubStrIndex=i;
}
if(i==str.length-1){
ctx.fillText(str.substring(lastSubStrIndex,i+1),initX,initY);
}
}
}
图片
var imgObj = new Image();
imgObj.src = "https://fe.yingyinglicai.com/h5-projects/blog/canvas/20180529_16.jpg";
// imgObj.crossOrigin = 'anonymous'; 如果跨域时需要加上
// 待图片加载完后,将其显示在canvas上
imgObj.onload = function () { //onload必须使用
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
var base64 = canvas.toDataURL('image/jpeg');
console.log(base64)
};
效果图
image
帧动画
-
setTimeout
-
setInterval
-
requestAnimationFrame
拿setInterval举个栗子
<html>
<div id="test"></div>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script>
var test = document.getElementById('test');
var num = 1, type = 'down';
setInterval(function () {
test.style.marginTop = num + 'px';
if (type == 'down') {
if (num > 100) {
num--;
type = 'up';
} else {
num++;
}
} else if (type == 'up') {
if (num <= 1) {
num++;
type = 'down';
} else {
num--;
}
}
}, 10)
</script>
</html>
上面那个小栗子用三个方法都能实现
但是不知道大家是否有这样的感觉,当你使用window.setInterval()或者window.setTimeout()制作出来的动画,一些比较炫酷的效果的时候总是一卡一卡的,这绝对不是大家想看到的。
两个函数的特征决定了它能展示给我们的效果:(1)其实它们从一生下来,就不是为动画服务的;
(2)它们虽然可以以毫秒作为单位,但是它们永远达不到毫秒的精确性;
(3)它们是死的,并不会考虑动画什么时间绘制才是最佳的,它们比较专一,脑子中只有你给予的那个数字(时间参数)。
所以大家在想,有没有这样一个方法:它们可以根据浏览器的性能自己决定绘制动画的速率。
也许在将来伟大的程序员会将window.setInterval()和window.setTimeout()的孙子打造出这样的性能,但是就现在来说,这个需求完全可以使用requestAnimationFrame()来完成。
requestAnimationFrame()接受一个参数,这个参数就是你要的动画引用(函数名)——为你省去了调试时间参数的烦恼。注:requestAnimationFrame 在切换游览器的时候会停止动画
即官方说的requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
那就再说下他的其他特点requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
网友评论