2016-02-12 89 views
0

我正在使用一个javascript动画,它在html画布中显示水中的涟漪。HTML画布中的Javascript动画 - 无法在边框内保留动画

这是JavaScript代码和jfiddle link

(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); 
 
    
 
})();

问题是纹波从画布的一侧溢出和动画在对面,我要保留从移动到对面。

谢谢!

回答

0

在边缘

停止波要停止跨你需要限制,增加了干扰,使其不写过去的边缘功能的边缘波的传播。

因此改变......

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; 
      } 
     } 
    } 
} 

而且你还需要改变波的传播是在功能。传播由data中的值控制。零值表示没有波并且没有传播。因此,测试像素是否在边缘上。如果像素是边缘像素,则通过将data设置为零来停止波形。为了节省CPU周期,我添加了hw的变量height - 1width - 1,因此您不必为每个像素执行两次减法。

变更功能从代码...

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时间,所以这是一个很好的解决方案。

一些笔记。

使用​​而不是setInterval(run, delay)时间,你会造成某些设备与您目前拥有的代码崩溃的页面,如果设备无法处理的CPU负载动画。​​会停止这种情况发生。

改变运行功能

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(); 

NEVER使用setInterval特别是对于这种类型的CPU密集型代码。您将导致许多机器崩溃页面。我们改用setTimeout或requestAnimationFrame。

还删除您创建纹理的with声明。