さて、この答えはそれ自身の獣になりました。多くの新しいバージョン、それは長く愚かになっていた。この回答に対する多くの多大な貢献者に感謝します。しかし、大衆にとってそれをシンプルに保つために。この回答の進化のすべてのバージョン/履歴をgithubにアーカイブしました。そしてここで、StackOverflowで最新バージョンを使ってクリーンに始めました。このバージョンについてMike 'Pomax' Kamermansに特に感謝します。彼は私に新しい数学を与えました。
この関数(pSBC
)は、16進数またはRGBのWebカラーを取ります。pSBC
濃くしたり明るくしたり、2番目の色とブレンドしたり、そのまま渡すこともできますが、HexからRGB(Hex2RGB)またはRGBからHex(RGB2Hex)に変換できます。あなたが使用しているカラーフォーマットを知らなくてもすべて。
これは、特に多くの機能を考慮すると、本当に高速で、おそらく最速で実行されます。制作には長い時間がかかりました。私のgithubでストーリー全体をご覧ください。シェーディングまたはブレンドするための絶対的に最小かつ最速の方法が必要な場合は、以下のマイクロ関数を参照し、2ライナー速度のデーモンの1つを使用してください。激しいアニメーションには最適ですが、このバージョンでは、ほとんどのアニメーションに十分対応できます。
この関数は、ログブレンディングまたは線形ブレンディングを使用します。ただし、色を適切に明るくまたは暗くするためにHSLに変換されません。したがって、この関数の結果は、 HSLを使用するはるかに大きくて遅い関数とは異なります。
jSFiddleとpSBC
github> pSBC Wiki
特徴:
- 文字列の形式で標準の16進数の色を自動検出して受け入れます。例:
"#AA6622"
または"#bb551144"
。
- 文字列形式の標準RGBカラーを自動検出して受け入れます。例:
"rgb(123,45,76)"
または"rgba(45,15,74,0.45)"
。
- パーセントで色を白または黒にシェーディングします。
- 色をパーセンテージでブレンドします。
- Hex2RGB変換とRGB2Hex変換を同時に、またはソロで行います。
- #RGB(または#RGBA)の形式で、3桁(またはアルファ付きの4桁)のHEXカラーコードを受け入れます。それらを拡張します。例:に
"#C41"
なり"#CC4411"
ます。
- アルファチャネルを受け入れて(線形)ブレンドします。
c0
(from)色またはc1
(to)色のいずれかにアルファチャネルがある場合、返される色にはアルファチャネルがあります。両方の色にアルファチャネルがある場合、返される色は、与えられたパーセンテージを使用した2つのアルファチャネルの線形ブレンドになります(通常のカラーチャネルと同じように)。2つのカラーのうち1つだけにアルファチャネルがある場合、このアルファは返されたカラーに渡されます。これにより、透明度を維持しながら透明色をブレンド/シェーディングできます。または、透明度レベルもブレンドする必要がある場合は、両方の色にアルファがあることを確認してください。シェーディングすると、アルファチャネルはそのまま通過します。アルファチャネルもシェーディングする基本的なシェーディングが必要な場合は、rgb(0,0,0,1)
またはrgb(255,255,255,1)
を使用してc1
(へ)色(またはそれらの16進数の同等物)。RGBカラーの場合、返されるカラーのアルファチャネルは小数点以下3桁に丸められます。
- ブレンドを使用する場合、RGB2HexおよびHex2RGB変換は暗黙的です。
c0
(からの)色に関係なく; 返される色はc1
、存在する場合、常に(変換先)の色形式になります。c1
(への)色がない場合は'c'
、c1
色として渡して、色をシェーディングして変換しc0
ます。変換のみが必要な場合は0
、パーセント(p
)としても渡します。場合はc1
色が省略されたまたは非がstring
渡され、それは変換しません。
- 二次機能もグローバルに追加されます。
pSBCr
HexまたはRGBカラーを渡すことができ、このカラー情報を含むオブジェクトを返します。その形式は、{r:XXX、g:XXX、b:XXX、a:X.XXX}です。ここで.r
、.g
、および.b
255の範囲0を持っており、何のアルファがない場合:.a
-1。それ以外の場合:.a
範囲は0.000から1.000です。
- RGB出力の場合、アルファチャネルを持つ色が(from)や(to)に渡されたときに出力さ
rgba()
れます。rgb()
c0
c1
- マイナーエラーチェックが追加されました。それは完璧ではありません。それでもクラッシュしたり、ジブリーシュを作成したりできます。しかし、それはいくつかのものをキャッチします。基本的に、構造が何らかの理由で間違っている場合、またはパーセンテージが数値でない場合や範囲外の場合は、が返され
null
ます。例:pSBC(0.5,"salt") == null
、ここで考えられるとおり、#salt
有効な色です。で終わる4行を削除しreturn null;
て、この機能を削除し、より速く、より小さくします。
- ログブレンディングを使用します。(4番目のパラメーター)に渡して
true
、l
線形混合を使用します。
コード:
// 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)
}
使用法:
// 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}
次の図は、2つのブレンド方法の違いを示しています。
マイクロ機能
速度とサイズが本当に必要な場合は、HEXではなくRGBを使用する必要があります。RGBはより単純でシンプルです。HEXは書き込みが遅すぎ、単純な2ライナー(IE。3、4、6、または8桁のHEXコードである可能性があります)にはあまりにも多くの種類があります。また、一部の機能、エラーチェック、HEX2RGBもRGB2HEXも犠牲にする必要があります。同様に、カラーブレンド計算に特定の関数(以下の関数名に基づく)を選択する必要があり、シェーディングまたはブレンドが必要かどうかも確認できます。これらの関数はアルファチャネルをサポートします。そして、両方の入力色にアルファがある場合、それらを線形ブレンドします。2つのカラーのうち1つだけにアルファがある場合、結果のカラーにそのまま渡されます。以下は、信じられないほど高速で小さい2つのライナー関数です。
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:")");
}
詳細が必要ですか?githubで完全な記事を読んでください。
PT
(追記)もし誰かが他のブレンド方法の数学を持っているなら、共有してください。)