I'm trying to implement my own color wheel picker, and I'm using this color wheel, as the base. I (finally) successfully added RGB sliders. So now when you change the color wheels color, the RGB sliders change dynamically, and when you change the RGB sliders, the color wheels color updates too.
The problem is, when I slide a slider from the RGB sliders, the other sliders tend to move a little bit too. For example, if I slide the green value, the red and blue values change a little bit.
I'm not exactly sure what's wrong. How can I get the other sliders to not move when I move one slider? (Obviously if I don't set the sliders value in redraw()
, the sliders won't change when I move 1 slider, but I'm trying to find the core issue.)
var b = document.body;
var colorWheelDiv = document.getElementById('colorWheelDiv');
var colorWheel = document.createElement('canvas');
var colorWheelOverlay = document.createElement('div');
var a = colorWheel.getContext('2d');
var label = document.getElementById('label');
var input = document.getElementById('input');
var redInput = document.getElementById('red');
var greenInput = document.getElementById('green');
var blueInput = document.getElementById('blue');
var alphaInput = document.getElementById('alpha');
var rgbInput = document.getElementsByClassName('rgbInput');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
// Jquery Elements
var $redSlider = $('#red');
var $greenSlider = $('#green');
var $blueSlider = $('#blue');
var $alphaSlider = $('#alpha');
(function() {
// 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.colorWheel = doc.createElement;
b.a = b.appendChild;
// Add the colorWheel and the colorWheelOverlay
colorWheelDiv.appendChild(colorWheelOverlay);
colorWheelDiv.appendChild(colorWheel);
colorWheelOverlay.id = 'colorWheelOverlay';
colorWheel.id = 'colorWheel';
var width = colorWheel.width = colorWheel.height = colorWheelDiv.clientHeight,
imageData = a.createImageData(width, width),
pixels = imageData.data,
oneHundred = input.value = input.max = 100,
circleOffset = 10,
diameter = width - circleOffset * 2,
radius = diameter / 2,
radiusPlusOffset = radius + circleOffset,
radiusSquared = radius * radius,
two55 = 255,
currentY = oneHundred,
currentX = -currentY,
center = radius / 2,
wheelPixel = circleOffset * 4 * width + circleOffset * 4;
// Math helpers
var math = Math,
PI = math.PI,
PI2 = PI * 2,
sqrt = math.sqrt,
atan2 = math.atan2;
// 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 = colorWheel_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.oninput = redraw;
colorWheel.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);
}
$(".rgbInput").not($alphaSlider).slider({
range: "max",
min: 0,
max: 255,
value: 0,
slide: function(event, ui) {
redrawRGB();
}
});
function redrawRGB() {
var red = $('#red').slider('value');
var green = $('#green').slider('value');
var blue = $('#blue').slider('value');
var hsv = colorWheel_rgbToHsv(red, green, blue);
var newD = math.round(math.pow(radius * hsv.s, 2));
var newTheta = (hsv.h * PI2) - PI;
currentX = math.round(math.sqrt(newD) * math.cos(newTheta));
currentY = math.round(math.sqrt(newD) * math.sin(newTheta));
input.value = math.round(hsv.v * 100);
redraw(0);
}
// 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 - colorWheelDiv.offsetLeft - colorWheel.offsetLeft - radiusPlusOffset || currentX;
currentY = e.pageY - colorWheelDiv.offsetTop - colorWheel.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;
}
var vValue = parseInt(input.value, 10);
var rgb = colorWheel_hsvToRgb(
(theta + PI) / PI2, // Current hue (how many degrees along the circle)
sqrt(d) / radius, // Current saturation (how close to the middle)
vValue / oneHundred // Current value (input type="range" slider value)
)
label.textContent = b.style.background = rgb[3];
colorWheelOverlay.style.opacity = ((vValue + 100 - 15) - (vValue * 2)) / oneHundred;
// Set slider Position \\
$redSlider.slider("value", math.round(rgb[0]));
$greenSlider.slider("value", math.round(rgb[1]));
$blueSlider.slider("value", math.round(rgb[2]));
// 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 colorWheel_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(" + math.round(r) + "," + math.round(g) + "," + math.round(b) + ")"];
}
function colorWheel_rgbToHsv(r, g, b) {
r = r / two55;
g = g / two55;
b = b / two55;
var max = math.max(r, g, b),
min = math.min(r, g, b);
var h, s, v = max;
var d = max - min;
s = max === 0 ? 0 : d / max;
if (max == min) {
h = 0; // achromatic
} else {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return {
h: h,
s: s,
v: v
};
}
// Kick everything off
redraw(0);
})();
#colorWheelDiv {
width: 400px;
height: 400px;
position: relative;
}
#colorWheelOverlay {
background-color: black;
position: absolute;
pointer-events: none;
}
#colorWheelDiv,
#colorWheelOverlay,
#colorWheel {
border-radius: 50%;
}
#colorWheelOverlay,
#colorWheel {
width: 100%;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
R:
<div id="red" class="rgbInput"></div>
<br />G:
<div id="green" class="rgbInput"></div>
<br />B:
<div id="blue" class="rgbInput"></div>
<br />A:
<div id="alpha" class="rgbInput"></div>
<br />
<div id=colorWheelDiv></div>
<p id='label' style="font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: 2em; line-height: normal; font-family: courier;">rgb(239,183,131)</p>
<input id="input" max="100" type="range" min="0">
Update
I tried that answer, and it didn't help. I still get the same results. The title may be the same, but I don't think the actual question is the same