canvas 水波效果

看到某些工具上有水波效果,想能不能用canvas实现呢,于是就google了一下还真有在这里与大家分享吧!

这里有一篇教程,介绍实现原理的,水波纹原理

 下面是js实现的源代码

var ripple = (function(img_src, container){
    var img = new Image, img_data, delay = 30, width, height, half_width, half_height, riprad = 5, oldind, newind, mapind, size, ripplemap = [], last_map = [], ripple, ripple_data, texture, texture_data, is_running = true, is_disturbed = false, timer_id, canvas = document.createElement('canvas'), /** @type {CanvasRenderingContext2D} */ ctx;
     
    function init(){
        width = img.width;
        height = img.height;
        half_width = width >> 1;
        half_height = height >> 1;
        size = width * (height + 2) * 2;
        canvas.width = width;
        canvas.height = height;
        oldind = width;
        newind = width * (height + 3);
         
        /** @type {CanvasRenderingContext2D} */
        ctx = canvas.getContext('2d');
        container.appendChild(canvas);
        ctx.drawImage(img, 0, 0, width, height);
        for (var i = 0; i < size; i++) {
            last_map[i] = ripplemap[i] = 0;
        }
        texture = ctx.getImageData(0, 0, width, height);
        texture_data = texture.data;
        ripple = ctx.getImageData(0, 0, width, height);
        ripple_data = ripple.data;
         
         
        canvas.addEventListener('mousemove', function(/* Event */evt){
            disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
        }, false);
        start();
        disturb(180,130);
    }
     
    function stop(){
        if (timer_id)
            clearInterval(timer_id);
    }
     
    function start(){
        stop();
        timer_id = setInterval(run, delay);
    }
     
    function run(){
        if (is_disturbed) {
            newframe(width, height);
            
            ctx.putImageData(ripple, 0, 0);
        }else{
             
        }
    }
     
    function disturb(dx, dy){
        dx <<= 0;
        dy <<= 0;
        is_disturbed = true;
         
        for (var j = dy - riprad; j < dy + riprad; j++) {
            for (var k = dx - riprad; k < dx + riprad; k++) {
                ripplemap[oldind + (j * width) + k] += 4048;
            }
        }
         
        //newframe(width, height);
        //ctx.putImageData(ripple, 0, 0);
    }
     
    function newframe(){
        var i, a, b, data, cur_pixel, new_pixel, old_data;
         
        i = oldind;
        oldind = newind;
        newind = i;
         
        i = 0;
        mapind = oldind;
        var _width = width, _height = height, _ripplemap = ripplemap, _mapind = mapind, _newind = newind, _last_map = last_map, _rd = ripple.data, _td = texture.data, _half_width = half_width, _half_height = half_height, _is_disturbed = false;
        for (var y = 0; y < _height; y++) {
            for (var x = 0; x < _width; x++) {
                data = (_ripplemap[_mapind - _width] +
                _ripplemap[_mapind + _width] +
                _ripplemap[_mapind - 1] +
                _ripplemap[_mapind + 1]) >>
                1;
                 
                data -= _ripplemap[_newind + i];
                data -= data >> 5;
                 
                _ripplemap[_newind + i] = 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
                    _is_disturbed = true;
                    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];
                    //_rd[cur_pixel + 3] = _td[new_pixel + 3];
                }
                 
                ++_mapind;
                ++i;
            }
        }
        mapind = _mapind;
        is_disturbed = _is_disturbed;
    }
     
    img.onload = init;
    img.src = img_src;
     
    return {
        start: start,
        stop: stop,
        disturb: disturb
    }
});

 与大家分享了!!!

 

分割线---------------------------------------------------------------------------------

 

 
posted @   dushaobin  Views(962)  Comments(2Edit  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示