devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
283 lines (269 loc) • 8.24 kB
JavaScript
/**
* DevExtreme (cjs/__internal/utils/color.helpers.js)
* Version: 26.1.4
* Build date: Fri Jul 24 2026
*
* Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.convertTo01Bounds = convertTo01Bounds;
exports.hslToRgb = hslToRgb;
exports.hsvToRgb = hsvToRgb;
exports.hueToRgb = hueToRgb;
exports.isIntegerBetweenMinAndMax = isIntegerBetweenMinAndMax;
exports.makeColorTint = makeColorTint;
exports.modifyColorTint = modifyColorTint;
exports.normalize = normalize;
exports.parseColor = parseColor;
exports.toHexFromRgb = toHexFromRgb;
exports.toHslFromRgb = toHslFromRgb;
exports.toHsvFromRgb = toHsvFromRgb;
function makeColorTint(colorPart, h) {
let colorTint = h;
if ("r" === colorPart) {
colorTint = h + 1 / 3
}
if ("b" === colorPart) {
colorTint = h - 1 / 3
}
return colorTint
}
function modifyColorTint(colorTint) {
let tint = colorTint;
if (tint < 0) {
tint += 1
}
if (tint > 1) {
tint -= 1
}
return tint
}
function hueToRgb(p, q, colorTint) {
const tint = modifyColorTint(colorTint);
if (tint < 1 / 6) {
return p + 6 * (q - p) * tint
}
if (tint < .5) {
return q
}
if (tint < 2 / 3) {
return p + (q - p) * (2 / 3 - tint) * 6
}
return p
}
function convertTo01Bounds(n, max) {
const bounded = Math.min(max, Math.max(0, n));
if (Math.abs(bounded - max) < 1e-6) {
return 1
}
return bounded % max / max
}
function hsvToRgb(h, s, v) {
const index = Math.floor(h % 360 / 60);
const vMin = (100 - s) * v / 100;
const a = h % 60 / 60 * (v - vMin);
const vInc = vMin + a;
const vDec = v - a;
let r = 0;
let g = 0;
let b = 0;
switch (index) {
case 0:
r = v;
g = vInc;
b = vMin;
break;
case 1:
r = vDec;
g = v;
b = vMin;
break;
case 2:
r = vMin;
g = v;
b = vInc;
break;
case 3:
r = vMin;
g = vDec;
b = v;
break;
case 4:
r = vInc;
g = vMin;
b = v;
break;
case 5:
r = v;
g = vMin;
b = vDec
}
return [Math.round(2.55 * r), Math.round(2.55 * g), Math.round(2.55 * b)]
}
function hslToRgb(h, s, l) {
let r = 0;
let g = 0;
let b = 0;
const h01 = convertTo01Bounds(h, 360);
const s01 = convertTo01Bounds(s, 100);
const l01 = convertTo01Bounds(l, 100);
if (0 === s01) {
r = l01;
g = l01;
b = l01
} else {
const q = l01 < .5 ? l01 * (1 + s01) : l01 + s01 - l01 * s01;
const p = 2 * l01 - q;
r = hueToRgb(p, q, makeColorTint("r", h01));
g = hueToRgb(p, q, makeColorTint("g", h01));
b = hueToRgb(p, q, makeColorTint("b", h01))
}
return [Math.round(255 * r), Math.round(255 * g), Math.round(255 * b)]
}
const standardColorTypes = [{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
process: colorString => [parseInt(colorString[1], 10), parseInt(colorString[2], 10), parseInt(colorString[3], 10)]
}, {
re: /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*\.*\d+)\)$/,
process: colorString => [parseInt(colorString[1], 10), parseInt(colorString[2], 10), parseInt(colorString[3], 10), parseFloat(colorString[4])]
}, {
re: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/,
process: colorString => [parseInt(colorString[1], 16), parseInt(colorString[2], 16), parseInt(colorString[3], 16)]
}, {
re: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/,
process: colorString => [parseInt(colorString[1], 16), parseInt(colorString[2], 16), parseInt(colorString[3], 16), Number((parseInt(colorString[4], 16) / 255).toFixed(2))]
}, {
re: /^#([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$/,
process: colorString => [parseInt(colorString[1] + colorString[1], 16), parseInt(colorString[2] + colorString[2], 16), parseInt(colorString[3] + colorString[3], 16), Number((parseInt(colorString[4] + colorString[4], 16) / 255).toFixed(2))]
}, {
re: /^#([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$/,
process: colorString => [parseInt(colorString[1] + colorString[1], 16), parseInt(colorString[2] + colorString[2], 16), parseInt(colorString[3] + colorString[3], 16)]
}, {
re: /^hsv\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
process(colorString) {
const h = parseInt(colorString[1], 10);
const s = parseInt(colorString[2], 10);
const v = parseInt(colorString[3], 10);
const rgb = hsvToRgb(h, s, v);
return [rgb[0], rgb[1], rgb[2], 1, [h, s, v]]
}
}, {
re: /^hsl\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
process(colorString) {
const h = parseInt(colorString[1], 10);
const s = parseInt(colorString[2], 10);
const l = parseInt(colorString[3], 10);
const rgb = hslToRgb(h, s, l);
return [rgb[0], rgb[1], rgb[2], 1, null, [h, s, l]]
}
}];
function parseColor(color) {
if ("transparent" === color) {
return [0, 0, 0, 0]
}
for (const colorType of standardColorTypes) {
const match = colorType.re.exec(color);
if (match) {
return colorType.process(match)
}
}
return null
}
function normalize(colorComponent) {
let def = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
let max = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 255;
if (void 0 === colorComponent || Number.isNaN(colorComponent) || colorComponent < 0) {
return def
}
return colorComponent > max ? max : colorComponent
}
function toHexFromRgb(r, g, b) {
return `#${(16777216|r<<16|g<<8|b).toString(16).slice(1)}`
}
function toHsvFromRgb(r, g, b) {
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const delta = max - min;
let H = 0;
let S = 0;
let V = max;
S = 0 === max ? 0 : 1 - min / max;
if (max === min) {
H = 0
} else {
switch (max) {
case r:
H = (g - b) / delta * 60;
if (g < b) {
H += 360
}
break;
case g:
H = (b - r) / delta * 60 + 120;
break;
case b:
H = (r - g) / delta * 60 + 240
}
}
S *= 100;
V *= 100 / 255;
return {
h: Math.round(H),
s: Math.round(S),
v: Math.round(V)
}
}
function calculateHue(r, g, b, delta) {
const max = Math.max(r, g, b);
switch (max) {
case r:
return (g - b) / delta + (g < b ? 6 : 0);
case g:
return (b - r) / delta + 2;
case b:
return (r - g) / delta + 4;
default:
return 0
}
}
function toHslFromRgb(r, g, b) {
const r01 = convertTo01Bounds(r, 255);
const g01 = convertTo01Bounds(g, 255);
const b01 = convertTo01Bounds(b, 255);
const max = Math.max(r01, g01, b01);
const min = Math.min(r01, g01, b01);
const maxMinSum = max + min;
let h = 0;
let s = 0;
const l = maxMinSum / 2;
if (max === min) {
h = 0;
s = 0
} else {
const delta = max - min;
if (l > .5) {
s = delta / (2 - maxMinSum)
} else {
s = delta / maxMinSum
}
h = calculateHue(r01, g01, b01, delta);
h /= 6
}
return {
h: Math.round(360 * h),
s: Math.round(100 * s),
l: Math.round(100 * l)
}
}
function isIntegerBetweenMinAndMax(value) {
let min = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
let max = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 255;
if ("number" !== typeof value || value % 1 !== 0 || value < min || value > max || isNaN(value)) {
return false
}
return true
}