Ta odpowiedź stała się własną bestią. Wiele nowych wersji robiło się głupio długo. Ogromne podziękowania dla wszystkich bardzo wielu autorów tej odpowiedzi. Ale dla uproszczenia dla mas. Zarchiwizowałem wszystkie wersje / historię ewolucji tej odpowiedzi na moim githubie . I zaczął to od nowa w StackOverflow tutaj z najnowszą wersją. Specjalne podziękowania należą się Mike'owi „Pomax” Kamermansowi za tę wersję. Dał mi nową matematykę.
Ta funkcja ( pSBC
) przyjmuje kolor WWW HEX lub RGB. pSBC
może przyciemnić go ciemniej lub jaśniej lub zmieszać go z drugim kolorem, a także przesłać go od razu, ale konwertować z Hex na RGB (Hex2RGB) lub RGB na Hex (RGB2Hex). Wszystko to bez Twojej wiedzy na temat używanego formatu kolorów.
Działa to naprawdę szybko, prawdopodobnie najszybciej, zwłaszcza biorąc pod uwagę jego wiele funkcji. Trwało to długo. Zobacz całą historię na moim githubie . Jeśli chcesz mieć absolutnie najmniejszy i najszybszy możliwy sposób cieniowania lub łączenia, zapoznaj się z poniższymi funkcjami Micro i użyj jednego z 2-liniowych demonów prędkości. Świetnie nadają się do intensywnych animacji, ale ta wersja tutaj jest wystarczająco szybka dla większości animacji.
Ta funkcja wykorzystuje mieszanie logów lub liniowe. Jednak NIE konwertuje on na HSL, aby właściwie rozjaśnić lub przyciemnić kolor. Dlatego wyniki tej funkcji będą się różnić od znacznie większych i wolniejszych funkcji korzystających z HSL.
jsFiddle z pSBC
github> Wiki pSBC
Funkcje:
- Automatycznie wykrywa i akceptuje standardowe kolory Hex w postaci łańcuchów. Na przykład:
"#AA6622"
lub "#bb551144"
.
- Automatycznie wykrywa i akceptuje standardowe kolory RGB w postaci łańcuchów. Na przykład:
"rgb(123,45,76)"
lub "rgba(45,15,74,0.45)"
.
- Odcienia kolory na biały lub czarny w procentach.
- Łączy kolory razem w procentach.
- Czy konwersja Hex2RGB i RGB2Hex w tym samym czasie lub solo.
- Akceptuje 3-cyfrowe (lub 4-cyfrowe w / alfa) kolorowe kody HEX, w formie #RGB (lub #RGBA). Rozszerzy je. Na przykład:
"#C41"
staje się "#CC4411"
.
- Akceptuje i (liniowy) łączy kanały alfa. Jeśli
c0
kolor (z) lub c1
(do) ma kanał alfa, wówczas zwracany kolor będzie miał kanał alfa. Jeśli oba kolory mają kanał alfa, wówczas zwracany kolor będzie liniowym połączeniem dwóch kanałów alfa z wykorzystaniem podanego procentu (tak jakby to był normalny kanał koloru). Jeśli tylko jeden z dwóch kolorów ma kanał alfa, ta alfa zostanie po prostu przekazana do zwracanego koloru. Umożliwia to mieszanie / cieniowanie przezroczystego koloru przy zachowaniu poziomu przezroczystości. Lub, jeśli poziomy przezroczystości również powinny się mieszać, upewnij się, że oba kolory mają alfy. Podczas cieniowania przejdzie kanał alfa prosto przez. Jeśli chcesz podstawowego cieniowania, które również zacienia kanał alfa, użyj rgb(0,0,0,1)
lub rgb(255,255,255,1)
jako własnegoc1
(do) kolor (lub ich odpowiedniki szesnastkowe). W przypadku kolorów RGB kanał alfa zwracanego koloru zostanie zaokrąglony do 3 miejsc po przecinku.
- Konwersje RGB2Hex i Hex2RGB są niejawne podczas korzystania z mieszania. Niezależnie od
c0
(z) koloru; zwracany kolor będzie zawsze w formacie koloru c1
(do) koloru, jeśli taki istnieje. Jeśli nie ma c1
koloru (do), wprowadź go 'c'
jako c1
kolor, a będzie cieniował i przekształcał niezależnie od c0
koloru. Jeśli pożądana jest tylko konwersja, należy również podać 0
wartość procentową ( p
). Jeśli c1
kolor zostanie pominięty lub nie string
zostanie przekazany żaden element , nie zostanie on przekonwertowany.
- Druga funkcja jest również dodawana do globalnej.
pSBCr
można przekazać kolor Hex lub RGB i zwraca obiekt zawierający tę informację o kolorze. Ma postać: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Gdzie .r
, .g
i .b
mają zakres od 0 do 255. A gdy nie ma alfa: .a
wynosi -1. W przeciwnym razie: .a
ma zakres od 0,000 do 1,000.
- W przypadku wyjścia RGB, sygnał wyjściowy
rgba()
kończy się, rgb()
gdy kolor z kanałem alfa został przekazany do c0
(od) i / lub c1
(do).
- Drobne sprawdzanie błędów zostało dodane. To nie jest idealne. Nadal może powodować awarie lub tworzyć szczypce. Ale to coś złapie. Zasadniczo, jeśli struktura jest w jakiś sposób niepoprawna lub jeśli wartość procentowa nie jest liczbą lub jest poza zakresem, zostanie ona zwrócona
null
. Przykład: pSBC(0.5,"salt") == null
gdzie, jak myśli, #salt
jest prawidłowy kolor. Usuń cztery linie, które kończą się, return null;
aby usunąć tę funkcję i uczynić ją szybszą i mniejszą.
- Używa mieszania dziennika. Przekaż
true
dla l
(czwarty parametr), aby użyć mieszania liniowego.
Kod:
// Version 4.0
const pSBC=(p,c0,c1,l)=>{
let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
if(!this.pSBCr)this.pSBCr=(d)=>{
let n=d.length,x={};
if(n>9){
[r,g,b,a]=d=d.split(","),n=d.length;
if(n<3||n>4)return null;
x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
}else{
if(n==8||n==6||n<4)return null;
if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
d=i(d.slice(1),16);
if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
}return x};
h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
if(!f||!t)return null;
if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
}
Stosowanie:
// Setup:
let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";
// Tests:
/*** Log Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(166,171,225)
pSBC ( -0.4, color5 ); // #F3A + [40% Darker] => #c62884
pSBC ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(225,171,166,0.98631)
// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #a6abe1ac
// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)
// Blending
pSBC ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(142,60,142,0.83)
pSBC ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(168,60,111,0.67423)
pSBC ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(134,191,208)
pSBC ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #86bfd0
/*** Linear Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1, false, true ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
pSBC ( -0.4, color5, false, true ); // #F3A + [40% Darker] => #991f66
pSBC ( 0.42, color8, false, true ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)
// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c", true ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac
// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c", true ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)
// Blending
pSBC ( -0.5, color2, color8, true ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.83)
pSBC ( 0.7, color2, color7, true ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
pSBC ( 0.25, color3, color7, true ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
pSBC ( 0.75, color7, color3, true ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9
/*** Other Stuff ***/
// Error Checking
pSBC ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] => null (Invalid Input Color)
pSBC ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null (Invalid Percentage Range)
pSBC ( 0.42, {} ); // [object Object] + [42% Lighter] => null (Strings Only for Color)
pSBC ( "42", color1 ); // rgb(20,60,200) + ["42"] => null (Numbers Only for Percentage)
pSBC ( 0.42, "salt" ); // salt + [42% Lighter] => null (A Little Salt is No Good...)
// Error Check Fails (Some Errors are not Caught)
pSBC ( 0.42, "#salt" ); // #salt + [42% Lighter] => #a5a5a500 (...and a Pound of Salt is Jibberish)
// Ripping
pSBCr ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'r':85,'g':103,'b':218,'a':0.941}
Poniższy obrazek pomoże pokazać różnicę w dwóch metodach mieszania:
Funkcje mikro
Jeśli naprawdę chcesz prędkości i rozmiaru, będziesz musiał użyć RGB, a nie HEX. RGB jest prostszy i prostszy, HEX pisze zbyt wolno i występuje w zbyt wielu odmianach dla prostego dwuliniowego (IE. Może to być 3, 4, 6 lub 8 cyfrowy kod HEX). Będziesz także musiał poświęcić niektóre funkcje, bez sprawdzania błędów, bez HEX2RGB ani RGB2HEX. Musisz także wybrać konkretną funkcję (na podstawie jej nazwy poniżej) dla matematyki mieszania kolorów, a jeśli chcesz cieniować lub mieszać. Te funkcje obsługują kanały alfa. A gdy oba kolory wejściowe mają litery, będzie je liniowo mieszać. Jeśli tylko jeden z dwóch kolorów ma alfa, przekaże go bezpośrednio do uzyskanego koloru. Poniżej znajdują się dwie funkcje liniowe, które są niezwykle szybkie i małe:
const RGB_Linear_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+j;
}
const RGB_Linear_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:255*p,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")");
}
const RGB_Log_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+j;
}
const RGB_Log_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:p*255**2,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")");
}
Chcesz więcej informacji? Przeczytaj pełny tekst na github .
PT
(Ps Jeśli ktoś ma matematykę do innej metody mieszania, proszę się podzielić.)