D3.js is the most popular library for creating interactive charts in any web application. You can also use D3.js library in Lightning components for graphical representation of data. These charts can be used to give sales insights to a member ( Salesforce user) of the sales team. This article will show how can we leverage D3.js to build charts with a simple example.
First, let’s see the component code.
D3Charts.cmp
D3ChartsController.js
[code language=”javascript”]
({
initD3Charts : function(component, event, helper) {
var width = 960;
var height = 500;
// Create SVG element, we can’t just use tag in lightning component
// So creating one dynamically using jquery
var svg = d3.select(“body”)
.append(“svg”)
.attr(“width”, width)
.attr(“height”, height);
// Calling server-action to get the data
var action = component.get(“c.getData”);
// Create a callback that is executed after
// the server-side action returns
action.setCallback(this, function(response) {
var state = response.getState();
if (state === “SUCCESS”) {
let data = response.getReturnValue();
console.log(data);
// Render the returned data as a pie chart
helper.renderChart( component, data );
}
else if(state === “ERROR”) {
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
console.log(“Error message: ” +
errors[0].message);
}
} else {
console.log(“Unknown error”);
}
}
});
$A.enqueueAction(action);
}
})
[/code]
D3ChartsHelper.js
[code language=”javascript”]
({
renderChart : function( component, data ) {
var svg = d3.select(“svg”),
width = +svg.attr(“width”),
height = +svg.attr(“height”),
radius = Math.min(width, height) / 2,
g = svg.append(“g”).attr(“transform”, “translate(” + width / 2 + “,” + height / 2 + “)”);
var color = d3.scaleOrdinal([“#98abc5”, “#8a89a6”, “#7b6888”, “#6b486b”, “#a05d56”, “#d0743c”, “#ff8c00”]);
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.candidates; });
var path = d3.arc()
.outerRadius(radius – 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius – 80)
.innerRadius(radius – 80);
var arc = g.selectAll(“.arc”)
.data(pie(data))
.enter().append(“g”)
.attr(“class”, “arc”);
arc.append(“path”)
.attr(“d”, path)
.attr(“fill”, function(d) { return color(d.data.age); });
arc.append(“text”)
.attr(“transform”, function(d) { return “translate(” + label.centroid(d) + “)”; })
.attr(“dy”, “0.35em”)
.text(function(d) { return d.data.age; });
}
})
[/code]
So, we have included d3.js library along with jquery.js and then called a server-side action when the script has loaded in order to fetch the chart data. In the defined callback function we passed that data to a helper function which rendered the chart.
D3ChartsController.apex
[code language=”java”]
public class D3ChartsController {
@AuraEnabled
public static List getData(){
// For this example, it’s just a static data but it can be generated
// as per any business logic
List lstData = new List();
lstData.add( new PieChart( ‘=65’, 61 ) );
return lstData;
}
public class PieChart {
@AuraEnabled public String age;
@AuraEnabled public Integer candidates;
public PieChart( String age, Integer candidates ) {
this.age = age;
this.candidates = candidates;
}
}
}
[/code]
Reference to resources –
By Naveen Sharma
August 17, 2018Hi Naval,
Thanks for the example.
However, I have a problem.
The afterScriptsLoaded=”{!c.initD3Charts}” isn’t being called/actioned.
I can’t see why.
Any suggestions?
By Naveen Sharma
August 18, 2018It could be because of the LocerService.
Check the following link –
https://salesforce.stackexchange.com/questions/143819/ltngrequire-not-firing-afterscriptsloaded-with-locker-service-enabled
By Naveen Sharma
August 22, 2018Hi Naval,
I found that the $Resource syntax doesn’t work.
Instead I used
(Couldn’t get a join to work either).
So the libraries load OK but I don’t see a pie chart.
I suspect a “div” or “canvas” is needed in the cmp but don’t know for sure.
By Naveen Sharma
August 22, 2018Found it! I’d left off the curly braces in my Join statement. Oops!
By Naveen Sharma
August 24, 2018I found a way to ‘tag’ to a thanks to joshbirk at https://gist.github.com/joshbirk/08be97d92b91c3bdc9e1
It seems D3 can select a if the name is prefixed with a ‘#’ sign.
add a div to your component:
then replace the dynamic scalable vector graphic creation with new code:
/*
var svg = d3.select(“body”)
.append(“svg”)
.attr(“width”, width)
.attr(“height”, height);
*/
var svg = d3.select(“#diagram”).append(“svg”)
.attr(“width”, width)
.attr(“height”, width)
.attr(“preserveAspectRatio”, “xMidYMid”)
.attr(“viewBox”, “-50 -50 1200 1200”);
nb: there’s a couple of extra attributes there that look fun and will need more research!
By Naveen Sharma
March 27, 2019I can’t compile the apex controller, because of wrong return type in this line:
public static List getData(). There should probably be a ‘String’ (if the list of PieChart-s gets serialized) or just a ‘List’. Please confirm on either one.
In any case nothing is shown – the component simply renders empty.
By Naveen Sharma
March 29, 2019It’s just a list and it’s automatically gets serialized when you get the result in the callback.
In the lightning component controller –
let data = response.getReturnValue();
variable ‘data’ will have an array of JS objects. You could be doing something wrong and that is leading the empty chart issue.
By Naveen Sharma
March 6, 2020Can you please provide me how to add tooltip and lengend to d3 scatter plot chart in lightening web component