Adding Interactions To Your Power BI Custom Visual

Adding Interactions To Your Power BI Custom Visual

This video explains how to add interactions to your Power BI custom visual. This is video #12 of the Power BI Custom Visual Development Fundamentals series, please check the playlist below for the set.

Video Transcript

Show power bi app on vgsales report editor

Hello again and welcome back.

In this video, we’re gonna look at how to add simple interactions to our little custom bar chart.

If you look at the visual as it stands, you’ll notice that you can’t really click anything at all.

It doesn’t highlight any bar and it won’t filter anything.

In fact, to prove the point and make testing easier, let’s bring in a vanilla bar visual to the side here and set it up to look more or less the same as ours.

And there we have it, a side by side comparison of our custom visual vs versus the vanilla visual from power bi itself.

So what we can notice here is that, if I click on the bars of the vanilla visual, our custom visual will get filtered by that same slice of data I’m clicking on.

Each of these bars on the vanilla visual represents a slice on that particular category so when I click one or more of the bars, the custom visual is filtered on that slice or group of slices, as you can see here.

Now note that we didn’t have to develop anything for our custom visual to accept filtering.

This is something Power BI already does for you behind the scenes by filtering the corresponding data before it reaches your custom visual.

In this way the custom visual is completely oblivious to who or what is triggering that filter.

All it needs to care is, well, I’m receiving this data, I’m going to render as best I can.

And that’s precisely what you’re seeing here.

Now this is all nice and dandy but if I start clicking on our own custom bar chart, well, the result is… absolutely nothing.

The custom visual does not react to clicks and does not affect any other visual.

Now that’s because Power BI doesn’t really know what it is that we are rendering here.

We visually see some bars but Power BI has no oversight of anything happening in the visual’s box.

Therefore, we need to give Power BI hand.

All it takes is some simple steps.

The first thing we need to is to add a property to the visual called selectionManager of type ISelectionManager.

private selectionManager: ISelectionManager;

The selection manager is one of the ways we have to notify power bi of selection changes in our custom visual.

The selection manager allows us to tell power bi that hey, the user has selected something on this visual - you may want to do something about it.

Of course, we need to instantiate it, so let’s go the constructor.

We can call upon the host to create a brand new selection manager just for us.

The selection manager does keep some important state, so it’s best to create only one at startup and call upon it as needed.

this.selectionManager = this.host.createSelectionManager();

Now that we have the basics sorted, let’s get back to the DataPoint interface yet again.

This time we’re going to add a property called identity and this will of type ISelectionId.

Now this is special interface from the Power BI API.

This SelectionId literally represents a slice of data.

We can use these SelectionIds to say that each specific DataPoint represents a specific category or a specific measure or a specific series or a combination of any of these three.

These SelectionIds allow us to send data selection state To Power BI using any combination of slices, no matter how complex.

The Selection IDs themselves are fairly complicated objects, but you don’t need to worry about that too much, as the API helps us build them up from scratch.

One last thing though, I have written the namespace powerbi.visuals there on purpose.

That’s because there are two types called SelectionId in the API.

One is on the powerbi.visuals namespace and the other one is on the powerbi.extensibility namespace.

Currently the API supports two approaches for handling interactions, one more simple and do-it-yourself, and one more heavy-weight and framework driven.

Now for some reason the development team decided to duplicate these types between these two approaches.

The problem is that these two different SelectionId types are not fully interchangeable and using one type in place of the other can cause strange runtime bugs, even when compiling just fine.

Hopefully this is a temporary situation until this bit of the API is stabilized.

For now, out of the two approaches I’m showing you the simple do-it-yourself approach and that requires the SelectionId interface that lives in the powerbi.visuals namespace.

Anyway, the next step, as you can probably imagine, is to go yet again to the view model code and define a selectionId for each data point.

Trustworthy typescript complains as usual that you’re missing the identity property, so, we may as well make it happy.

identity: this.host.createSelectionIdBuilder()
                        .withCategory(categories, i)
                        .createSelectionId()

Let’s fill in the identity property here for each data point.

So we’re doing a couple of things here in single chained statement.

First, we’re asking the Power BI host to create a SelectionId builder object for us.

This gives up a helper object that lets us create the fairly complex SelectionIds from scratch.

