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

To celebrate FabCon Vienna, we are offering 50% off select exams. Ends October 3rd. Request your discount now.

Reply
SKYViz
Frequent Visitor

How to implement colorPicker in custom visual for updating color of Pie charts slices?

Hello Everyone,

I have developed the pie chart custom visual by taking the reference from the PowerBI-visuals-sampleBarChart.
Pie chart has been created and default color has been assigned to each slice using the colorPallete.

However, I am struggling with the implementation of functionality for updation of color of Piechart's slices from formatting Pane. Selected color from the formatting Pane is not updated in the visual.

SKYViz_0-1723638369392.png

 

 

Black is selected for the "West" region.  However, color is not updated.



Please find out the code:
visual.ts:

 

 

 

 

import FormattingSettingsColorPicker = formattingSettings.ColorPicker;
import * as d3 from "d3";
import { axisBottom, axisLeft, scaleLinear, scaleBand } from "d3";
import powerbi from "powerbi-visuals-api";
import { formattingSettings, FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
import "./../style/visual.less";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
type Selection<T extends d3.BaseType, U = any, V extends d3.BaseType = any, W = any> = d3.Selection<T, U, V, W>;
import { Card, ColorPicker, Slice } from "powerbi-visuals-utils-formattingmodel/lib/FormattingSettingsComponents";
import { TextProperties } from "powerbi-visuals-utils-formattingutils/lib/src/interfaces";
import { valueFormatter } from "powerbi-visuals-utils-formattingutils";
import {createTooltipServiceWrapper, ITooltipServiceWrapper} from "powerbi-visuals-utils-tooltiputils";
import ISelectionManager = powerbi.extensibility.ISelectionManager;
import { dataViewObjects} from "powerbi-visuals-utils-dataviewutils";
import IColorPalette = powerbi.extensibility.IColorPalette;
import { VisualSettings } from "./settings";
import ISandboxExtendedColorPalette = powerbi.extensibility.ISandboxExtendedColorPalette;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import DataViewObjectPropertyIdentifier = powerbi.DataViewObjectPropertyIdentifier;
import Fill = powerbi.Fill;
import { legend, legendInterfaces } from 'powerbi-visuals-utils-chartutils';
import ILegend = legendInterfaces.ILegend;
import LegendPosition = legendInterfaces.LegendPosition;
import positionChartArea = legend.positionChartArea;
import createLegend = legend.createLegend;
import ISelectionId = powerbi.visuals.ISelectionId;

export interface PieChartDataPoint {
    category: string;
    color: string;
    data:any;
    selectionId: ISelectionId;
    slice:string;
    size:number;

}

function getColumnColorByIndex(
    category: DataViewCategoryColumn,
    index: number,
    colorPalette: ISandboxExtendedColorPalette,
): string {
    if (colorPalette.isHighContrast) {
        return colorPalette.background.value;
    }

    const defaultColor: Fill = {
        solid: {
            color: colorPalette.getColor(`${category.values[index]}`).value,
        }
    };

    const prop: DataViewObjectPropertyIdentifier = {
        objectName: "colorSelector",
        propertyName: "fill"
    };

    let colorFromObjects: Fill;
    if(category.objects?.[index]){
        colorFromObjects = dataViewObjects.getValue(category?.objects[index], prop);
    }

    return colorFromObjects?.solid.color ?? defaultColor.solid.color;
}


function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): PieChartDataPoint[] {
    console.log("createSelectorDataPoints function called");

    const pieChartDataPoints: PieChartDataPoint[] = [];

    let viewport = options.viewport;
    let dataView = options.dataViews;
    console.log("dataView", dataView);

    console.log("dataView length", dataView.length);

    let data = dataView[0];
    console.log("data[0]", data);
    let categorical = data.categorical;
    let categories = categorical.categories;
    let values = categorical.values;
    console.log("categorical", values);
    let slice = categories[0];
    let size = values[0];

    let xValues = slice.values;
    let sizeValues = size.values;

    console.log("xValues",xValues)

    const colorPalette: ISandboxExtendedColorPalette = host.colorPalette;

    for (let i = 0; i < xValues.length; i++) {
        let slice = xValues[i].toString();
        let size = +sizeValues[i];

        const color = colorPalette.getColor(slice).value;

        const selectionId: ISelectionId = host.createSelectionIdBuilder()
            .withCategory(categories[0], i)
            .createSelectionId();

        pieChartDataPoints.push({
            slice,
            size,
            color,
            selectionId,
            data, 
            category: slice 
        });  
    }

    console.log("pieChartDataPoints", pieChartDataPoints); 

    return pieChartDataPoints;
}

  
export class Visual implements IVisual {

    private textNode: Text;
    private formattingSettingsService: FormattingSettingsService;
    private selectionManager: ISelectionManager;
    private formattingSettings: VisualSettings;
    private svg: Selection<SVGGraphicsElement>
    private parentGroup: Selection<SVGElement>;
    private pieGroup: Selection<SVGElement>;
    private tooltipServiceWrapper: ITooltipServiceWrapper;
    private host: IVisualHost;
    private legend: ILegend;
    private colorPalette: IColorPalette;
    private pieDatapoints: PieChartDataPoint[];
    static margins = { top: 30, right: 30, bottom: 30, left: 30 };

