I am using this color wheel, and I want to change the color of the color wheel programmatically. So if I have a color value (rgb, hsv etc.) I want to change the color wheel to that specific color?
For example, if I have rgb(255, 255, 80)
, how can I change the color wheel to show that?
Relevant code:
Custom code:
function changeColor() {
var redColor = 255;
var greenColor = 255;
var blueColor = 80;
//currentX =
//currentY =
redraw(0);
// The following line is redundent if I'm calling 'redraw`, but it's there just to show what I mean.
label.textContent = b.style.background = 'rgb(' + redColor + ', ' + greenColor + ', ' + blueColor + ')';
}
Actual Code from the redraw() function
function redraw(e) {
// Only process an actual change if it is triggered by the mousemove or mousedown event.
// Otherwise e.pageX will be undefined, which will cause the result to be NaN, so it will fallback to the current value
currentX = e.pageX - c.offsetLeft - radiusPlusOffset || currentX;
currentY = e.pageY - c.offsetTop - radiusPlusOffset || currentY;
// Scope these locally so the compiler will minify the names. Will manually remove the 'var' keyword in the minified version.
var theta = atan2(currentY, currentX),
d = currentX * currentX + currentY * currentY;
// If the x/y is not in the circle, find angle between center and mouse point:
// Draw a line at that angle from center with the distance of radius
// Use that point on the circumference as the draggable location
if (d > radiusSquared) {
currentX = radius * math.cos(theta);
currentY = radius * math.sin(theta);
theta = atan2(currentY, currentX);
d = currentX * currentX + currentY * currentY;
}
label.textContent = b.style.background = hsvToRgb(
(theta + PI) / PI2, // Current hue (how many degrees along the circle)
sqrt(d) / radius, // Current saturation (how close to the middle)
input.value / oneHundred // Current value (input type="range" slider value)
)[3];
// Reset to color wheel and draw a spot on the current location.
a.putImageData(imageData, 0, 0);
// Draw the current spot.
a.stroke();
a.font = "1em arial";
a.fillText("♥", currentX+radiusPlusOffset-4,currentY+radiusPlusOffset+4);
}
(function() {
document.getElementById('button').onclick = changeColor;
function changeColor() {
var redColor = 255;
var greenColor = 255;
var blueColor = 80;
//currentX =
//currentY =
redraw(0);
// The following line is redundent if I'm calling 'redraw`, but it's there just to show what I mean.
label.textContent = b.style.background = 'rgb(' + redColor + ', ' + greenColor + ', ' + blueColor + ')';
}
// Declare constants and variables to help with minification
// Some of these are inlined (with comments to the side with the actual equation)
var doc = document;
doc.c = doc.createElement;
b.a = b.appendChild;
var width = c.width = c.height = 400,
label = b.a(doc.c("p")),
input = b.a(doc.c("input")),
imageData = a.createImageData(width, width),
pixels = imageData.data,
oneHundred = input.value = input.max = 100,
circleOffset = 10,
diameter = 380, //width-circleOffset*2,
radius = 190, //diameter / 2,
radiusPlusOffset = 200, //radius + circleOffset
radiusSquared = radius * radius,
two55 = 255,
currentY = oneHundred,
currentX = -currentY,
wheelPixel = 16040; // circleOffset*4*width+circleOffset*4;
// Math helpers
var math = Math,
PI = math.PI,
PI2 = PI * 2,
sqrt = math.sqrt,
atan2 = math.atan2;
// Setup DOM properties
b.style.textAlign = "center";
label.style.font = "2em courier";
input.type = "range";
// Load color wheel data into memory.
for (y = input.min = 0; y < width; y++) {
for (x = 0; x < width; x++) {
var rx = x - radius,
ry = y - radius,
d = rx * rx + ry * ry,
rgb = hsvToRgb(
(atan2(ry, rx) + PI) / PI2, // Hue
sqrt(d) / radius, // Saturation
1 // Value
);
// Print current color, but hide if outside the area of the circle
pixels[wheelPixel++] = rgb[0];
pixels[wheelPixel++] = rgb[1];
pixels[wheelPixel++] = rgb[2];
pixels[wheelPixel++] = d > radiusSquared ? 0 : two55;
}
}
// Bind Event Handlers
input.onchange = redraw;
c.onmousedown = doc.onmouseup = function(e) {
// Unbind mousemove if this is a mouseup event, or bind mousemove if this a mousedown event
doc.onmousemove = /p/.test(e.type) ? 0 : (redraw(e), redraw);
}
// Handle manual calls + mousemove event handler + input change event handler all in one place.
function redraw(e) {
// Only process an actual change if it is triggered by the mousemove or mousedown event.
// Otherwise e.pageX will be undefined, which will cause the result to be NaN, so it will fallback to the current value
currentX = e.pageX - c.offsetLeft - radiusPlusOffset || currentX;
currentY = e.pageY - c.offsetTop - radiusPlusOffset || currentY;
// Scope these locally so the compiler will minify the names. Will manually remove the 'var' keyword in the minified version.
var theta = atan2(currentY, currentX),
d = currentX * currentX + currentY * currentY;
// If the x/y is not in the circle, find angle between center and mouse point:
// Draw a line at that angle from center with the distance of radius
// Use that point on the circumference as the draggable location
if (d > radiusSquared) {
currentX = radius * math.cos(theta);
currentY = radius * math.sin(theta);
theta = atan2(currentY, currentX);
d = currentX * currentX + currentY * currentY;
}
label.textContent = b.style.background = hsvToRgb(
(theta + PI) / PI2, // Current hue (how many degrees along the circle)
sqrt(d) / radius, // Current saturation (how close to the middle)
input.value / oneHundred // Current value (input type="range" slider value)
)[3];
// Reset to color wheel and draw a spot on the current location.
a.putImageData(imageData, 0, 0);
// Draw the current spot.
// I have tried a rectangle, circle, and heart shape.
/*
// Rectangle:
a.fillStyle = '#000';
a.fillRect(currentX+radiusPlusOffset,currentY+radiusPlusOffset, 6, 6);
*/
/*
// Circle:
a.beginPath();
a.strokeStyle = '#000';
a.arc(~~currentX+radiusPlusOffset,~~currentY+radiusPlusOffset, 4, 0, PI2);
a.stroke();
*/
// Heart:
a.font = "1em arial";
a.fillText("♥", currentX + radiusPlusOffset - 4, currentY + radiusPlusOffset + 4);
}
// Created a shorter version of the HSV to RGB conversion function in TinyColor
// https://github.com/bgrins/TinyColor/blob/master/tinycolor.js
function hsvToRgb(h, s, v) {
h *= 6;
var i = ~~h,
f = h - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s),
mod = i % 6,
r = [v, q, p, p, t, v][mod] * two55,
g = [t, v, v, q, p, p][mod] * two55,
b = [p, p, t, v, v, q][mod] * two55;
return [r, g, b, "rgb(" + ~~r + "," + ~~g + "," + ~~b + ")"];
}
// Kick everything off
redraw(0);
/*
// Just an idea I had to kick everything off with some changing colors…
// Probably no way to squeeze this into 1k, but it could probably be a lot smaller than this:
currentX = currentY = 1;
var interval = setInterval(function() {
currentX--;
currentY*=1.05;
redraw(0)
}, 7);
setTimeout(function() {
clearInterval(interval)
}, 700)
*/
})();
<button id="button">Click Me To Change Color</button>
<br />
<canvas id="c"></canvas>
<script>
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
</script>
Here is a function taken from TinyColor (already referenced in this color wheel source) and added to some code to convert the HSV back to x,y,and slider values.
This ends up showing RGB values that are slightly off from whats passed in unless you change the
~~
NOT bitwise operator in the .. function to eliminate rounding issues from dropping the decimals.Here is a gist of the whole modified library. https://gist.github.com/tonypatton/bf4e13cabf03fc4a1777