Skip to content

Instantly share code, notes, and snippets.

@ktnyt
Created January 13, 2021 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ktnyt/2573047b5b4c7c775f2be22326ebf6a8 to your computer and use it in GitHub Desktop.
Save ktnyt/2573047b5b4c7c775f2be22326ebf6a8 to your computer and use it in GitHub Desktop.
Sass color mixing for TypeScript.

Sass color mixing for TypeScript.

A literal clone of the mixcolor function provided in libsass in TypeScript. Calling the mix function will do the mixing as well as color hex value sanity checking among other things.

const clamp = (n: number, min: number, max: number) =>
n <= min ? min : n >= max ? max : n
const toHex = (v: number) => {
const h = v.toString(16)
switch (h.length) {
case 1:
return `0${h}`
case 2:
return h
default:
throw new Error(`expected value from 0~255, got: ${v}`)
}
}
export class Color extends String {
constructor(s: string) {
if (/^#[0-9A-Fa-f]{8}$/.test(s) || /^#[0-9A-Fa-f]{6}$/.test(s)) {
super(s)
return
}
if (/^#[0-9A-Fa-f]{4}$/.test(s) || /^#[0-9A-Fa-f]{3}$/.test(s)) {
super(
`#${s
.substr(1)
.split('')
.map((c) => `${c}${c}`)
.join('')}`
)
return
}
throw new Error(`expected color hex string, got '${s}'`)
}
get red() {
return parseInt(this.substr(1, 2), 16)
}
get green() {
return parseInt(this.substr(3, 2), 16)
}
get blue() {
return parseInt(this.substr(5, 2), 16)
}
get alpha() {
return this.length === 9 ? parseInt(this.substr(7, 2), 16) : 1.0
}
get hasAlpha() {
return this.length === 9
}
public static fromRGB(r: number, g: number, b: number) {
return new Color(`#${toHex(r)}${toHex(g)}${toHex(b)}`)
}
public static fromRGBA(r: number, g: number, b: number, a: number) {
return new Color(`${Color.fromRGB(r, g, b)}${toHex(Math.floor(a * 255))}`)
}
mix(color: Color, weight = 50) {
const p = clamp(weight, 0.0, 100.0) / 100.0
const w = 2.0 * p - 1.0
const a = this.alpha - color.alpha
const w1 = ((w * a === -1.0 ? w : (w + a) / (1.0 + w * a)) + 1.0) / 2.0
const w2 = 1.0 - w1
const red = Math.round(this.red * w1 + color.red * w2)
const green = Math.round(this.green * w1 + color.green * w2)
const blue = Math.round(this.blue * w1 + color.blue * w2)
const alpha = this.alpha * p + color.alpha * (1.0 - p)
return this.hasAlpha || color.hasAlpha || alpha !== 1.0
? Color.fromRGBA(red, green, blue, alpha)
: Color.fromRGB(red, green, blue)
}
}
export const mix = (color1: string, color2: string, weight = 50) =>
String(new Color(color1).mix(new Color(color2), weight))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment