HTML Canvas 中的 Javascript Animation - 无法将动画保留在边框内
Javascript Animation in HTML Canvas - Can't keep animation within borders
我正在使用一个javascript动画,它在html画布中显示水中的涟漪。
这是javascript代码和jfiddle链接
(function(){
var canvas = document.getElementById('c'),
/** @type {CanvasRenderingContext2D} */
ctx = canvas.getContext('2d'),
width = 400,
height = 400,
half_width = width >> 1,
half_height = height >> 1,
size = width * (height + 2) * 2,
delay = 30,
oldind = width,
newind = width * (height + 3),
riprad = 3,
ripplemap = [],
last_map = [],
ripple,
texture,
line_width = 20,
step = line_width * 2,
count = height / line_width;
canvas.width = width;
canvas.height = height;
with (ctx) {
fillStyle = '#a2ddf8';
fillRect(0, 0, width, height);
fillStyle = '#07b';
save();
rotate(-0.785);
for (var i = 0; i < count; i++) {
fillRect(-width, i * step, width * 3, line_width);
}
restore();
}
texture = ctx.getImageData(0, 0, width, height);
ripple = ctx.getImageData(0, 0, width, height);
for (var i = 0; i < size; i++) {
last_map[i] = ripplemap[i] = 0;
}
/**
* Main loop
*/
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
}
/**
* Disturb water at specified point
*/
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var j = dy - riprad; j < dy + riprad; j++) {
for (var k = dx - riprad; k < dx + riprad; k++) {
ripplemap[oldind + (j * width) + k] += 128;
}
}
}
/**
* Generates new ripples
*/
function newframe() {
var a, b, data, cur_pixel, new_pixel, old_data;
var t = oldind; oldind = newind; newind = t;
var i = 0;
// create local copies of variables to decrease
// scope lookup time in Firefox
var _width = width,
_height = height,
_ripplemap = ripplemap,
_last_map = last_map,
_rd = ripple.data,
_td = texture.data,
_half_width = half_width,
_half_height = half_height;
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
data -= _ripplemap[_newind];
data -= data >> 5;
_ripplemap[_newind] = data;
//where data=0 then still, where data>0 then wave
data = 1024 - data;
old_data = _last_map[i];
_last_map[i] = data;
if (old_data != data) {
//offsets
a = (((x - _half_width) * data / 1024) << 0) + _half_width;
b = (((y - _half_height) * data / 1024) << 0) + _half_height;
//bounds check
if (a >= _width) a = _width - 1;
if (a < 0) a = 0;
if (b >= _height) b = _height - 1;
if (b < 0) b = 0;
new_pixel = (a + (b * _width)) * 4;
cur_pixel = i * 4;
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
}
++i;
}
}
}
canvas.onmousemove = function(/* Event */ evt) {
disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
};
setInterval(run, delay);
// generate random ripples
var rnd = Math.random;
setInterval(function() {
disturb(rnd() * width, rnd() * height);
}, 700);
})();
问题是涟漪从画布的一侧溢出并在另一侧动画化,我想防止它们移动到相反的一侧。
谢谢!
在边缘停止波浪
要阻止波在边缘的传播,您需要限制添加干扰的函数,使其不会写过边缘。
所以改变...
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var y = dy - riprad; y < dy + riprad; y++) {
for (var x = dx - riprad; x < dx + riprad; x++) {
ripplemap[oldind + (y * width) + x] += 128;
}
}
}
自。。。
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var y = dy - riprad; y < dy + riprad; y++) {
for (var x = dx - riprad; x < dx + riprad; x++) {
// don't go past the edges.
if(y >= 0 && y < height && x >= 0 && x < width){
ripplemap[oldind + (y * width) + x] += 128;
}
}
}
}
并且您还需要更改函数中的波传播 newFrame
.传播由 data
中的值控制。值为零表示没有波和传播。因此,测试像素是否在边缘。如果像素是边缘像素,则只需通过将data
设置为零来停止波。为了节省 CPU 周期,我添加了 vars h
,w
height - 1
和width - 1
,因此您不必为每个像素执行两次减法。
更改函数中的代码newFrame
从...
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
}
自。。。
var w = _width - 1; // to save having to subtract 1 for each pixel
var h = _height - 1; // dito
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
// is the pixel on the edge
if(y === 0 || x === 0 || y === h || x === w){
data = 0; // yes edge pixel so stop propagation.
}else{
// not on the edge so just do as befor.
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
}
这并不完美,因为它会抑制从侧面反弹的波浪,但您没有太多的 CPU 时间,因此这是一个很好的解决方案。
一些注意事项。
使用requestAnimationFrame
而不是setInterval(run, delay)
来计时动画,因为如果设备无法处理 CPU 负载,则会导致某些设备使用您当前拥有的代码使页面崩溃。 requestAnimationFrame
将阻止这种情况发生。
将运行函数更改为
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
requestAnimationFrame(run);
}
在代码底部删除setInterval(run,delay);
并添加
requestAnimationFrame(run);
并将第二个setInterval
更改为
var drops = function() {
disturb(rnd() * width, rnd() * height);
setTimeout(drops,700)
};
drops();
切勿使用setInterval
,特别是对于这种类型的CPU密集型代码。您将导致许多计算机使页面崩溃。我们设置超时或请求动画帧代替。
同时删除创建纹理的 with
语句。
- 如何设置html元素填充的动画
- 分派点击事件并保留击键修饰符
- 如何使用动画实现纸张推车
- 如何在生成下载文件时显示加载动画
- 剑道网格jQuery动画()问题
- EaseJS拖放;放下(动画CC)电影剪辑的鼠标坐标
- jQuery Lazy加载动画滚动
- jquery动画可以通过编程链接吗
- Javascript将数学动画化
- 动画.CSS重播
- 制作一个不带HTML a标记但在动画播放完毕后指向其他页面的超链接
- 如何使用jQuery在动画中期加速动画
- HTML Canvas 中的 Javascript Animation - 无法将动画保留在边框内
- CSS:当 image1 动画不合适时,一组图像会移动,而它们应该保留在原处
- 如何从 css 动画关键帧获取图像以在完成后保留在页面上
- Raphael js - 在组上动画不透明度,同时保留单个元素的不透明度
- GSAP:在动画SVG时保留以前的转换
- 如何在背景中保留动画,在另一个元素后面
- 当Flash层放置在元素上时,保留CSS动画
- 使用jQuery更改HTML,但保留CSS3动画