Winwheel.js tutorial: #16 Creating Pie graphs


In this tutorial I will show you how to create Pie graphs using Winwheel.js. While this is the not the primary use of the code it is fairly easy to create pie graphs given that like winning wheels they are a circle with segments inside.


The main difference between creating a winning wheel and a pie graph is that you will want to specify the size of each segment to match the percentage the data in the segment is out of a total of 100%.


The segment objects have a .size property which must be set, but as the size must be degrees 0-360 rather than a percent I have created a helper function called winwheelPercentToDegrees() which will convert a percentage 0-100% to 0-360 degrees of the wheel.


The function is named winwheelPercentToDegrees() because it is not part of the Winwheel class so you can use it at the time of creating a Winning wheel object and passing in the constructor parameters. Otherwise you would first need to create the wheel object and then set the segment size afterwards.



Pie graph - full example


In this example I create a pie graph setting the segment size using the percentToDegrees() helper function, also I use HTML5 canvas code to draw some boxes and text for the legend, and finally on click of the segments I use the getSegmentAt() feature (described in previous tutorial) to populate a div on the page with some additional information about the item clicked.


Note that because JavaScript is loosely typed language you can add any property to the segments or wheel object you desire (so long as it does not conflict with anything) and that is what I do here with the moreInfo property on the segments to hold the text for the div where more info is displayed when the user clicks the segments.


<div id='moreInfo'></div>

<script>
    let theWheel = new Winwheel({
        'numSegments'   : 4,
        'outerRadius'   : 170,
        'centerX'       : 190,  // By default wheel goes in center of canvas, move to left side.
        'segments'      :
        [
            // Define segments. The moreInfo property is not a standard parameter of segments
            // but because JavaScript is loosely typed if I want moreInfo property I can add it.
            {
                'fillStyle' : '#eae56f',
                'text'      : 'Data 1 (45%)',
                'size'      : winwheelPercentToDegrees(45),   // Note use of winwheelPercentToDegrees()
                'moreInfo'  : '<p>Data 1 is the biggest slice of the pie at 45% for this year!</p>'
            },
            {
                'fillStyle' : '#89f26e',
                'text'      : 'Data 2 (20%)',
                'size'      : winwheelPercentToDegrees(20),
                'moreInfo'  : '<p>Data 2 is selling well making up 20% of our sales.</p>'
            },
            {
                'fillStyle' : '#7de6ef',
                'text'      : 'Data 3 (5%)',
                'size'      : winwheelPercentToDegrees(5),
                'moreInfo'  : '<p>Data 3 only making up 5% of our sales.</p>'
            },
            {
                'fillStyle' : '#e7706f',
                'text'      : 'Data 4 (30%)',
                'size'      : winwheelPercentToDegrees(30),
                'moreInfo'  : '<p>Data 4 was a strong performer of the last year at 30% of sales.</p>'
            }
        ]
    });

    // Call function to draw legend boxes passing x and y co-ordinates of where to start the legend boxes.
    drawLegend(420, 90);

    // Function to draw legend, change x and y to change position of it
    // (ensure the canvas has enough width to fit the legend to the right).
    function drawLegend(x, y)
    {
        // Get context to same canvas used by wheel.
        let ctx = theWheel.ctx;

        // Set some HTML 5 canvas drawing options.
        ctx.lineWidth = 1;
        ctx.strokeStyle = 'black';
        ctx.font = '14px verdana';

        // Loop though segments in the wheel and create boxes.
        for (idx = 1; idx <= theWheel.numSegments; idx++) {
            // These are raw canvas functions you may want to learn about.
            ctx.beginPath();
            ctx.fillStyle = theWheel.segments[idx].fillStyle;
            ctx.rect(x, y, 40, 40);
            ctx.stroke();
            ctx.fill();

            // Do the text centred to the right.
            ctx.fillStyle = 'black';
            ctx.fillText(theWheel.segments[idx].text, x + 50, y + 25);

            // Move down after each one with gap in between.
            y += 55;

            // Reset the text fillstyle here so only 1 is red.
            theWheel.segments[idx].textFillStyle = 'black';
        }
    }

    // Get canvas and span objects.
    let canvas = document.getElementById('canvas');
    let moreInfo = document.getElementById('moreInfo');

    // Specify click handler for canvas.
    canvas.onclick = function (e)
    {
        // Call the getSegmentAt function passing the mouse x and y from the event.
        let clickedSegment = theWheel.getSegmentAt(e.clientX, e.clientY);

        // A pointer to the segment clicked is returned if the user clicked inside the wheel.
        if (clickedSegment) {
            // Set more info innerHTML.
            moreInfo.innerHTML = '<h3>' + clickedSegment.text + '</h3>' + clickedSegment.moreInfo;

            // Change clicked segment text to red.
            clickedSegment.textFillStyle = 'red';
            theWheel.draw();

            // Need to re-draw legend as wiped when wheel is re-drawn.
            drawLegend(420,90);
        }
    }

</script>


Graph Details
Canvas not supported Click Pie graph segment to see more information here.

Remember that segments in the wheel don't have to have the text drawn so if you have data items which make the segments too small for the text to fit inside (even with reduced font size) you can hide the text by setting the Winwheel.drawText property to false and only have it in the legend.


Also remember that you can animate pie graphs in other ways than spinning because GreenSock's TweenMax.js can animate any numeric property of the wheel over time. The custom Winwheel animation type would be the thing to use, or TweenMax.js directly. See the animation tutorials for more information of animating the wheel, or consider reading the TweenMax.js documentation.


Previous:
< #15 Getting the segment clicked
Next:
#17: Creating a Wheel with one Image per Segement >