|
|
|
|
;(function(window, undefined){
|
|
|
|
|
"use strict"
|
|
|
|
|
|
|
|
|
|
var _valueRanges = {
|
|
|
|
|
rgb: {r: [0, 255], g: [0, 255], b: [0, 255]},
|
|
|
|
|
hsv: {h: [0, 360], s: [0, 100], v: [0, 100]},
|
|
|
|
|
hsl: {h: [0, 360], s: [0, 100], l: [0, 100]},
|
|
|
|
|
alpha: {alpha: [0, 1]},
|
|
|
|
|
HEX: {HEX: [0, 16777215]} // maybe we don't need this
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_instance = {},
|
|
|
|
|
_colors = {},
|
|
|
|
|
|
|
|
|
|
grey = {r: 0.298954, g: 0.586434, b: 0.114612}, // CIE-XYZ 1931
|
|
|
|
|
luminance = {r: 0.2126, g: 0.7152, b: 0.0722}, // W3C 2.0
|
|
|
|
|
|
|
|
|
|
Colors = window.Colors = function(options) {
|
|
|
|
|
this.colors = {RND: {}};
|
|
|
|
|
this.options = {
|
|
|
|
|
color: 'rgba(204, 82, 37, 0.8)', // init value(s)...
|
|
|
|
|
grey: grey,
|
|
|
|
|
luminance: luminance,
|
|
|
|
|
valueRanges: _valueRanges
|
|
|
|
|
// customBG: '#808080'
|
|
|
|
|
// convertCallback: undefined,
|
|
|
|
|
// allMixDetails: false
|
|
|
|
|
};
|
|
|
|
|
initInstance(this, options || {});
|
|
|
|
|
},
|
|
|
|
|
initInstance = function(THIS, options) {
|
|
|
|
|
var importColor,
|
|
|
|
|
_options = THIS.options,
|
|
|
|
|
customBG;
|
|
|
|
|
|
|
|
|
|
focusInstance(THIS);
|
|
|
|
|
for (var option in options) {
|
|
|
|
|
if (options[option] !== undefined) _options[option] = options[option];
|
|
|
|
|
}
|
|
|
|
|
customBG = _options.customBG;
|
|
|
|
|
_options.customBG = (typeof customBG === 'string') ? ColorConverter.txt2color(customBG).rgb : customBG;
|
|
|
|
|
_colors = setColor(THIS.colors, _options.color, undefined, true); // THIS.colors = _colors =
|
|
|
|
|
},
|
|
|
|
|
focusInstance = function(THIS) {
|
|
|
|
|
if (_instance !== THIS) {
|
|
|
|
|
_instance = THIS;
|
|
|
|
|
_colors = THIS.colors;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Colors.prototype.setColor = function(newCol, type, alpha) {
|
|
|
|
|
focusInstance(this);
|
|
|
|
|
if (newCol) {
|
|
|
|
|
return setColor(this.colors, newCol, type, undefined, alpha);
|
|
|
|
|
} else {
|
|
|
|
|
if (alpha !== undefined) {
|
|
|
|
|
this.colors.alpha = limitValue(alpha, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
return convertColors(type);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Colors.prototype.setCustomBackground = function(col) { // wild gues,... check again...
|
|
|
|
|
focusInstance(this); // needed???
|
|
|
|
|
this.options.customBG = (typeof col === 'string') ? ColorConverter.txt2color(col).rgb : col;
|
|
|
|
|
// return setColor(this.colors, this.options.customBG, 'rgb', true); // !!!!RGB
|
|
|
|
|
return setColor(this.colors, undefined, 'rgb'); // just recalculate existing
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Colors.prototype.saveAsBackground = function() { // alpha
|
|
|
|
|
focusInstance(this); // needed???
|
|
|
|
|
// return setColor(this.colors, this.colors.RND.rgb, 'rgb', true);
|
|
|
|
|
return setColor(this.colors, undefined, 'rgb', true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------ //
|
|
|
|
|
// ---------- Color calculation related stuff ---------- //
|
|
|
|
|
// -------------------------------------------------------//
|
|
|
|
|
|
|
|
|
|
function setColor(colors, color, type, save, alpha) { // color only full range
|
|
|
|
|
if (typeof color === 'string') {
|
|
|
|
|
var color = ColorConverter.txt2color(color); // new object
|
|
|
|
|
type = color.type;
|
|
|
|
|
_colors[type] = color[type];
|
|
|
|
|
alpha = alpha !== undefined ? alpha : color.alpha;
|
|
|
|
|
} else if (color) {
|
|
|
|
|
for (var n in color) {
|
|
|
|
|
colors[type][n] = limitValue(color[n] / _valueRanges[type][n][1], 0 , 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (alpha !== undefined) {
|
|
|
|
|
colors.alpha = limitValue(+alpha, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
return convertColors(type, save ? colors : undefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function saveAsBackground(RGB, rgb, alpha) {
|
|
|
|
|
var grey = _instance.options.grey,
|
|
|
|
|
color = {};
|
|
|
|
|
|
|
|
|
|
color.RGB = {r: RGB.r, g: RGB.g, b: RGB.b};
|
|
|
|
|
color.rgb = {r: rgb.r, g: rgb.g, b: rgb.b};
|
|
|
|
|
color.alpha = alpha;
|
|
|
|
|
// color.RGBLuminance = getLuminance(RGB);
|
|
|
|
|
color.equivalentGrey = Math.round(grey.r * RGB.r + grey.g * RGB.g + grey.b * RGB.b);
|
|
|
|
|
|
|
|
|
|
color.rgbaMixBlack = mixColors(rgb, {r: 0, g: 0, b: 0}, alpha, 1);
|
|
|
|
|
color.rgbaMixWhite = mixColors(rgb, {r: 1, g: 1, b: 1}, alpha, 1);
|
|
|
|
|
color.rgbaMixBlack.luminance = getLuminance(color.rgbaMixBlack, true);
|
|
|
|
|
color.rgbaMixWhite.luminance = getLuminance(color.rgbaMixWhite, true);
|
|
|
|
|
|
|
|
|
|
if (_instance.options.customBG) {
|
|
|
|
|
color.rgbaMixCustom = mixColors(rgb, _instance.options.customBG, alpha, 1);
|
|
|
|
|
color.rgbaMixCustom.luminance = getLuminance(color.rgbaMixCustom, true);
|
|
|
|
|
_instance.options.customBG.luminance = getLuminance(_instance.options.customBG, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function convertColors(type, colorObj) {
|
|
|
|
|
// console.time('convertColors');
|
|
|
|
|
var colors = colorObj || _colors,
|
|
|
|
|
convert = ColorConverter,
|
|
|
|
|
options = _instance.options,
|
|
|
|
|
ranges = _valueRanges,
|
|
|
|
|
RND = colors.RND,
|
|
|
|
|
// type = colorType, // || _mode.type,
|
|
|
|
|
modes, mode = '', from = '', // value = '',
|
|
|
|
|
exceptions = {hsl: 'hsv', rgb: type},
|
|
|
|
|
RGB = RND.rgb, SAVE, SMART;
|
|
|
|
|
|
|
|
|
|
if (type !== 'alpha') {
|
|
|
|
|
for (var typ in ranges) {
|
|
|
|
|
if (!ranges[typ][typ]) { // no alpha|HEX
|
|
|
|
|
if (type !== typ) {
|
|
|
|
|
from = exceptions[typ] || 'rgb';
|
|
|
|
|
colors[typ] = convert[from + '2' + typ](colors[from]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!RND[typ]) RND[typ] = {};
|
|
|
|
|
modes = colors[typ];
|
|
|
|
|
for(mode in modes) {
|
|
|
|
|
RND[typ][mode] = Math.round(modes[mode] * ranges[typ][mode][1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RGB = RND.rgb;
|
|
|
|
|
colors.HEX = convert.RGB2HEX(RGB);
|
|
|
|
|
colors.equivalentGrey =
|
|
|
|
|
options.grey.r * colors.rgb.r +
|
|
|
|
|
options.grey.g * colors.rgb.g +
|
|
|
|
|
options.grey.b * colors.rgb.b;
|
|
|
|
|
colors.webSave = SAVE = getClosestWebColor(RGB, 51);
|
|
|
|
|
// colors.webSave.HEX = convert.RGB2HEX(colors.webSave);
|
|
|
|
|
colors.webSmart = SMART = getClosestWebColor(RGB, 17);
|
|
|
|
|
// colors.webSmart.HEX = convert.RGB2HEX(colors.webSmart);
|
|
|
|
|
colors.saveColor =
|
|
|
|
|
RGB.r === SAVE.r && RGB.g === SAVE.g && RGB.b === SAVE.b ? 'web save' :
|
|
|
|
|
RGB.r === SMART.r && RGB.g === SMART.g && RGB.b === SMART.b ? 'web smart' : '';
|
|
|
|
|
colors.hueRGB = ColorConverter.hue2RGB(colors.hsv.h);
|
|
|
|
|
|
|
|
|
|
if (colorObj) {
|
|
|
|
|
colors.background = saveAsBackground(RGB, colors.rgb, colors.alpha);
|
|
|
|
|
}
|
|
|
|
|
} // else RGB = RND.rgb;
|
|
|
|
|
|
|
|
|
|
var rgb = colors.rgb, // for better minification...
|
|
|
|
|
alpha = colors.alpha,
|
|
|
|
|
luminance = 'luminance',
|
|
|
|
|
background = colors.background,
|
|
|
|
|
rgbaMixBlack, rgbaMixWhite, rgbaMixCustom,
|
|
|
|
|
rgbaMixBG, rgbaMixBGMixBlack, rgbaMixBGMixWhite, rgbaMixBGMixCustom;
|
|
|
|
|
|
|
|
|
|
rgbaMixBlack = mixColors(rgb, {r: 0, g: 0, b: 0}, alpha, 1);
|
|
|
|
|
rgbaMixBlack[luminance] = getLuminance(rgbaMixBlack, true);
|
|
|
|
|
colors.rgbaMixBlack = rgbaMixBlack;
|
|
|
|
|
|
|
|
|
|
rgbaMixWhite = mixColors(rgb, {r: 1, g: 1, b: 1}, alpha, 1);
|
|
|
|
|
rgbaMixWhite[luminance] = getLuminance(rgbaMixWhite, true);
|
|
|
|
|
colors.rgbaMixWhite = rgbaMixWhite;
|
|
|
|
|
|
|
|
|
|
if (options.customBG) {
|
|
|
|
|
rgbaMixBGMixCustom = mixColors(rgb, background.rgbaMixCustom, alpha, 1);
|
|
|
|
|
rgbaMixBGMixCustom[luminance] = getLuminance(rgbaMixBGMixCustom, true);
|
|
|
|
|
rgbaMixBGMixCustom.WCAG2Ratio = getWCAG2Ratio(rgbaMixBGMixCustom[luminance],
|
|
|
|
|
background.rgbaMixCustom[luminance]);
|
|
|
|
|
colors.rgbaMixBGMixCustom = rgbaMixBGMixCustom;
|
|
|
|
|
/* ------ */
|
|
|
|
|
rgbaMixBGMixCustom.luminanceDelta = Math.abs(
|
|
|
|
|
rgbaMixBGMixCustom[luminance] - background.rgbaMixCustom[luminance]);
|
|
|
|
|
rgbaMixBGMixCustom.hueDelta = getHueDelta(background.rgbaMixCustom, rgbaMixBGMixCustom, true);
|
|
|
|
|
/* ------ */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
colors.RGBLuminance = getLuminance(RGB);
|
|
|
|
|
colors.HUELuminance = getLuminance(colors.hueRGB);
|
|
|
|
|
|
|
|
|
|
// renderVars.readyToRender = true;
|
|
|
|
|
if (options.convertCallback) {
|
|
|
|
|
options.convertCallback(colors, type); //, convert); //, _mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// console.timeEnd('convertColors')
|
|
|
|
|
// if (colorObj)
|
|
|
|
|
return colors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------ //
|
|
|
|
|
// ------------------ color conversion ------------------ //
|
|
|
|
|
// -------------------------------------------------------//
|
|
|
|
|
|
|
|
|
|
var ColorConverter = {
|
|
|
|
|
txt2color: function(txt) {
|
|
|
|
|
var color = {},
|
|
|
|
|
parts = txt.replace(/(?:#|\)|%)/g, '').split('('),
|
|
|
|
|
values = (parts[1] || '').split(/,\s*/),
|
|
|
|
|
type = parts[1] ? parts[0].substr(0, 3) : 'rgb',
|
|
|
|
|
m = '';
|
|
|
|
|
|
|
|
|
|
color.type = type;
|
|
|
|
|
color[type] = {};
|
|
|
|
|
if (parts[1]) {
|
|
|
|
|
for (var n = 3; n--; ) {
|
|
|
|
|
m = type[n] || type.charAt(n); // IE7
|
|
|
|
|
color[type][m] = +values[n] / _valueRanges[type][m][1];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
color.rgb = ColorConverter.HEX2rgb(parts[0]);
|
|
|
|
|
}
|
|
|
|
|
// color.color = color[type];
|
|
|
|
|
color.alpha = values[3] ? +values[3] : 1;
|
|
|
|
|
|
|
|
|
|
return color;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
RGB2HEX: function(RGB) {
|
|
|
|
|
return (
|
|
|
|
|
(RGB.r < 16 ? '0' : '') + RGB.r.toString(16) +
|
|
|
|
|
(RGB.g < 16 ? '0' : '') + RGB.g.toString(16) +
|
|
|
|
|
(RGB.b < 16 ? '0' : '') + RGB.b.toString(16)
|
|
|
|
|
).toUpperCase();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
HEX2rgb: function(HEX) {
|
|
|
|
|
HEX = HEX.split(''); // IE7
|
|
|
|
|
return {
|
|
|
|
|
r: parseInt(HEX[0] + HEX[HEX[3] ? 1 : 0], 16) / 255,
|
|
|
|
|
g: parseInt(HEX[HEX[3] ? 2 : 1] + (HEX[3] || HEX[1]), 16) / 255,
|
|
|
|
|
b: parseInt((HEX[4] || HEX[2]) + (HEX[5] || HEX[2]), 16) / 255
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hue2RGB: function(hue) {
|
|
|
|
|
var h = hue * 6,
|
|
|
|
|
mod = ~~h % 6, // Math.floor(h) -> faster in most browsers
|
|
|
|
|
i = h === 6 ? 0 : (h - mod);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
r: Math.round([1, 1 - i, 0, 0, i, 1][mod] * 255),
|
|
|
|
|
g: Math.round([i, 1, 1, 1 - i, 0, 0][mod] * 255),
|
|
|
|
|
b: Math.round([0, 0, i, 1, 1, 1 - i][mod] * 255)
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ------------------------ HSV ------------------------ //
|
|
|
|
|
|
|
|
|
|
rgb2hsv: function(rgb) { // faster
|
|
|
|
|
var r = rgb.r,
|
|
|
|
|
g = rgb.g,
|
|
|
|
|
b = rgb.b,
|
|
|
|
|
k = 0, chroma, min, s;
|
|
|
|
|
|
|
|
|
|
if (g < b) {
|
|
|
|
|
g = b + (b = g, 0);
|
|
|
|
|
k = -1;
|
|
|
|
|
}
|
|
|
|
|
min = b;
|
|
|
|
|
if (r < g) {
|
|
|
|
|
r = g + (g = r, 0);
|
|
|
|
|
k = -2 / 6 - k;
|
|
|
|
|
min = Math.min(g, b); // g < b ? g : b; ???
|
|
|
|
|
}
|
|
|
|
|
chroma = r - min;
|
|
|
|
|
s = r ? (chroma / r) : 0;
|
|
|
|
|
return {
|
|
|
|
|
h: s < 1e-15 ? ((_colors && _colors.hsl && _colors.hsl.h) || 0) :
|
|
|
|
|
chroma ? Math.abs(k + (g - b) / (6 * chroma)) : 0,
|
|
|
|
|
s: r ? (chroma / r) : ((_colors && _colors.hsv && _colors.hsv.s) || 0), // ??_colors.hsv.s || 0
|
|
|
|
|
v: r
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hsv2rgb: function(hsv) {
|
|
|
|
|
var h = hsv.h * 6,
|
|
|
|
|
s = hsv.s,
|
|
|
|
|
v = hsv.v,
|
|
|
|
|
i = ~~h, // Math.floor(h) -> faster in most browsers
|
|
|
|
|
f = h - i,
|
|
|
|
|
p = v * (1 - s),
|
|
|
|
|
q = v * (1 - f * s),
|
|
|
|
|
t = v * (1 - (1 - f) * s),
|
|
|
|
|
mod = i % 6;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
r: [v, q, p, p, t, v][mod],
|
|
|
|
|
g: [t, v, v, q, p, p][mod],
|
|
|
|
|
b: [p, p, t, v, v, q][mod]
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ------------------------ HSL ------------------------ //
|
|
|
|
|
|
|
|
|
|
hsv2hsl: function(hsv) {
|
|
|
|
|
var l = (2 - hsv.s) * hsv.v,
|
|
|
|
|
s = hsv.s * hsv.v;
|
|
|
|
|
|
|
|
|
|
s = !hsv.s ? 0 : l < 1 ? (l ? s / l : 0) : s / (2 - l);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
h: hsv.h,
|
|
|
|
|
s: !hsv.v && !s ? ((_colors && _colors.hsl && _colors.hsl.s) || 0) : s, // ???
|
|
|
|
|
l: l / 2
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
rgb2hsl: function(rgb, dependent) { // not used in Color
|
|
|
|
|
var hsv = ColorConverter.rgb2hsv(rgb);
|
|
|
|
|
|
|
|
|
|
return ColorConverter.hsv2hsl(dependent ? hsv : (_colors.hsv = hsv));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hsl2rgb: function(hsl) {
|
|
|
|
|
var h = hsl.h * 6,
|
|
|
|
|
s = hsl.s,
|
|
|
|
|
l = hsl.l,
|
|
|
|
|
v = l < 0.5 ? l * (1 + s) : (l + s) - (s * l),
|
|
|
|
|
m = l + l - v,
|
|
|
|
|
sv = v ? ((v - m) / v) : 0,
|
|
|
|
|
sextant = ~~h, // Math.floor(h) -> faster in most browsers
|
|
|
|
|
fract = h - sextant,
|
|
|
|
|
vsf = v * sv * fract,
|
|
|
|
|
t = m + vsf,
|
|
|
|
|
q = v - vsf,
|
|
|
|
|
mod = sextant % 6;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
r: [v, q, m, m, t, v][mod],
|
|
|
|
|
g: [t, v, v, q, m, m][mod],
|
|
|
|
|
b: [m, m, t, v, v, q][mod]
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------ //
|
|
|
|
|
// ------------------ helper functions ------------------ //
|
|
|
|
|
// -------------------------------------------------------//
|
|
|
|
|
|
|
|
|
|
function getClosestWebColor(RGB, val) {
|
|
|
|
|
var out = {},
|
|
|
|
|
tmp = 0,
|
|
|
|
|
half = val / 2;
|
|
|
|
|
|
|
|
|
|
for (var n in RGB) {
|
|
|
|
|
tmp = RGB[n] % val; // 51 = 'web save', 17 = 'web smart'
|
|
|
|
|
out[n] = RGB[n] + (tmp > half ? val - tmp : -tmp);
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getHueDelta(rgb1, rgb2, nominal) {
|
|
|
|
|
return (Math.max(rgb1.r - rgb2.r, rgb2.r - rgb1.r) +
|
|
|
|
|
Math.max(rgb1.g - rgb2.g, rgb2.g - rgb1.g) +
|
|
|
|
|
Math.max(rgb1.b - rgb2.b, rgb2.b - rgb1.b)) * (nominal ? 255 : 1) / 765;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getLuminance(rgb, normalized) {
|
|
|
|
|
var div = normalized ? 1 : 255,
|
|
|
|
|
RGB = [rgb.r / div, rgb.g / div, rgb.b / div],
|
|
|
|
|
luminance = _instance.options.luminance;
|
|
|
|
|
|
|
|
|
|
for (var i = RGB.length; i--; ) {
|
|
|
|
|
RGB[i] = RGB[i] <= 0.03928 ? RGB[i] / 12.92 : Math.pow(((RGB[i] + 0.055) / 1.055), 2.4);
|
|
|
|
|
}
|
|
|
|
|
return ((luminance.r * RGB[0]) + (luminance.g * RGB[1]) + (luminance.b * RGB[2]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mixColors(topColor, bottomColor, topAlpha, bottomAlpha) {
|
|
|
|
|
var newColor = {},
|
|
|
|
|
alphaTop = (topAlpha !== undefined ? topAlpha : 1),
|
|
|
|
|
alphaBottom = (bottomAlpha !== undefined ? bottomAlpha : 1),
|
|
|
|
|
alpha = alphaTop + alphaBottom * (1 - alphaTop); // 1 - (1 - alphaTop) * (1 - alphaBottom);
|
|
|
|
|
|
|
|
|
|
for(var n in topColor) {
|
|
|
|
|
newColor[n] = (topColor[n] * alphaTop + bottomColor[n] * alphaBottom * (1 - alphaTop)) / alpha;
|
|
|
|
|
}
|
|
|
|
|
newColor.a = alpha;
|
|
|
|
|
return newColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getWCAG2Ratio(lum1, lum2) {
|
|
|
|
|
var ratio = 1;
|
|
|
|
|
|
|
|
|
|
if (lum1 >= lum2) {
|
|
|
|
|
ratio = (lum1 + 0.05) / (lum2 + 0.05);
|
|
|
|
|
} else {
|
|
|
|
|
ratio = (lum2 + 0.05) / (lum1 + 0.05);
|
|
|
|
|
}
|
|
|
|
|
return Math.round(ratio * 100) / 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function limitValue(value, min, max) {
|
|
|
|
|
// return Math.max(min, Math.min(max, value)); // faster??
|
|
|
|
|
return (value > max ? max : value < min ? min : value);
|
|
|
|
|
}
|
|
|
|
|
})(window);
|