Intro
This time, I want to save charts what are drawn by Chart.js as images.
To do this, I will try saving HTMLCanvasElement as an image.
In this time, I just use samples to use Chart.js.
I will try Chart.js next time.
Environments
- Node.js ver.15.0.0
package.json
{
"browserslist": [
"last 2 version"
],
"scripts": {
"css": "npx postcss postcss -c postcss.config.js -d wwwroot/css -w"
},
"dependencies": {
"autoprefixer": "^10.0.1",
"chart.js": "^2.9.4",
"postcss": "^8.1.2",
"postcss-cli": "^8.1.0",
"postcss-import": "^13.0.0",
"precss": "^4.0.0",
"ts-loader": "^8.0.6",
"tsc": "^1.20150623.0",
"typescript": "^4.0.3",
"webpack": "^5.2.0",
"webpack-cli": "^4.1.0"
},
"devDependencies": {
"@types/chart.js": "^2.9.27",
"whatwg-fetch": "^3.4.1"
}
}
Base projects
ChartPage.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="../css/chart_page.css" >
</head>
<body>
<div id="outside">
<h1>Chart</h1>
<div class="chart_area">
<canvas id="chart_1" class="chart_canvas"></canvas>
</div>
</div>
<button onclick="Page.save()">Save</button>
<script src="../js/chartPage.bundle.js"></script>
<script>
(function() {
Page.init();
})();
</script>
</body>
</html>
chart_page.css
.chart_area{
background-color: white;
border: solid black 1px;
display: flex;
align-items: center;
justify-content: center;
height: 300px;
width: 300px;
}
.chart_canvas {
}
Draw chart samples
This time, I use the chart sample in Chart.js document.
chart.page.ts
import { SampleDrawer } from "./charts/sample-drawer";
export function init() {
const target = document.getElementById('chart_1');
if (target == null)
{
return;
}
const drawer = new SampleDrawer();
drawer.draw(target as HTMLCanvasElement);
}
sample-drawer.ts
import Chart from "chart.js";
export class SampleDrawer {
public draw(canvas: HTMLCanvasElement) {
const context = canvas.getContext('2d');
if (context == null) {
console.error('failed getting context');
return;
}
this.drawSample(canvas);
}
private drawSample(canvas: HTMLCanvasElement) {
const chart = new Chart(canvas, {
// as same as the sample script at "Creating a Chart"
});
}
}
Result
The chart size comes from the parent element's(<div class="chart_area">) width or height.
Though I change the canvas size, background-color, and etc. before instantiating the chart instance, they will be ignored.
Save as a image
The HTMLCanvasElement can generate Blob or Base64 string and I can use them to create images.
If I save image by a server application, I prefer using "toDataURL" and send Base64 string to the server.
But this time, I use "toBlob()" to download by TypeScript.
chart.page.ts
...
export function save() {
const target = document.getElementById('chart_1');
if (target == null)
{
console.error('chart_1 was not found');
return;
}
const targetCanvas = target as HTMLCanvasElement;
targetCanvas.toBlob((blob) => downloadImageBlob(blob), 'image/jpeg', 1);
}
function downloadImageBlob(blob: Blob|null) {
if(blob == null){
console.error('Failed getting image blob');
return;
}
if (navigator.msSaveBlob == null) {
if (navigator.msSaveBlob == null) {
const linkElement = document.getElementById('download_link') as HTMLAnchorElement;
linkElement.href = window.URL.createObjectURL(blob);
linkElement.download = 'sample_file.jpg';
linkElement.click();
return;
}
// for IE
window.navigator.msSaveBlob(blob, 'sample_file.jpg');
}
ChartPage.html
...
<button onclick="Page.save()">Save</button>
<a id="download_link"></a>
<script src="../js/polyfill/toBlob.js"></script>
<script src="../js/chartPage.bundle.js"></script>
...
For downloading created image, I add an AnchorElement.
And For IE, I add a polyfill file.
Result
Where did the background color come from?
It's because the chart didn't have background colors, and I saved as Jpeg image(no transparency).
So I have to set background color.
But it ignores canvas background color.
Set background color
To set background color, I use plugins of Chart.js.
sample-drawer.ts
public draw(canvas: HTMLCanvasElement) {
const context = canvas.getContext('2d');
if (context == null) {
return;
}
this.drawBackground();
this.drawSample(canvas);
}
private drawBackground() {
Chart.pluginService.register({
beforeDraw: c => {
const ctx = c.ctx;
if (ctx == null){
return;
}
const canvas = c.canvas;
if (canvas == null) {
return;
}
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
});
}
...
Result
Hide chart and save image
Can I only want to show an image what is created from a chart dynamically and hide the chart?
display:none; (Failed)
chart_page.css
#outside{
display: none;
}
...
I couldn't get the blob by "toBlob()".
visibility: hidden; (Success)
chart_page.css
#outside{
visibility: hidden;
}
...
Draw outside (Success)
#outside{
}
.chart_area{
...
height: 1024px;
width: 1024px;
position: absolute;
top: -2000px;
left: -2000px;
}
...
Top comments (0)