Nice Report Always Comes with Colourful Charts

Normally, we will show only tabular data in our online report module. However, tables are not exciting. So, why don’t we add some charts to the report to better describe the data? Thanks to Google Charts, web developers can add colourful charts to the web pages easily.

Step 1: The Required Libraries

The first thing we need is the Google API Loader which allows us later to easily load APIs from Google. So, with the help of it, we can make use of the Google Hosted Libraries.

 type="text/javascript" src="https://www.google.com/jsapi">

After that, we will load the API which will help us drawing charts. To do so, we will have the following JavaScript code.

google.load("visualization", "1.1", { packages: ["corechart"] });

Material Design

What is Google Material Design? There is an interesting video from Google Design team sharing the ideas behind it. (Image Credit: Google Design)
What is Google Material Design? There is an interesting video from Google Design team sharing the ideas behind it. (Image Credit: Google Design)

Recently, in order to support a common look-and-feel across all Google properties and apps running on Google platforms, Material Design is introduced to Google Charts as well.

There are more than 20 of charts available in Google Chart Gallery. Depends on which chart that you would like to use, you need to load different API in order to use the Material version of each chart. I played around with some of them which are useful in my use cases.

The first chart that I use is the Column Chart which is to draw vertical bar chart. So, the API can be called as follows.

google.load("visualization", "1.1", { packages: ["bar"] });

Other than vertical bar chart, another common graphs used in report will be Line Chart. The API of Line Chart can be called as follows.

google.load("visualization", "1.1", { packages: ["line"] });
Line Chart is available on Google Charts.
Line Chart is available on Google Charts.

The third chart that I use is Timeline. This chart is different from the two charts introduced above because so far I still can’t find the non-Material version of it. So, the only way to call the API of Timeline is as follows.

google.load("visualization", "1.1", { packages: ["timeline"] });
Timeline is a chart describing the happening events over time.
Timeline is a chart describing the happening events over time.

Step 2: The Data

After we have loaded API of the chart that we want to use, then we need to pump in the data.

var data = new google.visualization.DataTable();
data.addColumn('string', 'Branch');
data.addColumn('number', 'Sales');
data.addRows([
    ['Ang Mo Kio', 1205.80],
    ['Bedok', 828.90],
    ['Clementi', 2222.10],
    ['Dhoby Ghaut', 3180.00]
]);

In the code above, I created a data table with 2 columns. Then I added 4 rows of data with addRows.

The addRows part can be done using a simple for loop. However, due to the fact that not all browsers support Tailing Comma, the for loop needs to have additional step to remove Tailing Comma.

Step 3: Chart Render

After we have the data, now we can proceed to draw the chart. For example, if we want to draw a Column Chart for the data table above, then we will use the following code.

var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));chart.draw(data);

The HTML element chart_div above is just an empty div where the chart should be rendered at.

We will then be able to get the following diagram (Non-Material).

A simple Column Chart.
A simple Column Chart.

Customization of Charts with Options

Google Charts allows us to customize the diagram. For example, we can add title for the diagram, horizontal axis, and vertical axis.

var options = {
    title: 'Sales of Branches',
    hAxis: {
        title: 'Branch'
    },
    vAxis: {
        title: 'Amount (SGD)',
        minValue: 0
    },
    legend: {
        position: 'none'
    }
 };

chart.draw(data, options);

In the code above, I not only added titles, but I also force the vertical axis to start from 0 and hide the legend by setting its position to none.

Column chart is now updated with helpful titles.
Column chart is now updated with helpful titles.

What we have seen so far is the non-Material Column Chart. So how will a Material Column Chart look like?

To get a Material Column Chart, we will change the code above to the following.

var options = {
    chart: {
        title: 'Sales of Branches',
        subtitle: '2015 First Quarter'
    },
    axes: {
        y: { 0: { label: 'Amount (SGD)' } },
        x: { 0: { label: 'Branch' } } 
    },
    legend: {
        position: 'none'
    }
};

var chart = new google.charts.Bar(document.getElementById('chart_div'));

chart.draw(data, options);

Then we will be able to get the Material version of the chart. Now, we are even able to define a subtitle for the diagram.

Yup, we successfully upgraded our chart to the Material version.
Yup, we successfully upgraded our chart to the Material version.

In case you would like convert a non-Material Column Chart to a Material version, you can do so with the code below too.

chart.draw(data, google.charts.Bar.convertOptions(options));

