How to Use Chart.js in Retool Using a Custom Component

Retool provides a versatile platform for quickly building internal tools, and extending its functionality with custom components is one of its strengths. In this article, we'll guide you through integrating Chart.js into Retool using a custom React component. We'll use sample data representing players’ ages to demonstrate the process. Follow these steps to visualize your data in a pie chart using Chart.js.

Sample Data:
We’ll use the following data to create our pie chart. This data will be included in the model of the custom component:

{ "data": {

"x": ["Below 14", "14-16", "16-18", "18-20", "20-22", "22-24", "Above 24"],

"y": [29.79, 4.26, 0, 4.26, 34.04, 4.26, 23.4]

}}

HTML Structure:
Start by setting up the basic HTML and CSS structure within your Retool custom component:

<style>

.component {

border: 1px solid #CDA6DF;

width: 100%;

height: 100%;

border-radius: 12px;

background-color: #FFFFFF;

padding: 10px;

box-sizing: border-box;

}

.main {

background-color: #F2ECF5;

padding: 10px;

margin-top: 10px;

border-radius: 12px;

}

.root, .unique {

display: flex;

justify-content: space-between;

margin-bottom: 10px;

}

.first, .second {

border-bottom: 1px solid #CDA6DF;

color: #000000;

width: 100%;

font-family: 'Poppins', sans-serif;

font-size: 14px;

font-weight: 400;

line-height: 18px;

text-align: center;

}

.line {

height: 30px;

}

.percentage {

font-family: 'Poppins', sans-serif;

font-size: 24px;

font-weight: 400;

line-height: 31px;

text-align: center;

}

#myChart {

margin: 0 auto;

height: 380px !important;

width: 380px !important;

}

.title {

font-family: 'Poppins', sans-serif;

font-size: 18px;

font-weight: 400;

line-height: 23px;

color: #7C3C9B;

text-align: center;

}

.no-data {

text-align: center;

color: #BFBFBF;

font-family: 'Poppins', sans-serif;

font-size: 18px;

font-weight: 400;

line-height: 23px;

height: 325px;

display: flex;

justify-content: center;

align-items: center;

}

</style>

<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>

<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<div id="react"></div>

Creating the React Component:
Next, we’ll create a React component that renders the Chart.js pie chart using the sample data. Add the following script to your custom component:

<script type="text/babel">

const { useEffect, useRef } = React;

const MyCustomComponent = ({ model }) => {

const colors = [

'#FD6AF8',

'#41B54A',

'#F7971C',

'#2D67B1',

'#555555',

'#EC1F24',

'#C561F7'

];

const chartRef = useRef(null); // Ref to store chart instance

const prevDataRef = useRef([]); // Ref to store previous data

// Helper function to check if all values in an array are null

function allValuesAreNull(arr) {

return arr.every(value => value === null);

}

useEffect(() => {

const ctx = document.getElementById("myChart").getContext("2d");

// Function to destroy the chart

const destroyChart = () => {

if (chartRef.current) {

chartRef.current.destroy();

chartRef.current = null;

}

};

// Function to create or update the chart

const createOrUpdateChart = () => {

if (!chartRef.current) {

chartRef.current = new Chart(ctx, {

type: 'pie',

data: {

labels: model.data.x,

datasets: [{

label: 'Ages in %',

data: model.data.y,

backgroundColor: colors,

borderColor: "#FFFFFF",

borderWidth: 1.5,

}]

}

});

} else {

chartRef.current.data.labels = model.data.x;

chartRef.current.data.datasets[0].data = model.data.y;

chartRef.current.update();

}

prevDataRef.current = model.data.y;

};

// Create chart if there's data

if (!allValuesAreNull(model.data.y)) {

createOrUpdateChart();

} else {

destroyChart();

}

// Cleanup on component unmount

return destroyChart;

}, [model.data, colors]);

if (allValuesAreNull(model.data.y)) {

return (

<div className="component">

<span className="title">Ages of players</span>

<div className="no-data">No Data Found</div>

</div>

);

}

return (

<div className="component">

<span className="title">Ages of players</span>

<canvas id="myChart" width="400" height="400"></canvas>

<div className="main">

{model.data.x.map((age, index) => (

<div className={index === 6 ? "unique" : "root"} key={index}>

<div className="first">

Age {index === 0 || index === 6 ? age : `between ${age}`}

&nbsp;&nbsp;<span className="percentage" style={{ color: colors[index] }}>

{model.data.y[index]}%

</span>

</div>

{index % 2 !== 0 && <div className="line"></div>}

</div>

))}

</div>

</div>

);

};

const ConnectedComponent = Retool.connectReactComponent(MyCustomComponent);

const container = document.getElementById("react");

const root = ReactDOM.createRoot(container);

root.render(<ConnectedComponent />);

</script>

Explanation:

  • HTML and CSS Structure: Define the basic styles and structure of the component to ensure it fits well within the Retool dashboard.

  • React Component Setup: Use React’s useEffect hook to manage the lifecycle of the Chart.js instance, creating or updating the chart based on the provided model data.

  • Helper Functions:

    • allValuesAreNull: Checks if all values in the data array are null.

  • Chart Management:

    • createOrUpdateChart: Either create a new chart or update the data in the existing chart.

    • destroyChart: Destroys the chart if there is no valid data or when the component unmounts.

  • Data Handling: Checks if there’s data to display; if not, it renders a “No Data Found” message.

  • Component Mounting: Use Retool’s Retool.connectReactComponent to connect the custom React component with the Retool framework.

Conclusion:
By following these steps, you can successfully integrate Chart.js within a Retool custom component to visualize data with interactive pie charts. This approach offers flexibility, allowing you to further customize the chart according to your application’s needs.

Experiment with different chart types and data sets to unlock the full potential of custom components in Retool, enhancing your internal tools and dashboards.

Previous
Previous

Building a Custom Chat Component for Retool Using React and WebSocket

Next
Next

Frames in Retool: An In-Depth Guide