Search results

Configuring and Formatting Custom Widget

The Syncfusion Dashboard custom widget allows you to add any user-defined widget, d3 controls, Syncfusion controls, or any JS widgets in a dashboard, and it can perform like the normal widget.

Prerequisites and knowledge required for handling the custom widget authoring

This section covers the mandatory requirements to develop the custom widget.

Development Environment Bold BI Enterprise Edition and any web browser as mentioned in the link
Knowledge Required Basic knowledge about the HTML and JavaScript

Creating new widget

Step 1: Download the below attached custom widget template for developing.

Custom Widget Template : Template

Step 2: Modify the settings as per the widget requirement. In the below steps we have provided steps to configure the widget through the configuration file(widgetconfig.json).

Configuring widget using manifest file

custom widget package

You can configure the widget by using the manifest file.

The manifest file is used to specify the widget’s configuration. This file has to be placed in the custom widgets root directory with the name widgetconfig.json.

Custom widget can be configured using the following settings. Refer the structure of widgetconfig.json

{
	"widgetName" : "Name of the widget.",

	"displayName" : "Display name of the widget to be displayed in designer toolbox.",

	"guid": "Unique GUID for the widget.",

	"category" : "Category in which the widget should be displayed in the designer.",

	"description" : "Description of the widget.",

	"srcFile"  : "Path of the source file through which widget can be embedded to
 		       dashboard",

	"dependencies" : "Specify the dependency scripts and CSS files to be referred for 
                                              the widget",

	"dataFields" : " Specifies the widget fields required for binding data from a data
                                          source. Each field can be bound to single or multiple
                                          measure/dimension fields in a data source. When dataFields is not
                                          specified, this widget acts as a non-data bound widget. ",
										  

	"filterSettings": "Filter settings are used to configure whether the widget can take
                                           part in filter interactions between the widgets."
}

Setting name for the widget

Name for the widget can be set and specified through the widgetName API.

Format

widgetName: “name of widget”

Example

widgetName: “sunburst”

Rules

  • It is a mandatory field for the widget.
  • It should not contain any special characters and wide spaces.

Setting display name for the widget

Display name for the widget in the designer toolbar can be set through the displayName API.

Custom_widget toolbar

Format

displayName: “display name of the widget in designer toolbar”

Example

displayName: “Sunburst Chart”

Rules

  • It is not a mandatory field for the custom widget.
  • It can contain special character and wide spaces.

Setting category for the widget

This allows you to specify the category in which widget should be displayed.

Custom_widget category

Format

category: “name of the category in which the widget should be displayed”

Example

category: “Relationship”

Rules

  • It is not a mandatory field for the custom widget.

Setting description for the widget

You can describe the widget. The following message will be shown on hovering the widget icon in the expander toolbox of the designer.

Custom_widget description

Format

description: “description about the widget”

Example

description: “Sunburst Chart is used to visualize the hierarchical data. The center circle represents the root level of the hierarchy and outer circles represents higher levels of the hierarchy.”

Rules

  • It is not a mandatory field for the custom widget.

Setting source file location

Source file location should be specified here. Refer the use of source file in its module.

Format

srcFile: “location of the source file”

Example

srcFile: src/sunburst.js

Rules

  • It is a mandatory field for the widget.

Setting GUID for the widget

GUID is used to set unique identification for the custom widget, and it can be set through the guid API.

Format

guid: “used for unique identify the widget”

Example

guid: “74926583-8493-3333-6382-863428678492”

Rules:

  • It is a mandatory API for the widget.
  • Should satisfy the GUID format.

Setting dependency files for the widget

Dependency script and CSS files, which have to be referred for the widget, and should be specified in the dependencies section.

Format

"dependencies": {
    "scripts": [
      "src/dependency1.js",
      "src/ dependency2.js",..
    ],
    "styles": [
      "style/ dependency1.css",
      " style / dependency2.css",..
    ]
  }

Example

"dependencies": {
    "scripts": [
      "src/ej.sunburstchart.js",
      "src/ej.helper.js"
    ],
    "styles": [
      "style/ej.sunburstchart.css"
    ]
  }

Rules

  • It is not the mandatory API for the widget.
  • Files should be specified in the reference order.

Limitation

jQuery reference (jquery-1.10.2.min.js) will be added as built-in reference for the custom widget, So that you are not allowed to specify the jQuery files in dependencies.

Specifying data fields

This allows you to specify the data fields with its type for custom widgets. There are three types of data fields are available. It is listed as follows.

Measure data field

In the measure data field, numeric value column can be configured.

Dimension data field

In the dimension data field string, boolean and date value column can be configured.

Dimensionormeasure data field

In the dimensionormeasure data field, we can configure both the measure and dimension value column. In this data field the default summary type for measure value column is none.

dataFields:[
{
"displayName" : "display name of the data field1",
"valueType" : "type of the data field1, can be measure, dimension or dimensionormeasure",
"name" :  "name of the data field1",
"min" : "minimum number of block which has to be dropped for the datafield1",
"max" : "maximum number of block can be dropped for the datafield2",
"optional" : "specify whether it is mandatory data field"
},
{
"displayName" : " display name of the data field2",
"valueType" :" type of the data field2, can be measure, dimension or dimensionormeasure" ,
"name" : " name of the data field2",
"min" : "minimum number of block which has to be dropped for the datafield2",
"max": "maximum number of block can be dropped for the datafield2",
"optional" : "specify whether it is mandatory data field"
}
]

Example

dataFields:[
{
"displayName" : "Value",
"valueType" : "measure",
"name" :  "Value",
"min" : 1,
"max" : 1,
"optional" :false
},
{
"displayName" : "Levels",
"valueType" : "dimension",
"name" : "Levels",
"min" : 1,
"max":4,
"optional" : false
}]

Importing widget in designer

Place the custom widgets folder with in the location "C:\Bold BI\Dashboard Designer\CustomWidgets" after installing Bold BI Enterprise build as like in below image to get displayed in the Dashboard Designer after the browser refresh.

Custom_widget category

Debugging the widget through Designer

You can debug the custom widget by dragging and dropping it in the design canvas after placing ‘debugger’ in src/sourcefile.js. Now you debug the widget in following cases:

Init method

Widget can initialized through the init method, will be called initially when the widget is drag and dropped in design canvas with all the widget configuration details without data.

Update method

Once your widget is initialized through the init method, update method will called for widget updation like data update, widget resizing etc.

Rendering widget through the source file

Source file is used to embed the user defined widget within the dashboard. Refer the below API available in the source file.

Format

ej.dashboard.registerWidget(
{
		
	guid : `Specifies the GUID used in widgetconfig.json`, 
 
	widgetName : `Specifies the name of the widget used in widgetconfig.json`,
 
	init : function () {
 	/* init method will be called when the widget is initialized. */
	},
 
	update : function (option) {
		update method will be called when any update needs to be performed in the widget. */
		if (option.type == "resize") {
 		/* update type will be 'resize' if the widget is being resized. */
		}
		else if (option.type == "refresh") {
 		/* update type will be 'refresh' when the data is refreshed. */
		}
	}
});

Example

ej.dashboard.registerWidget(
         {
 
guid : "b0d5348d-f625-4b78-8db9-c5ed9d38eb45",
 
widgetName : "SunburstChart",
 
init : function () {
var widget =  document.createElement("div").setAttribute("id", this.element.getAttribute("id") + "_widget");
widget.innerHTML = "Widget is created successfully";
this.element.appendChild(widget);
},
 
update : function (option) {

var widget = document.getElementById(this.element.getAttribute("id") + "_widget");
if(option.type == "resize") {
 widget.innerHtml = "Widget is resized."
}
else if (option.type == "refresh") {
 	widget.innerHtml = "Widget data need to be refreshed."
}
}
   }
);

The following information will be available in this scope.

Syntax Uses
this.element this.element Container div element in which the custom widget should be embedded.
this.model.dataSource Holds the datasource for the custom widget in JSON format
this.model.boundColumns
this.model.boundColumns.datafield[columnIndex].columnName this.model.boundColumns.datafield[columnIndex].uniqueColumnName
Holds the information about the bounded column to the control.
  • columnName denotes the actual column name in the data source.
  • uniqueColumnName should be used at the time of interaction.

Samples

Adding Syncfusion ejSunburstChart as custom widget

  • Follow the below steps to add the Sunburst Chart as custom widget for the dashboard.

Step 1: Download the below attached custom widget template for developing.

Custom Widget Template : Template

Step 2: Configure the widget through the widgetconfig.json file.

description - You can provide the Description about the Sunburst chart.

srcFile - Path of the source file which is required for the Sunburst Chart.

dependencies - Dependency script and CSS files should be specified in the dependencies section.

ej.sunburstchart.js dependency file can be downloaded from this link.

"description": "Sunburst Chart is useful for visualizing hierarchical data.",
    "srcFile": "src/sunburst.js",
    "dependencies": {"scripts": [ "src/ej.sunburstchart.js"] },
  • As Sunburst Chart requires two data fields, so we have configured Values and Levels as shown below.
"dataFields": [
        {
            "displayName": "Value",
            "valueType": "measure",
            "name": "Value",
            "min": 1,
            "max": 1,
            "optional": false
        },
        {
            "displayName": "Levels",
            "valueType": "dimension",
            "name": "Levels",
            "min": 1,
            "max": 4,
            "optional": false
        }
    ],
  • After configuring the widgets, place the custom widget folder into C:\Bold BI\Dashboard Designer\CustomWidgets

Custom_widget category

  • Then, configure the widget with the necessary data.

Custom_widget category

  • Place the debugger in SunburstChart/src/sunburst.js, and then you can start rendering sunburst through the init method in the source file.

Custom_widget category

  • this.element is the container(div) provided to render the actual widget.

  • So, we are creating our sunburst chart in this.element by using the data in this.model.datasource .

  • In renderSunburstChartWidthDefaultData(), We are creating a new space (div) for rendering our sunburst chart custom widget with default data and appending into the container as you can see in the below code.

renderSunburstChartWidthDefaultData : function () {
			this.widget = document.createElement("div");
			this.widget.setAttribute("id", this.element.getAttribute("id") + "_widget");
			this.element.appendChild(this.widget);
  • The width and height of the widget is assigned from the container’s width and height respectively.
* $(this.widget).css({"width":$(this.element).width(), "height":$(this.element).height()});
  • Configure the datasource with some default values for initial rendering of Sunburst Chart. groupMemberPath and levels are the API’s of ejSunburstChart where we have to configure the uniqueColumnName of the columns that we bind in the levels section.
var dataSource = [{ Item: "Item1", Value: 50 },{ Item: "Item2", Value: 60 },{ Item: "Item3", Value: 70 },{ Item: "Item4", Value: 80 },{ Item: "Item5", Value: 90 },{ Item: "Item6", Value: 90 },{ Item: "Item7", Value: 90 },{ Item: "Item8", Value: 90 },{ Item: "Item9", Value: 90 },{ Item: "Item10", Value: 90 },{ Item: "Item11", Value: 90 }];
			var levels = [];
			var valueMember = "Value";
			levels = [ { groupMemberPath: "Item" }];
  • Sunburst chart is rendered by configuring the required API’S and assign the values
$(this.widget).ejSunburstChart({ dataSource: dataSource, 
							valueMemberPath: valueMember, levels: levels, 
							tooltip: { visible: true},
							margin: (this.marginVisibility())? { left: 10, top: 10, bottom: 10, right: 10} :{ left: 0, top: 0, bottom: 0, right: 0} ,
							border: { width: (this.marginVisibility())? 2:0 },
							load: $.proxy(this.sunburstChartLoad),
							enableAnimation: false,
							animationType: 'Rotation',
							innerRadius: 0.2,							
							dataLabelSettings:{visible:false},
							size: { height: $(this.element).height(), width: $(this.element).width()},	 
							legend: { visible:  (this.legendVisibility()) , position: this.legendPosition() },
							highlightSettings: {enable: true},
							selectionSettings: {enable: true, mode : "parent"}
							});	
  • Update method will be triggered for below operations,so here we are performing the operations based on the update type(resize, refresh) by invoking the respective API of the widget.

    1. Resize

    2. Refresh

update : function (option) {
			if(option.type == "resize") {
				this.resizeWidget(option.size);
			}
			else if (option.type == "refresh") {
				var widgetObj = $(this.widget).data("ejSunburstChart");	
				if(this.model.boundColumns.Value.length > 0){
					for (var i=0; i<this.model.dataSource.length; i++) {
						this.model.dataSource[i][this.model.boundColumns.Value[0].uniqueColumnName] =  parseInt( this.model.dataSource[i][this.model.boundColumns.Value[0].uniqueColumnName]);     	
					}
					var valueMember = this.model.boundColumns.Value[0].uniqueColumnName;
					if (this.model.boundColumns.Levels.length > 0) {
						var levels = [];				
						for (var level = 0; level < this.model.boundColumns.Levels.length; level++) {
							levels.push({ groupMemberPath : this.model.boundColumns.Levels[level].uniqueColumnName });
						}
						widgetObj.model.levels= levels;
					}
					widgetObj.model.dataSource = this.model.dataSource;
					widgetObj.model.valueMemberPath = valueMember;
					widgetObj.redraw();
				} else {
					this.renderSunburstChartWithDefaultData();
				}
			}			
}
  • For ejSunburstChart related API references, refer the link.

  • Sunburst widget will be rendered as follows:

Custom_widget category

Configuring custom widget for interaction

The custom widget can take part in the filter interaction like built-in widgets. Use the following API’s to perform the communication between the widgets.

Format

var selectedColumnsFilter = [];
var filterColumn = new ej.dashboard.selectedColumnInfo();
filterColumn.condition = "condition";
filterColumn.uniqueColumnName = "unique column name";
filterColumn.values =["value1", "value2", "value3"] ;
selectedColumnsFilter.push(filterColumn);
ej.dashboard.filterData(this, selectedColumnsFilter); /* selectedColumnsFilter is the list of selected column and its value send from custom widget for interaction. */

Various types of column

  • Dimension type column

Values in the dimension column will be a string, date format, or boolean format.

  • Measure type column

Values in the measure column will be in number format.

Dimension type column

Various conditions are available for the dimension column other than the DateTime data type:

  • include
  • exclude
  • startswith
  • endswith
  • contains

Example

The following code will filter the dimension value “India” and “China” in the other widgets

var selectedFilterInfos = [];
var filterinfo = new ej.dashboard.selectedColumnInfo();
filterinfo.condition = "include";
filterinfo.values = ["india","china"];
filterColumn.uniqueColumnName = "unique column name";
selectedFilterInfos.push(filterinfo);
ej.dashboard.filterData(that, selectedFilterInfos);

NOTE: In the above code sample, pass the unique column name of a particular column from the variable this.model.boundColumns to filter the data in the other widgets. In this variable all the bounded or configured data fields will be available with their bounded value column name and unique column name.

Various conditions are available for the dimension column with the DateTime data type:

  • range
  • include
  • exclude

The following code is the example to filter the data of the specified date range in the other widgets.

var selectedFilterInfos = [];
var filterinfo = new ej.dashboard.selectedColumnInfo();
filterinfo.condition = "range";
filterinfo.values =["1996", "1998"] ;
filterinfo.uniqueColumnName = "unique column name";
selectedFilterInfos.push(filterinfo);
ej.dashboard.filterData(this, selectedFilterInfos); 

Measure type column

To apply the filter based on the measure, the value type should be dimensionormeasure for data field and summary type of the measure should be set as none. Various condition types are available for measure type column as follows:

  • equals
  • notequals
  • lessthan
  • greaterthan
  • lessthanorequals
  • greaterthanorequals
  • isbetween
  • isnotbetween

The following code is the example to filter the other widgets based on the measure value.

var selectedFilterInfos = [];
var filterinfo = new ej.dashboard.selectedColumnInfo();
filterinfo.condition = "greaterthan";
filterinfo.uniqueColumnName = this.model.boundColumns.Value[0].uniqueColumnName;
filterinfo.values =[100] ;
selectedFilterInfos.push(filterinfo);
ej.dashboard.filterData(this, selectedFilterInfos); 

The following code is the example to filter the value between 10248 and 10251 in the other widgets.

var selectedFilterInfos = [];
var filterinfo = new ej.dashboard.selectedColumnInfo();
filterinfo.condition = "isbetween";
filterinfo.uniqueColumnName = "unique column name";
filterinfo.values =[10248,10251] ;
selectedFilterInfos.push(filterinfo);
ej.dashboard.filterData(this, selectedFilterInfos); 

Adding C3 chart as a custom widget

Here we are creating a C3 Chart using the D3 Library.

Note: The C3 Chart is open-source and it is under MIT license.

Follow these steps to add the third party widget(C3 Chart) as a custom widget for the dashboard.

  • Refer to this link to create a new custom widget files.

Custom_widget C3 chart

  • Configure the widget using the widgetconfig.json file.

  • As a C3 Chart requires two data fields, we have configured column and values as shown below and the properties section contains the properties related to the C3 Chart. Refer to this link for configuring the widgetconfig.json.

    "widgetName": "C3Chart",
    "displayName": "C3 Chart",
    "guid": "b0d5348d-f625-4b78-8db9-c5ed9d38eb45",
    "category": "Comparison",
    "description": "Compare values for a set of unordered items across categories",
    "srcFile": "src/sourcefile.js",
    "dependencies": {
	"scripts": [ 
	     "src/d3.js",
	     "src/c3.js"
		 ] 
		 },
    "dataFields": [
        {
            "displayName": "Value",
            "valueType": "measure",
            "name": "Value",
            "min": 1,
            "max": 1,
            "optional": false
        },
        {
            "displayName": "Column",
            "valueType": "dimension",
            "name": "Column",
            "min": 1,
            "max": 1,
            "optional": false
        }
    ],
    "functionalities": [
        {
            "header": "Basic Settings",
            "properties": [
                {
                    "displayName": "Show Tooltip",
                    "controlType": "bool",
                    "name": "showTooltip",
                    "defaultValue": "true"
                },
				{
                    "displayName": "Show Label",
                    "controlType": "bool",
                    "name": "showLabel",
                    "defaultValue": "true"
                },
                {
                    "displayName": "Color",
                    "controlType": "color",
                    "name": "barColor",
                    "defaultValue": "#2196F3"
                }
            ]
        },
      ],
    "filterSettings": {
        "masterFilter": {
            "visible": true,
            "defaultValue": true

        },
        "ignoreMasterFilter": {
            "visible": true,
            "defaultValue": false
        }
    }
  • The d3.js dependency file can be downloaded from the D3 website.

  • The c3.js dependency file can be downloaded from the C3 website.

  • import the custom widget into the designer.

  • Then, configure the widget with the necessary data.

Custom_widget C3 chart

  • You can debug the custom widget by dragging and dropping it into the design canvas after placing the ‘debugger’ in src/sourcefile.js.

  • this.element is the container(div) provided to render our actual widget.

  • So, we are creating our C3 Chart in this.element by using the data in this.model.dataSource.

  • In Init(), We are creating a new space (div) for rendering our C3 Chart custom widget and appending into the container as you can see in the following code.

  • The width and height of the widget are assigned from the container’s width and height respectively.

     init: function () { /* init method will be called when the widget is initialized */
	 this.widget = document.createElement("div");
	 this.widget.setAttribute('id', 'chart');
	 var width = document.getElementById('container').style.width;
	 var height = document.getElementById('container').style.height;
	 this.element.appendChild(this.widget);
	 var that = this;
  • Configure the datasource with some default values for initial rendering of C3 Chart.
	var columns =[];
	columns =[{column:'Item1',values: '50'},{column:'Item2',values: '20'},{column:'Item3',values: '30'}];
  • this.model.boundColumns.Value and this.model.boundColumns.length contains the columns bounded in the columns and values respectively. By checking the following condition, we can find whether the widget is configured with columns or not.

  • Converting the datasource structure required by C3 Chart.

    if (this.model.boundColumns.Value.length > zero) {
     for (var i = 0; i < this.model.dataSource.length; i++) {
	  columns.push({column: this.model.dataSource[i][this.model.boundColumns.Column[0].uniqueColumnName], values: this.model.dataSource[i][this.model.boundColumns.Value[0].uniqueColumnName]});
			}
  • To render the C3 Chart, configure the required API’s and assign the data to it.
    var chart = c3.generate({
		data:
		{
		  type: 'bar',
		  json: columns,
		  keys:
			{
			 x: 'column',
			 value: ['values']
			},
			labels: true,
			selection:
			{
			 enabled: true,
			 multiple: false,
			 draggable: true
			},
			onclick: function(d) {
								that.selectionChange(d)
							},
		},
		axis: 
		{
		 x:
		  {
		   type: 'category'
		  }
		},
		grid:
		{
		   x: {show: false},
		   y: {show: true}
		},
		bar:
	      {
		  width:
		   { 
			ratio: 0.5
		   }
	      },
		interaction: {enabled: true}
	   });
	this.widget = chart;
  • The C3 Chart widget will be rendered as follows:

Custom widget C3 chart

  • Update method will be triggered for the following operations and we have to do the required changes by checking the update types(resize, refresh, and propertyChange), and the widget will be updated accordingly by invoking the respective API of the widget.

    1. Resize

    2. Refresh

    3. property change

    update: function (option) {
        var widget = this.widget;

        /* update method will be called when any update needs to be performed in the widget. */

        if (option.type == "resize") {
            /* update type will be 'resize' if the widget is being resized. */
			widget.resize(option.size);
        }
        else if (option.type == "refresh") {
            /* update type will be 'refresh' when the data is refreshed. */
			this.refreshChart();
        }
        else if (option.type == "propertyChange") {
            /* update type will be 'propertyChange' when any property value is changed in the designer. */

            switch (option.property.name) {
                case "showTooltip":
                    widget.internal.config.tooltip_show = option.property.value;
                    break;
                case "showLabel":
                    widget.internal.config.data_labels = option.property.value;
					widget.flush();
                    break;
                case "barColor":
                    widget.internal.config.data_colors.values = option.property.value;
					widget.flush();
                    break;
                }
        }
    }
    refreshChart : function (e) {
		var columns =[];
		if (this.model.boundColumns.Value.length > 0)
		{
			for( var i=0; i< this.model.dataSource.length; i++)
			 {
			  columns.push({column:this.model.dataSource[i][this.model.boundColumns.Column[0].uniqueColumnName],values:this.model.dataSource[i][this.model.boundColumns.Value[0].uniqueColumnName]});
			 }
	    } else {
				columns =[{column:'A',values: '50'},{column:'B',values: '20'},{column:'C',values: '30'}];
			   }
	    var chart = c3.generate({
                    data: {                
                         type : 'bar',
                         json: columns,
                         keys: {
						      x: 'column',
						      value: ['values']
						       },
						 labels:this.model.properties.show label,
		                 selection:
						 {
                         enabled: true,
						 multiple: false,
						 draggable:true
						 },
						 onclick: function(d) {
								that.selectionChange(d)
							},
						 },
			        axis:
						 { 
						    x: {
                            type: 'category'
						       }
						 },
				    grid:
						 {
							 x:{ show : true},
							 y:{show: false}
						 },						 
					bar: 
						 { 
						  width: { ratio: 0.5 }
						 },
                    interaction: {enabled: true}
					}); 
                this.widget = chart;
				},