Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
augustindelaf
Impactful Individual
Impactful Individual

Add a basic Legend in a custom visual

Hi,

 

I tried to get that from Chart Utils : 

https://github.com/Microsoft/powerbi-visuals-utils-chartutils/blob/master/docs/api/legend.md

and I followed this to install the librarie: 

https://github.com/microsoft/powerbi-visuals-utils-chartutils/blob/master/docs/usage/installation-gu...

 

But without any changes to my code and despite it compiles, the Visual crashes at rendering : 

Uncaught SyntaxError: Cannot use import statement outside a module
    at Object.i [as injectJsCode] (customVisualsHost.bundle.min.js:19)
    at r (customVisualsHost.bundle.min.js:21)
    at i.loadWithoutResourcePackage (customVisualsHost.bundle.min.js:21)
    at i.executeMessage (customVisualsHost.bundle.min.js:21)
    at i.onMessageReceived (customVisualsHost.bundle.min.js:21)
    at customVisualsHost.bundle.min.js:21
    at e.invokeHandler (customVisualsHost.bundle.min.js:20)
    at e.dispatchMessage (customVisualsHost.bundle.min.js:20)
    at e.onMessageReceived (customVisualsHost.bundle.min.js:20)
    at windowMessageHandler (customVisualsHost.bundle.min.js:20)

 

Is there another library to draw a legend ? I do not need sophisticated one.

 

Thank you in advance.

 

Best Regards.

7 REPLIES 7
AakashMarasini
Frequent Visitor

Hi guys,

Thanks for your contribution! @augustindelaf @jppp 

The legends have been developed through the above code. Now, how can we handle the overflow of legend items or how can we add buttons that works like standard power bi legend?
Also need to add the title.

AakashMarasini_0-1697623723132.png

Please help me on this.

Thank You!

dm-p
Super User
Super User

Hi @augustindelaf,

Looks like that documentation is still out of date and uses the older import methods. I worked this out a while ago and the correct steps are:

  • Import library as normal:
npm install powerbi-visuals-utils-chartutils --save
  • Skip over the bits about pbiviz.json and tsconfig.json, as the newer SDK will bundle these up automatically. Older versions of the SDK needed these dependencies including manually.
  • Include the CSS assets as documented in your style.css:
@import (less) "node_modules/powerbi-visuals-utils-interactivityutils/lib/index.css";
@import (less) "node_modules/powerbi-visuals-utils-chartutils/lib/index.css";

Hopefully this gives you some guidance on how to proceed. Good luck!

Daniel





Did I answer your question? Mark my post as a solution!

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)




augustindelaf
Impactful Individual
Impactful Individual

Hi Daniel,

 

Thank you very much, your answer helped a lot to understand how it works. 😉


I have subsidiary questions.

1) I do not see where to set the inputdata in your renderLegend function (for example, I expected an object parameter in the drawLegend method) to have the correct behavior : 
For each dot forming the scatter plot of my visual (all dots having a different shape), I need to display in the legend the identifier of the data with the correct shape used and the correct color.

Legend data is usually a parameter field in the panel  but I don't need it because the scatter plot data I have is the information I need.

2) I have no idea what format is your Constants in the dependancies section (

 

import { VisualConstants } from '../constants'

 

) you use to manage the dimensions of your legend box.

 

3) In case I have to use the fields panel after all, is it have I to use datarole + capabilities.json to do it ? 


Conclusion : 

I wish not to use data field in the panel to get data for legend because it wil be redundant with the data used by the visual itself but rather the data object I built (in my update.ts) as an array of objects having all informations needed.

Please feel free to tell me if my wish is not a best practice.

Thank you in advance.

Best regards.

Hi @augustindelaf,

 

Lately I am always creating legend myself: tried the legend of the chartutils, but found it to complicated/to little control.

 

How I do it:

1. part of the method to convert the dataView data to your internal data structure store the legend values seperatly

2. in the init method add an SVG g container/placeholder and store in in a private variable

 

this.legend = this.svg.append("g").classed("legend", true);

 

3. use d3 functionallity to create the legend based on the data structure of step 1 and allign all the legend labels not to overlap each other, see the .each(function () {}) part

 

this.legend
    .selectAll(".legendItem")
    .data(legendNodes)
    .join(enter => enter
        .append("g")
        .classed("legendItem", true)
            .each(function (d) {
                select(this)
                    .append("circle")
                    .classed("legendMarker", true)
                    .attr("r", 5)
                    .style("fill", d.data.color)
                select(this)
                    .append("text")
                    .classed("legendText", true)
                    .attr("x", 7.5)
                    .attr("y", 4)
                    .style("alignment-baseline", "baseline")
                    .text(d.data.label.value)
            })
            .each(function () {
                let size = (<SVGGElement>this).getBoundingClientRect();
                select(this)
                    .attr("transform", `translate(${moveX} 0)`)
                moveX += size.width + 5;
            }),
        update => update
                .each(function (d) {
                    select(this)
                        .selectAll(".legendMarker")
                        .style("fill", d.data.color)
                    select(this)
                        .selectAll(".legendText")
                        .text(d.data.label.value)
                })
                .each(function (d) {
                    let size = (<SVGGElement>this).getBoundingClientRect();
                    select(this)
                        .attr("transform", `translate(${moveX} 0)')
                    moveX += size.width + 5;
                }),
            exit => exit
                .remove()
            );​

 

4. Positioning of the legend you can do via the legend container including the visibility if needed

 

Feel free to see if this is working for you.

 

-JP

augustindelaf
Impactful Individual
Impactful Individual

Hi @jppp ,

 

Thank you very much for your answer.

 

 I tried your code but sadly, nothing displays yet : I am reviewing if I made no mistake.

To help me for my reviewing, I have some questions : 

1) You use the keyword "select" in your function, This keyword is unknown in my code. What does it refer to ? I assumed "selectAll".

2) There is the variable moveX. I assume it is a number but where to initialize it ?

3) For your 2) I have no Init  method, I assume the init of the legend to be in the constructor. Am I correct ?

 

Once again thank you for your time.

 

Best regards.

Hi @augustindelaf ,

 

Sorry missed to provide some extra information:

1. I am using d3-selection and you can import it via 

import { select, Selection } from "d3-selection";

2. And just before the settings the legend variable set the moveX variable as:

let moveX = 0;

 3. Sorry I mean indeed the contructor instead of the init.

 

-JP

augustindelaf
Impactful Individual
Impactful Individual

Hi @jppp,

 

Thank you. 

The legend appeared on first rendering but disapeared on updating.

I will try to relocate the init of the Legend to understand why. 🙂

 

Thank you, your contribution saved me 😉

 

Best Regards.

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.