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

Fix hue related mix issues #338

Merged
merged 2 commits into from
Oct 11, 2023
Merged

Conversation

facelessuser
Copy link
Collaborator

- The color.js API states that mix takes the same arguments as `range`
  but all options were not getting passed, `hue` being an example.
- Clarification about the CSS spec mentions that when interpolating
  an undefined hue and defined hue that the undefined handling should
  be done before hue fix-up which would create both a shorter and
  longer arc between an undefined and defined hue.
  w3c/csswg-drafts#9436 (comment)
@facelessuser
Copy link
Collaborator Author

This ensures that we get the proper longer hue when mixing and interpolating:

> new Color("hsl(90deg 50% 50%)").mix('hsl(none 50% 50%)', {space: 'hsl', hue: 'longer'});
Color {
  space: <ref *1> ColorSpace {
    id: 'hsl',
    name: 'HSL',
    base: RGBColorSpace {
      id: 'srgb',
      name: 'sRGB',
      base: [RGBColorSpace],
      aliases: undefined,
      fromBase: [Function: fromBase],
      toBase: [Function: toBase],
      coords: [Object],
      white: [Array],
      formats: [Object],
      referred: 'display',
      path: [Array]
    },
    aliases: undefined,
    fromBase: [Function: fromBase],
    toBase: [Function: toBase],
    coords: { h: [Object], s: [Object], l: [Object] },
    white: [ 0.9504559270516716, 1, 1.0890577507598784 ],
    formats: { hsl: [Object], hsla: [Object] },
    referred: undefined,
    path: [ [ColorSpace], [RGBColorSpace], [RGBColorSpace], [Circular *1] ]
  },
  coords: [ 270, 50, 50 ],
  alpha: 1
}

@facelessuser
Copy link
Collaborator Author

I will note, that I had to use parseFloat on the hues as it appears pure floats are not stored in the object always. I was getting some odd typed objects. I don't know if they are intentional or not, but I'm certain is the product of recent efforts to type the library.

As this is a separate issue, one I am not as familiar with, I am deferring the root cause of the typed issues to someone who knows better. After hue adjustment, they were normalized to basic floats anyway, so forcing them to pure floats so we could check their NaN status didn't seem to be undesirable.

@LeaVerou
Copy link
Member

Hey, thanks for working on this!

I will note, that I had to use parseFloat on the hues as it appears pure floats are not stored in the object always. I was getting some odd typed objects. I don't know if they are intentional or not, but I'm certain is the product of recent efforts to type the library.

Could you elaborate on what these objects were?
If it was these objects, they should be usable as Numbers, since they are plain number objects. And for the few things that don't work on Number objects, you can convert them to number primitives by simply calling valueOf() on them (or doing math, e.g. subtrcting 0).

@facelessuser
Copy link
Collaborator Author

To be honest, I do not know exactly what they are. I was trying to avoid spiraling down a rabbit hole requiring me to fix bug after bug, so I specifically focused on the issue I was trying to fix. But I did log the object when I saw the NaN check failing when I was debugging:

console.log(θ1, θ2)
[Number: 90] { type: '<angle>', unit: 'deg', raw: '90deg' } [Number: NaN] { none: true, raw: 'none' }

I don't know what they are, but they can be cast to pure floats.

@facelessuser
Copy link
Collaborator Author

I'll try out the ValueOf thing.

@facelessuser
Copy link
Collaborator Author

Okay, this was just my inexperience with dealing with Number. I associated this issue with Number, but the original issue preventing proper handling was due to mix not passing the hue argument which I already fixed. I removed parseFloat.

@LeaVerou
Copy link
Member

To be honest, I do not know exactly what they are. I was trying to avoid spiraling down a rabbit hole requiring me to fix bug after bug, so I specifically focused on the issue I was trying to fix. But I did log the object when I saw the NaN check failing when I was debugging:

console.log(θ1, θ2)
[Number: 90] { type: '<angle>', unit: 'deg', raw: '90deg' } [Number: NaN] { none: true, raw: 'none' }

I don't know what they are, but they can be cast to pure floats.

They are just Number objects, which largely behave like regular numbers, with some exceptions, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/Number.
The reason they are Number objects instead of just numbers, is so they can carry additional metadata about where they came from.
Calling parseFloat() coerces the argument to a string first if it's not already a string, then parses it. It will produce the same result here, but in a roundabout way.
For your purposes, using them directly should work (though note that isNaN(new Number(NaN)) is true, but Number.isNaN(new Number(NaN)) is false), but feel free to do .valueOf() if that makes you more comfortable.

@facelessuser
Copy link
Collaborator Author

Thanks for the info! I researched them after you posted about them and have already resolved the issue in the latest push.

@LeaVerou LeaVerou merged commit d8ffbee into color-js:main Oct 11, 2023
4 checks passed
@LeaVerou
Copy link
Member

Merged, thanks!

@jamesnw
Copy link
Contributor

jamesnw commented Oct 17, 2023

@facelessuser Does this PR fix #57?

@facelessuser
Copy link
Collaborator Author

facelessuser commented Oct 17, 2023

@jamesnw, I believe so. I forgot I opened that issue 3 years ago 🙃.

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

Successfully merging this pull request may close these issues.

3 participants