Forcetrails: How to use chartjs in Lightning Web Components

Hello There!!

Today, in the era of digital transformation, we believe in faster and reusable solutions. Open source is one of the best sources for this kind of solution. Here our problem is to build custom charts and graphs. To be able to build custom charts in Salesforce. We have two options from open source.

  1. D3.Js
  2. ChartJs
If you are looking for Bar Chart, here is the separate post.

Today we will see an example of using ChartJs in lightning web components.
Below are the steps for that.

  • Download the distributed version of ChartJs from here. (Open link -> Right Click -> Save As)
  • Upload the downloaded js file into the static resource with the name ChartJs
  • Create a new Lightning web component with the name chartExample and put the following code into JS and HTML files respectively.

Here is the code for my component.

.js File

import { LightningElement, track } from 'lwc';
import chartjs from '@salesforce/resourceUrl/ChartJs';
import { loadScript } from 'lightning/platformResourceLoader';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';


export default class ChartExample extends LightningElement {
    @track isChartJsInitialized;
    chart;

    config = {
        type: 'line',
        data: {
            datasets: [{
                fill: false,
                label: 'Line Dataset',
                data: [{  
                    y:100,
                    x:0
                 },
                 {  
                    y:96,
                    x:10
                 },
                 {  
                    y:93,
                    x:20
                 },
                 {  
                    y:89,
                    x:30
                 },
                 {  
                    y:85,
                    x:50
                 },
                 {  
                    y:80,
                    x:60
                 },
                 {  
                    y:71,
                    x:70
                 },
                 {  
                    y:43,
                    x:80
                 },
                 {  
                    y:19,
                    x:90
                 },
                 {  
                    y:9,
                    x:100
                 },
                 {  
                    y:4,
                    x:110
                 },
                 {  
                    y:2,
                    x:120
                 },
                 {  
                    y:0,
                    x:130
                 },
                 {  
                    y: 140,
                    x:140
                 }
                 
                 ],
                backgroundColor: [
                    'rgba(255, 99, 132, 0.2)'
                ],
                borderColor: [
                    'rgba(255, 99, 132, 1)'
                ],
                pointBackgroundColor: 'rgba(255, 99, 132, 0.2)',
                pointBorderColor: 'rgba(255, 99, 132, 1)'
            },
            {
                fill: false,
                label: 'Line Dataset 2',
                data: [{  
                    y:100,
                    x:0
                 },{  
                    y:98,
                    x:10
                 },{  
                    y:95,
                    x:20
                 },{  
                    y:92,
                    x:30
                 },{  
                    y:88,
                    x:50
                 },{  
                    y:84,
                    x:60
                 },{  
                    y:75,
                    x:70
                 },{  
                    y:50,
                    x:80
                 },{  
                    y:25,
                    x:90
                 },{  
                    y:14,
                    x:100
                 },{  
                    y:8,
                    x:110
                 },{  
                    y:5,
                    x:120
                 },{  
                    y:2,
                    x:130
                 }],
                backgroundColor: [
                    '#80aaff'
                ],
                borderColor: [
                    'blue'
                ],
                pointBackgroundColor: '#80aaff',
                pointBorderColor: 'blue'
            }
            ]
        },
        options: {
            title: {
                display: true,
                text: 'Sand Samples Against Comm Weight %.'
            },
            scales: {
                xAxes: [{
                    type: 'linear',
                    ticks: {
                        suggestedMin: 0,
                        suggestedMax: 140,
                        stepSize: 10
                    }
                }],
                yAxes: [{
                    type: 'linear',
                    ticks: {
                        autoSkip: true,
                        suggestedMin: 0,
                        suggestedMax: 100,
                        stepSize: 5,
                        callback: function (value) {
                            return value + '%';
                        }
                    }
                }]
            },
        }
    };

    renderedCallback() {
        if (this.isChartJsInitialized) {
            return;
        }
        this.isChartJsInitialized = true;

        Promise.all([
            loadScript(this, chartjs)
        ]).then(() => {
            const ctx = this.template.querySelector('canvas.linechart').getContext('2d');
            this.chart = new window.Chart(ctx, this.config);
            this.chart.canvas.parentNode.style.height = '100%';
            this.chart.canvas.parentNode.style.width = '100%';
        }).catch(error => {
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Error loading ChartJS',
                    message: error.message,
                    variant: 'error',
                }),
            );
        });
    }
}

.html file

<template>
    <lightning-card title="Sand Samples" icon-name="utility:chart">
        <div class="slds-grid slds-wrap slds-grid--pull-padded">
            <div if:true={isChartJsInitialized} class="slds-col--padded slds-size--1-of-1">
                <canvas class="linechart" lwc:dom="manual"></canvas>
            </div>
            <div if:false={isChartJsInitialized} class="slds-col--padded slds-size--1-of-1">
                ChartJs Not loaded yet
            </div>
            <div class="slds-col--padded slds-size--1-of-1">
                Footer
            </div>
        </div>
    </lightning-card>
