Canvas is the HTML element, written as the canvas tag, that gives JavaScript a bitmap of pixels to draw on through a 2D or WebGL rendering context. It is defined in the WHATWG HTML Living Standard. A new canvas is 300 pixels wide and 150 pixels tall unless you set the width and height attributes.
A canvas holds a bitmap and nothing else. You call getContext with an identifier such as "2d", "webgl" or "webgl2" and draw with the returned object. Once drawn, shapes are just pixels: the browser keeps no list of objects, so you redraw the whole scene yourself to move something. This is the main difference from SVG and the DOM, where every shape stays addressable.
const c = document.createElement('canvas');
console.log([c.width, c.height]);
const ctx = c.getContext('2d');
ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, 10, 10);
console.log(Array.from(ctx.getImageData(5, 5, 1, 1).data));
console.log(c.getContext('2d') === ctx, c.getContext('webgl'));
c.width = c.width;
console.log(Array.from(ctx.getImageData(5, 5, 1, 1).data));
console.log(c.toDataURL().slice(0, 22));
Run in headless Chromium 141, the console shows these lines. Chromium also logs a willReadFrequently performance hint after the second getImageData call, left out here.
[300, 150]
[255, 0, 0, 255]
true null
[0, 0, 0, 0]
data:image/png;base64,
The default size of a canvas is 300 by 150 pixels. The same defaults apply when an attribute is missing or holds a value that is not a valid non-negative integer. In Chromium, setting the width attribute to "abc" gives a width of 300.
It throws because the canvas is tainted: you drew a cross-origin image that the server did not approve with CORS. A tainted canvas blocks reading pixels, so getImageData, toDataURL and toBlob all throw SecurityError. The fix has two parts. Set crossOrigin to "anonymous" on the image, and make the image server send an Access-Control-Allow-Origin header. In a test, an image with the header and crossOrigin set was readable. The same image without crossOrigin still tainted the canvas, and an image without the header failed to load at all when crossOrigin was set.