Platinum Partner
java,mobile,frameworks,tutorial,tools & methods,sencha touch

How to Create an Executive Dashboard Using Sencha Touch, Part 2

This is the second part of a Sencha Touch tutorial in which you will build an Executive Dashboard app that renders a number of charts with performance indicators for a hypothetical business.

dashboard-2-small

In the first part of this tutorial, you created the Sencha Touch barebones app that you will use as starting point for the Executive Dashboard, designed and created the main view of the app, and created a Sencha Touch data Model and Store that you will use to retrieve data from the server and feed it to the app’s charts.

Now you are ready to add the charts to the app. Let’s start with the Hours Worked chart.

Creating the Hours Worked chart

The first chart that you will create is the “Hours Worked” chart. In the app/view directory, create the HrsWorkedChart.js file, and add the following code to it:

Ext.define("dashboard.view.HrsWorkedChart", {
    extend: "Ext.chart.CartesianChart",
    requires: [
        "Ext.TitleBar",
        "Ext.chart.CartesianChart",
        "Ext.chart.series.Line",
        "Ext.chart.axis.Numeric",
        "Ext.chart.axis.Category",
        "Ext.draw.sprite.Circle"
    ],
    alias: "widget.hrsworkedchart",
    config: {
        flex: 1,
        xtype: "chart",
        store: "HrsAndValueByYear",
        cls: "chart",
        innerPadding: 10,
        animate: true,
        series: [
            {
                type: "line",
                xField: "year",
                yField: "hrsworked",
                title: "Hours Worked",
                style: {
                    stroke: "#003366",
                    lineWidth: 3
                },
                marker: {
                    type: "circle",
                    stroke: "#003366",
                    radius: 5,
                    lineWidth: 3
                }
            }
        ],
        axes: [
            {
                type: "numeric",
                position: "left",
                title: {
                    fontSize: 15,
                    text: "Hrs"
                },
                grid: {
                    even: {
                        fill: "#f9f9f9"
                    }
                }
            },
            {
                type: "category",
                position: "bottom"
            }
        ]
    }
});

This chart is an instance of the CartesianChart Class. In other words, it’s a line chart. The first detail you need to pay attention to is the requires object, where you list the classes needed to define the series, axis, and sprites you will use for the chart’s markers.

Note also the store, series and axes configs. While the store config is self explanatory, I would recommend that you review the Sencha Touch documentation for the series and axes config so you are aware of the multiple ways to configure these chart features. For example, in the series config, the most important properties are the xField and yField, which should match the model’s fields you want to display on the chart.

You should now add the chart to the views config of the application, in the app.js file:

views: [
    "HrsWorkedChart",
    "Main"
]

Adding the Hours Worked chart to the Main view

Then you can add an instance of the chart to the Main view of the app in the view/Main.js file

Ext.define("dashboard.view.Main", {
    extend: "Ext.Container",
    requires: [
        "Ext.TitleBar"
    ],
    alias: "widget.main",
    config: {
        layout: {
            type:"vbox"
        },
        items: [
            {
                xtype: "titlebar",
                docked: "top",
                title: "Executive Dashboard",
                items: [
                    {
                        iconCls: "refresh",
                        align: "right",
                        handler: function () {
                            var parent = this.up("titlebar").getParent();
                            parent.fireEvent("refreshRequestCmd", parent);
                        }
                    }
                ]
            },            
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Hours Billed Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    }
                ]
            }            ,
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Walue Worked Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Value Billed Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    }
                ]
            }                
        ]
    }
});

At this point you can check the app in a browser, where you should see the Hours Worked chart rendered as shown in the screenshot below.

dashboard-7-small

Creating the Hours Billed chart

The second chart is the Hours Billed chart. In the app/view directory, create the HrsBilledChart.js file. Type the following code in the file:

Ext.define("dashboard.view.HrsBilledChart", {
    extend: "Ext.chart.CartesianChart",
    requires: [
        "Ext.TitleBar",
        "Ext.chart.CartesianChart",
        "Ext.chart.series.Line",
        "Ext.chart.axis.Numeric",
        "Ext.chart.axis.Category",
        "Ext.draw.sprite.Circle"
    ],
    alias: "widget.hrsbilledchart",
    config: {
        flex: 1,
        xtype: "chart",
        store: "HrsAndValueByYear",
        cls: "chart",
        innerPadding: 10,
        animate: true,
        series: [
            {
                type: "line",
                xField: "year",
                yField: "hrsbilled",
                title: "Hours Billed",
                style: {
                    stroke: "#6d0060",
                    lineWidth: 3
                },
                marker: {
                    type: "circle",
                    stroke: "#6d0060",
                    radius: 5,
                    lineWidth: 3
                }
            }
        ],
        axes: [
            {
                type: "numeric",
                position: "left",
                title: {
                    fontSize: 15,
                    text: "Hrs"
                },
                grid: {
                    even: {
                        fill: "#f9f9f9"
                    }
                }
            },
            {
                type: "category",
                position: "bottom"
            }
        ]
    }
});

The Hours Billed chart is very similar to the Hours Worked chart. The only differences are the series.yField value, and the colors used for the stroke and markers.

Now add the chart to the views config of the application in the app.js file.

views: [
	'HrsWorkedChart',
	'HrsBilledChart',
	'Main'
]

Adding the Hours Billed chart to the Main view

Next you will add an instance of the chart to the Main view of the app, in the view/Main.js file:

Ext.define("dashboard.view.Main", {
    extend: "Ext.Container",
    requires: [
        "Ext.TitleBar"
    ],
    alias: "widget.main",
    config: {
        layout: {
            type:"vbox"
        },
        items: [
            {
                xtype: "titlebar",
                docked: "top",
                title: "Executive Dashboard",
                items: [
                    {
                        iconCls: "refresh",
                        align: "right",
                        handler: function () {
                            var parent = this.up("titlebar").getParent();
                            parent.fireEvent("refreshRequestCmd", parent);
                        }
                    }
                ]
            },            
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsbilledchart"
                            }
                        ]
                    }
                ]
            }            ,
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Walue Worked Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Value Billed Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    }
                ]
            }                
        ]
    }
});

Check the app in a browser one more time. You should see the Hours Billed chart rendered as shown in the following screenshot:
dashboard-8-small

Creating the Value Worked chart

Let’s repeat the process for the Value Worked chart. Create the ValueWorkedChart.js file in the app/view directory, and add the code below to it.

Ext.define("dashboard.view.ValueWorkedChart", {
    extend: "Ext.chart.CartesianChart",
    requires: [
        "Ext.TitleBar",
        "Ext.chart.CartesianChart",
        "Ext.chart.series.Line",
        "Ext.chart.axis.Numeric",
        "Ext.chart.axis.Category",
        "Ext.draw.sprite.Circle"
    ],
    alias: "widget.valueworkedchart",
    config: {
        flex: 1,
        xtype: "chart",
        store: "HrsAndValueByYear",
        cls: "chart",
        innerPadding: 10,
        animate: true,
        series: [
            {
                type: "line",
                xField: "year",
                yField: "valueworked",
                title: "Hours Worked",
                style: {
                    stroke: "#9d5d00",
                    lineWidth: 3
                },
                marker: {
                    type: "circle",
                    stroke: "#9d5d00",
                    radius: 5,
                    lineWidth: 3
                }
            }
        ],
        axes: [
            {
                type: "numeric",
                position: "left",
                title: {
                    fontSize: 15,
                    text: "Hrs"
                },
                grid: {
                    even: {
                        fill: "#f9f9f9"
                    }
                }
            },
            {
                type: "category",
                position: "bottom"
            }
        ]
    }
});

Now add the chart to the views config of the application in the app.js file:

views: [
	'HrsWorkedChart',
	'HrsBilledChart',
	'ValueWorkedChart',
	'Main'
]

Adding the Value Worked chart to the Main view

Next you will add an instance of the chart to the Main view of the app in the view/Main.js file:

Ext.define("dashboard.view.Main", {
    extend: "Ext.Container",
    requires: [
        "Ext.TitleBar"
    ],
    alias: "widget.main",
    config: {
        layout: {
            type:"vbox"
        },
        items: [
            {
                xtype: "titlebar",
                docked: "top",
                title: "Executive Dashboard",
                items: [
                    {
                        iconCls: "refresh",
                        align: "right",
                        handler: function () {
                            var parent = this.up("titlebar").getParent();
                            parent.fireEvent("refreshRequestCmd", parent);
                        }
                    }
                ]
            },            
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsbilledchart"
                            }
                        ]
                    }
                ]
            }            ,
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "valueworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "container",
                                html: "Value Billed Chart Placeholder",
                                margin: "15 0 0 15"
                            }
                        ]
                    }
                ]
            }                
        ]
    }
});

Another check in the browser should show that the Value Worked chart is in place, as depicted below.
dashboard-9-small

Creating the Value Billed chart

The last chart is the Value Billed chart. Create the ValueBilledChart.js file in the app/view directory. Then define the chart’s Class using the following code:

Ext.define("dashboard.view.ValueBilledChart", {
    extend: "Ext.chart.CartesianChart",
    requires: [
        "Ext.TitleBar",
        "Ext.chart.CartesianChart",
        "Ext.chart.series.Line",
        "Ext.chart.axis.Numeric",
        "Ext.chart.axis.Category",
        "Ext.draw.sprite.Circle"
    ],
    alias: "widget.valuebilledchart",
    config: {
        flex: 1,
        xtype: "chart",
        store: "HrsAndValueByYear",
        cls: "chart",
        innerPadding: 10,
        animate: true,
        series: [
            {
                type: "line",
                xField: "year",
                yField: "valuebilled",
                title: "Value Billed",
                style: {
                    stroke: "#789700",
                    lineWidth: 3
                },
                marker: {
                    type: "circle",
                    stroke: "#789700",
                    radius: 5,
                    lineWidth: 3
                }
            }
        ],
        axes: [
            {
                type: "numeric",
                position: "left",
                title: {
                    fontSize: 15,
                    text: "Hrs"
                },
                grid: {
                    even: {
                        fill: "#f9f9f9"
                    }
                }
            },
            {
                type: "category",
                position: "bottom"
            }
        ]
    }
});

Now add the chart to the views config of the application in the app.js file:

views: [
	'HrsWorkedChart',
	'HrsBilledChart',
	'ValueWorkedChart',
	'ValueBilledChart',
	'Main'
]

Adding the Value Billed chart to the Main view

At this point you can add the chart to the app’s Main view. Open the Main.js file in the app/view directory, and modify the items array of the fourth child container you created previously, as shown in the code below.

Ext.define("dashboard.view.Main", {
    extend: "Ext.Container",
    requires: [
        "Ext.TitleBar"
    ],
    alias: "widget.main",
    config: {
        layout: {
            type:"vbox"
        },
        items: [
            {
                xtype: "titlebar",
                docked: "top",
                title: "Executive Dashboard",
                items: [
                    {
                        iconCls: "refresh",
                        align: "right",
                        handler: function () {
                            var parent = this.up("titlebar").getParent();
                            parent.fireEvent("refreshRequestCmd", parent);
                        }
                    }
                ]
            },            
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout:"vbox",
                        items:[
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Hours Billed",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "hrsbilledchart"
                            }
                        ]
                    }
                ]
            }            ,
            {
                xtype: "container",
                flex: 1,
                layout: "hbox",
                items: [
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Worked",
                                margin: "15 0 0 15"
                            },
                            {
                                xtype: "valueworkedchart"
                            }
                        ]
                    },
                    {
                        xtype: "container",
                        flex: 1,
                        layout: "vbox",
                        items: [
                            {
                                xtype: "container",
                                docked: "top",
                                html: "Value Billed",
                                margin: "15 0 0 15"
                            },
                           {
                               xtype: "valuebilledchart"
                           }
                        ]
                    }
                ]
            }                
        ]
    }
});

A fourth check in the browser should show that the Value Billed chart is in place, as shown in the screenshot:.

dashboard-2-small

Let’s make a quick stop to check our progress. At this point, you have completed the following tasks:

  • Designed the layout of the app’s main view.
  • Created the main view.
  • Created the data model and store that will feed the charts.
  • Created the app’s four charts and added them to the main view.

