Bar Chart In Lightning Web Component Using Chartjs

Telegram logo Join our Telegram Channel
Bar Chart in Lightning Web Component
Bar Chart in Lightning Web Component

Data visualization is a very important part of today's Data Science era, the executives at any company love to see the visual representation of the data, being a web standard Lightning web components gives you the ability to show charts and graphs using external libraries like ChartJs, D3 Js.

In this post, I am going to demonstrate, how you can leverage the power of ChartJs to build a responsive Bar chart in Lwc. My last post on Using ChartJs in Lwc was just a simple example with some static data, in this post, I am going to demonstrate how you can get data from Opportunity and feed it to the bar chart.

Let us assume the scenario where you want to visualize opportunity amounts of the Closed Won opportunities for the last 30 days.

Create a lightning web component named 'chart', this is the generic ChartJs implementation. You can create all different types of charts supported by ChartJs by passing different chart configurations from its parent component.

1. Download this ChartJs file(Open link -> Right Click -> Save As) and upload it into a static resource with the name ''ChartJs".


2. Create a new Lwc with the name 'chart' and copy the below codes in the respective files.

chart.js
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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',
     })
    );
   });
 }
}
In the above code, I 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.

In the renderedCallback,

I have put the Chartjs source file in the static resource, with the help of platformResourceLoader loaded it in the component.

Initialized the chart js once the Chart.bundle.min.js is loaded.
chart.html
<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>
In the HTML I have added a canvas tag, the Chartjs library uses that canvas to draw the chart.

3. Now, create an apex class to fetch the Opportunity Data.

public class OpportunityChartCntrl {
    @AuraEnabled(cacheable=true)
    public static List<Opportunity> getOpportunities(){
        return [SELECT Amount,Name,StageName FROM Opportunity WHERE CloseDate >= LAST_N_DAYS:30 AND StageName = 'Closed Won'];
    }
}

4. Create another lwc, here you can use your desired component. I have named it as opportunityBarChart.

opportunityBarChart.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import {LightningElement, wire, track} from 'lwc';
import getOpportunities from '@salesforce/apex/OpportunityChartCntrl.getOpportunities';
export default class OpportunityBarChart 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 Last Week',
       barPercentage: 0.5,
       barThickness: 6,
       maxBarThickness: 8,
       minBarLength: 2,
                            backgroundColor: "green",
       data: chartData,
      },
     ],
    },
    options: {
    },
   };
   console.log('data => ', data);
   this.error = undefined;
  }
 }
}
The wire method fetches the opportunity data and feeds it into the chart lwc.

The most important thing, all the chart behavior is based on the config you set to the chart. All chart settings and data will be set using

chartConfiguration
It contains three main things 
1. type: It defines the type of chart being rendered, here we have 'bar'.
2. data: Here we pass the chartlabels and chart data and other settings for the bar chart.
3. options: additional settings for Charts.



opportunityBarChart.html
<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>
In the HTML we have called the chart component and set the chart-config parameter.

So this is it, we are ready with a bar chart in lwc.
I have put all this code on the GitHub repo. Feel free to download it.

Let me know if you have any questions in the comments.
Let me know if you face any issues with this.

Your suggestions are always welcome!

Happy Coding!!

More stuff coming up, please subscribe, keep visiting!


48 comments:
  1. I'm getting the following error when running the code: Cannot read property 'parentNode' of undefined

    How would I resolve this?

    ReplyDelete
    Replies
    1. Hello dear Unknown, the error seems to be in chart.js file, on line number 21. There can be two problems, either the canvas is not found or the chart config is not valid. Can you check if your chart.html file has canvas with class="barChar".

      Also check if the static resource is loaded successfully to be able to init the chart

      Delete
    2. Also please make sure that you have uploaded this chart js file into static resources with name = "ChartJs"(This is case sensitive). Let me know if this helps.

      Also if possible can you share your code on github, so I can take a look?

      Delete
    3. I have made some changes in the source code, please get the updated code.

      Delete
    4. Hi, sorry, I'm not sure why I'm coming through as "Unknown". :D
      Where are the changes? I don't see any in the github repo. You're talking about here, right: https://github.com/rahulgawale/chartjs-lwc/commits/master

      Delete
    5. This is something weird with blogger comments, one of my friend also facing the same issue.

      Anyway, I have updated the code in github too. Actually this is very small change on line 16 of chartjs.js file(point 2 in this post). I have removed the relative path from the static resource. you can see the difference here. Sorry for the inconvenience and thank you for your patience.

      Peace!!

      Delete
    6. So the issue with the error I got is that I was referencing the chart.js file in a zip file, and not in its own static resource? Very strange.

      Delete
    7. Yeah, initially when I built this, I was using the whole zip file from chartjs later, I learned that only one file is needed from that zip, so remove the others, I did the required changed in my own source code but, forgot to update that in my blog post and git repo.

      Delete
  2. hello, how we do if we want click bar and get eventt ?

    ReplyDelete
    Replies
    1. Hello Dear Unknown!! Yes you can do that, but you will need to play around it. I haven't tried that yet. Still this link from Stack Overflow have multiple options to do that.

      Delete
    2. Hello Rahul Gwale thx for your response, i have fine this example (https://jsfiddle.net/1gzhnv37/)but I can't transpose it to LWC.

      Delete
    3. Hi, I tried this in lwc but did not work... may be we need to try with latest version of chartjs

      Delete
  3. Hi Rahul i got it it's work for me.

    ReplyDelete
  4. Error loading ChartJS
    Cannot read property 'parentNode' of undefined

    ReplyDelete
    Replies
    1. Did you add the canvas to the html? make sure you have the correct id of the canvas to the queryselector at line 21 of chart.js. also you can share you code with me on github issues.

      Delete
  5. Hi Rahul, Bar chart is not displaying for me in Lightning App. I have copied the same code from your blog except the filter clause in the apex class. I placed the component in the App builder, to test the component, but the chart is not displayed, in the console i am able to see the data is retrieved from the apex class. Can you please let me know what might be the error.

    ReplyDelete
    Replies
    1. Please check if the chartjs script is getting loaded from the static resource. Try setting log in renderedCallback. Once you get the chart is loaded plug in the data in it. Let me know if this helps. Thanks!

      Delete
  6. Thank you for this wonderful job, it is helpful

    ReplyDelete
    Replies
    1. You are most welcome FOCO, I am glad that you found this helpful!

      Delete
  7. Hello,

    Please, I have some issues; I added the following code in options for shorthanding the millions (For example for 1000000 it displays 1M in yAxis), but the callback function doesn't run:
    options: {
    scales: {
    yAxes: [{
    ticks: {
    beginAtZero:true,
    // Shorthand the millions
    callback: function(value, index, values) {
    console.log('====IN Function '+JSON.stringify(value) );
    return value / 1e6 + 'M';
    }
    }
    }],
    xAxes: [{
    ticks: {
    }
    }]
    }
    }

    Help please!

    Thanks in advance

    ReplyDelete
    Replies
    1. Hi FOCO, Welcome back here! Actually I also had faced the similar issue in one of my demo project but could not solve that. I also wanted to add the custom ticks on the axis. Meanwhile I didn't look into that due to some other priorities, at this point I can't really help immediately (Until the weekend). Till then please see this "ChartJS Axes Callback not working". Appreciate your patience!

      Delete
    2. Hi Rahul,

      Thank for your feedback.
      I continue looking for the solution.

      Delete
    3. Hi FOCO, I appreciate your patience. I have the working example for that with Chart.js v2.8.0. You can try the same code with latest version too. Here is the git repo for that. chartjs-with-custom-ticks-lwc. Let me know if this helps you. For the code check in the chartExample.js file.

      Delete
    4. I try it and I will give you my feedback as soon as possible.
      Thank you Rahul

      Delete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Hi Rahul,
    In the above Image Y axis is getting Amount,& i have tried it but i am getting o.1,0.2....etc. I need in the Y axis top show Amount or another field

    ReplyDelete
    Replies
    1. can you share your code? If you want to add label for y axis that you can specify in the options. Also the axis values are based on the data so please verify the data.

      Delete
  10. Hi Rahul,
    I used currency field so it was resolved now & now how to display the numbers in chart

    ReplyDelete
    Replies
    1. Hi Santhosh, I never tried putting text on the bar, can you try solution from this link?

      Delete
  11. Thank you Rahul for this article. Really helpful.
    I used the same but getting error on below line
    this.template.querySelector('canvas.barChart').getContext('2d'); (from chart.js)
    Cannot read property 'getContext' of null. All my code is same. except the data. Appreciate any help

    ReplyDelete
    Replies
    1. Hello Dear Unknown, Did you add the class barChart to the canvas like this

      <canvas class="barChart" lwc:dom="manual"></canvas>

      If you still have any problem, please share your code on GitHub gist or raise an issue here

      Delete
    2. Thanks I opened an issue on github site.

      Delete
    3. Please ignore the post. Everything working fine. I was using wrong Chart.js (I used the chat.bundle.min.js as you suggested and able to get the chart. Thanks again for the nice article on charts.

      Delete
    4. No problem, always happy to help.

      Delete
  12. Hello Rahul , I need this chart in horizontal manner. How could I change this?

    ReplyDelete
    Replies
    1. Hi Dear Unknown, Try change the type to 'horizontalBar' on line #21 from opportunityBarChart.js file.

      Delete
  13. Hi Rahul!
    When adding LWC to a tab I get the error.

    Validation Errors While Saving Record(s)
    There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "We couldn't validate your component c:opportunityBarChart used in Custom Tab. Review it and try again.".

    Do you know the solution?
    Sorry for my English, thanks.

    ReplyDelete
  14. Hi Edwir, You have to mention the target as lightning__Tab in the meta.xml file of your component, then you can add that to tab.

    ReplyDelete
  15. What is the difference between
    https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js  From W3schools and 
    https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min ?

    Can your code use the Chart.js library from W3, or is there more stuff in the "this ChartJS" download?

    ReplyDelete
    Replies
    1. Only the difference is the version of chart js, for that you need to check if it works with lwc. Some of the features were not working because of lightning locker, but you can definitely give it a try with latest version of chartjs

      Delete
    2. Hi,I noticed an issue with the displayed graph where one data value is significantly larger (2147) compared to the other (2). Due to the large difference in scale, the lower value might not be visually represented in the graph. and if the value is zero xaxis the graph ranges from (-5 to +5) in yaxis .

      Delete
    3. Hi Renu, in that case you need to use logarithmic scale instead of linear scale. Also try to explore the options in chart js scale configurations.

      Delete
  16. Only the difference is the version of chart js, for that you need to check if it works with lwc. Some of the features were not working because of lightning locker, but you can definitely give it a try with latest version of chartjs

    ReplyDelete
  17. Hi,I noticed an issue with the bar graph where one data value is significantly larger (2147) compared to the other (2). Due to the large difference in scale, the lower value might not be visually represented accurately in the graph. how can i fix this issue? is there any option to adjust the axes of the graph ? if there is no value ,graph ranges from negative to positive (-5 to +5 in Yaxis) .

    ReplyDelete
  18. Hi Rahul!

    I couldn't pass the Apex class List values (correctly obtained according to the developer console's log) to the JS file (data appears as an array with the proper number of records, but each record is empty!). The chart displays only null values...

    ReplyDelete
    Replies
    1. Hi Bernardo, Good day, can you please share your relevant code snippets so that I can check what is the issue with the code? Please post the GitHub link or you can send it to me at rahul@forcetrails.com

      Delete

Hi there, comments on this site are moderated, you might need to wait until your comment is published. Spam and promotions will be deleted. Sorry for the inconvenience but we have moderated the comments for the safety of this website users. If you have any concern, or if you are not able to comment for some reason, email us at rahul@forcetrails.com