p5.js icon indicating copy to clipboard operation
p5.js copied to clipboard

Do you think angleMode() should apply to both Canvas and any p5.Graphics on it?

Open imrinahru opened this issue 1 month ago β€’ 9 comments

Topic

Recently I filed a bug on pixelDensity() in p5 2.x. Unlike in 1.x, setting pixelDensity(n) only changes that of the main canvas. https://github.com/processing/p5.js/issues/8289

However, when it comes to angleMode(), both 1.x and 2.x set only for the main canvas, not for individual p5.Graphics. https://editor.p5js.org/imrinahru/sketches/9UGvR304w

I'm inclined to make an enhancement where angleMode() will by default apply to both Canvas and p5.Graphics. It matches the same behavior as pixelDensity, having consistent design.

However, I'm interested in learning how other people think about this proposal, whether or not it's by design or could be changed.

In addition, are there other functions that we should think about when aligning the behavior?

imrinahru avatar Nov 22 '25 23:11 imrinahru

Welcome! πŸ‘‹ Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms.

For guidance on contributing, check out our contributing guidelines and other resources for contributors. πŸ’¬ If you have questions or need support, feel free to join the Processing Foundation Forum or visit our Community page. πŸ“œ Please also review our Code of Conduct to understand our community standards. Thank You!

welcome[bot] avatar Nov 22 '25 23:11 welcome[bot]

Hi @imrinahru I’ve run into the same confusion. In 2.x, pixelDensity() affects only the main canvas unless you set it again on each p5.Graphics, while angleMode() also only applies to the main canvas. If global drawing settings are meant to behave consistently, it probably makes sense for angleMode() to either apply to both canvas + graphics by default, or be clearly per-renderer, with createGraphics() inheriting the current angle mode. Do we know if anyone relies on using different angle modes between the canvas and graphics? That seems like the only real compatibility concern.

reshma045 avatar Nov 24 '25 10:11 reshma045

In general it seems like we have a few options for how state should work on the main canvas and graphics:

  • Totally separate states: a new main canvas and a new graphic gets a fresh start from the global p5 defaults. This is how fill(), stroke(), and most other APIs work.
  • Separate states with linked defaults: in 1.x, this is how pixelDensity worked, where you could set separate densities for the main canvas and for graphics, but for convenience, when you create a p5.Graphics, it would start with the same density as the main canvas.
  • Fully global states: Changing it changes it everywhere. (A separate question is whether or not you should be able to access these via graphics with a myGraphics. prefix at all; forcing you do use a global function makes it clearer that the state is only global.) Some things are like this right now on purpose, such as frameRate, as graphics don't have their own draw loop. Some thing are like this accidentally and may warrant a change, like how noiseDetail is currently not affected by push/pop.

Were you thinking of making them fully global or still separate states with a linked initial value?

davepagurek avatar Nov 24 '25 13:11 davepagurek

I was thinking of Separate states with linked defaults, same as how pixelDensity() worked. I think it's a convenience feature to let people start with the same setting as Canvas when they create Graphics. I also want to reduce inconsistent design, so if there's no reason against, I'd be more swayed to see same behavior for pixelDensity and angleMode().

It's good to see all the possible settings layed out here. And I feel like only frameRate has a good reason to have global states.

imrinahru avatar Nov 24 '25 21:11 imrinahru

I tested the behavior of angleMode() with both the main canvas and p5.Graphics in p5.js v2.0.5.

Here are the three test cases I tried:

Case 1: Canvas angleMode = DEGREES
Graphics has no angleMode
β†’ Both lines appear correctly at 45Β°.
β†’ This suggests that graphics is inheriting the angle mode from the canvas.

Case 2: Canvas angleMode removed (so canvas uses default RADIANS)
Graphics has no angleMode
β†’ Both canvas and graphics lines shift to the same (radians-based) angle.
β†’ Again, graphics seems to follow whatever the canvas is using.

Case 3: Canvas = DEGREES
Graphics = no angleMode
β†’ Same result as Case 1 (both match).

Based on these tests, it looks like p5.Graphics is already inheriting the angleMode of the main canvas.
If the expected behavior is that graphics should not inherit, or should start with a fresh independent state, then maybe the current behavior is inconsistent with that expectation.

Here is the exact sketch I used for testing:

let g;

function setup() {
  createCanvas(400, 400);
  angleMode(DEGREES);  // main canvas mode

  g = createGraphics(200, 200);
  // g.angleMode(DEGREES); // not setting graphics angleMode manually
  g.background(50);
  g.stroke(255, 0, 0);
  g.strokeWeight(4);

  g.line(100, 100, 100 + cos(45) * 70, 100 + sin(45) * 70);
}

function draw() {
  background(0);

  stroke(0, 255, 0);
  strokeWeight(4);
  line(200, 200, 200 + cos(45) * 70, 200 + sin(45) * 70);

  image(g, 0, 0);
  noLoop();
}

Ayaan005-sudo avatar Nov 26 '25 15:11 Ayaan005-sudo

Hi @Ayaan005-sudo! I think in your test, you're always using the main canvas's angle mode by using sin() and cos() instead of g.sin() and g.cos(), which would use the graphic's.

davepagurek avatar Nov 26 '25 15:11 davepagurek

Thanks @davepagurek You were right β€” in my earlier test I was still calling the global sin() and cos(), which always use the main canvas’s angle mode.

I updated the sketch to use g.sin() and g.cos() for the graphics: g.line(100, 100, 100 + g.cos(45) * 70, 100 + g.sin(45) * 70);

Now I'm able to clearly see the difference between the canvas and graphics angle modes.

Ayaan005-sudo avatar Nov 28 '25 13:11 Ayaan005-sudo

I want to make sure I fully understand the pixelDensity behavior in v1 and v2 before giving input on angleMode.

From what I know:

β€’ In p5.js 1.x β†’ pixelDensity() for the main canvas was inherited by a new p5.Graphics, but after creation, the canvas and graphics could have different pixel densities.

So the inheritance happened only at creation time, but later they behaved independently.

Before I comment on the best design for angleMode(), can someone confirm if the behavior in v2 is still the same?

β†’ i.e., when I call pixelDensity(2) before createGraphics(), the new graphics starts with 2, but changing pixelDensity later only affects the main canvas and not the graphics.

If this understanding is correct, then angleMode() currently behaves similarly (separate states, no inheritance), and the question becomes whether angleMode() should follow the "linked defaults" pattern (inherit once on creation) the way pixelDensity did in v1.

Would love clarification so I can give a clearer opinion.

Ayaan005-sudo avatar Nov 28 '25 13:11 Ayaan005-sudo

Hi, @Ayaan005-sudo thank you for joining the discussion, Actually the issue has nothing to do with retroactive application of pixelDensity or angleMode, that I think neither 1.x nor 2.x does.

The point is that while in 1.x, pixelDensity() affects the main canvas and any future createGraphics buffers, it is not like that in 2.x, And the further discussion point is that, even though angleMode didn't affect Graphics even in 1.x, should we set it to be the same behavior as pixelDensity in 1.x.

You can toggle between different version to see results here: https://editor.p5js.org/imrinahru/sketches/bJ3Ohg3Jm

Image

imrinahru avatar Dec 06 '25 20:12 imrinahru