This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Comments can be entered into the draw!! Specific lottery rules can see the end of the article!

I am trying to learn the front end of Mancuoj, welcome to pay attention to communicate with each other!

preface

The other day I saw someone else’s Color picker at Codepen and had the idea to recreate VS Code’s color palette. I was just learning front-end and wanted to try to write everything I saw.

It took several hours to write one. There are many bug thieves. Even if it is an idea, I am too lazy to change it.

Let’s take a look at what it looks like in the original version:

You can see the color and color value at the top. Click to switch between three color display modes, namely RGBA, HSLA and Hex8. Then a lower left column selects the color, and two right sliders select transparency and hue.

The upper right corner shows the original color and the bottom text prompt will not write 🙈 this time

Then check out the results of my hours of replicating (online preview) :

HTML+CSS

HTML has nothing to say, just div and div.

I sketched the overall layout:

Transparent background

The background of the black and white grid came up to me, but also a versatile search ah, and finally use a linear gradient solution:

background: linear-gradient(
                45deg.rgba(0.0.0.0.4) 25%, 
                transparent 25%, 
                transparent 75%.rgba(0.0.0.0.4) 75%.rgba(0.0.0.0.4)),linear-gradient(
                45deg.rgba(0.0.0.0.4) 25%, 
                transparent 25%, 
                transparent 75%.rgba(0.0.0.0.4) 75%.rgba(0.0.0.0.4));background-size: 10px 10px;
background-position: 0 0.5px 5px;
Copy the code

The second part of

Both transparency and hue selection are resolved with linear gradients:

/ / transparencybackground: linear-gradient(to bottom, rgba(0.0.0.1), rgba(0.0.0.0)); / / huebackground: linear-gradient(to bottom,
    hsl(0.100%.50%),
    hsl(60.100%.50%),
    hsl(120.100%.50%),
    hsl(180.100%.50%),
    hsl(240.100%.50%),
    hsl(300.100%.50%),
    hsl(360.100%.50%));Copy the code

The left and right slider should exceed 1px each:

.slide {
    width: 27px;
    height: 5px;
    border: 1px solid #eee;
    position: absolute;
    left: -2px;
    top: 0;
}
Copy the code

results

This is what CSS looks like after it is written:

JS

Let’s define all the variables we want to use:

const container = document.querySelector('.container')
const value = document.querySelector('.value')
const opacity = document.querySelector('.opacity')
const hue = document.querySelector('.hue')
const opaSlide = document.querySelector('#opa-slide')
const hueSlide = document.querySelector('#hue-slide')
const spectrum = document.querySelector('.spectrum')
const cursor = document.querySelector('.color-cursor')
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const speRect = canvas.getBoundingClientRect()

let bg_color = {
  h: 0.s: "100%".l: "50%".a: 1
};
Copy the code

canvas

Canvas is drawn with two black and white gradient overlay:

function draw(color) {
    ctx.clearRect(0.0, canvas.width, canvas.height);

    if(! color) color ='#f00';

    ctx.fillStyle = color;
    ctx.fillRect(0.0, canvas.width, canvas.height);

    let whiteGradient = ctx.createLinearGradient(0.0, canvas.width, 0);
    whiteGradient.addColorStop(0."#fff");
    whiteGradient.addColorStop(1."transparent");
    ctx.fillStyle = whiteGradient;
    ctx.fillRect(0.0, canvas.width, canvas.height);

    let blackGradient = ctx.createLinearGradient(0.0.0, canvas.height);
    blackGradient.addColorStop(0."transparent");
    blackGradient.addColorStop(1."# 000");
    ctx.fillStyle = blackGradient;
    ctx.fillRect(0.0, canvas.width, canvas.height);
}

draw();
Copy the code

Mouse events

Detect mouse down, move, lift events, and then change the information:

let isDraw = false;

container.onmousedown = () = > (isDraw = true);

container.onmousemove = (e) = > {
  if(! isDraw)return;
  ifMouse movement detected in target area {change display position; Change the color; } Change all colors and text information; }; container.onmouseup =() = > (isDraw = false);

// Avoid some bugs, but this affects the effect
canvas.onmouseout = () = > (isDraw = false);
Copy the code

Movement changes transparency and hue

Calculate the slider position through the mouse position, and then calculate the scale to modify the transparency and hue value, using TinyColor to parse the color.

let bg_color = {
  h: 0.s: "100%".l: "50%".a: 1
};

container.onmousemove = (e) = > {
  if(! isDraw)return;
  if (e.target === opacity || e.target.parentNode === opacity) {
    let y = e.pageY - opacity.getBoundingClientRect().top;
    if (y < 0) y = 0.1;
    if (y > 150) y = 145;
    opaSlide.style.top = y + "px";
    bg_color.a = 1 - y / opacity.offsetHeight;
  }

  if (e.target === hue || e.target.parentNode === hue) {
    let y = e.pageY - hue.getBoundingClientRect().top;
    if (y < 0) y = 0.1;
    if (y > 150) y = 145;
    hueSlide.style.top = y + "px";
    bg_color.h = (y / hue.offsetHeight) * 360; draw(tinycolor(bg_color)); }};Copy the code

Move and change color

Found a formula on StackOverflow that calculates the brightness and saturation of colors by the ratio of x and y to the canvas:

 if (e.target === spectrum || e.target.parentNode === spectrum) {
    let x = e.pageX - speRect.left - cursor.offsetWidth / 2;
    let y = e.pageY - speRect.top - cursor.offsetHeight / 2;

    let r = cursor.offsetHeight;

    if (x < 0) x = 0;
    if (x > speRect.width - r) x = speRect.width - r;
    if (y < 0) y = 0.1;
    if (y > speRect.height - r) y = speRect.height - r;

    cursor.style.left = x + "px";
    cursor.style.top = y + "px";

    // from stackoverflow
    let hsvValue = 1 - y / speRect.height;
    let hsvSaturation = x / speRect.width;
    let lightness = (hsvValue / 2) * (2 - hsvSaturation);
    let saturation =
      (hsvValue * hsvSaturation) / (1 - Math.abs(2 * lightness - 1));

    bg_color.l = lightness * 100 + "%";
    bg_color.s = saturation * 100 + "%";
}
Copy the code

Displays text and background colors

Here is the use of Tinycolor, you can see the official documentation.

let method = "toRgbString";

function changeBg() {
  let color = tinycolor(bg_color)[method]();
  value.style.background = color;
  value.style.color = parseInt(bg_color.l) >= 50 ? "black" : "white";
  value.innerHTML = color;
  document.body.style.background = `linear-gradient(to top, transparent, ${color}) `
  cursor.style.background = color;
}
Copy the code

Click on the top to switch the color display mode

let index = 0;

function changeType() {
  switch (index % 3) {
    case 0:
      method = "toRgbString";
      break;
    case 1:
      method = "toHex8String";
      break;
    case 2:
      method = "toHslString";
      break;
  }
  index++;
}

value.onclick = () = > {
  changeType();
  changeBg();
};
Copy the code

The source code

Bug huge and matchless, I still too dish, source code on codepen, want to see if you can see

Color Picker (codepen.io)

conclusion

Canvas is good to use, linear gradient is better to use, but I am too tired…

I really have procrastination, long finished writing the code, the blog dragged a few days did not write, the bug also do not want to change, code pull pull bar, everyone casually look, or a little reference.

Please feel free to discuss in the comments section. The nuggets will draw 100 nuggets in the comments section after the diggnation project. See the event article for details.