Skip to content
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

CT: color unable to parse color string #13

Closed
KatieWoe opened this issue Nov 13, 2020 · 13 comments
Closed

CT: color unable to parse color string #13

KatieWoe opened this issue Nov 13, 2020 · 13 comments

Comments

@KatieWoe
Copy link
Contributor

fourier-making-waves : phet-io-state-fuzz : unbuilt
https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io-wrappers/state/?sim=fourier-making-waves&phetioDebug&fuzz&wrapperContinuousTest=%7B%22test%22%3A%5B%22fourier-making-waves%22%2C%22phet-io-state-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1605264095291%22%2C%22timestamp%22%3A1605265096938%7D
Uncaught Error: Color unable to parse color string: #ff00
Error: Color unable to parse color string: #ff00
at Color.setCSS (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:328:13)
at Color.set (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:82:12)
at new Color (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:47:10)
at IOType.fromStateObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:1078:30)
at Object.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/axon/js/Property.js:596:37)
at IOType.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/tandem/js/types/IOType.js:131:14)
at PhetioStateEngine.setStateForPhetioObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:418:10)
at https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:318:14
at Array.forEach (<anonymous>)
at PhetioStateEngine.iterate (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:303:22)
id: Bayes Chrome
Snapshot from 11/13/2020, 3:41:35 AM

----------------------------------

fourier-making-waves : phet-io-state-fuzz : unbuilt
https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io-wrappers/state/?sim=fourier-making-waves&phetioDebug&fuzz&wrapperContinuousTest=%7B%22test%22%3A%5B%22fourier-making-waves%22%2C%22phet-io-state-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1605264095291%22%2C%22timestamp%22%3A1605271464916%7D
Uncaught Error: Color unable to parse color string: #ff00
Error: Color unable to parse color string: #ff00
at Color.setCSS (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:328:13)
at Color.set (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:82:12)
at new Color (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:47:10)
at IOType.fromStateObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:1078:30)
at Object.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/axon/js/Property.js:596:37)
at IOType.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/tandem/js/types/IOType.js:131:14)
at PhetioStateEngine.setStateForPhetioObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:418:10)
at https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:318:14
at Array.forEach (<anonymous>)
at PhetioStateEngine.iterate (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:303:22)
id: Bayes Chrome
Snapshot from 11/13/2020, 3:41:35 AM

----------------------------------

