คำตอบนี้กลายเป็นสัตว์ร้ายของตัวเอง เวอร์ชั่นใหม่หลายรุ่นมันเริ่มจะงี่เง่า ขอบคุณมากสำหรับผู้มีส่วนร่วมมากมายทุกคนในคำตอบนี้ แต่เพื่อให้ง่ายสำหรับฝูง ผมเก็บไว้ทุกรุ่น / ประวัติศาสตร์ของวิวัฒนาการของคำตอบนี้ไปฉันGitHub และเริ่มต้นใหม่ด้วย Clean บน StackOverflow ที่นี่ด้วยเวอร์ชั่นใหม่ล่าสุด ขอขอบคุณเป็นพิเศษสำหรับMike 'Pomax' Kamermansสำหรับรุ่นนี้ เขาให้คณิตศาสตร์ใหม่แก่ฉัน
ฟังก์ชั่นนี้ ( pSBC
) จะใช้สีของเว็บ HEX หรือ RGB pSBC
สามารถแรเงาได้เข้มขึ้นหรือจางลงหรือผสมผสานกับสีที่สองและยังสามารถส่งผ่านได้อย่างถูกต้อง แต่แปลงจาก Hex เป็น RGB (Hex2RGB) หรือ RGB เป็น Hex (RGB2Hex) ทั้งหมดโดยที่คุณไม่รู้ด้วยซ้ำว่าคุณกำลังใช้รูปแบบสีอะไร
สิ่งนี้ทำงานได้เร็วมากอาจจะเร็วที่สุดโดยเฉพาะเมื่อพิจารณาถึงคุณสมบัติมากมาย มันเป็นเวลานานในการสร้าง ดูเรื่องราวทั้งหมดของฉันGitHub หากคุณต้องการวิธีที่เล็กที่สุดและเร็วที่สุดในการแรเงาหรือการผสมผสานให้ดูฟังก์ชั่นไมโครด้านล่างและใช้ปีศาจความเร็ว 2 ซับอย่างใดอย่างหนึ่ง มันยอดเยี่ยมสำหรับแอนิเมชั่นที่รุนแรง แต่เวอร์ชั่นนี้เร็วพอสำหรับแอนิเมชั่นส่วนใหญ่
ฟังก์ชั่นนี้ใช้ Log Blending หรือ Linear Blending อย่างไรก็ตามจะไม่แปลงเป็น HSL เพื่อให้สีจางลงหรือเข้มขึ้นอย่างเหมาะสม ดังนั้นผลลัพธ์จากฟังก์ชั่นนี้จะแตกต่างจากฟังก์ชั่นที่ใหญ่กว่าและช้ากว่ามากที่ใช้ HSL
jsFiddle กับ pSBC
github> pSBC Wiki
คุณสมบัติ:
- ตรวจจับและยอมรับสี Hex มาตรฐานโดยอัตโนมัติในรูปแบบของสตริง ตัวอย่างเช่น: หรือ
"#AA6622"
"#bb551144"
- ตรวจจับและยอมรับสี RGB มาตรฐานโดยอัตโนมัติในรูปแบบของสตริง ตัวอย่างเช่น: หรือ
"rgb(123,45,76)"
"rgba(45,15,74,0.45)"
- เฉดสีเป็นสีขาวหรือสีดำตามเปอร์เซ็นต์
- ผสมสีเข้าด้วยกันเป็นเปอร์เซ็นต์
- ทำการแปลง Hex2RGB และ RGB2Hex ในเวลาเดียวกันหรือเดี่ยว
- ยอมรับรหัสสี HEX 3 หลัก (หรือ 4 หลัก w / alpha) ในรูปแบบ #RGB (หรือ #RGBA) มันจะขยายพวกเขา ตัวอย่างเช่น:
"#C41"
กลายเป็น"#CC4411"
กลายเป็น
- ยอมรับและ (เชิงเส้น) ผสมช่องอัลฟา หาก
c0
สี (จาก) หรือสีc1
(ถึง) มีช่องอัลฟาแล้วสีที่ส่งคืนจะมีช่องอัลฟา หากสีทั้งสองมีช่องอัลฟ่าสีที่ส่งคืนจะเป็นการผสมผสานเชิงเส้นของช่องอัลฟาสองช่องทางโดยใช้เปอร์เซ็นต์ที่กำหนด (ราวกับว่าเป็นช่องสีปกติ) หากหนึ่งในสองสีเท่านั้นที่มีช่องอัลฟาอัลฟ่านี้จะถูกส่งผ่านไปยังสีที่ส่งคืน สิ่งนี้ช่วยให้หนึ่งในการผสมผสาน / แรเงาสีโปร่งใสในขณะที่รักษาระดับความโปร่งใส หรือถ้าระดับความโปร่งใสควรผสมผสานเช่นกันตรวจสอบให้แน่ใจว่าทั้งสองสีมีอัลฟ่า เมื่อแรเงามันจะผ่านช่องอัลฟาผ่านตรง หากคุณต้องการการแรเงาขั้นพื้นฐานที่แรเงาช่องอัลฟาก็ให้ใช้rgb(0,0,0,1)
หรือrgb(255,255,255,1)
เป็นของคุณc1
สี (ถึง) สี (หรือเลขฐานสิบหกเทียบเท่า) สำหรับสี 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
มีช่วง 0 ถึง 255 และเมื่อไม่มีอัลฟา: .a
-1 มิฉะนั้น: .a
มีช่วง 0.000 ถึง 1.000
- สำหรับการส่งออก RGB มันจะออกผลลัพธ์
rgba()
มากกว่าrgb()
เมื่อสีที่มีช่องอัลฟาที่ถูกส่งผ่านเข้าc0
(จาก) และ / หรือc1
(เพื่อ)
- เพิ่มการตรวจสอบข้อผิดพลาดเล็กน้อยแล้ว มันไม่สมบูรณ์แบบ มันยังสามารถพังหรือสร้างการพูดปด แต่มันจะจับบางสิ่ง
null
โดยทั่วไปถ้าโครงสร้างที่ไม่ถูกต้องในบางวิธีหรือถ้าเปอร์เซ็นต์ไม่ได้เป็นจำนวนหรือออกจากขอบเขตก็จะกลับ ตัวอย่าง: pSBC(0.5,"salt") == null
ที่ซึ่งคิดว่า#salt
เป็นสีที่ถูกต้อง ลบสี่บรรทัดที่ลงท้ายด้วยreturn null;
เพื่อลบคุณลักษณะนี้และทำให้เร็วขึ้นและเล็กลง
- ใช้ Log Blending ส่งผ่าน
true
สำหรับl
(พารามิเตอร์ที่ 4) เพื่อใช้การผสมเชิงเส้น
รหัส:
// 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}
ภาพด้านล่างจะช่วยแสดงความแตกต่างในวิธีการผสมสองวิธี:
ฟังก์ชั่นไมโคร
ถ้าคุณต้องการความเร็วและขนาดจริง ๆ คุณจะต้องใช้ RGB ไม่ใช่ HEX RGB นั้นตรงไปตรงมาและเรียบง่ายกว่า HEX เขียนช้าเกินไปและมีหลายรสเกินไปสำหรับสองซับง่ายๆ (IE ซึ่งอาจเป็นรหัส HEX 3, 4, 6 หรือ 8 หลัก) คุณจะต้องเสียสละคุณสมบัติบางอย่างไม่มีการตรวจสอบข้อผิดพลาดไม่มี HEX2RGB หรือ RGB2HEX เช่นกันคุณจะต้องเลือกฟังก์ชั่นเฉพาะ (ตามชื่อฟังก์ชั่นด้านล่าง) สำหรับคณิตศาสตร์การผสมสีและถ้าคุณต้องการแรเงาหรือการผสม ฟังก์ชั่นเหล่านี้รองรับช่องอัลฟ่า และเมื่อสีอินพุตทั้งสองมีอัลฟาก็จะเป็น Linear Blend หากมีเพียงหนึ่งในสองสีเท่านั้นที่มีอัลฟามันจะผ่านไปยังสีที่เกิดขึ้น ด้านล่างนี้เป็นฟังก์ชั่นซับสองด้านที่รวดเร็วและเล็กอย่างไม่น่าเชื่อ:
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
(สดุดีถ้าใครมีคณิตศาสตร์สำหรับวิธีการผสมแบบอื่นกรุณาแชร์)