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

color.whiten() not working #166

Closed
ageofabenius opened this issue Nov 19, 2019 · 6 comments
Closed

color.whiten() not working #166

ageofabenius opened this issue Nov 19, 2019 · 6 comments

Comments

@ageofabenius
Copy link

When I use color.whiten in-browser, I get no change to the color object. My test code below:

import Color from 'color';

let color = Color("#0099cc")
console.log(color.hwb())
let newColor = Color(color).whiten(0.5)
console.log(newColor.hwb())
let newColor2 = Color(color).blacken(0.5)
console.log(newColor2.hwb())

@EvanWard
Copy link

EvanWard commented Dec 21, 2019

I am seeing another issue where Color('#000000').whiten(anyValue) is always returning absolute white instead of a shade of gray. Tested with 0, 0.01, 0.05, 0.1, 0.5, and 1.

@lifenautjoe
Copy link

Same issue here! @Qix- could you please look at https://github.com/Qix-/color/pull/167 ?

@Qix-
Copy link
Owner

Qix- commented Feb 28, 2020

Quick note: Sorry for any spelling typos in this post. I'm in the process of learning German and it appears MacOS cannot handle two languages at once with spell check. This is what I see.

This has been my feedback for a number of "not working" issues, but I guess I'll re-form it here for the folks using the HWB color model and the associated methods (.whiten() and .blacken()).

Let me make it abundantly clear that .whiten() and .blacken() are working as intended. Please don't flame me before you read the rest of this comment, because it's starting to wear on me a bit as a maintainer.

HWB is a color model similar to HSV (the "H" means Hue, which is identical between the two cylindrical color models) with "whiten" and "blacken" channels. Basically, it takes a fully-saturated color (W=0, B=0) and 'mixes' black and/or white to achieve varying degrees of lightness (W=0, B>0 or W>0, B=0) or (de-)saturation (W>0, B>0). A full grey (RGB 127, 127, 127) is where W=100%, B=100%; the Hue no longer has any significance in such a case.

Keep in mind, color was designed to work with color models, and the methods exist to reflect that. The methods were not designed to reflect human-friendly operations per se. "Whiten" and "blacken" can mean very different things given the intended effect, color model and source color.

The problem here isn't with implementation, but with the intent of the API - color is designed as a more "academic" library than a "end-user friendly" library; corrollary: color's API is focused on manipulating color spaces in a mathematically correct way.

.whiten() increases the white (W) channel of the HWB color by a ratio - that is, W += W * r (where r is the parameter to .whiten()). Black does the same thing, just with the black channel. If you want to remove black from the black channel, you'd pass a negative parameter to the method.

If you check the source code, this is exactly what's happening. It is mathematically and academically correct behavior.

This is also why Color('#000000').whiten(n) will still result in black - the White channel in the HWB color model is 0 for #000000. Multiplying anything by zero is always zero, of course, and then adding zero to zero is - of course - zero, resulting in #000000.

.whiten() is working as intended.

If you print out the output from the OP, you'll see the White (W) channel of the color is 0, but the Black (B) channel is not 0. This is why .blacken() results in different color whereas .whiten() does not.

image

These two methods are working entirely as intended.


Now, that's not to say something can't be improved here. I fully agree that the API methods are not intuitive to most people who do not care about the color theory behind the library (why else would you use this library instead of using color-convert directly? 🙃)

However, the issue then becomes about the API naming conventions, not about the correctness of the mathematical methods. I'm very much open to having a discussion about the naming conventions used here because I fully understand there is some confusion with what this library does and what users are trying to do.

Please also keep in mind I'm not the original author of this library, and that even if I were, designing an API that is intuitive, just as powerful, mathematically sound and useful to a whole range of people (designers all the way to academics) is very, very difficult. It has been a problem with this library for a while and it's a problem I've been racking my brain on how to solve for years. Any input is appreciated.


As-is, this is a won't-fix. I know that's not the response you want to hear.

The two methods I would suggest looking into are .lighten(), which works with the HSL model's Lightness (L) channel, or instead to color.mix() the Color('white') instead.

@vyushin
Copy link
Contributor

vyushin commented Mar 2, 2020

@Qix- Thanks for answer.
So, I see only one way to change brighteness independently current values - use lightness() method.

let color = Color('rgb(255, 0, 0)');
color.lightness(); // 50
console.log(color.lightness(90).rgb().toString()) // rgb(255, 204, 204)

@Qix-
Copy link
Owner

Qix- commented Mar 2, 2020

If your definition of "brightness" is the lightness channel in the HSL color model, then yes :) other people might think "brightness" means saturation.

Perhaps I should add a guide of common transformations to the readme.

vyushin added a commit to vyushin/color that referenced this issue Mar 2, 2020
Qix- pushed a commit that referenced this issue Mar 2, 2020
@Qix-
Copy link
Owner

Qix- commented Mar 2, 2020

Some more examples that demonstrate this were added to the readme.

You are indeed looking for lightness in this case. I'd also, again, recommend .mix() as it might suit you as well.

@Qix- Qix- closed this as completed Mar 2, 2020
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

No branches or pull requests

5 participants