Canvas绘图
使用Canvas绘图
- 自己的一些理解和注意点:
- 1、目的:能“替代”flash等其他用于做动画或者游戏的插件的一个标签,可以减小页面结构,让页面加载速度更快
- 2、canvas可以理解为一个div,只不过div是用来存放元素的,canvas则提供了一个绘制图形的区域
- 3、canvas标签习惯上在标签内部对其
大小
进行设置(其他样式还是该怎样写怎样写还是用css),而不是css js- 4、canvas标签本身可以认为是一张普通画板,除此之外没有其他功能,
内部的所有内容或者图形要用js脚本来完成
- 5、
画板和画家
:var huaban=document.querySelector(".canvas")
var bicaso=huaban.getContext(“2d”);(getContext() 方法返回一个用于在画布上绘图的环境
)- 6、画家有一个官方称呼:【convas上下文对象,习惯上命名为ctx(context)】
- 7、要用canvas则先要准备一个脚本并且获取到canvas上下文(首先要检测 getContext() 方法是否存在)
- 8、特征:
上屏即像素化(内部绘制的图形一旦完成就不能变更,相当于已经是像素了只能擦掉重新画)- 9、
fps:
frame per second(每秒钟多少帧)(就像ps时间轴中的帧动画)- 10、如果canvas要加载一个图片,
必须先等到图片load完再上屏
,这与画家画油画感觉很像,先要看到整个物体,而不是像3D打印机过到哪画到哪
细致的基本用法
2D上下文(与python的使用turtle库画图类比)
- 填充和描边
fillStyle
:填充strokeStyle
:描边
- 绘制矩形(三个方法都是4个参数)
- fillRect(矩形的 x 坐标、矩形的 y 坐标、矩形
宽度和矩形高度) - strokeRect()
- clearRect()
- fillRect(矩形的 x 坐标、矩形的 y 坐标、矩形
// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
// 绘制半透明的蓝色矩形
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
// 绘制红色描边矩形
context.strokeStyle = "#ff0000";
context.strokeRect(10, 10, 50, 50);
-
绘制路径(
首先调出beginPath()方法
)- 一些方法如下图:
-
一个例子:(绘制一个不带数字的时钟表盘)
var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if (drawing.getContext){
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 绘制分针
context.moveTo(100, 100);
context.lineTo(100, 15);
// 绘制时针
context.moveTo(100, 100);
context.lineTo(35, 100);
// 描边路径
context.stroke();
}
- 绘制文本(两个方法都接受
4个参数
)- fillText(要绘制的文本字符串、x 坐标、y 坐标和可选的最大像素宽度)
- strokeText()
- 2个方法都以下面三个属性为基础:
这几个属性都有默认值,因此
没有必要
每次使用它们都重新设置一遍值
-
变换(5个方法)
-
绘制图像(使用 ==drawImage(传入一个 HTML 元素,以及绘制该图像的起点的 x 和 y 坐标)==方法)
1、除了给 drawImage() 方法
传入 HTML <img> 元素外
,还可以传入另一个 <canvas> 元素
作为其第一个参数
2、操作的结果可以通过
toDataURL() 方法获得(不过,有一个例外,即图像不能来自其他域。如果图像来自其他域,调用
toDataURL()
会抛出一个错误
)
- 阴影(4个属性)
像ps混合模式中添加阴影,可以改变阴影深度大小和偏移量
- 渐变(两步走)
- 1、创建一个新的线性渐
变,可以调用 createLinearGradient(起点的 x 坐标、起点的 y 坐
标、终点的 x 坐标、终点的 y 坐标) 方法
+2、使用 addColorStop(色标位置和 CSS 颜色值) 方法来指定色标
例子:
- 1、创建一个新的线性渐
var gradient = createRectLinearGradient(context, 30, 30, 50, 50);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//绘制渐变矩形
context.fi llStyle = gradient;
context.fillRect(30, 30, 50, 50);
- 模式(实质是重复的图像,用来填充或描边图形)
- createPattern(一个 HTML 元素,一个表示如何重复图像的字符串) 方法
第二个参数的值
与 CSS 的 background-repeat 属性值相同
,包括 “repeat” 、 “repeat-x” 、“repeat-y” 和 “no-repeat”
- 使用图像数据
- 取得原始图像数据:getImageData(要取得其数据的画面区域的 x , y 坐标以及该区域的像素宽度,高度)
var imageData = context.getImageData(10, 5, 50, 50);//取得左上角坐标为(10,5)、大小为 50×50 像素的区域的图像数据
理解:上个例子返回ImageData 的实例,每个 ImageData 对象都有
三个属性: width 、 height 、data
,data是一个数组,保存着图像中每一个像素的数据,而每个像素用4个元素来保存,分别表示红、绿、蓝(就像ps中的alpha通道
)和透明度值
- 合成(两个属性)
- ==globalAlpha:==是一个介于 0 和 1 之间的值(包括 0和 1),用于指定所有绘制的透明度,默认值为 0
- 例子:
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//修改全局透明度
context.globalAlpha = 0.5;
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);
//重置全局透明度
context.globalAlpha = 0;
理解:蓝色矩形会呈现半透明效果,
透过它
可以看到下面的红色矩形
-
globalComposition-
Operation:表示后绘制的图形怎样与先绘制的图形结合
,这个属性的的值是固定的:如图:
-
给出看视频学的两个例子:
这是一个控制一个矩形左右来回移动的代码段
<style>
.canvas {
border: 1px solid pink
}
</style>
<body>
<canvas width="300" height="200" class="canvas"></canvas>
<script>
var huaban = document.querySelector(".canvas");
var bicaso = huaban.getContext("2d");
var timer = null;
var distance = 10;
var fangxiang = 1;//本变量表示累加的变量,用来控制图形前进的方向,+1表示右,-1表示向左
timer = setInterval(function () {
if (distance == 0) {
fangxiang = 1;//通过变更横坐标来变更方向
}
if (distance == 250) {
fangxiang = -1;
}
switch (fangxiang) {
case 1: {
//擦除原有图形
bicaso.clearRect(0, 0, 300, 200);
//绘制新图形
bicaso.fillRect(++distance, 50, 50, 50);
}
break;
case -1: {
//擦除原有图形
bicaso.clearRect(0, 0, 300, 200);
//绘制新图形
bicaso.fillRect(--distance, 50, 50, 50);
}
break;
}
}, 25);
</script>
</body>
第二个例子:实现鼠标粒子跟随效果,要用到underscore库,相关可参考https://blog.csdn.net/napolunyishi/article/details/23695477?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.nonecase
<style>
canvas { background: #333; }
</style>
</head>
<body>
<canvas width="800" height="500">您的浏览器不支持此标签!</canvas>
<script src="js/underscore.min.js"></script>
<script>
// 获取canvas元素
var cvs = document.querySelector("canvas");
// 获取上下文对象
var ctx = cvs.getContext("2d");
// 声明一个空数组,用来放后面生成的小球
var ballsArr = [];
// 创建一个小球类
function Balls (x, y){
// 坐标x为传进来的x
this.x = x;
// 坐标y为传进来的y
this.y = y;
// 生成的小球半径为5到10中的任一整数(参数随便)
this.r = _.random(5, 10);
// 生成的小球的颜色为这七种颜色中的随机一种(参数随便)
this.c = _.sample(["red", "orange", "yellow", "green", "cyan", "blue", "white"]);
// 小球坐标x的增量为-4到4之间的整数(参数随便)
this.dx = _.random(-4, 4);
// 小球坐标y的增量为-4到4之间的整数(参数随便)
this.dy = _.random(-4, 4);
// 把生成的小球存入数组ballsArr
ballsArr.push(this);
}
// 给所有Balls绑定一个方法update,目的是为了每次都能按照随机方向移动
Balls.prototype.update = function (){
// 每次x坐标加上增量dx
this.x += this.dx;
// 每次y坐标加上增量dy
this.y += this.dy;
// 每次半径缩小0.5(参数随便)
this.r -= 0.5;
// 半径小于等于0的话,就从小球数组中移出
if(this.r <= 0){
_.without(ballsArr, this);
}
}
// 给所有Balls绑定一个方法render,目的是画圆。
Balls.prototype.render = function (){
// 半径小于等于0就没必要画了
if(this.r <= 0){
return;
}
// 开始绘制
ctx.beginPath();
// 绘制圆形,(圆心坐标x,圆心坐标y, 起始弧度,终止弧度,[顺逆时针])
ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI);
// 颜色为数组中随机的一个
ctx.fillStyle = this.c;
// 画上画布
ctx.fill();
// 终止绘制
ctx.closePath();
}
// onmousemove事件监听
cvs.onmousemove = function (){
new Balls(event.offsetX, event.offsetY);
new Balls(event.offsetX, event.offsetY);
}
// setInterval 模拟25FPS的帧率
setInterval(function (){
// 因为canvas上屏即像素化,所以先清屏
ctx.clearRect(0, 0, cvs.width, cvs.height);
// _.each方法是针对每一个前面的元素,都运行后面的方法
_.each(ballsArr, function (value){
value.update();
value.render();
});
}, 40);
</script>
</body>