Feb 27, 2014
Roman Tsukanov

The Story of a Plumpy Man

As I was passing by my bedroom mirror last night, I couldn’t help but notice one of those things that most young men really dread – an ever growing belly. After a thoughtful examination of myself and then a quick run-down of my diet in my head, I realized that my everyday eating habits were simply not inducive to a healthy and slim me. Something had to give. But is a piece of beef really less healthy than a plate of broccoli?

To answer this question, I implemented an application that helps me sort out what foods are the healthy choice for my figure. For this app, I used several widgets from the DevExtreme Data Visualization library. These widgets easily resolve any data visualization task and are very simple to configure. Just take a look.

Choosing Ingredients for the App

I began with only two chart widgets: dxChart to represent the contents of my fridge, and dxLinearGauge to indicate the total amount of consumed calories. My next step was to arrange them on a page.

Arranging the Widgets

Each widget should be placed in a separate div container on an HTML page. I added the containers and didn't forget to place a picture under them. My hope is that this image will discourage the viewer from leading an unhealthy lifestyle.

HTML
<div id="chartContainer" style="height:400px; width:700px; margin: 0 auto;"></div>
<div style="text-align:center">
    <div id="linearGaugeContainer" style="height:100px; width:460px; margin: 0 auto;"></div>
    <img width="450" height="236" src="/Content/images/blogs/chartjs/05_the_story_of_a_plumpy_man/1.png" />
</div>

Then, I created the widgets within those containers. Note that I used the jQuery approach, but you can also use Knockout or AngularJS to do the same.

JavaScript
$(function () {
    $("#chartContainer").dxChart();
    $("#linearGaugeContainer").dxLinearGauge();
});

By this time, all this thinking about food made me even hungrier. So I opened the fridge.

What's in the Fridge?

There were many different products in my fridge. I quickly made a list of them and then put them in a variable along with their caloric values - information I gathered from the Fat Secret website.

JavaScript
var dataSource = [
    { type: 'Dairy', name: 'Milk', calories: 50 },
    { type: 'Dairy', name: 'Ice Cream', calories: 201 },
    { type: 'Dairy', name: 'American Cheese', calories: 337 },
    { type: 'Fruits', name: 'Apples', calories: 52 },
    { type: 'Fruits', name: 'Bananas', calories: 89 },
    { type: 'Fruits', name: 'Oranges', calories: 47 },
    { type: 'Grains', name: 'White Rice', calories: 129 },
    { type: 'Grains', name: 'Oats', calories: 389 },
    { type: 'Grains', name: 'Wheat', calories: 198 },
    { type: 'Beverages', name: 'Beer', calories: 43 },
    { type: 'Beverages', name: 'Rum', calories: 231  },
    { type: 'Beverages', name: 'Soda', calories: 38 },
    { type: 'Meat', name: 'Beef', calories: 288 },
    { type: 'Meat', name: 'Chicken', calories: 195 },
    { type: 'Meat', name: 'Pork', calories: 271 },
    { type: 'Vegetables', name: 'Tomatoes', calories: 18 },
    { type: 'Vegetables', name: 'Potatoes', calories: 70 },
    { type: 'Vegetables', name: 'Broccoli', calories: 34 },
    { type: 'Sweets', name: 'Chocolate Cake', calories: 367 },
    { type: 'Sweets', name: 'Blueberry Pie', calories: 245 },
    { type: 'Sweets', name: 'Jujube', calories: 79 }
];

An impressive list, wouldn't you say? I used this array as a data source for the dxChart widget.

JavaScript
$(function () {
    $("#chartContainer").dxChart({
        dataSource: dataSource
    });
});

Then, I specified the chart series. From the variety of series types provided by dxChart, I chose the "bubble" type, which allows you to display data as bubbles of different sizes. I used the commonSeriesSettings and seriesTemplate objects to specify the series.

JavaScript
$(function () {
    $("#chartContainer").dxChart({
        // ...
        commonSeriesSettings: {
            type: 'bubble',
            argumentField: 'name',
            valueField: 'calories',
            sizeField: 'calories'
        },
        seriesTemplate: { nameField: 'type' }
    });
});

