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

Real-time SPC Web Application for iPad/Android tablet using jQuery/AJAX/AJAX enabled WCF Service

5.00/5 (12 votes)
18 Dec 2013CPOL11 min read 59.3K   1K  
Real time SPC is a Web Application for iPad and Androind using HTML5 and jQuery AJAX.

Real Time SPC

Introduction

A couple of months back I wrote an article titled TaskTracker Offline Web Application for Mobile using HTML5, jQuery-UI and KNOCKOUT.js. In that the focus of the article was offline programming using HTML5 and exploring the features of different powerful frameworks such as jQuery, jQuery-UI, and Knockout. This article is an extension of it and covers some additional features such as HTML5 Canvas, integration with back-end database using jQuery AJAX, and AJAX enabled WCF Services. The key features explored in this article are given below:

  • Application Cache, Webstorage, and Canvas features of HTML5 are used in this application
  • jQuery AJAX makes asynchronous programming easier and enables you to interact with Web Services from JavaScript.
  • AJAX enabled WCF Services and Entity Framework

Background 

SPC is a very important part of quality control in any manufacturing process. Currently the data capture process for doing SPC analysis is mostly manual. This is mainly due to the harsh environment in the shop floor and it is difficult to use conventional computers or laptops there. With the advancement in smart phone technology it is now possible to write an application for this purpose to automate the data capture process and do quick SPC analysis in real time. Also, with key features such as offline programming of HTML5, you can now save data locally in the absence of internet and then save it to the backend database once connected to the internet, for future analysis.

Hence Real Time SPC (Statistical Process Control) applications for iPad/Android tablets will be very useful to engineering, manufacturing, and process industries. This will enable quality inspectors and operators of this industry to capture data in real time from the shop floor and do quick SPC analysis and check control charts in real time to ensure that the manufacturing process is in control. You can check the working version of the application here.

Design Overview

The application is built using the popular MVVM design pattern. MVVM is a design pattern very similar to the old MVC design pattern and addresses the separation of concerns. Like MVC it has a model, view, but the controller role is done by the ViewModel. The View Model is responsible for handling user interactions and also interacts with the model and updates the view. It can have additional attributes apart from the Model, which can be view specific. Also, in a complex web application comprising of multiple views, each view can have a corresponding view model. In our application there is only one view and one view model. The key files of the application are newmain.html, SPCNewController.js, StorageController.js, controlCharts.js, SPCAjaxHelper.js, and SPCService.svc. The class diagram of the application is shown in Figure 1.

Class Diagram of Real Time SPC

From figure 1, the RealTimeSPCUI class is a conceptual class and represents the UI for the application and is implemented as plain HTML. SPCViewModel is a key class responsible for handling all the user interactions and updating the view and interacting with the model. Measurement is an entity class which acts as a model for this application. StorageController is a wrapper class and is responsible for saving and retrieving data from WebStorage.

XBarRangeChart is the class responsible for the control charts. SPCAjaxHelper is a helper class for handling the jQuery AJAX interaction with the WCF Service class SPCService.

JavaScript is not like conventional object oriented programming languages such as C++, C#, or Java and it does not have the Class construct, so all the classes are implemented differently. I will first explain the business layer implementation, then the data layer, and finally the UI.

Business Layer

The business layer consists of a key entity Measurement and represents the Model. Another important class is SPCViewModel. The section below shows the implementation details of the Measurment class.

JavaScript
// Declare Measurment class
function Measurement() {
    var self = this;
    self.parameter= ko.observable("");
    self.id = 1,
        self.TimeStamp = ko.observable($.datepicker.formatDate('yy-mm-dd',new Date())),
        self.PartNo = ko.observable(""),
        self.Machine= ko.observable(""),
        self.Operator=ko.observable(""),
        self.Parameter= ko.observable("Inner Diameter");
        self.P1=ko.observable(0),
        self.P2=ko.observable(0),
        self.P3=ko.observable(0),
        self.P4=ko.observable(0),
        self.P5=ko.observable(0),
        self.PAve = ko.dependentObservable(function () {
            var aveValue=(eval(self.P1())+eval(self.P2())+
              eval(self.P3())+eval(self.P4())+eval(self.P5()))/5;


         return Math.round(aveValue*1000)/1000;
    });
    self.PRange = ko.dependentObservable(function () {
        var m= Math.max(self.P1(),self.P2(),self.P3(),self.P4(),self.P5());
        var n= Math.min(self.P1(),self.P2(),self.P3(),self.P4(),self.P5());
           return Math.round((m-n)*1000)/1000;
    });
}

// example of creating new instance of these classes
var curMeasurement = new Measurement();
// Important point to remember knockout observables are methods.
// e.g. you need to read machine name,you invoke it as a method.
var machine= curMeasurement.machine(); // see we access the property as function.
// set the property.
curMeasurement.machine('M1'); // setting the observable property.

If you look at the above code you might have noticed that the class contains only properties as it is an entity class and does not expose any methods. But also, you might notice that these properties are initialized with Knockout constructs. These properties are declared as observables. This will enable these properties to bind to the UI and will provide two way binding. So any change done to these properties in the UI will automatically update the properties. Or if you change their values programmatically, then those changes will be reflected in the UI. One thing to remember is that the Knockout observables are functions and you can't access or initialize them as normal properties. Also notice the declaration for dependent observable properties. These properties are derived from other properties. See the above code showing an example of setting and accessing a Knockout observable property.

Let us now see the implementation details of SPCViewModel. This is the key class responsible for handling user interaction and will update the UI and model.

JavaScript
// Only some sections of the code are shown here.
function SPCViewModel() {
    var self = this;
    self.onLine = ko.observable(false);
    self.filterDate = ko.observable("");
    self.filterPoints = ko.dependentObservable(function () {
        var partno = self.lastPart();
        var parameter = self.lastParameter();
        return ko.utils.arrayFilter(self.dataPoints(), function (item) {
            var cp, cparam;
            if ($.isFunction(item.PartNo))
                cp = item.PartNo();
            else
                return false;
            if ($.isFunction(item.Parameter))
                cparam = item.Parameter();
            else
                return false;
            if ((partno === cp) && (parameter === cparam))
                return true;
            else
                return false;
        });
    });
   // Remove Measurment.
   self.removeMeasurement = function (iDP) {
        self.dataPoints.remove(iDP);
        var mDP = ko.toJSON(self.dataPoints);
        self.normalDP = JSON.parse(mDP);
        tsk_ns.storage.saveItem("measurments", mDP);
        self.updateDPArray();
    };
    // Edit measurement
    self.editMeasurement = function (iDP) {
        self.selected(iDP);
        self.currentDP(iDP);
        self.taskMenu("Edit Data");
        $("#accordion").accordion("activate", 0);
        self.editFlag = true;
    };
}

SPCViewModel is a core class of this application and is responsible for handling user interactions and interacts with the model and updates the view. The above code is not the complete source code, but just a highlight of the key methods. The view model has two observable arrays defined for storing all the measurment points. Also note the use of dependent observables to filter the measurment points by filtering criteria. The key methods are responsible for the following tasks:

  • Retrieve and save measurement data to local webstorage.
  • Retrieve and save measurement data to back-end database
  • Analyse data and display data in tabular fashion
  • Update control charts

Also note that the status of internet connection is updated in real time, and the buttons used to save the data to the database and retrieve history are enabled only when the user is connected to the internet. The abbove section shows only some part of the code and I request you to refer to the source code for the full implementation details.

Data Layer

Data layer is implemented in two stages: storing the data to local Webstorage and storing it to the back-end database. Local storage is handled by the StorageManager class. Details of its implementation are given below:

JavaScript
// Store Manager Singleton class
// Implemented using revealing module design pattern
var tsk_ns = tsk_ns || {};
tsk_ns.storage = function () {
    // create instance of local storage
    var local = window.localStorage,
    // Save to local storage
        saveItem = function (key, item) {
            local.setItem(key, item);
        },
        getItem = function (key) {
            return local.getItem(key);
        },
        hasLocalStorage = function () {
            return ('localStorage' in window && window['localStorage'] != null);
        };

    // public members
    return {
        saveItem: saveItem,
        getItem: getItem,
        hasLocalStorage: hasLocalStorage

    };
} ();

The above class is just a wrapper to window.localStorage  and provides a wrapper method to save and get data from the local storage. The class has a hasLocalStorage method which checks whether the browser supports localStorage.

Saving and retrieval of data to the backend database is implemented using jQuery AJAX and an AJAX enabled WCF service. This is implemented using two classes: SPJAjaxHelper.js is a helper class responsible for making all AJAX calls to invoke the WCF service, SPCService is a class implemented as a WCF service. The implementation of these classes is given below:

JavaScript
// Helper to call Jquery AJAX to interact with
// SPCService.svc (AJAX enabled WCF Service.
//
// Below is wrapper to invoke Jquery ajax.
/// <reference path="json2.js">
function CheckIfOnLine(successMethod, failMethod) {
    var sUrl = "SPCService.svc/CheckIfConnected";
   
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: sUrl,
        dataType: "json",
        processdata: false,
        success: successMethod,
        error: failMethod
    });
}

function GetMeasurementData(msFilter,successFunction) {
    var sUrl = "SPCService.svc/GetMeasurmentDataArray";
    var ms = { measFilter:msFilter };
    var sparam = JSON.stringify(ms);
  //  alert(sparam);
    InvokeWebService(sUrl, sparam, successFunction);
}
  function UpdateMeasurment(msArray,successMethod)
  {
        var sUrl="SPCService.svc/UpdateMeasurmentArray";
        var ps = { parray: msArray };
        var sparam = JSON.stringify(ps);
    //   alert(sparam);
        InvokeWebService(sUrl,sparam,successMethod);
  };


  function InvokeWebService(sUrl,sparam,successMethod) {
      $.ajax({
          type: "POST",
          contentType: "application/json; charset=utf-8",
          url: sUrl,
          data: sparam,
          dataType: "json",
          processdata: false,
          success:successMethod,
          error: function (result) {
              alert('Service call failed: ' + result.status + ' ' + result.textStatus);
          }
      });
        
      
      };
</reference>

The SPCAJAXHelper.js file has three key functions: checking online status, retrieving measurement data based on filter criteria, and saving the data to the database. All these methods call the InvokeWebService method which in turn calls the ajax method of jQuery. Each method passes the appropriate parameters and success callback methods. In case of any error the error message is displayed to the user.

Let us now see the implementation of SPCService. The SPCService class exposes the following methods:

  • CheckIfOnline 
  • GetMeasurmentDataArray
  • UpdateMeasurmentArray

The below code shows the details of each of these methods. Please note the attribute defined for the WCF Service class. See the ServiceContract attribute for the class. Each exposed method is declared with an attribute OperationContract and any parameters passed to the method such as entity classes have the attribute DataContract and each of the properties of the entity class is decorated with the attribute DataMember. Also, the AspNetCompatibilityRequirements attribute to the class is also required. Message exchange between the WCF service and AJAX calls made from JavaScript use the JSON format. Please refer to the WebInvoke attribute in the below code where the message format is defined.

An important point to remember is parameter names passed to invoke the methods should match the exact signature of the WCF method. I have created similar entity classes in JavaScript so that the same type of parameters can be passed. In our case, there are two entities: MeasurmentSummary and MeasurmentFilter. I won't explain the details of each method as the code is self explanatory.

C#
[ServiceContract(Namespace = "SPCAnalysisWeb")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SPCService
{
    [OperationContract]
    [WebInvoke(Method = "POST", 
      BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public string CheckIfConnected()
    {
        return "SUCCESS";
    
    }
     // Add more operations here and mark them with [OperationContract]
    [OperationContract]
    [WebInvoke(Method = "POST", 
      BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public MeasurementSummary [] GetMeasurmentDataArray(MeasuremntFilter measFilter)
    {
       // please refer source code for the details.
       return null;
    }

    // Add more operations here and mark them with [OperationContract]
    [OperationContract]
    [WebInvoke(Method = "POST", 
      BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public string UpdateMeasurmentArray(MeasurementSummary[] parray)
    {
       // Method prototype is shown here.
    }
}

[DataContract(Namespace = "SPCAnalysisWeb", Name = "MeasurementFilter")]
public class MeasuremntFilter
{
    [DataMember(IsRequired = true, Name = "PartNo")]
    public string PartNo { get; set; }
    [DataMember(IsRequired = true, Name = "Parameter")]
    public string Parameter { get; set; }
  
}

[DataContract(Namespace = "SPCAnalysisWeb", Name = "MeasurementSummary")]
public class MeasurementSummary
{
    [DataMember(IsRequired = true, Name = "PartNo")]
    public string PartNo { get; set; }
    [DataMember(IsRequired = true, Name = "Machine")]
    public string Machine { get; set; }
    [DataMember(IsRequired = true, Name = "Operator")]
    [DataMember(IsRequired = true, Name = "PAve")]
    public double PAve { get; set; }
    [DataMember(IsRequired = true, Name = "PRange")]
    public double PRange { get; set; }
}

Web.config has configuration details for the WCF Service. If you are using the Visual studio 2010 IDE then it has a template for AJAX enabled WCF Services and it creates all the boilerplate code and configuration for you. Details of Web.Config are given below:

XML
<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="SPCAnalysisWeb.SPCServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true" />
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="SPCAnalysisWeb.SPCService">
        <endpoint address="" behaviorConfiguration="SPCAnalysisWeb.SPCServiceAspNetAjaxBehavior"
          binding="webHttpBinding" contract="SPCAnalysisWeb.SPCService" />
      </service>
    </services>
</system.serviceModel>

All the configuration for the WCF service is under the system.servicemodel section. The key point to note is the binding attribute whose value is set to webHttpBinding. Those who want to know more about the WCF service's working and configuration of WCF services, please refer to the MSDN documentation.

I have used Entity framework to interact with the database. But you can also use LINQ to SQL.

UI Layer

The UI layer is implemented as a plain HTML file. I have used the Accordion widget of jQuery-UI as well as Tabbed Layout.

Once all the document is loaded, it executes the below initialization code. The code defines the validation rules, jQuery-UI initialization code, and the binding of the view model to the UI.

JavaScript
// Document ready
$(function () {
   $('#tabs').tabs();
   
    // Define validation options for taskform
    $('#measForm').validate({
        rules: {
            partno: "required",
            machine: "required",
            operator:"required",

            dp1: {
                required:true,
                number: true
            },
            dp2: {
                required:true,
                number: true
            },
            dp3: {
                required:true,
                number: true,
            },
            dp4: {
                required:true,
                number: true
            },
            dp5: {
                required:true,
                number: true
            }
        }
      });

    $("#hisForm").validate({
        rules: {
            hispart: {
                required:true
            },
            filterdatefrom: {
                required:true,
                date:true
            },
            filterdateto: {
            required:true,
            date:true
                }
        }
    });
      
   
    $("#accordion").accordion({active:1});
   // $("#filterdatefrom,#fromdateto").datepicker();
    $("#taskNew,#taskSave,#taskUpdate,#btnRefresh,#btnRetrieve,#btnTest").button();
    $("#taskNew").button("option", "disabled", false);
    $("#taskUpdate").button("option", "disabled", true);

    var viewModel = new SPCViewModel();
    viewModel.init();
    ko.applyBindings(viewModel);
    //$( "#dialog:ui-dialog" ).dialog( "destroy" );
    $("#dlgSave").dialog({
        autoOpen: false,
        modal: true,
        buttons: {
            Ok: function () {

                $(this).dialog("close");
                viewModel.saveToDatabase();
            }
        }
    });
    var id= setInterval(viewModel.updateOnLineStatus,10000);
});

The above code does initialization of the GUI widgets and the field validation for the Measurement form. Also, the JavaScript timer is setup to update online status. Finally, the view model is initialized and the binding is applied to the view.

One of the key parts of the UI is Control Charts. I have implemented it using HTML Canvas. The key class implementing the charting functionality is XBarRangeChart. Please refer to the source code for details of the implementation.

I have used different types of bindings such as for-each,  with, form binding features of KnockoutJS. Please refer to the source code for complete details.

Configuring for Offline Working

With HTML5, we can now configure the pages, assets, and resources of the application which should be served offline. This is possible by defining the Application Manifest file, which is a plain text file. Also, in the html tag, you need to define the manifest attribute to specify the name of the manifest file. <html manifest="manfiest.appcache"> I have added a manifest file with the extension of .appcache. But you can use any extension. But we need to configure the webserver to include this new extension type as well as specify its MIME type as text/cache-manifest. Please refer to the code below to see the content of the manifest file.

Please remember that the fist line in the manifest file should be CACHE MANIFEST. Don't put any comments before this line. The structure of the manifest file is simple. It has three sections: CACHE, NETWORK, and FALLBACK. All the pages and resources used off-line need to be specified under the CACHE: section. Pages/resources required only online are under the NETWORK section. In the FALLBACK section you can specify alternate pages in case of fallback. That's it!

The browser supporting the application cache will initially save all the offline resources on the client side and then it will always serve these resources from the application cache irrespective of whether you are online or offline. So if any changes are done to these pages, they will reflect only when the manifest file is modified. This is an important point to remember. Modify the manifest file and update the version to indicate to the browser that there are some changes so that it will bring the latest changes from the server and save it again on the client side.

CACHE MANIFEST
## version 2.3
CACHE:
themes/ui-darkness/jquery-ui-1.8.21.custom.css
themes/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png
themes/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png
themes/ui-darkness/images/ui-bg_glass_20_555555_1x400.png
themes/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png
themes/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png
themes/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png
themes/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png
themes/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png
themes/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png
themes/ui-darkness/images/ui-icons_222222_256x240.png
themes/ui-darkness/images/ui-icons_4b8e0b_256x240.png
themes/ui-darkness/images/ui-icons_a83300_256x240.png
themes/ui-darkness/images/ui-icons_cccccc_256x240.png
themes/ui-darkness/images/ui-icons_ffffff_256x240.png
Styles/spcmain.css
Scripts/jquery-1.7.1.min.js
Scripts/json2.js
Scripts/jquery-ui-1.8.17.custom.min.js
Scripts/jquery-ui-timepicker-addon.js
Scripts/knockout-latest.js
Scripts/ko-protected-observable.js
Scripts/StorageManager.js
Scripts/SPCNewController.js
Scripts/jquery.validate.min.js
Scripts/additional-methods.js
Scripts/ControlCharts.js
Scripts/jquery.dateFormat-1.0.js
Scripts/SPCAjaxHelper.js
Images/app-note-icon.png
Images/Actions-document-edit-icon.png
Images/edit-trash-icon.png
newmain.htm
NETWORK:
SPCService.svc
SPCService.svc.cs

Styling for Mobile

I don't have to do a major change to configure this application for mobile. The only thing you need to specify is the viewport setting in the head section of your HTML file. I had to define an extra style for the textarea tag as its width was overflowing outside its parent container. Please refer to the code below for details.

CSS
// <meta name="viewport" content="width=device-width, initial-scale=1">
 // styling for textarea
 .fixwidth
{
    width:80%;    
}

Points of Interest

HTML Canvas is not yet supported by all browsers. So this code may not work on all browsers. Luckily, all the Smartphones and tablets have browser support for it and I have tested it on iPad, Android, and Blackberry tablets. When you download the source code you need to provide the database connection string for information such as server name, userID, and password.

Android Phone/iPhone/iPad Users

A working version of the application is available here. You can bookmark this page. It will work both in off-line and online modes.

History

I was thinking of extending my TaskTracker application to provide support for saving and retrieving data to the back-end database. But I thought it will be better to do a completely new application and also I wanted to explore the features of HTML Canvas, and hence I developed this application which is also useful to the manufacturing and process industry.

Conclusion

Due to the new features in HTML5 it is now easy to develop off-line web applications. The application explores the key features of HTML5, jQuery, jQuery-UI, jQuery-Validation, and KnockoutJs. You can also see how the power of jQuery AJAX is used to retrieve and save data to the back-end database using an AJAX Enabled WCF Service. Also we can use an Open Source framework such as PhoneGap to convert it to a native application for different mobile platforms. Please let me know your comments and suggestions. You can e-mail me for any queries or clarifications about the implementation. Thank you.

License

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