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
BrentonC
Helper I
Helper I

Custom Visual Tooltip Data Option

Hello,

I have been working on a custom visual and would like to add a tooltip to it, although I can not get the option to appear in the "fields" area, to add data into it. Any help would be appreciated.
capabilities.json 

 

 

{    
    "objects": {},
   
    
    "dataRoles": [
        {
            "displayName": "CCFV",
            "name": "category1",
            "kind": "Grouping"
           
        }
    ],
    "tooltips": {
        "supportedTypes": {
        "default": true,
        "canvas": true
    },
        "roles": [
        "tooltips"
        ]},
    "dataViewMappings": [
        {
            "conditions": [
                {
                    "category1": {
                        "max": 1
                    }
                }
            ],
            "table": {
                "rows": {
                    "for": {
                        "in": "category1"
                    }
                }
            }
        }
    ]
}

 

 

 

Image of the editor.

 
 

img.PNG

 

visual.ts (some of it)

 

 

 

"use strict";
import "core-js/stable";
import "../style/visual.less";
import powerbi from "powerbi-visuals-api";
import IVisual = powerbi.extensibility.IVisual;
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
import VisualObjectInstanceEnumeration = powerbi.VisualObjectInstanceEnumeration;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import DataView = powerbi.DataView;
import VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem;

import * as d3 from "d3";
import {
    createTooltipServiceWrapper,
    ITooltipEventArgs,
    ITooltipServiceWrapper,
} from "./tooltipServiceWrapper";

type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;



export class Visual implements IVisual {
    private element: HTMLElement;
    private isLandingPageOn: boolean;
    private LandingPageRemoved: boolean;
    private host: IVisualHost;
    private svg: Selection<SVGElement>;
    private container: Selection<SVGElement>;
    private circle: Selection<SVGElement>;
    private textValue: Selection<SVGElement>;
    private textLabel: Selection<SVGElement>;
    // Declare an array list for the line objects
    private lineOffset: Selection<SVGElement>;
    private arr = new Array();
    private arrDots = new Array();
    // Declare as array of integers to hold the segments of the circle
    private arrSegments = new Array();
    private arrOffsetSegments = new Array();
    private singleSegment: number;
    private categorys: number = 17;
    private CenterarrayOffset_ = new Array();
    private LandingPage: Selection<any>;
    virificationArray: string[];
    private tooltipServiceWrapper: ITooltipServiceWrapper;


    constructor(options: VisualConstructorOptions) {
        this.element = options.element;
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('circleCard', true);
        this.host = options.host;
        this.container = this.svg.append("g")
            .classed('container', true);
            this.tooltipServiceWrapper = createTooltipServiceWrapper(this.host.tooltipService, options.element);
            this.tooltipServiceWrapper.addTooltip(this.container.selectAll('.circleCard'),
            (tooltipEvent: ITooltipEventArgs<number>) => Visual.getTooltipData(tooltipEvent.data),
            (tooltipEvent: ITooltipEventArgs<number>) => tooltipEvent.data[0]);
    }

 

 

 

 

1 ACCEPTED SOLUTION
dm-p
Super User
Super User

Hi @BrentonC,

In your capabilities, you specified a role named "tooltips", but haven't supplied a dataRole for it, so update the dataRoles section of your capabilities as follows:

{
    ...
    "dataRoles": [
        {
            "displayName": "CCFV",
            "name": "category1",
            "kind": "Grouping"
        },
        {
            "displayName": "Tooltips",
            "name": "tooltips",
            "kind": "Measure"
        }
    ],
    ...
}

(the kind could be GroupingOrMeasure also, as you're using the table data view mapping; I've just gone with Measure for now)

This will then show up a place to add measure fields:

image.png

The sample bar chart has a very similar setup to this.

However if you want to make use of the measure(s) you pass in here, you'll need to update your dataViewMapping, as it will not appear in there and as such will not be accessible to the visual (note that only Dose is present):

image.png

I've modified this as follows:

{
    ...
    "dataViewMappings": [
        {
            "conditions": [
                {
                    "category1": {
                        "max": 1
                    }
                }
            ],
            "table": {
                "rows": {
                    "select": [
                        {
                            "for": {
                                "in": "category1"
                            }
                        },
                        {
                            "for": {
                                "in": "tooltips"
                            }
                        }
                    ]
                    
                }
            }
        }
    ]
    ...
}

Now, this will be accessible to the visual's data view, e.g.:

image.png

You'll then need to update your view model to include the tooltip data when you map the data view, and ensure that your getTooltipData function iterates through any additional measures you've added so that it knows what to display when the tooltip is rendered - unfortunately you haven't supplied these parts of your code for me to check, but it should be fairly straightforward for you to do if you're already mapping your category1 role into the visual's view model 🙂

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)




View solution in original post

4 REPLIES 4
dm-p
Super User
Super User

Hi @BrentonC,

In your capabilities, you specified a role named "tooltips", but haven't supplied a dataRole for it, so update the dataRoles section of your capabilities as follows:

{
    ...
    "dataRoles": [
        {
            "displayName": "CCFV",
            "name": "category1",
            "kind": "Grouping"
        },
        {
            "displayName": "Tooltips",
            "name": "tooltips",
            "kind": "Measure"
        }
    ],
    ...
}

(the kind could be GroupingOrMeasure also, as you're using the table data view mapping; I've just gone with Measure for now)

This will then show up a place to add measure fields:

image.png

The sample bar chart has a very similar setup to this.

However if you want to make use of the measure(s) you pass in here, you'll need to update your dataViewMapping, as it will not appear in there and as such will not be accessible to the visual (note that only Dose is present):

image.png

I've modified this as follows:

{
    ...
    "dataViewMappings": [
        {
            "conditions": [
                {
                    "category1": {
                        "max": 1
                    }
                }
            ],
            "table": {
                "rows": {
                    "select": [
                        {
                            "for": {
                                "in": "category1"
                            }
                        },
                        {
                            "for": {
                                "in": "tooltips"
                            }
                        }
                    ]
                    
                }
            }
        }
    ]
    ...
}

Now, this will be accessible to the visual's data view, e.g.:

image.png

You'll then need to update your view model to include the tooltip data when you map the data view, and ensure that your getTooltipData function iterates through any additional measures you've added so that it knows what to display when the tooltip is rendered - unfortunately you haven't supplied these parts of your code for me to check, but it should be fairly straightforward for you to do if you're already mapping your category1 role into the visual's view model 🙂

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)




I am still having issues with getting my tooltips to display, I am sure it is how I have possibly implemented them in the visual.ts file?

 

"use strict";
import "core-js/stable";
import "../style/visual.less";
import powerbi from "powerbi-visuals-api";
import { dict } from './images'; 
import IVisual = powerbi.extensibility.IVisual;
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
import VisualObjectInstanceEnumeration = powerbi.VisualObjectInstanceEnumeration;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import DataView = powerbi.DataView;
import VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem;
import * as d3 from "d3";

import {
    TooltipEventArgs,
    TooltipEnabledDataPoint,
    createTooltipServiceWrapper,
    ITooltipServiceWrapper,
} from 'powerbi-visuals-utils-tooltiputils'


type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;



export class Visual implements IVisual {
    private element: HTMLElement;
    private isLandingPageOn: boolean;
    private LandingPageRemoved: boolean;
    private host: IVisualHost;
    private svg: Selection<SVGElement>;
    private container: Selection<SVGElement>;
    private circle: Selection<SVGElement>;
    // Declare an array list for the line objects
    private lineOffset: Selection<SVGElement>;
    private arr = new Array();
    private arrDots = new Array();
    // Declare as array of integers to hold the segments of the circle
    private arrSegments = new Array();
    private arrOffsetSegments = new Array();
    private singleSegment: number;
    private categorys: number = 17;
    private CenterarrayOffset_ = new Array();
    private CenterarrayOffset_bk = new Array();
    private LandingPage: Selection<any>;
    virificationArray: string[];
    private tooltipServiceWrapper: ITooltipServiceWrapper;
   



    constructor(options: VisualConstructorOptions) {
        this.element = options.element;
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('circleCard', true);
        this.host = options.host;
        this.container = this.svg.append("g")
            .classed('container', true);

            
    }

    

    
    private static getTooltipData(value: any): VisualTooltipDataItem[] {
        return [{
            displayName: value.category,
            value: value.value.toString(),
            color: value.color,
            header: 'ToolTip Title'
        }];
    }
    private HandleLandingPage(options: VisualUpdateOptions) {
        console.log("landing")
        if(!options.dataViews || !options.dataViews.length) {
            if(!this.isLandingPageOn) {
                this.isLandingPageOn = true;
                const SampleLandingPage: Element = this.createSampleLandingPage();
                this.element.appendChild(SampleLandingPage);

                this.LandingPage = d3.select(SampleLandingPage);
            }

        } else {
                if(this.isLandingPageOn && !this.LandingPageRemoved){
                    this.LandingPageRemoved = true;
                    this.LandingPage.remove();
                }
            
        }
    }

    private createSampleLandingPage(): Element {
        let div = document.createElement("div");

        let header = document.createElement("h1")
        header.textContent = "Sample Bar Chart Landing Page";
        header.setAttribute("class","LandingPage");
        
        let p1 = document.createElement("a");
        p1.setAttribute("class", "LandingPageHelpLink");
        p1.textContent = "Learn more about Landing page";

        

        div.appendChild(header);
        div.appendChild(p1);

        return div;
    }
   
    public update(options: VisualUpdateOptions) {
        
        
        let dataView_: DataView = options.dataViews[0];
        // this.host.fetchMoreData();
        let width: number = options.viewport.width;
        let height: number = options.viewport.height;
        this.svg.attr("width", width);
        this.svg.attr("height", height);
        let radius: number = Math.min(width, height) / 2.4;
        let radiusDot: number = Math.min(width, height) / 250;
        let centerOffset: number;
        let cX: number;
        let cY: number;

        let cX_: number;
        let cY_: number;
        let cXOffset: number;
        let cYOffset: number;
        let counter: number;
        let counter1: number;
        let entryCounter: number;
        let ccfvfColour: string;
        this.CenterarrayOffset_ = new Array();
        this.CenterarrayOffset_bk = new Array();
        this.virificationArray = new Array();
        let colourCounter: number;
        let colourString: string;

        // To prevent from drawing everyting over and over again, remove all drawing and start again.
        this.svg.selectAll('circle').remove();
        this.svg.selectAll('image').remove();



        
        this.HandleLandingPage(options);
        entryCounter = 0
        
        for (var j = 0; j < dataView_.table.rows.length; j++) {
            if (
                this.virificationArray.indexOf(dataView_.table.rows[j].toString().split(",")[2]) > -1){

                }
                else{
                    this.virificationArray.push(String(dataView_.table.rows[j].toString().split(",")[2]))
                }

            }


        this.circle = this.container.append("circle")
            .classed('circle', true);




        // Create the lines for the categorys to split the kelly wheel into 17 sections

        for (let i = 0; i < this.categorys; i++) {
            this.arr.push(this.container.append("line").classed("line_" + i, true));
        }

        // Get the single segments of the kelly wheel in deg of 360
        this.singleSegment = 360 / this.arr.length;
        for (var i = 0; i < this.arr.length; i++) {
            this.arrSegments.push(this.singleSegment * i)
        }

        for (var a = 0; a < this.virificationArray.length; a++) {
 
            this.arrDots[a] = new Array();
            entryCounter = 0
           
            for (var j = 0; j < dataView_.table.rows.length; j++) {
                if (
                    dataView_.table.rows[j].toString().split(",")[2] == this.virificationArray[a]) {
                    entryCounter = entryCounter + 1
                }
            }

            for (var i = 0; i < entryCounter; i++) {
                this.arrDots[a].push(this.container.append("circle").classed("circle__" + a + "_" + i, true));
            }
        }

        /*
        *  Get the edge of the circle
        */
        this.circle
            .style("stroke", "black")
            .style("stroke-width", 2)
            .attr("r", radius)
            .attr("cx", width / 2)
            .attr("cy", height / 2)
            .style("fill", "#ffe500");


        counter = 0
        counter1 = 0
        
        for (var i = 0; i < 17; i++) {
            cX = (width / 2) + radius * Math.cos(this.arrSegments[i] * Math.PI / 180);
            cY = (height / 2) + radius * Math.sin(this.arrSegments[i] * Math.PI / 180);

            cX_ = width / 2 - radius  * Math.cos(this.arrSegments[i] );
            cY_ = height / 2 - radius * Math.sin(this.arrSegments[i] );

            centerOffset = 40;
            // outer offset
            cXOffset = (width / 2) + radius * Math.cos((this.arrSegments[i]) * Math.PI / 180);
            cYOffset = (height / 2) + radius * Math.sin(this.arrSegments[i] * Math.PI / 180);

            this.arr[i]
                .attr("x1", '50%')
                .attr("y1", '50%')
                .attr("x2", cX)
                .attr("y2", cY)
                .attr("stroke-width", 3)
                .attr("stroke", "black");
            centerOffset = 0



            // left right | up down | in out
            this.CenterarrayOffset_ =
                // First loop
                [[23, 4, .06], //1
                [20, 13, .06], //2
                [15, 19, .06], //3
                [4, 22, .06], //4
                [-3, 23, .06],//5
                [-11, 20, .06],//6
                [-18, 16, .06],//7
                [-22, 6, .06],//8
                [-22, -1, .06],//9
                [-20, -9, .06],//10
                [-14, -16, .06],//11
                [-9, -20, .06],//12
                [-1, -20, .06],//13
                [7, -20, .06],//14
                [13, -17, .06],//15
                [18, -11, .06],//16
                [22, -3, .06]]//17

            for (var z = 0; z < this.arrDots[counter].length; z++) {
                if(z >=138){
                    // Max 138 per FV section
                    continue
                }

                colourCounter = 0
            

                for (var j = 0; j < dataView_.table.rows.length; j++) {
                  
                //    console.log(this.virificationArray[a])
                    if (
                        dataView_.table.rows[j].toString().split(",")[2] == this.virificationArray[i]) {
                            
                        colourCounter = colourCounter + 1
                    }

                    if (colourCounter == z) {
                        colourString = dataView_.table.rows[j].toString().split(",")[1]
                    }
                }

                if (colourString == "Yes") {
                    ccfvfColour = "green"
                }
                else {
                    ccfvfColour = "red"
                }

                this.arrDots[i][z]
                    .style("fill", ccfvfColour)
                    .style("stroke", ccfvfColour)
                    .style("stroke-width", 2)
                    .attr("r", radiusDot)
                    .attr("cx", (this.CenterarrayOffset_[counter1][2] + centerOffset) * (cXOffset - (width / 2) + this.CenterarrayOffset_[counter1][0]) + (width / 2) + this.CenterarrayOffset_[counter1][0])
                    .attr("cy", (this.CenterarrayOffset_[counter1][2] + centerOffset) * (cYOffset - (height / 2) + this.CenterarrayOffset_[counter1][1]) + (height / 2) + this.CenterarrayOffset_[counter1][1])
                    
                    
                    ;
                centerOffset = (radius / 800000) + centerOffset + 0.025
               if(z == 0){
                this.CenterarrayOffset_bk = [
                    [15,    10, .48], //1
                    [0,    20, .48], //2
                    [-15,    22, .48], //3
                    [-30,     23, .48], //4
                    [-40,    12, .48],//5
                    [-44,   3, .48],//6
                    [-48,   -12, .48],//7
                    [-47,   -27, .48],//8
                    [-45,   -37, .48],//9    6
                    [-35, -45, .48],//10
                    [-20, -53, .48],//11
                    [-10, -50, .48],//12
                    [6, -45, .48],//13
                    [15, -38, .48],//14
                    [24, -28, .48],//15
                    [36, -18, .48],//16
                    [40, -8, .48]]
            
        
                this.container.append("svg:image")
                .attr("xlink:href",dict[this.virificationArray[i]])
                .attr("x", (.9 + centerOffset) * (cXOffset - (width / 2) + this.CenterarrayOffset_bk[counter1][0]) + (width / 2) + this.CenterarrayOffset_bk[counter1][0])
                .attr("y", (.9 + centerOffset) * (cYOffset - (height / 2) + this.CenterarrayOffset_bk[counter1][1]) + (height / 2) + this.CenterarrayOffset_bk[counter1][1]).
                attr("width", 50)
                .attr("height", 50);;
             

               }
                if (z == 29) {

                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [28, 12, .08], //1
                        [20, 22, .08], //2
                        [13, 29, .08], //3
                        [0, 31, .08], //4
                        [-10, 28, .08],//5
                        [-19, 22, .08],//6
                        [-27, 15, .08],//7
                        [-30, 2, .08],//8
                        [-28, -8, .08],//9
                        [-23, -18, .08],//10   2
                        [-15, -25, .08],//11
                        [-7, -28, .08],//12
                        [5, -27, .08],//13
                        [14, -24, .08],//14
                        [22, -19, .08],//15
                        [28, -9, .08],//16
                        [30, 2, .08]]
                }

                if (z == 58) {
                    //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [28,    19, .18], //1
                        [19,    30, .18], //2
                        [5,    32, .18], //3
                        [-7,     31, .18], //4
                        [-17,    28, .18],//5
                        [-27,   21, .18],//6
                        [-33,   9, .18],//7   3
                        [-34,   -3, .18],//8
                        [-28,   -15, .18],//9
                        [-25, -27, .18],//10
                        [-14, -33, .18],//11
                        [1, -30, .18],//12
                        [11, -27, .18],//13
                        [22, -24, .18],//14
                        [28, -15, .18],//15
                        [32, -3, .18],//16
                        [30, 9, .18]]
                }

                if (z == 82) {
                    //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [28,    26, .26], //1
                        [17,    37, .26], //2
                        [-2,    36, .26], //3
                        [-14,     32, .26], //4
                        [-25,    28, .26],//5
                        [-35,   20, .26],//6
                        [-39,   5, .26],//7
                        [-39,   -9, .26],//8    4
                        [-28,   -22, .26],//9
                        [-23, -35, .26],//10
                        [-10, -39, .26],//11
                        [7, -34, .26],//12
                        [18, -27, .26],//13
                        [28, -18, .26],//14
                        [34, -10, .26],//15
                        [36, 3, .26],//16
                        [30, 16, .26]]
                }


                if (z == 102) {
                    //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [19,    33, .39], //1
                        [6,    40, .39], //2
                        [-9,    40, .39], //3
                        [-22,     31, .39], //4
                        [-33,    22, .39],//5
                        [-38,   9, .39],//6
                        [-40,   -5, .39],//7
                        [-32,   -20, .39],//8
                        [-25,   -30, .39],//9
                        [-12, -39, .39],//10
                        [1, -39, .39],//11
                        [16, -33, .39],//12    5
                        [26, -25, .39],//13
                        [34, -16, .39],//14
                        [35, 1, .39],//15
                        [36, 12, .39],//16
                        [30, 24, .39]]
                }

                if (z == 120) {
                    //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [17,    40, .54], //1
                        [0,    45, .54], //2
                        [-15,    43, .54], //3
                        [-30,     31, .54], //4
                        [-40,    21, .54],//5
                        [-44,   6, .54],//6
                        [-43,   -12, .54],//7
                        [-33,   -27, .54],//8
                        [-25,   -37, .54],//9    6
                        [-10, -45, .54],//10
                        [9, -41, .54],//11
                        [24, -33, .54],//12
                        [33, -25, .54],//13
                        [40, -12, .54],//14
                        [41, 5, .54],//15
                        [36, 20, .54],//16
                        [30, 31, .54]]
                }


                
                if (z == 132) {
                   //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [15,    47, .70], //1
                        [-4,    50, .70], //2
                        [-23,    43, .63], //3
                        [-37,     31, .63], //4
                        [-47,    21, .63],//5
                        [-50,   3, .63],//6
                        [-43,   -21, .63],//7    7
                        [-37,   -32, .63],//8
                        [-21,   -44, .63],//9
                        [-4, -50, .63],//10
                        [15, -45, .63],//11
                        [31, -34, .63],//12
                        [40, -24, .63],//13
                        [46, -8, .63],//14
                        [47, 8, .63],//15
                        [35, 28, .63],//16
                        [30, 38, .63]]
                }

                if (z == 152) {
                    //-  left right +|- up down +| in out
                    centerOffset = 0
                    this.CenterarrayOffset_ = [
                        [11,    52, .80], //1
                        [-11,    53, .80], //2
                        [-29,    45, .80], //3
                        [-43,     31, .80], //4
                        [-53,    16, .80],//5
                        [-53,   -5, .80],//6
                        [-47,   -25, .80],//7
                        [-35,   -40, .80],//8
                        [-21,   -50, .80],//9
                        [0, -55, .80],//10    8
                        [18, -50, .80],//11
                        [36, -37, .80],//12
                        [47, -24, .80],//13
                        [52, -6, .80],//14
                        [50, 14, .80],//15
                        [40, 31, .80],//16
                        [30, 44, .80]]
                }

                if (z == 140) {
                    // left right | up down | in out
                    centerOffset = 0
                    // Get the remainder of CCFV and add a number to the end of the column

                }


            }
            this.svg.selectAll("line").raise()
            counter = counter + 1
            counter1 = counter1 + 1

   
        }

        this.tooltipServiceWrapper.addTooltip(this.svg.selectAll('circle'), 
       (tooltipEvent: TooltipEventArgs<number>) => 
 Visual.getTooltipData(tooltipEvent.data),
        (tooltipEvent: TooltipEventArgs<number>) => null);
        
        this.arrDots = []
        this.arr = []
    }
}

Update:

I ended up getting it sorted, I added each object as they were made in a loop as such.

 

                let dot = this.arrDots[i][z]
                    .style("fill", ccfvfColour)
                    .style("stroke", ccfvfColour)
                    .style("stroke-width", 2)
                    .attr("r", radiusDot)
                    .attr("cx", (this.CenterarrayOffset_[counter1][2] + centerOffset) * (cXOffset - (width / 2) + this.CenterarrayOffset_[counter1][0]) + (width / 2) + this.CenterarrayOffset_[counter1][0])
                    .attr("cy", (this.CenterarrayOffset_[counter1][2] + centerOffset) * (cYOffset - (height / 2) + this.CenterarrayOffset_[counter1][1]) + (height / 2) + this.CenterarrayOffset_[counter1][1])
                
                    this.tooltipServiceWrapper.addTooltip(dot,
                        (tooltipEvent: TooltipEventArgs<number>) => this.getTooltipData(tooltipEvent.data),
                        (tooltipEvent: TooltipEventArgs<number>) => null
                        // Get the remainder of CCFV and add a number to the end of the column
                        )

 Thank You 

Thank you very much, I am currently working on getting it sorted as I get stuck I'll post again for sure.

 

Brenton Collins

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.