Create and save your drawings locally
Bootstrap 5 version
Local Storage is a web browser feature that allows you to store data directly on a user's computer. Unlike cookies, it has a much larger storage capacity (typically 5-10MB) and doesn't expire automatically.
Local Storage stores data as key-value pairs. Here's how the data flows:
Most browsers: 5-10MB per domain
Note: This app stores drawings as images, which are quite large. You can typically store 10-20 drawings before reaching limits.
✅ Chrome, Firefox, Safari, Edge, and most modern browsers
❌ Internet Explorer (use SessionStorage instead)
Here's how this app uses Local Storage:
// Get existing data
const drawings = JSON.parse(localStorage.getItem('drawings')) || [];
// Create new drawing object
const drawing = {
id: Date.now(),
name: 'My Drawing',
data: canvas.toDataURL(), // Convert canvas to image
date: new Date().toLocaleString()
};
// Add to array and save
drawings.push(drawing);
localStorage.setItem('drawings', JSON.stringify(drawings));
// Retrieve all drawings
const drawings = JSON.parse(localStorage.getItem('drawings')) || [];
// Loop through and display
drawings.forEach(drawing => {
console.log(drawing.name, drawing.date);
});
// Remove a specific drawing
let drawings = JSON.parse(localStorage.getItem('drawings'));
drawings = drawings.filter(d => d.id !== idToDelete);
localStorage.setItem('drawings', JSON.stringify(drawings));
// Clear all data
localStorage.clear();
JSON.stringify() when saving objectsJSON.parse() when retrieving objectslocalStorage.getItem('key') || '{}''userDrawings' instead of 'd'Open your browser's Developer Tools (F12), go to the "Storage" or "Application" tab, and check the "Local Storage" section to see how your drawings are being stored as JSON!
The original version of this app (jjSketchDrawBoostrap5Sketch0.js / jjSketchDrawBootstrap5_0.html) had three bugs that silently broke the Line, Circle, and Rectangle tools. The Pen and Eraser worked fine, so the bugs were easy to miss. Here's what went wrong — and why it's a great set of lessons for any JavaScript developer.
Shapes were drawn with near-zero size and appeared as dots. The variable lastX/lastY was used to remember where the mouse was first pressed down, but those same variables were overwritten on every mousemove event. By the time the mouse button was released, lastX/lastY held the final mouse position — not the starting point — so both ends of the shape were basically the same location.
Fix: Two new dedicated variables, startX and startY, are set once at mousedown and never changed during the drag.
Nothing appeared on the canvas while dragging with a shape tool. The draw() function (which runs on every mousemove) contained only empty comment placeholders for line, circle, and rectangle — no actual drawing code. Students would drag across the canvas, see nothing, then get a tiny dot on release.
Fix: A snapshot of the canvas pixels (ImageData) is captured at mousedown. On each mousemove, the snapshot is restored and the preview shape is redrawn on top — the standard "rubber-band" preview technique.
Even when a shape was drawn on mouseup, it immediately disappeared. The stopDrawing() function called redrawCanvas() to restore the canvas baseline, then drew the final shape. The problem: redrawCanvas() uses img.onload — which is asynchronous. JavaScript ran the shape-drawing code right away, then the onload callback fired a moment later and wiped the canvas, erasing the shape.
Fix: Replace the async redrawCanvas() call with the synchronous ctx.putImageData(), which restores pixels instantly so the shape draw happens in the correct order.
Key lesson: In JavaScript, code placed after an async call does not wait for that async call to finish. Always use synchronous APIs when the next line of code depends on the result being ready.