reactjs 基于百分比值在两种颜色之间进行插值

qgelzfjb  于 2023-04-29  发布在  React
关注(0)|答案(3)|浏览(106)

我目前正在开发一个JS动画库,需要根据0 - 1之间的进度值计算两个值之间的颜色。
例如,函数可能看起来像下面的内容。这将以HEX格式输入两种颜色。

  • colourA =初始颜色
  • colourB =最终颜色
  • 进度= 0。5人(50%)
const interpolateColour = (colourA, colourB, progress) => { return polColour }

目标是返回颜色0。两种颜色之间的5个进度或50%。我知道十六进制颜色很可能需要转换成RGBA的HSV来实现这种效果,虽然不确定哪种是最好的方法。
编辑:我想出来了。..

const is = {
    hex: a => /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a),
    rgb: a => /^rgb/.test(a),
    hsl: a => /^hsl/.test(a),
    col: a => (is.hex(a) || is.rgb(a) || is.hsl(a)),
}

const convertToRgba = (colour) => {
    return is.hex(colour) ? hexToRgba(colour)
        : is.rgb(colour) ? rbgToRgba(colour)
            : is.hsl(colour) ? hslToRgba(colour)
                : colour
}

const hexToRgba = (colour, alpha = 1) => {
    const [r, g, b] = colour.match(/\w\w/g).map(x => parseInt(x, 16))
    return `rgba(${r},${g},${b},${alpha})`
};

const rbgToRgba = (colour, alpha = 1) => {
    const [r, g, b] = colour.replace(/[^\d,]/g, '').split(',')
    return `rgba(${r},${g},${b},${alpha})`
}

const deconstructRgba = (rgba) => {
    return rgba.replace(/[^\d,]/g, '').split(',').map(x => parseInt(x))
}

const formatRbga = (colour) => {
    return `rgba(${colour.r},${colour.g},${colour.b},${colour.a})`
}

const interpolateColour = (colourA, colourB, progress) => {
    const [r1, g1, b1, a1] = deconstructRgba(convertToRgba(colourA))
    const [r2, g2, b2, a2] = deconstructRgba(convertToRgba(colourB))
    return formatRbga({
        r: Math.round((r1 + r2) * progress),
        g: Math.round((g1 + g2) * progress),
        b: Math.round((b1 + b2) * progress),
        a: Math.round((a1 + a2) * progress)
    })
}

export {
    interpolateColour,
    convertToRgba,
    hexToRgba,
    rbgToRgba,
    deconstructRgba
}
vm0i2vca

vm0i2vca1#

R、G和B值的简单插值就足够了。

// extract numeric r, g, b values from `rgb(nn, nn, nn)` string
function getRgb(color) {
  let [r, g, b] = color.replace('rgb(', '')
    .replace(')', '')
    .split(',')
    .map(str => Number(str));;
  return {
    r,
    g,
    b
  }
}

function colorInterpolate(colorA, colorB, intval) {
  const rgbA = getRgb(colorA),
    rgbB = getRgb(colorB);
  const colorVal = (prop) =>
    Math.round(rgbA[prop] * (1 - intval) + rgbB[prop] * intval);
  return {
    r: colorVal('r'),
    g: colorVal('g'),
    b: colorVal('b'),
  }
}

function doit(progression) {
  const div1 = document.getElementById('color1');
  const color1 = div1.style.backgroundColor;
  const div2 = document.getElementById('color2');
  const color2 = div2.style.backgroundColor;

  const rgbNew = colorInterpolate(
    color1,
    color2, progression
  );

  const divResult = document.getElementById('result');
  divResult.style.backgroundColor =
    `rgb( ${rgbNew.r}, ${rgbNew.g}, ${rgbNew.b})`;
}

document.querySelector('button').onclick = () => {
  const intval = Number(document.querySelector('input').value);
  doit(intval);
};
#color1,
#color2,
#result {
  width: 200px;
  height: 40px;
  margin: 12px;
  padding: 0.2rem 0.5rem;
}
<h4>Interpolate Between Two Colors</h4>
<label for="number">Interpolate by:</label>
<input id="number" type="number" value="0.5" min="0" max="1" step="0.05" />
<button>Interpolate</button>

<div style="display: flex">
  <div id="color1" style="background-color: #922B21">color1</div>
  <div id="result" style="background-color: #e0e0e0">interpolated</div>
  <div id="color2" style="background-color: #85C1E9">color2</div>
</div>
0s7z1bwu

0s7z1bwu2#

使用十六进制颜色:

function convert(col1, col2, p) {
  const rgb1 = parseInt(col1, 16);
  const rgb2 = parseInt(col2, 16);

  const [r1, g1, b1] = toArray(rgb1);
  const [r2, g2, b2] = toArray(rgb2);

  const q = 1-p;
  const rr = Math.round(r1 * p + r2 * q);
  const rg = Math.round(g1 * p + g2 * q);
  const rb = Math.round(b1 * p + b2 * q);

  return  Number((rr << 16) + (rg << 8) + rb).toString(16);
}

function toArray(rgb) {
  const r = rgb >> 16;
  const g = (rgb >> 8) % 256;
  const b = rgb % 256;

  return [r, g, b];
}
qvk1mo1f

qvk1mo1f3#

对于那些寻求简单、独立的解决方案的人:

function interpolate(color1, color2, percent) {
  // Convert the hex colors to RGB values
  const r1 = parseInt(color1.substring(1, 3), 16);
  const g1 = parseInt(color1.substring(3, 5), 16);
  const b1 = parseInt(color1.substring(5, 7), 16);

  const r2 = parseInt(color2.substring(1, 3), 16);
  const g2 = parseInt(color2.substring(3, 5), 16);
  const b2 = parseInt(color2.substring(5, 7), 16);

  // Interpolate the RGB values
  const r = Math.round(r1 + (r2 - r1) * percent);
  const g = Math.round(g1 + (g2 - g1) * percent);
  const b = Math.round(b1 + (b2 - b1) * percent);

  // Convert the interpolated RGB values back to a hex color
  return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

使用方法:

interpolate('#c200ff', '#00ffff', 0.8);  // #27ccff
interpolate('#000000', '#ffffff', 0.5);  // #808080

相关问题