</template>


Now, add the below code to your meta-xml file after <apiVersion> tag to expose the component to the app builder, the home page, or community page.

<isExposed>true</isExposed>
<targets>
    <target>lightning__AppPage</target>
    <target>lightning__RecordPage</target>
    <target>lightning__HomePage</target>
    <target>lightningCommunity__Page</target>
</targets>

This is the output.

Let me know in the comments if this was helpful to you, thank you!
Happy Coding!!


You may also like...

44 comments:
  1. Build a config object for Chart
    Load the chart.


    Not getting these 2 steps. I deployed and I see no chart.

    ReplyDelete
    Replies
    1. You need to pass the configurations to chart, in that you can specify different properties of the chart, like data you want to load on chart, type of chart etc. For the demo purpose I have hardcoded this data on line 11 of js(search "config = {").

      Delete
    2. Hi Unknown User, I have modified that part of the post and I have added more details to avoid the confusion.

      Delete
  2. Will the chart rerender if i provide the dataset dynamically?

    ReplyDelete
    Replies
    1. Yes, Create another component and wrap this chart component inside it. Change 'config' into a public property using '@api'. Then pass the dynamic data from the parent component. I have some thing similar to this in my another post https://sftrailmixer.blogspot.com/2020/04/bar-chart-in-lightning-web-component-lwc-bar-chartjs.html on

      Delete
  3. i tried it out using exactly the same code you did, the chart is not displayed after being deployed. " ChartJs Not loaded yet" is not displayed either so the chart is just not rendering. what else should be checked?

    ReplyDelete
    Replies
    1. Did you upload the static resource, please check if the static resources are rendered correctly. Try putting log after this line "]).then(() => {".

      Also if you are looking for "How to feed dynamic data to the chart", then please my another post = https://sftrailmixer.blogspot.com/2020/04/bar-chart-in-lightning-web-component-lwc-bar-chartjs.html

      Delete
    2. I know why, there was problem in the code of loading the static resource I have fixed that. Now you can copy the updated code and use the same. Please let me know if further help is needed. Thanks!

      Delete
  4. Can we display reports and charts in lWC?

    ReplyDelete
    Replies
    1. Charts you can, but I am not sure about the standard Salesforce Reports, although you can create custom. Also, you can try adding the reports in an iframe, but I have never tried that.

      Delete
    2. I am doing an POC for displaying the reports in the LWC , where reports being generated from the objects in the salesforce so by grouping reports we can create an chart i want that chart tobe shown in LWC. i have looked for many source couldnt find an approach so far.

      Delete
    3. Is there any reason that you want to show standard reports in lwc? are you trying to display it in community?

      Delete
  5. we want to generate report on the existing data which has been there from many years and we are not displaying in community

    ReplyDelete
    Replies
    1. If you just need reports, I think you don't need LWC, just use the standard reports and dashboards.

      Delete
  6. I tried changing the chart type in config based on user selection. But chart loads and shows with old chart type only. Is there anyway we can achieve this?

    ReplyDelete
    Replies
    1. You need to update the chart whenever there is change in the data or configuration. You need to call the "chart.update()" method for this.

      Delete
    2. I tried it didnt work. And document also says it can only update data and options of chart.Can you provide correct syntax of doing it if possible?

      Delete
    3. I have done it like below. I have getter, setter to update the chart.

      @api
      get config() {
      return this._config;
      }

      set config(value) {
      console.log('inside set config!');
      this._config = value;

      if(this.chart){
      this.chart.update();
      this.isChartJsInitialized = false;
      console.log('chart updated');
      }
      }


      Also in the "renderedcallback" I have below code.


      renderedCallback() {
      if (this.isChartJsInitialized) {
      return;
      }
      this.isChartJsInitialized = true;
      if (this._config) {
      // because we cannot edit the public attribute passed by parent
      this.privateConfig = JSON.parse(JSON.stringify(this._config));
      Promise.all([
      loadScript(this, chartjs + '/dist/Chart.bundle.min.js')
      ]).then(() => {
      const ctx = this.template.querySelector('canvas.linechart').getContext('2d');
      this.chart = new window.Chart(ctx, this.privateConfig);
      //this.saveAsImage();
      }).catch(error => {
      this.dispatchEvent(
      new ShowToastEvent({
      title: 'Error loading ChartJS',
      message: error.message,
      variant: 'error',
      }),
      );
      });
      }
      }

      Delete
  7. Hi Rahul.. Do you have an example on Pie chart. If yes..plz share.
    Thanks

    ReplyDelete
    Replies
    1. Just use below configuration..

      config = {
      type: "pie",
      data: {
      datasets: [
      {
      data: [200, 450, 300, 50],
      backgroundColor: [
      "#ff6384",
      "#36a2eb",
      "#ffcd56",
      "#42d83f"
      ]
      }
      ],
      labels: ["Top", "High", "Low", "Volume"]
      }
      };

      Delete
  8. Hey!! Rahul,
    I am unable to see any thing in my chart,
    so when i did the console.log after this line "]).then(() => {".
    I found that there is error in inspect console of chorme, its not getting the correct url
    loadScript(this, chartjs + '/dist/Chart.bundle.min.js')--->what should i write in place of /dis.
    Thanks

    ReplyDelete
    Replies
    1. if you have uploaded the chartjs file directly.the just use loadScript(this, chartjs)

      Delete
  9. Hi Rahul, Can you provide example with D3.js chart

    ReplyDelete
  10. Can you provide example with D3.js chart.
    Thanks.

    ReplyDelete
    Replies
    1. Hello Mr/Ms None! I will upload the D3.js example very soon.

      Delete
    2. Hello Dear None, I have posted one example with D3 js library here

      Delete
  11. I am doing a POC on responsive charts. Say I have a block with fixed height and when I place the chart component inside that block it should respect the height of the parent and adjust accordingly. Also I have the maintainAspectRatio set as false, so it should take up the entire space. Currently thats not the case and its goes out of the block. Did you try anything like this? I have a very complex use case though.

    ReplyDelete
  12. Hi Rahul,
    Thanks for this post with good explanation. Is there any way to display the values on the chart?

    ReplyDelete
    Replies
    1. Yes there is a way. Follow this link. Also by default the values are displayed when you hover over the graph.

      Delete
    2. Thank you so much for your reply. How do I install the plugin? Do we have to download the whole folder from and create as a static resource in the salesforce org?

      Delete
    3. Most Welcome!, I had uploaded the chart.min.js file in the static resource directly, if you want to you can upload .zip file too, but if you upload zip, you need to append the path of the file to the Static resource url when you call loadScript. for ex. loadScript(this, chartjs + "/chart.min.js")

      Delete
    4. Thanks Rahul. I did that but it is not working always. It is showing the datalabels only once .WhenI refresh the page there is an error coming up.

      Delete
    5. import chartjs from '@salesforce/resourceUrl/ChartJs';
      import chartDataLabels from '@salesforce/resourceUrl/chartdatalabelplugin'; My import statement
      This is my loadscript
      // load static resources.
      Promise.all([
      loadScript(this, chartjs),
      loadScript(this, chartDataLabels)
      ]).then(()

      Delete
    6. Uncaught (in promise) TypeError: Cannot read property 'message' of undefined
      at eval

      Delete
  13. Thanks Rahul. I did that but it is not working always. It is showing the datalabels only once .WhenI refresh the page there is an error coming up.

    ReplyDelete
  14. import chartjs from '@salesforce/resourceUrl/ChartJs';
    import chartDataLabels from '@salesforce/resourceUrl/chartdatalabelplugin'; My import statement
    This is my loadscript
    // load static resources.
    Promise.all([
    loadScript(this, chartjs),
    loadScript(this, chartDataLabels)
    ]).then(()

    ReplyDelete
    Replies
    1. Hi Rahul, I found the issue. It was due to loadScript method. We need to make sure chart.js is loaded before the plugin. I changed that and it working as expected.
      Thank you so much for your help

      Delete
    2. Promise.all([loadScript(this, chartjs)]).then(() => {
      Promise.all([loadScript(this, chartDataLabels)]).then(() => {
      this.isChartJsInitialized = true;
      const ctx = this.template.querySelector('canvas.lineChart').getContext('2d');
      console.log('ctx::::' + ctx);
      console.log('this.chartConfig::' + JSON.stringify(this.chartConfig));
      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%';

      })
      })

      Delete
    3. Thats how I changed the code. Sharing this as it might be useful for someone if they have same issue

      Delete
    4. Thank you friend, I am glad that this post has helped you. And sorry for the late reply. Enjoy coding!!

      Delete
  15. Rahul, please ignore my previous post. Your code is working and I am able to display the chart.
    My issue is resolved by using the chat.bundle.min.js (i was using chat.min.js before which gave me a null error) Thanks again for nice article.

    ReplyDelete
  16. Can you suggest a code for org hierarchy chart for LWC ??

    ReplyDelete
    Replies
    1. There are some chart libraries in JS that provide the Org Chart but unfortunately those do not work with LWC due to Locker Service. Two of them are Google Charts and Org Chart, that I have tried and didn't work. But good news is that you can build one with D3Js, check OrgChart using D3Js. But I have implemented it yet in LWC. I im pretty sure that it will work. Also Winter2022 release states that SF has removed some of the restrictions to make it easier to use external JS libraries, so need to check if OrgChart or Google chart or other Org chart libraries can work with Winter2022 or not, give it a try. I am planning to build orgchart example with LWC due to high demand but can't promise when it will be live. Thank you for visiting. I hope this gives you little guideline.

      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, reach email us at rahul@forcetrails.com