Skip to content

Commit

Permalink
Merge pull request #6229 from ffd8/dev-existing-canvas
Browse files Browse the repository at this point in the history
Supporting existing canvas element for createCanvas() and createGraphics()
  • Loading branch information
Qianqianye committed Jun 30, 2023
2 parents 2a1bb03 + affc510 commit 637e0cc
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 40 deletions.
20 changes: 15 additions & 5 deletions src/core/p5.Graphics.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,26 @@ import * as constants from './constants';
* @param {Number} h height
* @param {Constant} renderer the renderer to use, either P2D or WEBGL
* @param {p5} [pInst] pointer to p5 instance
* @param {Object} [canvas] existing html canvas element
*/
p5.Graphics = class extends p5.Element {
constructor(w, h, renderer, pInst) {
let canvas = document.createElement('canvas');
super(canvas, pInst);
constructor(w, h, renderer, pInst, canvas) {
let canvasTemp;
if (canvas) {
canvasTemp = canvas;
} else {
canvasTemp = document.createElement('canvas');
}

super(canvasTemp, pInst);
this.canvas = canvasTemp;

const r = renderer || constants.P2D;

this.canvas = canvas;
const node = pInst._userNode || document.body;
node.appendChild(this.canvas);
if (!canvas) {
node.appendChild(this.canvas);
}

// bind methods and props of p5 to the new object
for (const p in p5.prototype) {
Expand Down
117 changes: 82 additions & 35 deletions src/core/rendering.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const defaultClass = 'p5Canvas';
* function. If <a href="#/p5/createCanvas">createCanvas()</a> is not used, the
* window will be given a default size of 100×100 pixels.
*
* Optionally, an existing canvas can be passed using a selector, ie. `document.getElementById('')`.
* If specified, avoid using `setAttributes()` afterwards, as this will remove and recreate the existing canvas.
*
* For more ways to position the canvas, see the
* <a href='https://github.com/processing/p5.js/wiki/Positioning-your-canvas'>
* positioning the canvas</a> wiki page.
Expand All @@ -42,6 +45,7 @@ const defaultClass = 'p5Canvas';
* @param {Number} w width of the canvas
* @param {Number} h height of the canvas
* @param {Constant} [renderer] either P2D or WEBGL
* @param {Object} [canvas] existing html canvas element
* @return {p5.Renderer} pointer to p5.Renderer holding canvas
* @example
* <div>
Expand All @@ -57,56 +61,84 @@ const defaultClass = 'p5Canvas';
* @alt
* Black line extending from top-left of canvas to bottom right.
*/
p5.prototype.createCanvas = function(w, h, renderer) {
/**
* @method createCanvas
* @param {Number} w
* @param {Number} h
* @param {Object} [canvas]
* @return {p5.Renderer} pointer to p5.Renderer holding canvas
*/
p5.prototype.createCanvas = function(w, h, renderer, canvas) {
p5._validateParameters('createCanvas', arguments);
//optional: renderer, otherwise defaults to p2d
const r = renderer || constants.P2D;

let r;
if (arguments[2] instanceof HTMLCanvasElement) {
renderer = constants.P2D;
canvas = arguments[2];
} else {
r = renderer || constants.P2D;
}

let c;

if (r === constants.WEBGL) {
if (canvas) {
c = document.getElementById(defaultId);
if (c) {
//if defaultCanvas already exists
c.parentNode.removeChild(c); //replace the existing defaultCanvas
const thisRenderer = this._renderer;
this._elements = this._elements.filter(e => e !== thisRenderer);
}
c = document.createElement('canvas');
c.id = defaultId;
c.classList.add(defaultClass);
c = canvas;
this._defaultGraphicsCreated = false;
} else {
if (!this._defaultGraphicsCreated) {
c = document.createElement('canvas');
let i = 0;
while (document.getElementById(`defaultCanvas${i}`)) {
i++;
if (r === constants.WEBGL) {
c = document.getElementById(defaultId);
if (c) {
//if defaultCanvas already exists
c.parentNode.removeChild(c); //replace the existing defaultCanvas
const thisRenderer = this._renderer;
this._elements = this._elements.filter(e => e !== thisRenderer);
}
defaultId = `defaultCanvas${i}`;
c = document.createElement('canvas');
c.id = defaultId;
c.classList.add(defaultClass);
} else {
// resize the default canvas if new one is created
c = this.canvas;
if (!this._defaultGraphicsCreated) {
if (canvas) {
c = canvas;
} else {
c = document.createElement('canvas');
}
let i = 0;
while (document.getElementById(`defaultCanvas${i}`)) {
i++;
}
defaultId = `defaultCanvas${i}`;
c.id = defaultId;
c.classList.add(defaultClass);
} else {
// resize the default canvas if new one is created
c = this.canvas;
}
}
}

// set to invisible if still in setup (to prevent flashing with manipulate)
if (!this._setupDone) {
c.dataset.hidden = true; // tag to show later
c.style.visibility = 'hidden';
}
// set to invisible if still in setup (to prevent flashing with manipulate)
if (!this._setupDone) {
c.dataset.hidden = true; // tag to show later
c.style.visibility = 'hidden';
}

if (this._userNode) {
// user input node case
this._userNode.appendChild(c);
} else {
//create main element
if (document.getElementsByTagName('main').length === 0) {
let m = document.createElement('main');
document.body.appendChild(m);
if (this._userNode) {
// user input node case
this._userNode.appendChild(c);
} else {
//create main element
if (document.getElementsByTagName('main').length === 0) {
let m = document.createElement('main');
document.body.appendChild(m);
}
//append canvas to main
document.getElementsByTagName('main')[0].appendChild(c);
}
//append canvas to main
document.getElementsByTagName('main')[0].appendChild(c);
}

// Init our graphics renderer
Expand Down Expand Up @@ -218,11 +250,15 @@ p5.prototype.noCanvas = function() {
* to check what version is being used, or call <a href="#/p5/setAttributes">pg.setAttributes({ version: 1 })</a>
* to create a WebGL1 context.
*
* Optionally, an existing canvas can be passed using a selector, ie. document.getElementById('').
* By default this canvas will be hidden (offscreen buffer), to make visible, set element's style to display:block;
*
* @method createGraphics
* @param {Number} w width of the offscreen graphics buffer
* @param {Number} h height of the offscreen graphics buffer
* @param {Constant} [renderer] either P2D or WEBGL
* undefined defaults to p2d
* @param {Object} [canvas] existing html canvas element
* @return {p5.Graphics} offscreen graphics buffer
* @example
* <div>
Expand All @@ -247,9 +283,20 @@ p5.prototype.noCanvas = function() {
* @alt
* 4 grey squares alternating light and dark grey. White quarter circle mid-left.
*/
p5.prototype.createGraphics = function(w, h, renderer) {
/**
* @method createGraphics
* @param {Number} w
* @param {Number} h
* @param {Object} [canvas]
* @return {p5.Graphics} offscreen graphics buffer
*/
p5.prototype.createGraphics = function(w, h, renderer, canvas) {
if (arguments[2] instanceof HTMLCanvasElement) {
renderer = constants.P2D;
canvas = arguments[2];
}
p5._validateParameters('createGraphics', arguments);
return new p5.Graphics(w, h, renderer, this);
return new p5.Graphics(w, h, renderer, this, canvas);
};

/**
Expand Down

0 comments on commit 637e0cc

Please sign in to comment.