Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

HTML5 Server-Driven Progress Bar

4.90/5 (9 votes)
23 Jun 2015CPOL3 min read 31.1K   469  
A clock rendered as 4 progress bars and published by the server in real-time.

Introduction

This article demonsttrates an html/javascript real-time progress bar, updated by the server. In order to accomplish this, we have made a Spike Engine server that sends necessary time components (hours, minutes, seconds and milliseconds) to the connected clients, every 100 milliseconds. For a quick summary:

  1. Time components (hours, min, sec, ms) are sent from the server to the client every 100 milliseconds.
  2. It uses progressbar.js library to show and update progress bar on client side.
  3. It uses websockets internally, but abstracted by Spike-Engine, will fallback to flash sockets for older browsers.
  4. The application server is a self-hosted executable.
  5. The client is just a plain HTML page that shows the progress bars and the progress bars gets updated as the client get the published data from server.

Image 1

[Live Demo]

As one can see in the screenshot above, there are four progress bars for hours, minutes, seconds and milliseconds. The hour progress bar completes when 24 hours are complete. The minute and second progress bars complete when the values of minutes and seconds reach to 60. The millisecond progress bar completes for every single second. 

Server-Side Implementation

Let's begin by making the server. This server needs to do several things:

  1. Listen to a particular endpoint (IP+Port) and create a publish-subscribe channel for posting messages to the client.
  2. Get time components on a particular frequency (100 ms in our case) and publish the value to all subscribed clients.

For the first task, we need to call Service.Listen method in order to start listening on a specific IPAddress and a port (called endpoint). This line in the Main method accomplishes it:

C#
Service.Listen(new TcpBinding(IPAddress.Any, 8002));

Next, we create a new PubHub instance, provided us by Spike-Engine using statement:

C#
var hub = Service.Hubs.GetOrCreatePubHub("Clock");

This implements publish-subscribe model. In publish-subscribe model senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers. Instead, published messages are characterized into classes, without knowledge of what, if any, subscribers there may be. Similarly, subscribers express interest in one or more classes, and only receive messages that are of interest, without knowledge of what, if any, publishers there are. We first create our PubHub instance and give it a name. The name is important as we will need to provide the same name in our clients when we want to subscribe.

Then we schedule a function to be called every 100 milliseconds, this function will publish messages to the PubHub.

C#
hub.Schedule(TimeSpan.FromMilliseconds(100), OnTick);

Here's what it looks like:

C#
[InvokeAt(InvokeAtType.Initialize)]
public static void Initialize()
{
   // We create a PubHub which acts as publish-subscribe channel. This allows us to publish
   // simple string messages and remote clients can subscribe to the publish notifications
   var hub = Service.Hubs.GetOrCreatePubHub("Clock");

   // We schedule the OnTick() function to be executed every 100 milliseconds.
   hub.Schedule(TimeSpan.FromMilliseconds(100), OnTick);
}

Here's how the complete function to publish messages looks like. It's rather straightforward, as we simply call Publish method. You might notice that we didn't worry about the serialization of the dictionary we want to transmit to our consumers. The method takes in an object and simply auto-serializes it using JSON format.

C#
private static void OnTick(IHub hub)
{
   // Cast is as Pubhub
   var pubHub = hub as PubHub;
   if (pubHub != null)
   {
       // Get the current time and push it into the dictionary
       var dateTime = DateTime.Now;
       var time = new Dictionary<string, int>();
       time.Add("hours", dateTime.Hour);
       time.Add("minutes", dateTime.Minute);
       time.Add("seconds", dateTime.Second);
       time.Add("milliseconds", dateTime.Millisecond);

       // Publish data
       pubHub.Publish(time);
    }
}

Client-Side Implementation

Now, we have to create a client that will consume the data published by our server and will render progress bars in the html page. For this, we have used the progressbar.js library for showing progress bar.

We start by adding the required javascript references in our page:

XML
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="Scripts/progressbar.min.js" type="text/javascript"></script>
<script src="Scripts/spike-sdk.min.js" type="text/javascript"></script>

Then we create the divs in which our progress bars will be shown.

XML
<div id="divHoursProgressBar"></div>
<div id="divMinutesProgressBar"></div>
<div id="divSecondsProgressBar"></div>
<div id="divMillisecondsProgressBar"></div>

Next, we implement the client side functionality in javascript. To get published data from server, we need to connect to the server. When client is connected to the server, it subscribes to Clock hub as the name given to it.

C#
var server = new spike.ServerChannel("127.0.0.1:8002");

// Once the browser is connected to the server, subscribe.
server.on('connect', function() {
    server.hubSubscribe('Clock', null);
});

Once the published data is received on the client side, we call for the function “setStatus” that is responsible for handling the progress bar.

C#
// When we got a notification from the server
server.on('hubEventInform', function(p) {
    setStatus(p.message);
});

function setStatus(timeComponents) 
{
    var parsedTimeComponents = JSON.parse(timeComponents);

    // Handle hours progress bar
    var hours = parsedTimeComponents.hours;
    var hoursProgressBarPercent = hours / .24;
    document.getElementById('lblHoursCount').innerHTML = hours;
    hoursProgressBar.setPercent(hoursProgressBarPercent);

    // Handle minutes progress bar
    var minutes = parsedTimeComponents.minutes;
    var minutesProgressBarPercent = minutes / .6;
    document.getElementById('lblMinutesCount').innerHTML = minutes;
    minutesProgressBar.setPercent(minutesProgressBarPercent);

    // Handle seconds progress bar
    var seconds = parsedTimeComponents.seconds;
    var secondsProgressBarPercent = seconds / .6;
    document.getElementById('lblSecondsCount').innerHTML = seconds;
    secondsProgressBar.setPercent(secondsProgressBarPercent);

    // Handle milliseconds progress bar
    var milliseconds = parsedTimeComponents.milliseconds;
    var millisecondsProgressBarPercent = milliseconds / 10;
    document.getElementById('lblMillisecondsCount').innerHTML = milliseconds;
    millisecondsProgressBar.setPercent(millisecondsProgressBarPercent);
}

History

  • 23/06/2015: Source code & article updated to Spike v3
  • 18/06/2014: Initial Version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)