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.
I have created a pie chart and added Data Color property to it.
But if i change the color of a data point,the change in color can be seen only after I reload the visual.
Why is it not instantaneous?
Please Help.
Here's my visual.ts
module powerbi.extensibility.visual { "use strict"; interface Data { quantity: number; category: string; color:string; selectionId: powerbi.visuals.ISelectionId; } interface PieChartArc { datapoints: Data[]; setting: pieChartSettings; dataview: DataView[]; } interface pieChartSettings { Legend : { show:boolean; }; } interface LegendValues { category:string; color:string; selection: powerbi.visuals.ISelectionId; } function visualTransform(options:VisualUpdateOptions,host:IVisualHost) : PieChartArc { let dataViews=options.dataViews; let defaultSetting : pieChartSettings = { Legend:{ show:false, } }; let viewModel: PieChartArc= { datapoints:[], setting : <pieChartSettings>{}, dataview: dataViews }; if (!dataViews || !dataViews[0] || !dataViews[0].categorical || !dataViews[0].categorical.categories || !dataViews[0].categorical.categories[0].source || !dataViews[0].categorical.values) return viewModel; let categorical=dataViews[0].categorical; let category=categorical.categories[0]; let dataValue=categorical.values[0]; let pieChartData: Data[]=[]; let colorPalette:IColorPalette=host.colorPalette; let objects=dataViews[0].metadata.objects let pieChartSetting: pieChartSettings={ Legend:{ show: getValue<boolean>(objects,'Legend','show',defaultSetting.Legend.show) } } for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { let defaultColor: Fill = { solid: { color: colorPalette.getColor(<string>category.values[i]).value } } for(let i=0;i<Math.max(category.values.length,dataValue.values.length);i++) { pieChartData.push({ quantity:<number>dataValue.values[i], category:<string>category.values[i], color:getCategoricalObjectValue<Fill>(category, i, 'dataPoint', 'fill', defaultColor).solid.color==defaultColor.solid.color ?colorPalette.getColor(<string>category.values[i]).value : getCategoricalObjectValue<Fill>(category, i, 'dataPoint', 'fill', defaultColor).solid.color, //color: colorPalette.getColor(<string>category.values[i]).value, selectionId: host.createSelectionIdBuilder() .withCategory(category, i) .createSelectionId() }); console.log(pieChartData[i].color); } return { datapoints: pieChartData, setting: pieChartSetting, dataview:dataViews }; } } 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 selectionManager:ISelectionManager; private svg: d3.Selection<SVGElement>; private legend:d3.Selection<SVGElement>; private g: any; private pie: any; private color: string; private tooltipServiceWrapper: ITooltipServiceWrapper; private pieSettings: pieChartSettings; static data: DataView[]; private datapoints: Data[]=[]; static config= { solidOpacity:1, transparentOpacity:0.5, }; constructor(options: VisualConstructorOptions) { console.log('Visual constructor', options); this.target = options.element; this.host=options.host; this.selectionManager=options.host.createSelectionManager(); //this.legend=d3.select(options.element); let svg=this.svg=d3.select(options.element) .append('svg') .classed("pieChart",true) ; this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);//.attr('transform','translate('+100+',' +100+')'); this.tooltipServiceWrapper = createTooltipServiceWrapper(this.host.tooltipService, options.element); } public update(options: VisualUpdateOptions) { // let legendModel : LegendValues[] = legendTransform(options,this.host); let viewModel: PieChartArc = visualTransform(options, this.host); let settings=this.pieSettings=viewModel.setting; let category=options.dataViews[0].categorical.categories[0]; let dataValue=options.dataViews[0].categorical.values[0]; // let legend=this.legend; let legendEnumerate:LegendValues[]; this.datapoints=viewModel.datapoints; PieChart.data=options.dataViews; let width=options.viewport.width; let height=options.viewport.height; let radius=Math.min(width,height)/2; //this.pieChartContainer.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); this.svg.attr({ width: width-20, height: height-20, }); //this.svg.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); this.arc=d3.svg.arc() .innerRadius(0) .outerRadius(radius-20); this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity).sort(null); let fill = ((d):string=> d.data.color); let tf = (d: Data) => `translate(${this.arc.centroid(d)})`; let text = d => d.data.category; this.svg.append('g'); this.g=this.svg.selectAll('.arc') .data(this.pie(viewModel.datapoints)) .enter() .append('g') .attr('class', 'arc') .data(this.pie(viewModel.datapoints)) // .attr("fill",fill) ; let path= this.g.append('path') .attr('d', this.arc) .attr('fill',fill) .attr('fill-opacity',1) //.style("stroke","black") .attr("stroke-width","0.8"); this.g.append('text').attr('transform', tf).text(text).attr('fill',"white"); this.tooltipServiceWrapper.addTooltip(path, (tooltipEvent: TooltipEventArgs<number>) => PieChart.getTooltipData(tooltipEvent.data), (tooltipEvent: TooltipEventArgs<number>) => null); let selectionManager = this.selectionManager; path.on("click",function(d) { // path.attr('fill','blue'); selectionManager.select(d.data.selectionId).then((ids: powerbi.visuals.ISelectionId[])=> { path.attr('fill-opacity',ids.length>0? PieChart.config.transparentOpacity: PieChart.config.solidOpacity); d3.select(this).attr('fill-opacity',PieChart.config.solidOpacity); (<Event>d3.event).stopPropagation; }); }); path.exit() .remove(); //shows if(settings.Legend.show) { //this.svg.append("text").text("Hello"); // console.log(settings.Legend.show); for(let i=0;i<category.values.length;++i) { legendEnumerate.push({ category:<string>category.values[i], color:<string>dataValue.values[i], selection:this.host.createSelectionIdBuilder() .withCategory(category, i) .createSelectionId() }); } let legend = this.svg.selectAll('.legend') .data(legendEnumerate) .enter() .append('g') .attr('class','legend') .attr('x',20) .attr('y',20); for(let i=0;i<Math.max(category.values.length,dataValue.values.length);++i) { // this.legend.html(legendEnumerate[i].category).attr("transform","translate(" + i*20 +",0)") // leg.a legend.append('circle') .attr('cx',20) .attr('cy',20) .attr('r',8) .attr('fill',legendEnumerate[i].color) .attr("transform","translate(" + i*20 +",0)") ; legend.append('text') .text(legendEnumerate[i].category) .attr("transform","translate(" + i*30 +",0)") ; } } } 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); let objectName=options.objectName; let objectEnumeration:VisualObjectInstance[]=[]; switch(objectName) { case 'Legend': objectEnumeration.push({ objectName: objectName, properties:{ show:this.pieSettings.Legend.show, }, selector:null }); case 'dataPoint': for(let DataPoint of this.datapoints ) { objectEnumeration.push({ objectName: objectName, displayName: DataPoint.category, properties: { fill: { solid: { color: DataPoint.color } } }, selector: DataPoint.selectionId.getSelector() }); } break; }; return objectEnumeration; } private static getTooltipData(value: any): VisualTooltipDataItem[] { return [{ displayName: PieChart.data[0].metadata.columns[1].displayName, value: value.value.toString(), color: value.data.color, header:value.data.category }]; } } }
Solved! Go to Solution.
@Anonymous,
Change it as follows.
let arcs = this.pieChartContainer.selectAll('.arc') .data(this.pie(this.datapoints)) ; arcs.enter() .append('path') .attr('class', 'arc') ;
@Anonymous,
If convenient, share us a complete project for a quick test.
@Anonymous,
Inspect the generated HTML in Web Console and change the code as Sample Bar Chart Repo does.
let radius=Math.min(width,height)/2; let arc=this.arc=d3.svg.arc() .innerRadius(0) .outerRadius(radius); console.log(radius);
@v-chuncz-msft,Actually the radius value is changing if I resize the visual. But the d3.svg.arc retains the old value until the visual is reloaded.
@Anonymous,
See the code snippet below.
let pies = this.pieChartContainer.selectAll('.arc') .data(this.pie(viewModel.datapoints)); pies.enter() .append('path') .classed('arc', true); pies.attr('d', this.arc) .attr('fill', fill);
this.arc = d3.svg.arc() .innerRadius(0) .outerRadius(radius); console.log(radius); this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity).sort(null); let fill = ((d):string=> d.data.color); // let tf = (d: Data) => `translate(${this.arc.centroid(d)})`; //let text = d => d.data.category; let arcs=this.pieChartContainer.selectAll('.arc') .data(this.pie(this.datapoints)) .enter() .append('path') .attr('class', 'arc') ; arcs .attr('d', this.arc) .attr('fill',fill) .attr('fill-opacity',1) .attr("stroke-width","0.8") ;
This is my current code. Still not working. The radius also changes only after visual reload.
@Anonymous,
Change it as follows.
let arcs = this.pieChartContainer.selectAll('.arc') .data(this.pie(this.datapoints)) ; arcs.enter() .append('path') .attr('class', 'arc') ;
Thanks @v-chuncz-msft . This helped a lot. Could you please explain why it worked?
Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City
Check out the April 2024 Power BI update to learn about new features.
User | Count |
---|---|
14 | |
2 | |
2 | |
1 | |
1 |