-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a78c3fe
commit ad9e970
Showing
3 changed files
with
107 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* Functions for manipulating RGB/RGBA strings and tuples. | ||
*/ | ||
|
||
type RgbTuple = [number, number, number]; | ||
type RgbaTuple = [number, number, number, number]; | ||
|
||
// __brand is a compile time-only type trick to make these two incompatible, | ||
// even though they're really just `string`s. | ||
type RgbString = string & { __brand: 'rgb' }; | ||
type RgbaString = string & { __brand: 'rgba' }; | ||
|
||
/** | ||
* Returns a string formatted: `rgb(R, G, B, A)` from RGB number tuple, where | ||
* `r`, `g`, `b` are values ranged [0, 255]. | ||
*/ | ||
function rgbTupleToString([r, g, b]: RgbTuple): RgbString { | ||
return `rgb(${r}, ${g}, ${b})` as RgbString; | ||
} | ||
|
||
/** | ||
* Returns a string formatted `rgba(R, G, B, A)` from RGBA number tuple, where | ||
* `R`, `G`, `B` are values ranged [0, 255], `A` ranged [0, 1]. | ||
*/ | ||
function rgbaTupleToString([r, g, b, a]: RgbaTuple): RgbaString { | ||
return `rgba(${r}, ${g}, ${b}, ${a / 255})` as RgbaString; | ||
} | ||
|
||
/** | ||
* Returns an corresponding RGB tuple for an RGB string. | ||
* Input string must be formatted as `rgb(R, G, A)`, where where `R`, `G`, `B` | ||
* are values ranged `[0, 255]`, `A` ranged `[0, 1]`. | ||
* | ||
* For performance, this function does not check the input string. | ||
*/ | ||
|
||
function rgbStringToTuple(str: RgbString): RgbTuple { | ||
return str | ||
.slice(4, -1) | ||
.split(',') | ||
.map((c) => Number.parseInt(c)) as RgbTuple; | ||
} | ||
|
||
/** | ||
* Returns an corresponding RGB tuple for an RGB string. | ||
* Input string must be formatted as `rgb(R, G, A)`, where where `R`, `G`, `B` | ||
* are values ranged `[0, 255]`, `A` ranged `[0, 1]`. | ||
* | ||
* For performance, this function does not check the input string. | ||
*/ | ||
|
||
function rgbaStringToTuple(str: RgbaString): RgbaTuple { | ||
return str | ||
.slice(5, -1) | ||
.split(',') | ||
.map((c, i) => (i === 3 ? Number.parseInt(c) * 255 : Number.parseInt(c))) as RgbaTuple; | ||
} | ||
/** | ||
* Blends two colors linearly (not HSV lerp). | ||
* RGB inputs are converted to RGBA with alpha value of 1. | ||
*/ | ||
function rgbaTupleLerp<T extends RgbTuple | RgbaTuple>(colorA: T, colorB: T, alpha: number): RgbaTuple { | ||
const interp = Math.max(Math.min(alpha, 1), 0); | ||
if (colorA.length === 3) colorA.push(255); | ||
if (colorB.length === 3) colorB.push(255); | ||
return colorA.map((Ai, i) => Ai + interp * (colorB[i] - Ai)) as RgbaTuple; | ||
} | ||
|
||
/** | ||
* Blends two colors linearly (not HSV lerp). | ||
* RGB inputs are converted to RGBA with alpha value of 1. | ||
*/ | ||
function rgbaStringLerp(colorA: RgbaString, colorB: RgbaString, alpha: number): RgbaString { | ||
const arrayA = rgbaStringToTuple(colorA); | ||
const arrayB = rgbaStringToTuple(colorB); | ||
return rgbaTupleToString(rgbaTupleLerp(arrayA, arrayB, alpha)); | ||
} | ||
|
||
/** | ||
* Blends two colors linearly (not HSV lerp). | ||
* RGB inputs are converted to RGBA with alpha value of 1. | ||
*/ | ||
function rgbStringLerp(colorA: RgbString, colorB: RgbString, alpha: number): RgbString { | ||
const arrayA = rgbStringToTuple(colorA); | ||
const arrayB = rgbStringToTuple(colorB); | ||
return rgbaStringToRgb(rgbaTupleToString(rgbaTupleLerp(arrayA, arrayB, alpha))); | ||
} | ||
|
||
/** | ||
* Removes A value from string formatted `rgba(R, G, B, A)`. | ||
*/ | ||
function rgbaStringToRgb(str: RgbaString): RgbString { | ||
const [r, g, b] = rgbaStringToTuple(str); | ||
return `rgb(${r}, ${g}, ${b})` as RgbString; | ||
} | ||
|
||
/** | ||
* Compresses A value from string formatted `rgba(R, G, B, A)` to the range `[0.75, 1]` | ||
*/ | ||
function enhanceAlpha(str: RgbaString): RgbaString { | ||
const [r, g, b, a] = rgbaStringToTuple(str); | ||
return rgbaTupleToString([r, g, b, Math.min(0.25 * a + 192, 255)]); | ||
} |