Color Clicker explainer

The aim of this puzzle: Make the circle change to a random color each time you tap it.
Walkthrough of the solution: When you run your program, it sees that you created a function called changeColor(). It doesn’t run it right away, but waits until another part of your code calls it into action. So the first thing to actually run is the circle.attr('fill', pickRandom(color)); at the very beginning. This sets the circle to a random color. Next, the function is skipped over, and it moves on to the circle.on('click', changeColor); line. This part is tricky, but it helps if you read it backwards: it will run the function changeColor once you 'click' .on() the circle. So, you click on the circle, and it turns black because you need to look inside the function where you set the 'fill' attribute and change it to pickRandom(color) just like the first line does. Your function should run the same code as the first line, but it needs to run every time you tap the circle, and that is exactly what the last line of the program does.
Sample code solution:
(Tap below to reveal)

circle.attr('fill', pickRandom(color));
function changeColor() {
    circle.attr('fill', pickRandom(color));
}
circle.on('click', changeColor);

JavaScript Concepts: Code Block (function), Calling Functions, Call Nesting, Identifiers
Grasshopper Concepts: pickRandom()
D3 Concepts: .attr(‘fill’,), .on(‘click’,)
Additional Code (hidden code that runs before the puzzle’s code):

var circle = svg.append('circle').attr('r',window.innerHeight/2-20).attr('cx',window.innerWidth/2).attr('cy',window.innerHeight/2);
let color = [...Array(36)].map((_,i)=>`hsl(${10*i},100%,50%)`);

seperti ini kah? Hehehe :smile: :wink:

1 Like

@Tri_Putra_Alexander Kerja bagus :slight_smile:

(Used google translate hopefully that says good job :slight_smile: )

1 Like

Hi guys, I’ve completed the puzzle, but just out of curiosity can someone please explain why the following code doesn’t also work?

Hey there,

The 2nd argument of .on() needs to be a function to run when the circle is clicked.

Wrapping lines of code in a function means they are stored in the computer’s memory, and retrieved when they are called (in this case, when then circle is clicked).

The .on() function will throw an error here as the line of code is not a function.

You could try declaring the function separately, and then putting the function’s identifier (its name, without parentheses after it) as the 2nd argument of .on(), like this:

function changeColor() {
    circle.attr('fill', pickRandom(color));
}

circle.on('click', changeColor);

Or, you could declare the function anonymously (a function without a name) inside .on(), like this:

circle.on('click', function() {
    circle.attr('fill', pickRandom(color));
});

Or finally, you could write it as an anonymous arrow function, like this:

circle.on('click', () => {
    circle.attr('fill', pickRandom(color));
});

Hope this helps!
Ben

5 Likes

Got it. Thanks, Ben!

Thanks, this is useful to think through the various options. If nothing else, it allows us to see how to do the same thing with an arrow function as was done with an anonymous function.

Could you maybe elaborate on how color is defined in the background? I assume JS does not know an infinite set of colors. So the pickRandom function should choose a random color, but I would actually be interested in the specifics of this the variable setup of color.

Hey there, there’s hidden additional code that sets up the color array like this:

let color = [...Array(36)].map((_,i)=>`hsl(${10 * i}, 100%, 50%)`);

This code is tough to read, but this is how it works:

[...Array(36)]

This tells the computer to create an array with 36 items. These items aren’t defined yet though, so all of the items in this array are undefined.

.map((_, i) => `hsl(${10*i},100%,50%)`)

This looks pretty confusing, but here’s the basic purpose of the function:

There are many ways to define colors in CSS. There are the basic 140 colors hard-coded in to CSS. There are also hex colors (short for hexidecimal). There are RGB colors, which we tend to favor in most of our lessons.

This code, however, is using HSL colors, which stands for “Hue, Saturation, and Lightness”.

.map() is used to iterate over the items in an array, run a function on each item, and then return the results to a new array.

This function takes the index of each item in the original array, multiplies it by 10, and then uses that as the hue for the HSL color, so the returned array would look like this:

[
  `hsl(0, 100%, 50%)`,
  `hsl(10, 100%, 50%)`,
  `hsl(20, 100%, 50%)`,
  `hsl(30, 100%, 50%)`,
  `hsl(40, 100%, 50%)`
]

The first parameter in .map() represents the current item in the array, and the optional 2nd parameter represents the index of that item. Because we only care about the index, the first parameter is just set to _.

This style of programming, which favors shortened code length over readability, is very much not my favorite. We can rewrite it to make it a bit simpler:

const colors = [];
for (let i = 0; i < 36; i++) {
  let hue = i * 10;
  colors.push(`${hue}, 100%, 50%`);
}

Hope this helps! Let me know if you have any questions.
Ben

2 Likes

circle

.

attr

(

‘fill’

,

pickRandom

(

color

)

)

;

function

changeColor

(


)

{

circle

.

attr

(

‘fill’

,

pickRandom

(

color

)

)

;


}

;

circle

.

on

(

‘click’

,

changeColor

)

;Preformatted text