cancel
Showing results for 
Search instead for 
Did you mean: 
intapiuser
Community Team Member
Community Team Member
Introduction
This post describes the process for creating a new plugin that extends the functionality of one of the existing Sisense widgets.  There are several different aspects that you can modify, this document will focus on the most common use cases.
 
Run code only for specific widgets
When creating a plugin to extend the functionality of a widget, the type of widget will influence how you structure your code. Typically, its a good practice to create an array in your plugin that specifies what widget types are supports, along with a function that determines if the current widget is in that list.  You can get the chart types from the javascript console, just open the widget editor for a given chart type and type prism.activeWidget.type into the javascript console, and it will provide the specific chart type.  There are also sub-types available through prism.activeWidget.subtype.
 
// Define allowed chart types
var supportedChartTypes = ["pivot"];

// Function to determine if this chart type is supported
function widgetIsSupported(type){
 if (supportedChartTypes.indexOf(type) >= 0) {
   return true;
 } else {
   return false;
 }
}
 
Once you have this function defined, you can call it whenever the widget is initialized. This can be run directly from prism.run and if your widget type is supported, then it will attach your custom function to an event handler on the widget.
 
// Registering dashboard/ widget creation in order to perform drilling
prism.on("dashboardloaded", function (e, args) {
 args.dashboard.on("widgetinitialized", onWidgetInitialized);
});

// register widget events upon initialization
function onWidgetInitialized(dashboard, args) {
 // Hooking to ready/destroyed events
 args.widget.on("destroyed", onWidgetDestroyed);
 var shouldInit = widgetIsSupported(args.widget.type);
 if (shouldInit) {
   args.widget.on("eventName", myCustomFunction);
 }
}

// unregistering widget events
function onWidgetDestroyed(widget, args) {
 widget.off("destroyed", onWidgetDestroyed);
}
 
Add menu options to the Widget Editor
In order to add custom formatting options to a chart, a common way is to add new menu items to the widget settings menu or a value/dimension menu.  To do this you need to leverage the prism.on events, which can be found here.  The function to run as the event handler should check the setting.name attribute in order to determine if the menu opened is the menu you are looking for.  A good practice to to create a function dedicated to checking the menu type, that just returns a boolean.  
// Function to determine if the checkbox option should be added
function canEnabledOption(e,args,headerMenuCaption){
 
  // Assume true by default
  var result = true; 
  try { // Has the menu been added already? 
    $.each(args.settings.items, function(){
      if (this.caption == headerMenuCaption) {
        result = false;
        return result;
      }
    })

    // Only show this in the widget editor
    var widgetEditorOpen = (prism.$ngscope.appstate == 'widget');
    if (!widgetEditorOpen) {
      result = false;
      return result;
    } 

    // find the widget
    var widget = e.currentScope.widget;
    if(typeof widget === "undefined"){
      result = false;
      return result;
    }

    // Widget must be an allowed chart
    if(!widgetIsSupported(widget.type)){
      result = false;
      return result;
    }

    // Make sure the user clicked on a widget's settings menu
    if (args.settings.name != "widget-metadataitem") {
      result = false;
      return result;
    }

    // For pivot charts, make sure the settings menu is for a value
    if (e.currentScope.widgetType == "pivot") {
      // Only capture events on the ROWS panel
      if (args.settings.item.$$panel.name != "rows") {
        result = false;
        return false;
      }
    }
  } catch(e) {
    result = false;
  }
 
  // Return result
  return result;
}
 
If you want to add menu items to measures/dimensions in the widget editor, you can adjust the above code to look for args.settings.name == "widget-metadataitem" and use the table below to check for specific datatypes.
 
Menu Item Properties Available for Specific Datatypes
 
 
Once you have this, you can just check the function (maybe in multiple places) and then decide what code to run.
 
prism.on("beforemenu", function (e, args) {

 // Define the menu label
 var headerMenuCaption = "My Caption Label";

 // Can we show the options?
 var addMenuItems = canEnabledOption(e,args,headerMenuCaption);

 // Add some extra menu items
 if (addMenuItems) {
   ...some code here...
 }
})
 
 
Use Cases
Here we will break down the specific types of widgets, and what the process looks like for customizing each.

INDICATORS

