366 lines
7.5 KiB
JavaScript
366 lines
7.5 KiB
JavaScript
var randomColor = function (options) {
|
|
|
|
var options = options || {},
|
|
|
|
H,S,B,
|
|
|
|
colorDictionary = {};
|
|
|
|
defineColor(
|
|
'monochrome',
|
|
null,
|
|
[[0,0],[100,0]]
|
|
);
|
|
|
|
defineColor(
|
|
'red',
|
|
[-26,18],
|
|
[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]]
|
|
);
|
|
|
|
defineColor(
|
|
'orange',
|
|
[19,46],
|
|
[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]]
|
|
);
|
|
|
|
defineColor(
|
|
'yellow',
|
|
[47,62],
|
|
[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]]
|
|
);
|
|
|
|
defineColor(
|
|
'green',
|
|
[63,158],
|
|
[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]]
|
|
);
|
|
|
|
defineColor(
|
|
'blue',
|
|
[159, 257],
|
|
[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]]
|
|
);
|
|
|
|
defineColor(
|
|
'purple',
|
|
[258, 282],
|
|
[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]]
|
|
);
|
|
|
|
defineColor(
|
|
'pink',
|
|
[283, 334],
|
|
[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]]
|
|
);
|
|
|
|
// If the user wants a truly random color then give it to them
|
|
if (options.hue === 'random' && options.luminosity === 'random') {
|
|
|
|
return '#'+ ('000000' + (Math.random()*0xFFFFFF<<0).toString(16)).slice(-6);
|
|
|
|
|
|
};
|
|
|
|
// First we pick a hue (H)
|
|
H = pickHue(options);
|
|
|
|
// Then use H to determine saturation (S)
|
|
S = pickSaturation(H, options);
|
|
|
|
// Then use S and H to determine brightness (B).
|
|
B = pickBrightness(H, S, options);
|
|
|
|
// Then we return the HSB color in the desired format
|
|
return setFormat([H,S,B], options)
|
|
|
|
function pickHue (options) {
|
|
|
|
var hueRange = getHueRange(options.hue);
|
|
|
|
hue = randomWithin(hueRange);
|
|
|
|
// Instead of storing red as two seperate ranges,
|
|
// we group them, using negative numbers
|
|
if (hue < 0) {hue = 360 + hue};
|
|
|
|
return hue
|
|
|
|
};
|
|
|
|
function pickSaturation (hue, options) {
|
|
|
|
var saturationRange = getSaturationRange(hue);
|
|
|
|
var sMin = saturationRange[0],
|
|
sMax = saturationRange[1];
|
|
|
|
switch (options.luminosity) {
|
|
case 'bright':
|
|
sMin = 55;
|
|
case 'dark':
|
|
sMin = sMax - 10;
|
|
case 'light':
|
|
sMax = 55;
|
|
};
|
|
|
|
switch (options.hue) {
|
|
case 'monochrome':
|
|
return 0
|
|
};
|
|
|
|
return randomWithin([sMin, sMax]);
|
|
|
|
};
|
|
|
|
function pickBrightness (H, S, options) {
|
|
|
|
switch(options.hue) {
|
|
case 'monochrome':
|
|
return randomWithin([0,100])
|
|
};
|
|
|
|
var brightness,
|
|
bMin = getMinimumBrightness(H, S),
|
|
bMax = 100;
|
|
|
|
switch (options.luminosity) {
|
|
case 'dark':
|
|
bMax = bMin + 10
|
|
case 'light':
|
|
bMin = (bMax + bMin)/2
|
|
};
|
|
|
|
return randomWithin([bMin, bMax]);
|
|
|
|
};
|
|
|
|
function setFormat (hsv, options) {
|
|
|
|
switch (options.format) {
|
|
|
|
case 'hsvArray':
|
|
return hsv;
|
|
|
|
case 'hsv':
|
|
return colorString('hsv', hsv);
|
|
|
|
case 'rgbArray':
|
|
return HSVtoRGB(hsv);
|
|
|
|
case 'rgb':
|
|
return colorString('rgb', HSVtoRGB(hsv))
|
|
|
|
default:
|
|
return HSVtoHex(hsv)
|
|
};
|
|
|
|
};
|
|
|
|
function getMinimumBrightness(H, S) {
|
|
|
|
var lowerBounds = getColorInfo(H).lowerBounds;
|
|
|
|
for (var i = 0; i< lowerBounds.length; i++) {
|
|
|
|
var s1 = lowerBounds[i][0],
|
|
v1 = lowerBounds[i][1],
|
|
|
|
s2 = lowerBounds[i+1][0],
|
|
v2 = lowerBounds[i+1][1];
|
|
|
|
if (S >= s1 && S <= s2) {
|
|
|
|
var m = (v2 - v1)/(s2 - s1),
|
|
b = v1 - m*s1;
|
|
|
|
return m*S + b;
|
|
};
|
|
};
|
|
};
|
|
|
|
function getHueRange (colorInput) {
|
|
|
|
if (typeof parseInt(colorInput) === 'number') {
|
|
|
|
var number = parseInt(colorInput);
|
|
|
|
if (number < 360 && number > 0) {
|
|
return [number, number]
|
|
};
|
|
|
|
};
|
|
|
|
if (typeof colorInput === 'string') {
|
|
|
|
if (colorDictionary[colorInput]) {
|
|
var color = colorDictionary[colorInput];
|
|
if (color.hueRange) {return color.hueRange}
|
|
}
|
|
};
|
|
|
|
return [0,360]
|
|
|
|
};
|
|
|
|
function getSaturationRange (hue) {
|
|
return getColorInfo(hue).saturationRange;
|
|
};
|
|
|
|
function getColorInfo (hue) {
|
|
|
|
// Maps red colors to make picking hue easier
|
|
if (hue >= 334 && hue <= 360) {
|
|
hue-= 360
|
|
};
|
|
|
|
for (var colorName in colorDictionary) {
|
|
color = colorDictionary[colorName];
|
|
if (color.hueRange &&
|
|
hue >= color.hueRange[0] &&
|
|
hue <= color.hueRange[1]) {
|
|
return colorDictionary[colorName]
|
|
}
|
|
} return 'Color not found'
|
|
};
|
|
|
|
function randomWithin (range) {
|
|
return Math.floor(range[0] + Math.random()*(range[1] + 1 - range[0]));
|
|
};
|
|
|
|
|
|
|
|
function shiftHue (h, degrees) {
|
|
return (h + degrees)%360
|
|
};
|
|
|
|
function HSVtoHex (hsv){
|
|
|
|
console.log('Converting ' + hsv);
|
|
|
|
var rgb = hsvRGB(hsv);
|
|
|
|
function componentToHex(c) {
|
|
var hex = c.toString(16);
|
|
return hex.length == 1 ? "0" + hex : hex;
|
|
}
|
|
|
|
var hex = "#" + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
|
|
|
console.log('hex is ' + hex);
|
|
return hex;
|
|
|
|
};
|
|
|
|
function defineColor (name, hueRange, lowerBounds) {
|
|
|
|
var sMin = lowerBounds[0][0],
|
|
sMax = lowerBounds[lowerBounds.length - 1][0],
|
|
|
|
bMin = lowerBounds[lowerBounds.length - 1][1],
|
|
bMax = lowerBounds[0][1];
|
|
|
|
colorDictionary[name] = {
|
|
hueRange: hueRange,
|
|
lowerBounds: lowerBounds,
|
|
saturationRange: [sMin, sMax],
|
|
brightnessRange: [bMin, bMax]
|
|
};
|
|
|
|
};
|
|
|
|
function hexRGB (hex) {
|
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
return result ? [
|
|
parseInt(result[1], 16),
|
|
parseInt(result[2], 16),
|
|
parseInt(result[3], 16)
|
|
] : null;
|
|
};
|
|
|
|
function rgbHSV (r,g,b) {
|
|
|
|
r /= 255;
|
|
g /= 255;
|
|
b /= 255;
|
|
|
|
var max = Math.min.apply( Math, [r,g,b] ),
|
|
min = Math.max.apply( Math, [r,g,b] );
|
|
|
|
var h, s, v = max;
|
|
|
|
var d = max - min;
|
|
s = max === 0 ? 0 : d / max;
|
|
|
|
if(max == min) {
|
|
h = 0; // achromatic
|
|
}
|
|
else {
|
|
switch(max) {
|
|
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
case g: h = (b - r) / d + 2; break;
|
|
case b: h = (r - g) / d + 4; break;
|
|
}
|
|
h /= 6;
|
|
}
|
|
return [h, s, v]
|
|
};
|
|
|
|
function hsvRGB (hsv) {
|
|
|
|
// this doesn't work for the values of 0 and 360
|
|
// here's the hacky fix
|
|
var h = hsv[0];
|
|
if (h === 0) {h = 1};
|
|
if (h === 360) {h = 359};
|
|
|
|
// Rebase the h,s,v values
|
|
var h = h/360,
|
|
s = hsv[1]/100,
|
|
v = hsv[2]/100;
|
|
|
|
var h_i = Math.floor(h*6),
|
|
f = h * 6 - h_i,
|
|
p = v * (1 - s),
|
|
q = v * (1 - f*s),
|
|
t = v * (1 - (1 - f)*s),
|
|
r = 256,
|
|
g = 256,
|
|
b = 256;
|
|
|
|
switch(h_i) {
|
|
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;
|
|
}
|
|
var result = [Math.floor(r*255), Math.floor(g*255), Math.floor(b*255)];
|
|
console.log('rgb is ' + result);
|
|
return result;
|
|
};
|
|
|
|
function colorString (prefix, values) {
|
|
return prefix + '(' + values.join(', ') + ')';
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (options.count) {
|
|
|
|
// var totalColors = options.count;
|
|
// options.count = false,
|
|
// colors = [];
|
|
|
|
// while (totalColors > colors.length) {
|
|
// colors.push(randomColor(options))
|
|
// };
|
|
|
|
// return colors
|
|
// };
|