A Pen by François Georgy on CodePen.
Created
November 26, 2024 12:49
-
-
Save francoisgeorgy/29d6cb334cdde9f3b3c91b87397f2c73 to your computer and use it in GitHub Desktop.
Smooth Full-Spectrum Color Picker with buttons
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <div id="color-spectrum"> | |
| <canvas id="gradient-canvas"></canvas> | |
| <div id="color-indicator"></div> | |
| </div> | |
| <div id="selected-color">Selected Color: <span id="color-display">N/A</span></div> | |
| <div id="controls"> | |
| <button id="select-white">Select White</button> | |
| <button id="select-black">Select Black</button> | |
| <button id="select-random">Select Random</button> | |
| </div> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const spectrum = document.getElementById('color-spectrum'); | |
| const canvas = document.getElementById('gradient-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const indicator = document.getElementById('color-indicator'); | |
| const colorDisplay = document.getElementById('color-display'); | |
| // Buttons | |
| const whiteButton = document.getElementById('select-white'); | |
| const blackButton = document.getElementById('select-black'); | |
| const randomButton = document.getElementById('select-random'); | |
| // Initialize canvas to cover the full viewport | |
| function initializeCanvas() { | |
| canvas.width = spectrum.offsetWidth; | |
| canvas.height = spectrum.offsetHeight; | |
| const width = canvas.width; | |
| const height = canvas.height; | |
| // Create an imageData object to directly manipulate pixels | |
| const imageData = ctx.createImageData(width, height); | |
| for (let y = 0; y < height; y++) { | |
| for (let x = 0; x < width; x++) { | |
| const index = (y * width + x) * 4; | |
| // Horizontal gradient: hue | |
| const hue = (x / width) * 360; | |
| const [r1, g1, b1] = hslToRgb(hue, 1, 0.5); | |
| // Vertical gradient: brightness adjustment | |
| const brightness = 1 - y / height; | |
| // Apply brightness to the hue | |
| imageData.data[index] = r1 * brightness; // Red | |
| imageData.data[index + 1] = g1 * brightness; // Green | |
| imageData.data[index + 2] = b1 * brightness; // Blue | |
| imageData.data[index + 3] = 255; // Alpha | |
| } | |
| } | |
| // Draw the processed image data onto the canvas | |
| ctx.putImageData(imageData, 0, 0); | |
| } | |
| // Convert HSL to RGB | |
| function hslToRgb(h, s, l) { | |
| const c = (1 - Math.abs(2 * l - 1)) * s; | |
| const x = c * (1 - Math.abs((h / 60) % 2 - 1)); | |
| const m = l - c / 2; | |
| let r = 0, g = 0, b = 0; | |
| if (h >= 0 && h < 60) [r, g, b] = [c, x, 0]; | |
| else if (h >= 60 && h < 120) [r, g, b] = [x, c, 0]; | |
| else if (h >= 120 && h < 180) [r, g, b] = [0, c, x]; | |
| else if (h >= 180 && h < 240) [r, g, b] = [0, x, c]; | |
| else if (h >= 240 && h < 300) [r, g, b] = [x, 0, c]; | |
| else if (h >= 300 && h < 360) [r, g, b] = [c, 0, x]; | |
| return [ | |
| Math.round((r + m) * 255), | |
| Math.round((g + m) * 255), | |
| Math.round((b + m) * 255), | |
| ]; | |
| } | |
| // Initialize the canvas on page load | |
| initializeCanvas(); | |
| // Event listener to handle mouse movement | |
| spectrum.addEventListener('mousemove', (event) => { | |
| const { offsetX, offsetY } = event; | |
| // Move the color indicator | |
| indicator.style.left = `${offsetX}px`; | |
| indicator.style.top = `${offsetY}px`; | |
| // Get the pixel color under the cursor | |
| const imageData = ctx.getImageData(offsetX, offsetY, 1, 1); | |
| const [r, g, b] = imageData.data; | |
| const color = `rgb(${r}, ${g}, ${b})`; | |
| // Update the color display | |
| updateSelectedColor(color); | |
| }); | |
| // Button event handlers | |
| whiteButton.addEventListener('click', () => { | |
| updateSelectedColor('rgb(255, 255, 255)'); | |
| }); | |
| blackButton.addEventListener('click', () => { | |
| updateSelectedColor('rgb(0, 0, 0)'); | |
| }); | |
| randomButton.addEventListener('click', () => { | |
| const randomX = Math.floor(Math.random() * canvas.width); | |
| const randomY = Math.floor(Math.random() * canvas.height); | |
| const imageData = ctx.getImageData(randomX, randomY, 1, 1); | |
| const [r, g, b] = imageData.data; | |
| const color = `rgb(${r}, ${g}, ${b})`; | |
| updateSelectedColor(color); | |
| }); | |
| // Function to update the selected color | |
| function updateSelectedColor(color) { | |
| colorDisplay.textContent = color; | |
| indicator.style.backgroundColor = color; | |
| } | |
| // Redraw canvas on window resize | |
| window.addEventListener('resize', () => { | |
| initializeCanvas(); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| body, html { | |
| margin: 0; | |
| padding: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow: hidden; | |
| cursor: crosshair; | |
| } | |
| #color-spectrum { | |
| position: relative; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| #gradient-canvas { | |
| width: 100%; | |
| height: 100%; | |
| display: block; | |
| } | |
| #color-indicator { | |
| position: absolute; | |
| width: 20px; | |
| height: 20px; | |
| border: 2px solid white; | |
| border-radius: 50%; | |
| box-shadow: 0 0 5px black; | |
| pointer-events: none; | |
| transform: translate(-50%, -50%); | |
| } | |
| #controls { | |
| position: absolute; | |
| bottom: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| display: flex; | |
| gap: 10px; | |
| z-index: 10; /* Ensure buttons are above the canvas */ | |
| } | |
| button { | |
| padding: 10px 20px; | |
| font-size: 14px; | |
| font-family: Arial, sans-serif; | |
| cursor: pointer; | |
| border: 1px solid white; /* White border */ | |
| border-radius: 5px; | |
| background-color: transparent; /* Transparent background */ | |
| color: white; | |
| box-shadow: none; | |
| transition: background-color 0.3s ease, box-shadow 0.3s ease; | |
| } | |
| button:hover { | |
| background-color: rgba(255, 255, 255, 0.2); /* Semi-opaque background */ | |
| box-shadow: 0 0 5px rgba(255, 255, 255, 0.5); /* Subtle glow on hover */ | |
| } | |
| #selected-color { | |
| position: absolute; | |
| bottom: 80px; | |
| left: 10px; | |
| padding: 10px; | |
| background: white; | |
| border: 1px solid black; | |
| font-family: Arial, sans-serif; | |
| font-size: 14px; | |
| box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); | |
| z-index: 10; /* Ensure display is above the canvas */ | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment