Data Visualization
An overview of integrating Highcharts with Paste's data visualization components, including setup, licensing, and chart context.
In progress
As our current data visualization offerings are in progress these documents are subject to change. We will revise and expand these pages when new features are supported.
Our charting components are designed to work seamlessly with Highcharts. However, due to licensing restrictions, we cannot include Highcharts directly in our library. This limitation creates challenges when developing components for a library we cannot directly interact with.
To address this, we have created components and wrappers that simplify the Highcharts API. These tools expose various props, allowing you to configure charts through a streamlined and user-friendly interface. The props are transformed into objects that Highcharts can interpret, and our components automatically apply styles to the charts for a consistent appearance on a chart type bases. Global styles will be set in the BaseChart
using our existing hook.
Paste does not provide a license for Twilio usage. Licenses are acquired on an applicaiton level. If you are developing in one of our existing products it is highly likely licenses are already purchased. If you are creating a new application you may need to acquire a new license. If you need further information you can reach out to us via GitHub discussions or the Procurement team.
To ensure our components function correctly, some initial configuration is required in your project. This seciton will cover:
- Storing and retrieving rendered chart objects.
- Adding any additional modules required for additional functionality such as gauges, exporting etc.
You will need to include a component that retrieves the chart configuration from our ChartProvider's context and passes it to Highcharts. This component must also capture the rendered chart and store it in the Chart Provider context.
Storing the rendered chart is essential for several reasons. It allows us to determine the positioning of elements relative to the screen, enabling the placement of components like tooltips. Additionally, it facilitates triggering update functions on the chart for interactions such as zooming or toggling the visibility of series through a legend component.
We recommend copying the below code and creating an instance of it in your application to use with our components. This component is designed to be reused across all charts. You do not need a new instance of this component for each chart.
Modules subject to change
As we expand our supported charts you will need to maintain this file to include any required modules for the new charts or functionality of our components to work correctly. The change will look like the following:
applyPasteHighchartsModules(Highcharts, HighchartsAccessibilityModule);
applyPasteHighchartsModules(Highcharts, HighchartsAccessibilityModule, HighchartsSankeyModule, ...);
import { ChartContext } from "@twilio-paste/core/chart-provider";
import { Box } from "@twilio-paste/core/box";
import { applyPasteHighchartsModules, usePasteHighchartsTheme } from "@twilio-paste/core/data-visualization-library";
import * as Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import HighchartsAccessibilityModule from "highcharts/modules/accessibility";
import * as React from "react";
const Chart: React.FC = () => {
// Load the accessibility module and any other modules you need.
applyPasteHighchartsModules(Highcharts, HighchartsAccessibilityModule);
const chartRef = React.useRef<HTMLElement | null>(null);
const { options, setChart, setChartRef } = React.useContext(ChartContext);
const [chartOptions, setChartOptions] = React.useState<Highcharts.Options>(usePasteHighchartsTheme(options));
React.useLayoutEffect(() => {
setChartOptions(Highcharts.merge(chartOptions, options));
}, [options]);
React.useEffect(() => {
if (chartRef.current) {
setChartRef(chartRef.current);
}
}, [chartRef.current]);
const callback = (chart: Highcharts.Chart) => {
// Ensure the chart has been rendered before setting it. This will cause issues in our components if the series is empty.
if (chart?.series?.length > 0) {
setChart(chart);
}
};
return (
<Box gridArea="base-chart" ref={chartRef} position="relative">
<HighchartsReact
highcharts={Highcharts}
options={chartOptions}
constructorType={chartOptions.chart?.map ? "mapChart" : undefined}
updateArgs={[true, true, false]}
callback={callback}
/>
</Box>
);
};
export const BaseChart = React.memo(Chart);
We use React Context to store the rendered chart object to use in our components. When talking about the chart context we do not only mean the rendered object but also the initial configuration. You will need to pass data to the context for the BaseChart
to read and use.
Each individual chart instance will be wrapped in a ChartProvider which sets the initial configuration and apply chart specific styles.
An individual chart instance does not mean a chart only. It may also mean chart titles, legends, tooltips and any other component that does not sit in or on the chart canvas. In simpler terms, it is a container that wraps not only the Highcharts elements but any of our Paste components that interact with that chart and canvas.