@sirhc77/canvas-math-kit
Version:
A lightweight, interactive canvas-based vector visualizer for math, linear algebra, and ML education. Built with React + TypeScript.
114 lines (113 loc) • 3.24 kB
JavaScript
export function toCanvas(x, y, origin, scale) {
return {
x: origin.x + x * scale,
y: origin.y - y * scale,
};
}
export function drawGrid(ctx, width, height, scale) {
ctx.save();
ctx.strokeStyle = '#eee';
ctx.lineWidth = 1;
const originX = width / 2;
const originY = height / 2;
const startX = -Math.floor(originX / scale);
const endX = Math.ceil((width - originX) / scale);
const startY = -Math.floor(originY / scale);
const endY = Math.ceil((height - originY) / scale);
for (let i = startX; i <= endX; i++) {
const x = originX + i * scale;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let j = startY; j <= endY; j++) {
const y = originY - j * scale;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
ctx.restore();
}
export function drawAxes(ctx, width, height, origin) {
ctx.save();
ctx.strokeStyle = '#999';
ctx.lineWidth = 2;
// X-axis
ctx.beginPath();
ctx.moveTo(0, origin.y);
ctx.lineTo(width, origin.y);
ctx.stroke();
// Y-axis
ctx.beginPath();
ctx.moveTo(origin.x, 0);
ctx.lineTo(origin.x, height);
ctx.stroke();
ctx.restore();
}
export function drawLine(ctx, from, to, color, lineWidth) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.moveTo(from.x, from.y);
ctx.lineTo(to.x, to.y);
ctx.stroke();
ctx.restore();
}
export function drawArrowhead(ctx, from, to, color) {
const headLength = 10; // size in logical pixels
const dx = to.x - from.x;
const dy = to.y - from.y;
const angle = Math.atan2(dy, dx);
ctx.save();
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(to.x, to.y);
ctx.lineTo(to.x - headLength * Math.cos(angle - Math.PI / 6), to.y - headLength * Math.sin(angle - Math.PI / 6));
ctx.lineTo(to.x - headLength * Math.cos(angle + Math.PI / 6), to.y - headLength * Math.sin(angle + Math.PI / 6));
ctx.closePath();
ctx.fill();
ctx.restore();
}
export function drawCircle(ctx, center, radius, color) {
ctx.save();
ctx.beginPath();
ctx.arc(center.x, center.y, radius, 0, 2 * Math.PI);
ctx.fillStyle = color;
ctx.fill();
ctx.restore();
}
export function drawParallelogram(ctx, p0, p1, p2, p3, fillColor, strokeColor) {
ctx.save();
if (fillColor) {
ctx.fillStyle = fillColor;
}
if (strokeColor) {
ctx.strokeStyle = strokeColor;
ctx.lineWidth = 2;
}
ctx.beginPath();
ctx.moveTo(p0.x, p0.y);
ctx.lineTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.lineTo(p3.x, p3.y);
ctx.closePath();
if (fillColor)
ctx.fill();
if (strokeColor)
ctx.stroke();
ctx.restore();
}
export function writeLabel(ctx, text, x, y, font = '16px Arial', color = '#333', textAlign = 'left', textBaseline = 'middle') {
if (ctx) {
ctx.save();
ctx.font = font;
ctx.fillStyle = color;
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
ctx.fillText(text, x, y);
ctx.restore();
}
}