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

We've captured the moments from FabCon & SQLCon that everyone is talking about, and we are bringing them to the community, live and on-demand. Starts on April 14th. Register now

Reply
delphine_g
Regular Visitor

Is it possible to use Chart.JS to create a Power BI Custom visual ?

Hello,
I would like to use the Chart.JS library to create my visual. To do this, I referred to this tutorial:

https://medium.com/@jatin7gupta/adding-external-js-libraries-powerbi-custom-visuals-9b0b9a7d4ae
But when I execute pbiviz start, the visual is completely blank.
So I wanted to know if it is possible to use Chart.JS to develop a custom visual and if so, how can I fix my code to display the visual?

1 ACCEPTED SOLUTION

you should import the library

import {Chart} from 'chart.js';

create a private properties for the Visual class

private myChart: Chart;

and then at the end of your code change that chart constant to

var ctx = 'canvasId';
        if(this.myChart)
            this.myChart.destroy();
        this.myChart = new Chart(ctx, {
            type: 'bar',
            data: barChartData,
.....
})

 with your graph configuration

View solution in original post

4 REPLIES 4
Anonymous
Not applicable

Hello,

 

Of course it is possible to use external libraries like Chart.JS to create a Power BI Custom Visual and regarding the article you provided, there is a code sample that shows how to do that.

 

Could you please provide use the code you used in your visual Class and also what is your data role/mapping?

 

It seems that the example in the Medium article is using the default data role/mapping and only update the constructor and the update methods of the visual so it should be easy to reproduce so tell us what you have done and we will find how to help you 

Hello,
Thank you for your answer.
Here's the Datarole/Mapping I used :

"dataRoles": [
        {
            "displayName": "Categories",
            "name": "category",
            "kind": "Grouping"
        },
        {
            "displayName": "Right Values",
            "name": "right_value",
            "kind": "Measure"
        },
        {
            "displayName": "Left Values",
            "name": "left_value",
            "kind": "Measure"
        }
    ],
"dataViewMappings": [
        {
            "conditions": [
                {
                    "category": {
                        "max": 1
                    },
                    "right_value": {
                        "max": 1
                    },
                    "left_value": {
                        "max": 1
                    }
                }
            ],
            "categorical": {
                "categories": {
                    "for": {
                        "in": "category"
                    },
                    "dataReductionAlgorithm": {
                        "top": {}
                    }
                },
                "values": {
                    "select": [
                        {
                            "bind": {
                                "to": "right_value"
                            }
                        },
                        {
                            "bind": {
                                "to": "left_value"
                            }
                        }
                    ]
                }
            }
        }
    ],

 And this is the code I used for my visual Class :

export class Pyramid implements IVisual {
    private target: HTMLElement;
    private updateCount: number;

    constructor(option : VisualConstructorOptions) {
        console.log('Visual constructor', option);
            this.target = option.element;
            this.updateCount = 0;
            if (typeof document !== "undefined") {
                const new_p: HTMLElement = document.createElement("div");
                const can: HTMLElement = document.createElement("canvas");
                can.setAttribute("id", "canvasId");
                new_p.appendChild(can);
                this.target.appendChild(new_p);
            }
        
    }
    public update(option : VisualUpdateOptions) {
        const extracted_data = [] ;   
        if(option.dataViews 
            && option.dataViews[0] 
            &&  option.dataViews[0].categorical
            &&  option.dataViews[0].categorical.categories
            &&  option.dataViews[0].categorical.values
            ) {               
        const categoricalData = option.dataViews[0].categorical;
        const category = categoricalData.categories[0] ;
        const right_value = categoricalData.values[0]; 
        const left_value = categoricalData.values[1]; 

        for (let i = 0; i< category.values.length; i++){
            extracted_data.push({
                category: category.values[i],
                rvalue: right_value.values[i], //blue values
                lvalue: left_value.values[i] , //red values
            });
        }}
        
        const labels = extracted_data.map(dataPoint => dataPoint.category);
        const data = {
          labels: labels,
          datasets: [{
            label: 'Right Data',
            data: extracted_data.map(dataPoint => dataPoint.rvalue),            
            borderColor: '#33B0FF',
            backgroundColor: '#33B0FF',
            borderWidth: 1
          },
          {
            label: 'Left Data',
            data: extracted_data.map(dataPoint =>  dataPoint.lvalue * -1),            
            borderColor: '#FF33BD',
            backgroundColor: '#FF33BD',            
            borderWidth: 1
          }]
        };
            let d = (<any>window).Chart;

            const chart = {
                type: 'bar',
                data: data,
                options: {
                  inexAxis : 'y',
                  scales: {
                    x: {
                      stacked: true
                    },
                    y: {
                      beginAtZero: true,
                      stacked: true
                    }
                  }
                },
              };
    }
}
    

Can you help me to find what's wrong here please ?

you should import the library

import {Chart} from 'chart.js';

create a private properties for the Visual class

private myChart: Chart;

and then at the end of your code change that chart constant to

var ctx = 'canvasId';
        if(this.myChart)
            this.myChart.destroy();
        this.myChart = new Chart(ctx, {
            type: 'bar',
            data: barChartData,
.....
})

 with your graph configuration

The import was wrong :

import {Chart} from 'chart.js';

I change it for :

import Chart from "chart.js/auto"; 

 And with the rest of your solution it worked !
Thank you 😁

Helpful resources

Announcements
New to Fabric survey Carousel

New to Fabric Survey

If you have recently started exploring Fabric, we'd love to hear how it's going. Your feedback can help with product improvements.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.

Join our Fabric User Panel

Join our Fabric User Panel

Share feedback directly with Fabric product managers, participate in targeted research studies and influence the Fabric roadmap.

March Power BI Update Carousel

Power BI Community Update - March 2026

Check out the March 2026 Power BI update to learn about new features.

Top Solution Authors