AdapTable Version:
Framework:
Summary
- Most charting users access the charts provided by AG Grid
- However AdapTable can work with any charting library
AdapTable integrates closely with AG Grid's charts, and is the most common charting use case.
But AdapTable can be used in conjunction with any charting library.
AdapTable's rich Adaptable API and the many Adaptable Events make it easier to synchronise data in the Grid with your preferred Charting library.
Feedback
- We are keen to add additional support for external charting and to meet all use cases
- So please contact us if there is specific functionality that you would like us to make available
- This demo shows how to use the Highcharts Charting library from AdapTable
- From any valid selection (one string and one numeric) column we are able to use the Context Menu to create 3 different chart types:
- Pie Chart
- Line Chart
- Bar Chart
Try It Out
- Select a range that includes a numeric and a string column (we pre-select a range using the Grid API)
- Create a Highchart by selecting
Show Chartsfrom the Context Menu (the first item, and only enabled if there is a valid selection) and choose a Chart type
import { AdaptableOptions, ContextMenuContext, CustomContextMenuContext, SelectedCellInfo, UserContextMenuItem, } from '@adaptabletools/adaptable'; import {WebFramework} from './rowData'; import {chartIcon, pieIcon, lineChartIcon, barChartIcon} from './icons'; import {charginService} from './chartingService'; /** * Selection is valid only when: * - two columns are selected * - one is numeric and the other text */ const isSelectionValidForSimpleCharts = (selection: SelectedCellInfo) => { // Two columns need to be selected if (selection.columns.length !== 2) { return false; } // At least one is numeric const oneColumnIsNumeric = selection.columns.filter(column => column.dataType === 'number').length === 1; if (!oneColumnIsNumeric) { return false; } // At least one text const oneColumnIsText = selection.columns.filter(column => column.dataType === 'text').length === 1; if (!oneColumnIsText) { return false; } return true; }; const contextMenuOptions: AdaptableOptions['contextMenuOptions'] = { customContextMenu: (context: CustomContextMenuContext) => { const {defaultAgGridMenuStructure, defaultAdaptableMenuStructure} = context; const chartMenuItem: UserContextMenuItem = { menuType: 'User', label: 'Show Charts', icon: { element: chartIcon, }, subMenuItems: [ { menuType: 'User', label: 'Pie Chart', icon: {element: pieIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); charginService.showPieChart(selection); }, }, { menuType: 'User', label: 'Line Chart', icon: {element: lineChartIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); charginService.showLineChart(selection); }, }, { menuType: 'User', label: 'Bar Chart', icon: {element: barChartIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); charginService.showBarChart(selection); }, }, ], }; return [ chartMenuItem, '-', ...defaultAgGridMenuStructure, '-', ...defaultAdaptableMenuStructure, ]; }, }; export const adaptableOptions: AdaptableOptions<WebFramework> = { primaryKey: 'id', adaptableId: 'Using External Charts', contextMenuOptions, initialState: { Dashboard: { Tabs: [ { Name: 'Charting', Toolbars: ['Layout'], }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'github_watchers', 'language', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], AutoSizeColumns: true, }, ], }, }, };
Saving Charts
External charts can also be saved into Adaptable State.
Similar to the configuration for AG Grid Charts, External Charts can be:
- defined in Initial Adaptable State (i.e. configured at design-time)
- created at run-time and then saved into State to be available when the application restarts
- be displayed in custom locations provided by the users
- This example shows how External Charts can be saved into Adaptable State and then displayed in AdapTable
- 2 external (Highcharts) charts are defined in Initial Adaptable State:
- Github Stars Line Chart
- Frameworks Pie
- 2 custom Charting Containers are defined in Charting Options:
- Above Grid
- Below Grid
Try It Out
- In the Charting Toolbar select an External Chart and a Container
- Click the
Show Chart(Eye icon) button to display / hide the Charts
import { AdaptableOptions, ContextMenuContext, CustomContextMenuContext, SelectedCellInfo, UserContextMenuItem, } from '@adaptabletools/adaptable'; import {WebFramework} from './rowData'; import {chartIcon, pieIcon, lineChartIcon, barChartIcon} from './icons'; import {ChartingService, ChartModel} from './chartingService'; const chartingService = new ChartingService(); /** * Selection is valid only when: * - two columns are selected * - one is numeric and the other text */ const isSelectionValidForSimpleCharts = (selection: SelectedCellInfo) => { // Two columns need to be selected if (selection.columns.length !== 2) { return false; } // At least one is numeric const oneColumnIsNumeric = selection.columns.filter(column => column.dataType === 'number').length === 1; if (!oneColumnIsNumeric) { return false; } // At least one text const oneColumnIsText = selection.columns.filter(column => column.dataType === 'text').length === 1; if (!oneColumnIsText) { return false; } return true; }; const contextMenuOptions: AdaptableOptions['contextMenuOptions'] = { customContextMenu: (context: CustomContextMenuContext) => { const {defaultAgGridMenuStructure, defaultAdaptableMenuStructure} = context; const chartMenuItem: UserContextMenuItem = { menuType: 'User', label: 'Show Charts', icon: { element: chartIcon, }, subMenuItems: [ { menuType: 'User', label: 'Pie Chart', icon: {element: pieIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); const chartModel = chartingService.showPieChart(selection); menuContext.adaptableApi.chartingApi.addExternalChartDefinition({ Name: 'Pie Chart', Data: chartModel, }); }, }, { menuType: 'User', label: 'Line Chart', icon: {element: lineChartIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); const chartModel = chartingService.showLineChart(selection); menuContext.adaptableApi.chartingApi.addExternalChartDefinition({ Name: 'Chart-Name', Data: chartModel, }); }, }, { menuType: 'User', label: 'Bar Chart', icon: {element: barChartIcon}, onClick: (menuContext: ContextMenuContext) => { const selection = menuContext.adaptableApi.gridApi.getSelectedCellInfo(); const chartModel = chartingService.showBarChart(selection); menuContext.adaptableApi.chartingApi.addExternalChartDefinition({ Name: 'Pie Chart', Data: chartModel, }); }, }, ], }; return [ chartMenuItem, '-', ...defaultAgGridMenuStructure, '-', ...defaultAdaptableMenuStructure, ]; }, }; const chartingOptions: AdaptableOptions['chartingOptions'] = { chartContainers: [ { name: 'Above Grid', element: 'demoOutputAbove', }, { name: 'Below Grid', element: 'demoOutputBelow', }, ], externalChartingOptions: { /** * This indicates to Adaptable if a chart is rendered or not. * This status is used to call the corect handlers when showing/hiding a chart. */ isChartOpened: ({adaptableApi, chartDefinition}) => { const chartModel = chartDefinition?.Data as ChartModel; return chartingService.isChartOpened(chartModel.chartId); }, /** * This is called when the user clicks the eye button next to the chart. */ onHideChart: ({adaptableApi, chartDefinition}) => { const chartModel = chartDefinition.Data as ChartModel; chartingService.destroyChart(chartModel.chartId); }, /** * This is called when the user clicks the eye button next to the chart. */ onShowChart: ({adaptableApi, chartDefinition, container}) => { const chartModel = chartDefinition.Data as ChartModel; chartingService.restoreChart(chartModel, container?.element); }, /** * This is called when the user deltes a chart from from adaptable. * We may want to hide the chart when it is deleted. */ onDeleteChart: ({adaptableApi, chartDefinition}) => { const chartModel = chartDefinition.Data as ChartModel; if (chartingService.isChartOpened(chartModel.chartId)) { chartingService.destroyChart(chartModel.chartId); } }, /** * Preview charts are transient charts, these charts should not be saved in state. * They are rendered in preivews. * * The returned object is passed to 'onHideChart'. * The returned object needs to have enough information to identify the instance of the chart. * This is important because we want to destory the chart when the preview is closed. */ onPreviewChart: ({adaptableApi, chartDefinition, container}) => { const chartModel = chartDefinition.Data as ChartModel; return { Name: 'Preview Chart', Data: chartingService.previewChart(chartModel, container?.element), }; }, }, }; export const adaptableOptions: AdaptableOptions<WebFramework> = { primaryKey: 'id', adaptableId: 'Saving External Charts', contextMenuOptions, chartingOptions, initialState: { Dashboard: { Tabs: [ { Name: 'Charting', Toolbars: ['Charting'], }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'github_watchers', 'language', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], AutoSizeColumns: true, }, ], }, Charting: { ExternalChartDefinitions: [ { Name: 'Github Stars Line chart', Data: { options: { chart: { type: 'line', }, title: { text: 'Dynamic Simple Line Chart', align: 'left', }, yAxis: { title: { text: 'Name', }, }, xAxis: { categories: [ 'react', 'angular', 'vue', 'svelte', 'alpine', 'lit', 'stimulus', 'ember.js', 'stencil', ], }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle', }, plotOptions: { series: { label: { connectorAllowed: false, }, }, }, series: [ { name: 'Name and GitHub Stars', data: [ 179429, 78348, 191435, 53935, 19338, 9752, 11049, 22093, 9884, ], }, ], responsive: { rules: [ { condition: { maxHeight: 300, }, chartOptions: { legend: { layout: 'horizontal', align: 'center', verticalAlign: 'bottom', }, }, _id: 'highcharts-c73e53c-14', }, ], }, }, chartId: 'CHART_ID_1696840189274', }, Uuid: '80da73bd-75e4-4371-a7f9-7ba518cb9113', }, { Name: 'Frameworks Pie chart', Data: { options: { chart: { plotBackgroundColor: null, plotBorderWidth: null, plotShadow: false, type: 'pie', }, title: { text: 'Dynamic Simple Pie Chart', align: 'left', }, tooltip: { pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>', }, accessibility: { point: { valueSuffix: '%', }, }, plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', dataLabels: { enabled: true, format: '<b>{point.name}</b>: {point.percentage:.1f} %', }, }, }, series: [ { name: 'Name', colorByPoint: true, data: [ { name: 'angular', y: 78348, }, { name: 'vue', y: 191435, }, { name: 'svelte', y: 53935, }, { name: 'alpine', y: 19338, }, { name: 'lit', y: 9752, }, { name: 'stimulus', y: 11049, }, { name: 'ember.js', y: 22093, }, { name: 'stencil', y: 9884, }, { name: 'solid', y: 13119, }, ], }, ], }, chartId: 'CHART_ID_1696840216341', }, Uuid: '19f72754-c322-4b23-b4f5-2fca05a0132b', }, ], }, }, };
Framework: