JavaScript Color Wheel Picker

JavaScript Color Wheel Picker
Project: HSL picker color-wheel
Author: Claudiu Codreanu
Edit Online: View on CodePen
License: MIT

This JavaScript code snippet helps you to create a wheel color picker for selecting HSL color values. The color picker is created inside a parent element specified by the user. When the user changes the HSL values by interacting with the picker, a callback function is called with the new HSL values as arguments. The HSL values are used to update the background color of an element with id “sample” and the text of an element with id “hsl-values”. The initial hue value of the picker can also be specified using the third argument of the “createHslPicker” function.

How to Create JavaScript Color Wheel Picker

First of all, create the HTML structure for the color wheel picker as follows:

<h1>HSL picker (JavaScript)</h1>

<p class="text">
Click the color-wheel to pick a Hue from <b>0</b> to <b>360</b> (going counter-clock-wise).
<br>
Drag the corresponding sliders to pick the Saturation and Lightness (from <b>0</b>% to <b>100</b>%).
<br>
You'll see the HSL numeric values and the sample color, in the rectangle below.
</p>

<div id="container" class="hsl-container"></div>

<div id="sample-container" class="sample-container">
  <p class="text"><span id="hsl-values">Hue: <b>0</b>, Saturation: <b>100</b>%, Lightness: <b>50</b>%</span>
  <br>See sample below:</p>
<div id="sample" class="sample">&nbsp;</div>
</div>

Style the wheel picker using the following CSS styles:

body {
  padding-top: 10px;
  padding-left: 50px;
}

h1 {
	font-family: Georgia, serif;
	font-size: 22px;
	font-weight: bold;
	color: midnightblue;
	letter-spacing: 1.4px;
	margin-bottom: 20px;
}

.sample-container {
  margin-left: 10px;
}

.sample {
  width: 400px;
  height: 150px;
  background: grey;
  border: solid 1px #444444;
  transition: background 0.5s;
}

.text {
  font-family: Verdana;
	font-size: 12px;
	color: #333333;
	line-height: 150%;
	letter-spacing: .25px;
}

.hsl-container {
  margin-top: 40px;
  margin-bottom: 50px;
}

Finally, add the following JavaScript function to activate the color picker.

let parent = document.getElementById("container");

createHslPicker(parent, (h, s, l) => {
  let sample = document.getElementById("sample"),
      text = document.getElementById("hsl-values");
  
  sample.style.background = `hsl(${h}, ${s}%, ${l}%)`;
  text.innerHTML = `Hue: <b>${h}</b>, Saturation: <b>${s}</b>%, Lightness: <b>${l}</b>%`;
}, 50);


/*
  Main function, creates the HSL picker inside a parent that you provide (such as a div).
  As the user picks different HSL values, you are notified via the callback.
  The HSL values are provided as arguments, and you can use them to update other parts of your UI.
  You can also pass an initial hue, via the thrid argument.
*/
function createHslPicker(parent, callback, initialHue = 0) {
	parent.innerHTML = getHtml();
  
  let canvas = document.getElementById("canvas-hue"),
      rgSat = document.getElementById("rg-saturation"),
      rgLight = document.getElementById("rg-lightness"),
      hsl = [initialHue, 100, 50];
  
  
  drawColorWheel();
  onHslChanged();
  
  
  rgSat.addEventListener("change", onSaturationPicked);
  rgLight.addEventListener("change", onLightnessPicked);
  
  
  let xCircle = canvas.width / 2,
      yCircle = canvas.height / 2,
      radius = canvas.width / 2;
  
  
  canvas.addEventListener("mousemove", ev => {
    let dist = Math.sqrt(Math.pow(ev.offsetX - xCircle, 2) + Math.pow(ev.offsetY - yCircle, 2));
    canvas.style.cursor = dist <= radius ? "pointer" : "default";
  });

  
  canvas.addEventListener("mousedown", ev => {
    if(ev.button != 0) {
      return;
    }

    let dist = Math.sqrt(Math.pow(ev.offsetX - xCircle, 2) + Math.pow(ev.offsetY - yCircle, 2));

    if(radius < dist) {
      return;
    }

    let sine = (yCircle - ev.offsetY) / dist,
        radians = Math.atan2(yCircle - ev.offsetY, ev.offsetX - xCircle);

    if(radians < 0) {
      radians = 2 * Math.PI - Math.abs(radians);
    }

    let degrees = radians * 180 / Math.PI,
        hue = Math.round(degrees);

    onHuePicked(hue);
  });
  
  
  function onHuePicked(h) {
    hsl[0] = h;
    onHslChanged();
  }
  
  function onSaturationPicked() {
    hsl[1] = +document.getElementById("rg-saturation").value;
    drawColorWheel();
    
    onHslChanged();
  }
  
  function onLightnessPicked() {
    hsl[2] = +document.getElementById("rg-lightness").value;
    drawColorWheel();
    
    onHslChanged();
  }
  
  
  function onHslChanged() {
    if(callback) {
      callback(...hsl);
    }
  }

  
	function drawColorWheel() {
		let ctx = canvas.getContext("2d"),
			  radius = canvas.width / 2,
			  x = canvas.width / 2,
			  y = canvas.height / 2,
        [h, s, l] = hsl;
			
		for(let i = 0; i < 360; i++) {
		  let color = `hsl(${i}, ${s}%, ${l}%)`;
	  
		  ctx.beginPath();

		  ctx.moveTo(x, y);
		  ctx.arc(x, y, radius, -(i + 1) * Math.PI / 180, -i * Math.PI / 180);
		  ctx.lineTo(x, y);
		  ctx.closePath();

		  ctx.fillStyle = color;
		  ctx.strokeStyle = color;

		  ctx.fill();
		  ctx.stroke();
		}
	}
  
  function getHtml() {
    return `<div style="padding: 20px; border: 1px solid #999999; height: 330px; width: 700px; background: #f5f5f5; box-shadow: 0px 0px 30px #555555;">
		<div style="display: grid; grid-column-gap: 10px; grid-template-columns: 330px 350px; grid-template-rows: 130px 130px; grid-template-areas: 'hue saturation' 'hue lightness';">
		  <div style="grid-area: hue;">
			<span style="padding-left: 20px;">Hue:</span>
			<canvas id="canvas-hue" width="300" height="300"></canvas>
		  </div>
		  
		  <div style="grid-area: saturation; padding-top: 30px; padding-left: 20px;">
			<label for="rg-saturation">Saturation:</label>
			<input type="range" id="rg-saturation" min="0" max="100" value="100" style="width: 300px; display: block; cursor: pointer;">
			<span>0</span>
			<span style="margin-left: 270px; text-align: right;">100</span>
		  </div>
		  
		  <div style="grid-area: lightness; padding-top: 30px; padding-left: 20px;">
			<label for="rg-lightness">Lightness:</label>
			<input type="range" id="rg-lightness" min="0" max="100" value="50" style="width: 300px; display: block; cursor: pointer;">
			<span>0</span>
			<span style="margin-left: 270px; text-align: right;">100</span>
		  </div>
		</div>
    </div>`;
  }
}

Code Explanation

The code first sets the parent container element using the getElementById method, and then calls the createHslPicker function, passing the parent container element, a callback function, and an initial hue value of 50 as arguments.

The createHslPicker function starts by setting the innerHTML of the parent container element using the getHtml function, which returns an HTML string for the color picker interface. The function then sets some initial values for the HSL values, creates the color wheel using the drawColorWheel function, and calls the onHslChanged function.

Similarly, the onHslChanged function calls the callback function passed to the createHslPicker function, passing the current HSL values as arguments. This allows the caller to update other parts of the user interface with the selected color.

The getHtmlreturns an HTML string for the color picker interface, which includes a canvas element for the color wheel, range inputs for saturation and lightness, and labels and text for displaying the selected HSL values.

That’s all! hopefully, you have successfully created a color wheel picker using JavaScript. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply