Skip to main content

Make a custom chart interactive

Knowledge Checkpoint

A grasp of these concepts will help you understand this documentation better:

Custom charts can support the same interactions as Holistics's built-in charts:

How interactions work

Enabling an interaction takes two steps:

  1. Declare what your chart accepts, in Selections
  2. Wire it to a Holistics feature, via holisticsConfig

Selections

Selections declare what a user can do, such as clicking a data point or dragging to select a range. You define them with Vega-Lite params. Vega-Lite calls a selection a signal.

A selection is either point-based or interval-based.

  • Point selection (click). A point selection fires when a user clicks a single value (left click), or selects several values (hold Shift and left click). To deselect, the user clicks a selected value again. Read more in the Vega-Lite selection docs.

    Point selection highlighting a value on a bar chart
  • Interval selection (drag). An interval selection fires when a user holds left click and drags across a range of values. To deselect, the user double-clicks anywhere on the chart.

holisticsConfig

This property wires those selections to Holistics features.

Two fields matter:

For the full property reference, see holisticsConfig and params.

Interaction examples

Each example below starts from a working chart and adds one interaction. The full, copy-ready code for each one lives in the Custom Chart Library.

Highlight selected columns on point selection

Outcome. When a user selects one or more columns, those columns stay fully visible while the rest fade out. On hover, a stroke outlines the column.

  1. In your template, declare two point selections in params: one that fires on click, and one that fires on hover.

    template: @vgl {
    ...
    "params": [
    // effective only while the user hovers
    { "name": "pointSelectionOnMouseOver", "select": {"type": "point", "on": "mouseover"} },
    // effective when the user clicks
    { "name": "normalPointSelection", "select": "point" }
    ]
    ...
    }
  2. Add a fillOpacity rule so selected columns keep full opacity while the rest fade.

    template: @vgl {
    ...
    "mark": {
    "fill": "#484848" // base color of the columns
    },
    "encoding": {
    "fillOpacity": {
    // selected columns stay fully visible
    "condition": {"param": "normalPointSelection", "value": 1},
    // unselected columns fade to 30%
    "value": 0.3
    }
    }
    ...
    }
  3. Try it. Click a single column, then select a range by holding Shift and clicking. The selected columns should stay highlighted.

    Selected columns highlighted while the others fade out
  4. Add a strokeWidth rule so hovered columns get a light stroke and selected columns get a bolder one.

    template: @vgl {
    ...
    "mark": {
    "fill": "#484848",
    "stroke": "black" // stroke color
    },
    "encoding": {
    "strokeWidth": {
    "condition": [
    // bolder stroke (2) on selected columns
    { "param": "normalPointSelection", "empty": false, "value": 2 },
    // light stroke (1) on hovered columns
    { "param": "pointSelectionOnMouseOver", "empty": false, "value": 1 }
    ],
    "value": 0 // no stroke by default
    }
    }
    ...
    }
  5. Try selecting and hovering again. You should see a light stroke on hovered columns and a bolder stroke on selected ones.

    Light stroke on hovered columns and a bolder stroke on selected columns

Full code example: Highlight stroke effect on point selection.

Cross-filter on point selection

Outcome. When a user selects data on your chart, a cross filter for that selection is applied to every widget in the dashboard.

Prerequisite: a chart with a point selection declared. The highlight example above is a good starting point.

  1. In your template, declare a point selection in params.

    template: @vgl {
    ...
    "params": [
    // effective when the user clicks
    { "name": "normalPointSelection", "select": "point" }
    ]
    ...
    }
  2. Add a holisticsConfig field with crossFilterSignals, and list the point selection from step 1.

    template: @vgl {
    ...
    "holisticsConfig": {
    "crossFilterSignals": ["normalPointSelection"]
    }
    ...
    }
  3. Try it. Click a single column, or select a range with Shift and click. A cross filter should be created and applied to the other reports in your dashboard.

Full code example: Cross Filter on point selection.

Cross-filter on interval selection

Outcome. When a user drags to select an interval on your chart, a cross filter for that range is applied to every widget in the dashboard.

