Source: components/chart-pie.js

;(function () {
    'use strict';

    /**
     * Draw simple pie chart using svg.
     * @namespace
     */
    db.libs.pieChart = (function($){

        var name = 'pieChart';

        /**
         * Animates chart to values to in series.
         * @public
         * @memberof db.libs.pieChart
         * @param {external:jQuery|string} id Selector or jQuery element
         * @return {external:jQuery} jQuery element
         */
        function update(id){
            var $id = $(id);
            var options = $id.data('options');
            var slices = $id.get(0).querySelectorAll('.slice');
            var animate, animateTransform;

            for(var i = 0; i < slices.length; i++){
                animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
                animate.setAttribute('attributeName', 'd');
                animate.setAttribute('from', slices[i].getAttribute('d'));
                animate.setAttribute('to', options.slices[i].path);
                animate.setAttribute('dur', '0.3s');
                animate.setAttribute('begin', 'click');
                animate.setAttribute('fill', 'freeze');
                animate.setAttribute('keySplines', '0 0.75 0.25 1');
                animate.setAttribute('calcMode','spline');
                animate.setAttribute('keyTimes','0;1');

                animateTransform = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
                animateTransform.setAttribute('attributeName', 'transform');
                animateTransform.setAttribute('type', 'rotate');
                animateTransform.setAttribute('from', slices[i].getAttribute('transform').replace('rotate(','').replace(')',''));
                animateTransform.setAttribute('to', options.slices[i].rotation + ' 200 200');
                animateTransform.setAttribute('dur', '0.3s');
                animateTransform.setAttribute('begin', 'click');
                animateTransform.setAttribute('fill', 'freeze');
                animateTransform.setAttribute('keySplines', '0 0.75 0.25 1');
                animateTransform.setAttribute('calcMode','spline');
                animateTransform.setAttribute('keyTimes','0;1');

                slices[i].appendChild(animate);
                slices[i].appendChild(animateTransform);
                slices[i].dispatchEvent( new Event('click', {'bubbles':true, 'cancelable':false}) );
            }

            // Clean up the once the animation is complete.
            setTimeout(function(){
                for(var s = 0; s < slices.length; s++){
                    slices[s].setAttribute('d', options.slices[s].path);
                    slices[s].setAttribute('transform', 'rotate(' + options.slices[s].rotation + ' 200 200)');
                    slices[s].innerHTML = '';
                }
            }, 300);

            return $id;
        }

        /**
         * Updates data series.
         * @public
         * @memberof db.libs.pieChart
         * @param {external:jQuery|string} id Selector or jQuery element
         * @param {array|string} data Series data. Accepts array or string that can be parsed to array using JSON.parse
         * @return {external:jQuery} jQuery element
         */
        function series(id, data){
            var $id = $(id);
            var options = $id.data('options');
            var rotation = 0;

            options.slices = [];
            options.series = db.libs.chart.parse(data);
            options.total = db.libs.chart.sum(options.series);

            for(var i=0; i < options.series.length; i++){
                options.slices.push( slice(options.series[i], options.total, rotation) );
                rotation += options.slices[options.slices.length - 1].degrees;
            }

            $id.data('options', options);
            return $id;
        }

        /**
         * Returns values for a slice
         * @private
         * @memberof db.libs.pieChart
         * @param {number} value The value for the slice
         * @param {number} total The total value for the chart
         * @param {number} rotation The rotation for the slice
         * @return {object} object containing data needed to draw the slice
         */
        function slice(value, total, rotation){
            var degrees = (value * 360) / total;
            var x1 = 200 + 180 * Math.cos( Math.PI * 0 / 180);
            var y1 = 200 + 180 * Math.sin( Math.PI * 0 / 180);
            var x2 = 200 + 180 * Math.cos( Math.PI * degrees / 180);
            var y2 = 200 + 180 * Math.sin( Math.PI * degrees / 180);

            return {
                degrees: degrees,
                rotation: rotation,
                path: "M 200 200 L " + x1 + " " + y1 + " A 180 180 0 0 1 " + x2 + " " + y2 + " Z"
            };
        }

        /**
         * Render the chart
         * @public
         * @memberof db.libs.pieChart
         * @param {external:jQuery|string} id Selector or jQuery element
         * @fires rendered
         * @return {external:jQuery} jQuery element
         */
        function render(id){
            var $id = $(id);
            var options = $id.data('options');

            options.donut = ((options.width / 2) / 100) * options.donut;

            $id.html( Mustache.render(db.templates['chart-pie'], options) );
            $id.get(0).dispatchEvent( new Event('rendered') );

            return $id;
        }

        /**
         * Initialize the component
         * @public
         * @example <caption>Initializing can be done with or without jQuery</caption>
         * db.libs.pieChart(document.getElementById('pieChartDemo'), { series: [113,100,50,28,27,44,68,52] });
         * $('#pieChartDemo').pieChart({ series: [113,100,50,28,27,44,68,52] });
         * @memberof db.libs.pieChart
         * @param {external:jQuery|string} [id] Selector or jQuery element
         * @param {object} [options] Options can be passed to init or read from the data-options attribute on the element
         * @param {number} [options.width=400] Width given as pixels
         * @param {number} [options.height=400] Height given as pixels
         * @param {number} [options.donut=0] Size of donut given as a percentage size of the chart
         * @param {array} [options.series] Values used to create the chart
         * @return {array} Returns array of all targeted elements
         */
        function init(id, options){
            var $targets;

            if(id !== undefined){
                $targets = $(id);
            } else {
                $targets = $('.pie[data-options]');
            }

            $targets.each(function(i, el){
                if( !db.utils.isInitialized(el, name) ){
                    var $el = $(el);

                    var defaults = {
                        width: 400,
                        height: 400,
                        donut: 50,
                        series: [],
                        angles: [],
                        paths: [],
                        slices: [],
                        total: 0
                    };

                    if(id === undefined){
                        options = Foundation.utils.data_options($el);
                    }
                    options = $.extend({}, defaults, options);

                    $el.data('options', options);
                    series($el, options.series);
                    render($el);

                    db.utils.initialized(el, name);
                }
            });

            return $targets;
        }

        return {
            init: init,
            reflow: function(){},
            series: series,
            render: render,
            update: update
        };

    })(jQuery);
})();