Forum Discussion

Anonymous's avatar
Anonymous
Not applicable
8 years ago
Solved

Creating a Pie chart visual with Static Data.

Hi guys. I'm trying to create a pie chart power Bi visual for practicing custom visual creation.I have followed the tutorial given in the github repo for the environment setup and now is currently on the first step , ie creating visual with static data.

The visual is being built and served correctly.But when I insert the visual in the powerBi service,all i get is a blank  screen.
Can someone help? I'm new to d3 and TypeScript, so there may be a chance that I may have made some silly mistakes.
Here's my code: 

 

module powerbi.extensibility.visual {
    "use strict";

    interface Data 
    {        
    quantity: number;
    category: string;
    }

    export class PieChart implements IVisual {
        private target: HTMLElement;        
        private settings: VisualSettings;
        private textNode: Text;
        private pieChartContainer:d3.Selection<SVGElement>;
        private arc:any;
        private host:IVisualHost;
        private svg:d3.Selection<SVGElement>;
        private g:any;
        private pie:any;
        private color:string;

        constructor(options: VisualConstructorOptions) {
            console.log('Visual constructor', options);
            this.target = options.element;
            this.host=options.host;
            let svg=this.svg=d3.select(options.element)
                                .append('svg')
                                .classed("pieChart",true);
            this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);                        
        }


        public update(options: VisualUpdateOptions) {
            this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
            let testData: Data[] = [
                {
                    quantity: 25,
                    category: 'a'
                },
                {
                    quantity: 50,
                    category: 'b'
                },
                {
                    quantity: 100,
                    category: 'c'
                },
                {
                    quantity: 200,
                    category: 'd'
                },
                {
                    quantity: 300,
                    category: 'e'
                }];
          
            let width=options.viewport.width;
            let height=options.viewport.height;
            let radius=Math.min(width,height)/2;
            this.svg.attr({
                width:width,
                height:height,
            });
            let colourValues = d3.scale.category20c();
            this.arc=d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius-20);
            this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity);
            let fill = (d=> colourValues(d.category));
            let tf   =  d => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;
            this.svg.append('g')
            .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            this.g=this.svg.selectAll('.arc')
                    .data(this.pie(testData))
                    .enter()
                    .append('g')
                    .attr('class', 'arc')
                    .data(this.pie(testData));

            this.g.append('path')
                    .attr('d', this.arc)
                    .attr('fill', fill)
                    .style("stroke","black")
                    .style("stroke-width","0.8")
                    .on("mouseover",d=>
                     {
                                            
                    d3.select(d)
                    .attr('fill','blue')
                    .style('opacity','0.6')
                    .attr('d',this.arc)
                    .style("stroke","black")
                    .style("stroke-width","3");
                    
                    this.color=d.getAttribute('fill');

                     })
                    
                    .on("mouseout",d=>
                     {   
                    d3.select(d)
                    .attr('fill',colourValues(this.color))
                    .style("opacity","1")
                    .attr('d',this.arc)
                    .style("stroke-width","0.8");
                   
                    
                    }).append("svg:title");
                    //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
                    this.g.append('text').attr('transform', tf).text(text);
        }


        private static parseSettings(dataView: DataView): VisualSettings {
            return VisualSettings.parse(dataView) as VisualSettings;
        }

        /** 
         * This function gets called for each of the objects defined in the capabilities files and allows you to select which of the 
         * objects and properties you want to expose to the users in the property pane.
         * 
         */
        public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
            return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
        }
    }
}
  • v-viig's avatar
    v-viig
    8 years ago

    Please take a look at this fixed version:

    module powerbi.extensibility.visual {
        "use strict";
    
        interface Data {
            quantity: number;
            category: string;
        }
    
        export class PieChart implements IVisual {
            private target: HTMLElement;
            private settings: VisualSettings;
            private textNode: Text;
            private pieChartContainer: d3.Selection<SVGElement>;
            private arc: any;
            private host: IVisualHost;
            private svg: d3.Selection<SVGElement>;
            private g: any;
            private pie: any;
            private color: string;
    
            constructor(options: VisualConstructorOptions) {
                debugger;
                console.log('Visual constructor', options);
                this.target = options.element;
                this.host = options.host;
                let svg = this.svg = d3.select(options.element)
                    .append('svg')
                    .classed("pieChart", true);
    
                this.pieChartContainer = svg
                    .append('g')
                    .classed('pieChartContainer', true);
            }
    
    
            public update(options: VisualUpdateOptions) {
                console.log(options);
    
                this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
                let testData: Data[] = [
                    {
                        quantity: 25,
                        category: 'a'
                    },
                    {
                        quantity: 50,
                        category: 'b'
                    },
                    {
                        quantity: 100,
                        category: 'c'
                    },
                    {
                        quantity: 200,
                        category: 'd'
                    },
                    {
                        quantity: 300,
                        category: 'e'
                    }];
    
                let width = options.viewport.width;
                let height = options.viewport.height;
                let radius = Math.min(width, height) / 2;
    
                this.svg.attr({
                    width: width,
                    height: height,
                });
    
                let colourValues = d3.scale.category20c();
    
                this.arc = d3.svg.arc()
                    .innerRadius(0)
                    .outerRadius(radius - 20);
                this.pie = d3.layout.pie<Data>().value((d: Data): number => d.quantity);
                let fill = (d => colourValues(d.category));
                let tf = d => `translate(${this.arc.centroid(d)})`;
                let text = d => d.data.category;
    
                this.pieChartContainer.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
    
    
                this.g = this.pieChartContainer.selectAll('.arc')
                    .data(this.pie(testData))
                    .enter()
                    .append('g')
                    .attr('class', 'arc')
                    .data(this.pie(testData));
    
                this.g.append('path')
                    .attr('d', this.arc)
                    .attr('fill', fill)
                    .style("stroke", "black")
                    .style("stroke-width", "0.8")
                    .on("mouseover", d => {
    
                        d3.select(d)
                            .attr('fill', 'blue')
                            .style('opacity', '0.6')
                            .attr('d', this.arc)
                            .style("stroke", "black")
                            .style("stroke-width", "3");
    
                        this.color = d.getAttribute('fill');
    
                    })
    
                    .on("mouseout", d => {
                        d3.select(d)
                            .attr('fill', colourValues(this.color))
                            .style("opacity", "1")
                            .attr('d', this.arc)
                            .style("stroke-width", "0.8");
    
    
                    }).append("svg:title");
                //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
                this.g.append('text').attr('transform', tf).text(text);
            }
    
    
            private static parseSettings(dataView: DataView): VisualSettings {
                return VisualSettings.parse(dataView) as VisualSettings;
            }
    
            /** 
             * This function gets called for each of the objects defined in the capabilities files and allows you to select which of the 
             * objects and properties you want to expose to the users in the property pane.
             * 
             */
            public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
                return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
            }
        }
    }

    Ignat Vilesov,

    Software Engineer

     

    Microsoft Power BI Custom Visuals

    [email protected]

