Reputation: 27
I'm trying to compare two RGB colors in a guessing game. There are 6 squares with 6 different colors. When the user clicks on the color that matches pickedColor
, the result should be 'Correct!'. But I never get that result.
This is my code:
var colors = [
"rgb(255,0,0)",
"rgb(255,255,0)",
"rgb(0,255,0)",
"rgb(0,255,255)",
"rgb(0,0,255)",
"rgb(255,0,255)"
];
var squares = document.querySelectorAll(".square");
var pickedColor = colors[3];
var colorDisplay = document.getElementById("colorDisplay");
colorDisplay.textContent = pickedColor;
for (var i = 0; i < squares.length; i++) {
//add initinal colors to squares
squares[i].style.background = colors[i];
//add the click listener to the squares
squares[i].addEventListener("click", function () {
var clickedColor = this.style.background;
if (clickedColor === pickedColor) alert("Correct!");
else alert("Incorrect!");
});
}
Upvotes: 0
Views: 6328
Reputation: 12239
The trouble is that the color expression 'rgb(0,255,255)'
is formatted differently by the browser. In the test clickedColor === pickedColor
, you're comparing two strings that no longer look the same even if they represent the same color.
Different browsers can represent an RGB color in different ways, so it's unsafe to pick a particular format. A better approach is to extract the color components from the strings and compare the component values one by one, as in the code below.
function rgbExtract(s) {
var match = /^\s*rgb\(\s*(\d+),\s*(\d+),\s*(\d+)\)\s*$/.exec(s);
if (match === null) {
return null;
}
return { r: parseInt(match[1], 10),
g: parseInt(match[2], 10),
b: parseInt(match[3], 10) };
}
function rgbMatches(sText, tText) {
var sColor = rgbExtract(sText),
tColor = rgbExtract(tText);
if (sColor === null || tColor === null) {
return false;
}
var componentNames = [ 'r', 'g', 'b' ];
for (var i = 0; i < componentNames.length; ++i) {
var name = componentNames[i];
if (sColor[name] != tColor[name]) {
return false;
}
}
return true;
}
The rgbMatches
function is demonstrated in the following snippet. You'll see that you can now click on the square with the correct color and you'll get the appropriate message even though the underlying RGB strings are formatted differently.
var colors = [
"rgb(255,0,0)",
"rgb(255,255,0)",
"rgb(0,255,0)",
"rgb(0,255,255)",
"rgb(0,0,255)",
"rgb(255,0,255)"
];
var squares = document.querySelectorAll(".square");
var pickedColor = colors[3];
var colorDisplay = document.getElementById("colorDisplay");
colorDisplay.textContent = pickedColor;
function message(s) {
document.getElementById('messageContainer').innerHTML = s;
}
function rgbExtract(s) {
var match = /^\s*rgb\(\s*(\d+),\s*(\d+),\s*(\d+)\)\s*$/.exec(s);
if (match === null) {
return null;
}
return { r: parseInt(match[1], 10),
g: parseInt(match[2], 10),
b: parseInt(match[3], 10) };
}
function rgbMatches(sText, tText) {
var sColor = rgbExtract(sText),
tColor = rgbExtract(tText);
if (sColor === null || tColor === null) {
return false;
}
var componentNames = [ 'r', 'g', 'b' ];
for (var i = 0; i < componentNames.length; ++i) {
var name = componentNames[i];
if (sColor[name] != tColor[name]) {
return false;
}
}
return true;
}
for (var i = 0; i < squares.length; ++i) {
var square = squares[i];
square.style.background = colors[i];
square.addEventListener("click", function () {
var clickedColor = this.style.background;
if (rgbMatches(clickedColor, pickedColor)) {
message('Correct! ' + clickedColor + ' matches ' + pickedColor);
} else {
message('Incorrect. ' + clickedColor + ' doesn\'t match ' + pickedColor);
}
});
}
body {
font-family: sans-serif;
}
.square {
display: inline-block;
margin: 5px;
width: 50px;
height: 50px;
border: 1px solid #888;
cursor: pointer;
}
.output {
margin: 10px 5px;
}
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="output" id="colorDisplay"></div>
<div class="output" id="messageContainer"></div>
Upvotes: 1
Reputation: 288690
Do not trust the color returned by the browser. Different browsers will use different formats.
Instead, use classes or data-*
attributes to set the color, and check that:
var colors = ["red", "yellow", "lime", "cyan", "blue", "fuchsia"],
squares = document.querySelectorAll(".square"),
pickedColor = colors[Math.floor(Math.random()*colors.length)],
message = document.getElementById("messageContainer");
document.getElementById("colorDisplay").textContent = pickedColor;
for (var i = 0; i < squares.length; ++i) {
squares[i].setAttribute('data-color', colors[i]);
squares[i].addEventListener("click", function () {
var clickedColor = this.getAttribute('data-color');
message.textContent = clickedColor === pickedColor
? "Correct!" : "Incorrect!";
});
}
.square {
display: inline-block;
margin: 5px;
width: 50px;
height: 50px;
border: 1px solid #888;
cursor: pointer;
}
.output {
margin: 10px 5px;
}
[data-color=red] { background: rgb(255,0,0) }
[data-color=yellow] { background: rgb(255,255,0) }
[data-color=lime] { background: rgb(0,255,0) }
[data-color=cyan] { background: rgb(0,255,255) }
[data-color=blue] { background: rgb(0,0,255) }
[data-color=fuchsia] { background: rgb(255,0,255) }
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="output" id="colorDisplay"></div>
<div class="output" id="messageContainer"></div>
Upvotes: 0
Reputation: 4055
I would be wary of comparing two rgb strings like this. Different browsers may store style background colors differently (as you have already discovered).
I would suggest writing a custom comparison function which parses two rgb strings and compares them.
Or you could convert them to hex color values and compare those instead.
Upvotes: 0
Reputation: 3435
Ok so I set up an example here and it looks like the problem is that your initial set of colours don't have spaces between the commas:
var colors = [
"rgb(255,0,0)",
"rgb(255,255,0)",
"rgb(0,255,0)",
"rgb(0,255,255)",
"rgb(0,0,255)",
"rgb(255,0,255)"
];
clickedColor has no spaces and the pickedColor does, so changing this to:
var colors = [
"rgb(255, 0, 0)",
"rgb(255, 255, 0)",
"rgb(0, 255, 0)",
"rgb(0, 255, 255)",
"rgb(0, 0, 255)",
"rgb(255, 0, 255)"
];
Should do the trick.
Upvotes: 4