Prerequisite: a working custom chart you can add a selection to.

  1. In your template, declare an interval selection in params.

    template: @vgl {
    ...
    "params": [
    {
    "name": "intervalSelection",
    "select": {"type": "interval", "encodings": ["x"]}
    }
    ]
    ...
    }
  2. Add a holisticsConfig field with crossFilterSignals, and list the interval selection from step 1.

    template: @vgl {
    ...
    "holisticsConfig": {
    "crossFilterSignals": ["intervalSelection"]
    }
    ...
    }
  3. Try it. Hold left click and drag across a range of values. A cross filter should be created and applied to the other reports in your dashboard.

Full code example: Cross Filter on interval selection.

Cross-filter all sub-charts in a combo chart

Outcome. A selection on a combo (mixed) chart applies the cross filter to every sub-chart in the layer, not just the one the user interacted with.

Prerequisite: a combo chart built with a Vega-Lite layer. See Cross Filter on sub-charts in a combo chart for how to build one.

  1. In your template, find the sub-chart in the layer array that the cross filter should also apply to.

    template: @vgl {
    ...
    "layer": [
    // your bar chart definition
    { ... },
    // your line chart definition (the one we'll filter)
    { ... }
    ]
    ...
    }
  2. Add a transform to that sub-chart with a filter that takes the user's selection as its param.

    template: @vgl {
    ...
    "layer": [
    { ... }, // your bar chart definition
    {
    "transform": [
    // filter this sub-chart by the user's interval selection
    { "filter": {"param": "intervalSelection"} }
    ]
    // ...the rest of the sub-chart definition
    }
    ]
    ...
    }
  3. Create a cross filter on your dashboard and confirm the sub-chart updates along with the rest.

Full code example: Cross Filter on sub-charts in a combo chart.

Open the context menu on point selection

Prerequisite: a chart you can add a selection to (see the cross-filter example).

The context menu opens on right-click, so it must read the point currently under the cursor. That means it needs a hover selection, not the click selection you use for Cross Filter. (A click selection has no target on right-click unless the user left-clicks the point first, which would also cross-filter.)

  1. In your template, declare a hover point selection in params. The "on": "mouseover" trigger makes it track whichever point the cursor is over.

    template: @vgl {
    ...
    "params": [
    { "name": "hoverPointSelection", "select": {"type": "point", "on": "mouseover", "clear": "mouseout"} }
    ]
    ...
    }
  2. Add a holisticsConfig field with contextMenuSignals, and list the hover selection from step 1.

    template: @vgl {
    ...
    "holisticsConfig": {
    "contextMenuSignals": ["hoverPointSelection"]
    }
    ...
    }

Steps 1–2 wire up the whole context menu at once, so every option below needs them. What each option needs on top of that:

Drill-through

Outcome. Right-clicking a data point opens Drill-through in the context menu.

Prerequisite: at least one dimension field. Drill-through passes dimension values as filters to the target dashboard, so a chart with no dimensions has nothing to drill with.

Additional setup: none.

Date-drill

Outcome. Right-clicking a data point opens Date-drill in the context menu.

Prerequisite: a date or datetime dimension field. Date-drill changes the time granularity of that field, so the chart needs a date field to drill on.

Additional setup: none.

View underlying data

Outcome. The context menu's View underlying data option resolves the full data row behind the point you right-clicked.

Prerequisite: none beyond steps 1–2 above.

Additional setup: widen the selection's fields array to include at least 1 measure/metric and 1 dimension. Otherwise Holistics can't resolve the full underlying row:

template: @vgl {
...
"params": [
{
"name": "hoverPointSelection",
"select": {
"type": "point",
"fields": [@{fields.category.name}, @{fields.value.name}], // include the metric field
"on": "mouseover",
"clear": "mouseout"
}
}
]
...
}

If that selection is already scoped to one field for another purpose and you don't want to widen it, declare a second selection with the full field list instead, and list both signal names in contextMenuSignals.


Open Markdown
Let us know what you think about this document :)