Viskit.js

The javascript charting library

This project is maintained by wso2

Try out Viskit.js

Viskit.js is more than just a charting library. It solves the data filtering part as well for your visualizations. Viskit has inbuilt constructs such as data filters and providers so the chart creators can easily retrieve the required data from a data service.

Viskit is open sourced and available under Apache2.0 licence.

What's been used behind the scene

Viskit uses multiple charting libraries behind the scene and also provides an interface to plug your own charting toolkit. The libraries which are being used are

We also like to thank all the geniuses who contributed to these projects.

Some notable features

Example charts

Working with charts - use-cases of Viskit

Viskit supports both jqPlot and Protovis and provides a common interface to the user hiding the complexities and the differences between various charting libraries. The following section explains step by step on how charts can be developed using Viskit via either JQPlot or Protovis.

Including required files

Viskit requires users to include a few scripts and CSS files into their html source. You need to have following scripts included

<script type="text/javascript" language="javascript" src="/Viskit/js/Viskit.js"></script>

jqPlot Note: To work with jqPlot the following two lines should also be added

<script type="text/javascript" language="javascript" src="/Viskit/js/jquery.jqplot.js"></script>
<link rel="stylesheet" type="text/css" href="/Viskit/css/jqplot/jquery.jqplot.css" />

Creating the chart

Creating a chart is done by calling a constructor of the chart type required and passing the necessary values used by the chart.

wso2vis.s.chart.jqplot.pluginsType("BarChart");
var chart = document.getElementById('chart1')    
var barChart = new Viskit.s.chart.jqplot.BarChart(chart,"Title","");    

barChart.dataField(["services", "service"])    
          .dataValue(["stats", "requestCount"])    
          .dataLabel(["@name"])    
          .width(600)    
          .height(300)    
          .showPointLabels(true)    
          .barWidth(75)    
          .barMargin(45)    
          .yTitle("RequestCount")    

barChart.load();    

dataProvider.addDataReceiver(dataFilter);    
dataFilter.addDataReceiver(barChart); 
dataProvider.pullData();   
dataProvider.initialize();    

If you are using JQPlot, its mandetory to include the "Barchart" plugin, which is done in the line No. 1 The second line creates a DOM object from a div element with the id “chart1”. Then calls the jqplot.BarChart constructor passing the DOM object of the chart object, the title of the chart and description of the chart (in the example the description is left blank)

Note: The chart id can also be set instead of the DOM object. The following code snippet also works

var barChart = new Viskit.s.chart.jqplot.BarChart("chart1","Title","");

Setting chart properties

Viskit provides the user the ability to change the chart properties in a simple manner. There is a set of properties that are common to all the charts irrespective of their type.

Ex. dataField, width

And there is another set of properties that are specific to each chart.

Ex. barWdith barMargin ( these are specific to jqPlot bar charts).

dataField, dataValue and dataLabel are the most important properties of the chart. Let us look at what they are used for.

dataField

Specifies which data element to use from the data set. For the sample we use the following XML data set

<services>  
   <service name="Service 03">  
         <stats>  
           <requestCount>34</requestCount>  
           <responseCount>18</responseCount>  
           <faultCount>16</faultCount>  
           <averageResponseTime>579</averageResponseTime>  
           <maximumResponseTime>624</maximumResponseTime>  
           <minimumResponseTime>383</minimumResponseTime>  
         </stats>  

         <operations>  
          …………….  
         </operations>  
   </service>          

   <service name="Service 04">  
         <stats>  
           <requestCount>44</requestCount>  
           <responseCount>18</responseCount>  
           <faultCount>26</faultCount>  
           <averageResponseTime>635</averageResponseTime>  
           <maximumResponseTime>685</maximumResponseTime>  
           <minimumResponseTime>631</minimumResponseTime>  
         </stats>  

         <operations>  
          …………………….  
         </operations>  
   </service>
<services>          

service field is taken from, the above dataset and provided to the chart as following

barChart.dataField(["services", "service"])  

dataValue

Specifies the actual value to be used to draw the chart from the specified in the dataField.

barChart.dataValue(["stats", "requestCount"])

dataLabel

Specifies the value to be used as the data label in barchart. In jqplot bar charts this is used to name the x-axis of the chart.

 barChart.dataLabel(["@name"])

After specifiying these three properties and the other optional properties all that needs to be done is to call the load() function and add the chart object to a data provider. In this example a data filter is used so the chart object will not be added directy to the data provider instead it will be added to the data filter.

 barChart.load();  
 dataProvider.addDataReceiver(dataFilter);  
 dataFilter.addDataReceiver(barChart);

The “load” function will initialize the chart and set the necessary parameters to draw the chart.

onTooltip

Allows the user to specify and tooltip for the chart the function would be as follows

barChart.onTooltip = function barTooltip(data) {  
      return data["@name"] + " - Requests: "+ data["stats"]["requestCount"];  
}

onClick

Allows the user to specify a message to be displayed if an element is clicked

 barChart.onClick = function barClick(data) {  
      alert("Clicked: " + data["@name"]);  
 }

Data providers

Providers perform the task of provisioning data (Currently the basic providers are written to take XML like data sets). Viskit gives the user three variants of data providers ProviderGET, ProviderGETJSON, ProviderGETMakeRequest

ProviderGET() Takes a data service URL that returns the data in a XML format.

ProviderGETJSON() Takes data service URL that returns the data in JSON format.

ProviderGETMakeRequest() Normal AJAX requests cannot be made from within open social gadgets because of the cross domain restrains. This provider uses gadgets.io.makeRequest to retrieve data. This takes a data service URL that returns data in XML format

var dataProvider = new Viskit.p.ProviderGET("http://localhost/Viskit/examples/generator2.php"); 

This line creates a data provider that receives data from the given URL. The next step is to add data receivers to the created data provider. Data providers keep an array of data receivers that it pushes data into when the data provider receives new data. New data receivers can be added to the list as follows.

dataProvider.addDataReceiver(theReceiver);

This will add “theReceiver” object into the data provider’s receiver list. “theReceiver” can be a data filter or a chart object. Then to actually make the data provider pull data from the data source the following line should be included in your code. This call will retrieve data from the data source and push them into all the data receivers registered to that data provider.

dataProvider.initialize();  
dataProvider.pullData();

dataProvider.initialize() is called to run any initialization of some logic if needed.

Data filters

Data filters are used to filter out only the necessary data that is needed for the charts. Filters can be easily added to data providers to filter the data

var dataFilter = new Viskit.f.BasicFilter(["services", "service"], ["@name"],["Service 04",Service 03]);

The above line declares a Basic filter which takes three parameters dataField, dataLabel, filterArray

dataField Specifies which data element to use from the data set

dataLabel The label that will be used to filter the data

filterArray The values that the data label should be filtered against

Setting a Timer

When working with data that change over time it is important to update after a specific time interval. Viskit provides a timing mechanism that can address this issue. You can set a timer to a time interval of your choice and set the data provider to pull new data from the data source when a tick is made in the timer. the timer can be used in any way the user wants it is not limited to data providers. Let’s look at the code that is related to timers.

var timer = new Viskit.u.Timer(5000);  
timer.tick = dataProvider.pullData();  
timer.startTimer();

The above code snippet creates a timer that ticks every 5 seconds. In this code snippet the tick is set to call dataProvider.pullData()

Using local Storage

One of the features provided by Viskit is the local and session storage support. This feature is currently available in jpPlot charts. Local storage is important when charting the variation of a property against time. Local storage will allow you to keep the values of that property for longer periods of time even if the browser is closed or the device is shutdown. Uses can activate local or session storage by simply specifying two extra properties for jpPlot charts. Users can either enable local storage or session storage and the user can specify the time interval (in milliseconds) that the users want to keep the data in the storage. Only data that are newer than the specified time will be kept in the storage.

barChart .enableLocalStorage(true);  
barChart. storageTime(1000*5);

Writing your own visualization for Viskit

Sometimes the existing visualization implementation may not be sufficient to your needs or may lack one or two features that you need. Let’s say you need a new type of chart that is not currently implemented in the current visualization libraries then it is possible to implement your own chat or any other form of visualization that you require. This guide will show how a new visualization can be added in to Viskit using Raphael.

Raphael is a highly customizable charting library that can be used to create any type of visualization using vector graphics. We will try to create a simple bar chart implementation for Viskit using Raphael for this guide.

Understanding Viskit charts

Before we start to write our own chart let's take a look at the structure of Viskit charts. Each and every chart extends from Viskit.Chart class that defines the main functions and parameters of a chart. Any chart implementation overrides the necessary function from the functions that are defined in Viskit.Chart.

Your own bar chart with Raphaël

Let’s start to create our Raphael bar chart implementation. We will create a simple bar chart to understand how to create your own chart implementation. To understand this guide having a general idea about Raphael will be helpful. You can take a look at the Raphael documentation here

Creating the constructor

We will first write a constructor for the chart that is similar to the constructor in Viskit.Chart. the constructor will be named "Viskit.s.chart.raphael.BarChart" according to the naming standards of Viskit. The constructor will call the super class constructor, set default values to properties that are defined for this chart ( Since we did not define what the properties are we will add this later) and define any variables that will be needed by the chart implementation.

Viskit.s.chart.raphael.BarChart = function(canvas, chartTitle, chartDesc) {
    Viskit.s.chart.Chart.call(this, canvas, chartTitle, chartDesc);

    this.colscheme(20)      
    this.chart = null
    this.formattedDataArray = [];
}

Extending Viskit.Chart

The following code line should be added to the code to say that this chart extends from Viskit.Chart.

Viskit.extend(Viskit.s.chart.raphael.BarChart, Viskit.s.chart.Chart);

Defining chart properties

Now we will define all the chart properties that we need for our bar chart implementation. We will only need a small number of properties because we are creating a rather simple bar chart. Any number of properties can be defined as needed.

Viskit.s.chart.raphael.BarChart.prototype
    .property("dataField")
    .property("dataValue")
    .property("dataLabel")
    .property("barWidth")
    .property("barPadding")
    .property("fontFamily")
    .property("fontSize")
    .property("raphaelPaper")
    .property("marginSize");

Now we shall add the lines to set defaults to the defined properties.

Note: dataField, dataValue and dataLabel are not assigned with default values since these properties must be specified when creating a chart object.

Viskit.s.chart.raphael.BarChart = function(canvas, chartTitle, chartDesc) {
    Viskit.s.chart.Chart.call(this, canvas, chartTitle, chartDesc);

    this.colscheme(20)
        .width(500)
        .height(300)
        .barWidth(55)
        .barPadding(35)
        .fontFamily('Fontin-Sans, Arial')
        .fontSize('10px')
        .raphaelPaper(null)
        .marginSize(20);

    this.chart = null
    this.formattedDataArray = [];
}

Creating a data converter (the important point)

Now we will write a function to convert the received data into a form that we can use easily. We shall name this method "convertData". this method will convert the data into an array of JSON objects with two properties “label” and “value”.

label This will be used to label each bar of the chart. "label"” will keep the values specified by the "dataLabel" property.

value This property will be used to draw the chart this will specify the height of the chart. This will keep the value specified by the “dataValue” property.

The code for the data converter will be as follows.

wso2vis.s.chart.raphael.BarChart.prototype.convertData = function (that) {
    var df = that.traverseToDataField(that.data, that.dataField());    
    var dcount = 1;
    if (df instanceof Array) {
        dcount = df.length;
    };

    that.formattedData = [];

    for (var i = 0; i < dcount; i++) {
        that.formattedData.push({
            "label":getLbl(i),
            "value":getVal(i)
            });
        that.formattedDataArray.push(getVal(i));
    };

    function getVal(x) {
        var r;
        if (df instanceof Array) {
            r = df[x];
        }
        else {
            r = df;
        }        
        return parseInt(that.traverseToDataField(r, that.dataValue()));
    };

    function getLbl(x) {
        var r;
        if (df instanceof Array) {
            r = df[x];
        }
        else {
            r = df;
        }
        return that.traverseToDataField(r, that.dataLabel());
    };
};

The “load” function

This is the function that is called to actually create the chart. Here we will simply call the "createBarChart" method

Viskit.s.chart.raphael.BarChart.prototype.load = function () {
    if (this.raphaelPaper() == null) {
        this.createBarChart();
    }
    return this;
}

The “update” function

This is the only method we will be overriding for this example as explained earlier we will write the code to draw when data is changed in this method

Viskit.s.chart.raphael.BarChart.prototype.update = function () {
    this.formattedDataArray = [];
    this.convertData(this);

    var r = this.raphaelPaper();
    r.clear();
    var ratio = (this.height()-(this.height()/10))/this.formattedDataArray.max();
    var grid = r.drawGrid(this.marginSize(),0, this.width(), this.height()-this.marginSize(), 10, 10, "#333");
    r.setYAxis(this.marginSize(),  this.height()-this.marginSize(), 10, 0, this.formattedDataArray.max(), r);

    for( var i = 0; i < this.formattedData.length;i++){
        var bar = r.createBar( this.formattedData[i].value*ratio, i+1,this.formattedData[i].label,this,r);

    }
}

This method will call the custom Raphael functions that we defined to draw the chart. Before drawing the chart the canvas will be cleared to make sure the new chart is not sketched on top of any previous charts.

A complete code which was written for a Raphael pie chart can be fount at the repository

Adding the new chart into Viskit

Now our bar chart is ready to be deployed into Viskit. To add a new implementation into Viskit you have to create a .js file that contains the code for the implementation place it in the appropriate place of the folder structure and do some minor changes into build files.

We will place the BarChart.js file in Viskit\js\subscriber\chart\raphael

You need to add this to the build script and build the library, so evrything will be packedup correctly. The build will also genarate you a Viskit.js minified version as well

Licence

Viskit is available under Apache2.0 licence.