How to Draw a Linear Chart with Canvas on React
In this article, we will learn how to draw a linear chart using the HTML Canvas element in React.
Given the following coordinates of points. We are required to draw a linear chart using the HTML Canvas element.
const data = [
{ x: 0, y: 50 },
{ x: 1, y: 80 },
{ x: 2, y: 20 },
{ x: 3, y: 90 },
{ x: 4, y: 40 },
{ x: 5, y: 60 },
{ x: 6, y: 75 },
];
Draw Axes
First, we need to draw the axises. We will draw the x-axis and y-axis.
// Draw axes
ctx.beginPath();
ctx.strokeStyle = "#333";
ctx.lineWidth = 1;
// Y-axis
ctx.moveTo(padding, padding);
ctx.lineTo(padding, height - padding);
// X-axis
ctx.moveTo(padding, height - padding);
ctx.lineTo(width - padding, height - padding);
ctx.stroke();
Draw Grid Lines and Labels
// Draw grid lines and labels
ctx.strokeStyle = "#eee";
ctx.fillStyle = "#666";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
// Y-axis grid and labels
for (let i = 0; i <= 10; i++) {
const y = height - padding - (i * chartHeight) / 10;
ctx.beginPath();
ctx.moveTo(padding, y);
ctx.lineTo(width - padding, y);
ctx.stroke();
ctx.fillText(`${i * 10}`, padding - 5, y);
}
// X-axis labels
ctx.textAlign = "center";
ctx.textBaseline = "top";
data.forEach((point, index) => {
const x = padding + index * xScale;
ctx.fillText(point.x.toString(), x, height - padding + 5);
});
Draw Line
ctx.beginPath();
ctx.strokeStyle = "#2563eb";
ctx.lineWidth = 2;
data.forEach((point, index) => {
const x = padding + index * xScale;
const y = height - padding - point.y * yScale;
if (index === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.stroke();
Render points
// Draw points
data.forEach((point, index) => {
const x = padding + index * xScale;
const y = height - padding - point.y * yScale;
ctx.beginPath();
ctx.fillStyle = "#2563eb";
ctx.arc(x, y, 4, 0, Math.PI * 2);
ctx.fill();
});
Full Code
import React, { useEffect, useRef } from 'react';
const CanvasLineChart = () => {
const canvasRef = useRef(null);
// Sample data
const data = [
{ x: 0, y: 50 },
{ x: 1, y: 80 },
{ x: 2, y: 20 },
{ x: 3, y: 90 },
{ x: 4, y: 40 },
{ x: 5, y: 60 },
{ x: 6, y: 75 }
];
const drawChart = (ctx, width, height) => {
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Chart dimensions
const padding = 40;
const chartWidth = width - padding * 2;
const chartHeight = height - padding * 2;
// Scale factors
const xScale = chartWidth / (data.length - 1);
const yScale = chartHeight / 100; // Assuming data ranges from 0-100
// Draw axes
ctx.beginPath();
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
// Y-axis
ctx.moveTo(padding, padding);
ctx.lineTo(padding, height - padding);
// X-axis
ctx.moveTo(padding, height - padding);
ctx.lineTo(width - padding, height - padding);
ctx.stroke();
// Draw grid lines and labels
ctx.strokeStyle = '#eee';
ctx.fillStyle = '#666';
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
// Y-axis grid and labels
for (let i = 0; i <= 10; i++) {
const y = height - padding - (i * chartHeight / 10);
ctx.beginPath();
ctx.moveTo(padding, y);
ctx.lineTo(width - padding, y);
ctx.stroke();
ctx.fillText(`${i * 10}`, padding - 5, y);
}
// X-axis labels
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
data.forEach((point, index) => {
const x = padding + index * xScale;
ctx.fillText(point.x.toString(), x, height - padding + 5);
});
// Draw line
ctx.beginPath();
ctx.strokeStyle = '#2563eb';
ctx.lineWidth = 2;
data.forEach((point, index) => {
const x = padding + index * xScale;
const y = height - padding - (point.y * yScale);
if (index === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.stroke();
// Draw points
data.forEach((point, index) => {
const x = padding + index * xScale;
const y = height - padding - (point.y * yScale);
ctx.beginPath();
ctx.fillStyle = '#2563eb';
ctx.arc(x, y, 4, 0, Math.PI * 2);
ctx.fill();
});
};
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
// Set canvas size
canvas.width = 600;
canvas.height = 400;
// Handle high DPI displays
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;
drawChart(ctx, rect.width, rect.height);
}, []);
return (
<div className="p-4">
<canvas
ref={canvasRef}
className="w-full max-w-2xl border border-gray-200 rounded-lg"
/>
</div>
);
};
export default CanvasLineChart;