Nowadays, in the era of Data Science, emphasis is placed significantly on data visualization. Presenting data visually holds substantial sway over the user interface. However, constructing personalized, adaptable charts and graphs within Salesforce poses a challenge. Open source solutions stand out as one of the finest options for addressing this need. ChartJS, an open source solution, empowers the creation of charts and graphs that are entirely responsive, accessible, and reactive, ensuring optimal performance. Utilizing ChartJS in Salesforce enables the customization of charts and graphs.
This blog will explore harnessing the capabilities of ChartJS to construct a responsive Bar chart within Lightning Web Components (LWC). We’ll delve into extracting data from an Opportunity and integrating it into the bar chart
What are the benefits of utilizing ChartJS
Charts can be included on pages by employing the App Builder’s “Standard Report Chart” component. Yet, while report filters can showcase pertinent data on these charts, limitations arise when numerous custom filters and complex logic need implementation within a Lightning component. This is where ChartJs proves invaluable. Let’s delve into an example to highlight this.
Instance:
In this demonstration, we’ll generate a bar chart that represents the amounts of the ten most recent Opportunities in the “Closed Won” stage.
Step 1: Obtain the ChartJs library by downloading it.
Click HereTo access the link, right-click on the page and select “Save As” to download the file. Then, upload the file into Static Resources with the title ‘ChartJS’.
Step 2: Generate a Lightning Web Component named ‘chart’.
<template> <div class="slds-p-around_small slds-grid slds-grid--vertical-align-center slds-grid--align-center"> <canvas class="barChart" lwc:dom="manual"></canvas> <div if:false={isChartJsInitialized} class="slds-col--padded slds-size--1-of-1"> <lightning-spinner alternative-text="Loading" size="medium" variant={loaderVariant}></lightning-spinner> </div> </div> </template>
Within the HTML, there’s a canvas tag employed by the ChartJS library to render the chart.
import {LightningElement, api, track} from 'lwc'; import chartjs from '@salesforce/resourceUrl/ChartJs'; import {loadScript} from 'lightning/platformResourceLoader'; import {ShowToastEvent} from 'lightning/platformShowToastEvent'; export default class Chart extends LightningElement { @api loaderVariant = 'base'; @api chartConfig; @track isChartJsInitialized; renderedCallback() { if (this.isChartJsInitialized) { return; } // load static resources. Promise.all([loadScript(this, chartjs)]) .then(() => { this.isChartJsInitialized = true; const ctx = this.template.querySelector('canvas.barChart').getContext('2d'); this.chart = new window.Chart(ctx, JSON.parse(JSON.stringify(this.chartConfig))); this.chart.canvas.parentNode.style.height = 'auto'; this.chart.canvas.parentNode.style.width = '100%'; }) .catch(error => { this.dispatchEvent( new ShowToastEvent({ title: 'Error loading ChartJS', message: error.message, variant: 'error', }) ); }); } }
Here we have declared two @api attributes in the chart component
- loaderVariant – Used to set the loader variant from the parent component.
- chartConfig – Used to pass the chart settings and data from the parent component, so that we can reuse this component for different charts.
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>55.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> <target>lightning__HomePage</target> <target>lightningCommunity__Page</target> </targets> </LightningComponentBundle>
Step 3: Develop an Apex class to retrieve Opportunity data.
public class OpportunityChartController { @AuraEnabled(cacheable=true) public static List<Opportunity> getOpportunities(){ return [SELECT Amount,Name,StageName FROM Opportunity WHERE StageName = 'Closed Won' ORDER BY CreatedDate ASC LIMIT 10]; } }
Obtaining data from Opportunities.
Step 4: Generate a parent Lightning Web Component titled ‘barChartExample
<template> <lightning-card title="Opportunity Bar Chart" icon-name="utility:chart"> <template if:true={chartConfiguration}> <c-chart chart-config={chartConfiguration}></c-chart> </template> </lightning-card> </template>
Invoking the child component ‘chart’ and configuring the chart settings.
import {LightningElement, wire, track} from 'lwc'; import getOpportunities from '@salesforce/apex/OpportunityChartController.getOpportunities'; export default class BarChartExample extends LightningElement { @track chartConfiguration; @wire(getOpportunities, {}) getOpportunities({error, data}) { if (error) { this.error = error; console.log('error => ' + JSON.stringify(error)); this.chartConfiguration = undefined; } else if (data) { let chartData = []; let chartLabels = []; data.forEach(opp => { chartData.push(opp.Amount); chartLabels.push(opp.Name); }); this.chartConfiguration = { type: 'bar', data: { labels: chartLabels, datasets: [ { label: 'Closed Won', barPercentage: 0.5, barThickness: 6, maxBarThickness: 8, minBarLength: 2, backgroundColor: "blue", data: chartData, }, ], }, options: { }, }; console.log('data => ', data); this.error = undefined; } } }
The wire method retrieves data from Opportunities and supplies it to the chart Lightning web component (LWC).
The pivotal element is the chartConfiguration, dictating the chart’s behavior based on the configuration we establish. There are three key attributes:
- Type: This attribute determines the type of chart displayed, in this case, it’s set to ‘bar’.
- Data: Here, we include chartLabels, chartData, and various settings for the bar chart.
- Options: Additional configurations for the chart.
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>55.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> <target>lightning__HomePage</target> <target>lightningCommunity__Page</target> </targets> </LightningComponentBundle>