Embedding custom visualizations within a widget
Introduction
This document outlines the process for overriding an existing chart with a Highcharts Donut Pie chart. For a more robust solution, it is recommended to create a custom plugin as that would allow non-technical users to create charts without editing scripts. However, if this is a one-off solution, an existing widget’s script can be overridden to allow for integration with 3rd party charting solutions.
Steps
Here we will explain how to do it in detailed steps.
Step 1 - Create the SiSense widget
Try to be consistent with the image size along the post.
Step 2 - Copy in the custom JavaScript
Click on the Edit Script button for the widget to pull up the script editor.
Open the attached JS file, then copy and paste the code into the script editor. The only thing that might need to be changes is to change the Highcharts div container ID. If you want more than 1 of these charts on the same dashboard, they need to have unique IDs. So just change the value of the JavaScript variable ChartDivName from “MyHighcharts” to “MyHighcharts2” or any other unique ID. Click the save button, and reload the dashboard. This code requires there to be a dimension specified as a Category, a second dimension specified under Break By, and a metric specified as a value. The screenshot below shows the setup used for the example.
Overview of custom JavaScript code
The code attached consists of the following 4 tasks:
1. Retrieve data from the widget
The results of the ElastiCube query are stored in the widget object, which is accessible through the sender variable. The dimensions/value names and data points are contained within the sender.rawQueryResult property. This data set will need to be transformed to fit the Highcharts data format.
2. Format the data
The data comes back from the query as an array consisting of data points in the following format: [CategoryName, DataPointName, DataPointValue]. This will need to be modified to match the format required by the desired 3rd party visualization tool.
3. Replace SiSense chart w/ new visualization
The stacked column chart specified in this example gets rendered by the SiSense engine as a SVG element. This block of code finds the newly rendered stacked bar chart and replaces the svg tag with a div container for the Highcharts..
4. Create the new visualization
At this point, the data is formatted appropriately and the SiSense chart has been replaced with an empty container for the 3rd party visualization. This code block uses the Highcharts API to create a new donut pie chart within the specified div container.
Customizing the code
Following steps one and two will create a donut pie chart based on the given data set, but what if the required 3rd party chart was slightly different? The JavaScript would need to be customized to meet the requirements of the 3rd party chart. When pulling data from SiSense, the key object to look at is the sender.rawQueryResult variable. This object contains an array headers, which contains information about the dimensions and metrics specified by the widget. It also includes a variable values, which contains an array of all data points. These two objects can be looped through to build a data set compatible with the desired 3rd party visualization tool.
See also
Here we will put links to
- Highcharts Pie Donut Chart - http://www.highcharts.com/demo/pie-donut
- SiSense Widget API - https://docs.google.com/document/d/1nQBZtWAdNFAd9nBhPWGVT3qOMS4Qm0PzBZVIzz5DfE8/
Highcharts-DonutPie-Figure1.png
Highcharts-DonutPie-Figure2.png
Highcharts-DonutPie.zip
Highcharts-DonutPie-Figure3.png
-
Hi @Ehounoud,
I'm not exactly sure what may be the problem with this specific widget, though we provide a few custom visualization plugins such as the Chord Dependancy Diagram, or Double Stacked Bar Chart
We have a few more on the Sisense Partner Market Place
Feel free to reach out if you need any additional assistance with creating any other new plugin you may find beneficial for your users,
Thanks
Ido
qbeeq.pl
Sisense Partner of the Year 2019!
-
Hello there,
First of all, thank you Aviad Harell for sharing your code with us. I'm a new customer of SiSense, and it's helpful to understand how JavaScript can be leveraged to extend the customization of our widgets, without having to use external plugins.However, I have the same issue as Ehounoud Eby. That is, the script works when I apply the code in the Widget Editor. And as long as I refresh my page in this editor, the wished output is displayed. But when I leave the widget editor, and display my dashboard, it's empty. I believe this is caused by the line:
MyWidget.find("svg").remove();
Problem is, if I remove this line, then the dashboard view just shows the initial Pie chart, instead of the graph I'd like to show.
Moreover, I have other issues with the below lines, which return "Undefined" in the console.
// get the height and width
var MyChart = MyWidget.find("svg");
console.log("MyChart_is:")
console.log(MyChart)
var MyChartWidth = MyChart.attr("width");
/*MyChartWidth=600*/
console.log("MyChartWidth_is:")
console.log(MyChartWidth)
var MyChartHeight = MyChart.attr("height");
/*MyChartHeight=450*/
console.log("MyChartHeight_is:")
console.log(MyChartHeight)Aiming to find where the problems comes from, I've modified the code as below, so that almost each variable is printed out, into the console. Note that at the end, it returns a static graph with dummy data. This is for the sake of simplification. If I could get my script working outside of the widget editor, this would be a nice start. I think I can handle the graph part myself, I think. Here is "my" code (indent got lost in formatting):
widget.on('ready', function(sender, ev){
console.log('starting custom code');
/**************************************************
*** Retrieve data from the widget ***
*** ***
*************************************************/
var ChartTitle = sender.title;
console.log("ChartTitle:")
console.log(ChartTitle)
var ChartDivName = "MyHighchart";
console.log("ChartDivName:")
console.log(ChartDivName)
var ChartDivStyle = sender.style;
console.log("ChartDivStyle:")
console.log(ChartDivStyle)
//this ID must be unique for the whole HTML page,
//so if you use multiple custom charts in the same dashboard then this will need to be changed
//fetch data from widget
var QueryResult = sender.rawQueryResult;
console.log("QueryResult:")
console.log(QueryResult)
//var ChartMetric = QueryResult.headers[2];
//console.log("ChartMetric:")
//console.log(ChartMetric)
var ChartLevel1 = QueryResult.headers[0];
console.log("ChartLevel1:")
console.log(ChartLevel1)
var ChartLevel2 = QueryResult.headers[1];
console.log("ChartLevel2:")
console.log(ChartLevel2)
/**************************************************
*** Format the data for Highcharts ***
*** ***
*************************************************/
var ChartDataSet = QueryResult.values;
console.log("ChartDataSet:")
console.log(ChartDataSet)
var ChartCategories = [];
var ChartValues = [];
var ChartColors = Highcharts.getOptions().colors;
console.log("ChartColors:")
console.log(ChartColors)
console.log("LOOP STARTS")
//loop through data to build top level
$.each( ChartDataSet, function() {
//get category and value
var MyCategoryName = this[0].text;
console.log("MyCategoryName:")
console.log(MyCategoryName)
var MyDataPointName = this[1].text;
console.log("MyDataPointName:")
console.log(MyDataPointName)
//var MyDataPointValue = this[2].data;
var MyDataPointValue = this[1].data;
console.log("MyDataPointValue:")
console.log(MyDataPointValue)
var MyDataPointColor;
//look for existing category w/ matching name
var ExistingCategory = $.grep( ChartCategories, function(el) {
return (el.name == MyCategoryName );
});
//does it exist already?
if ( ExistingCategory.length == 0 )
{
//category doesn't exist, so add it
MyDataPointColor = ChartColors[ ChartCategories.length ];
var NewCategory = {
name: MyCategoryName,
y: MyDataPointValue,
color: MyDataPointColor
};
ChartCategories.push( NewCategory );
}
else
{
//category exists, so just add value to the total
ExistingCategory[0].y += MyDataPointValue;
MyDataPointColor = ExistingCategory[0].color;
}
//create the data point
var brightness = (ExistingCategory.length * 0.1) + 0.1;
console.log("brightness:")
console.log(brightness)
var NewDataPoint = {
name: MyDataPointName,
y: MyDataPointValue,
color: Highcharts.Color(MyDataPointColor).brighten(brightness).get()
};
console.log("NewDataPoint_is:")
console.log(NewDataPoint)
ChartValues.push( NewDataPoint );
console.log("CharleValues_Updated:")
console.log(ChartValues)
});
console.log("LOOP ENDS")
/**************************************************
*** Replace SiSense chart with Highchart ***
*** container ***
*************************************************/
//get object id of current indicator
var ObjectID = sender.oid;
console.log("ObjectID_is:")
console.log(ObjectID)
//get the current widget
var MyWidget = $('widget[widgetid=' + ObjectID + ']');
console.log("MyWidget_is:")
console.log(MyWidget)
if (MyWidget.length == 0)
{
MyWidget = $('.widget-body');
console.log("MyWidget_if_length_is_0:")
console.log(MyWidget)
}
// get the height and width
var MyChart = MyWidget.find("svg");
console.log("MyChart_is:")
console.log(MyChart)
var MyChartWidth = MyChart.attr("width");
/*MyChartWidth=600*/
console.log("MyChartWidth_is:")
console.log(MyChartWidth)
var MyChartHeight = MyChart.attr("height");
/*MyChartHeight=450*/
console.log("MyChartHeight_is:")
console.log(MyChartHeight)
//set the widget's div id and clear all children
var ChartDiv=document.createElement('div');
console.log("ChartDiv_is:")
console.log(ChartDiv)
ChartDiv.setAttribute("id",ChartDivName);
console.log("ChartDiv_withAtt_id_set_to_ChartDivName:")
console.log(ChartDiv)
ChartDiv.setAttribute("style","width: " + MyChartWidth + "px; height: " + MyChartHeight + "px; margin: 0 auto");
console.log("ChartDiv_withAtt_styleWidthHeightMargin_set_to_MyChartWidth_and_MyChartHeight_and_constantMarginHardcoded:")
console.log(ChartDiv)
MyChart.after(ChartDiv);
MyChart = $("#" + ChartDivName);
MyWidget.find("svg").remove();
/**************************************************
*** Create the Highchart within the ***
*** Highcharts div container ***
*************************************************/
// Create the chart
$('#' + ChartDivName).highcharts({
chart:{
type:"line"
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4],
name: 'Meteorological data',
dataLabels: {
enabled:true,
formatter: function () {
return this.y > 150 ? null : this.y;
},
color: 'red',
distance: -30
}
}]
});
console.log('custom code finished.');
})Ido Darnell, do you have a clue regarding what goes wrong here ? Why is my dashboard empty, when I leave the widget editor ?
-
I'm not sure what the issue is, feel free to reach out so we can investigate together,
Ido
Please sign in to leave a comment.
Comments
6 comments