As you can see from this code, the names of the products specify chart arguments, while their caloric values specify values and bubble sizes for the chart. In addition, the products are grouped in several series by types as specified by the seriesTemplate option.

I now knew what my app should contain, but hadn't yet specified how it should appear there. So in the next step, I configured the appearance of the widgets.

Adjusting the Fridge Shelves

The dxChart widget, as the most sophisticated of all the DevExtreme visualization widgets, has a lot of elements. For my app, I specified only several of them. My chart has a title and displays the names of the products by point labels rather than axis labels. In addition, I enabled and customized tooltips and specified a palette to be used for coloring chart series.

JavaScript
$(function () {
    $("#chartContainer").dxChart({
        // ...
        commonSeriesSettings: {
            // ...
            label: {
                visible: true,
                customizeText: function (point) {
                    return point.argument;
                }
            }
        },
        argumentAxis: {
            label: { visible: false }
        },
        title: "Calories Amount (per 100 g of a Product)",
        tooltip: {
            enabled: true,
            customizeText: function (point) {
                return point.argument + ' - ' + point.value + ' kcal';
            }
        },
        palette: ['powderblue', 'lightgreen', 'goldenrod', 'sienna',  'red', 'green', 'orchid' ]
    });
});

Here is what the content of my fridge looks like after the appearance of dxChart has been configured.

dxChart looks stunning and you can gather a lot of information about the caloric value of each product from it. However, as a standalone widget, it is almost useless in counting calories. For scorekeeping purposes, I configured the dxLinearGauge widget.

Tuning Up the Scoreboard

In the dxLinearGauge widget, a value is displayed on a straight scale. Moreover, you can specify several gauge ranges and color them differently. In my app, each range designates my weight gain, if any, after a meal. The following code demonstrates how I configured this widget.

JavaScript
$(function () {
    // ...
    $('#linearGaugeContainer').dxLinearGauge({
        scale: {
            startValue: 0,
            endValue: 3500
        },
        rangeContainer: {
            ranges: [
                { startValue: 0, endValue: 700, color: 'green' },
                { startValue: 700, endValue: 1400, color: 'dodgerblue' },
                { startValue: 1400, endValue: 2100, color: 'lightskyblue' },
                { startValue: 2100, endValue: 2800, color: 'orange' },
                { startValue: 2800, endValue: 3500, color: 'firebrick' }
            ]
        },
        value: 0,
        title: 'Calories Consumed'
    });
});

This is what the configured dxLinearGauge widget looks like.

After configuring the widgets, all that was left is to combine them into one nice-looking app. Discover how I did this in the following paragraph.

Connecting Widgets

The DevExtreme visualization widgets are supplied with an API that allows you to perform actions on different events, e.g., on click, hover, etc. I used the pointClick event to select a chart point by a click, and the pointSelectionChanged event to alter the gauge value and change the demotivating picture. Here is the code I added to the dxChart configuration object.

JavaScript
$(function () {
    $("#chartContainer").dxChart({
        // ...
        pointSelectionMode: 'multiple',
        pointClick: function() {
            this.isSelected() ? this.clearSelection() : this.select();
        },
        pointSelectionChanged: function() {
            var gauge = $('#linearGaugeContainer').dxLinearGauge('instance');
            this.isSelected() ? gauge.value(gauge.value() + this.originalValue) : gauge.value(gauge.value() - this.originalValue);
            selectBodyType(gauge.value());
        }
    });
    // ...
});

And here is the final result. Click a point on dxChart to select the corresponding product. Its caloric value will be automatically added to the value of dxLinearGauge. The larger the value, the more plumpy you will be after the meal. The full code of the app can be found on jsFiddle.

Closing

As you see, the DevExtreme visualization widgets are very simple to configure and enjoy. With the DevExtreme visualization library at hand, any task related with data visualization becomes the easiest thing in the world. To see more examples of using the DevExtreme visualization widgets, you are welcome to visit the Visualization Gallery. The documentation section is at your service anytime as well. Keep in shape!