Note that we have to create a new builder every time we need a new selection id.

We then say that this selectionId will represent a slice over our category column, whatever that column is in the model, using the category value at position i.

This is simply a generic way of saying, I want to slice by that specific category value.

By the way, we are not limited one slice criteria.

We can add and combine slices over Measures and series and other categories as well.

It’s up to us to say what slice of data this particular DataPoint identifies and we can make it as broad or particular as we want.

Once we’re happy with our slicing, we ask the builder to give us the corresponding SelectionId and we store that in the data point.

So with this we’ve taken care of associating each of our visual bars with a specific slice of data, at least in a way that Power BI can understand.

The last thing we need to do is to make the bars react to clicking and then tell Power BI that something happened and it should go and do something about it.

So for that, let’s get back to rendering code, yet again to the spot where we are defining the behaviour of bar.

What we want to do now is to make each bar react to a mouse click or a tap on the screen.

To wire that up, we can use a D3 on-click event.

.on("click", (d) => {

                });

This goes through each single bar and wires up its click event to trigger the inline function we define here.

When that click happens, D3 does some magic for us and passes in the data point associated with that bar to the click event handler.

This syntax sugar allows to know exactly what bar was clicked and even saves us the trouble of looking the data point.

Yet another thumbs up for D3.

Now we want to do a number of different things here, so let’s take this step by step.

The most important thing is to tell power bi that the user has selected a slice of data.

this.selectionManager.select(d.identity);

The simplest way to do that is to call upon the selection manager and tell it that the user has selected a particular selection id, which we can get from the data point.

Now this is the simplest way, but not necessarily the best, and you can tell why straight away.

Let’s save the file and get to the report.

So let’s see what happens when I click on different bars.

So far so good.

But what if I click on the same one again?

Hmm. Interesting.

So what happening here, is that the default behaviour of the selection manager is to toggle whatever selection you provide to it.

This behaviour is to make it consistent with the vanilla charts, when you’re selecting one data point at a time, so that’s something to keep in mind.

this.selectionManager.select(d.identity, true);

If instead you want to enable multiple selection, you can pass in the parameter true to select method.

As you can see, we can toggle between all of them at will.

Now if you want to really mimic the vanilla visual, you’ll have to change between selecting one item and selecting multiple items, depending on whether the user is pressing a key like control on the keyboard.

However, I’ll leave that as an exercise for you.

For now, we are dearly missing something.

I’m selecting columns left and right, but there’s no user feedback that my selection are being applied.

What we want is a an effect similar to the vanilla visual, we want to dim the colours of all columns that have not been selected and leave only the ones we clicked as being highlighted.

.then(ids => {
        bars.style({
            'fill-opacity': ids.length > 0 ? 0.5 : 1.0
        });
    });

Let’s get back to the click event handler and add a bit more code to it.

So what we’re doing here is basically dimming all columns in the visual, depending on whether any column has been selected or not.

The then function of the selection manager gives us access to all selectionids that are currently, well, selected and saves us from having to go after them.

We then set the fill opacity style on every column to either 50% if there is at least one column selected or 100% if there is no selection at all.

Let’s see how this went.

Not bad.

All that’s left is to actually highlight the selected columns to begin with.

.then(ids => {
        bars.style({
            'fill-opacity': ids.length > 0 ?
                d => ids.indexOf(d.identity) >= 0 ? 1.0 : 0.5 :
                1.0
        });
    });

Let’s change our code here to a little bit smarter.

So we’re adding another condition here.

We’re now saying that if there are any columns selected, then we’re gonna check if each column is selected or not before we decide to dim or leave it highlighted.

For that, we can just see if the selection id or identity of the data point for that column is one of the currently selected selection ids.

That’s all there is to it.

Let’s what this did.

And there you have it.

Some nice interaction between your custom visual and others in the report.

Thanks for watching and make sure you thumbs and subscribe you want to see more videos like this.

In the next video in this series we will add highlighting behaviour to your custom visual so it can react to selections in other visuals, so make sure you enable YouTube notifications to be first one to know.

Until then, take care and see you next time.

Jorge Candeias's Picture

About Jorge Candeias

Jorge helps organizations build high-performing solutions on the Microsoft tech stack.

London, United Kingdom https://jorgecandeias.github.io