这是 canvas 的 drawImage 方法对图片的一个应用
drawImage(obj,sx,sy,sw,sh,dx,dy,dw,dh)方法一共有 9 个参数,第一个参数看 MDN 的解释:
绘制到上下文的元素。允许任何的 canvas 图像源 (
CanvasImageSource
),例如:CSSImageValue
,HTMLImageElement
来操纵 <img> 元素的布局和图像.”),SVGImageElement
,HTMLVideoElement
,HTMLCanvasElement
,ImageBitmap
工厂方法模式,它可以从多种源中生成。ImageBitmap 提供了一种异步且高资源利用率的方式来为 WebGL 的渲染准备基础结构。”) 或者OffscreenCanvas
- 说的很清楚了,可以是 img 标签、svg 图片元素、video 标签、另一个 canvas、base64 和屏幕外的 canvas(内存里的)
- 其他八个参数可以分为两组,第一组标签分别是:sx,sy,sw,sh;s 表示 source(源)的意思,也就是对原图片要从哪个 x,y 坐标开始画以及要画多宽 sw 和多高 sh;同理,下一组的 dx,dy,dw,dh,d 表示 destination(目标点),要画在 canvas 里的哪个地方 dx、dy 以及要画多宽多高 dw、dh。
好,这些都了解了之后,开始讲原理:
来看下面这张图:
- 上面四张图表示小鱼在游的时候的动作,下面四张图表示被捕之后的动作,我们只用上面四张图,用 drawImage 不断的取第一条鱼第二条第三条第四条画在 canvas 上,画的时候把前面画的先清掉,就会有动画的效果了,我们要做的就是不断更新 sy(原图像的 y 坐标)和 dx(画在 canvas 上的鱼的 x 坐标)。
<canvas width="800" height="600" style="background:white;"></canvas>
获取对象,然后新建一个 image 对象:
let c1 = document.getElementsByTagName('canvas')[0];
let gd = c1.getContext('2d');
let oImg = new Image();
oImg.src = '录制 gif/fish1.png';
由于我们在执行 drawImage 操作的时候 oImg 可能还没创建完,所以我们加个 onload,然后用 requestAnimationFrame:
oImg.onload = function () {requestAnimationFrame(next);// 前面有介绍用法
function next() {
gd.drawImage(oImg,// 画鱼
0, 0, 55, 37,
100, 100, 55, 37
)
requestAnimationFrame(next);
}
}
重影了,得先清掉以前画的:
gd.clearRect(0,0,c1.width,c1.height);
更新 sy 的值不断的从上往下取那条小鱼,设置一个变量 i 不断的 ++:
let i = 0;
oImg.onload = function () {requestAnimationFrame(next);// 前面有介绍用法
function next() {gd.clearRect(0,0,c1.width,c1.height);
i++;
gd.drawImage(oImg,// 画鱼
0, 37*i, 55, 37,
100, 100, 55, 37
)
requestAnimationFrame(next);
}
}
咋一闪而过呢?
变量 i 太大了,图片就那么高,让 i ==4(第四条鱼)的时候归零:
if(i==4)i=0;
设置一个变量调下速:
window.onload = function () {let c1 = document.getElementsByTagName('canvas')[0];
let gd = c1.getContext('2d');
let oImg = new Image();
oImg.src = '录制 gif/fish1.png';
let i = 0;
let frameCounter = 0// 调速变量
oImg.onload = function () {requestAnimationFrame(next);// 前面有介绍用法
function next() {gd.clearRect(0, 0, c1.width, c1.height);
if (frameCounter % 3 == 0) {// 每 3 帧 i ++
i++;
if (i == 4) i = 0;
}
gd.drawImage(oImg,// 画鱼
0, 37 * i, 55, 37,
100, 100, 55, 37
)
frameCounter++;
requestAnimationFrame(next);
}
}
}
正常了
然后让他动起来,设置一个变量 x:
window.onload = function () {let c1 = document.getElementsByTagName('canvas')[0];
let gd = c1.getContext('2d');
let oImg = new Image();
oImg.src = '录制 gif/fish1.png';
let i = 0;
let frameCounter = 0// 调速变量
let x=100;// 让鱼动起来
oImg.onload = function () {requestAnimationFrame(next);// 前面有介绍用法
function next() {gd.clearRect(0, 0, c1.width, c1.height);
x+=2;// 调节鱼游动的速度
if (frameCounter % 3 == 0) {// 每 3 帧 i ++
i++;
if (i == 4) i = 0;
}
gd.drawImage(oImg,// 画鱼
0, 37 * i, 55, 37,
x, 100, 55, 37
)
frameCounter++;
requestAnimationFrame(next);
}
}
}
最后 可以加个鼠标点击页面然后小鱼暂停,再点击在动的事件:
这里我就不一步步教写了,核心的就是上面的部分,下面是完整的代码:
window.onload = function () {let c1 = document.getElementsByTagName('canvas')[0];
let gd = c1.getContext('2d');
let oImg = new Image();
oImg.src = '录制 gif/fish1.png';
let i = 0, x = 100;
let frameCounter = 0;
let pause = false;// 控制是否暂停
function move(pause) {// 小鱼运动函数
gd.clearRect(0, 0, c1.width, c1.height);
if(!pause){// 暂停了就不更新 x 的值, 不让他游
x += 2;
}
if (frameCounter % 3 == 0) {// 控制小鱼游动速度
i++;// 控制小鱼摆动速度
if (i == 4) i = 0;// 循环摆动
}
gd.drawImage(oImg,// 画鱼
0, 37 * i, 55, 37,
x, 100, 55, 37
)
frameCounter++;
}
oImg.onload = function () {requestAnimationFrame(next);// 前面有介绍用法
function next() {if (!pause) {// 如果没点暂停,小鱼就运动
move()}
else {// 点了就不游动,只摆动
move(pause);
}
requestAnimationFrame(next);
}
}
document.onclick = function () {pause = !pause;// 点击页面切换暂停或继续}
}
效果就是第一张图