Your code (overwriting p5's mousePressed
method with a new, unrelated function):
reportButton.mousePressed = () => {
scenes.reportComment();
};
Correct code (calling p5's mousePressed
method, passing in a callback that represents the handler to trigger on press):
reportButton.mousePressed(() => {
scenes.reportComment();
});
It's a subtle difference, but a close look at the example in the createButton
docs shows the way.
Manipulating p5.js objects usually involves method calls rather than setting object properties with =
, in case this helps you "smell" the pattern easier in the future. You may have been misled by the look of draw = () => {}
and mousePressed = () => {}
, but these overwrite window
variables, replacing function draw()
and function mousePressed()
to change the main loop that p5 runs and the global mouse press handler, respectively. That's a different case.
A good debugging strategy is to eliminate all unneeded code until all that's left is the following minimal reproduction:
function setup() {
const b = createButton("Report");
b.position(10, 10);
b.mousePressed = () => console.log("worked!");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
After removing all distractions having to do with scenes, it's much easier to figure out that mousePressed
is being used incorrectly.
Your other handler, cancelButton.mousePressed
, should also be adjusted.
After you fix your handlers, you'll probably notice that you can't type into your input. The reason is that it's being created many times per second because it's in the draw()
loop:
draw = () => {
// repeat this code many times a second
clear();
input = createInput();
input.position(20, 65);
// ...
Instead, put your element-creation code outside draw()
so it's executed one time. For each scene, that top-level code is basically setup()
for that scene. draw()
is generally for animation, moving objects around the screen, and occasionally creating and destroying objects as the animation requires. Your current app doesn't need any draw()
s at the current time, so I'd remove them to avoid confusion.
clear()
clears the canvas, not DOM elements, so it's also not necessary in your app yet. Ditto for textAlign(CENTER);
and textSize(50);
.
Putting it all together:
const scenes = {
report: () => {
const reportButton = createButton("Report");
reportButton.position(5, 5);
reportButton.mousePressed(() => {
reportButton.remove();
scenes.reportComment();
});
},
reportComment: () => {
const cleanup = () => {
input.remove();
cancelButton.remove();
submitButton.remove();
header.remove();
};
const transitionToReport = () => {
cleanup();
scenes.report();
};
const transitionToSendReport = () => {
const value = input.value();
cleanup();
scenes.sendReport(value);
};
const cancelButton = createButton("Cancel");
cancelButton.position(5, 5);
cancelButton.mousePressed(transitionToReport);
const input = createInput();
input.position(20, 65);
const submitButton = createButton("Submit");
submitButton.position(input.x + input.width, 65);
submitButton.mousePressed(transitionToSendReport);
const header = createElement("h2", "Report");
header.position(20, 5);
},
sendReport: customQ => {
const header = createElement("h2", `report: '${customQ}'`);
header.position(20, 5);
},
};
function setup() {
scenes.report();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
Or keeping it to two scenes:
const scenes = {
report: () => {
const reportButton = createButton("Report");
reportButton.position(5, 5);
reportButton.mousePressed(() => {
reportButton.remove();
scenes.reportComment();
});
},
reportComment: () => {
const transitionToReport = () => {
input.remove();
cancelButton.remove();
submitButton.remove();
header.remove();
scenes.report();
};
const cancelButton = createButton("Cancel");
cancelButton.position(5, 5);
cancelButton.mousePressed(transitionToReport);
const input = createInput();
input.position(20, 65);
const submitButton = createButton("Submit");
submitButton.position(input.x + input.width, 65);
const sendReport = () =>
header.elt.textContent = input.value();
submitButton.mousePressed(sendReport);
const header = createElement("h2", "Report");
header.position(20, 5);
},
};
function setup() {
scenes.report();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
Note that I'm locally-scoping all variables to each scene. Each scene is responsible for cleaning up its own elements when transitioning to another scene. This helps manage complexity as the app grows.
UX isn't great since the user should be able to press Enter to transition to the next scene, and there should probably be some validation that the input has some content in it, but that's out of scope for this answer.
` value and clear the input within `reportComment`. My code is just an example you can modify as needed. If you do stick with your approach, I'd suggest putting `sendReport` inside its scene.
– ggorlen Feb 03 '23 at 23:19