How to customize table cells and format sparklines using SplunkJS Stack

While you can use regular styles to format a table, you can also customize the way cells are rendered to change the way the data is displayed. To do this, you'll need to create a custom cell renderer.

The Web Framework already includes a custom cell renderer for sparklines, allowing you to easily set properties to format the sparkline. When you want to apply your own visual effects, you'll need to implement your own custom cell renderer.

Formatting sparklines

To add sparklines to search results, first add the sparkline function to your search query, and then display the search results in a Table view. When you create the table, set the sparkline properties to change the way the sparkline is formatted. For example, you can choose the type of sparkline (bar, discrete, or line), set the colors, and define value ranges. For a description of all the properties you can set, see the Sparkline options in the Dashboards and Visualizations manual.

Here's an example of the default sparkline and a formatted sparkline:

Formatted sparkline

Sparkline properties can only be set in JavaScript when you create the table. Use the table's format property and set it to a dictionary of properties and values, some of which are also dictionaries. Here's the structure of the format property:

format: {
    "sparkline_fieldname": [
        {
            "type": "sparkline",

            // Sparkline options
            "options": 
            {
                "property-1": "value-1",
                ...
                "property-n": "value-n"
            }
        }
    ]
}

Two format properties are required:

  • sparkline_fieldname is a variable that corresponds to the field name of the sparkline within the search results. The default value is "sparkline". If you rename the field in your search query, make sure to use the same field name here.
  • The type property must be set to "sparkline". (There is also an optional type property within the sparkline options indicating the type of sparkline to display.)

The code example below shows how to format a sparkline using the built-in cell renderer.

Creating a custom cell renderer

When you want to apply custom formatting to data in a table cell, you need to create a custom cell renderer. For example, here's a cell with rangemap values, and then the same data with a custom cell renderer that swaps the text for icons:

Custom table cell renderer

To create a custom cell renderer, write a class that inherits from the Table view's BaseCellRenderer class, which has methods that you can override:

  • initialize: function(): Initializes setup.
  • canRender: function(cellData): Required. Indicates when to apply custom cell rendering. When this method returns true, the custom cell renderer is applied.
  • setup: function($td, cellData): Runs before rendering the cell.
  • render: function($td, cellData): Required. Renders the cell.
  • teardown: function($td, cellData): Clears resources.

The function parameters contain the following information:

  • $td: Container for the cell.
  • cellData: Contains data about the cell as an object with several fields: columnType, extremes, field, heatDelta, index, sparklineFormat, timestampFormat, and value.

The following example shows the basic structure for creating a custom cell renderer:

// Require the Table view library
require([
    "splunkjs/mvc/tableview",
    "splunkjs/mvc/simplexml/ready!"
], function(TableView) {


    // Inherit from the BaseCellRenderer base class
    var MyCustomCellRenderer = TableView.BaseCellRenderer.extend({
        initialize: function() {
            ...
        },
        canRender: function(cellData) {
            // Required
            ...
        },
        setup: function($td, cellData) {
            ...
        },
        teardown: function($td, cellData) {
            ...
        },
        render: function($td, cellData) {
            // Required
            ...
        }
    });

   ...
   
});

To work with your custom cell renderer, use these methods with the Table view:

  • addCellRenderer(renderer): Adds a cell renderer to the table, where renderer is an instance of your custom cell renderer.
  • removeCellRenderer(renderer): Removes a cell renderer from the table, where renderer is an instance of your custom cell renderer.
  • getCellRenderers: Gets an array of the cell renderers that have been added to the table.
  • addCellRenderer(renderer): Adds a cell renderer to the table, where renderer is an instance of your custom cell renderer.
  • removeCellRenderer(renderer): Removes a cell renderer from the table, where renderer is an instance of your custom cell renderer.
  • getCellRenderers: Gets an array of the cell renderers that have been added to the table.
  • render: Draws the view to the screen.

The example below shows how to use the BaseCellRenderer class and Table view methods to create a custom cell renderer.

Custom table example

Here's an example that shows two tables with a sparkline and a rangemap value, with some custom style definitions. The first table shows the default cells, and the second table shows how to format the sparkline and apply a custom cell renderer to the "range" field to display different icons based on the severity value.

<!-- Define icon styles -->
<style>
    td.icon {
        text-align: center;
    }

    td.icon i {
        font-size: 15px;
        text-shadow: 1px 1px #aaa;
    }

    td.icon .severe {
        color: red;
    }

    td.icon .elevated {
        color: orangered;
    }

    td.icon .low {
        color: #006400;
    }
</style>

...

<script>

    require([
        "underscore",
        "splunkjs/mvc/searchmanager",
        "splunkjs/mvc/tableview",
        "splunkjs/mvc/simplexml/ready!"
    ], function(
       _,
       SearchManager,
       TableView
    ) {

        // Set up search manager
        var search1 = new SearchManager({
            id: "mainsearch",
            search: "index=_internal | head 10000 | stats sparkline count by sourcetype | rangemap field=count low=0-100 elevated=101-1000 default=severe",
            earliest_time: "-1h@h", 
            latest_time: "now",
            preview: true,
            cache: true
        });

        // Create a default table
        var myPlainTable = new TableView({
            id: "table-plain",
            managerid: "mainsearch",
            el: $("#table-plain")
        }).render();

        // Create a custom table and set sparkline properties
        var myCustomTable = new TableView({
            id: "table-custom",
            managerid: "mainsearch",
            el: $("#table-custom"),
            // Format the sparkline cell
            format: {
                "sparkline": [ // This field name is required
                    {
                        "type": "sparkline", // This property must be "sparkline"

                        // Sparkline options
                        "options": 
                        {
                            "type": "bar",
                            "height": "40px", 
                            "barWidth": "5px",
                            "colorMap": 
                            {
                                "100:": "#0033CC", 
                                ":99": "#00FF00"
                            }
                        }
                    }
                ]
            }
        });

        // Define icons for the custom table cell
        var ICONS = {
            severe: 'alert-circle',
            elevated: 'alert',
            low: 'check-circle'
        };

        // Use the BaseCellRenderer class to create a custom table cell renderer
        var CustomIconCellRenderer = TableView.BaseCellRenderer.extend({ 
            canRender: function(cellData) {
                // This method returns 'true' for the 'range' field
                return cellData.field === 'range';
            },
            
            // This render function only works when canRender returns 'true'
            render: function($td, cellData) {
                console.log("cellData: ", cellData);

                var icon = 'question';
                if(ICONS.hasOwnProperty(cellData.value)) {
                    icon = ICONS[cellData.value];
                }
                $td.addClass('icon').html(_.template('<i class="icon-<%-icon%> <%- range %>" title="<%- range %>"></i>', {
                    icon: icon,
                    range: cellData.value
                }));
            }
        });
        
        // Create an instance of the custom cell renderer
        var myCellRenderer = new CustomIconCellRenderer();

        // Add the custom cell renderer to the table
        myCustomTable.addCellRenderer(myCellRenderer); 

        // Render the table
        myCustomTable.render();

    });
</script>