HTML5, CSS3 & JS Experiments

By Martin Ivanov

Charts

Demo

If you are looking for a feature-complete pie chart plotting system, you may want to check this page.

You may also want to check AcidJs.Gauge. It's a JavaScript widget, using the HTML5 canvas element to draw interactive gauges with various configuration options on the page with a simple, but yet powerful API.

Register the Class

<script src="AcidJs.Charts/lib/jQuery/jquery-1.9.1.min.js"></script>
<script src="AcidJs.Charts/lib/AcidJs.Renderer/Renderer.js"></script>
<script src="AcidJs.Charts/classes/Charts.js"></script>

The Charts Class

/*
 * Charts
 * HTML5 and CSS3 Charts Engine
 * developer's website: http://wemakesites.net/#!/web-dev
 * developer's twitter: https://twitter.com/#!/wemakesitesnet
 * developer's blog http://acidmartin.wordpress.com/
 **/

(function() {
    "use strict";
    
    /*
     * @namespace window.AcidJs
     **/
    if(undefined === window.AcidJs) {
        window.AcidJs = {};
    }
    
    /*
     * @namespace window.AcidJs
     * @class Charts
     * @constructor
     **/
    function Charts() {
        this.tm = new window.AcidJs.Renderer();
        
        var
            tm = this.tm;
        
        $.each(this.TEMPLATES, function(key, value) {
            tm.add(key, value);
        });
    }
    
    /*
     * @namespace window.AcidJs
     * @class Charts
     * @prototype
     **/
    Charts.prototype = {
        /*
         * @member TEMPLATES
         * @info these templates will be processed by the AcidJs.Renderer class
         * @public
         **/
        TEMPLATES: {
            title: '
{{title}}
', details: '
{{details}}
', description: '

{{description}}

', innerWrapper: '
{{content}}
', ul: '
    {{items}}
', grid: '
    {{gridItems}}
', gridItem: '
  • ', li: '
  • {{value}}{{title}}
  • ' }, /* * @member CSS_CLASSES * @public **/ CSS_CLASSES: { base: "acidjs-charts", loading: "acidjs-charts-loading" }, /* * @member DEFAULTS * @info default values for optional properties * @public **/ DEFAULTS: { bgColor: "#666", width: 640, height: 480 }, /* * @method getJsonData * @public * @param url * @param boundingBox * @info if the config.data member of the draw() method is a URL, try to load it via AJAX * @return (Object) **/ getJsonData: function(url, boundingBox) { var that = this, config = { boundingBox: boundingBox }; $.ajax({ url: url, dataType: "json", success: function(data) { config.data = data.data; that.draw(config); }, error: function(jqXHR, ajaxSettings, thrownError) { window.console.log(jqXHR, ajaxSettings, thrownError); } }); }, /* * @method draw * @public * @param config (Object) * { * boundingBox: (jQueryDomObject), * data: { * height: (Number) [optional, default is 640], * width: (Number) [optional, default is 480], * title: (String) [optional], * description: (String) [optional], * series: [{ * value: (Number 0-100) if more than 100, 100 will be used; if less than 0, 0 will be used, * title: (String) [optional, if not set, the bar index will be used instead], * background: (Color) [optional, if not set #666 will be used] * },{ * value: (Number 0-100) if more than 100, 100 will be used; if less than 0, 0 will be used, * title: (String) [optional, if not set, the bar index will be used instead], * background: (Color) [optional, if not set #666 will be used] * }] * } * } * @info if the config.data member of the draw method is a URL, try to load it via AJAX * @return void **/ draw: function(config) { if(!config) { return; } if("string" === typeof(config.data)) { this.getJsonData(config.data, config.boundingBox); return; } var tm = this.tm, defaults = this.DEFAULTS, bbox = config.boundingBox, width = config.data.width || defaults.width, height = config.data.height || defaults.height, title = config.data.title || "", description = config.data.description || "", series = config.data.series || [], details = "", classes = this.CSS_CLASSES, gridItems = [], gridItemslength = 11, items = []; while(gridItemslength--) { gridItems.push(tm.compile("gridItem")); } gridItems = gridItems.join(""); gridItems = tm.compile("grid", { gridItems: gridItems }); bbox.html("") .addClass(classes.base) .addClass(classes.loading) .css({ width: width }); $.each(series, function(i) { var item = series[i], /* * @method _itemValue * @protected * @info process the value of the current item * @return (Number) **/ _itemValue = function() { if(item.value > -1) { return item.value > 100 ? 100 : item.value; } return 0; }; items.push(tm.compile("li", { value: _itemValue.call(this), title: item.title || i, background: item.background || defaults.bgColor })); }); items = items.join(""); items = tm.compile("ul", { width: width, height: height, items: items }); if(title) { title = tm.compile("title", { title: title }); } if(description) { description = tm.compile("description", { description: description }); } details = tm.compile("details", { details: title + description }); bbox.html(tm.compile("innerWrapper", { content: gridItems + items, width: width, height: height })); bbox.prepend(details); window.setTimeout(function() { bbox.removeClass(classes.loading); }, 500); } }; window.AcidJs.Charts = Charts; })();

    The Renderer Class

    /*
     * Renderer
     * HTML Template Engine
     * developer's website: http://wemakesites.net/#!/web-dev
     * developer's twitter: https://twitter.com/#!/wemakesitesnet
     * developer's blog http://acidmartin.wordpress.com/
     **/
    
    (function() {
        "use strict";
        
        /*
         * @namespace window.AcidJs
         **/
        if(undefined === window.AcidJs) {
            window.AcidJs = {};
        }
        
        /*
         * @class Renderer
         * @constructor
         **/
        function Renderer() {}
        
        Renderer.prototype = {
            /*
             * @member TEMPLATES
             * @public
             * @info key/value storage of templates that will be used
             **/
            TEMPLATES: {},
            
            /*
             * @method compile
             * @public
             * @param name (String) name of the template that will be used
             * @param data (Object) key/value pairs of template placeholders and values that should be replaced against these placeholders
             **/
            compile: function(name, data) {
                var 
                    html = this.TEMPLATES[name] || "";
                
                data = data || {};
                
                for (var key in data) {
                    if (data.hasOwnProperty(key)) {
                        var
                            value = data[key],
                            regexp = new RegExp("{{" + key + "}}", "g");
                    
                        html = html.replace(regexp, value);
                    }
                }
                
                return html;
            },
            
            /*
             * @method add
             * @public
             * @param name (String)
             * @param html (String)
             * @param callback (Function) [optional]
             **/
            add: function(name, html, callback) {
                if(name && html) {
                    this.TEMPLATES[name] = html;
                    if(callback) {
                        callback.call(this);
                    }
                }
            },
            
            /*
             * @method remove
             * @public
             * @param name (String)
             **/
            remove: function(name) {
                if(this.TEMPLATES[name]) {
                    delete this.TEMPLATES[name];
                }
            }
        };
        
        window.AcidJs.Renderer = Renderer;
    })();

    Usage

    (function() {
        "use strict";
    
        window.charts = new AcidJs.Charts();
    
        // draw chart 1
        window.charts.draw({
            boundingBox: $("#chart-1"),
            data: {
                width: 280,
                height: 200,
                title: "Lorem Ipsum",
                description: "Dummy text of the printing and typesetting industry",
                series: [{
                    value: 20,
                    title: "Bar 1",
                    background: "#4586d8"
                },{
                    value: 10,
                    title: "Bar 2",
                    background: "#ff0080"
                },{
                    value: 80,
                    title: "Bar 3",
                    background: "#ff9a2e"
                },{
                    value: 35,
                    title: "Bar 4",
                    background: "#dc443f"
                },{
                    value: 100,
                    title: "Bar 5",
                    background: "#aad34f"
                },{
                    value: 50,
                    title: "Bar 6",
                    background: "#8562b4"
                }]
            }
        });
        
        // draw chart 2 from an external data file
        window.charts.draw({
            boundingBox: $("#chart-2"),
            data: "pages/html5-charts/example/Data/chart-2.json"
        });
        
        // draw chart 2 from an external data file
        window.charts.draw({
            boundingBox: $("#chart-3"),
            data: "pages/html5-charts/example/Data/chart-3.json"
        });
    })();

    Example of an External Chart Data File

    {
        "data": {
            "width": 280,
            "height": 200,
            "title": "Sed ut Perspiciatis",
            "description": "Nemo enim ipsam voluptatem quia voluptas sit aspernatur",
            "series": [{
                "value": 5,
                "title": "Bar 1",
                "background": "#2673ec"
            },{
                "value": 10,
                "title": "Bar 2",
                "background": "#ae113d"
            },{
                "value": 80,
                "title": "Bar 3",
                "background": "#7200ac"
            },{
                "value": 100,
                "title": "Bar 4",
                "background": "#199900"
            },{
                "value": 50,
                "title": "Bar 4",
                "background": "#ff7d23"
            },{
                "value": 15,
                "title": "Bar 4",
                "background": "#ff2e12"
            }]
        }
    }

    CSS

    /*
     * Charts
     * HTML5 and CSS3 Charts Engine
     * developer's website: http://wemakesites.net/#!/web-dev
     * developer's twitter: https://twitter.com/#!/wemakesitesnet
     * developer's blog http://acidmartin.wordpress.com/
     **/
    
    .acidjs-charts,
    .acidjs-charts *::before,
    .acidjs-charts *::before
    {
        -webkit-box-sizing: content-box; 
        -moz-box-sizing: content-box;
        box-sizing: content-box;
    }
    
    .acidjs-charts ul,
    .acidjs-charts ul li div,
    .acidjs-charts ul li div *,
    .acidjs-charts ul li div::before,
    .acidjs-charts .acidjs-charts-grid
    {
        width: 100%;
    }
    
    .acidjs-charts ul,
    .acidjs-charts ul li,
    .acidjs-charts ul li div::before,
    .acidjs-charts .acidjs-charts-grid
    {
        height: 100%;
    }
    
    .acidjs-charts p,
    .acidjs-charts h6,
    .acidjs-charts ul li div *
    {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    
    .acidjs-charts ul li div *,
    .acidjs-charts ul li div::before,
    .acidjs-charts .acidjs-charts-grid
    {
        position: absolute;
    }
    
    .acidjs-charts li div,
    .acidjs-charts ul li div *,
    .acidjs-charts .acidjs-charts-details
    {
        text-align: center;
    }
    
    .acidjs-charts.acidjs-charts-loading ul li div *,
    .acidjs-charts.acidjs-charts-loading .acidjs-charts-details
    {
        opacity: 0;
    }
    
    .acidjs-charts ul li div *,
    .acidjs-charts .acidjs-charts-details
    {
        opacity: 1;
        
        -moz-transition: opacity 500ms 1s cubic-bezier(.09, .11, .24, .91);
        -webkit-transition: opacity 500ms 1s cubic-bezier(.09, .11, .24, .91);
        -ms-transition: opacity 500ms 1s cubic-bezier(.09, .11, .24, .91);
        -o-transition: opacity 500ms 1s cubic-bezier(.09, .11, .24, .91);
        transition: opacity 500ms 1s cubic-bezier(.09, .11, .24, .91);
    }
    
    .acidjs-charts,
    .acidjs-charts .acidjs-charts-grid li b::before
    {
        display: inline-block;
    }
    
    .acidjs-charts > div,
    .acidjs-charts li div
    {
        position: relative;
    }
    
    .acidjs-charts li div,
    .acidjs-charts ul li div *
    {
        font-size: 12px;
    }
    
    .acidjs-charts ul,
    .acidjs-charts .acidjs-charts-grid
    {
        display: table;
    }
    
    .acidjs-charts ul li div em,
    .acidjs-charts .acidjs-charts-grid
    {
        margin: -20px 0 0;
    }
    
    .acidjs-charts ul li,
    .acidjs-charts .acidjs-charts-grid li b
    {
        display: table-cell;
    }
    
    .acidjs-charts,
    .acidjs-charts p
    {
        color: #878787;
    }
    
    /* reset all elements inside of the chart element */
    .acidjs-charts *
    {
        padding: 0;
        margin: 0;
        list-style: none;
        font-weight: normal;
        font-style: normal;
    }
    
    .acidjs-charts .acidjs-charts-details *
    {
        line-height: 18px;
    }
    
    .acidjs-charts h6
    {
        font-size: 16px;
    }
    
    .acidjs-charts p
    {
        font-size: 14px;
    }
    
    .acidjs-charts
    {
        vertical-align: top;
        padding: 4px 4px 4px 30px;
        font-family: "Segoe UI", Arial, Sans-serif;
        background: #1d1d1d;
        border-radius: 6px;
        cursor: default;
        -moz-user-select: none;
        -webkit-user-select: none;
        user-select: none;
    }
    
    .acidjs-charts.acidjs-charts-loading li div
    {
        height: 0 !important;
    }
    
    .acidjs-charts li div
    {
        top: -20px;
        -moz-transition: height 500ms cubic-bezier(.09, .11, .24, .91);
        -webkit-transition: height 500ms cubic-bezier(.09, .11, .24, .91);
        -ms-transition: height 500ms cubic-bezier(.09, .11, .24, .91);
        -o-transition: height 500ms cubic-bezier(.09, .11, .24, .91);
        transition: height 500ms cubic-bezier(.09, .11, .24, .91);
    }
    
    .acidjs-charts .acidjs-charts-grid
    {
        border-collapse: collapse;
        counter-reset: percentage 11;
    }
    
    .acidjs-charts .acidjs-charts-grid li
    {
        display: table-row;
        counter-increment: percentage -1; /* display a reverse counter */
    }
    
    .acidjs-charts .acidjs-charts-grid li b
    {
        border: dashed 1px rgba(135, 135, 135, .2);
        border-left: 0;
        border-right: 0;
        font-size: 10px;
        vertical-align: middle;
    }
    
    .acidjs-charts .acidjs-charts-grid li b::before
    {
        content: counter(percentage) "0%";
        text-align: right;
        width: 26px;
        margin: 0 0 0 -28px;
    }
    
    .acidjs-charts .acidjs-charts-grid li:last-child b::before
    {
        content: "0%";
    }
    
    .acidjs-charts ul li
    {
        padding: 0 2px;
        vertical-align: bottom;
    }
    
    .acidjs-charts ul li div
    {
        border-radius: 4px 4px 0 0;
    }
    
    /* add "glossy" look and feel to the bars */
    .acidjs-charts ul li div::before
    {
        content: "";
        top: 0;
        left: 0;
        background: -webkit-linear-gradient(left, rgba(0, 0, 0, .1), rgba(255, 255, 255, .2), rgba(0, 0, 0, .1));
        background: -moz-linear-gradient(left, rgba(0, 0, 0, .1), rgba(255, 255, 255, .2), rgba(0, 0, 0, .1));
        background: -ms-linear-gradient(left, rgba(0, 0, 0, .1), rgba(255, 255, 255, .2), rgba(0, 0, 0, .1));
        background: -o-linear-gradient(left, rgba(0, 0, 0, .1), rgba(255, 255, 255, .2), rgba(0, 0, 0, .1));
        background: linear-gradient(left, rgba(0, 0, 0, .1), rgba(255, 255, 255, .2), rgba(0, 0, 0, .1));
    }
    
    .acidjs-charts ul li:last-child div
    {
        border-radius: 4px 4px 4px 0;
    }
    
    .acidjs-charts ul li:first-child div
    {
        border-radius: 4px 4px 0 4px;
    }
    
    .acidjs-charts ul li div *
    {
        display: block;
        line-height: 16px;
    }
    
    .acidjs-charts ul li div b
    {
        bottom: -20px;
    }
    
    .acidjs-charts .acidjs-charts-details
    {
        margin: 0 0 40px;
    }
    
    /* browser fixes */
    /* fixes a Google Chrome redrawing issue */
    @media screen and (-webkit-min-device-pixel-ratio: 0)
    {
        .acidjs-charts.acidjs-charts-loading li div
        {
            margin: 1px 0 0;
        }
    }
    
    /* Internet Explorer 6 and 7 are not supported due to CSS issues, so we just hide the charts */
    * html .acidjs-charts,
    * + html .acidjs-charts
    {
        display: none;
    }