Syncfusion Custom Widget Authoring

Overview

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.

You can download the Syncfusion controls source files from the following links

To learn more about the custom widget creation, refer the video link.

Prerequisites and knowledge required for handling the custom widget authoring

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

Development Environment Dashboard Designer and any web browser as mentioned in the

link


Knowledge Required Basic knowledge about the HTML and JavaScript

Syncfusion ships the following custom widgets along with the Syncfusion Dashboard Designer.

And these custom widgets are available in the below location also.

Location: C:\ProgramData\Syncfusion\DashboardDesigner\Custom Widgets

Creating new widget

Syncfusion Custom Widget Utility (sycw.exe) is used to create and manage the custom widget and it will be shipped along with the Dashboard Designer setup installation in the following location.

Location: [Local drive installation location]\ Syncfusion\Dashboard Designer\DashboardDesigner\sycw.exe

Custom Widget path

Create command is used to create the widget in the specified path with provided name along with its unique GUID.

Format

create [widget creation path]

Example

create e:\widgets\sunburstchart

Custom widget created

After the create command execution, you can see the widget named folder that is created as below:

Custom widget folder

Rules

  • If you need to modify the widget name, display name, or GUID, it should be modified in both the widget configuration file(widgetconfig.json) and the source file(sourcefile.js) without mismatching. But modifying the GUID is not recommended.

Configuring widget using manifest file

After creating the widget, 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 sunburst folder structure

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

  • JS
  • {
    	"widgetName" : "Name of the widget.",
    
    	"displayName" : "Display name of the widget to be displayed in designer toolbox.",
    	
    	"enableIFrame" : "Used to render the widget within IFrame tag",
    
    	"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. ",
    
                 "functionalities" : " Custom properties for the widget can be specified through the
                                                   functionalities API. ",
    
    	"filterSettings": "Filter settings are used to configure whether the widget can take
                                               part in filter interactions between the widgets.",
    
    	"enableLinking": "Used to enable or disable the linking support for the widget",
    
    	"linkSettings": "Used to configure linking related settings for the widget"
    }

    This file contains the data necessary for the designer to import the custom widget and serialize the custom widget into *.sydx package while publishing the dashboard.

    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 sunburst

    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 IFrame for the widget

    Enable IFrame is used to specify whether the custom widget should be render within the IFrame tag or directly within the DashboardViewer. This support is used to resolve Scripts and CSS conflicts that occurs between the DashboardViewer and the custom widget. Currently exporting to image and PDF options are not provided for IFrame widgets.

    Format

    enableIFrame: “IFrame can be enabled or disabled for the widget”

    Example

    enableIFrame: “true”

    Rules

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

    Setting category for the widget

    This allows you to specify the category in which widget should be displayed. If the specified category name is not exist, then a new category will be created on the provided name and the widget will be added under the new category.

    If the name of the category is not provided for the widget, then it will be added under the miscellaneous category (default category).

    Custom_widget sunburst

    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.

    API version

    Version is used to denote the current API version of the created widget and this value should not be modified.

    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

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

    Example

  • JS
  • "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 when the IFrame is disabled, So that you are not allowed to specify the jQuery files in dependencies. If you want to add any specific version of jQuery, then you should enable the IFrame for the custom widget. For more information refer the link.

    Specifying data fields

    This allows you to specify the data fields with its type for custom widgets.

  • JS
  • dataFields:[
    {
    "displayName" : "display name of the data field1",
    "valueType" : "type of the data field1, can be measure or dimension",
    "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 or dimension",
    "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

  • JS
  • 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
    }]

    Rules

    • It is not the mandatory API for the widget.

    Custom_widget schema

    Adding functionalities

    Custom properties for the widget can be set and specified through the functionalities API.

    Format

  • JS
  • "functionalities": [
    		{
    			"header": "name of the header",
    			"properties": [
    				{
    					"displayName": "display name of the properties",
    					"controlType": "type of control to be created in 
    properties window under this group",
    					"name": "name of property",
    					"defaultValue": "default value of the property",
    					"listItems": "list of items if the control type have list."
    				},
    				{
    					"displayName": " display name of the properties ",
    					"controlType": " type of control to be created in
    properties window under this group ",
    					"name": " name of property ",
    					"defaultValue": " default value of the property "
    				}
    				………
    				………	  
    			]
    		},
    {
    			"header": "name of the header",
    			"properties": [
    				{
    					"displayName": "display name of the properties",
    					"controlType": "type of control to be created in 
    properties window under this group",
    					"name": "name of property",
    					"defaultValue": "default value of the property",
    					"listItems": "list of items if the control type have list."
    				},
    				{
    					"displayName": " display name of the properties ",
    					"controlType": " type of control to be created in
    properties window under this group ",
    					"name": " name of property ",
                        			"defaultValue": " default value of the property "
    				}
    				………
    				………	  
    			]
    		}
    		……..
    		……..
    	]

    Various control type sample

    • Checkbox

    Custom_widget checkbox

    Format

  • JS
  • {
    	"displayName": "display name for the checkbox",
    	"controlType": "checkbox",
    	"name": "name of the property",
    	"defaultValue": "either true or false"

    Example

  • JS
  • {
    	"displayName": "Enable Animation",
    	"controlType": "checkbox",
    	"name": "enableAnimation",
    	"defaultValue": "true"
    }
    • Textbox

    Custom_widget Textbox

    Format

  • JS
  • {
    	"displayName": " display name for the textbox ",
    	"controlType": "textbox",
    	"name": "name of property",
    	"defaultValue": "default text to be displayed in the textbox"
    }

    Example

  • JS
  • {
    	"displayName": "Control Text",
    	"controlType": "textbox",
    	"name": " subtitle ",
    	"defaultValue": "My first widget"
    }
    • Combobox

    Custom_widget Combobox

    Format

  • JS
  • {
       "displayName": "display name of the property",
       "controlType": "combobox",
       "name": "name of property",
       "listItems": ["listitem1"," listitem2"],
       "defaultValue": " listitem2"
    }

    Example

  • JS
  • {
    	"displayName": "Legend Position",
    	"controlType": "combobox",
    	"name": "legendPosition",
        "listItems": ["top", "bottom", "left", "right"],
    	"defaultValue": "left"
    }
    • ColorPicker

    Custom_widget color picker

    Format

  • JS
  • {
    	"displayName": "display name of the property ",
    	"controlType": "colorpicker",
    	"name": "name of property",
    	"defaultValue": "default color code"
    }

    Example

  • JS
  • {
    	"displayName": "label Color",
    	"controlType": "colorpicker",
    	"name": "labelColor",
    	"defaultValue": "#463859"
    }
    • Updown

    Custom_widget updown

    Format

  • JS
  • {
    	"displayName": " display name of the property ",
    	"controlType": "updown",
    	"name": " name of property ",
    	"defaultValue": "10",					
        "min" : "minimum value can be set",
    	"max" : "maximum value can be set"
    }

    Example

  • JS
  • {
    	"displayName": "Text Size",
    	"controlType": " updown ",
    	"name": "textSize",
    	"defaultValue": "10",					
        "min" : "1",
    	"max" : "50"
    }

    Filter settings

    If the widget should take part in filter interactions that occur between the widgets, then the filter settings can be used.

    Format

  • JS
  • "filterSettings": {
    		"masterFilter": {
    			"visible": "boolean value to specify whether can be act as master ",
    			"defaultValue": " boolean value to specify whether widget is master by default"
    		},
    		"ignoreMasterFilter": {
    			"visible": " boolean value to specify whether can be updated on 
           interaction from other widgets",
    			"defaultValue": " boolean value to specify whether widget ignore master 
          action by default "
    		}
    	}

    Example

  • JS
  • "filterSettings": {
    		"masterFilter": {
    			"visible": "true",
    			"defaultValue": "true"
    		},
    		"ignoreMasterFilter": {
    			"visible": "true",
    			"defaultValue": "false"
    		}
    	}

    Rules:

    • It is not a mandatory field for the widget.

    To configure Linking for the widget

    If the widget need to configured with navigation support, then linking can be used.

    Format

    enableLinking: “Linking can be enabled or disabled for the widget”

    Example

    enableLinking: “true”

    Custom_widget linking

    Rules

    It is not a mandatory field for custom widget

    If you need to configure each bounded column with unique links, then enableTabularUrlLinking of linkSettings can be used.

    Format

  • JS
  • "linkSettings": {
    		enableTabularUrlLinking: "tabular url linking can be enabled or disabled"
     }

    Example

  • JS
  • "linkSettings": {
    	 enableTabularUrlLinking: "true"
     }

    Custom_widget tabular linking

    Custom_widget Url settings

    Rules

    • It is not a mandatory field for custom widget.

    Packing the widget

    After configuring the widget, you can pack the widget by using pack comments.

    To import the custom widget in the dashboard designer, you should pack the widget in the .sycw format. The pack command is used to pack the widget which can be imported.

    Format

    pack [path of the widget to be packed]

    Example

    Specify the root path of the widget to be packed in the pack command.

    Custom_widget

    SunburstChart.sycw file will be created in the output folder as below:

    Custom_widget Sunburst chart

    Rules

    • If you need to modify the widget, you can modify the widget and import it again in the dashboard designer to reflect the changes.

    Unpacking the widget

    To modify or to reconfigure the custom widget, you should unpack the custom widget which is in the .sycw format.

    Steps to unpack the custom widget

    1. Rename the extension of the provided ‘.sycw’ into ‘.zip’ extension as shown in the below image.

    Renaming the extension

    1. Now right click on the renamed widget as in the image. Click ‘Extract All’ to view the source file.

    Opening the zip file

    1. You can find the unpacked Organization chart custom widget and it’s source file as in the below image.

    Viewing the source

    Rules

    • If you need to modify the widget, you can modify the widget and import it again in the dashboard designer to reflect the changes.

    Importing widget in designer

    From the ‘Widget’ menu in the designer, select ‘Manage Custom Widgets’ to import, rename, and delete the widgets. You can import the custom widget file with the extension *.sycw through the add widget option.

    Custom_widget Import

    Custom_widget Import

    Debug the widget through HTML file

    After importing the custom widget in the designer, you can debug the widget in following cases:

    • At initial rendering through the init method.
    • Updation request through update method.

    Render initially through the init method

    Custom_widget init method

    Update widget through update method

    Update request for the widget will be triggered in the following cases.

    • On widget container resizing.

    Custom_widget resize

    • On datasource update

    Custom_widget update

    • On property change

    Custom_widget change

    After initial rendering of the widget, you can debug the property through the browser. Use the following steps for debugging:

    • Drag and drop the imported widget in the designer canvas, after this HTML file will be created at the location %appdata%\Syncfusion\DashboardDesigner\versionnumber\Html[custom widget report_id].html

    • Run the custom widget HTML file.

    • Change the needed property like in the below specified format.

    • You can debug the changed property in the custom widget source file.

    Format

  • JS
  • ej.dashboard.setProperty(document.getElementById("container"),{ "name": "name of the property to be changed", "value": "value of the property" });

    document.getElementById(“container”) – widget container element.

    name - name of the property specified in the widgetconfig.json under functionalities properties.

    value – depends on the control type specified in the widgetconfig.json under functionalities properties.

    Custom_widget Sunburst functions

    Example

  • JS
  • ej.dashboard.setProperty (document.getElementById("container"),{ name: showTitle, value: true});

    Custom_widget show title

    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

  • JS
  • 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. */
    		}
    		else if (option.type == "propertyChange") {
     		update type will be 'propertyChange' when any property value is changed in the designer. */
    		}
    	}
    });

    Example

  • JS
  • 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."
    }
    else if (option.type == "propertyChange") {
     	widget.innerHtml = "Widget property have been changed."
    }
    }
       }
    );

    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 this.model.boundColumns.datafield[columnIndex].dataType this.model.boundColumns.datafield[columnIndex].valueType this.model.boundColumns.datafield[columnIndex].dateTimeFormat this.model.boundColumns.datafield[columnIndex].dateTimeComponent this.model.boundColumns.datafield[columnIndex].culture this.model.boundColumns.datafield[columnIndex].currencyCode this.model.boundColumns.datafield[columnIndex].decimalPoints this.model.boundColumns.datafield[columnIndex].decimalSeparator this.model.boundColumns.datafield[columnIndex].groupSeparator this.model.boundColumns.datafield[columnIndex].measureType this.model.boundColumns.datafield[columnIndex].negativeValueFormat this.model.boundColumns.datafield[columnIndex].prefix this.model.boundColumns.datafield[columnIndex].suffix this.model.boundColumns.datafield[columnIndex].summaryType this.model.boundColumns.datafield[columnIndex].unit
    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.
    • dataType of the column.
    • dateTimeFormat holds the datetime format like dd/mm/yyyy etc.
    • dateTimeComponent like date, datetime, quarter etc.
    • culture holds the culture value chosen in the formatting window.
    • currencyCode holds the currency code value for the culture chosen in the formatting window.
    • decimalPoints holds the number of decimal points value chosen in the formatting window.
    • decimalSeparator holds the decimal symbol value chosen in the formatting window.
    • groupSeparator holds the grouping symbol value chosen in the formatting window.
    • measureType holds the measure type value chosen in the formatting window.
    • negativeValueFormat holds the negative value format chosen in the formatting window.
    • prefix holds the prefix value chosen in the formatting window.
    • suffix holds the suffix value chosen in the formatting window.
    • summaryType holds the summaryType value chosen in the formatting window.
    • unit holds the unit value chosen in the formatting window.
    this.model.properties Holds the properties window properties.
    this.model.baseURL this.model.baseURL Holds the base url of custom widget package, used to fetch the asserts (images etc..) in the custom widget folder..
    this.model.initMode this.model.initMode Value will be set according to the rendering mode. (designtime - when rendering in designer, runtime -when render in viewer, export – When the widget rendered for export.)
    this.model.isDataBound this.model.isDataBound Boolean value will be set as true when the widget satisfies the Min Max condition in data fields.

    Rules:

    • Widget API’s should be in JSON format and need to pass as parameter for ej.dashboard.registerWidget method.
    • The following are the mandatory API’s (guid, widgetName, init, update) for the custom widget.

    Formatting widget data

    The custom widget data can be formatted as like built-in widgets.

    Measure Format

    Click on the Settings icon and then select Format option to format the measure values.

    Custom_widget measure format

    Custom widget measure formatting window

    The values chosen in the formatting window will be stored in the respective column of this.model.boundColumns. Refer the above table for API reference.

    Measure value can be formatted in two ways.

    • formatNumberThroughSchema() - to format the value based on the options selected in the formatting window
    • formatNumber() - to format the value based on custom parameters.

    formatNumberThroughSchema()

    To invoke this method, instance for Internationalization() should be created with the selected culture.

  • JS
  • var instance = new ej.dashboard.Internationalization(this.model.boundColumns.columnName[index].culture);

    formatNumberThroughSchema() should be invoked using created instance with value to be formatted and the corresponding column information as a method parameter.

  • JS
  • instance.formatNumberThroughSchema(value, this.model.boundColumns.columnName[index]);

    It will return the formatted value based on the options selected in the measure formatting window.

    formatNumber()

    If we want to format the number with custom parameters then we can make use of formatNumber()

  • JS
  • instance.formatNumber(value,  {format:measureType, currency:currencyCode, unit:unitValue, decimal:decimalSeparatorValue, group:groupSeparatorValue,                         negative:negativeValueFormat, prefix:prefixValue, suffix:suffixValue});

    value - Number which we need to format.

    currencyCode: Specifies the currency code (used only when the format is set as currency)

    decimalSeparatorValue: Specifies the decimal separator.

    groupSeparatorValue: Specifies the group separator.

    measureType: Specifies the type of the measure like Number, Decimal, Percentage.

    Examples: “N0”, “C0”, “P0” where N, C, P represents Number, Currency and Percentage respectively and “0” represents the number of decimal points.

    negativeValueFormat: Specifies the negative value format.

    Examples: 0 -> -1234, 1 -> (1234) 2 -> 1234-

    prefixValue: Specifies the prefix value.

    suffixValue: Specifies the suffix value.

    unitValue: Specifies the representation of the value

    Possible values: “auto”, “ones”, “thousands”, “millions”, “billions” etc.

    Examples:

  • JS
  • var instance = new ej.dashboard.Internationalization("en-US");
    instance.formatNumber(123456,  {format:"N2", unit:"ones", decimal:"&", group:" ", negative:0, prefix:"s", suffix:"Unit(s)"});
    
    // this will return "s123 456&00Unit(s)"
    
    instance.formatNumber(123456,  {format:"C2", currency:"USD", unit:"ones", decimal:"&", group:" ", negative:0});
    
    // this will return "$123 456&00"
    
    instance.formatNumber(123456,  {format:"P2", unit:"ones", decimal:"&", group:" ", negative:0});
    "
    // this will return "12 345 600&00%"

    Date Formats

    Click on the Settings icon and select Settings option to format the date values

    Custom_widget date settings

    Custom_widget date settings

    The values chosen in the formatting window will be stored in the respective column of this.model.boundColumns. Refer the above table for API reference.

    Date values can be formatted in two ways.

    • formatDateThroughSchema() - to format the date value based on the options selected in the date settings window
    • formatDate() - to format the date value value based on custom format.

    formatDateThroughSchema()

    To invoke this method, instance for Internationalization() should be created.

  • JS
  • var instance = new ej.dashboard.Internationalization();

    formatDateThroughSchema() should be invoked using created instance with value to be formatted and the corresponding column information as a method parameter.

  • JS
  • instance.formatDateThroughSchema(dateValue.toString(), this.model.boundColumns.columnName[index]);

    It will return the formatted date value with the based on option selected in the date settings window.

    formatDate()

    In case if we format the date with a custom format then we can make use of formatDate()

  • JS
  • instance.formatDate(dateObj,{format:dateFormat});

    Examples:

  • JS
  • var date = new Date();
    date.setYear(2016);
    instance.formatDate(date,{format:"yy"});
    
    // this will return "16"
    
    date.setMonth(2);
    instance.formatDate(date,{format:"MMMM"});
    
    // this will return "March"
    
    date.setDate(27);
    this.formatDate(date,{format:"dddd"});
    
    // this will return "Tuesday"

    Configuring widget for interaction

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

    Format

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

    Various types of column

    • Dimension type column

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

    • Measure type column

    Values in the measure column will be in number format.

    Date type of column

    Data type of a bounded column can be obtained through the below API.

    Format

  • JS
  • this.element.boundColumns.[data field name][index].dateType

    Example

  • JS
  • this.element.boundColumns.Levels.[0].dateType

    Dimension type column

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

    • include
    • exclude
    • startswith
    • endswith
    • contains
    • equal
    • notequal

    Example

    The below highlighted code will return the values which starts with ‘i’.

  • JS
  • var selectedFilterInfos = [];
    var filterinfo = new ej.dashboard.selectedColumnInfo();
    filterinfo.condition = "startswith";
    filterinfo.values = ["i"];
    filterColumn.uniqueColumnName = "unique column name";
    selectedFilterInfos.push(filterinfo);
    ej.dashboard.filterData(that, selectedFilterInfos);

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

    • range
    • include
    • exclude
    • relative

    NOTE

    If the widget has only one data field block and its limit is one, the Relative Dates will be enabled. Or else Relative Date Filter will be enabled in Dashboard Designer.

    Relative Dates:

    Custom_widget relative dates

    Relative Date Filter:

    Custom_widget relative date filter

    Example for dimension to filter the selected value.

  • JS
  • var selectedColumnsFilter = [];
    var filterColumn = new ej.dashboard.selectedColumnInfo();
    filterinfo.condition = "include";
    filterinfo.values =["india", "china"] ;
    selectedColumnsFilter.push(filterColumn);
    ej.dashboard.filterData(this, selectedColumnsFilter);

    Measure type column

    Various condition types for measure type

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

    Example for measure to specify the in-between condition.

  • JS
  • var selectedColumnsFilter = [];
    
    var filterColumn = new ej.dashboard.selectedColumnInfo();
    filterColumn.condition = "isbetween";
    filterColumn.uniqueColumnName = this.model.boundColumns.Value[0].uniqueColumnName;
    filterColumn.values =[12,100] ;
    selectedColumnsFilter.push(filterColumn);
    ej.dashboard.filterData(this, selectedColumnsFilter);

    Configuring widget for linking

    You can configure to navigate either to a published dashboard or to a general URL with or without parameters. For more information, Linking.

    Format

  • JS
  • // Following code should be implemented in sourcefile.js.
    
    ej.dashboard.navigateThroughLinking(this, selectedColumnsInfo); /* selectedColumnsInfo is the list of selected column queries send from custom widget for linking. */
    
    For more information about selectedColumnsInfo, Refer [FilterInteraction](#configuring-widget-for-interaction).

    Example

  • JS
  • var selectedColumnsFilter = [];
    var filterColumn = new ej.dashboard.selectedColumnInfo();
    filterinfo.condition = "include";
    filterinfo.values =["india", "china"] ;
    selectedColumnsFilter.push(filterColumn);
    ej.dashboard.navigateThroughLinking(this, selectedColumnsFilter);

    Configuring widget for tabular url linking

    By using tabular linking, we can configure unique links to each bounded columns of widget.

    Example

  • JS
  • /* Code to find the unique link configured with selected value
    and it should be implemented in sourcefile.js file*/
    
        if (this.model.linkSettings.enableTabularUrlLinking) {
    					for (var i = 0; i < this.model.linkSettings.urlPatterns.length; i++) { // urlPatterns contains bounded column details along with configured links.
    						if (this.model.linkSettings.urlPatterns[i].uniqueColumnName ===    selectedFilterInfos[0].uniqueColumnName ) {
    							configuredUrl = this.model.linkSettings.urlPatterns[i].urlLink;
    						}
    					}
    	}
        ej.dashboard.navigateThroughLinking(this,selectedFilterInfos,configuredUrl); /* configuredUrl is link configured to selected column in widget */

    Samples

    We have created the following custom widgets from Syncfusion controls. You can download the sample custom widgets from below links:

    Adding Syncfusion ejSunburstChart as custom widget

    Follow the below steps to add the sunburst chart as custom widget for the dashboard. You can download the actual widget from this link.

    • Refer the commands to create new custom widget files.

    Custom_widget Sunburst

    • 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.

  • JS
  • "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, we have configured values and levels as shown below and the properties section contains the properties related to the sunburst chart. Refer this link for configuring widgetconfig.json.
  • JS
  • "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
            }
        ],
    • ej.sunburstchart.js dependency file can be downloaded from this link.

    • Pack the widget and import it in the designer.

    • Then, configure the widget with the necessary data.

    Custom_widget Sunburst

    • Run the sunburstchart_xx.html (%appdata%\Syncfusion\DashboardDesigner\versionnumber\Html) generated in the location, and then you can start rendering sunburst through the init method in the source file.

    Custom_widget appdata

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

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

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

  • JS
  • renderSunburstChart : 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.
  • JS
  • $(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.
  • JS
  • 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" }];
    • this.model.boundColumns.value and this.model.boundColumns.length contains the columns bounded in the values and levels respectively. By checking the below condition, we can find whether the widget is configured with columns or not.

    • Using for loop, the groupMemberPath value for each levels is assigned.

  • JS
  • if (this.model.boundColumns.Value.length > 0 && this.model.boundColumns.Levels.length > 0) {
    				levels = [];
    				dataSource = this.model.dataSource;
    				valueMember = this.model.boundColumns.Value[0].uniqueColumnName;
    				for (var level = 0; level < this.model.boundColumns.Levels.length; level++) {
    					levels.push({ groupMemberPath : this.model.boundColumns.Levels[level].uniqueColumnName });
    				}
    			}
    • Properties for the custom widget will be available in this.model.properties. For example showLegend, titleText, animationType, etc.

    • sunburst chart is rendered by configuring the required API’S and assign the values from the this.model.properties

  • JS
  • $(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: (this.model.initMode === "export") ? false : this.model.properties.enableAnimation,
    							animationType: this.getAnimationType(this.model.properties.animationType),
    							innerRadius: 0.2,
    							title: { text:  this.model.properties.titleText , visible: this.model.properties.showTitle},
    							zoomSettings:{enable:this.model.properties.enablezoom, zoomOnClick: this.model.properties.enablezoom  },
    							dataLabelSettings:{visible:this.dataLabelVisibility(),labelRotationMode: this.getRotationMode(this.model.properties.dataLabelRotationMode), labelOverflowMode : "hide", font: { size: "10px" }},
    							size: { height: $(this.element).height(), width: $(this.element).width()},	 
    							legend: { visible:  (this.legendVisibility()) , position: this.legendPosition() },
    							pointRegionClick : $.proxy(this.selectionChange,this),
    							highlightSettings: {enable: true},
    							selectionSettings: {enable: true, mode : "parent"},
    							dataLabelRendering : $.proxy(this.dataLabelFormat, this),
    							legendItemRendering : $.proxy(this.legendFormat, this),
    							tooltipInitialize : $.proxy(this.tooltipFormat,this)
    							});	
    		});
    • For ejSunburstChart related API references, refer the link.

    marginVisibility()

    • marginVisibility function controls the visibility of the margins by returning a boolean value based on the widget and height of the container.
  • JS
  • marginVisibility : function () {
    			return ($(this.widget).width() > 200 && $(this.widget).height() > 200);
    }

    getAnimationType()

    • getAnimationType function returns the type of animation based on the type we select in the widget property window.

    dataLabelVisibility()

    • dataLabelVisibility function controls the visibility of the data labels by returning a boolean value based on the width and height of the container.
  • JS
  • dataLabelVisibility : function (e) {
    	return !($(this.element).width() < 300 || $(this.element).height() < 300);
    	}

    getRotationMode

    • getRotationMode function returns the type based on the type we selected in the widget properties window.
  • JS
  • getRotationMode : function(rotationMode) {
    			if (rotationMode === "Normal")
    				return "normal";
    			else if(rotationMode === "Angle")
    				return "angle";
    		}

    legendVisibility()

    • legendVisibility function controls the visibility of the data labels by returning a boolean value based on the width and height of the container.
  • JS
  • legendVisibility : function (e) {
    			return ($(this.element).width() > 300 && $(this.element).height() > 300 && this.model.properties.showLegend);
    		}

    legendPosition()

    • legendPosition function is used to place the legend position based on the condition if ( $(this.element).width() > $(this.element).height()). (i.e) If the the size of the container width is greater than the length then the legend displays on right. Otherwise, it will display on left of the widget.
  • JS
  • legendPosition : function (e) {
    				if ( $(this.element).width() > $(this.element).height())
    				return "right";
    			else 
    				return "top";
    		}
    • Sunburst widget will be rendered as follows:

    Custom_widget sunburst

    selectionChange

    • Other widgets in the dashboard that are configured as a slave for sunburst chart can be updated based on the selected data in the sunburst chart by using below code. ej.dashboard.filterData(this, selectedFilterInfos) is used to send filter data request.

    • On triggering pointRegionClick the selectionChange will gets invoked. In selectionChange(), we get the chart data and get the parent element using findSelectionParent method and push the parent element into data[]. Then create a selectedFilterInfos object of ej.dashboard.selectedColumnInfo() type with the information present in the data[] and pass the selectedFilterInfos into the ej.dashboard.filterData(this,selectedFilterInfos).

    Note: findSelectionParent is a internal API of ejSunburstChart, which is used to get the parent element. It not exposed in the sunburst chart documentation.

    dataLabelFormat()

    • dataLabelFormat() is used to customize the data label based on the formatting options.
  • JS
  • dataLabelFormat : function(e){
    if(this.model.boundColumns.Levels.length > 0 && this.model.boundColumns.Value.length > 0 && !ej.isNullOrUndefined(e.data.Text)){
    	var instance = new ej.dashboard.Internationalization();
    	e.data.Text = this.model.boundColumns.Levels[e.data.level - 1].dataType == "datetime" ? instance.formatDateThroughSchema(e.data.Text.toString(), this.model.boundColumns.Levels[e.data.level - 1]) : e.data.Text ;
    	}
    }

    legendFormat()

    • legendFormat() is used to customize the legend text based on the formatting options.
  • JS
  • legendFormat : function(e){
    if(this.model.boundColumns.Levels.length > 0 && this.model.boundColumns.Value.length > 0 && !ej.isNullOrUndefined(e.data.text)){
      	var instance = new ej.dashboard.Internationalization();
       	e.data.text = this.model.boundColumns.Levels[e.data.level - 1].dataType == "datetime" ? instance.formatDateThroughSchema(e.data.text.toString(), this.model.boundColumns.Levels[e.data.level - 1]) : e.data.text ;
    	}
    }

    tooltipFormat()

    • tooltipFormat is used to customize the tooltip text based on the formatting options.
  • JS
  • tooltipFormat : function (e){
    if(this.model.boundColumns.Levels.length > 0 && this.model.boundColumns.Value.length > 0 && !ej.isNullOrUndefined(e.data.currentText)){
    	var instance = new ej.dashboard.Internationalization(this.model.boundColumns.Value[0].culture);
    	e.data.currentText = this.model.boundColumns.Levels[e.data.level - 1].columnName + " : " + (this.model.boundColumns.Levels[e.data.level - 1].dataType == "datetime" ? 
    	instance.formatDateThroughSchema(e.data.currentText.split(": ")[0],this.model.boundColumns.Levels[e.data.level - 1]) : e.data.currentText.split(": ")[0] )  + "<br>" + this.model.boundColumns.Value[0].summaryType + " of " + this.model.boundColumns.Value[0].columnName + " : " + instance.formatNumberThroughSchema(e.data.currentText.split(": ")[1]*1,this.model.boundColumns.Value[0]);
    	}
    }
    • Update method will be triggered for below operations and we have to do the required changes by checking the update types(resize, refresh, propertyChange) and widget will be updated accordingly by invoking the respective API of the widget.

      1) Resize

      2) Refresh

      3) property change

  • JS
  • update : function (option) {
    	if(option.type == "resize") {  // option type will be resize when the browser is resized 
    		this.resizeWidget(option.size);  // widget will be resized through this method
    	}
    	else if (option.type == "refresh") {  // option type will be refresh when the widget data gets modified
    		var widgetObj = $(this.element).data("ejSunburstChart"); 
    		widgetObj.model.dataSource = this.model.dataSource;  // updating new data to the control
    		widgetObj.redraw();
    	}
    	else if (option.type == "propertyChange") {  // option type will be propertyChange when widget properties changed in the Dashboard Designer
    		var widgetObj = $(this.element).data("ejSunburstChart");
    		switch (option.property.name)  // option.property contains the property name and value of the modified property.
    		{
    			case "enableAnimation":
    				widgetObj.model.enableAnimation = option.property.value; 
    			break;
    			case "animationType":
    				widgetObj.model.animationType = option.property.value; 
    				break;
    			case "titleText":
    				widgetObj.model.title.text =  option.property.value; 
    			case "showTitle":
    				widgetObj.model.title.visible =  option.property.value;
    				break;
    			case "enablezoom":
    				widgetObj.model.zoomSettings.enable =  option.property.value;
    			case "showLegend":
    				widgetObj.model.legend.visible = option.property.value;
    				break;
    		}
    		widgetObj.redraw(); // widget will be updated based on the property changes.
    			}
    		}

    Note: Find the sample sunburst chart widget from the location C:\ProgramData\Syncfusion\DashboardDesigner\Custom Widgets.

    Adding C3 chart as custom widget

    Here we are creating C3 Chart using D3 Library.

    Note: C3 Chart is an open source and it is under MIT licensed.

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

    • Refer the commands to create new custom widget files.

    Custom_widget C3 chart

    • Configure the widget through the widgetconfig.json file.

    • As 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 this link for configuring widgetconfig.json.

  • JS
  • "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": "checkbox",
                        "name": "showTooltip",
                        "defaultValue": "true"
                    },
    				{
                        "displayName": "Show Label",
                        "controlType": "checkbox",
                        "name": "showLabel",
                        "defaultValue": "true"
                    },
                    {
                        "displayName": "Color",
                        "controlType": "colorpicker",
                        "name": "barColor",
                        "defaultValue": "#2196F3"
                    }
                ]
            },
          ],
        "filterSettings": {
            "masterFilter": {
                "visible": true,
                "defaultValue": true
    
            },
            "ignoreMasterFilter": {
                "visible": true,
                "defaultValue": false
            }
        }
    • d3.js dependency file can be downloaded from D3 website.

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

    • Pack the widget and import it in the designer.

    • Then, configure the widget with the necessary data.

    Custom_widget C3 chart

    • Run the C3Chart_xx.html (%appdata%\Syncfusion\DashboardDesigner\versionnumber\Html) generated in the location, and place the break point in the init method in the source file of the widget.

    Custom_widget appdata

    • 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 below code.

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

  • JS
  • 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.
  • JS
  • 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 below condition, we can find whether the widget is configured with columns or not.

    • Converting datasource structure required by C3 Chart.

  • JS
  • 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.
  • JS
  • 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;
    • C3 Chart widget will be rendered as follows:

    Custom widget C3 chart

    selectionChange

    • Other widgets in the dashboard that are configured as a slave for C3 Chart can be updated based on the selected data in the C3 Chart by using below code. ej.dashboard.filterData(this, selectedFilterInfos) is used to send filter data request.

    • On triggering onclick the selectionChange will gets invoked. In selectionChange(), we get the chart data and push the selected value into data[]. Then create a selectedFilterInfos object of ej.dashboard.selectedColumnInfo() type with the information present in the data[] and pass the selectedFilterInfos into the ej.dashboard.filterData(this,selectedFilterInfos).

  • JS
  • selectionChange: function (e) {
    	     var data = [];
    	     data.push(this.model.dataSource[e.x][this.model.boundColumns.Column[0].uniqueColumnName]);
    	     var zero = 0;
    		 var selectedFilterInfos = [];
    		 if (data.length > zero) 
    		    { 
    		    var filterinfo = new ej.dashboard.selectedColumnInfo();
    			filterinfo.condition = "include";
    			filterinfo.uniqueColumnName = this.model.boundColumns.Column[0].uniqueColumnName;
    			filterinfo.values.push(data[0]);
    			selectedFilterInfos.push(filterinfo);
    			}
    			ej.dashboard.filterData(this, selectedFilterInfos);
    			},
    • Update method will be triggered for below operations and we have to do the required changes by checking the update types(resize, refresh, propertyChange) and widget will be updated accordingly by invoking the respective API of the widget.

      1) Resize

      2) Refresh

      3) property change

  • JS
  • 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;
                    }
            }
        }
  • JS
  • 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;
    				},