The easiest way to customize indicators is by manipulating the HTML after it's been rendered.  It's pretty straightforward to do this, using jQuery (which is already loaded with Sisense).  There is a helpful forum post that describes how to find specific pieces of an indicator.  The script in the forum post runs for all indicators on a dashboard, but it could also be run to customize the formatting of a specific indicator.  The code below shows how to find a specific indicator's text fields, title, subtitle, and numerical fields.  Standard CSS is used to customize the look and feel of each of these pieces.
widget.on('ready', function(sender, ev){ 

  // General Class for all the parts of the Indicator
  var indicator = $('.indicator_section span',element);
  indicator.css('font-family','Times New Roman,Georgia,Serif'); // change font family
  indicator.css('font-size','50px'); // change font size
  indicator.css('font-style','italic'); // change font style indicator.css('white-space','normal'); // Wrap Text
 
  // primary title (id)
  var title = $('#title_span',element);
  title.css('color','blue');
  title.css('font-style','Bold'); // change font style
 
  //secondary title (id)
  var subTitle = $('#secondary_title_span',element);
  subTitle.css('font-size','25px'); // change font size
  subTitle.css('color','green');
  subTitle.css('font-style','Bold'); // change font style
 
  //catches both of the 'number' classes (primary+secondary)
  var numberSpan = $('.number_span,.secondary_span',element);
  numberSpan.css('color','red');
 
  //id of the secondary title
  var subTitleSpan = $('#secondary_title_span',element);
  subTitleSpan.css('color','Black')
 
  //ID of the secondary number - overrides the .secondary_span css class
  var subSpan = $('#secondary_span',element);
  subSpan.css('color','#9E08C3') //a kind of purple
})
 
If you are interested in customizing gauges, then hook into the processresult event of the widget.  See the code snippet below that gets the gauge object from a widget's event object.  This object contains the default color, along with the conditional colors that are set for the gauge.
widget.on('processresult', function(sender,event){
 var gauge = event.result.gauge;
})
Relevant plugins/Javascript:

HIGHCHARTS-BASED WIDGETS (COLUMN, BAR, AREA, PIE, POLAR, & SCATTER)

Several of the charts used in Sisense (Column, Bar, Area, Pie, Polar, and Scatter widgets) leverage Highcharts behind the scenes.  This means that any of these chart types can be easily manipulated using the Highcharts API.  Catch the processresult or render event and look for the result variable (for processresult) or queryResult variable (for render).  This will be the equivalent of $("#container").highcharts( { } ) in the Highcharts API.  Once you have this object, you can customize it using any of Highchart's available options.  Check out the links below that ouline common uses cases for modifying the widget using the Highcharts API.
function customizeHighchartOnProcessResult(sender,event) {
 var highchart = event.result;
}
function customizeHighchartOnRender(w) {
 var highchart = w.queryResult;
}
Relevant plugins/Javascript:

PIVOT WIDGET

The Pivot widget works a bit differently than all the other widgets in Sisense.  When you create a query from this widget, the result is a formatted HTML table.  You can access this on processresult, using event.result.table.  This can be manipulated just like any other HTML element, and is easily done using jQuery.  One quirk of jQuery is that if you ask for the HTML of an element, it will give you the HTML of only the children of that element.  In order to get the entire HTML, create an empty DIV element named myTable and append the HTML table as a child.  Once you have this, you can manipulate it as needed and get the table back by using myTable.html().
 
widget.on('processresult', function(sender,event){

 //    Get the result table
 var myTable = $('<div>').append($(event.result.table));

 //    Do something to the table

 //    Write the table back to the widget
 event.result.table = myTable.html();
})
 
 
One important piece to keep in mind is how to find specific columns within this table.  If you look at the result.fields object, it lists out the dimensions and values that exist in the pivot table along with an index.  When searching through the HTML table look for the fidx attribute which will match with the indexes.  
Relevant plugins/Javascript&colon;

TABLE WIDGET

The table widget is based off the DataTables framework.  This table is not pre-formatted like the Pivot table, instead it is sent back as an array of rows.  Each row contains all the columns in the row, with a data field and text field.  You can manipulate the text field with HTML and the browser will render it for you.  The example below is the best reference for seeing this in action.
Relevant plugins/Javascript&colon;
 

OTHER WIDGETS

There are a few more widget types (treemap, calendar, sunburst) which use the D3 library.  Each one of these will be pretty different, as D3.js is more of a framework for creating shapes.  The rendering process here is handled more behind the scenes, instead of through configuration objects, so the best way to manipulate them is by hooking onto the ready event and manipulating the HTML after it's been written to the page.  Alternatively, you can hook into the render event and manipulate the data at w.queryResult.$$rows
The scatter map widget uses a the Leaflet framework, which uses Mapbox as a mapping engine.  Again, the rendering for this chart type is done internally, so the best way to manipulate it is either by changing the data on render at w.queryResult.$$rows or by waiting for it to complete and hook into the ready function to manipulate the HTML on the page.  Alternatively, the bottom link shows how to save the map object that gets created and allows for manipulation after it's been loaded.
Relevant plugins/Javascript&colon;
Rate this article:
Version history
Last update:
‎02-09-2024 01:51 PM
Updated by: