Skip to content

Raw Data Table

The Raw Data Table (RDT) is an ag-grid based table used to display raw, non aggregated data. Its configuration and options differ from the rest of the visuals.

Rendering the RDT

The RDT uses .field() instead of .groupby() and it doesn’t use .metrics()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var fields = [
  cf.Field('eventname.keyword','Event Name'),
  cf.Field('venuecity.keyword', 'Venue City'),
  cf.Field('catname.keyword', 'Category Name'),
  cf.Field('pricepaid', 'Price')
]
cf.provider('Elasticsearch')
  .source('ticket_sales')
  .fields(...fields)
  .graph('Raw Data Table')
  .element('rdt-div')
  .execute()

This will render an RDT like this:

RDT

The first thing to notice here is the fields variable, which is an array of Field objects that exist specifically for the RDT. Each one of these objects has the name of the field and any label we want to display as column header for that field. That’s the main purpose of the Field object.

You can also define field labels using Custom Metadata. See the Custom Metadata section to learn how to define field labels.

If we don’t want to use the Field object, you can just pass an array of strings representing the field names into the .fields() function like this:

1
2
3
4
5
6
cf.provider('Elasticsearch')
 .source('ticket_sales')
 .fields('eventname','venuecity','catname','pricepaid')
 .graph('Raw Data Table')
 .element('rdt-div')
 .execute()

RDT F

Notice how the column headers changed now to use the field names instead of the field labels.

Get all fields and exclude some

This is a very common case. Bring all fields and exclude a few. To do this we use the .fields() function without parameters, it will understand that if no fields were specified it will retrieve all of them.

The in order to exclude some of those fields, we’ll use the .exclude() function passing the fields we don’t want to query. The parameters will be the names of those fields:

1
2
3
4
5
6
7
cf.provider('Elasticsearch')
 .source('ticket_sales')
 .fields()
 .exclude('sales_id','event_id','user_id')
 .graph('Raw Data Table')
 .element('rdt-div')
 .execute()

Sorting by columns

The RDT will allow to sort the data by clicking over any column header. It will loop through descending, ascending and alphabetically which is the default.

Setting the sort via AQL

Sort order can be specified via AQL in this way:

1
2
3
4
5
.set('sort', [
    {'catname': 'asc'},
    {'commission': 'desc'},
    {'eventname': 'asc'}
])

The above will sort by catname ascending first, then eventname descending and finally pricepaid for Shows ascending:

PT

Sorted columns will have the up arrow indicator when is ascending and the down arrow when is descending. Also the sort order in the same way that was specified in the aql.

Tip

When playing data with the Time Slider data player, sort your RDT by the time field used in the Time Slider in descending order so that you can see the new data arriving at the top.

RDT options

The options for the RDT must be specified BEFORE the visualization is rendered, meaning before invoking the .execute() method.

Row number

This option displays row numbers on the first column. See the example below.

1
2
3
4
5
6
7
cf.provider('Elasticsearch')
 .source('ticket_sales')
 .fields('eventname','venuecity','catname','pricepaid')
 .set('showRowNumber', true)
 .graph('Raw Data Table')
 .element('rdt-div')
 .execute()

RDT RN

The row loading indicator

The loading indicator is displayed when the RDT is waiting for data:

RDT LI

This indicator is not provided within ChartFactor, instead ChartFactor tries to load it from ${app_root}/../img/loading.gif by default. If we have a different structure like ${app_root}/assests/images/loader.gif, then we need to tell ChartFactor the right path as shown below:

1
rdt.set('loader', '/assets/images/loader.gif')

Or, if we don’t have a gif and we want to pull it from an external resource, or use a font like Google fonts or Awesome fonts that provider spinners as DOM elements classes, we can specify the html element that will render the spinner instead:

1
rdt.set('loader', '<img src="http://icons.com/loading/23"/>')

or

1
rdt.set('loader', '<span class="fa fa-spinner back"></span>')

Formatting cells

The main purpouse of the RDT is to show raw data as it is stored in the data engine. However, we can still format the values and apply styles to them for a better visualization. The formatting is applied then at render time with the option cellFormat.

1
2
3
4
5
6
let formatter = {
  fields: // ... The fields to format
  format: // A function with the formatting rules
}

rdt.set('cellFormat', formatter);

In the object we have two properties, the first one is fields. This property accept the following values:

1
2
3
4
5
6
7
8
// An array of field names
fields: ['field_name_1', 'field_name_2'],

// A field type to affect all fields for that specific type
fields: 'INTEGER', // PERCENT, TIME, ....

// The word ALL, to affect all fields
fields: 'ALL'

The property format, must be a function that takes three parameters: the field name, the value of the field for the corresponding cell and the params object. The last one is an ag-grid custom object that can be used to access custom properties like api, columnApi or the entire row node. More details about params here.

Internally the result of this function will be applied to the cellRenderer property for the definition of each cell in each column, if this one matches the fields property criteria.

The function must return an object with any (or both) of this two properties depending on what we need: value and style. The first one is the new value for the cell and the second one is an object with css properties.

For example, let's say that for a given field we want to display them in different colors depending on their values and the row data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let formatter = {
  fields: ['my_numeric_field'],
  format: function(field, value, params) {
    const data = params.data;
    const createdAt = data.created_at;

    // Records created before the 2021/01/01 will be displayed in grey
    if (createdAt < new Date('2021/01/01')) return { style: { color: 'grey'}};

    // Negative numbers will be displayed in red and bold:
    if (value < 0) return { style: { color: 'red', 'font-weight':'bold' }};

    // In yellow if is positve under 4
    if (value >= 0 && value < 4) return {style:{ color:'yellow'}};

    // Green for the rest
    return { style: { color: 'green'}};
  }
}

The next example will transform the value depending on the field:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
let formatter = {
  fields: 'ALL',
  format: function(field, value, params) {

    // Change the format of the time field to a custom one
    if (field === 'time_field' ) {
      return { 
          value: changeTimeFormat(value)
        }
    }

    // Append "-SEC" to all values of "other_field" and increase the font
    if (field === 'other_field') {
      return {
        value: value + "-SEC"
        style { 'font-size': '16px'};
      }
    }
  }
}

Group columns

Columns can be grouped like this:

RDT LI

We can define the groups and what fields will be under that group in two ways. The first one can be used when we use .fields() without specifiying the fields and we want to group some of them:

1
2
3
4
5
6
7
8
let groups = {
   'Group 1' : ['likebroadway', 'likeclassical',
    'likeconcerts', 'likejazz', 'likemusicals',
    'likeopera', 'likerock', 'likesports',
    'liketheatre', 'likevegas'],
   'Group 2': ['state', 'user_id']
}
rdt.set('colGroup', groups)

The second way is by telling the Field object what group to use:

1
2
3
4
5
6
7
8
9
let grp1 = 'Group 1';
let grp2 = 'Group 2';
let fields = [
    cf.Field('eventname.keyword').group(grp1),
    cf.Field('venuecity.keyword').group(grp1),
    cf.Field('city.keyword').group(grp2),
    cf.Field('state').group(grp2),
    ...
]

Size columns to fit

This option will make the columns to scale (growing or shrinking) to fit the available width. This is useful when adding more data (new fields for example) after the table has been rendered for the first time. It can be set at execution time or after the table was rendered.

1
rdt.set('sizeColumnsToFit', true)

Auto size columns

This option will make all columns to adjust to the text width. It can be considered as the opposite to sizeColumsToFit, and this means that when one of them is applied will override the effect of the other one.

1
rdt.set('autoSizeColumns', true)

Columns width

The columnWidth property allows to manually set the ideal width for every grid column. This property won't have any effect if this property sizeColumnsToFit is also set.

1
2
3
4
5
6
7
.set("columnsWidth", [
          {"community_areas":146},
          {"company":93},
          {"dropoff_census_tract":154},
          {"dropoff_community_area":177},
          {"dropoff_community_area_desc":206}]
    )

Column sortable

The sortable property allows to declaratively enable or disable the sort behaviour for specific columns. The default value for all columns is true meaning that sorting is enabled for all columns unless their data type does not support it (e.g. Geopoint data type). In the example below, we specify that the "company" column should not allow sorting.

1
2
3
4
.set("sortable", [
        {"company":false},
        {"dropoff_community_area_desc":true}]
    )

Export content to CSV

The RDT allows to export its content into a csv file. We can specify what columns to use and the name of the file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let args = {
    // The file name used without the .csv
    fileName: 'RDT-file', 

    // The names of the fields  to be exported
    columns: [ 'index_11', 'index_21' ], 
};

// When this is executed, a csv file will be downloaded in the browser.
rdt.get('csv')(args);

The use of args, as well as any of the two parameters are optional. By default all columns will be exported, and the file name will be export.csv.

Limits and Page Size

Raw data tables use infinite scrolling to show data as naturally as possible, but behind the scenes, it uses pages of 100 rows by default. This page size can be changed with the limit function as we can see bellow:

1
rdt.limit(200)  // Changed page size to 200

Limits under 100 are not allowed. This ensures a page size big enough to be displayed in the view port of the Raw Data Table.

Ag-grid custom options

Since the RDT is based on ag-grid, we can specify custom configurations directly to the grid options. For the inner working of the RDT there are a few options and events that cannot be overwritten. These are the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
columnDefs
rowModelType
cacheOverflowSize
maxConcurrentDatasourceRequests
infiniteInitialRowCount
maxBlocksInCache
suppressFieldDotNotation
cacheBlockSize
onGridReady
onModelUpdated
onColumnResized

Any other option supported by ag-grid can be specified through the customOpts property to provide more flexibility when applying custom styles for example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let opts = {
        // The height of the cells
        rowHeight: 30, 

        // The height of the headers
        headerHeight: 30, 

        // The height of group header
        groupHeaderHeight: 35,

        // The header icons when is sorted
        icons: {
            sortAscending: '<i class="fa fa-arrow-up-o"/>',
            sortDescending: '<i class="fa fa-arrow-down-o"/>',
        }

}

rdt.set('customOpts', opts)

