Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

164
Views
JavaScript canvas pie chart warping issue

I am trying to create a custom HTML element that allows me to create pie charts easily. I have been very successful so far except for the fact that I cant seem to get the actual canvas drawing to be proportioned correctly.

class PieChart extends HTMLElement {
    constructor(){
        super();
    }

    connectedCallback(){
        this.classList.add('pie-chart')
        this.innerHTML = `<canvas style="width:100%; height:100%;"></canvas>`
        this.style.display = 'block'
        this.ctx = this.getElementsByTagName('canvas')[0].getContext('2d')

        const results = [
            {mood: "Angry", total: 1599, shade: "#0a9627"},
            {mood: "Happy", total: 478, shade: "#960A2C"},
            {mood: "Melancholic", total:332, shade: "#332E2E"},
            {mood: "Gloomy", total: 195, shade: "#F73809"},
            {mood: "Eh", total: 195, shade: "#000000"}
        ];

            this.chartify(results);
        

    }

    chartify(results){
        var el_width = this.getBoundingClientRect().width;
        var half = (el_width / 2);
        let sum = 0;
        let portion = results.reduce((sum, {total}) => sum + total, 0);
        let currentAngle = 0;
    
        for (let moodValue of results) {
            //calculating the angle the slice (portion) will take in the chart
            let portionAngle = (moodValue.total / portion) * 2 * Math.PI;
            //drawing an arc and a line to the center to differentiate the slice from the rest
            this.ctx.beginPath();
            this.ctx.arc(half, half, half, currentAngle, currentAngle + portionAngle);
            currentAngle += portionAngle;
            this.ctx.lineTo(half, half);
            //filling the slices with the corresponding mood's color
            this.ctx.fillStyle = moodValue.shade;
            this.ctx.fill();
        }
    }
}

window.customElements.define('pie-chart', PieChart);
export{PieChart};

this is the returned result

enter image description here

The custom element is designed to have dynamic size. So to draw the arcs I was dividing the width by 2 in order to get the midpoint. I figured this would also be the radius. then all I need is to calculate the angle which I have no problem with. Why is it that the pie chart is oblong and not taking up the full space? What am I doing wrong in my canvas draw code?.

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

The canvas element has default values for its height and width attributes of 150 and 300, respectively. If you need your canvas to be square, you need to specify these sizes to be the same.

This example tweaks your el_width variable to read the width off the canvas directly, instead of using getBoundingClientRect. I've also tweaked the way the canvas element is created so it has width and height attributes, and its 100% width and height styles are set via CSS:

class PieChart extends HTMLElement {
    constructor(){
        super();
    }

    connectedCallback(){
        this.classList.add('pie-chart')
        this.innerHTML = `<canvas width="300" height="300"></canvas>`
        this.style.display = 'block'
        this.ctx = this.getElementsByTagName('canvas')[0].getContext('2d')

        const results = [
            {mood: "Angry", total: 1599, shade: "#0a9627"},
            {mood: "Happy", total: 478, shade: "#960A2C"},
            {mood: "Melancholic", total:332, shade: "#332E2E"},
            {mood: "Gloomy", total: 195, shade: "#F73809"},
            {mood: "Eh", total: 195, shade: "#000000"}
        ];

            this.chartify(results);
        

    }

    chartify(results){
        var el_width = this.ctx.canvas.width;
        var half = (el_width / 2);
        let sum = 0;
        let portion = results.reduce((sum, {total}) => sum + total, 0);
        let currentAngle = 0;
    
        for (let moodValue of results) {
            //calculating the angle the slice (portion) will take in the chart
            let portionAngle = (moodValue.total / portion) * 2 * Math.PI;
            //drawing an arc and a line to the center to differentiate the slice from the rest
            this.ctx.beginPath();
            this.ctx.arc(half, half, half, currentAngle, currentAngle + portionAngle);
            currentAngle += portionAngle;
            this.ctx.lineTo(half, half);
            //filling the slices with the corresponding mood's color
            this.ctx.fillStyle = moodValue.shade;
            this.ctx.fill();
        }
    }
}

window.customElements.define('pie-chart', PieChart);
pie-chart {
  width: 150px;
  aspect-ratio: 1 / 1;
}

pie-chart canvas {
  width: 100%;
  height: 100%;
}
<pie-chart></pie-chart>

You'll also notice that if you use width and height values that are smaller than the actual size at which the canvas is displayed, it will be noticeably scaled up since it's producing a raster image rather than a vector one.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!