2

I would like to only run the p5.js draw() and setup() functions once three input fields are all not blank and a button is clicked.

function roundNumber(num, decimal_places) {
  if (!("" + num).includes("e")) {
    return +(Math.round(num + "e+" + decimal_places) + "e-" + decimal_places);
  } else {
    var arr = ("" + num).split("e");
    var sig = ""
    if (+arr[1] + scale > 0) {
      sig = "+";
    }
    return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + decimal_places)) + "e-" + decimal_places);
  }
} /* From https://stackoverflow.com/questions/11832914/round-to-at-most-2-decimal-places-only-if-necessary */

function computeSelection() {
  const expr = document.forms[0].mathExpr.value;
  var tempAns = parseFloat(eval(expr));
  var roundedAnswer = roundNumber(tempAns, 10);
  var answer = roundedAnswer;
  document.getElementById("output").textContent = answer;
}

function get_x_min_x_max() {
  const x_min = $("#x_min").value;
  const x_max = $("#x_max").value;
  var x_min_x_max = [x_min, x_max];
  return x_min_x_max;
}

function setup() {
  createCanvas(300, 300);
}

function draw() {

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <form>
    <label>Graph y=</label>
    <input id="mathExpr" type="text" name="mathExpr" value="">
    <label> from x=</label>
    <input id="x_min" type="text" name="x_min" value="">
    <label> to </label>
    <input id="x_max" type="text" name="x_max" value="">
    <input type="button" name="result" value="Result" onclick="computeSelection();">
  </form>
  <h2>Answer: <span id="output"></span></h2>
</body>

If this is my code, I only want the draw and setup at the bottom of the js code to run once mathExpr, x_min, and x_max all contain some text and the result button is clicked. How can I do that?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
applemonkey496
  • 683
  • 1
  • 10
  • 29

4 Answers4

2

For what you want to do you can use the noLoop() and loop() instruction.
noLoop() stops p5.js from continuously executing the the draw() and loop() resumes it.

Add a noLoop() instruction to draw(). This cause the loop to be stopped after 1 execution.

function draw() {
    noLoop()
    // [...]
}

Add a loop() instruction to computeSelection() this cause the loop to be resumed. The noLoop() in draw will stop it again after 1 execution:

function computeSelection() {
    // [...]
    loop()
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
2

Another approach would be to use instance mode.

You can learn more here, but the general approach would look like this:

const s = ( sketch ) => {

  let x = 100;
  let y = 100;

  sketch.setup = () => {
    sketch.createCanvas(200, 200);
  };

  sketch.draw = () => {
    sketch.background(0);
    sketch.fill(255);
    sketch.rect(x,y,50,50);
  };
};

let myp5 = new p5(s);

With this approach, you could hold off on creating a p5 instance until you were ready.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
0

I found another solution for myself. Within setup() I did:

$(document).ready(function() {
  document.forms[0].result.click(function() {
    createCanvas(300, 300);
    // Other code in here
  });
});

so that the setup only runs on the click.

applemonkey496
  • 683
  • 1
  • 10
  • 29
0

If you need to start the sketch on a button click for example, expose the function startSketch() and add it as onClick event.

noLoop() does not prevent the draw() function to be executed once but you can work around like this:

let firstIteration = true;

function startSketch() {
  loop()
}

function setup() {
  // other setup you might want to load
  noLoop();
}

function draw() {
  if (firstIteration) {
    firstIteration = false;
    return;
  }
}
dcts
  • 1,479
  • 15
  • 34