【问题标题】:How to create a color picker circle like Phillips Hue如何创建像 Philips Hue 这样的颜色选择器圈
【发布时间】:2021-12-25 16:08:04
【问题描述】:

我正在尝试在 javascript 画布中创建颜色选择器。我想做这样的事情:

我希望当我单击圆圈中的任意位置时,我得到 x、y 坐标(这样我可以使用其他一些元素来标记所选颜色)和颜色。 我希望解决方案不是带有嵌入图像的画布,而是类似于linear-gradient

我已经搜索了互联网,但没有找到任何与我的问题有关的内容。

P.S.:也许 css border-radius 会帮助做一个圆圈。

【问题讨论】:

标签: javascript css html5-canvas


【解决方案1】:

如果您真的不想使用图像,则当前需要手动绘制每个像素。我确信某处有数学函数。

您不能使用渐变来执行此操作的原因是,要获得这样的渐变色轮,您需要堆叠径向渐变和圆锥渐变。圆锥渐变将创建色轮,径向渐变将提供从中心展开的白色叠加层。

您目前无法使用画布执行此操作,因为并非所有浏览器 currently supportcreateConicGradient 函数都在 canvas 上。在这些浏览器中,您只能使用径向渐变(当然还有线性渐变,但这些对此无济于事)。

可以使用堆叠的 CSS 背景渐变,但浏览器目前没有可靠的方法来确定特定 X/Y 坐标处的单个像素的背景颜色,除了在画布内。并且由于 CSS 背景样式不是画布上下文的一部分,因此它不起作用。有一些使用 html2canvas 库的解决方法,但这在不支持画布上的圆锥渐变的浏览器中存在同样的问题。

浏览器 starting to implement EyeDropper API,但这仍然很少见,即使浏览器确实有它,它也是一个不稳定的 API,并不真正适合生产使用。但是,如果它受支持,您可以将其与常规 div 上的堆叠 CSS 背景渐变一起使用,就像这样,不需要画布:

document.addEventListener('DOMContentLoaded', function() {
  document.getElementById('color-wheel').addEventListener('click', function() {
    (new EyeDropper()).open().then(function(result) {
      document.getElementById('color').innerText = result.sRGBHex;
    });
  });
});
#color-wheel {
  width: 150px;
  height: 150px;
  background: radial-gradient(white, transparent 80%),
              conic-gradient(#e43f00, #fae410, #55cc3b, #09adff, #6b0efd, #e70d86, #e43f00);
  border-radius: 50%;
}
<div id="color-wheel"></div>
Color: <span id="color"></span>

但正如我所说,这是不稳定的,并且在可预见的将来肯定不会在所有浏览器中工作。

【讨论】:

    【解决方案2】:

    免责声明:此答案旨在改进 rickdenhaan 的答案。

    您可以堆叠 css 渐变以获得色轮,并使用简单的数学计算给定坐标处的颜色,而无需实际从色轮中选择颜色。 这种方法不使用 EyeDropper,所以它应该有完整的浏览器支持。在下面的代码中,我将代码绑定到 mousemove 事件以轻松测试它;只需将事件名称替换为“click”即可获得预期的行为:

    const colors = [
        {r: 0xe4, g: 0x3f, b: 0x00},
        {r: 0xfa, g: 0xe4, b: 0x10},
        {r: 0x55, g: 0xcc, b: 0x3b},
        {r: 0x09, g: 0xad, b: 0xff},
        {r: 0x6b, g: 0x0e, b: 0xfd},
        {r: 0xe7, g: 0x0d, b: 0x86},
        {r: 0xe4, g: 0x3f, b: 0x00}
    ];
    document.addEventListener('DOMContentLoaded', function() {
        document.getElementById('color-wheel').addEventListener('mousemove', function(e) {
            var rect = e.target.getBoundingClientRect();
            //Compute cartesian coordinates as if the circle radius was 1
            var x = 2 * (e.clientX - rect.left) / (rect.right - rect.left) - 1;
            var y = 1 - 2 * (e.clientY - rect.top) / (rect.bottom - rect.top);
            //Compute the angle in degrees with 0 at the top and turning clockwise as expected by css conic gradient
            var a = ((Math.PI / 2 - Math.atan2(y, x)) / Math.PI * 180);
            if (a < 0) a += 360;
            //Map the angle between 0 and number of colors in the gradient minus one
            a = a / 360 * (colors.length - 1);  //minus one because the last item is at 360° which is the same as 0°
            //Compute the colors to interpolate
            var a0 = Math.floor(a) % colors.length;
            var a1 = (a0 + 1) % colors.length;
            var c0 = colors[a0];
            var c1 = colors[a1];
            //Compute the weights and interpolate colors
            var a1w = a - Math.floor(a);
            var a0w = 1 - a1w;
            var color = {
                r: c0.r * a0w + c1.r * a1w,
                g: c0.g * a0w + c1.g * a1w,
                b: c0.b * a0w + c1.b * a1w
            };
            //Compute the radius
            var r = Math.sqrt(x * x + y * y);
            if (r > 1) r = 1;
            //Compute the white weight, interpolate, and round to integer
            var cw = r < 0.8 ? (r / 0.8) : 1;
            var ww = 1 - cw;
            color.r = Math.round(color.r * cw + 255 * ww);
            color.g = Math.round(color.g * cw + 255 * ww);
            color.b = Math.round(color.b * cw + 255 * ww);
            //Compute the hex color code and apply it
            var xColor = rgbToHex(color.r, color.g, color.b);
            document.getElementById('color').innerText = xColor;
            document.getElementById('color').style.backgroundColor = xColor;
        });
    });
    
    function componentToHex(c) {
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }
    
    function rgbToHex(r, g, b) {
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }
    #color-wheel {
        width: 150px;
        height: 150px;
        background: radial-gradient(white, transparent 80%),
                    conic-gradient(#e43f00, #fae410, #55cc3b, #09adff, #6b0efd, #e70d86, #e43f00);
        border-radius: 50%;
    }
    <div id="color-wheel"></div>
    Color: <span id="color"></span>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      • 2021-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多