对颜色/颜色值进行排序
我正在尽可能精确地对齐以下颜色数组。对颜色/颜色值进行排序
搜索后&尝试使用Stackoverflow建议的许多解决方案,但是,pusher.color库具有最佳解决方案,但它也远非完美。我想听到解决方案,我们如何完美地对齐它们。
JSFIDDLE LINK:http://jsfiddle.net/dxux7y3e/
代码:
var coloursArray=['#FFE9E9','#B85958','#FFB1AE','#FFC2BF','#C55E58','#FFC7C4','#FF9A94','#FF9D96','#FA9790','#A78B88','#A78B88','#CE675B','#DB8073','#FF9D90','#FF7361','#FFD6D1','#F9A092','#FF7B67','#EBACA2','#FF806D','#DD6D5B','#D16654','#ED8673','#FFC4B8','#E2725B','#ED7A64','#8F3926','#BD492F','#9D3C27','#AD533E','#BF4024','#FFC9BC','#6B6766','#E1CDC8','#C2654C','#B3978F','#FFC7B8','#CE2B00','#C2654C','#A24D34','#FF926D','#E78667','#FFB198','#8C756D','#9E6D5B','#FFC7B0','#FFBEA4','#D2B9AF','#FFB193','#632710','#B26746','#976854','#F44900','#E79873','#EFA27F','#532510','#BC866B','#FDE5D9','#FF5B00','#D18C67','#FF5B00','#9E4312','#763713','#BB6B39','#B5622E','#CC7742','#6D4227','#B56B38','#FF7518','#F3B080','#995C30','#995C30','#FF6A00','#D89769','#71472A','#EDAC7B','#EEAB79','#EBCFB9','#FBE3D1','#E19255','#5E381B','#FFDCC1','#FFF0E4','#F68D39','#7B5B40','#FF8313','#FFCEA4','#AA8667','#975414','#CB9867','#8C5B2B','#FFCE9E','#7B4714','#FFF3E7','#FFA449','#CEAF90','#CDB69E','#EFD6BC','#DDA66B','#B27737','#B88A57','#CE9B61','#F4C38B','#543817','#BC9C78','#DBB07A','#FF8E04','#F6EADB','#DBC2A4','#C49B64','#CBA26B','#80551E','#FF9200','#FFECD3','#FFC87C','#FFB755','#DBB680','#D2D0CD','#EFDBBE','#E5C18B','#FFE5BC','#F2EADB','#885F12','#FFE7B6','#825A08','#906712','#F2D18E','#C8C6C2','#FFB000','#FFC243','#C6BEAD','#D0C3A4','#916800','#8C6700','#F4E9CA','#FFF0C5','#FFE080','#FFEBA8','#846600','#FFE692','#F5F0DB','#433F2F','#BBB394','#FFEFAA','#FFE76D','#FFFAE0','#3E3B28','#554900','#E1E0D8','#74725C','#605F54','#F8F7DD','#A5A467','#DDDDDA','#FFFFEE','#A3A39D','#E0E0D7','#BEBEB9','#E8E8E5','#454531','#ACACAA','#E9E9DF','#FFFFDC','#EBEBE7','#979831','#C5C6BE','#B9C866','#898D72','#F3FAD1','#616452','#CED5B0','#A1A787','#595C4E','#B0BB8C','#EEFFB6','#ACB78E','#8FA359','#858F6C','#86916E','#374912','#AEB0AA','#79904C','#627739','#747F60','#9FA98E','#E7F9CB','#E1F9BE','#495637','#8A9978','#4E5F39','#86996E','#C3CEB7','#78866B','#CEDDC1','#B5CEA2','#536149','#D6E6CC','#D6E6CC','#809873','#4F564C','#4F6C45','#555F52','#4F7942','#5F705B','#D0DFCD','#2B3929','#F0F7EF','#AAD5A4','#99BC95','#B6D4B4','#869E86','#618661','#006700','#E9EEE9','#739E73','#005B06','#EDF7EE','#D0E0D2','#809784','#ABCEB1','#C0E0C8','#3A5241','#435549','#E6ECE8','#E3EAE6','#3B604C','#00602F','#92B7A5','#2F5B49','#318061','#30745B','#316955','#00A275','#C2D1CE','#80A7A0','#00A082','#C2D1CF','#5C6E6C','#607473','#EDF7F7','#1E8285','#D5E7E8','#AADEE1','#188086','#107F87','#566364','#007B86','#66949A','#CAE2E5','#18656F','#004F61','#0C5B6C','#668E98','#BBD0DA','#91B4C5','#AFC3CD','#738A99','#3A5467','#476174','#244967','#556C80','#667A8C','#516D87','#1E4263','#7C8791','#849CB6','#738CAA','#1E3A5F','#1E3655','#9EB0CE','#B6BAC2','#67738D','#BEC1CD','#555559','#616180','#000049','#000031','#F8F8FC','#938BA4','#47375D','#F7F6F8','#3D0067','#514C53','#9566A2','#7F5482','#A279A4','#6D1261','#A06492','#925582','#945B80','#CE94BA','#ECCFE1','#A20058','#A6005B','#BC0061','#BB0061','#F3CEE1','#B3005B','#AB165F','#8A184D','#AA185B','#F3DAE4','#DB3779','#E71261','#E74F86','#FFD6E5','#BE9BA7','#D0396A','#DB1855','#F798B6','#9C294A','#D62B5B','#DE3969','#BC1641','#E7547A','#D52756','#9C7D85','#DB244F','#A1354F','#C22443','#FFBDCA','#8B6D73','#DC3D5B','#FF738C','#F13154','#BC4055','#FED4DB','#FFCFD6','#CB4E61','#ED455A','#F36C7B','#C94F5B','#F3959D','#A8444C','#FFCCD0','#735B5D','#D15D67','#B44B52','#FD868D','#FFD5D8','#C3767B','#FF8087','#C8242B','#FFEAEB','#F95A61','#E96D73','#E6656B','#FF6D73','#FF555B','#A35A5B','#FFD3D4','#B84B4D'];
var body=document.getElementsByTagName('body')[0];
function hexToRgb(hex) {
hex = hex.substring(1, hex.length);
var r = parseInt((hex).substring(0, 2), 16);
var g = parseInt((hex).substring(2, 4), 16);
var b = parseInt((hex).substring(4, 6), 16);
return r + "," + g + "," + b;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
var rgbArr=new Array();
var div=document.createElement('div');
div.id='Original';
body.appendChild(div);
for(var color in coloursArray){
color=coloursArray[color];
displayColor(color,div);
rgbArr.push(hexToRgb(color));
}
var hslArr=new Array();
for(var i=0;i<rgbArr.length;i++){
//Transforming rgb to hsl
//`hslArr[i][1]` (`i`) is a reference to the rgb color, in order to retrieve it later
hslArr[i]=[rgbToHsl(rgbArr[i]),i];
}
var sortedHslArr=new Array();
//Sorting `hslArr` into `sortedHslArr`
outerloop:
for(var i=0;i<hslArr.length;i++){
for(var j=0;j<sortedHslArr.length;j++){
if(sortedHslArr[j][0][0]>hslArr[i][0][0]){
sortedHslArr.splice(j,0,hslArr[i]);
continue outerloop;
}
}
sortedHslArr.push(hslArr[i]);
}
var sortedRgbArr=new Array();
//Retrieving rgb colors
for(var i=0;i<sortedHslArr.length;i++){
sortedRgbArr[i]=rgbArr[sortedHslArr[i][1]];
}
function displayColor(color,parent){
var div;
div=document.createElement('div');
div.style.backgroundColor=color;
div.style.width='22px';
div.style.height='22px';
div.style.cssFloat='left';
div.style.position='relative';
parent.appendChild(div);
}
var finalArray=new Array();
var div=document.createElement('div');
div.id='Sorted';
body.appendChild(div);
for(var color in sortedRgbArr){
color=sortedRgbArr[color];
color=color.split(',');
color=rgbToHex(parseInt(color[0]),parseInt(color[1]),parseInt(color[2]));
displayColor(color,div);
finalArray.push(color);
}
function rgbToHsl(c){
var r = c[0]/255, g = c[1]/255, b = c[2]/255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min)/2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d/(2 - max - min) : d/(max + min);
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 new Array(h * 360, s * 100, l * 100);
}
var sorted = coloursArray.sort(function(colorA, colorB) {
return pusher.color(colorA).hue() - pusher.color(colorB).hue();
});
// console.log(sorted);
var div=document.createElement('div');
div.id='Pusher';
body.appendChild(div);
for(var color in sorted){
color=sorted[color];
displayColor(color,div);
}
var div=document.createElement('div');
body.appendChild(div);
var str='';
for(var color in sorted){
color=sorted[color];
str+='\''+color+'\',';
}
div.innerHTML=str;
function sorthueColors (colors) {
for (var c = 0; c < colors.length; c++) {
/* Get the hex value without hash symbol. */
var hex = colors[c].substring(1);
//var hex = colors[c].hex.substring(1);
/* Get the RGB values to calculate the Hue. */
var r = parseInt(hex.substring(0,2),16)/255;
var g = parseInt(hex.substring(2,4),16)/255;
var b = parseInt(hex.substring(4,6),16)/255;
/* Getting the Max and Min values for Chroma. */
var max = Math.max.apply(Math, [r,g,b]);
var min = Math.min.apply(Math, [r,g,b]);
/* Variables for HSV value of hex color. */
var chr = max-min;
var hue = 0;
var val = max;
var sat = 0;
if (val > 0) {
/* Calculate Saturation only if Value isn't 0. */
sat = chr/val;
if (sat > 0) {
if (r == max) {
hue = 60*(((g-min)-(b-min))/chr);
if (hue < 0) {hue += 360;}
} else if (g == max) {
hue = 120+60*(((b-min)-(r-min))/chr);
} else if (b == max) {
hue = 240+60*(((r-min)-(g-min))/chr);
}
}
}
/* Modifies existing objects by adding HSV values. */
colors[c].hue = hue;
colors[c].sat = sat;
colors[c].val = val;
}
/* Sort by Hue. */
return colors.sort(function(a,b){return a.hue - b.hue;});
}
问题是,排序需要一个明确的秩序 - 换句话说,你需要将所有的颜色映射到一个维度。虽然有一些方法可以在两个维度上显示色彩空间,但我不知道任何能够在一个维度上显示色彩空间的方法,并且仍然对人眼有意义。
但是,如果您不坚持使用某种通用排序,而只是希望以一种看起来不错的方式放置给定的颜色列表,那么某些聚类方法可能会产生更好的结果。我尝试了一种天真的方法,这里的想法是将相似的颜色放入同一个群集,并合并这些群集,直到只有一个。这里是我有代码:
function colorDistance(color1, color2) {
// This is actually the square of the distance but
// this doesn't matter for sorting.
var result = 0;
for (var i = 0; i < color1.length; i++)
result += (color1[i] - color2[i]) * (color1[i] - color2[i]);
return result;
}
function sortColors(colors) {
// Calculate distance between each color
var distances = [];
for (var i = 0; i < colors.length; i++) {
distances[i] = [];
for (var j = 0; j < i; j++)
distances.push([colors[i], colors[j], colorDistance(colors[i], colors[j])]);
}
distances.sort(function(a, b) {
return a[2] - b[2];
});
// Put each color into separate cluster initially
var colorToCluster = {};
for (var i = 0; i < colors.length; i++)
colorToCluster[colors[i]] = [colors[i]];
// Merge clusters, starting with lowest distances
var lastCluster;
for (var i = 0; i < distances.length; i++) {
var color1 = distances[i][0];
var color2 = distances[i][1];
var cluster1 = colorToCluster[color1];
var cluster2 = colorToCluster[color2];
if (!cluster1 || !cluster2 || cluster1 == cluster2)
continue;
// Make sure color1 is at the end of its cluster and
// color2 at the beginning.
if (color1 != cluster1[cluster1.length - 1])
cluster1.reverse();
if (color2 != cluster2[0])
cluster2.reverse();
// Merge cluster2 into cluster1
cluster1.push.apply(cluster1, cluster2);
delete colorToCluster[color1];
delete colorToCluster[color2];
colorToCluster[cluster1[0]] = cluster1;
colorToCluster[cluster1[cluster1.length - 1]] = cluster1;
lastCluster = cluster1;
}
// By now all colors should be in one cluster
return lastCluster;
}
的colorDistance()
功能的工作原理与被表达为具有三个元素阵列RGB颜色。肯定有much better approaches to do this,他们可能会产生看起来更好的结果。还请注意,这不是最有效的算法,因为它计算每种颜色之间的距离(O(n )),所以如果您有很多颜色可能需要优化它。
使用颜色的色调通常是一种令人愉快的方式来映射一维尺度上的颜色。您可以使用此处的答案将rgb颜色转换为hsv:RGB to HSV color in javascript?
问题中的代码似乎是一种非常复杂的方式,正是你所提出的。结果看起来不对,但我的猜测是在那里实现的自定义排序算法有错误。 – 2014-09-24 13:22:26
假设没有最佳解决方案。这是我如何找到我最喜欢的东西。
首先我会用颜色距离函数:
var balance = [10, 0, 0.01];
function colorDistance(color1, color2) {
var result = 0;
color1 = rgbToHsl(color1[0], color1[1], color1[2]);
color2 = rgbToHsl(color2[0], color2[1], color2[2]);
for (var i = 0; i < color1.length; i++)
result += (color1[i] - color2[i]) * (color1[i] - color2[i]) * balance[i];
return result;
}
我会用平衡功能:
-
色调距离
var balance = [1, 0, 0];
-
饱和度距离
var balance = [0, 1, 0];
-
lightness distance
var balance = [0,0,1];
之后,你可以试验并选择你喜欢的东西。请注意,值不会被标准化为在0到1之间出现,但除此之外它应该可以正常工作。你也可以使用另一个距离函数,这个函数只是最简单和最知名的一个,可以得到不错的结果。
这种方法并没有给你最好的解决方案,但描述了一种方法来摆弄它,并获得结果你在哪里寻找。玩的开心。
谢谢你的努力,但是,虽然它似乎对齐基于亮度的颜色值,色调都在这个地方,并会导致很多悲伤。我认为如果我能够找出何时从一种色调跳转到另一种色调之间的联系,HSL或HSV就是这种方式... – Kayote 2014-09-19 15:40:09
@Kayote:随意实现符合您的标准的'colorDistance()'函数更好 - 你没有在问题中指定这些标准,而且我的头脑阅读技能有点生疏。无论您选择哪种比较函数,算法的其余部分都不需要任何更改。 – 2014-09-22 09:41:31
想要为演示提及+1。 – Margus 2014-09-25 18:56:14