Render chartjs and export image to data not in the DOM - javascript

I am using chart.js from a frontend react application. I need to create a plot with chart.js so that I can attach it to a powerpoint slide with pptxgen. This image does not have to be rendered visually, I just need to create it when the user requests to generate the ppt.
Chart needs a context, so I created a canvas element to act as such, then tried to render and export the base64 image that I would then proceed to feed into pptxgen:
let ctx = document.createElement("canvas")
ctx.setAttribute("width", "400")
ctx.setAttribute("height", "400")
let chart: Chart = new Chart(ctx, {
type: "bar",
data: {
datasets: [{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}]
},
options: {
scales: {}
}
} )
chart.render()
console.log(chart.toBase64Image())
But all I obtain is "data:;" which looks to be an empty image.
Do you know how to make it render?

The only way to render a chart without you specifically adding it to the dom is by making use of the offscreen-canvas as explained here in the documentation of chart.js:
https://www.chartjs.org/docs/3.7.1/general/performance.html#parallel-rendering-with-web-workers-chromium-only
Downside is that the offscreen canvas API is only available in chromium based browsers.
Other approach you can take is by adding the canvas to the dom, let chart.js render to it, get the base64 representation and then remove the canvas directly after that like so:
let ctx = document.createElement("canvas")
document.documentElement.appendChild(ctx)
ctx.setAttribute("width", "400")
ctx.setAttribute("height", "400")
let chart = new Chart(ctx, {
type: "bar",
data: {
labels: ['a', 'b', 'c', 'd', 'e', 'f', ' g'],
datasets: [{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}]
},
options: {
scales: {}
}
})
const base64 = chart.toBase64Image();
ctx.remove();
console.log(base64)
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>

its not possible to render without attaching canvas to dom, but you can hide it and it will work as expected.
const chartEl = document.createElement("canvas");
const ctx = chartEl.getContext("2d");
chartEl.setAttribute("width", "400");
chartEl.setAttribute("height", "400");
chartEl.style.display = "none";
document.body.append(chartEl);
let chart = new Chart(ctx, {
type: "bar",
data: {
datasets: [
{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}
]
},
options: {
scales: {}
}
});
chart.render();
console.log(chart.toBase64Image());
chartEl.remove();

Related

Cannon convert chartJS to base64 data [duplicate]

I am using chart.js from a frontend react application. I need to create a plot with chart.js so that I can attach it to a powerpoint slide with pptxgen. This image does not have to be rendered visually, I just need to create it when the user requests to generate the ppt.
Chart needs a context, so I created a canvas element to act as such, then tried to render and export the base64 image that I would then proceed to feed into pptxgen:
let ctx = document.createElement("canvas")
ctx.setAttribute("width", "400")
ctx.setAttribute("height", "400")
let chart: Chart = new Chart(ctx, {
type: "bar",
data: {
datasets: [{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}]
},
options: {
scales: {}
}
} )
chart.render()
console.log(chart.toBase64Image())
But all I obtain is "data:;" which looks to be an empty image.
Do you know how to make it render?
The only way to render a chart without you specifically adding it to the dom is by making use of the offscreen-canvas as explained here in the documentation of chart.js:
https://www.chartjs.org/docs/3.7.1/general/performance.html#parallel-rendering-with-web-workers-chromium-only
Downside is that the offscreen canvas API is only available in chromium based browsers.
Other approach you can take is by adding the canvas to the dom, let chart.js render to it, get the base64 representation and then remove the canvas directly after that like so:
let ctx = document.createElement("canvas")
document.documentElement.appendChild(ctx)
ctx.setAttribute("width", "400")
ctx.setAttribute("height", "400")
let chart = new Chart(ctx, {
type: "bar",
data: {
labels: ['a', 'b', 'c', 'd', 'e', 'f', ' g'],
datasets: [{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}]
},
options: {
scales: {}
}
})
const base64 = chart.toBase64Image();
ctx.remove();
console.log(base64)
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
its not possible to render without attaching canvas to dom, but you can hide it and it will work as expected.
const chartEl = document.createElement("canvas");
const ctx = chartEl.getContext("2d");
chartEl.setAttribute("width", "400");
chartEl.setAttribute("height", "400");
chartEl.style.display = "none";
document.body.append(chartEl);
let chart = new Chart(ctx, {
type: "bar",
data: {
datasets: [
{
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 2,
data: [10, 20, 30, 40, 50, 60, 70]
}
]
},
options: {
scales: {}
}
});
chart.render();
console.log(chart.toBase64Image());
chartEl.remove();

How do I create a chart and write it to a png file?

Hello I'm trying to use chart.js to create charts however I have found it hard to find out how to create graphs in my node js program, it requires a context but as it's local I'm not sure what to put in here as it's not meant to be a site and it will also not be.
I would like to create a graph and just put it out as a png is there a way to do this?
I tried
const { Chart } = require("chart.js/auto");
let ctx = null
let crt = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'data',
data: [[-3, 5], [2, 10], [1, 3], [-4, -1], [4, 8]],
backgroundColor: 'lightblue'
}]
},
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Horizontal Floating Bars'
}
}
});```
But have not had any results from this as I got an error. Can someone please help me?
You do need a canvas for chart.js to work. Fortunately, there are some projects that can provide a virtual canvas in node. I use node-canvas; see also this blog post.
It is a little tricky to set the background color, but chart.js docs provide us with a solution.
Thus, after npm installing canvas (you already have installed chart.js), your code can be transformed to:
const { Chart } = require("chart.js/auto");
//from https://blog.logrocket.com/creating-saving-images-node-canvas/
const { createCanvas } = require("canvas");
const fs = require("fs");
const width = 1200, height = 800;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
// not working
// ctx.fillStyle = "#ffffff";
// ctx.fillRect(0, 0, canvas.width, canv\as.height);
// from https://www.chartjs.org/docs/latest/configuration/canvas-background.html
const plugin = {
id: 'customCanvasBackgroundImage',
beforeDraw: (chart) => {
const ctx = chart.ctx;
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
};
new Chart(ctx, {
type: 'bar',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'data',
data: [[-3, 5], [2, 10], [1, 3], [-4, -1], [4, 8]],
backgroundColor: 'lightblue'
}]
},
options: {
indexAxis: 'y',
legend: {
position: 'top',
},
title: {
display: true,
text: 'Horizontal Floating Bars'
}
},
plugins: [plugin]
});
const buffer = canvas.toBuffer("image/png");
fs.writeFileSync("./image.png", buffer);

How to show values on top of bars in a PDF using chart.js and chartjs-node-canvas?

I need to show the values on the top of bars using chartjs-node-canvas to create a PDF in Node
I have been able to recreate what I am looking in HTML but the plugin has the limitation of not accepting the "animation" property, for this reason I am looking to know if there is another way to do it in Node without the need for another external plugin. This is my current code
var ctx = document.getElementById("myChart");
var chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["a", "b", "c", "d", "e", "f"],
datasets: [
{
type: "bar",
backgroundColor: "blue",
borderColor: "blue",
borderWidth: 1,
label: "promedio",
order: 1,
data: [60, 49, 72, 90, 100, 60]
},
{
type: "bar",
backgroundColor: "orange",
borderColor: "orange",
borderWidth: 1,
label: "promedio",
order: 1,
data: [40, 5, 20, 30, 10, 6]
},
{
type: "line",
label: "casos",
data: [25, 13, 30, 35, 25, 40],
lineTension: 0,
backgroundColor: "red",
borderColor: "red",
order: 0,
fill: false
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
animation: {
duration: 1,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(16, 20, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 2);
});
});
}
},
legend: {
display: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<body>
<canvas id="myChart" width="400" height="200"></canvas>
</body>
Short answer is no, you either have to implement your own external inline plugin or use the datalabels plugin (https://chartjs-plugin-datalabels.netlify.app/samples/charts/bar.html) since there is no build in way to achieve this

Make a Histogram in Chart.js

We use the Chart.js library in our codebase and I need to create a histogram, which is not one of their default chart types. So I'm attempting to override the x-axis tick marks on a bar chart so that they appear at the left and right corners of each bar instead of directly underneath.
In the below example I've gotten the x-axis how I want it by adding an extra item in the labels array and displaying a second x-axis in the options. But, because there's now an extra label, the bars are taking up 4/5ths of the width, leaving space for a non-existent data point.
Is there some way that I can specify to ignore the missing data point? Or offset the bars? Or am I barking up the wrong tree?
The documentation is a little hard to parse through, so I'm not sure if there's something simple I'm missing.
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4],
datasets: [{
label: 'Group A',
data: [12, 19, 3, 5],
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.30,
}, {
display: true,
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>
Edit: I realize there are other libraries that could achieve something similar and I am looking into other options. But, I've posted this just in case someone out there knows of a solution via Chart.js, which would be ideal.
Here's an example of what the end result I'm going for is:
I believe you can get the result you want by using the max parameter on the ticks configuration of the x axes.
By using 2 different x axes with different maximums you can label the bars differently from how they're drawn. Resulting in labeling the marks in between the bars without drawing an extra "empty" bar.
var ctx = document.getElementById("myChart").getContext('2d');
var dataValues = [12, 19, 3, 5];
var dataLabels = [0, 1, 2, 3, 4];
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dataLabels,
datasets: [{
label: 'Group A',
data: dataValues,
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.3,
ticks: {
max: 3,
}
}, {
display: true,
ticks: {
autoSkip: false,
max: 4,
}
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>

Thickness multiple data chart doughnut

i'm trying to set the different measure for thickness in my chart in a webView for an iOS application.
I wish that the data in "red" have smaller thickness than data in center.
This is the code that i used with chart.js library.
{
var ctx = document.getElementById("myChart");
var data = {
datasets: [
{
data: [10, 90],
backgroundColor: ['ff0000', 'F8F8F8'],
hoverBackgroundColor: [colorA, colorB],
},
{
data: [60, 40],
backgroundColor: [colorA, colorB],
hoverBackgroundColor: [colorA, colorB],
},
{
data: [90, 10],
backgroundColor: ['F8F8F8', 'ff0000'],
hoverBackgroundColor: [colorA, colorB],
}
]
};
var options = {
......,
cutoutPercentage: 55,
};
// And for a doughnut chart
var myDoughnutChart = new Chart(ctx, {
type: 'doughnut',
data: data,
options: options
});
it seems that the options are for the entire chart and not for single data.
thanks again

Categories

Resources