Tutorial

Drawing and Animating Jelly Shapes with Canvas

Draft updated on Invalid Date
    Default avatar

    By Luis Manuel

    Drawing and Animating Jelly Shapes with Canvas

    This tutorial is out of date and no longer maintained.

    Introduction

    In recent times, we have seen that the web is no longer a page in a browser full of squares. Every day there are more designs that incorporate irregular shapes.

    In this tutorial, we want to teach you how to create and animate shapes with a jelly effect. In the end, you will be able to create the jelly shape you want and animate it according to your needs without too much effort.

    Specifically, in this first part we will see how to achieve the following result:

    Animated gif of jelly animation.

    The maths behind an effect like this can be very difficult to achieve. That’s why we have tried to group the code needed to create and animate jelly shapes in a library that is easy to use for developers.

    At the same time, we have been inspired by this pen by Thom Chiovoloni, inspired as well in the game The Floor is Jelly. And we have started specifically from this implementation of the jelly physics.

    So, we’ve packaged this implementation into a library we’ve just called jelly.js, to which we’ve added everything we need to get jelly shapes easily. Then let’s see how to use it!

    Creating the shapes with SVG paths

    We have chosen SVG paths to create the shapes because we believe it is the easiest and most customizable way we have to do it. In this way, we can create the shapes that we want in a vector editor (like Inkscape or Illustrator), and insert them directly into our HTML document, or even import them from JavaScript.

    For example, we can draw a simple shape like this:

    Pentagon

    Then we can include the relevant SVG code directly in the HTML:

    <!-- SVG with a pentagon path -->
    <!-- Note the `display: none` style, because we don't want to show the SVG, but just get the path from JavaScript -->
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="400" style="display: none">
        <path id="pentagon-path" d="m200 97.218 108.07 78.524-41.28 127.04h-133.58l-41.281-127.04z"/>
    </svg>
    

    Setup the markup

    We also need a canvas to draw the shape, and some other elements with the aim of moving a letter (S, from Scotch) coordinately with the centroid (average point) of the shape.

    <div class="jelly-container">
        <!-- Canvas to draw the jelly pentagon -->
        <canvas class="jelly-canvas"></canvas>
    
        <!-- Text in the centroid of the jelly pentagon -->
        <div class="centroid-container">
            <div class="centroid-text">S</div>
        </div>
    </div>
    

    A bit of style

    For this example, we need very few styles. Let’s see the code:

    /* General styles */
    
    html, body {
      margin: 0;
    }
    
    body {
      background-color: #D98327;
      overflow: hidden;
    }
    
    /* Jelly styles */
    
    .jelly-container {
      position: relative;
      display: inline-block;
      left: 50%;
      margin-left: -200px;
    }
    
    .jelly-container, .jelly-canvas {
      width: 400px;
      height: 400px;
    }
    
    /* It's important to position the `.centroid-container` in the top-left corner
       This way the `.centroid-text` will be positioned in the center (with JavaScript) */
    .centroid-container {
      position: absolute;
      left: 0;
      top: 0;
      transform: translate(-50%, -50%);
      pointer-events: none;
    }
    
    .centroid-text {
      font-size: 100px;
      color: white;
    }
    

    Making it jelly

    Finally, we have arrived at the most fun part! Let’s draw our pentagon on the canvas and see how we can animate it in a jelly way. But don’t worry, it will be very easy using our library.

    We just need a few lines of code to draw our pentagon, and to get it reacting in a jelly way if we move the mouse to the edges of the shape:

    /* Setup options */
    
    var options = {
        paths: '#pentagon-path',     // Shape we want to draw
        pointsNumber: 10,            // Number of points
        maxDistance: 70,             // Max distance among points
        color: '#5C1523',
        centroid: '.centroid-text'   // Element to move accordingly with the centroid of the shape
        // debug: true               // Uncomment this to see the points
    };
    
    /* Initializing jelly */
    
    var jelly = new Jelly('.jelly-canvas', options);
    

    Note that the constructor of our library (Jelly) receives a canvas element and a set of options. We can also provide an array of options, a set of options for each shape we want to draw. For a detailed description of the available options, you can check the GitHub repository.

    We could leave it there, but our library has much more to offer. So let’s look at some other things we can do.

    Implementing a jelly dragging

    To illustrate a little more the options we have (and for fun), let’s see how we can shake our pentagon as we drag it across the screen.

    First, we need to know when the mouse is inside the shape, to allow dragging it only when that happens. Check the following code, doing just that:

    /* Check hover item (shape) and update cursor */
    
    var container = document.querySelector('.jelly-container');
    var hoverIndex = -1;
    
    function checkHover() {
        // The `getHoverIndex` function will return the index of the shape being hovered, or -1
        hoverIndex = jelly.getHoverIndex();
        container.style.cursor = hoverIndex === -1 ? 'default' : 'pointer';
        window.requestAnimationFrame(checkHover);
    }
    window.requestAnimationFrame(checkHover);
    

    And let’s see how we can implement a basic dragging logic. Please look at the comments to understand what is happening there, and pay special attention to the shake function:

    /* Drag and drop */
    
    var startX, startY, dx, dy, endX = 0, endY = 0, x = 0, y = 0, lastX = 0, lastY = 0;
    var down = false;
    // This will be the max distance for shaking
    var shakeLimit = 5;
    
    container.addEventListener('mousedown', function (e) {
        if (hoverIndex >= 0) {
            startX = e.clientX;
            startY = e.clientY;
            down = true;
        }
    });
    
    document.addEventListener('mousemove', function (e) {
        if (down) {
            x = e.clientX - startX;
            y = e.clientY - startY;
            container.style.transform = 'translate(' + (endX + x) + 'px, ' + (endY + y) + 'px)';
    
            dx = x - lastX;
            dy = y - lastY;
            if (dx > shakeLimit || dx < - shakeLimit) dx = dx < 0 ? - shakeLimit : shakeLimit;
            if (dy > shakeLimit || dy < - shakeLimit) dy = dy < 0 ? - shakeLimit : shakeLimit;
    
            // The `shake` function will "move" the half of the points (alternately) the distance defined
            jelly.shake({x: - dx, y: - dy});
    
            lastX = x;
            lastY = y;
        }
    });
    
    function mouseUp() {
        if (down) {
            down = false;
            endX += x;
            endY += y;
        }
    }
    
    document.addEventListener('mouseup', mouseUp);
    
    document.addEventListener('mouseout', function (e) {
        if (e.target.nodeName == 'HTML') {
            mouseUp();
        }
    });
    

    Performance and browser support

    The browser support is really good because all modern browsers have support for canvas. But jelly.js uses Promises, so we need a polyfill for any browser that does not support native promises.

    On the other hand, the performance is very variable according to the browsers and the operating systems. This is due to the CPU-intensive work in each animation frame. So, don’t abuse the use of these effects, because they can kill website performance.

    Conclusion

    And we are done! So far we have created a truly jelly pentagon without too much effort. Our shape also change the cursor on hover event, and respond to dragging in a jelly way as well :)

    You can see the final demo here, and you can get the full code on GitHub too.

    These are not the only things we can do. In fact, in the second part of this tutorial, we will build an awesome slider, where everything will be jelly. In broad outline, we will learn how to:

    • Draw more jelly shapes and text!
    • Use images inside the shapes, not only solid colors.
    • Animate the shapes to show or hide them smoothly.
    • Morph from a jelly shape to another.
    • Make the entire slider responsive.

    We really hope you enjoyed it and found it useful! See you in the second part.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about us


    About the authors
    Default avatar
    Luis Manuel

    author

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    Leave a comment
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more
    DigitalOcean Cloud Control Panel