This code might be a bit abstract since it’s based on the external framework. Just to be clear, everything else works perfect, just when I try and include the legend or caption I get the error.
Here’s the code for the plot:
createOppPlot(currentGoal) {
return Plot.plot({
marginLeft: 100,
marginRight: 50,
marginBottom: 50,
height: 100,
color: {
scheme: 'bugn',
legend: true,
},
y: {
label: null,
grid: true,
axis: null,
},
x: {
domain: [0, d3.max([currentGoal], d => d.OpportunityGoal)],
label: `${d3.format('$,.2f')(currentGoal.currentOppTotalValue)} / ${d3.format('$,.0f')(
currentGoal.OpportunityGoal
)}`,
tickFormat: '$,.0f',
ticks: 4,
labelAnchor: 'center',
labelOffset: 36,
clamp: true,
},
marks: [
Plot.barX(
currentGoal.Gifts,
Plot.stackX(
Plot.groupZ(
{ x: 'sum' },
{
x: 'amount',
fill: 'type',
title: d => `${d.type} - ${d3.format('$,.2f')(d.amount)}`,
}
)
)
),
Plot.ruleX([0]),
Plot.text([currentGoal], {
x: 0,
textAnchor: 'start',
dx: +4,
text: d => `${d3.format('.0%')(d.currentOppTotalValue / d.OpportunityGoal)}`,
y: 'rm',
fill: 'black',
}),
Plot.frame(),
],
});
}
I’m passing in a pretty simple data structure that looks like this:
[
{
"rm": "Josh Kenzer",
"Gifts": [
{
"type": "Owner + Co-Owner Value",
"amount": 2025000
},
{
"type": "Stewarded",
"amount": 106529.46
},
{
"type": "Team Value",
"amount": 799424.39
}
],
"PlannedGifts": [
{
"type": "Owner + Co-Owner Count",
"amount": 0
},
{
"type": "Team Count",
"amount": 0
}
],
"currentOppTotalValue": 2930953.85,
"OpportunityGoal": 12000000,
"PlannedGiftGoal": 7,
"currentPlannedGiftTotal": 0
}
]
And the output I get when I don’t pass legend: true:
When I pass legend: true, then I get this error:
Uncaught (in promise) TypeError: Function.prototype.apply was called on undefined, which is a undefined and not a function
at Object.br [as plot] (plot:2:56162)
at U.createOppPlot (displayDevelopmentGoals.js:1:5709)
at U.renderPlot (displayDevelopmentGoals.js:1:5428)
at eval (displayDevelopmentGoals.js:1:4625)
Here are the relevant parts of the web component using the lwc.dev framework (the link is to an off-Salesforce implementation by Salesforce). I am doing this on platform.
renderPlot() {
this.renderedPlot = true;
console.log(Plot.version);
// LWC syntax for selecting dom element
let thePlots = this.template.querySelector('div.plot');
// clear out dom elements in case the user toggles the fiscal year to view
while (thePlots.firstChild) {
thePlots.removeChild(thePlots.firstChild);
}
// sort the results by relationship manager last name
this.currentGoalValues = this.currentGoalValues.sort((a, b) => {
return d3.ascending(a.rm.split(' ')[1], b.rm.split(' ')[1]);
});
// loop through each relationship manager creating a separate horizontal bar chart for each relationship manager
for (let index = 0; index < this.currentGoalValues.length; index++) {
let currentGoal = this.currentGoalValues[index];
// create containing row
let rowEle = document.createElement('div');
rowEle.classList.add('slds-grid', 'slds-gutters', 'thePlots', 'slds-m-bottom_x-large');
// display the rm name
let rmEle = document.createElement('div');
rmEle.classList.add('slds-col', 'slds-size_2-of-12', 'slds-align-middle');
let rmHeaderEle = document.createElement('div');
rmHeaderEle.classList.add('slds-text-heading_small');
rmHeaderEle.innerHTML = currentGoal.rm;
rmEle.appendChild(rmHeaderEle);
rowEle.appendChild(rmEle);
// add the plot
let elePlotGoal = document.createElement('div');
elePlotGoal.classList.add('slds-col', 'slds-size_10-of-12');
let plot = this.createOppPlot(currentGoal);
elePlotGoal.appendChild(plot);
rowEle.appendChild(elePlotGoal);
// append to the dom
this.template.querySelector('div.plot').appendChild(rowEle);
}
}
I know this is complex out of context but if you have any thoughts, that would great. As an alternative, could I create the legend separately and insert that into the DOM? How would I grab the color scale into some structure to work with separately?