首页 > 特效插件 > 粒子效果 >  html5气泡光晕特效正文

html5气泡光晕特效

特效介绍
canvas气泡

    基于html5+js+canvas的气泡光晕特效,气泡随机产生,大大小小铺满整个屏幕,并且缓缓移动,每次刷新,背景的渐变色都会变化。非常适合做网页背景来使用。由于代码比较简单,就不提供下载地址,直接按照下面的方法就可以了。
使用方法
1、如果要当做背景,请加入下面的css:
body, html {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: 0;
    padding: 0;
}
#background {
    position: fixed;
    top: 0;
    left: 0;
    z-index: -100;
}
否则的话,canvas就是一张图,并不能作为背景来使用

2、在适当位置加入canvas
<canvas id="background"></canvas>
3、在</body>前加入js
window.addEventListener("load", function() {
    var ctx = document.getElementById('background').getContext('2d');
    //gradient
    var options =
    {
        resolution: 1,
        gradient:
        {
            resolution: 4,
            smallRadius: 0,
            hue:
            {
                min: 0,
                max: 360
            },
            saturation:
            {
                min: 40,
                max: 80
            },
            lightness:
            {
                min: 25,
                max: 35
            }
        },
        bokeh:
        {
            count: 30,
            size:
            {
                min: 0.1,
                max: 0.3
            },
            alpha:
            {
                min: 0.05,
                max: 0.4
            },
            jitter:
            {
                x: 0.3,
                y: 0.3
            }
        },
        speed:
        {
            min: 0.0001,
            max: 0.001
        },
        debug:
        {
            strokeBokeh: false,
            showFps: false
        }
    };
    var mobile =
    {
        force: false,
        resolution: 0.5,
        bokeh:
        {
            count: 6
        }
    };
    //buffers
    var gradientBuffer = document.createElement('canvas').getContext('2d');
    var circleBuffer = document.createElement('canvas').getContext('2d');
    //render time, fps calculations, debug
    var time;
    var targetFps = 60; //not actual fps, but updates per second
    var curFps = 0;
    var cntFps = 0;
    var fps = 0;
    var w = 0;
    var h = 0;
    var scale = 0;
    //constants for faster calcs
    var pi2 = Math.PI * 2;
    //util functions
    function lerp(a, b, step) {
        return step * (b - a) + a;
    }
    function clamp(a) {
        if (a < 0) return 0;
        if (a > 1) return 1;
        return a;
    }
    function rand(obj) {
        return Math.random() * (obj.max - obj.min) + obj.min;
    }
    function newColor() {
        return new Color(
                rand(options.gradient.hue),
                rand(options.gradient.saturation),
                rand(options.gradient.lightness)
                );
    }

    function isMobile() {
        return (
                mobile.force
                || navigator.userAgent.match(/Android/i)
                || navigator.userAgent.match(/webOS/i)
                || navigator.userAgent.match(/iPhone/i)
                || navigator.userAgent.match(/iPad/i)
                || navigator.userAgent.match(/iPod/i)
                || navigator.userAgent.match(/BlackBerry/i)
                || navigator.userAgent.match(/Windows Phone/i)
               );
    }

    window.requestAnimFrame = (function(callback) {
        if (isMobile())
            return function(callback) {
                window.setTimeout(callback, 1000 / 10);
            };
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame
            || window.mozRequestAnimationFrame || window.oRequestAnimationFrame
            || window.msRequestAnimationFrame || function(callback) {
                window.setTimeout(callback, 1000 / 60);
            };
    })();

    //classes
    function Color(h, s, l) {
        this.h = h;
        this.s = s;
        this.l = l;

        this.str = function() {
            return this.h + ", " + this.s + "%, " + this.l +"%";
        }
    }
    function ColorPoint(x, y, color) {
        this.x = x;
        this.y = y;
        this.oldColor = color;
        this.newColor = color;
        this.step = 0;
        this.speed = 0;

        this.color = function() {
            return new Color(lerp(this.oldColor.h, this.newColor.h, this.step),
                    lerp(this.oldColor.s, this.newColor.s, this.step),
                    lerp(this.oldColor.l, this.newColor.l, this.step));
        }

    }
    var colorPoints = [
        new ColorPoint(0, 0, new Color(196, 59, 34)),
        new ColorPoint(0, 1, new Color(269, 79, 32)),
        new ColorPoint(1, 0, new Color(30, 42, 33)),
        new ColorPoint(1, 1, new Color(304, 47, 27))
    ];

    function BokehCircle(x, y, size, alpha) {
        this.oldX = x;
        this.oldY = y;
        this.oldSize = size;
        this.oldAlpha = alpha;
        this.newX = 0;
        this.newY = 0;
        this.newAlpha = 0;
        this.newSize = 0;
        this.step = 0;
        this.speed = 0;

        this.x = function() {
            return lerp(this.oldX, this.newX, this.step);
        }
        this.y = function() {
            return lerp(this.oldY, this.newY, this.step);
        }
        this.alpha = function() {
            return lerp(this.oldAlpha, this.newAlpha, this.step);
        }
        this.size = function() {
            return lerp(this.oldSize, this.newSize, this.step);
        }
    }
    var circles = [];

    function setJitter(circle) {
        circle.newX = clamp(circle.oldX + rand({
            min: -options.bokeh.jitter.x,
            max: options.bokeh.jitter.x
        }));
        circle.newY = clamp(circle.oldY + rand({
            min: -options.bokeh.jitter.y,
            max: options.bokeh.jitter.y
        }));
    }
    function resize() {
        var width = window.innerWidth;
        var height = window.innerHeight;

        w = width * options.resolution;
        h = height * options.resolution;
        scale = Math.sqrt(w * h);

        //actual canvas
        ctx.canvas.width = width;
        ctx.canvas.height = height;
        ctx.scale(1 / options.resolution, 1 / options.resolution);

        //圆
        var circleSize = options.bokeh.size.max * scale;
        circleBuffer.canvas.width = circleSize * 2 + 1;
        circleBuffer.canvas.height = circleSize * 2 + 1;

        circleBuffer.fillStyle = "rgb(255, 255, 255)";
        circleBuffer.beginPath();
        circleBuffer.arc(circleSize, circleSize, circleSize, 0, pi2);
        circleBuffer.closePath();
        circleBuffer.fill();

        //force render on mobile
        if (isMobile())
            render();
    }
    function softCopy(src, dest)
    {
        var i = 0;

        for (var property in src)
        {
            if (dest.hasOwnProperty(property))
                if (softCopy(src[property], dest[property]) == 0)
                    dest[property] = src[property];
            i++;
        }
        return i;
    }
    function init() {
        gradientBuffer.canvas.height = options.gradient.resolution;
        gradientBuffer.canvas.width = options.gradient.resolution;

        if (isMobile())
            softCopy(mobile, options);

        resize();

        colorPoints.forEach(function(point) {
            point.oldColor = newColor();
            point.newColor = newColor()
                point.speed = rand(options.speed);
        });

        for(i = 0; i < options.bokeh.count; i++) {
            circles.push(new BokehCircle(Math.random(), Math.random(),
                        rand(options.bokeh.size), rand(options.bokeh.alpha)));
            circles[i].newAlpha = rand(options.bokeh.alpha);
            circles[i].newSize = rand(options.bokeh.size);
            circles[i].speed = rand(options.speed);
            setJitter(circles[i]);
        }
    }
    function iterate() {
        var now = Date.now();
        curFps += (now - (time || now));
        cntFps++;
        var delta = (now - (time || now)) / (1000 / targetFps);
        time = now;

        if(curFps > 1000) {
            fps = 1000 / (curFps / cntFps);
            curFps -= 1000;
            cntFps = 0;
        }

        colorPoints.forEach(function(point) {
            point.step += point.speed * delta;

            if (point.step >= 1) {
                point.step = 0;

                point.oldColor = point.newColor;

                point.newColor = newColor();
                point.speed = rand(options.speed);
            }
        });

        circles.forEach(function(circle) {
            circle.step += circle.speed * delta;
            if(circle.step >= 1) {
                circle.step = 0;

                circle.oldX = circle.newX;
                circle.oldY = circle.newY;
                circle.oldAlpha = circle.newAlpha;
                circle.oldSize = circle.newSize;

                setJitter(circle);
                circle.newAlpha = rand(options.bokeh.alpha);
                circle.newSize = rand(options.bokeh.size);
                circle.speed = rand(options.speed);
            }
        });
    }

    function render() {
        iterate();

        //绘制点渐变到缓冲区
        colorPoints.forEach(function(point) {
            var x = point.x * options.gradient.resolution;
            var y = point.y * options.gradient.resolution;
            var grad = gradientBuffer.createRadialGradient(x, y,
                    options.gradient.smallRadius, x, y,
                    options.gradient.resolution);
            grad.addColorStop(0, 'hsla(' + point.color().str() + ', 255)');
            grad.addColorStop(1, 'hsla(' + point.color().str() + ', 0)');

            gradientBuffer.fillStyle = grad;
            gradientBuffer.fillRect(0, 0,
                    options.gradient.resolution, options.gradient.resolution);
        });

        //绘制渐变
        ctx.globalCompositeOperation = "source-over";
        ctx.drawImage(gradientBuffer.canvas, 0, 0, w, h);

        //绘制气泡
        ctx.globalCompositeOperation = "overlay";
        if (options.debug.strokeBokeh)
            ctx.strokeStyle = "yellow";

        circles.forEach(function(circle) {
            var size = circle.size() * scale;

            ctx.globalAlpha = circle.alpha();
            ctx.drawImage(circleBuffer.canvas,
                    circle.x() * w - size / 2, circle.y() * h - size / 2,
                    size, size);

            if(options.debug.strokeBokeh) {
                ctx.globalAlpha = 1;
                ctx.globalCompositeOperation = "source-over";
                ctx.strokeRect(circle.x() * w - size / 2,
                        circle.y() * h - size / 2, size, size);
                ctx.globalCompositeOperation = "overlay";
            }
        });
        ctx.globalAlpha = 1;

        if (options.debug.showFps) {
            if(fps <= 10) ctx.fillStyle = 'red';
            else ctx.fillStyle = 'yellow';

            ctx.font = "20px sans-serif";
            ctx.fillText(Math.round(fps) + " fps", 10, 20);
        }

        //渲染完成,等待帧
        window.requestAnimFrame(render);
    }

    //不影响性能
    window.addEventListener("resize", resize);

    //初始化和渲染
    init();
    render();
});
如果要调整气泡的大小、随机数量、背景色等,请修改上面的js