Skip to content

Suggestion: include an error message when drawing shapes with NaN values. #5675

@lindapaiste

Description

@lindapaiste
Contributor

Increasing Access

If the user tries to draw a shape where any of the arguments are NaN it does not draw anything. I would expect that it would log an error using the friendly error system so that the user knows why their code didn't do what they intended. This would make it much easier for beginners to debug their code.

Most appropriate sub-area of p5.js?

  • Accessibility (Web Accessibility)
    Build tools and processes
    Color
    Core/Environment/Rendering
    Data
    DOM
    Events
    Friendly error system
    Image
    IO (Input/Output)
    Localization
    Math
    Unit Testing
    Typography
    Utilities
    WebGL
    Other (specify if possible)

Feature enhancement details

Initially I assumed that p5.js was somehow catching or avoiding a DOM error. Unfortunately it seems like the canvas API itself does not give any errors or warnings when encountering NaN values (SVG does ☹️). So p5.js would need to check and validate arguments on its own.

We would want to include an NaN check in all shape functions such as rect(), line(), etc.

Here is an example code but it's very uninteresting. It doesn't do anything.

function setup() {
  createCanvas(400, 400);
  vanillaJs();
}

function draw() {
  background(220);
  fill(0);
  const myVar = undefined + 1;
  rect(0, myVar, 100, 100);
  line(100, 100, myVar, 100);
}

function vanillaJs() {
  const canvas = document.createElement('canvas');
  canvas.width = 400;
  canvas.height = 400;
  document.body.appendChild(canvas);
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = 'red';
  const myVar = undefined + 1;
  ctx.fillRect(0, myVar, 100, 100);
}

Activity

welcome

welcome commented on May 12, 2022

@welcome

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already.

limzykenneth

limzykenneth commented on Aug 14, 2022

@limzykenneth
Member

@almchung @outofambit Would you like to have a look at this? I would imagine including a check for NaN here as technically NaN is considered a number type, or even using the native isNaN or Number.isNaN function to do this check.

almchung

almchung commented on Aug 15, 2022

@almchung

Good catch! The current isNumber() (which uses the native isNaN()) misses the case where Javascript returns the global property Infinity: L349. It's unclear whether Infinity can be considered a number, for the purpose of our drawing functions, we may only want to take finite number arguments. One remedy can be using isFinite()to only pass cases where finite numbers are passed as arguments. From MDN doc, isFinite() returns:

false if the argument is (or will be coerced to) positive or negative Infinity or NaN or undefined; otherwise, true.

limzykenneth

limzykenneth commented on Aug 15, 2022

@limzykenneth
Member

In the case of NaN (not string that parses to NaN) it will satisfy the first condition of typeof NaN == "number" and return true right there. Directly using isNaN() only can take care of most cases I think, but there may be edge cases I didn't think of. For infinity we'll need to leave it be as it has some utility when dealing with number comparisons (max() and min() for example).

almchung

almchung commented on Aug 16, 2022

@almchung

Sorry, I totally misread last time. I agree using isNaN() should solve this. Number.isNaN() doesn't count in the fact that a correctly formatted numerical string argument will be converted into a number.

Found another bug while testing: null argument would be converted to 0 and thus shouldn't throw EMPTY_VAR err msg.

I still think drawing functions like line() may benefit from using isFinite() or some kind of Infinity checking, but not sure if that should be a high priority :)

oscarczer

oscarczer commented on Oct 19, 2022

@oscarczer

Is anyone currently working on this? If not I might have a crack at implementing the finite/infinite checking aspect

Qianqianye

Qianqianye commented on Oct 19, 2022

@Qianqianye
Contributor

@oscarczer Please go ahead with a fix! Thanks.

oscarczer

oscarczer commented on Oct 25, 2022

@oscarczer

Just confirming that we want null to be accepted as an input? I was going to implement an additional check here alongside finite checking to ensure that the string "null" isn't considered a valid parameter (as I don't believe that isNaN accounts for this) but saw what @almchung said and am now not so sure. I feel as if null and 0 shouldn't necessarily be treated the same as they could likely occur from different situations but if you'd like this to be the case I'll leave it as it :)

almchung

almchung commented on Oct 25, 2022

@almchung

@oscarczer I agree that null and 0 shouldn't be treated the same. In some cases (like seen in line(), people will make use of this auto null-to-zero conversion, but this would be much rare (and since this kind of usage will be intentional, people can disregard the error messages).
I have a question though: in the proposed isNumber(), when param's type is string [here from PR], did you intend to check for an empty string, param=="" instead of param=="null"? I think it would be meaningful if isNumber() can catch the empty string case (especially since isNaN("null") would return true and isNaN("") would return false).

oscarczer

oscarczer commented on Oct 26, 2022

@oscarczer

@almchung I was under the impression that isNaN(null) returns false as for some reason it is given the type of number (I think actually because of the instance it is able to be turned into 0?). I assumed that this would extent to isNaN("null") as well however I could definitely be wrong about that. Given this, it might also be worth putting a check for null in the first case of the param switch. However, irrespective of that I'm more than happy to add a check for isNaN("") as well as you're right about that also being an edge-case worth accounting for

almchung

almchung commented on Oct 28, 2022

@almchung

Javascript can be confusing -- it would be helpful to check their String coercion rules on the official reference here.

I don't think we will need to add a separate case for checking null, since typeof(null)==object would follow default case where the current code already returns false.

Getting "null" or "" for your parameter would be a different case, where your typeof("null") and typeof("") are both string -- our current code would treat "null" as a string (so we get an expected output), however, the empty string will be converted into 0 (which is a special case we may want to include in our check).

Hopefully this is helpful!

Bernice55231

Bernice55231 commented on Mar 29, 2023

@Bernice55231
Contributor

Hi, I was wondering why we use isNaN() to check under the 'string' case in the function isNumber. From my understanding, isNaN should be under 'number' case.

limzykenneth

limzykenneth commented on Mar 29, 2023

@limzykenneth
Member

@Bernice55231 For p5.js, it is possible to pass a number string (eg. "100") to functions expecting numbers and it'll work as if the string has been parsed into a string. isNaN() is special in that it works on both numbers and strings that can be parsed into numbers, and will return true if it found that a string passed in cannot be parsed into a number but false if the string can be normally parsed as a valid number (which is the behaviour matching p5.js).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @limzykenneth@Qianqianye@almchung@lindapaiste@Bernice55231

      Issue actions

        Suggestion: include an error message when drawing shapes with `NaN` values. · Issue #5675 · processing/p5.js