    constructor(options: VisualConstructorOptions) {
        console.log('Visual constructor', options);
        this.formattingSettingsService = new FormattingSettingsService();
        this.svg = d3.select(options.element).append('svg').classed('pie', true);
        this.parentGroup = this.svg.append('g').attr('class', 'parent');
        this.pieGroup = this.parentGroup.append('g').attr('class', 'dots');
        this.host = options.host;
        this.colorPalette = options.host.colorPalette; 
        this.selectionManager = options.host.createSelectionManager();

     this.tooltipServiceWrapper = createTooltipServiceWrapper(this.host.tooltipService, options.element);

    }

    public update(options: VisualUpdateOptions) {
        this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualSettings, options.dataViews);
        this.pieDatapoints = createSelectorDataPoints(options, this.host);
        this.formattingSettings.initColors(this.pieDatapoints);
       let viewport = options.viewport;
       this.svg.attr('height', viewport.height).attr('width', viewport.width);

        this.parentGroup.attr('transform', 'translate(' + viewport.width / 2 + ',' + viewport.height / 2 + ')');

        let radius = Math.min(viewport.width, viewport.height) / 4;
        let pie = d3.pie<PieChartDataPoint>().value(function (d) {
            console.log("arcd",d.size);
            return d.size;
        });

        let g = this.pieGroup.selectAll(".arc")
            .data(pie(this.pieDatapoints))
            .enter();

        let arc = g.selectAll("arc")
            .data(pie(this.pieDatapoints))
            .enter();
console.log("arc",arc);
        let path = d3.arc()
            .outerRadius(radius)
            .innerRadius(0);
        arc.append("path")
            .attr("d", function (d) { return path(d as any); })
            .attr("fill", function (d) {
                return d.data.color;
            })     
    }

    public getFormattingModel(): powerbi.visuals.FormattingModel {
        return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
    }
}

 

 

 

 


Settings.ts:

 

 

 

 

"use strict";
import { formattingSettings } from "powerbi-visuals-utils-formattingmodel";
import FormattingSettingsCard = formattingSettings.Card;
import FormattingSettingsColorPicker = formattingSettings.ColorPicker;
import FormattingSettingsModel = formattingSettings.Model;
import FormattingSettingsSlice = formattingSettings.Slice;
import { ColorHelper } from "powerbi-visuals-utils-colorutils";

import {PieChartDataPoint} from "./visual";
import { Visual } from "./visual";
import { Card, ColorPicker, Slice } from "powerbi-visuals-utils-formattingmodel/lib/FormattingSettingsComponents";


export class ColorSelectorCardSettings extends Card {
    name: string = "colorSelector";
    displayName: string = "Data Colors";
    slices: Slice[] = [];
}

export class VisualSettings extends FormattingSettingsModel {
    colorSelector = new ColorSelectorCardSettings();
    cards: Card[] = [this.colorSelector];

    public initColors(dataPoints:PieChartDataPoint[]) {

        const slices:Slice[]=this.colorSelector.slices;
        if (dataPoints) {
            dataPoints.forEach(dataPoint => {
                slices.push(new ColorPicker({
                    name: "fill",
                    displayName: dataPoint.slice,
                    value: { value: dataPoint.color },
                    selector: dataPoint.selectionId.getSelector(),
                }));
            });
        }

        console.log("slices",slices)
    }

}

 

 

 

 


Capabilities.json:

 

 

 

 

{
    "dataRoles": [
        {
            "displayName": "Slice",
            "name": "slice",
            "kind": "Grouping"
        },
        {
            "displayName": "Value",
            "name": "size",
            "kind": "Measure"
        }
    ],
    "dataViewMappings": [
        {
            "categorical": {
                "categories": {
                    "select": [
                        {
                            "for": { "in": "slice" }
                        }
                    ]
                },
                "values": {
                    "select": [
                        {
                            "bind": {
                                "to": "size"
                            }
                        }
                    ]
                }
            }
        }
    ],

    "objects": {
        "colorSelector": {
            "properties": {
                "fill": {
                    "type": { "fill": { "solid": { "color": true } } }
                }
            }
        }
    },
    "privileges": []
}

 

 

 

 



Basically, I am having difficulties in implementing logic for updating the color after selection from the color Picker. However, still I am unaware if I miss something more.

 

 

 

 

        arc.append("path")
            .attr("d", function (d) { return path(d as any); })
            .attr("fill", function (d) {
                return ordScale(d.data.slice).toString();
            })

 

 

 

 


Thank You!

1 ACCEPTED SOLUTION
SKYViz
Frequent Visitor

I have managed to fix the issue:

const color = colorPalette.getColor(slice).value;
Replace the above line of code with:
const color: string = getColumnColorByIndex(categories[0], i, colorPalette);

View solution in original post

1 REPLY 1
SKYViz
Frequent Visitor

I have managed to fix the issue:

const color = colorPalette.getColor(slice).value;
Replace the above line of code with:
const color: string = getColumnColorByIndex(categories[0], i, colorPalette);

Helpful resources

Announcements
September Power BI Update Carousel

Power BI Monthly Update - September 2025

Check out the September 2025 Power BI update to learn about new features.

August 2025 community update carousel

Fabric Community Update - August 2025

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

Top Solution Authors