JavaScript canvas 饼图变形问题
JavaScript canvas pie chart warping issue
我正在尝试创建自定义 HTML 元素,以便轻松创建饼图。
到目前为止,我一直非常成功,除了我似乎无法让实际的 canvas 绘图按比例正确。
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};
这是返回结果
自定义元素设计为具有动态大小。因此,为了绘制弧线,我将宽度除以 2 以获得中点。我想这也是半径。那么我所需要的就是计算我没有问题的角度。为什么饼图是长方形的,没有占满space?我的 canvas 绘制代码有什么问题?
canvas element 的 height
和 width
属性的默认值分别为 150
和 300
。如果您需要 canvas 是正方形,则需要将这些尺寸指定为相同。
此示例调整您的 el_width
变量以直接读取 canvas 的宽度,而不是使用 getBoundingClientRect
。我还调整了 canvas
元素的创建方式,使其具有 width
和 height
属性,其 100% 宽度和高度样式通过 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>
您还会注意到,如果您使用的 width
和 height
值小于显示 canvas 的实际大小,它会明显放大因为它生成的是光栅图像而不是矢量图像。
我正在尝试创建自定义 HTML 元素,以便轻松创建饼图。 到目前为止,我一直非常成功,除了我似乎无法让实际的 canvas 绘图按比例正确。
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};
这是返回结果
自定义元素设计为具有动态大小。因此,为了绘制弧线,我将宽度除以 2 以获得中点。我想这也是半径。那么我所需要的就是计算我没有问题的角度。为什么饼图是长方形的,没有占满space?我的 canvas 绘制代码有什么问题?
canvas element 的 height
和 width
属性的默认值分别为 150
和 300
。如果您需要 canvas 是正方形,则需要将这些尺寸指定为相同。
此示例调整您的 el_width
变量以直接读取 canvas 的宽度,而不是使用 getBoundingClientRect
。我还调整了 canvas
元素的创建方式,使其具有 width
和 height
属性,其 100% 宽度和高度样式通过 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>
您还会注意到,如果您使用的 width
和 height
值小于显示 canvas 的实际大小,它会明显放大因为它生成的是光栅图像而不是矢量图像。