Draw a canvas into another canvas not working
Categories:
Drawing One HTML Canvas Onto Another: Common Pitfalls and Solutions

Explore why drawing one HTML canvas onto another might not work as expected and learn the correct techniques to achieve seamless canvas composition in your web applications.
HTML5 Canvas provides a powerful API for dynamic graphics rendering in the browser. A common task is to compose multiple canvas elements, such as drawing the content of one canvas onto another. While seemingly straightforward, developers often encounter issues where the target canvas remains blank or displays unexpected results. This article delves into the reasons behind these problems and provides robust solutions, ensuring your canvas compositions work flawlessly.
Understanding the drawImage()
Method for Canvas Composition
The primary method for drawing images, videos, or other canvas elements onto a target canvas is CanvasRenderingContext2D.drawImage()
. This versatile method can accept various source types, including an HTMLCanvasElement
. However, its behavior can be tricky, especially when dealing with canvas elements that are not yet rendered or have security restrictions.
const sourceCanvas = document.getElementById('sourceCanvas');
const targetCanvas = document.getElementById('targetCanvas');
const sourceCtx = sourceCanvas.getContext('2d');
const targetCtx = targetCanvas.getContext('2d');
// Draw something on the source canvas
sourceCtx.fillStyle = 'red';
sourceCtx.fillRect(10, 10, 50, 50);
// Attempt to draw sourceCanvas onto targetCanvas
targetCtx.drawImage(sourceCanvas, 0, 0);
console.log('Source canvas drawn onto target canvas.');
Basic usage of drawImage()
to transfer content between canvases.
Common Reasons for drawImage()
Failure
Several factors can prevent drawImage()
from successfully rendering one canvas onto another. Understanding these is crucial for effective debugging and resolution.
flowchart TD A[Start: Call drawImage()] --> B{Source Canvas Ready?} B -- No --> C[Failure: Source not rendered/empty] B -- Yes --> D{Cross-Origin Issue?} D -- Yes --> E[Failure: Tainted canvas] D -- No --> F{Source Canvas Dimensions?} F -- Invalid --> G[Failure: Incorrect dimensions] F -- Valid --> H[Success: Content drawn]
Decision flow for common drawImage()
failures.
drawImage()
.Solution 1: Ensuring Source Canvas Content and Timing
The most frequent reason for drawImage()
not working is that the source canvas is empty or its content hasn't been fully rendered when drawImage()
is called. This often happens in asynchronous operations or when drawing logic is not properly sequenced. Always ensure the source canvas has completed its drawing operations before attempting to use it as an image source.
function drawOnSource(ctx) {
ctx.fillStyle = 'blue';
ctx.fillRect(20, 20, 60, 60);
}
function drawOnTarget(sourceCanvas) {
const targetCanvas = document.getElementById('targetCanvas');
const targetCtx = targetCanvas.getContext('2d');
targetCtx.clearRect(0, 0, targetCanvas.width, targetCanvas.height);
targetCtx.drawImage(sourceCanvas, 0, 0);
}
const sourceCanvas = document.getElementById('sourceCanvas');
const sourceCtx = sourceCanvas.getContext('2d');
// Draw on source canvas first
drawOnSource(sourceCtx);
// Then, draw the source onto the target
drawOnTarget(sourceCanvas);
Correct sequencing of drawing operations to ensure source canvas has content.
Solution 2: Handling Cross-Origin Restrictions
If your source canvas contains images or data loaded from a different domain (cross-origin), the canvas becomes 'tainted'. A tainted canvas cannot be used as a source for drawImage()
on another canvas, nor can its pixel data be read (e.g., with toDataURL()
or getImageData()
), due to security restrictions. To resolve this, ensure all assets loaded into the source canvas are from the same origin, or configure CORS appropriately on your server and set crossOrigin = 'anonymous'
on your image elements.
const img = new Image();
img.crossOrigin = 'anonymous'; // Important for cross-origin images
img.src = 'https://example.com/path/to/cross-origin-image.jpg'; // Replace with an actual cross-origin URL
img.onload = () => {
const sourceCanvas = document.getElementById('sourceCanvas');
const sourceCtx = sourceCanvas.getContext('2d');
sourceCtx.drawImage(img, 0, 0);
const targetCanvas = document.getElementById('targetCanvas');
const targetCtx = targetCanvas.getContext('2d');
targetCtx.drawImage(sourceCanvas, 0, 0);
console.log('Cross-origin image drawn successfully after setting crossOrigin.');
};
img.onerror = () => {
console.error('Failed to load cross-origin image. Check CORS settings.');
};
Loading a cross-origin image with crossOrigin='anonymous'
before drawing to canvas.
crossOrigin = 'anonymous'
to work, the server hosting the image must send appropriate CORS headers (e.g., Access-Control-Allow-Origin: *
or Access-Control-Allow-Origin: your-domain.com
). Without these headers, the image will still taint the canvas.Solution 3: Verifying Canvas Dimensions
While less common, incorrect or zero dimensions for either the source or target canvas can lead to drawImage()
not rendering anything. Always ensure your canvas elements have valid width
and height
attributes, either set in HTML or via JavaScript. A canvas with width="0"
or height="0"
will effectively be invisible and cannot be drawn from or to.
<!-- Ensure valid dimensions -->
<canvas id="sourceCanvas" width="200" height="150"></canvas>
<canvas id="targetCanvas" width="400" height="300"></canvas>
Setting canvas dimensions directly in HTML.
const sourceCanvas = document.getElementById('sourceCanvas');
const targetCanvas = document.getElementById('targetCanvas');
// Set dimensions via JavaScript if not set in HTML
sourceCanvas.width = 200;
sourceCanvas.height = 150;
targetCanvas.width = 400;
targetCanvas.height = 300;
console.log(`Source Canvas: ${sourceCanvas.width}x${sourceCanvas.height}`);
console.log(`Target Canvas: ${targetCanvas.width}x${targetCanvas.height}`);
Setting canvas dimensions programmatically using JavaScript.
console.log(sourceCanvas.width, sourceCanvas.height)
to quickly check if your canvas elements have the expected dimensions.