I'm trying to create a color picker in javascript canvas. I want to make something like this:
I want that when i click anywhere in the circle, i get x, y coordinates (so I can use some other element to mark the selected color) and color.
I would prefer if the solution was not a canvas with embedded image, but something like linear-gradient
.
I have searched the internet, but have not found anything to my question.
P.S.: Maybe css border-radius
will help to make a circle.
Disclaimer: this answer is intended as an improovement of rickdenhaan's answer.
You can stack css gradients to obtain the color wheel, and use simple math to compute the color at given coordinates without actually picking the color from the wheel. This approach doesn't use EyeDropper, so it should have full browsers support. In the following code I have bind the code to the mousemove event to test it easily; just replace the event name with "click" to get the expected behaviour:
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>