We can also extend the functionality beyond the defaults. For example, the RDT doesn't trigger filter natively since its main purpose is to show the raw data. This can be implemented by hooking to the ag-grid events directly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
rdt.set("customOpts", {
    suppressCellSelection: false,
    suppressRowClickSelection: false,
    rowSelection: 'single',
    onSelectionChanged: (ev) => {
      const eventSelected = ev.api.getSelectedRows()[0].eventname;

      // Create the filter here
      const filter = cf.Filter('eventname').value(eventSelected)
      const api = cf.getIManager().get('api')

      api.setFilter(filter)
      api.applyFilters()
    }
})

For more configurations please refer to the official ag-grid documentation.

Custom columns options

RDT columns can be configured with ag-grid level options through the fields objects. You can learn more about these options here. This adds more flexibility in cases when we need to modify behaviour for a given column that is not allowed directly through the aql.

In Chartfactor the properties for each column can be configured using the fromJSON() function like the example bellow:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const fields = [
  cf.Field('event_name','event_name'),
  cf.Field('category', 'category'),
  cf.Field('created_at', 'created_at'),
  cf.Field('user_created_at', 'user_created_at')
]
// Custom cellRenderer function to be reused
const myCellRenderer = params => `<span style="color: ${params.color}">${params.value}</span>`; 