fourier-making-waves : phet-io-state-fuzz : unbuilt
https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io-wrappers/state/?sim=fourier-making-waves&phetioDebug&fuzz&wrapperContinuousTest=%7B%22test%22%3A%5B%22fourier-making-waves%22%2C%22phet-io-state-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1605264095291%22%2C%22timestamp%22%3A1605278097339%7D
Uncaught Error: Color unable to parse color string: #ff00
Error: Color unable to parse color string: #ff00
at Color.setCSS (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:328:13)
at Color.set (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:82:12)
at new Color (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:47:10)
at IOType.fromStateObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/scenery/js/util/Color.js:1078:30)
at Object.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/axon/js/Property.js:596:37)
at IOType.applyState (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/tandem/js/types/IOType.js:131:14)
at PhetioStateEngine.setStateForPhetioObject (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:418:10)
at https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:318:14
at Array.forEach (<anonymous>)
at PhetioStateEngine.iterate (https://bayes.colorado.edu/continuous-testing/ct-snapshots/1605264095291/phet-io/js/PhetioStateEngine.js:303:22)
id: Bayes Chrome
Snapshot from 11/13/2020, 3:41:35 AM
@pixelzoom
Copy link
Contributor

Caused by lack of a "color Property" and the PhET-iO's inability to handle {null|string|Color}, see phetsims/scenery#1115. I thought I had converted everything to Color instances, but apparently not.

@pixelzoom pixelzoom changed the title CT color unable to parse color string CT: color unable to parse color string Nov 13, 2020
@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

Difficult (as usual) to debug in the State wrapper. But it looks like the failure is occurring when ColorIO attempts to deserialize a Color using fromStateObject. No idea which Color, or which Property it's associated with.

"#ff00" doesn't appear explicitly in Fourier code, and it's not a valid CSS color string.

Fourier also has no occurrences of rgb( or rgba(.

@pixelzoom
Copy link
Contributor

Reproduced locally with phet-io-wrappers/state/?sim=fourier-making-waves&phetioDebug. Fails immediately on startup with:

?sim=fourier-making-waves&phetioDebug:152 Uncaught Error: Color unable to parse color string: #ff00
    at Color.setCSS (Color.js:328)
    at Color.set (Color.js:82)
    at new Color (Color.js:47)
    at IOType.fromStateObject (Color.js:1078)
    at Object.applyState (Property.js:596)
    at IOType.applyState (IOType.js:131)
    at PhetioStateEngine.setStateForPhetioObject (PhetioStateEngine.js:418)
    at PhetioStateEngine.js:318
    at Array.forEach (<anonymous>)
    at PhetioStateEngine.iterate (PhetioStateEngine.js:303)

@pixelzoom
Copy link
Contributor

I tried the usual workaround of adding a debugger statement to assert.js. but that doesn't give me any additional info.

I need help from someone on the iO team. I have no idea how to narrow this down to a specific Property.

@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

If I make this change to ColorIO, the problem goes away:

  fromStateObject: stateObject => {
-    return stateObject.hex ? new Color( stateObject.hex ) : new Color( stateObject.r, stateObject.g, stateObject.b, stateObject.a );
+    return new Color( stateObject.r, stateObject.g, stateObject.b, stateObject.a );
  }

Color.toStateObject is:

  toStateObject() {
    return {
      r: this.r,
      g: this.g,
      b: this.b,
      a: this.a,
      hex: '#' + this.toNumber().toString( 16 )
    };
  }

So when would stateObject.hex not have a value, and why is the conditional in fromStateObject needed?

And has the computation of hex been tested, or is it buggy?

@samreid
Copy link
Member

samreid commented Nov 13, 2020

hex was just added 4 days ago as part of work in phetsims/scenery-phet#515. @zepumph can you please comment?

@samreid samreid removed their assignment Nov 13, 2020
@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

hex sure looks buggy to me:

> var color = new phet.scenery.Color( 200, 100, 0 )
> '#' + color.toNumber().toString( 16 )
"#c86400"
> var color = new phet.scenery.Color( 0, 0, 0 )
> '#' + color.toNumber().toString( 16 )
"#0"

@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

Discussed with @zepumph via Zoom. The problem is that the color chooser in Studio and color.html only works with CSS strings in hex format. A hex field was added to Color's state object, and this has introduced bugs.

Color, ColorProfile, and PhetioElementView all need some work.

Color has this bit of buggy code in toStateObject:

      hex: '#' + this.toNumber().toString( 16 )

... and this in fromStateObject:

    return stateObject.hex ? new Color( stateObject.hex ) : new Color( stateObject.r, stateObject.g, stateObject.b, stateObject.a );

ColorProfile has something similar in reportColor, which is apparently used by color.html. This should be factored out.

    let hexColor = this[ key + 'Property' ].value.toNumber().toString( 16 );

In PhetioElementView, colorInput.onchange feels wrong. A Color state object is not { hex: }, it's { r: , g:, b:, a:, hex: }. So this is calling setValue with an invalid state object, and relying on code in fromStateObject to deal this special case. Do we really want to go down the path of having optional fields in state objects?

    colorInput.onchange = () => {
      window.phetio.phetioClient.invoke( phetioElement.phetioID, 'setValue', [ { hex: colorInput.value } ] );
    };

My feeling is that hex should not be part of a Color state object. r, g, b, a are sufficient to serialize/deserialize, and we shouldn't be adding special-case fields to meet special needs. Add toHex to Color. If you need hex format, deserialize a Color and call toHex.

@zepumph is going to take it from here.

@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

Another comment. Color and ColorProfile are both using toNumber().toString( 16 ) to create the hex string. I realize that JavaScript seems to be more lax about using toString. But personally, I would do everything possible to avoid writing code that relies on the format of toString, and only use it as a last resort. (And maybe this is a last resort situation.)

@zepumph
Copy link
Member

zepumph commented Nov 13, 2020

Another comment. Color and ColorProfile are both using toNumber().toString( 16 ) to create the hex string. I realize that JavaScript seems to be more lax about using toString. But personally, I would do everything possible to avoid writing code that relies on the format of toString, and only use it as a last resort. (And maybe this is a last resort situation.)

I do not know another way to convert a number to base 16 strings. I think that Number.prototype.toString() is a well vetted and maintained way to achieve this goal. Stack overflow is not an authority, but https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb serves as a nice data point. I did not see a single implementation in those answers that didn't use Number.toString() to get the right radix.


Above I committed the bug fix that was actually causing the error reported in this issue. I also factored out toHex() into a method. But as noted in #13 (comment), there is more work to be done!

@pixelzoom
Copy link
Contributor

pixelzoom commented Nov 13, 2020

This might be another acceptable solution:

Use hex as the serialized representation for Color. In Color.js:

  toStateObject() {
    return {

      // Serialize to hex format because other HTML color chooser (used in Studio and color.html) needs hex.
      hex: ...
    };
  }

  fromStateObject: stateObject => {
    return new Color( stateObject.hex );
  }

zepumph added a commit to phetsims/scenery that referenced this issue Nov 13, 2020
@zepumph
Copy link
Member

zepumph commented Nov 13, 2020

Use hex as the serialized representation for Color. In Color.js:

From what @samreid and I see, this removes alpha from the implementation. We felt better about keeping rgba as the serialization, and then adding logic to studio to support the conversion, as @pixelzoom and I discussed doing this morning.

I think I prefer having an explicit rgba as the single serialization. This implementation involved using ColorIO serialization methods in the wrapper, but @samreid and I felt like that was acceptable and avoided duplicated code.

@pixelzoom will you please review.

@zepumph zepumph assigned samreid and pixelzoom and unassigned zepumph and samreid Nov 13, 2020
@pixelzoom
Copy link
Contributor

👍🏻 Looks good, closing.

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

No branches or pull requests

4 participants