HOWTO: Use CSS3 transitions to save space

Introduction

What do you do when you have a finite and small amount of space that you can use but need to squeeze multiple charts into it? CSS3 transitions to the rescue! The example below shows you how you can adjust the canvas tag's width and height so that you can fit nine canvas tags into the same space that a regular (or two) full-size canvas tags would take up. The canvas tags then have some CSS applied to them that makes them respond to them getting focus, become larger, and by using transitions, the expansion is animated.

I'll stress that the effect shown here does not use JavaScript! The trigger for the effect is when the canvas gains focus - in this case, that means that you can click on them. Tabbing to the canvas tags also works because that also gives the elements focus.

Being CSS, the transition effect is smooth and jerk-free and CSS is also used to remove the focus outline. The code to achieve this effect is shown below.

Example

[No canvas support] [No canvas support] [No canvas support] [No canvas support] [No canvas support] [No canvas support] [No canvas support] [No canvas support] [No canvas support]

The necessary HTML

These are the canvas tags that the charts are drawn on. The width and height attributes on the tags stipulate the full width and height of the canvas tags (ie when they're enlarged). Though the canvas tags are set by the CSS :focus pseudo-selector to be 90% of this. It's also necessary to add the tabindex attribute because without this the tags cannot be tabbed to and thus will not get focus.

<div id="container">
    <canvas id="cvs1" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs2" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs3" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs4" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs5" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs6" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs7" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs8" width="900" height="375" tabindex="1">[No canvas support]</canvas>
    <canvas id="cvs9" width="900" height="375" tabindex="1">[No canvas support]</canvas>
</div>

The CSS to define the sizes and transitions

CSS is used to size the canvas tags, position them and set the transition (animation) effect that you see when you click on the tags. It also turns off the focus ring that you see when you click on the tags. See the comments below for more details.

<style>
    /*
    * This is the <div> that the <canvas> tags are defined in. It's sized to
    * be the same size as the full-sized <canvas> tags (ie 900x375). It
    * also sets the position to relative so that the canvas tags
    * that it contains can be positioned absolutely. The margin-left and
    * margin-right properties are set to auto so that the block of charts is aligned
    * centrally in the page.
    */
    #container {
        position: relative;
        width: 900px;
        height: 375px;
        margin-left: auto;
        margin-right: auto;
    }

    /*
    * These styles are applied to all of the canvas tags. It makes them positioned
    * absolutely, turns off the focus ring (with the outline property), defines
    * the transition details (the animation effect) and sets the initial z-index
    * to zero.
    */
    #container canvas {
        outline: none;
        position: absolute;
        transition: top .5s, left .5s, width .5s, height .5s, z-index .5s, transform .25s, box-shadow .5s;
        transition-delay: .25s;
        z-index: 0;
        background-color: rgba(255,255,255,0.9);
        width: 300px;
        height: 125px;
    }

    /*
    * The following styles are applied to the canvas tags in
    * order to initially position them correctly.
    */
    #container canvas#cvs1 {top: 0;     left: 0;}
    #container canvas#cvs2 {top: 0;     left: 300px;}
    #container canvas#cvs3 {top: 125px; left: 0;}
    #container canvas#cvs4 {top: 125px; left: 300px;}
    #container canvas#cvs5 {top: 0;     left: 600px;}
    #container canvas#cvs6 {top: 125px; left: 600px;}
    #container canvas#cvs7 {top: 250px; left: 0;}
    #container canvas#cvs8 {top: 250px; left: 300px;}
    #container canvas#cvs9 {top: 250px; left: 600px;}

    /*
    * These styles are applied to the canvas tags when they
    * are clicked on - ie they get focus. They're repositioned,
    * resized and have a shadow applied to them.
    */
    #container canvas#cvs1:focus,
    #container canvas#cvs2:focus,
    #container canvas#cvs3:focus,
    #container canvas#cvs4:focus,
    #container canvas#cvs5:focus,
    #container canvas#cvs6:focus,
    #container canvas#cvs7:focus,
    #container canvas#cvs8:focus,
    #container canvas#cvs9:focus {
        top: 5%;
        left: 5%;
        width: 90%;
        height: 90%;
        z-index: 999;
        box-shadow: 0 0 25px #ccc;
    }

    /*
    * When the screen size is smaller the block of charts changes,
    * using media queries, from being three charts wide to two. The
    * small versions of the charts have to be repositioned as well
    * as the enlarged versions.
    */
    @media screen and (max-width: 700px) {
        #container {width: 600px; height: 625px}
        #container canvas#cvs1 {top: 0;     left: 0;}
        #container canvas#cvs2 {top: 0;     left: 300px;}
        #container canvas#cvs3 {top: 125px; left: 0;}
        #container canvas#cvs4 {top: 125px; left: 300px;}
        #container canvas#cvs5 {top: 250px; left: 0px;}
        #container canvas#cvs6 {top: 250px; left: 300px;}
        #container canvas#cvs7 {top: 375px; left: 0;}
        #container canvas#cvs8 {top: 375px; left: 300px;}
        #container canvas#cvs9 {top: 500px; left: 0px;}

        #container canvas#cvs1:focus,
        #container canvas#cvs2:focus,
        #container canvas#cvs3:focus,
        #container canvas#cvs4:focus,
        #container canvas#cvs5:focus,
        #container canvas#cvs6:focus,
        #container canvas#cvs7:focus,
        #container canvas#cvs8:focus,
        #container canvas#cvs9:focus {
            left: 0;
            width: 600px;
            height: 250px;
            z-index: 999;
            box-shadow: 0 0 25px #ccc;
        }

        #container canvas#cvs1:focus, #container canvas#cvs2:focus {top:-62.5px;}
        #container canvas#cvs3:focus, #container canvas#cvs4:focus {top:62.5px;}
        #container canvas#cvs5:focus, #container canvas#cvs6:focus {top:187.5px;}
        #container canvas#cvs7:focus, #container canvas#cvs8:focus {top:312.5px;}
        #container canvas#cvs9:focus {top:437.5px;}
    }</style>

The RGraph libraries and code

And finally here is the HTML to include the RGraph libraries and the JavaScript that creates the charts. There's nothing special happening here - just some basic charts.

<!--
    Include the RGraph libraries
-->
<script src="RGraph.common.core.js" ></script>
<script src="RGraph.bar.js" ></script>
<script src="RGraph.line.js" ></script>
<script src="RGraph.waterfall.js" ></script>
<script src="RGraph.hbar.js" ></script>

<!--
    This is the code that creates the charts. It's not using the
    window.onload event so it should be placed after the canvas
    tags in your page
-->
<script>
    new RGraph.Bar({
        id: 'cvs1',
        data: [4,5,3,1,2,6,5,4,8],
        options: {
            xaxisLabels: ['Dave','Loui','Luis','Pete','Olga','Steve','Kevin','John','Cuthbert'],
            textSize: 14
        }
    }).draw();

    new RGraph.Bar({
        id: 'cvs5',
        data: [4,7,9,5,3,7,6],
        options: {
            xaxisLabels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
            marginInner: 20
        }
    }).draw();

    new RGraph.Line({
        id: 'cvs2',
        data: [1,3,5,2,6,4,7,8,9],
        options: {
            xaxisLabels: ['Dave','Loui','Luis','Pete','Olga','Steve','Kevin','John','Cuthbert'],
            textSize: 14,
            spline: true
        }
    }).draw();

    new RGraph.Line({
        id: 'cvs6',
        data: [3,7,8,4,4,2,7],
        options: {
            xaxisLabels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
            textSize: 14,
            marginInner: 25,
            spline: true
        }
    }).draw();

    new RGraph.Waterfall({
        id: 'cvs3',
        data: [45,-2,-9,4,6,3,-23,2,4],
        options: {
            xaxisLabels: ['Dave','Loui','Luis','Pete','Olga','Steve','Kevin','John','Total'],
            textSize: 14
        }
    }).draw();

    new RGraph.Waterfall({
        id: 'cvs4',
        data: [4,5,3,1,2,6,5,4,-8],
        options: {
            xaxisLabels: ['Dave','Loui','Luis','Pete','Olga','Steve','Kevin','John','Total'],
            textSize: 14
        }
    }).draw();

    new RGraph.HBar({
        id: 'cvs7',
        data: [8,3,7,4,6,9,8],
        options: {
            yaxisLabels: ['Jolly','Wolly','Lolly','Colly','Dolly','Molly','Polly'],
            textSize: 14,
            marginLeft: 75,
            marginLeftAuto: false,
            marginInner: 10
        }
    }).draw();

    new RGraph.Line({
        id: 'cvs8',
        data: [8,3,7,4,6,9,8],
        options: {
            xaxisLabels: ['Jolly','Wolly','Lolly','Colly','Dolly','Molly','Polly'],
            textSize: 14,
            marginInner: 25,
            spline: true,
            linewidth: 20,
            shadow: true,
            backgroundGridVlines: false,
            backgroundGridBorder: false,
            xaxis: false,
            yaxis: false,
            textSize: 20
        }
    }).draw();

    new RGraph.Bar({
        id: 'cvs9',
        data: [7,3,9,7,4,8,3],
        options: {
            xaxisLabels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
            marginInner: 25
        }
    }).grow();
</script>

A downloadable demo

If you want to see a standalone demo page of this technique then there's one available in the download archive called bar-css-expand.html