Created
March 15, 2014 10:49
-
-
Save garex/9565057 to your computer and use it in GitHub Desktop.
Tryin to play with imitation of Color Scheme designer which is buggy from start to end :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('transformToLessOperations', function() { | |
eval('var transformToLessOperations = require("..").transformToLessOperations'); | |
var cm = require("color-model"); | |
var cm = require("../../nodejs-color-model"); | |
eval('var AbstractModel = cm.AbstractModel'); | |
eval('var HexRgb = cm.HexRgb'); | |
eval('var Hsl = cm.Hsl'); | |
eval('var Rgb = cm.Rgb'); | |
/* | |
describe('extreme cases', function() { | |
it('should get base color when both colors are same', function() { | |
transformToLessOperations('#fe23ca', '#fe23ca').should.be.equal('#fe23ca; // #fe23ca'); | |
transformToLessOperations('fff', '#ffffff').should.be.equal('#ffffff; // #ffffff'); | |
}); | |
it('should throw error when bad color values provided', function() { | |
(function(){ | |
transformToLessOperations('ggg', 'ffffff'); | |
}).should.throwError(/unknown/); | |
(function(){ | |
transformToLessOperations('', ''); | |
}).should.throwError(/unknown/); | |
}); | |
}); | |
describe('default cases', function() { | |
it('should get only positive spin when positive hue difference', function() { | |
transformToLessOperations('#fe23ca', '#fe23a5').should.be.equal('spin(#fe23ca, 10%); // #fe23ca'); | |
transformToLessOperations('#abc', '#aab0cc').should.be.equal('spin(#aabbcc, 20%); // #aab0cc'); | |
}); | |
it('should get only negative spin when negative hue difference', function() { | |
transformToLessOperations('#fe23ca', '#fe23ef').should.be.equal('spin(#fe23ca, -10%); // #fe23ef'); | |
transformToLessOperations('#abc', '#aac6cc').should.be.equal('spin(#aabbcc, -20%); // #aac6cc'); | |
}); | |
it('should get only saturate when positive saturation difference', function() { | |
transformToLessOperations('#fe23ca', '#ff22cb').should.be.equal('saturate(#fe23ca, 10%); // #ff22cb'); | |
transformToLessOperations('#abc', '#9cbbda').should.be.equal('saturate(#aabbcc, 20%); // #9cbbda'); | |
transformToLessOperations('#ddd', '#e7d3d3').should.be.equal('saturate(#dddddd, 30%); // #e7d3d3'); | |
}); | |
it('should get only desaturate when negative saturation difference', function() { | |
transformToLessOperations('#fe23ca', '#f32ec4').should.be.equal('desaturate(#fe23ca, 10%); // #f32ec4'); | |
transformToLessOperations('#abc', '#b8bbbe').should.be.equal('desaturate(#aabbcc, 20%); // #b8bbbe'); | |
}); | |
it('should get only lighten when positive lightness difference', function() { | |
transformToLessOperations('#fe23ca', '#fe56d6').should.be.equal('lighten(#fe23ca, 10%); // #fe56d6'); | |
transformToLessOperations('#abc', '#eaeef2').should.be.equal('lighten(#aabbcc, 20%); // #eaeef2'); | |
transformToLessOperations('#ddd', '#ffffff').should.be.equal('lighten(#dddddd, 30%); // #ffffff'); | |
}); | |
it('should get only darken when negative lightness difference', function() { | |
transformToLessOperations('#fe23ca', '#ed01b5').should.be.equal('darken(#fe23ca, 10%); // #ed01b5'); | |
transformToLessOperations('#abc', '#6a88a6').should.be.equal('darken(#aabbcc, 20%); // #6a88a6'); | |
transformToLessOperations('#ddd', '#919191').should.be.equal('darken(#dddddd, 30%); // #919191'); | |
}); | |
it('should get all needed operations when all 3 components differs', function() { | |
transformToLessOperations('#fe23ca', '#ff55ba').should.be.equal('spin(saturate(lighten(#fe23ca, 10%), 10%), 10%); // #ff55ba'); | |
transformToLessOperations('#abc', '#828c8e').should.be.equal('spin(desaturate(darken(#aabbcc, 20%), 20%), -20%); // #828c8e'); | |
transformToLessOperations('#ddd', '#ebe9e9').should.be.equal('spin(saturate(lighten(#dddddd, 5%), 5%), 5%); // #ebe9e9'); | |
}); | |
}); | |
*/ | |
describe('advanced cases', function() { | |
it('should allow to imitate analogic color scheme from Color Scheme designer', function() { | |
var h2 = 27.2, | |
h3 = 326.1; //33,9 | |
h2 = 30; | |
var scheme = [[ | |
{"HSV" : {"H" : 0,"S" : 1, "V" : 1}, "RGB" : {"R" : 255,"G" : 0, "B" : 0}}, | |
{"HSV" : {"H" : 0,"S" : 0.75, "V" : 0.75}, "RGB" : {"R" : 191,"G" : 48, "B" : 48}}, | |
{"HSV" : {"H" : 0,"S" : 1, "V" : 0.65}, "RGB" : {"R" : 166,"G" : 0, "B" : 0}}, | |
{"HSV" : {"H" : 0,"S" : 0.75, "V" : 1}, "RGB" : {"R" : 255,"G" : 64, "B" : 64}}, | |
{"HSV" : {"H" : 0,"S" : 0.55, "V" : 1}, "RGB" : {"R" : 255,"G" : 115,"B" : 115}}, | |
{"HSV" : {"H" : h2,"S" : 1, "V" : 1}, "RGB" : {"R" : 255,"G" : 116,"B" : 0}}, | |
{"HSV" : {"H" : h2,"S" : 0.75, "V" : 0.75}, "RGB" : {"R" : 191,"G" : 113,"B" : 48}}, | |
{"HSV" : {"H" : h2,"S" : 1, "V" : 0.65}, "RGB" : {"R" : 166,"G" : 75, "B" : 0}}, | |
{"HSV" : {"H" : h2,"S" : 0.75, "V" : 1}, "RGB" : {"R" : 255,"G" : 150,"B" : 64}}, | |
{"HSV" : {"H" : h2,"S" : 0.55, "V" : 1}, "RGB" : {"R" : 255,"G" : 178,"B" : 115}}, | |
{"HSV" : {"H" : h3,"S" : 1, "V" : 0.8020222978826353}, "RGB" : {"R" : 205,"G" : 0, "B" : 116}}, | |
{"HSV" : {"H" : h3,"S" : 0.75,"V" : 0.6015167234119765}, "RGB" : {"R" : 153,"G" : 38, "B" : 103}}, | |
{"HSV" : {"H" : h3,"S" : 1, "V" : 0.521314493623713}, "RGB" : {"R" : 133,"G" : 0, "B" : 75}}, | |
{"HSV" : {"H" : h3,"S" : 0.75,"V" : 0.9010111489413177}, "RGB" : {"R" : 230,"G" : 57, "B" : 155}}, | |
{"HSV" : {"H" : h3,"S" : 0.55,"V" : 0.9010111489413177}, "RGB" : {"R" : 230,"G" : 103,"B" : 175}} | |
]]; | |
function roundTo(val, to) { | |
if (undefined === to) { | |
to = 100000; | |
} | |
return Math.round(val * to) / to; | |
} | |
function floorTo(val, to) { | |
if (undefined === to) { | |
to = 100000; | |
} | |
return Math.floor(val * to) / to; | |
} | |
function ceilTo(val, to) { | |
if (undefined === to) { | |
to = 100000; | |
} | |
return Math.ceil(val * to) / to; | |
} | |
function _HSVtoRGB(h, s, v) { | |
var r, g, b, i, f, p, q, t; | |
if (h && s === undefined && v === undefined) { | |
s = h.s, v = h.v, h = h.h; | |
} | |
i = Math.floor(h * 6); | |
f = h * 6 - i; | |
p = v * (1 - s); | |
q = v * (1 - f * s); | |
t = v * (1 - (1 - f) * s); | |
console.log(i, f, p, q, t); | |
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; | |
} | |
var rate = 255.999999997; | |
return { | |
R: Math.floor(r * rate), | |
G: Math.floor(g * rate), | |
B: Math.floor(b * rate) | |
}; | |
}; | |
function HSVtoRGB11(hue, saturation, value) { | |
var chroma = value * saturation, | |
huePart = hue / 60, | |
secondComponent = chroma * (1 - Math.abs(huePart % 2 - 1)); | |
return { | |
R: 0, | |
G: 0, | |
B: 0 | |
}; | |
}; | |
/** | |
* HSV to RGB color conversion | |
* | |
* H runs from 0 to 360 degrees | |
* S and V run from 0 to 100 | |
* | |
* Ported from the excellent java algorithm by Eugene Vishnevsky at: | |
* http://www.cs.rit.edu/~ncs/color/t_convert.html | |
*/ | |
function hsvToRgb(h, s, v) { | |
var r, g, b; | |
var i; | |
var f, p, q, t; | |
// Make sure our arguments stay in-range | |
h = Math.max(0, Math.min(360, h)); | |
s = Math.max(0, Math.min(100, s)); | |
v = Math.max(0, Math.min(100, v)); | |
// We accept saturation and value arguments from 0 to 100 because that's | |
// how Photoshop represents those values. Internally, however, the | |
// saturation and value are calculated from a range of 0 to 1. We make | |
// That conversion here. | |
s /= 100; | |
v /= 100; | |
if(s == 0) { | |
// Achromatic (grey) | |
r = g = b = v; | |
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; | |
} | |
h /= 60; // sector 0 to 5 | |
i = Math.floor(h); | |
f = h - i; // factorial part of h | |
p = v * (1 - s); | |
q = v * (1 - s * f); | |
t = v * (1 - s * (1 - f)); | |
switch(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; | |
default: // case 5: | |
r = v; | |
g = p; | |
b = q; | |
} | |
var rate = 255.999999997; | |
rate = 255; | |
return { | |
R: Math.round(r * rate), | |
G: Math.round(g * rate), | |
B: Math.round(b * rate) | |
}; | |
}; | |
function hsv2hsl(hue,sat,val){ | |
var _li = (2 - sat) * val; | |
var _sa = sat * val; | |
_sa /= (_li <= 1) ? (_li) : 2 - (_li); | |
_li /= 2; | |
return [hue, _sa, _li]; | |
return[ //[hue, saturation, lightness] | |
//Range should be between 0 - 1 | |
hue, //Hue stays the same | |
//Saturation is very different between the two color spaces | |
//If (2-sat)*val < 1 set it to sat*val/((2-sat)*val) | |
//Otherwise sat*val/(2-(2-sat)*val) | |
//Conditional is not operating with hue, it is reassigned! | |
sat*val/((hue=(2-sat)*val)<1?hue:2-hue), | |
hue/2 //Lightness is (2-sat)*val/2 | |
//See reassignment of hue above | |
] | |
}; | |
for (var i = 0, iMax = scheme.length; i < iMax; i++) { | |
for (var preset = scheme[i], j = 0, jMax = preset.length; j < jMax; j++) { | |
var hsv = preset[j]['HSV'], | |
rgb = preset[j]['RGB'], | |
_hsl = hsv2hsl(hsv['H'], hsv['S'], hsv['V']), | |
hsl = new Hsl(_hsl[0], roundTo(_hsl[1]), roundTo(_hsl[2])), | |
_rgb = hsvToRgb(hsv['H'], hsv['S']*100, hsv['V']*100); | |
var diff = []; | |
for (var color in _rgb) { | |
if (_rgb[color] != rgb[color]) { | |
diff.push(color + ': ' + (parseInt(_rgb[color]) - parseInt(rgb[color]))); | |
} | |
} | |
if (diff.length) { | |
console.log(hsv, ' // ' + diff.join(' ')); | |
} | |
//console.log(hsl.toRgb().toString(), rgb, hsl.toString(), hsv); | |
} | |
} | |
return; | |
var primaryRgb = new HexRgb('#ff0000'), | |
less = [''], | |
format = ['%(operationsStart)s', '%(operationsBaseColor)s', '%(operationsEnd)s; // %(desiredColor)s']; | |
// @clr-primary-1: #ff0000; // #ff0000 | |
less.push('@clr-primary-1: ' + transformToLessOperations(primaryRgb, primaryRgb)); | |
format[1] = '@clr-primary-1'; | |
formatStr = format.join(''); | |
// @clr-primary-2: #bf3030; // #bf3030 | |
less.push('@clr-primary-2: ' + transformToLessOperations(primaryRgb, | |
primaryRgb.toHsl().desaturate('40.5%').darken('3%').toRgb().toHexString(), | |
formatStr)); | |
// @clr-primary-3: #a60000; // #a60000 | |
less.push('@clr-primary-3: ' + transformToLessOperations(primaryRgb, | |
primaryRgb.toHsl().darken('17.4%').toRgb().toHexString(), | |
formatStr)); | |
// @clr-secondary-a-1: #ff7400; // #ff7400 | |
var secondaryA = primaryRgb.toHsl().spin(27 + 140/360).toRgb(); | |
less.push('@clr-secondary-a-1: ' + transformToLessOperations(primaryRgb, | |
secondaryA.toHexString(), | |
formatStr)); | |
format[1] = '@clr-secondary-a-1'; | |
formatStr = format.join(''); | |
// @clr-secondary-a-2: #bf7130; // #bf7130 | |
less.push('@clr-secondary-a-2: ' + transformToLessOperations(primaryRgb, | |
secondaryA.toHsl().desaturate('40.5%').darken('3%').toRgb().toHexString(), | |
formatStr)); | |
// @clr-secondary-a-3: #a64b00; // #a64b00 | |
less.push('@clr-secondary-a-3: ' + transformToLessOperations(primaryRgb, | |
secondaryA.toHsl().darken('17.4%').toRgb().toHexString(), | |
formatStr)); | |
format[1] = '@clr-primary-1'; | |
formatStr = format.join(''); | |
// @clr-secondary-b-1: #cd0074; // #cd0074 | |
var secondaryB = primaryRgb.toHsl() | |
.spin(360 - 34) | |
.darken('9.9%') | |
.toRgb(); | |
less.push('@clr-secondary-b-1: ' + transformToLessOperations(primaryRgb, | |
secondaryB.toHexString(), | |
formatStr)); | |
format[1] = '@clr-secondary-b-1'; | |
formatStr = format.join(''); | |
// @clr-secondary-b-2: #992667; // #992667 | |
less.push('@clr-secondary-b-2: ' + transformToLessOperations(primaryRgb, | |
secondaryB.toHsl() | |
.desaturate('40.5%') | |
.darken('3%') | |
.toRgb().toHexString(), | |
formatStr)); | |
// @clr-secondary-b-3: #85004b; // #85004b | |
less.push('@clr-secondary-b-3: ' + transformToLessOperations(primaryRgb, | |
secondaryB.toHsl().darken('17.4%').toRgb().toHexString(), | |
formatStr)); | |
console.log(less.join('\n ')); | |
}); | |
//it('should support hue adjustements of analogic color scheme from red to yellow base color'); | |
}); | |
/** | |
* @returns {AbstractModel} | |
*/ | |
AbstractModel.prototype.increase = function (name, value) { | |
if ((typeof value == 'string') && '%' == value.substr(-1)) { | |
value = parseFloat(value) / 100; | |
} | |
return this.component(name, this.component(name) + value); | |
}; | |
/** | |
* @returns {AbstractModel} | |
*/ | |
AbstractModel.prototype.decrease = function (name, value) { | |
if ((typeof value == 'string') && '%' == value.substr(-1)) { | |
value = parseFloat(value) / 100; | |
} | |
this.component(name, this.component(name) - value); | |
return this; | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.saturate = function(value) { | |
return this.increase('saturation', value); | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.desaturate = function(value) { | |
return this.decrease('saturation', value); | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.lighten = function(value) { | |
return this.increase('lightness', value); | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.darken = function(value) { | |
return this.decrease('lightness', value); | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.spin = function(value) { | |
return this.increase('hue', value); | |
}; | |
/** | |
* @returns {Hsl} | |
*/ | |
Hsl.prototype.unspin = function(value) { | |
return this.decrease('hue', value); | |
}; | |
Hsl.prototype.toString1 = function() { | |
var v = [ | |
this._hue.get(), | |
this._saturation.get() * 100 + '%', | |
this._lightness.get() * 100 + '%' | |
]; | |
return this._name + '(' + v.join(', ') + ')'; | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment