JavaScript HTML5 Canvas Animation Background

JavaScript HTML5 Canvas Animation Background
Code Snippet:Ribbons Effect With HTML5 Canvas and Javascript
Author: Rainner Lins
Published: January 11, 2024
Last Updated: January 22, 2024
Downloads: 6,872
License: MIT
Edit Code online: View on CodePen
Read More

This JavaScript code snippet helps you to create HTML5 canvas animation background. It draws an attractive low-poly ribbons background effect inside a target container. The ribbon’s color and size can be customized according to your needs. You can use this for website background to attract users.

How to Create JavaScript HTML5 Canvas Animation Background

1. First of all, add the following CSS styles to your project:

body {
  background-color: #403060;
  background-image: radial-gradient(circle, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-size: cover;
}

3. Then, add the following JavaScript code and done.

/**
 * Ribbons Class File.
 * Creates low-poly ribbons background effect inside a target container.
 */
(function( name, factory )
{
   if( typeof window === "object" )
   {
       window[ name ] = factory();
   }

})( "Ribbons", function()
{
    var _w = window,
        _b = document.body,
        _d = document.documentElement;

    // random helper
    var random = function()
    {
        if( arguments.length === 1 ) // only 1 argument
        {
            if( Array.isArray( arguments[0] ) ) // extract index from array
            {
                var index = Math.round( random( 0, arguments[0].length - 1 ) );
                return arguments[0][ index ];
            }
            return random( 0, arguments[0] ); // assume numeric
        }
        else if( arguments.length === 2 ) // two arguments range
        {
            return Math.random() * ( arguments[1] - arguments[0] ) + arguments[0];
        }
        return 0; // default
    };

    // screen helper
    var screenInfo = function( e )
    {
        var width   = Math.max( 0, _w.innerWidth || _d.clientWidth || _b.clientWidth || 0 ),
            height  = Math.max( 0, _w.innerHeight || _d.clientHeight || _b.clientHeight || 0 ),
            scrollx = Math.max( 0, _w.pageXOffset || _d.scrollLeft || _b.scrollLeft || 0 ) - ( _d.clientLeft || 0 ),
            scrolly = Math.max( 0, _w.pageYOffset || _d.scrollTop || _b.scrollTop || 0 ) - ( _d.clientTop || 0 );

        return {
            width   : width,
            height  : height,
            ratio   : width / height,
            centerx : width / 2,
            centery : height / 2,
            scrollx : scrollx,
            scrolly : scrolly,
        };
    };

    // mouse/input helper
    var mouseInfo = function( e )
    {
        var screen = screenInfo( e ),
            mousex = e ? Math.max( 0, e.pageX || e.clientX || 0 ) : 0,
            mousey = e ? Math.max( 0, e.pageY || e.clientY || 0 ) : 0;

        return {
            mousex  : mousex,
            mousey  : mousey,
            centerx : mousex - ( screen.width / 2 ),
            centery : mousey - ( screen.height / 2 ),
        };
    };

    // point object
    var Point = function( x, y )
    {
        this.x = 0;
        this.y = 0;
        this.set( x, y );
    };
    Point.prototype = {
        constructor: Point,

        set: function( x, y )
        {
            this.x = ( x || 0 );
            this.y = ( y || 0 );
        },
        copy: function( point )
        {
            this.x = ( point.x || 0 );
            this.y = ( point.y || 0 );
            return this;
        },
        multiply: function( x, y )
        {
            this.x *= ( x || 1 );
            this.y *= ( y || 1 );
            return this;
        },
        divide: function( x, y )
        {
            this.x /= ( x || 1 );
            this.y /= ( y || 1 );
            return this;
        },
        add: function( x, y )
        {
            this.x += ( x || 0 );
            this.y += ( y || 0 );
            return this;
        },
        subtract: function( x, y )
        {
            this.x -= ( x || 0 );
            this.y -= ( y || 0 );
            return this;
        },
        clampX: function( min, max )
        {
            this.x = Math.max( min, Math.min( this.x, max ) );
            return this;
        },
        clampY: function( min, max )
        {
            this.y = Math.max( min, Math.min( this.y, max ) );
            return this;
        },
        flipX: function()
        {
            this.x *= -1;
            return this;
        },
        flipY: function()
        {
            this.y *= -1;
            return this;
        },
    };

    // class constructor
    var Factory = function( options )
    {
        this._canvas  = null;
        this._context = null;
        this._sto     = null;
        this._width   = 0;
        this._height  = 0;
        this._scroll  = 0;
        this._ribbons = [];
        this._options = {
            // ribbon color HSL saturation amount
            colorSaturation: "80%",
            // ribbon color HSL brightness amount
            colorBrightness: "60%",
            // ribbon color opacity amount
            colorAlpha: 0.65,
            // how fast to cycle through colors in the HSL color space
            colorCycleSpeed : 6,
            // where to start from on the Y axis on each side (top|min, middle|center, bottom|max, random)
            verticalPosition : "center",
            // how fast to get to the other side of the screen
            horizontalSpeed : 150,
            // how many ribbons to keep on screen at any given time
            ribbonCount: 3,
            // add stroke along with ribbon fill colors
            strokeSize: 0,
            // move ribbons vertically by a factor on page scroll
            parallaxAmount : -0.5,
            // add animation effect to each ribbon section over time
            animateSections : true,
        };
        this._onDraw   = this._onDraw.bind( this );
        this._onResize = this._onResize.bind( this );
        this._onScroll = this._onScroll.bind( this );
        this.setOptions( options );
        this.init();
    };

    // class prototype
    Factory.prototype = {
        constructor: Factory,

        // Set and merge local options
        setOptions: function( options )
        {
            if( typeof options === "object" )
            {
                for( var key in options )
                {
                    if( options.hasOwnProperty( key ) )
                    {
                        this._options[ key ] = options[ key ];
                    }
                }
            }
        },

        // Initialize the ribbons effect
        init: function()
        {
            try
            {
                this._canvas = document.createElement( "canvas" );
                this._canvas.style["display"] = "block";
                this._canvas.style["position"] = "fixed";
                this._canvas.style["margin"] = "0";
                this._canvas.style["padding"] = "0";
                this._canvas.style["border"] = "0";
                this._canvas.style["outline"] = "0";
                this._canvas.style["left"] = "0";
                this._canvas.style["top"] = "0";
                this._canvas.style["width"] = "100%";
                this._canvas.style["height"] = "100%";
                this._canvas.style["z-index"] = "-1";
                this._onResize();

                this._context = this._canvas.getContext( "2d" );
                this._context.clearRect( 0, 0, this._width, this._height );
                this._context.globalAlpha = this._options.colorAlpha;

                window.addEventListener( "resize", this._onResize );
                window.addEventListener( "scroll", this._onScroll );
                document.body.appendChild( this._canvas );
            }
            catch( e ) {
                console.warn( "Canvas Context Error: " + e.toString() );
                return;
            }
            this._onDraw();
        },

        // Create a new random ribbon and to the list
        addRibbon: function()
        {
            // movement data
            var dir    = ( Math.round( random( 1, 9 ) ) > 5 ) ? "right" : "left",
                stop   = 1000,
                hide   = 200,
                min    = 0 - hide,
                max    = this._width + hide,
                movex  = 0,
                movey  = 0,
                startx = ( dir === "right" ) ? min : max,
                starty = Math.round( random( 0, this._height ) );

            // asjust starty based on options
            if( /^(top|min)$/i.test( this._options.verticalPosition ) )
            {
                starty = 0 + hide;
            }
            else if( /^(middle|center)$/i.test( this._options.verticalPosition ) )
            {
                starty = ( this._height / 2 );
            }
            else if( /^(bottom|max)$/i.test( this._options.verticalPosition ) )
            {
                starty = this._height - hide;
            }

            // ribbon sections data
            var ribbon = [],
                point1 = new Point( startx, starty ),
                point2 = new Point( startx, starty ),
                point3 = null,
                color  = Math.round( random( 0, 360 ) ),
                delay  = 0;

            // buils ribbon sections
            while( true )
            {
                if( stop <= 0 ) break; stop--;

                movex = Math.round( ( Math.random() * 1 - 0.2 ) * this._options.horizontalSpeed );
                movey = Math.round( ( Math.random() * 1 - 0.5 ) * ( this._height * 0.25 ) );

                point3 = new Point();
                point3.copy( point2 );

                if( dir === "right" )
                {
                    point3.add( movex, movey );
                    if( point2.x >= max ) break;
                }
                else if( dir === "left" )
                {
                    point3.subtract( movex, movey );
                    if( point2.x <= min ) break;
                }
                // point3.clampY( 0, this._height );

                ribbon.push({ // single ribbon section
                    point1 : new Point( point1.x, point1.y ),
                    point2 : new Point( point2.x, point2.y ),
                    point3 : point3,
                    color  : color,
                    delay  : delay,
                    dir    : dir,
                    alpha  : 0,
                    phase  : 0,
                });

                point1.copy( point2 );
                point2.copy( point3 );

                delay += 4;
                color += this._options.colorCycleSpeed;
            }
            this._ribbons.push( ribbon );
        },

        // Draw single section
        _drawRibbonSection: function( section )
        {
            if( section )
            {
                if( section.phase >= 1 && section.alpha <= 0 )
                {
                    return true; // done
                }
                if( section.delay <= 0 )
                {
                    section.phase += 0.02;
                    section.alpha = Math.sin( section.phase ) * 1;
                    section.alpha = ( section.alpha <= 0 ) ? 0 : section.alpha;
                    section.alpha = ( section.alpha >= 1 ) ? 1 : section.alpha;

                    if( this._options.animateSections )
                    {
                        var mod = ( Math.sin( 1 + section.phase * Math.PI / 2 ) * 0.1 );

                        if( section.dir === "right" )
                        {
                            section.point1.add( mod, 0 );
                            section.point2.add( mod, 0 );
                            section.point3.add( mod, 0 );
                        } else {
                            section.point1.subtract( mod, 0 );
                            section.point2.subtract( mod, 0 );
                            section.point3.subtract( mod, 0 );
                        }
                        section.point1.add( 0, mod );
                        section.point2.add( 0, mod );
                        section.point3.add( 0, mod );
                    }
                }
                else { section.delay -= 0.5; }

                var s = this._options.colorSaturation,
                    l = this._options.colorBrightness,
                    c = "hsla("+ section.color +", "+ s +", "+ l +", "+ section.alpha +" )";

                this._context.save();

                if( this._options.parallaxAmount !== 0 )
                {
                    this._context.translate( 0, this._scroll * this._options.parallaxAmount );
                }
                this._context.beginPath();
                this._context.moveTo( section.point1.x, section.point1.y );
                this._context.lineTo( section.point2.x, section.point2.y );
                this._context.lineTo( section.point3.x, section.point3.y );
                this._context.fillStyle = c;
                this._context.fill();

                if( this._options.strokeSize > 0 )
                {
                    this._context.lineWidth = this._options.strokeSize;
                    this._context.strokeStyle = c;
                    this._context.lineCap = "round";
                    this._context.stroke();
                }
                this._context.restore();
            }
            return false; // not done yet
        },

        // Draw ribbons
        _onDraw: function()
        {
            // cleanup on ribbons list to rtemoved finished ribbons
            for( var i = 0, t = this._ribbons.length; i < t; ++i )
            {
                if( !this._ribbons[ i ] )
                {
                    this._ribbons.splice( i, 1 );
                }
            }
           
            // draw new ribbons 
            this._context.clearRect( 0, 0, this._width, this._height );

             for( var a = 0; a < this._ribbons.length; ++a ) // single ribbon
             {
                 var ribbon = this._ribbons[ a ],
                     numSections = ribbon.length,
                     numDone = 0;

                 for( var b = 0; b < numSections; ++b ) // ribbon section
                 {
                     if( this._drawRibbonSection( ribbon[ b ] ) )
                     {
                         numDone++; // section done
                     }
                 }
                 if( numDone >= numSections ) // ribbon done
                 {
                     this._ribbons[ a ] = null;
                 }
             }
             // maintain optional number of ribbons on canvas
             if( this._ribbons.length < this._options.ribbonCount )
             {
                 this.addRibbon();
             }
            requestAnimationFrame( this._onDraw );
        },

        // Update container size info
        _onResize: function( e )
        {
            var screen   = screenInfo( e );
            this._width  = screen.width;
            this._height = screen.height;

            if( this._canvas )
            {
                this._canvas.width  = this._width;
                this._canvas.height = this._height;
                
               if( this._context )
               {
                  this._context.globalAlpha = this._options.colorAlpha;
               }
            }
        },

        // Update container size info
        _onScroll: function( e )
        {
            var screen   = screenInfo( e );
            this._scroll = screen.scrolly;
        },

    };

    // export
    return Factory;
});


new Ribbons({
  colorSaturation: "60%",
  colorBrightness: "50%",
  colorAlpha: 0.5,
  colorCycleSpeed : 5,
  verticalPosition : "random",
  horizontalSpeed : 200,
  ribbonCount: 3,
  strokeSize: 0,
  parallaxAmount : -0.2,
  animateSections : true,
});

That’s all! hopefully, you have successfully integrated this HTML5 canvas animation background code snippet into your project. If you have any questions or are facing any issues, please feel free to comment below.

3 thoughts on “JavaScript HTML5 Canvas Animation Background”

  1. Hello, every time i refresh the page it says “Ribbons is not defined” at row 449 “new Ribbons” and i have to delete a part of the code then refres hand put it back for it to work again, however then it breaks again if i refresh

    Reply
    • Hi

      Please make sure Ribbons Class File is included in your project and does not conflict with other JavaScript files. Follow the tutorial carefully to integrate it into your project.

      Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About CodeHim

Free Web Design Code & Scripts - CodeHim is one of the BEST developer websites that provide web designers and developers with a simple way to preview and download a variety of free code & scripts. All codes published on CodeHim are open source, distributed under OSD-compliant license which grants all the rights to use, study, change and share the software in modified and unmodified form. Before publishing, we test and review each code snippet to avoid errors, but we cannot warrant the full correctness of all content. All trademarks, trade names, logos, and icons are the property of their respective owners... find out more...

Please Rel0ad/PressF5 this page if you can't click the download/preview link

X