10 Replies

  • Anonymous's avatar
    Anonymous
    Not applicable

    Hi guys. I'm trying to create a pie chart power Bi visual for practicing custom visual creation.I have followed the tutorial given in the github repo for the environment setup and now is currently on the first step , ie creating visual with static data.

    The visual is being built and served correctly.But when I insert the visual in the powerBi service,all i get is a blank  screen.
    Can someone help? I'm new to d3 and TypeScript, so there may be a chance that I may have made some silly mistakes.
    Here's my code: 

    module powerbi.extensibility.visual {
        "use strict";
    
        interface Data 
        {        
        quantity: number;
        category: string;
        }
    
        export class PieChart implements IVisual {
            private target: HTMLElement;        
            private settings: VisualSettings;
            private textNode: Text;
            private pieChartContainer:d3.Selection<SVGElement>;
            private arc:any;
            private host:IVisualHost;
            private svg:d3.Selection<SVGElement>;
            private g:any;
            private pie:any;
            private color:string;
    
            constructor(options: VisualConstructorOptions) {
                console.log('Visual constructor', options);
                this.target = options.element;
                this.host=options.host;
                let svg=this.svg=d3.select(options.element)
                                    .append('svg')
                                    .classed("pieChart",true);
                this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);                        
            }
    
    
            public update(options: VisualUpdateOptions) {
                this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
                let testData: Data[] = [
                    {
                        quantity: 25,
                        category: 'a'
                    },
                    {
                        quantity: 50,
                        category: 'b'
                    },
                    {
                        quantity: 100,
                        category: 'c'
                    },
                    {
                        quantity: 200,
                        category: 'd'
                    },
                    {
                        quantity: 300,
                        category: 'e'
                    }];
              
                let width=options.viewport.width;
                let height=options.viewport.height;
                let radius=Math.min(width,height)/2;
                this.svg.attr({
                    width:width,
                    height:height,
                });
                let colourValues = d3.scale.category20c();
                this.arc=d3.svg.arc()
                .innerRadius(0)
                .outerRadius(radius-20);
                this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity);
                let fill = (d=> colourValues(d.category));
                let tf   =  d => `translate(${this.arc.centroid(d)})`;
                let text = d => d.data.category;
                this.svg.append('g')
                .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
                this.g=this.svg.selectAll('.arc')
                        .data(this.pie(testData))
                        .enter()
                        .append('g')
                        .attr('class', 'arc')
                        .data(this.pie(testData));
    
                this.g.append('path')
                        .attr('d', this.arc)
                        .attr('fill', fill)
                        .style("stroke","black")
                        .style("stroke-width","0.8")
                        .on("mouseover",d=>
                         {
                                                
                        d3.select(d)
                        .attr('fill','blue')
                        .style('opacity','0.6')
                        .attr('d',this.arc)
                        .style("stroke","black")
                        .style("stroke-width","3");
                        
                        this.color=d.getAttribute('fill');
    
                         })
                        
                        .on("mouseout",d=>
                         {   
                        d3.select(d)
                        .attr('fill',colourValues(this.color))
                        .style("opacity","1")
                        .attr('d',this.arc)
                        .style("stroke-width","0.8");
                       
                        
                        }).append("svg:title");
                        //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
                        this.g.append('text').attr('transform', tf).text(text);
            }
    
    
            private static parseSettings(dataView: DataView): VisualSettings {
                return VisualSettings.parse(dataView) as VisualSettings;
            }
    
            /** 
             * This function gets called for each of the objects defined in the capabilities files and allows you to select which of the 
             * objects and properties you want to expose to the users in the property pane.
             * 
             */
            public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
                return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
            }
        }
    }
  • v-viig's avatar
    v-viig
    Community Champion

    Hello Anonymous,

     

    I'm wondering if you can clarify these items:

    • Did you install d3 by executing npm i [email protected] --save?
    • Did you include d3 into externalJS property of pbiviz.json? (example)

     

    Ignat Vilesov,

    Software Engineer

     

    Microsoft Power BI Custom Visuals

    [email protected]

    • Anonymous's avatar
      Anonymous
      Not applicable

      I'm using d3 3.5.17 and yes, i have included it into externalJS property.

      • v-viig's avatar
        v-viig
        Community Champion

        Your code actually works for me:

         

         

        However, Pie chart is misplaced. I suppose that you should apply CSS transform-translate to fix position issue.

         

        Ignat Vilesov,

        Software Engineer

         

        Microsoft Power BI Custom Visuals

        [email protected]