fields.forEach((f) => {
    // Set custom css classes to each column header and cells
    const opts = {
        colId: f._name,
        headerClass: ['custom-header-class'],
        cellClass: ['custom-cell-class'],
    };

    // Set custom css if the field meets certain criteria
    const opts = {
    if (['event_name', 'category'].includes(f._name)) {
        opts.headerClass.push('centered');
        opts.cellClass.push('custom-cell');

        opts.cellRendererParams = {
          color: 'red'
        }
        opts.cellRenderer = myCellRenderer;        
    }

    if (f._name === 'created_at') {
        opts.headerTooltip = 'Custom tooltip for created_at field.';
    }

    // We may need to query a field but hide it in the RDT:
    if (f._name === 'user_created_at') {
        opts.hide = true;
    }
    f.fromJSON({ colOpts: opts });
});

IMPORTANT: Note that the property cellRenderer is defined for event_name and category. If a function is defined to format the cells with the set('cellFormat', formatter) method (See formatting cells), in this case the cell rendering for the two fields will be driven by the myCellRenderer function an not by the cellFormat configuration.

Copy row on selection

By default the Raw Data Table doesn't allow users to copy its content as normal text. Instead the aql provides the copyRowOnSelection option to allow users to copy row values when a selection is performed. The example below shows how to set the copyRowOnSelection property:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/* Configuration code for this widget */
let provider = cf.provider("Aktiun Elastic");
let source = provider.source('chicago_taxi_trips');

let fields = [
cf.Field('community_areas','community_areas'),
cf.Field('company','company'),
cf.Field('dropoff_census_tract','dropoff_census_tract'),
cf.Field('dropoff_community_area','dropoff_community_area'),
cf.Field('dropoff_community_area_desc','dropoff_community_area_desc')
];

let myData = source.fields(...fields);
// --- Define chart options and static filters ---
let myChart = myData.graph("Raw Data Table")
            .set("showRowNumber", false)
            .set("autoSizeColumns", true)
            .set("copyRowOnSelection", true)
            .execute();

You can use the following configuration if users also want to copy the table headers:

1
2
3
.set("copyRowOnSelection", {
      "copyWithHeaders": true
})

The option copyRowOnSelection will not work if you set one of the following in the customOpts property:

  • suppressCellSelection: true.
  • suppressRowClickSelection: true.

Tree Data Table

The ChartFactor Tree Data Table renders a tree with expandable/collapsible nodes. Example below.

image

It supports infinite scrolling plus expandable and collapsible functionality while maintaining at the most two pages of data in the browser. This means that it supports theoretically infinite amounts of data. Expanding a large node (e.g. 100k rows) will not crash the browser.

Note

The Tree Data Table setting is currently supported only for the Elasticsearch data provider.

The data assumption is that the hierarchical columns are concatenated in a single column with the separator of your choice. See the next section for details.

Configuring your Tree Data Table

To configure your Tree Data Table, set the treeConfig property as follows:

1
2
3
4
5
.set("treeConfig", {
          field: "concat", 
          separator: '__', 
          showHeaderControls: true
      })
  • field: The column that contains the concatenated hierarchical values. An example of concatenated hierarchical values is Allergies__Female__commercial__asian__. Each value between the __ separator is a tree node. In this example, you have 4 hierarchy levels. The last level is a leaf and it also ends with the separator __. This would render like this:
1
2
3
4
 Allergies
    |- Female
      |- commercial
        |- asian (leaf)
  • separator: One or more characters that define the separation between the tree nodes
  • showHeaderControls: This property is a Boolean (true or false) and allows you to specify if you want to render the "Expand all" and "Collapse all" buttons at the top.

Note

  • The Tree Data Table automatically sorts the column specified in the field property ascending. Users can sort the remaining columns as needed.
  • When applying filters, you should programatically remove the treeConfig setting. Otherwise, filtering out parent nodes can leave the tree data table in an inconsistent state.

The Tree Raw Data Table demo provides a working code example.

Suppress movable

This setting allows you to block the movement of specific columns by sending an array of fields and their moving settings. You can also easily block the movement of all columns by setting suppressMovable to true.

1
2
3
4
5
6
7
8
9
// Block the movement of the column 1 and 3
.set('suppressMovable', [
    {field: 'column_1', movable: false},
    {field: 'column_2', movable: true},
    {field: 'column_3', movable: false},
])

// Block the movement of all columns
.set('suppressMovable', true)

Column pinning

This setting allows you to specify what columns are pinned and their pinning position, either left or right. Example:

1
2
3
.set('columnPinning', [
  { field: 'my_field', position:'left' }
])

Column filters

This option allows you to provide column filtering for table fields. To enable column filters, use the columnFilters setting and provide an array of objects where each object includes the field name and optionally the component name. Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.set('columnFilters', [
  { 
      field: 'company_code',
      component: 'slicer' ,
      props: {
          selectMode: 'single',
          limit: 15000
      },
      staticFilterFields: ['company_name', 'company_type']
  },
  { field: 'company_name' }
])

RDT MULTIFILTER

If you don't specify a component name, the Chartfactor Toolkit uses its out-of-the-box components depending on the field type:

  • The slicer filter component renders for ATTRIBUTE and INTEGER field types. Refer to the Slicer for a full description of its capabilites and settings.
  • The range filter component renders for NUMBER, MONEY, PERCENT field types. Refer to the Range Filter for a full description of its capabilites.
  • The datePicker filter component renders for TIME field types. Refer to the Time Range Picker for a full description of its capabilities. Note that you can change the granularity of the TIME attribute by using the props option to specify the "func" value as shown below:
1
2
3
.set('columnFilters', [
    { field: "saletime", component: "datePicker", props: {func: "YEAR"}},
])

Column Filter object properties

  • field: The name of the field to apply column filters
  • component: The name of the filter component. Out-of-the-box, available components are: slicer and range
  • customClass: The class to use in the column filter. Useful when you provide your own custom component. See the Custom component section for more details.
  • staticFilterFields: An array of strings specifying fields that should be considered as static filters when loading the column filter component
  • props: With this property you can pass settings to a column filter component. For example, for the slicer column filter component, you could set the selectMode as single. In addition, the slicer column filter component supports the limit setting to limit the available values. However, it does not support the noMerge setting as it internally uses client filters.

Note

  • You need to add the Interaction Manager component to your application to enable column filtering
  • Field names in Elasticsearch may include the .keyword suffix. Please check the index field definition and add this suffix to your field name if needed.

Custom component

If you want to implement your own filter component you just need to provide the name of the component and the component class:

1
2
3
.set('columnFilters', [
  { field: 'creation_year', component: 'myComponent', customClass: MyComponent},
])
RDT MULTIFILTER

The component you provide should follow the ag-grid filter component structure. Additionally, the ChartFactor Toolkit includes the following information in the init method params:

  • The provider of the RDT: params.colDef.filterProvider
  • The source of the RDT: params.colDef.filterSource
  • The field to apply the filter: params.colDef.fieldName
  • The props for the column filter component: params.colDef.fcProps
  • The element ID for the column filter component: params.colDef.columnFilterId. It is important to use this element ID for your column filter visualization (e.g. .element(params.colDef.columnFilterId)) for the Raw Data Table's getColumnFilterId() function to work properly.
  • The static filters that are already in the RDT: params.colDef.staticFilters. This is so that you can apply the same static filters to your column filter component.
  • An array of strings with the fields that should be considered as static filters: params.colDef.staticFilterFields. You can, for example, obtain the Interaction Manager current filters and apply them to your column filter component if they are specified in this property.

You can use these additional properties to create your own HTML and visualizations to include the column filters in the Interaction Manager. Example below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MyComponent {
    init(params) {
      this.elementID = params.colDef.columnFilterId;
      this.eGui = document.createElement('div');
      this.eGui.setAttribute('id', elementID);
      this.eGui.classList.add('test-range');


      setTimeout(() => {
        cf.provider(params.colDef.filterProvider)
          .source(params.colDef.filterSource)
          .metrics(cf.Metric(params.colDef.fieldName))
          .graph("Range Filter")
          .element(elementID)
          .execute();
      }, 500);

    }

    getGui() {
      return this.eGui;
    }

    getModel() {}

    setModel() {}
  }

For more information about the ag-grid filter component structure check this AG Grid Filter Components article. You can also check the Raw Data Table - Custom Column filter demo.

Column totals

This configuration allows you to show a row sticky to the bottom containing the aggregation of specific columns. The possible aggregation functions are the ones supported by your specific data provider (e.g. sum, avg, min, max, unique ). Example below:

1
2
3
4
.set('columnTotals', [
  {field:'fare', function: 'sum'},
  {field:'tips', function: 'sum'}
])

image

Please note the following: * The columnTotals configuration only supports numeric field types. They are INTEGER, NUMBER, MONEY, PERCENT. * Applying a filter to the raw data table will also recalculate its column totals

Header icons

This option allows you to render an icon for a column header instead of its field label. You can use Font Awesome and Google Material icons but it's also possible to use custom icons in formats like a URL, a Base64 encoded image, a PNG, SVG and other image formats.

To use Font Awesome or Google Material icons you need to have one of the following fonts installed in your project:

Header icon properties

  • Key: The key of each object is the name of the field in which you are going to use the icon: example: pricepaid: {...},
  • align: The raw data table uses css flex to align the header elements of each column
  • size: This is a css size. If you are using a Font Awesome or Google Material icon the size means the font-size of the icon. If you are using a custom icon the size means the width of the provided source (src)
  • color: The color works just for the Font Awesome or Google Material icons and you can use a css color format. Example: #f44336, rgb(244, 67, 54), etc.
  • tooltip: A single text that shows when you hover a column
  • icon: This is an object to specify the icon to render in the column header. It includes the following properties:
    • type: Specifies what kind of icon you want to use. Available values are:
      • fa - Font Awesome icon
      • material - Google Material icon
      • custom - Custom icon
    • src: This is used when you are using a custom icon and you can use formats like a URL, a Base64 code image, or an PNG, SVG or other image formats
    • name: This is used when you are using a font icon like Font awesome or Google material icons

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.set('headerIcons', {
    pricepaid: { // font awesome example 
        align: 'center',
        size: '15px',
        color: '#ffc107',
        icon: { type: 'fa', name: 'fas fa-dollar-sign' }, 
        tooltip: 'Price paid',
    },
    qtysold: { // url example
        align: 'center',
        size: '15px',
        color: '#4caf50',
        icon: { type: 'custom', src: 'https://chartfactor.com/doc/latest/img/dollar.png' },
        tooltip: 'Quantity sold',
    },
    cat_id: { // base 64 example
        align: 'center',
        size: '15px',
        color: '#4caf50',
        icon: { type: 'custom', src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANYAAACVCAYAAAAkLwTsAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAnqSURBVHhe7Z0hb1RbFIX5BxhkFaaykqS2BoXG1uCqqpFNarDYKgwSU4tCoXBNsHhUE9S8t+fdCaX9ute5c+bR7nvWl3zJy3qhc9Zkdmbmzj33PvmXlbV252Jore0TQ2ttnxhaa/vE0FrbJ4bW2j4xtNb2iaG1tk8MrbV9Ymit7RNDa22fGFpr+8RwtsfHx6vz8/PVhw8frC1pvH7jdUyv7y3EsNl3796trq+vV8YshXg9x+uaXu8zxLDJq6uraSnGLI9v377h675RDKXxoMYsnS9fvuDrv0EMU09OTqaHNWb5bPm9C8NUv1uZkdjyXQvDVGNG4ufPnzgHQgxTjRkNmgMhhqnGjAbNgRDDVGNGg+ZAiGGqMaNBcyDEMNWY0aA5EGKYasxo0BwIMUw1ZjRoDoQYphozGjQHQgxTjRkNmgMhhqnGjAbNgRDDVGNGg+ZAiGGqMaNBcyDEMLUib9++XZ2dnc3y/fv307+eT+xC3eYxd2FsMY8dsLH+i4uL9bbzjx8/rj5//rz6+vXr6sePH9MqTSs0B0IMUytCPZRHR0fTv57PlmdE/1UPDg5Wr1+/Xg/ip0+fVt+/f59Wb25Dz58Qw9SKUA/ly5cvp389nwqDdZ+xsS/e5fzO9ht6noQYplaEeihHHaybxrtafKQcfcjouRFimFoR6qH0YP1pPB/xPW1E6PkQYphaEeqh9GCxz58/Xx8MGQl6HoQYplaEeig9WLl7e3vr60GMAPUXYphaEeqh9GC1GQc7ln7RVuotxDC1ItRD6cGaZ/xGtlSorxDD1IpQD+VDDVYcidvGw8PD1atXr9bGf8d3oadPn+Jj/F/GD9JLhLoKMUytCPVQPtRgxb/dJfExLQ6XxxG9eOG/efMGH3dXnp6eTo+8HKinEMPUilAP5UMN1t/6zSjOtIhTn/b393EdPcbwLgnqKMQwtSLUQ7n0wbpJXN141+9kS3rnon5CDFMrQj2UIw3WhnjsHd4jav2OuASomxDD1IpQD+WIg7Wh4y4bd1zC2RrUS4hhakWoh3LkwQp+/fq1Pvud1jjXeD4qQ52EGKZWhHooRx+sDbGvjNY5x/gJoDLUSYhhakWoh9KD9ZvYs0VrnWPs+aoK9RFimFoR6qH0YP1JHOWj9c6xKtRFiGFqRaiH0oN1l9hVTWtutedyBw8JdRFimFoR6qH0YN2lp9fGilAPIYapFaEeSg8WE9+VaN2txrb/alAPIYapFaEeSg/W/fR8JIyTg6tBPYQYplaEeig9WPdzdXWFa2+12g3iqYMQw9SKUA+lBysnfpui9bdY7TxC6iDEMLUi1EPpwcrpPe2pErR+IYapFaEeSg+WhtbfaqUdx7R+IYapFaEeSg+WpueMjEpnvtP6hRimVoR6KD1Ymp6DGD2X8P7b0PqFGKZWhHooPVht9FxXI86grwCtXYhhakWoh9KD1UbPzuMqh91p7UIMUytCPZQerDbiqrjUo8UqV9SltQsxTK0I9VB6sNro+Z4Ve70qQGsXYphaEeqh9GC1Ed+TqEeLVQ5g0NqFGKZWhHooPVjtbHsAI/5dBWjtQgxTK0I9lB6sdnqujVHhyCCtW4hhakWoh9KD1U7PdTEq9KV1CzFMrQj1UHqw2omdwdSlRQ/WZEWoh9KD1U7P5scK5wzSuoUYplaEeig9WO3ERTmpS4sVLuhJ6xZimFoR6qH0YLXTs4Xk8vJy+iuPF1q3EMPUilAPpQernfg4R11arHC9QVq3EMPUilAPpQernTjnj7q0WOG0Jlq3EMPUilAPpQernZ7TmipctYnWLcQwtSLUQ+nBaiduYkddWvRgTVaEeig9WO3EmqlLixWujkvrFmKYWhHqofRgtdMzWBW26NO6hRimVoR6KD1Y7fR8FPRgTVaEeig9WO14sO6IYWpFqIfSg9VOz+F2D9ZkRaiH0oPVTs+ZFxcXF9NfebzQuoUYplaEeig9WO30nCvow+2TFaEeSg9WOzEc1KVFn3kxWRHqofRgtXN2doZdWvTZ7ZMVoR5KD1Y7Jycn2KXFCtcWpHULMUytCPVQerDa2d/fxy4tVuhL6xZimFoR6qH0YLVDPVq9vr6e/srjhdYtxDC1ItRD6cFqI9ZLPVr05c9uWBHqofRgtdFzvYu4bFoFaO1CDFMrQj2UHqw2ei59VuUeWbR2IYapFaEeSg9WG3EXfOrRYoVD7QGtXYhhakWoh9KDpen5fhVW6UprF2KYWhHqofRgaXou1BnvdFWg9QsxTK0I9VB6sDQ9HwNPT0+nv/L4ofULMUytCPVQerByei55Flb5fhXQ+oUYplaEeig9WDnHx8e4/lar3H84oPULMUytCPVQerDuJ9ZIa2817ltcCeogxDC1ItRD6cG6n577YYUVboRwE+ogxDC1ItRD6cFienYLh5WOBm6gHkIMUytCPZQerLv03G94Y4Udw7ehHkIMUytCPZQerLv0fgQMK0I9hBimVoR6KD1YfxLn9dF651hhGz5BXYQYplaEeig9WL+JKynRWud4cHAw/bV6UB8hhqkVoR5KD9Z/7OKdKow7klSF+ggxTK0I9VB6sFbr35tojXM9Pz+f/mJNqJMQw9SKUA/lyIMVvzM9e/YM1zfXFy9eTH+1LtRLiGFqRaiHcsTBisfe1bvUxgrXtFBQLyGGqRWhHsqRBiveoXrP/SMf08faHqibEMPUilAP5ZIHK37ojWGK7z67+sh327gDyVKgfkIMUytCPZSVBys+fsXfiRd3XBAztmjEpsS4PsXh4SE+7i5dyjvVBuooxDC1ItRD+VCDVdmjo6NFfKe6DXUVYphaEeqh9GDNs/oh9QzqK8QwtSLUQ+nBajMOp1f+8bcF6i3EMLUi1EPpwcrd29tbXV5eTo2XDfUXYphaEeqh9GCxsZ8qrn47EvQ8CDFMrQj1UHqw/jRu1VNt5++uoOdDiGFqRaiHcvTBihsWxOH5OFRf6cIv/wf0/AgxTK0I9VDG7z3bUm2wYktHbGKMM9ljkJb2O1Qv9JwJMUytSLxg4gfSOfZsIY/fcrZ5zF0Yjxu3Lr1tHA6P/x+bDWN44mOdB6gNmgMhhqnGjAbNgRDDVGNGg+ZAiGGqMaNBcyDEMNWY0aA5EGKYasxo0BwIMUw1ZjRoDoQYphozGjQHQgxTjRkNmgMhhqnGjAbNgRDDVGNGg+ZAiGGqMaNBcyDEMNWY0aA5EGKYOvoWAjMeNAdCDFPjclrGjEK83mkOhBimVrsxszE9bHnJbQylo27RNmMRr3N6/TeIYZP+SGiWzJYfATdi2GzsSPXBDLMkNru/6fU+QwxnG9dLiK3fsZ3d2orG63cXNy+fxNBa2yeG1to+MbTW9omhtbZPDK21fWJore0TQ2ttnxhaa/vE0FrbJ4bW2q19svoHitsvYTbscj0AAAAASUVORK5CYII='},
        tooltip: 'Quantity sold',
    },
})

image

Column statistics

This option allows you to render statistics for each table column so that users can quickly understand how column data is distributed. The type of visualization is driven by the field type and cardinality. To be efficient, each column statistic is rendered when it is visible depending on the user's horizontal scroll. The remaining column statistics are rendered as users scroll horizontally. Once a column statistic is loaded, no additional queries are made unless the user applies filters.

The column statistics widgets available are:

  • Unique counter: This is used for unique INTEGER and ATTRIBUTE field types
  • Histogram: This widget is used for INTEGER, NUMBER, MONEY and PERCENT field types
    • To specify the number of buckets or bars you can set the fixedBars property in the widget props
  • Slicer: This is used for ATTRIBUTE and INTEGER fields that are non-unique, and for TIME fields
    • The default number of rows is 3. This number is configurable through the limit property in the widgets props. Note that the number of rows to display is also limited by the height of the column stats (also configurable). The bigger the height of the statistics column, the more rows it can display.
    • For TIME fields, the granularity and the format of the datetime is calculated using the min and max of the dates in the column. You can also define the datetime granularity using the widget props array as shown in the example below. Time granularity defaulting rules are as follows:
      • YEAR: More than 25 years
      • MONTH: More than 12 months
      • DAY: More than 13 days
      • HOUR: More than 5 hours
      • MINUTE: Less than 5 hours

An example of the columnStats setting is below. Notice how the widgetProps property allows you to provide additional configurations to column statistics widgets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.set("columnStats", {
    enabled: true,
    height:70,
    widgetProps: [
        {
            field: 'trip_start_timestamp',
            props: {
                show: true, // if false the column stat is not going to be rendered, true by default
                granularity: 'DAY', // Useful just for TIME fields
                limit: 5 // For slicers means 5 rows, for histogram you need to use fixedBars for the number of buckets
            }
        }
    ]
})

image

Note

Rendering column statistics in your raw data table requires you to import the cft-standard-charts.min.js module in order for the histogram chart to be available. See the Chartfactor toolkit installation instructions for more details.

For a working example of a Column Statistics configuration you can check the Raw Data Table - Column Statistics Demo

Custom theme

If you'd like to change the theme and styles of the Raw Data Table you can refer to Table theme configuration

RDT functions

Sometimes, you may want to create an application that provides a UI to manage the table header, column filters, or even the table colors. The functions below allow you to do that.

Column stats functions

getColumnStatId(colName)

This functions returns the column stat visualization id for the provided column name, use this to handle the visualization in the column stat

Header functions

updateColumnHeader(headerName, newHeaderName, isGroup, groupPosition = undefined)

This function allows you to change the visible name of the column header in the grid

Params specification:

  • headerName: The name of the column to change. For Elasticsearch, the name can be with or without the .keyword suffix.

  • newHeaderName: The name to display in the header

  • isGroup: A Boolean to specify if the header name to update is for a group or field (group: true, field: false)

  • groupPosition: If you have more than one group with the same name you can specify what group you want to update by indicating its position, taking into account only groups and not columns. Example: If you have 5 groups and 3 of them have the same name like this: group_1, group_2, group_3, group_3, group_3 and you want to update the second group_3, you need to specify the position 3.

1
cf.getVisualization('my-rdt').get('updateColumnHeader')('company_name', 'Company name', false);

refreshHeader()

This function allows you to refresh the header of the Raw Data Table. This is useful when you change manually the ag-grid column definitions

1
cf.getVisualization('my-rdt').get('refreshHeader')();

Column functions

setSortable(column, sortable)

This function allows you to enable or disable the sort behaviour in a specific column

Params specification:

  • column: A string with the name of the column to hide or show

  • sortable: A boolean, if False the column will not be sortable, if True the column will be sortable

setColumnVisible(column, visible)

This function allows you to hide or show a column without deleting it.

Params specification:

  • column: A string with the name of the column to hide or show

  • visible: A boolean, if False the column will be hidden, if True the column will be showed

showColumnStat(column, show)

This function allows you to hide or show a specific column stat.

Params specification:

  • column: A string with the name of the column to hide or show

  • show: A boolean, if False the column stats will be removed, if True the column will be showed and re-rendered

refreshColumnStats()

This function allows you to refresh the column statistics row if it is enabled. This is useful when you are playing directly with ag-grid functions and you need to refresh column statistics so that they are not left in a loading state.

autosizeColumn(column, ignoreWidthDefinition = false, colDef = undefined)

This function allows you to auto-size the specified column according to its content

Params specification:

  • column: A string with the name of the column to auto-size

  • ignoreWidthDefinition: A boolean, if False the columnsWidth configuration will be ignored, False by default

  • colDef: Ag-grid colDef object if you specified this the colDef object will be updated with the property autoResized in True, this is useful when you need to know if a column is auto-sized, undefined by default

moveColumnTo(columnName, toIndex, isGroup = false, refreshGrid = true)

Moves the specified column or group to the target index

Params specification:

  • columnName: A string with the name of the column or group to move

  • toIndex: An integer with the target index starting from 0. To specify the index to move a column or group, it is necessary to consider the position of the columns in the table, not the position of the group.

  • isGroup: A boolean to specify if the function is moving a column or a group. By default this parameter is false

  • refreshGrid: A boolean to specify if you want to refresh the table header with the new changes. By default this parameter is true. Using false in this param is useful in special cases where you need to update the visualization field definitions and not the table. You can update the table later with the function reCreateColumnDefs()

1
2
3
4
5
// Moving a column to another position:
cf.getVisualization('my-rdt').get('moveColumnTo')('myColumn', 2);

// Moving a group to another position:
cf.getVisualization('my-rdt').get('moveColumnTo')('My group', 0, true);

reCreateColumnDefs()

Refreshes the column definitions. This is useful in some special cases where you update the visualization field definitions, and then you need to render those changes in the table.

1
cf.getVisualization('my-rdt').get('reCreateColumnDefs')();

joinGroup(column, groupName, position = undefined)

This function inserts the specified field into the specified group. If the group doesn't exist it creates the group.

Params specification:

  • column: A string with the name of the column to insert in the group

  • groupName: A string with the name of the group to join

  • position: An integer with the index within the group. If this parameter is specified the field will take that position within the group. undefined by default

1
cf.getVisualization('my-rdt').get('joinGroup')('myColumn', 'Target group');

leaveGroup(column, position = undefined)

This function allow you to remove a field from a group and put it in the main field list

Params specification:

  • column: A string with the name of the column to remove from the group

  • position: An integer with the new position for the field. If this parameter is not specified the field will be placed in front of the group.

1
cf.getVisualization('my-rdt').get('leaveGroup')('myColumn', 0);

Column Filter functions

getColumnFilterSupport()

This function allows you to obtain an array with all column filter components available for the supported field types. This is useful when you want to provide your users with a choice of column filter component (e.g. a slicer vs. a range filter for integer values). Example below.

1
cf.getVisualization('my-rdt').get('getColumnFilterSupport')();

getColumnFilterId(field)

This function allows you to get the element ID dynamically assigned to the column filter component of a specific field. This is useful when you want to programatically obtain the Aktive object of this specific component. The parameter is the field name of the column.

1
cf.getVisualization('my-rdt').get('getColumnFilterId')('my-field');

addColumnFilters(columnFilters, refresh)

This function allows you to enable the column filters for the columns that you specify without reloading the Raw Data Table

Params specification:

  • columnFilters: An array with the field and component for the column filter be added, the prop uses the same structure of the columnFilters definition

  • refresh: This prop receives a Boolean that indicates if you want to refresh the grid header or not (refresh only the header not the entire visualization)

1
2
3
4
5
6
const columnFilters = [
    {field: 'company_code'},
    {field: 'company_name', component: 'slicer'}
];

cf.getVisualization('my-rdt').get('addColumnFilters')(columnFilters, true);

removeColumnFilter(colName, refresh)

This function allows you to remove a specific column filter form the Raw Data Table

Params specification:

  • colName: The name of the column that you want to delete, with or without the .keyword suffix

  • refresh: This prop receives a Boolean that indicates if you want to refresh the grid header or not (refresh only the header not the entire visualization)

1
cf.getVisualization('my-rdt').get('addColumnFilters')('company_code', true);

Color functions

setColorTheme(cfColor)

This function allows you to change the color theme of the Raw Data Table

Params specification:

  • cfColor: The Color object provided for the toolkit cf.Color()
1
2
3
4
5
6
7
let color = cf.Color();
color.theme({
    'headerStyle': 'background: #607d8b; color: #fff; font-size: 16px;',
    'headerIconStyle': 'color: #fff; font-size: 16px;'
});

cf.getVisualization('my-rdt').get('setColorTheme')(color, false);

RDT Events

The RDT triggers the following events:

sort-changed

This event fires when the header of the columns are clicked to change the sort. The event received provides information about the sort model used:

1
2
3
4
5
6
7
8
9
.on('sort-changed', event => {
    console.log(event.data)

    /* [
        {colId: "catgroup", sort: "desc"},
        {colId: "catname", sort: "asc"}
       ]
     */
})

rdt:data-updated

This one is triggered when new data is received and is ready to be displayed in the columns. New data refers to the initial data loaded and subsequent request triggered by the RDT infinite scrolling.

1
2
3
4
5
.on('rdt:data-updated', event => {
    event.name // rdt:data-updated
    event.chart // The id of the RDT dom element 
    event.data // An array with the rows received
})

rdt:columnMoved

This event is triggered when a column is moved to a different position. Example:

1
2
3
4
5
.on('rdt:columnMoved', event => {
    event.name // rdt:columnMoved
    event.chart // The id of the RDT dom element 
    event.data // The event object proveided by ag-grid when a column is moved
})

rdt:dragStopped

This event is triggered when the column dragging event finishes.

1
2
3
4
5
.on('rdt:dragStopped', event => {
    event.name // rdt:dragStopped
    event.chart // The id of the RDT dom element 
    event.data // The event object proveided by ag-grid when a column is moved
})

rdt:col-stats-rendered

This event is triggered when the column statistics cells are rendered in the DOM. It is triggered on the first load of the Raw Data Table and when new columns are coming to the scroll viewport.

1
2
3
4
5
.on('rdt:col-stats-rendered', event => {
    event.name // rdt:col-stats-rendered
    event.chart // The id of the RDT dom element 
    event.data // The origin of the update
})

rdt:columnPinned

This event is triggered when a column is pinned by dragging and dropping the column to the left or right.

1
2
3
4
5
.on('rdt:columnPinned', event => {
    event.name // rdt:columnPinned
    event.chart // The id of the RDT dom element 
    event.data // The event object proveided by ag-grid when a column is moved
})