There are a couple of areas that you still need to work on in order to be able to refresh the charts with new data when the user taps the Refresh button on the main view:

  • The controller.
  • The server-side code.

Creating the application’s controller

You will use a controller to refresh the data for the charts. Create the Main.js file in the app/controller directory. Add the following code to the file.

Ext.define("dashboard.controller.Main", {
    extend: "Ext.app.Controller",
    config: {
        refs: {
            mainView:"main"
        },
        control: {
            mainView: {
                refreshRequestCmd: "onRefreshRequestCmd"
            }
        }
    },
    onRefreshRequestCmd: function (view) {
        Ext.getStore("HrsAndValueByYear").load();
        console.log("load");
    }
});

The first thing that you do in the controller is to declare the mainView reference in the refs config. Then, in the control config, you use the mainView reference to set up an event handler for the refreshRequestCmd event. You will call this event handler onRefreshRequestCmd.

Inside the onRefreshRequestCmd method, all you need to do is call the load method of the HrsAndValueByYear store. You can obtain a reference to the store using the Ext.getStore() method.

Finally, you need to declare the controller in the controllers section of the app, in the app.js file:

controllers: [
	'Main'
]

Defining a proxy for the store

There is a small change you need to make before taking care of the server-side code – add a proxy to the store so it can obtain its data from the server. Jump back to the HrsAndValueByYear file in the app/store directory, and modify its code as follows.

Ext.define("dashboard.store.HrsAndValueByYear", {
    extend: "Ext.data.Store",
    config: {
        proxy: {
            type: 'ajax',
            url: '../../services/dashboard.php?metric=hrsandvaluebyyear',
            model: 'dashboard.model.HrsAndValueByYear',
            reader: {
                type: "json",
                rootProperty: "items"
            }
        },
        autoLoad: true
    }
});

What you did with this code is to replace the data config with the proxy config, which defines an ajax proxy with its url, model and reader properties. Note that the url property refers to a dashboard.php page, and uses the metric query string parameter to tell the page what data it needs to send to the client.

Creating the server-side code

You will use PHP as the language for the server-side page that will provide the data for the HrsAndValueByYear store. The code is so simple that you will not have any difficulties translating it to your preferred server-side language.

In the services directory, create the dashboard.php file. Add this code to the file:

<?php
$metric = $_GET["metric"];
$result = "";

switch ($metric) {
    
	case "hrsandvaluebyyear":
		$result = "{success:true,items:[{ year: '2010', hrsbilled: '130000', hrsworked: '143000', valuebilled: '475000', valueworked: '500000' },{ year: '2011', hrsbilled: '149000', hrsworked: '158000', valuebilled: '270000', valueworked: '285000' },{ year: '2012', hrsbilled: '153000', hrsworked: '149000', valuebilled: '325000', valueworked: '380000' },{ year: '2013', hrsbilled: '165000', hrsworked: '171000', valuebilled: '265000', valueworked: '270000'}]}";
		break;
}		

header('Cache-Control: no-cache, must-revalidate');
header("content-type:application/json");
echo($result);

For the purposes of this tutorial you are simply hardcoding the data in the server-side page. In a production-grade app you will likely need to make a database call in order to obtain this data. I will not go that far in this tutorial, but you should try it as soon as you have an opportunity.

After the last round of changes, a quick check in the browser should show the application working as originally designed.
dashboard-2-small

Conclusion

You made it! In this tutorial you created a Sencha Touch application that you can use as a foundation to create dashboard-like user interfaces for tablet devices. You also learned how to configure Sencha Touch charts, how to connect the charts to a server-side endpoint, and how to refresh the charts on demand.

Download source code

You can download the source code for this Sencha Touch tutorial here: https://github.com/MiamiCoder/sencha-touch-recipe-dashboard

The other parts of this tutorial

Want to learn more?

My Sencha Touch and jQuery Mobile books will guide you, step by step, through the process of building Sencha Touch and jQuery Mobile applications. If you like to learn by doing, these books are for you.

You can also check the rest of my Sencha Touch tutorials and recipes, which cover interesting subjects related to Sencha Touch.

Published at DZone with permission of {{ articles[0].authors[0].realName }}, DZone MVB. (source)

Opinions expressed by DZone contributors are their own.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}