Challenge with Tab in Bootstrap

When I was adding Google Charts to one of my web page with tabs using Bootstrap framework, I realized there was a problem with the display of the rendered diagram. The labels in the chart are incorrectly positioned. This problem has been discussed on Stack Overflow as well.

 

Display Issues of Google Charts in Bootstrap Tabs
Display Issues of Google Charts in Bootstrap Tabs

Interestingly, if the chart happens to be in the first tab which is visible by default, then there won’t be any display issue on the chart. This problem only occurs when the charts are located in those subsequent tabs which are hidden during the first load of the page. When user clicks on any of those subsequent tabs, then the display issue will happen.

So one obvious solution is actually to only call the Google API to render the graph when the tab is clicked. To be safe enough, I actually put a delay to the click event of the tab so that the chart will be drawn 3 seconds after the the corresponding tab is clicked. This seems to help fixing the display problem.

Similar to my solution, there is also a better alternative which is to bind the draw function to the show event of the tab, as discussed on Stack Overflow. I like the solution too because of its cleanliness of the code.

Try More with Google Charts

Google Charts is undoubtedly a very easy-to-use solution for web developers to present their data. So, please try it out and be amazed by the number of charts available on Google Charts.

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner

Razor Learning Notes

Razor is still a new markup language to me, after working on ASP .NET Web Form projects for 3 years. I started to learn Razor in the beginning of this year (2015), so I decide to note down what I find interesting in my Razor learning journey and then share it here.

A Powerful HTML Helper Method: EditorFor

When I first started learning Razor, I was confused by EditorFor and TextboxFor. So, what is the difference between both of them?

TextboxFor is easy to understand. It is a helper method is used to render a TextBox on the web page no matter which type of the data is passed to the method.

EditorFor is more powerful than TextboxFor. Besides rendering a TextBox, it can also render other HTML elements based on the type of the data. For example, if the datatype is boolean, it renders a checkbox. If the datatype is calendar, it will render a textbox with calendar popup (which is not so nice looking as compared to the calendar popup created using XDSoft DateTimePicker).

Even though the datatype is specified to be DateTime, EditorFor does not provide a control for time section.
Even though the datatype is specified to be DateTime, EditorFor does not provide a control for time section.

EditorFor Accepts Custom Templates

By default, the EditorFor will create a textbox with calendar popup for data which is DateTime. We can change it to use another look-and-feel by create our own template.

So let’s say we want the EditorFor to render five dropdown boxes for each of the following components in DateTime: Year, Month, Day, Hour, and Minute.

Firstly, I create a file called DropDownDateTime.cshtml file which is in charge of the look-and-feel of the custom template. This file needs to be put under /Views/Shared/EditorTemplates. Also, please take note that the filename must be same as the corresponding data type.

@model MyProject.Models.DropDownDateTime
@{
    List<SelectListItem> years = new List<SelectListItem>();
    int prevYearCount = Model.PreviousYearCount;
    int nextYearCount = Model.NextYearCount;
    for (int i = Model.DateTime.Year - prevYearCount; i <= Model.DateTime.Year + nextYearCount; i++)
    {
        years.Add(new SelectListItem() { 
            Text = i.ToString(), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Year ? true : false) });
    }

    List<SelectListItem> months = new List<SelectListItem>();
    for (int i = 1; i <= 12; i++)
    {
        months.Add(new SelectListItem() {
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Month ? true : false) });
    }
 
    List<SelectListItem> days = new List<SelectListItem>();
    for (int i = 1; i <= 31; i++)
    {
        days.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Day ? true : false) });
    }

    List<SelectListItem> hours = new List<SelectListItem>();
    for (int i = 0; i < 24; i++)
    {
        hours.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Hour ? true : false) });
    }

    List<SelectListItem> minutes = new List<SelectListItem>();
    for (int i = 0; i < 60; i += 15)
    {
        minutes.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Minute ? true : false) });
    }
}

@Html.DropDownList("years", years)
@Html.DropDownList("months", months)
@Html.DropDownList("days", days) at 
@Html.DropDownList("hours", hours) : 
@Html.DropDownList("minutes", minutes)

So, with the help of this template, whenever I pass in a data which has DropDownDateTime as its type, EditorFor will automatically render the five dropdown lists, as shown in the screenshot below.

Yup, customized look-and-feel for DateTime picker.
Yup, customized look-and-feel for DateTime picker.

Razor and Content

When I am building apps using ASP .NET Web Forms, I often need to add some server codes within the HTML in .aspx file. For example,

<h2>Animes</h2>

<ul>
    <% foreach (var anime in animeCollection) { %>
        <li><%= anime.Name %></li>
    <% } %>
</ul>

In Razor, we do not need to explicitly denote the start and end of the server blocks within our HTML. The Razor parser is smart enough to implicitly identify when a server block ends by looking for HTML tags. Hence, Razor is able to keep the HTML clean, as shown in the sample coe below.

<h2>Animes</h2>

<ul>
    @foreach (var anime in animeCollection) {
        <li>@anime.Name</li>
    }
</ul>

However, there are sometimes where the Razor parser cannot do the job properly, especially when we need to mix Razor and Javascript code. For example, when we are rendering diagram using Google Charts, as shown in the sample below.

@{ int counter = 0; }


    var data = new google.visualization.DataTable();

    data.addColumn('string', 'Sales Date');
    data.addColumn('number', 'Sales');

    data.addRows([
        @foreach (var record in dailySalesSummaryRecords)
        {
            counter++;
            if (counter == dailySalesSummaryRecords.Count())
            {
                @:['@record.Key', @record.TotalSales.ToString("0.00")]
            }
            else
            {
                @:['@record.Key', @record.TotalSales.ToString("0.00")],
            }
        }]
    );
    
    ...

The two lines highlighted above are Razor code within JS. Both of them are actually doing the same thing. Just that one of them has no trailing comma which is to avoid browsers like Internet Explorer 8 to throw errors.

The @: Character Sequence is used to explicitly tell Razor to interpret the following line of content as content. However, @: can only work on single line. So for scenarios with multiple lines of content, we need to do something as follows.

...
@: Line one of content
@: Line two of content
@: Line three of content
...

Alternatively, we can just use <text> Tag to effectively mark the start and end of content.

...
<text>
    Line one of content
    Line two of content
    Line three of content
</text>
...

To read more about @: Character Sequence and <text> Tag, please refer to a detailed blog post about them on ScottGu’s Blog.

Razor Encodes String by Default

Yes, Razor encodes string by default. So what should we do if we want rendering without encoding? Well, we can do something as follows.

@Html.Raw(" alert('Hello World!'); ")

<text> Tag, Html.Raw, and Encoding

There is a very interesting discussion on Stack Overflow about how to correctly doing encoding/decoding in Razor with JavaScript. It starts with a question on how to avoid the apostrophe characters in s.Name to be rendered as ‘.

    $(function () { 
        $('#calendar').fullCalendar({
        header: { left: '', center: 'title', right: 'month,agendaWeek,agendaDay' },
        month: 5,
        year: 2011,
        editable: false,
        events: [
            @foreach (var s in ViewBag.Sessions)
            {
                @:{
                @:title: '@s.Name',
                @:start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
                @:end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
                @:},
            }
        ]});
    });

First of all, we change the code to use <text> because the content is multiple lines. Using @: repeatedly seems a bit strange to me.

<text>
    {
        title: '@s.Name'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

Next, we will apply Html.Raw so that apostrophes won’t be encoded as ‘.

<text>
    {
        title: '@Html.Raw(s.Name)'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

However, without encoding apostrophes, we may break the JavaScript code with the existence of apostrophes characters, such as

title: 'Jiahao's Birthday'

So, we need to still encode it using JavaScriptStringEncode.

<text>
    {
        title: '@Html.Raw(HttpUtility.JavaScriptStringEncode(s.Name))'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

Wait… We don’t want apostrophes to be encoded as ‘ in the first place? Why do we doing encoding now?

This is because JavaScriptStringEncode, a newly introduced method in .NET 4, will encode apostrophes not as &#39 which is something not human-friendly, but it will encode it as \’. So yup, this solve the problem.

JavaScriptStringEncode is a great feature which helps us to handle encoding C# string to a JavaScript string. It is able to escape not only apostrophes, but also double quotes (“), question marks (?), backslash (\), and ampersand (&).

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner

Summer 2015 Self-Learning

Summer Self-Learning
It has been about half a year since I started to learn ASP .NET MVC and Entity Framework (EF). In this period of time, I have learnt about not just MVC and EF, but also Azure PaaS, Google Maps API, web application security, cool jQuery plugins, Visual Studio Online, etc.

In the beginning of May, I started to note down useful things I’d learned in my learning journey. Months of bringing together information in this summer has helped me compile my notes about what I’ve learned in the past 6 months. I have currently completed compiling notes for 17 topics that I’ve learnt in this summer.

I listed down the title of the 17 posts below to give you a quick overview about all the 17 topics.

Contents

ASP .NET MVC and Entity Framework

Security

Microsoft Azure

Google APIs

Web Development Tools

Learning After Work

I’m working in Changi Airport. The office working hour is from 8:30am to 6pm. In addition, I am staying quite far from the airport which will take about one hour for me to travel from home to office. Hence, the only time that I can have sufficient time to work on personal projects is weekends.

This summer self-learning project is originally planned to be done by the end of May. Normally, it takes me about one day to finish writing a post. After that, if I find any new materials about the topics, I will then modify the post again. Sometimes, however, I am just too tired and I would not write anything even though it’s weekend. Hence, I end up finishing all the 17 topics three months later.

This summer learning project covers not only what I’ve learnt in my personal projects, but also new skills that I learn in my workplace. I always enjoy having a chat with my colleagues about the new .NET technology, app development, Azure hosting, and other interesting development tools. So yup, these 17 articles combine all the new knowledge I acquire.

I’m also very happy that that I am able to meet developers from both .NET Developers Community Singapore and Azure Community Singapore and share with them what I’ve learnt. That gives me a great opportunity to learn from those experienced .NET developers. =)

Azure Community March Meetup in Microsoft Singapore office.
Azure Community March Meetup in Microsoft Singapore office.

I am not that hardworking to work on personal projects every day. Sometimes, I will visit family and friends. Sometimes, I will travel with friends to overseas. Sometimes, I will play computer games or simply just sleep at home. So ya, this self-learning project takes a longer time to complete. =D

Working on personal projects after work is stressful also. Yup, so here is a music that helps reducing my stress. =)

Modernizr and Progressive Enhancement

Modernizr

Since Visual Studio 2012, we can always find this file called modernizr-(version).js in the default ASP .NET 4.5 MVC template. So, what is Modernizr (can be downloaded from Nuget)?

Modernizr is a JS library which is able to detect HTML5 and CSS features in the user’s browser. During page load, Modernizr will start to test those next-generation features. After that, it will create a JS object which contains the test results. For example, Modernizr.canvas will be true if the browser supports the HTML5 <canvas> element.

Modernizr then adds CSS classes to the <html> tag that tell us which CSS / HTML5 features are supported on the current user’s browser. For example, in my Chrome browser, touch feature is not supported, thus, there is a no-touch class added. The other features like video, audio are all supported.

<html class=" js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">

With this information, we will then be able to provide alternative look-and-feel for those users who are using older versions of browser instead of telling those users “Best view in version xxx of browser yyy”.

With YepNope.js, we will also be able to tell Modernizr what to test and then what JS/CSS to load if the test passes or fails.

Finally, please remember that Modernizr only provides us information about which features are (not) supported. It won’t magically enable those features for us. We need to write corresponding JS/CSS to provide alternative views when the features are not supported on the browser.

In short, Modernizr is a good tool for designers to implement the idea of Progressive Enhancement.

Graceful Degradation

When I was reading about Progressive Enhancement, I read this term called Graceful Degradation. It basically means the way of using the newest and best web technologies while maintaining support for older browsers.

The famous border-radius feature in CSS3 is supported in modern browsers like IE11, Edge, Chrome, and Firefox but it’s not supported in Internet Explorer 7 and 8. Does this stop us from using border-radius in our website? Nope. This is because for users who are still using IE7/8, they can still use the website in the same way as those who are using modern browsers. Just that those who are using old browsers cannot see the beautiful effect of border-radius.

Different visual effect in IE8 and IE11.
Different visual effect in IE8 and IE11.

So basically the idea of Graceful Degradation is that it starts at ideal user experience level and it decreases depending on browser capability down to a minimum level.

Progressive Enhancement

Progressive Enhancement does in the opposite way as Graceful Degradation. It starts at a board minimum user experience and increases depending on browser capability. For example, when user switches from old browser to modern browser, he/she will be able to experience more advanced functionality that will be automatically enabled on the modern browser. So, Modernizr helps us to achieve this by checking if a certain feature is enabled or not on the current browser.

References

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner