The Mathematical Canvas: Beyond Naive Coordinates
In standard web development, coordinates are defined by top-left pixel offsets: (0,0) sits in the top-left corner of the container, and values increase rightward and downward. In mathematics, Cartesian coordinate systems center (0,0) at the origin, with the Y-axis increasing upward.
Constantly recalculating pixel offsets for every point in application state causes messy code and rounding errors. Instead, we maintain all mathematical data in pure, scale-independent Cartesian space and delegate the screen transformation to an Affine Transformation Matrix.
World Space to Screen Space: The Affine Transformation Matrix
By leveraging the Canvas 2D context's native transformation stack (`ctx.setTransform(scale, 0, 0, -scale, offsetX, offsetY)`), the GPU handles translating, zooming, and inverting the Y-axis in hardware.
This architectural decoupling allows your mathematical calculation functions to work purely in theoretical coordinate spaces without caring about device screen resolutions, container widths, or CSS zoom factors.
// Viewport Frustum Culling & Matrix Transform Pipeline
export interface ViewportTransform {
zoom: number;
panX: number;
panY: number;
width: number;
height: number;
}
export class MathCanvasRenderer {
public renderVisibleNodes(ctx: CanvasRenderingContext2D, points: { x: number; y: number; isPrime: boolean }[], vp: ViewportTransform) {
// 1. Calculate visible mathematical bounding box in world space
const minX = (0 - vp.panX) / vp.zoom;
const maxX = (vp.width - vp.panX) / vp.zoom;
const minY = (0 - vp.panY) / vp.zoom;
const maxY = (vp.height - vp.panY) / vp.zoom;
// 2. Clear canvas and apply hardware transform matrix
ctx.clearRect(0, 0, vp.width, vp.height);
ctx.save();
ctx.translate(vp.panX, vp.panY);
ctx.scale(vp.zoom, vp.zoom);
// 3. Batch render only points visible in current viewport (Frustum Culling)
ctx.fillStyle = '#ffffff';
for (let i = 0; i < points.length; i++) {
const p = points[i];
if (p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY) {
if (p.isPrime) {
ctx.fillRect(p.x - 0.4, p.y - 0.4, 0.8, 0.8);
}
}
}
ctx.restore();
}
}
Frustum Culling: The 10x Performance Win
In an Ulam spiral of 100,000 numbers, only a tiny fraction of the points are within the user's visible viewport when zoomed in. Passing 100,000 `fillRect` calls to the canvas context every frame overwhelms the draw call pipeline, even if 95% of those rectangles fall outside the visible screen edge.
Frustum culling calculates the mathematical world-space bounding box currently visible on screen. Any point outside the `[minX, maxX, minY, maxY]` range is discarded before invoking canvas draw commands, dropping active draw calls from 100,000 to under 500 per frame.
Sub-Pixel Antialiasing and High-DPI Screens
To prevent mathematical plots from appearing fuzzy on high-resolution displays (Apple Retina, 4K monitors), the canvas pixel dimensions (`canvas.width`) must equal the CSS client dimensions multiplied by `window.devicePixelRatio`.
By pairing device pixel scaling with mathematical coordinate transforms and frustum culling, you can render vast datasets and intricate fractal geometries with razor-sharp fidelity and smooth 60 FPS pan/zoom physics.