Check your eligibility for this 50% exam voucher offer and join us for free live learning sessions to get prepared for Exam DP-700.
Get StartedDon't miss out! 2025 Microsoft Fabric Community Conference, March 31 - April 2, Las Vegas, Nevada. Use code MSCUST for a $150 discount. Prices go up February 11th. Register now.
Hello everyone,
I have just started learning to create Power BI custom visuals and I have created my first custom visual i.e. Circle Card by referring the Microsoft tutorial.
Now, I want to modify this little bit and want to show a percentage based on Actual Value and Target Value and fill the circle according to the percentage i.e. if the percentage is 85% then fill 85% circle with a different color. I have managed to do this using the below sort of code in the Update method of the visual lifecycle.
var gradient = this.container.append("defs").append("linearGradient").attr("id", "gradient")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
gradient.append("stop").attr("offset", + fillPercent + "%").style("stop-color", "red");
gradient.append("stop").attr("offset", fillPercent + "%").style("stop-color", "white");
this.circle
.style("fill", function () {
return "url(#gradient)";
})
.style("fill-opacity", 1)
.style("stroke", "black")
.style("stroke-width", this.visualSettings.gauge.circleThickness)
.attr("r", radius)
.attr("cx", width / 2)
.attr("cy", height / 2);
The problem is that the gradient fill is not getting refreshed based on the percentage I need to press the reload visual button. (See below)
I have attached my visual.ts file for the reference.
Please let me know what's wrong here?
Thank you in advance.
Please click here to open visual.ts
Solved! Go to Solution.
Hi @Anonymous,
As we only have your visual.ts to go on, I can't reproduce fully locally to confirm, the first line in your posted snippet is the suspect:
var gradient = this.container.append("defs").append("linearGradient").attr("id", "gradient")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
How this is currently written, will append a defs element to your container element each time the update method runs, rather than replacing it. This is because your container property (and it's children) is persisted across the lifecycle of the visual.
So, when you start your visual and the update method runs for the first time the gradient is applied as you expect (akin to your scenario of refreshing the visual to see it in your post). When you update your visual, the original will still be there in the g element represented by this.container.
So, here's what it might look like on the first run:
Now, if I update the visual in a similar way to you, e.g. changing a slicer value, this happens to your DOM when the update method runs:
And if we expand this, it looks as follows:
Hopefully the above should help illustrate that there are 5 defs now attached, and SVG will just be using the first one that was originally added as it's not been cleared down.
There are more elegant ways to solve this, but for minimal changes to your code, add the following line prior to the var gradient... declaration, e.g.:
...
this.container.select('defs').remove();
var gradient = this.container.append("defs").append("linearGradient").attr("id", "gradient")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
...
This checks for the presence of a defs element and removes it prior to adding the new one, and hopefully this is close to what you're after:
Regards,
Daniel
Proud to be a Super User!
My course: Introduction to Developing Power BI Visuals
On how to ask a technical question, if you really want an answer (courtesy of SQLBI)
Hi @Anonymous,
As we only have your visual.ts to go on, I can't reproduce fully locally to confirm, the first line in your posted snippet is the suspect:
var gradient = this.container.append("defs").append("linearGradient").attr("id", "gradient")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
How this is currently written, will append a defs element to your container element each time the update method runs, rather than replacing it. This is because your container property (and it's children) is persisted across the lifecycle of the visual.
So, when you start your visual and the update method runs for the first time the gradient is applied as you expect (akin to your scenario of refreshing the visual to see it in your post). When you update your visual, the original will still be there in the g element represented by this.container.
So, here's what it might look like on the first run:
Now, if I update the visual in a similar way to you, e.g. changing a slicer value, this happens to your DOM when the update method runs:
And if we expand this, it looks as follows:
Hopefully the above should help illustrate that there are 5 defs now attached, and SVG will just be using the first one that was originally added as it's not been cleared down.
There are more elegant ways to solve this, but for minimal changes to your code, add the following line prior to the var gradient... declaration, e.g.:
...
this.container.select('defs').remove();
var gradient = this.container.append("defs").append("linearGradient").attr("id", "gradient")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
...
This checks for the presence of a defs element and removes it prior to adding the new one, and hopefully this is close to what you're after:
Regards,
Daniel
Proud to be a Super User!
My course: Introduction to Developing Power BI Visuals
On how to ask a technical question, if you really want an answer (courtesy of SQLBI)
Hello @dm-p,
Thank you so much for your detailed explanation. It resolved my issue.
Thank you once again.
No worries! Glad it's working for you 🙂
Proud to be a Super User!
My course: Introduction to Developing Power BI Visuals
On how to ask a technical question, if you really want an answer (courtesy of SQLBI)
March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount!
Check out the January 2025 Power BI update to learn about new features in Reporting, Modeling, and Data Connectivity.