计算具有2种颜色和百分比/位置的颜色HEX值

26

在渐变过程中是否可能计算出中间颜色?

var color1 = 'FF0000';
var color2 = '00FF00';

// 50% between the two colors, should return '808000'
var middle = gradient(color1, color2, 0.5); 

我只有两个十六进制字符串,我希望得到一个字符串。


这是一个简单的线性代数问题(你已经知道了,因为你已经得到了你的示例颜色的答案)。你目前编写了什么代码? - Pointy
4个回答

50

这应该可以工作:

它基本上涉及将它们转换为十进制,找到一半,将结果转换回十六进制,然后连接它们。

var color1 = 'FF0000';
var color2 = '00FF00';
var ratio = 0.5;
var hex = function(x) {
    x = x.toString(16);
    return (x.length == 1) ? '0' + x : x;
};

var r = Math.ceil(parseInt(color1.substring(0,2), 16) * ratio + parseInt(color2.substring(0,2), 16) * (1-ratio));
var g = Math.ceil(parseInt(color1.substring(2,4), 16) * ratio + parseInt(color2.substring(2,4), 16) * (1-ratio));
var b = Math.ceil(parseInt(color1.substring(4,6), 16) * ratio + parseInt(color2.substring(4,6), 16) * (1-ratio));

var middle = hex(r) + hex(g) + hex(b);

请注意第三个参数 -> 0.5,它是 color1color2 的比率。 - Kalamar Obliwy
1
这确实很接近,但如果比率为0,则颜色应为color1而不是黑色。此外,r.toString等不会填充零,对吗? - Kalamar Obliwy
var r1 = parseInt(color1.substring(0,1), 16), r2 = parseInt(color2.substring(0,1), 16); var r = Math.ceil(r1 + (r2-r1)*ratio); 变量r1等于将color1的第一个字符转换为16进制后的整数, 变量r2等于将color2的第一个字符转换为16进制后的整数。变量r等于r1加上(r2减去r1)乘以比率后向上取整。 - Kalamar Obliwy
1
子字符串错误,参数为:(0、2)-(2、4)-(4、6)。 - Emanuele Pavanello
1
hex函数的返回值应该是:return (x.length == 1) ? x + x : x; - tolmark
显示剩余4条评论

7

使用ES6语法的推导式版本:

function interpolateColor(c0, c1, f){
    c0 = c0.match(/.{1,2}/g).map((oct)=>parseInt(oct, 16) * (1-f))
    c1 = c1.match(/.{1,2}/g).map((oct)=>parseInt(oct, 16) * f)
    let ci = [0,1,2].map(i => Math.min(Math.round(c0[i]+c1[i]), 255))
    return ci.reduce((a,v) => ((a << 8) + v), 0).toString(16).padStart(6, "0")
}

如接受的答案中所述,c0c1是颜色代码(没有前导的#),f是两个值之间的“进度”。 (在f = 0时,这将返回c0,在f = 1时,这将返回c1)。

  • 前两行将颜色代码转换为整数数组
  • 第三行:
    • “拉链”两个整数数组
    • 对应值相加
    • 将和四舍五入并夹紧到0-255
  • 第四行:
    • 将整数数组转换为单个整数(reduce和位移)
    • 将整数转换为其十六进制字符串形式
    • 确保结果字符串长度为6个字符并返回它

4

我无法对上面的答案进行评论,所以我在这里写下来:

我发现在JavaScript的substring方法中,to参数索引不包括在返回的字符串中。也就是说:

var string = "test";
//index:      0123
alert(string.substring(1,3));

//will alert es and NOT est

编辑:所以正确的应该是:

parseInt(color1.substring(0,2), 16);
parseInt(color1.substring(2,4), 16);

并且

parseInt(color1.substring(4,6), 16);

3
你可以使用这个现成的ES6函数:

您可以使用此准备好的函数(ES6):

const calculateMiddleColor = ({
  color1 = 'FF0000',
  color2 = '00FF00',
  ratio,
}) => {
  const hex = (color) => {
    const colorString = color.toString(16);
    return colorString.length === 1 ? `0${colorString}` : colorString;
  };

  const r = Math.ceil(
    parseInt(color2.substring(0, 2), 16) * ratio
      + parseInt(color1.substring(0, 2), 16) * (1 - ratio),
  );
  const g = Math.ceil(
    parseInt(color2.substring(2, 4), 16) * ratio
      + parseInt(color1.substring(2, 4), 16) * (1 - ratio),
  );
  const b = Math.ceil(
    parseInt(color2.substring(4, 6), 16) * ratio
      + parseInt(color1.substring(4, 6), 16) * (1 - ratio),
  );

  return hex(r) + hex(g) + hex(b);
};
//////////////////////////////////////////////////////////////////////
console.log(calculateMiddleColor({ ratio: 0 / 5 })); // ff0000
console.log(calculateMiddleColor({ ratio: 5 / 5 })); // 00ff00
console.log(calculateMiddleColor({ ratio: 2.5 / 5 })); // 808000
console.log(calculateMiddleColor({ ratio: 4.2 / 5 })); // 29d700

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接