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.
Now, add the below code to your
This is the output.
Let me know in the comments if this was helpful to you, thank you!
Happy Coding!!
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.
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!!
Build a config object for Chart
ReplyDeleteLoad the chart.
Not getting these 2 steps. I deployed and I see no chart.
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 = {").
DeleteHi Unknown User, I have modified that part of the post and I have added more details to avoid the confusion.
DeleteWill the chart rerender if i provide the dataset dynamically?
ReplyDeleteYes, 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
Deletei 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?
ReplyDeleteDid you upload the static resource, please check if the static resources are rendered correctly. Try putting log after this line "]).then(() => {".
DeleteAlso 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
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!
DeleteBuld a bar chart in LWC
ReplyDeleteCan we display reports and charts in lWC?
ReplyDeleteCharts 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.
DeleteI 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.
DeleteIs there any reason that you want to show standard reports in lwc? are you trying to display it in community?
Deletewe want to generate report on the existing data which has been there from many years and we are not displaying in community
ReplyDeleteIf you just need reports, I think you don't need LWC, just use the standard reports and dashboards.
DeleteI 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?
ReplyDeleteYou need to update the chart whenever there is change in the data or configuration. You need to call the "chart.update()" method for this.
DeleteI 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?
DeleteI have done it like below. I have getter, setter to update the chart.
Delete@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',
}),
);
});
}
}
Hi Rahul.. Do you have an example on Pie chart. If yes..plz share.
ReplyDeleteThanks
Just use below configuration..
Deleteconfig = {
type: "pie",
data: {
datasets: [
{
data: [200, 450, 300, 50],
backgroundColor: [
"#ff6384",
"#36a2eb",
"#ffcd56",
"#42d83f"
]
}
],
labels: ["Top", "High", "Low", "Volume"]
}
};
Hey!! Rahul,
ReplyDeleteI 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
if you have uploaded the chartjs file directly.the just use loadScript(this, chartjs)
DeleteHi Rahul, Can you provide example with D3.js chart
ReplyDeleteCan you provide example with D3.js chart.
ReplyDeleteThanks.
Hello Mr/Ms None! I will upload the D3.js example very soon.
DeleteHello Dear None, I have posted one example with D3 js library here
DeleteI 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.
ReplyDeleteHi Rahul,
ReplyDeleteThanks for this post with good explanation. Is there any way to display the values on the chart?
Yes there is a way. Follow this link. Also by default the values are displayed when you hover over the graph.
DeleteThank 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?
DeleteMost 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")
DeleteThanks 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.
Deleteimport chartjs from '@salesforce/resourceUrl/ChartJs';
Deleteimport chartDataLabels from '@salesforce/resourceUrl/chartdatalabelplugin'; My import statement
This is my loadscript
// load static resources.
Promise.all([
loadScript(this, chartjs),
loadScript(this, chartDataLabels)
]).then(()
Uncaught (in promise) TypeError: Cannot read property 'message' of undefined
Deleteat eval
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.
ReplyDeleteimport chartjs from '@salesforce/resourceUrl/ChartJs';
ReplyDeleteimport chartDataLabels from '@salesforce/resourceUrl/chartdatalabelplugin'; My import statement
This is my loadscript
// load static resources.
Promise.all([
loadScript(this, chartjs),
loadScript(this, chartDataLabels)
]).then(()
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.
DeleteThank you so much for your help
Promise.all([loadScript(this, chartjs)]).then(() => {
DeletePromise.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%';
})
})
Thats how I changed the code. Sharing this as it might be useful for someone if they have same issue
DeleteThank you friend, I am glad that this post has helped you. And sorry for the late reply. Enjoy coding!!
DeleteI also had to do this.
Deletelet config = {
type: this._chartType,
data: cloneData,
options: cloneOptions,
plugins : [ChartDataLabels]
}
and
datalabels: {
display: true,
}
Rahul, please ignore my previous post. Your code is working and I am able to display the chart.
ReplyDeleteMy 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.
Can you suggest a code for org hierarchy chart for LWC ??
ReplyDeleteThere 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.
DeleteHi Rahul,
ReplyDeleteI am trying to display a horizontal bar chart and your blog helped me a lot.
I want to display ticks in % on my x axis and title on x axis. Also tooltip value should also be postfixed with %.
chartConfiguration = {
type: 'horizontalBar',
data: {
labels: chartLabels,
datasets: [
{
label: 'Vacancies',
data: chartData,
backgroundColor: "#03045e",
},
],
},
options: {
scales: {
xAxes:[{
display: true,
labelString: '% of Fieldforce Vacancy',
ticks: {
suggestedMin: 0,
//suggestedMax: 140,
stepSize: 2,
callback: function (value) {
return value + '%';
}
}
}],
}
},
};
Please help.
Hi Kunal, you need use different configuration something like this
Deletelet config = {
datasets:[
{
label:"Data1",
data:[
{x:"2015",y:5},
{x:"2016",y:10}
]
},
{
label:"Data2",
data:[
{x:"2016",y:7},
{x:"test",y:8}
]
}
],
labels:["2015", "2016", "test"]
};
For more information, you can refer ChartJs docs: https://www.chartjs.org/docs/latest/axes/
DeleteHi Rahul, I'm able to view the HTML intent like sand samples and icon and footer but I'm not able to view the chart
ReplyDeleteHi Man, did you use the exact same chartjs file? Can you share your code on GitHub, so I can review it?
Delete