Skip to content

Create Graphics fixing in dev-2.0 branch. #7829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/empty-example/index.html
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
background-color: #1b1b1b;
}
</style>
<script src="../p5.rollup.min.js"></script>
<script src="../p5.min.js"></script>
<!-- <script src="../addons/p5.sound.js"></script> -->
<script src="sketch.js"></script>
</head>
2 changes: 1 addition & 1 deletion src/core/p5.Graphics.js
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ class Graphics {
const r = renderer || constants.P2D;

this._pInst = pInst;
this._renderer = new renderers[r](this._pInst, w, h, false, canvas);
this._renderer = new renderers[r](this, w, h, false, canvas);

this._initializeInstanceVariables(this);

10 changes: 10 additions & 0 deletions src/core/p5.Renderer.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,16 @@
* @for p5
*/

/**
* `pInst` may be:
*
* The main sketch-wide `p5` instance (global canvas), or
* an off-screen `p5.Graphics` wrapper.
*
* Therefore a renderer must only call properties / methods that exist
* on both objects.
*/

import { Color } from '../color/p5.Color';
import * as constants from '../core/constants';
import { Image } from '../image/p5.Image';
22 changes: 12 additions & 10 deletions src/core/p5.Renderer2D.js
Original file line number Diff line number Diff line change
@@ -75,7 +75,6 @@ class Renderer2D extends Renderer {
}
// Set and return p5.Element
this.wrappedElt = new Element(this.elt, this._pInst);

this.clipPath = null;
}

@@ -178,9 +177,10 @@ class Renderer2D extends Renderer {
// create background rect
const color = this._pInst.color(...args);

//accessible Outputs
if (this._pInst._addAccsOutput()) {
this._pInst._accsBackground(color._getRGBA([255, 255, 255, 255]));
// Add accessible outputs if the method exists; on success,
// set the accessible output background to white.
if (this._pInst._addAccsOutput?.()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also minor: I don't think I've seen the ?. pattern in this codebase before, maybe it's more easy to read to explicitly check existance and then '&&'?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Kit, I think here in dev-2.0 branch, we uses chaining as well.

this._renderer = context?._renderer?.filterRenderer?._renderer || context;

I think, if I choose optional chaining operator that will keep our code a bit cleaner than repeating the property name with &&. If you just confirm me to choose && pattern, I can quickly change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: No worries, my oversight! Please keep the chaining use but please add a more descriptive incline comment to explain? To make it more easy to understand for new contributors.

Rather than "accessible Outputs" something more like "add accessible outputs if possible; on success...", what do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sure. I'll do it now.

this._pInst._accsBackground?.(color._getRGBA([255, 255, 255, 255]));
}

const newFill = color.toString();
@@ -211,9 +211,10 @@ class Renderer2D extends Renderer {
const color = this.states.fillColor;
this._setFill(color.toString());

//accessible Outputs
if (this._pInst._addAccsOutput()) {
this._pInst._accsCanvasColors('fill', color._getRGBA([255, 255, 255, 255]));
// Add accessible outputs if the method exists; on success,
// set the accessible output background to white.
if (this._pInst._addAccsOutput?.()) {
this._pInst._accsCanvasColors?.('fill', color._getRGBA([255, 255, 255, 255]));
}
}

@@ -222,9 +223,10 @@ class Renderer2D extends Renderer {
const color = this.states.strokeColor;
this._setStroke(color.toString());

//accessible Outputs
if (this._pInst._addAccsOutput()) {
this._pInst._accsCanvasColors('stroke', color._getRGBA([255, 255, 255, 255]));
// Add accessible outputs if the method exists; on success,
// set the accessible output background to white.
if (this._pInst._addAccsOutput?.()) {
this._pInst._accsCanvasColors?.('stroke', color._getRGBA([255, 255, 255, 255]));
}
}

24 changes: 20 additions & 4 deletions src/dom/p5.Element.js
Original file line number Diff line number Diff line change
@@ -63,11 +63,27 @@ class Element {
}
}

// delete the reference in this._pInst._elements
const index = this._pInst._elements.indexOf(this);
if (index !== -1) {
this._pInst._elements.splice(index, 1);
// `this._pInst` is usually the p5 “sketch” object that owns the global
// `_elements` array. But when an element lives inside an off-screen
// `p5.Graphics` layer, `this._pInst` is that wrapper Graphics object
// instead. The wrapper keeps a back–pointer (`_pInst`) to the real
// sketch but has no `_elements` array of its own.

let sketch = this._pInst;

// If `sketch` doesn’t own an `_elements` array it means
// we’re still at the graphics-layer “wrapper”.
// Jump one level up to the real p5 sketch stored in sketch._pInst.

if (sketch && !sketch._elements && sketch._pInst) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a little more inline docs could be useful here to explain the logic

sketch = sketch._pInst; // climb one level up
}

if (sketch && sketch._elements) { // only if the array exists
const i = sketch._elements.indexOf(this);
if (i !== -1) sketch._elements.splice(i, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is this not true / should that path also be handled?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi kit,
That condition is false in two cases:-

  1. Sketch is null / undefined, so there isn’t any p5 sketch to talk to.

  2. Sketch exists but it never set up its _elements list.

In both sutiotions there is no list we can remove ourselves from, so the safest action is to do nothing and just reutrn. Trying to touch a list that isn’t there would crash, so skipping the code is exactly what we want.

}


// deregister events
for (let ev in this._events) {