AG Studio: Build dashboards using native components in web apps. Join us for a webinar on 28th July at 2pm UTC+1 Register

JavaScript ChartsContext Menu

Version 14.1.0
Enterprise

The Context Menu provides context-aware interactions with the chart elements.

In this example:

  • Right clicking anywhere on the chart shows the Context Menu with the option to download the chart.
  • Right clicking on a legend item will show the Context Menu with additional options to toggle series visibility.

The Context Menu is enabled by default, to disable set contextMenu.enabled to false.

{
    contextMenu: {
        enabled: false,
    },
}

Built-in Items Copy Link

The Context Menu displays default items based on the right-clicked element.

The contextMenu.items array accepts special string values to conveniently reconfigure these defaults.

{
    contextMenu: {
        items: [
            'defaults', //all the default menu-items in the pre-determined order.
            'separator', // a non-interactive horizontal line.
            'toggle-series-visibility', // used for legend items.
            'toggle-other-series', // used for legend items in multi-series charts.
            'zoom-to-cursor', // used with zoom.
            'pan-to-cursor', // used with zoom.
            'reset-zoom', // used with zoom.
            'download',
        ],
    },
}

In this example:

  • The "Custom Order" button reorders the default built-in Menu Items and adds separators.
  • The "Default Order" button resets the Menu Items to the default ['defaults'] value.

These string values can be used in combination with Custom Actions.

Custom Actions Copy Link

The Context Menu's custom actions can be used to run arbitrary functions based on the element that is right-clicked.

Use the showOn property to specify when a custom item should be shown:

  • always - shown regardless of what was clicked.
  • axis - shown when right-clicking an axis.
  • caption - shown when right-clicking a caption (title, subtitle, footnote).
  • cross-line - shown when right-clicking a Cross Line's line or fill.
  • series-area - shown when right-clicking anywhere within the series area bounds.
  • series-node - shown when right-clicking a datum node.
  • legend-item - shown when right-clicking a legend item.

If there are multiple elements that match the showOn value, all of them are shown in the Context Menu.

{
    contextMenu: {
        items: [
            'defaults',
            'separator',
            {
                showOn: 'always',
                label: 'Say hello',
                action: () => console.log('Hello world!'),
            },
            'separator',
            {
                showOn: 'axis',
                label: 'Say hello to an axis',
                action: (ev) => console.log(`Hello in axis "${ev.axisId}":"`, ev),
            },
            {
                showOn: 'series-area',
                label: 'Say hello in the series area',
                action: () => console.log('Hello in the series area!'),
            },
            'separator',
            {
                showOn: 'series-node',
                label: 'Say hello to a node',
                action: ({ datum, yKey }) => console.log(`Hello ${yKey} in ${datum.month}!`),
            },
            //...more custom actions for legend items, captions, etc.
        ],
    },
}

In this configuration:

  • A single custom action is added for the entire chart, the captions, the axes, the series area, the series node and the legend items.
  • Multiple entries per showOn element can be specified within the array if required.
  • Right clicking on one of these areas will show these additional actions in the Context Menu.
  • Clicking these extra actions will display information in the console, demonstrating that the action is aware of details about the right-clicked item.

To add Sub-Menus to the Context Menu, simply use the items property recursively.

{
    contextMenu: {
        items: [
            'download',
            {
                showOn: 'series-area',
                label: 'Zoom Controls',
                items: ['zoom-to-cursor', 'pan-to-cursor', 'reset-zoom'],
            },
            {
                showOn: 'legend-item',
                label: 'Legend Controls',
                items: ['toggle-series-visibility', 'toggle-other-series'],
            },
            'separator',
            {
                label: 'Debug Console',
                items: [
                    {
                        showOn: 'always',
                        label: `On 'always'`,
                        action: () => console.log(`On 'always' clicked.`),
                    },
                    {
                        showOn: 'axis',
                        label: `On 'axis'`,
                        action: (ev) => console.log(`On 'axis' clicked -`, ev.axisId, ev),
                    },
                    {
                        showOn: 'caption',
                        label: `On 'caption'`,
                        action: ({ captionType, text }) =>
                            console.log(`On 'caption' clicked -`, captionType, text),
                    },
                    {
                        showOn: 'series-area',
                        label: `On 'series-area'`,
                        action: () => console.log(`On 'series-area' clicked.`),
                    },
                    {
                        showOn: 'series-node',
                        label: `On 'series-node'`,
                        action: ({ datum, xKey, yKey }) =>
                            console.log(`On 'series-node' clicked -`, yKey, datum[xKey], datum[yKey]),
                    },
                    {
                        showOn: 'legend-item',
                        label: `On 'legend-item'`,
                        action: ({ itemId }) => console.log(`On 'legend-item' clicked -`, itemId),
                    },
                ],
            },
        ],
    },
}

In this configuration:

  • The built-in Zoom and Legend menu items are placed into Sub-Menus.
  • An additional "Debug Console" Sub-Menu is added with custom actions to log events to the console.

Dynamic Items Copy Link

The getItems callback can be used to implement Dynamic Context Menus. This is typically used to write Menu Items that depend on underlying state or data in some way.

{
    contextMenu: {
        getItems: (params) => {
            if (params.showOn === 'series-node') {
                const xName = params.datum[params.xKey];
                return [
                    'defaults',
                    'separator',
                    // Dynamic Context Menu Item
                    {
                        type: 'action',
                        showOn: 'series-node',
                        label: `Log Datum "${params.seriesId} - ${xName}"`,
                        action: () => console.log(params.datum),
                    },
                ];
            }
        },
    },
}

In this example:

  • The Context Menu on Bar Nodes includes a console Log Datum Menu Item, whose text is dynamically derived from the Context Menu Event parameters.
  • The getItems params includes a showOn property which indicates which element type was right-clicked, alongside relevant information about the clicked element.
  • If there are multiple elements at the same click point, the allShowOnParams array on the getItems params provides the parameters for every element, not just the winning one.

Example: Interactive Customisation Copy Link

The getItems callback can be used to change the state or appearance of a data point or series.

{
    contextMenu: {
        getItems: (params) => {
            if (params.showOn === 'series-node') {
                const { seriesId } = params;
                const year = String(params.datum[params.xKey]);
                const yKey = params.yKey;
                const isEmphasised = emphasisedPoints.has(pointKey(seriesId, year));
                return [
                    {
                        type: 'action',
                        showOn: 'series-node',
                        label: `${isEmphasised ? 'Remove Emphasis from' : 'Emphasise'} "${year}" Point`,
                        action: () => toggleEmphasis(seriesId, year),
                    },
                    {
                        type: 'action',
                        showOn: 'series-node',
                        label: `Remove "${year}" Point`,
                        action: () => removeDataPoint(year, yKey),
                    },
                ];
            }
            if (params.showOn === 'legend-item') {
                const { seriesId } = params;
                return [
                    'toggle-series-visibility',
                    {
                        type: 'action',
                        showOn: 'legend-item',
                        label: `Remove "${seriesId}"`,
                        action: () => removeSeries(seriesId),
                    },
                    // A submenu of colour options
                    {
                        showOn: 'legend-item',
                        label: `Colour "${seriesId}"`,
                        items: seriesColors.map((color) => ({
                            type: 'action',
                            showOn: 'legend-item',
                            label: color.label,
                            action: () => colorSeries(seriesId, color.value),
                        })),
                    },
                ];
            }
        },
    },
}

In this example, right-clicking a data point shows custom actions for that point:

  • "Emphasise" enlarges the marker and displays the value; triggering it again removes the emphasis.
  • "Remove Point" sets the point's value to null, leaving a gap in the line.

Right-clicking a legend item shows actions for the whole series:

  • The built-in toggle-series-visibility item hides or shows the series.
  • "Remove Series" drops the series.
  • "Colour" is a submenu of preset colours; selecting one recolours the series' line and markers.

API Reference Copy Link