50

I'd like to have an HTML canvas context that I can paint to and read off-screen (in this example, writing text and reading the shape that is created, but it's a general question). I may also want to use a canvas as an off-screen frame-buffer.

I suppose I could create a hidden DOM element but I'd rather create it from JavaScript (I may want to create and destroy a number of canvas at runtime).

Possible?

Joe
  • 46,419
  • 33
  • 155
  • 245
  • It is easy to create elements with `document.createElement`. However I don't know whether manipulating the `canvas` will work if it is not added to DOM (not visible). – Felix Kling Jul 07 '11 at 10:19
  • 3
    In a way, I want a context but not a canvas, if that makes any sense (it probably doesn't). – Joe Jul 07 '11 at 10:20
  • Mmmh. You definitely need the DOM element I think, but you don't have to add it to the DOM. Let me try something... – Felix Kling Jul 07 '11 at 10:26
  • Don't go to any trouble, I can try it myself when I have a spare minute. – Joe Jul 07 '11 at 10:30
  • Ah no worries, it was just copy and pasting code ;) – Felix Kling Jul 07 '11 at 10:32
  • Possible duplicate of [Add canvas to a page with javascript](http://stackoverflow.com/questions/9152224/add-canvas-to-a-page-with-javascript) – Vadzim Jun 04 '16 at 13:05
  • 4
    @Vadzim, please read the question, this one is the absolute opposite of your proposed dupe... Also why do you point to this horrible question ? – Kaiido Jun 04 '16 at 13:45

4 Answers4

63

You can create a new canvas element with document.createElement:

var canvas = document.createElement('canvas');

and then get the context from it. Just make sure you set the width and height. You don't have to add the canvas to the tree in order to make it work:

DEMO

But you definitely have to create that node. You could create a function for that though:

function createContext(width, height) {
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    return canvas.getContext("2d");
}

But that is where my competency ends... whether you can somehow transfer a context to another context or canvas, I don't know...

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    This is very similar to what I want to do. Here's the 7.99 question: Which would be faster: 1) Doing that multiple times (eg as often as the mousemove event fires), or 2) Creating the offscreen canvas once and storing it as a global variable (still not added to the DOM)? – Richard Oct 19 '12 at 09:15
  • 1
    I don't have evidence, but on the face of it, it definitely sounds like storing a created canvas would be a lot cheaper than creating a new canvas every frame – shieldgenerator7 Dec 12 '19 at 21:40
8

Its old but what about saving one canvas with toDataURL and copying to the other with drawImage. you could also use save and restore to make a frame buffer

function createCanvas(width, height) {
    var c = document.createElement('canvas');
    c.setAttribute('width', width);
    c.setAttribute('height', height);
    return c;
}

function canvasImg(canvas) {
    var ctx = canvas.getContext('2d');
    ctx.fillRect(0,0,canvas.width, canvas.height);
    var img = canvas.toDataURL('image/png');

    return img;
}

function placeImage(canvas, img) {
    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0,0);
}

window.onload = function(){
    var canvas = createCanvas(400, 400);
    var hiddenCanvas = createCanvas(400,400);
    var i = canvasImg(hiddenCanvas);
    var img = new Image();
    img.src = i;
    placeImage(canvas, img);
    document.body.appendChild(canvas);
}
live2
  • 3,771
  • 2
  • 37
  • 46
Dave
  • 81
  • 1
  • 2
7

There is apparently a new thing called OffscreenCanvas that was deliberately designed for this use case. An additional bonus is that it also works in Web Workers.

You can read the specifications here: https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface

And see examples here: https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas

Currently it is only fully supported by Chrome and is available behind flags in Firefox and Opera, but you can always check for the latest information on supported browsers here: https://caniuse.com/#feat=offscreencanvas

ps.: Google also has a dedicated guide explaining it's use in Web Workers: https://developers.google.com/web/updates/2018/08/offscreen-canvas

Isti115
  • 2,418
  • 3
  • 29
  • 35
0

Both the CanvasRenderingContext2D and WebGLRenderingContext classes have the canvas element associated with them as the property canvas; and, like normal, both context instances and their canvases will be garbage collected when your code no longer makes references to them at run time.

You can use this function to create a new context

function newContext({width, height}, contextType = '2d') {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    return canvas.getContext(contextType);
}

const ctx = newContext({width: 100, height: 100});
console.log(ctx.canvas.width == 100) // true

And by making use of dereferencing you can easily create a clone of a DOM canvas for frame buffering like this:

const domCanvas = document.getElementById('myCanvas');

const frameBuffer = newContext(domCanvas);
frameBuffer.drawImage(domCanvas, 0, 0);

Which will create a context with the same width and height as the canvas element passed in. You can extend the function as needed.

nevernew
  • 650
  • 10
  • 23