quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
296 lines (247 loc) • 6.76 kB
JavaScript
const reRGBA = /^rgb(a)?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?([01]?\.?\d*?)?\)$/
export function rgbToHex ({ r, g, b, a }) {
const alpha = a !== void 0
r = Math.round(r)
g = Math.round(g)
b = Math.round(b)
if (
r > 255
|| g > 255
|| b > 255
|| (alpha && a > 100)
) {
throw new TypeError('Expected 3 numbers below 256 (and optionally one below 100)')
}
a = alpha
? (Math.round(255 * a / 100) | 1 << 8).toString(16).slice(1)
: ''
return '#' + ((b | g << 8 | r << 16) | 1 << 24).toString(16).slice(1) + a
}
export function rgbToString ({ r, g, b, a }) {
return `rgb${ a !== void 0 ? 'a' : '' }(${ r },${ g },${ b }${ a !== void 0 ? ',' + (a / 100) : '' })`
}
export function hexToRgb (hex) {
if (typeof hex !== 'string') {
throw new TypeError('Expected a string')
}
hex = hex.replace(/^#/, '')
if (hex.length === 3) {
hex = hex[ 0 ] + hex[ 0 ] + hex[ 1 ] + hex[ 1 ] + hex[ 2 ] + hex[ 2 ]
}
else if (hex.length === 4) {
hex = hex[ 0 ] + hex[ 0 ] + hex[ 1 ] + hex[ 1 ] + hex[ 2 ] + hex[ 2 ] + hex[ 3 ] + hex[ 3 ]
}
const num = parseInt(hex, 16)
return hex.length > 6
? { r: num >> 24 & 255, g: num >> 16 & 255, b: num >> 8 & 255, a: Math.round((num & 255) / 2.55) }
: { r: num >> 16, g: num >> 8 & 255, b: num & 255 }
}
export function hsvToRgb ({ h, s, v, a }) {
let r, g, b
s = s / 100
v = v / 100
h = h / 360
const
i = Math.floor(h * 6),
f = h * 6 - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s)
switch (i % 6) {
case 0:
r = v
g = t
b = p
break
case 1:
r = q
g = v
b = p
break
case 2:
r = p
g = v
b = t
break
case 3:
r = p
g = q
b = v
break
case 4:
r = t
g = p
b = v
break
case 5:
r = v
g = p
b = q
break
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
a
}
}
export function rgbToHsv ({ r, g, b, a }) {
const
max = Math.max(r, g, b),
min = Math.min(r, g, b),
d = max - min,
s = (max === 0 ? 0 : d / max),
v = max / 255
let h
switch (max) {
case min:
h = 0
break
case r:
h = (g - b) + d * (g < b ? 6 : 0)
h /= 6 * d
break
case g:
h = (b - r) + d * 2
h /= 6 * d
break
case b:
h = (r - g) + d * 4
h /= 6 * d
break
}
return {
h: Math.round(h * 360),
s: Math.round(s * 100),
v: Math.round(v * 100),
a
}
}
export function textToRgb (str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string')
}
const color = str.replace(/ /g, '')
const m = reRGBA.exec(color)
if (m === null) {
return hexToRgb(color)
}
const rgb = {
r: Math.min(255, parseInt(m[ 2 ], 10)),
g: Math.min(255, parseInt(m[ 3 ], 10)),
b: Math.min(255, parseInt(m[ 4 ], 10))
}
if (m[ 1 ]) {
const alpha = parseFloat(m[ 5 ])
rgb.a = Math.min(1, isNaN(alpha) === true ? 1 : alpha) * 100
}
return rgb
}
/* works as darken if percent < 0 */
export function lighten (color, percent) {
if (typeof color !== 'string') {
throw new TypeError('Expected a string as color')
}
if (typeof percent !== 'number') {
throw new TypeError('Expected a numeric percent')
}
const rgb = textToRgb(color),
t = percent < 0 ? 0 : 255,
p = Math.abs(percent) / 100,
R = rgb.r,
G = rgb.g,
B = rgb.b
return '#' + (
0x1000000 + (Math.round((t - R) * p) + R) * 0x10000
+ (Math.round((t - G) * p) + G) * 0x100
+ (Math.round((t - B) * p) + B)
).toString(16).slice(1)
}
export function luminosity (color) {
if (typeof color !== 'string' && (!color || color.r === void 0)) {
throw new TypeError('Expected a string or a {r, g, b} object as color')
}
const
rgb = typeof color === 'string' ? textToRgb(color) : color,
r = rgb.r / 255,
g = rgb.g / 255,
b = rgb.b / 255,
R = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4),
G = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4),
B = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4)
return 0.2126 * R + 0.7152 * G + 0.0722 * B
}
export function brightness (color) {
if (typeof color !== 'string' && (!color || color.r === void 0)) {
throw new TypeError('Expected a string or a {r, g, b} object as color')
}
const rgb = typeof color === 'string'
? textToRgb(color)
: color
return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000
}
export function blend (fgColor, bgColor) {
if (typeof fgColor !== 'string' && (!fgColor || fgColor.r === void 0)) {
throw new TypeError('Expected a string or a {r, g, b[, a]} object as fgColor')
}
if (typeof bgColor !== 'string' && (!bgColor || bgColor.r === void 0)) {
throw new TypeError('Expected a string or a {r, g, b[, a]} object as bgColor')
}
const
rgb1 = typeof fgColor === 'string' ? textToRgb(fgColor) : fgColor,
r1 = rgb1.r / 255,
g1 = rgb1.g / 255,
b1 = rgb1.b / 255,
a1 = rgb1.a !== void 0 ? rgb1.a / 100 : 1,
rgb2 = typeof bgColor === 'string' ? textToRgb(bgColor) : bgColor,
r2 = rgb2.r / 255,
g2 = rgb2.g / 255,
b2 = rgb2.b / 255,
a2 = rgb2.a !== void 0 ? rgb2.a / 100 : 1,
a = a1 + a2 * (1 - a1),
r = Math.round(((r1 * a1 + r2 * a2 * (1 - a1)) / a) * 255),
g = Math.round(((g1 * a1 + g2 * a2 * (1 - a1)) / a) * 255),
b = Math.round(((b1 * a1 + b2 * a2 * (1 - a1)) / a) * 255)
const ret = { r, g, b, a: Math.round(a * 100) }
return typeof fgColor === 'string'
? rgbToHex(ret)
: ret
}
export function changeAlpha (color, offset) {
if (typeof color !== 'string') {
throw new TypeError('Expected a string as color')
}
if (offset === void 0 || offset < -1 || offset > 1) {
throw new TypeError('Expected offset to be between -1 and 1')
}
const { r, g, b, a } = textToRgb(color)
const alpha = a !== void 0 ? a / 100 : 0
return rgbToHex({
r, g, b, a: Math.round(Math.min(1, Math.max(0, alpha + offset)) * 100)
})
}
export function getPaletteColor (colorName) {
if (typeof colorName !== 'string') {
throw new TypeError('Expected a string as color')
}
const el = document.createElement('div')
el.className = `text-${ colorName } invisible fixed no-pointer-events`
document.body.appendChild(el)
const result = getComputedStyle(el).getPropertyValue('color')
el.remove()
return rgbToHex(textToRgb(result))
}
export default {
rgbToHex,
hexToRgb,
hsvToRgb,
rgbToHsv,
textToRgb,
lighten,
luminosity,
brightness,
blend,
changeAlpha,
getPaletteColor
}