JavaScript实现HSL拾色器

HSL 和 HSV 在数学上定义为在 RGB 空间中的颜色的 R, G 和 B 的坐标的变换。

从 RGB 到 HSL 或 HSV 的转换

设 (r, g, b) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。设 max 等价于 r, g 和 b 中的最大者。设 min 等于这些值中的最小者。要找到在 HSL 空间中的 (h, s, l) 值,这里的 h ∈ [0, 360)是角度的色相角,而 s, l ∈ [0,1] 是饱和度和亮度,计算为:

h 的值通常规范化到位于 0 到 360°之间。而 h = 0 用于 max = min 的(就是灰色)时候而不是留下 h 未定义。
HSL 和 HSV 有同样的色相定义,但是其他分量不同。HSV 颜色的 s 和 v 的值定义如下:

从 HSL 到 RGB 的转换

给定 HSL 空间中的 (h, s, l) 值定义的一个颜色,带有 h 在指示色相角度的值域 [0, 360)中,分别表示饱和度和亮度的s 和 l 在值域 [0, 1] 中,相应在 RGB 空间中的 (r, g, b) 三原色,带有分别对应于红色、绿色和蓝色的 r, g 和 b 也在值域 [0, 1] 中,它们可计算为:
首先,如果 s = 0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,r, g 和 b 都等于 l。注意 h 的值在这种情况下是未定义的。
当 s ≠ 0 的时候,可以使用下列过程:

对于每个颜色向量 Color = (ColorR, ColorG, ColorB) = (r, g, b),

从 HSV 到 RGB 的转换

类似的,给定在 HSV 中 (h, s, v) 值定义的一个颜色,带有如上的 h,和分别表示饱和度和明度的 s 和 v 变化于 0 到 1 之间,在 RGB 空间中对应的 (r, g, b) 三原色可以计算为:

对于每个颜色向量 (r, g, b),

<html>
  <style>
    .childDiv {
      display:inline-block;
      vertical-align:middle;
      margin-left: 30px;
      margin-top: 10px;
      margin-bottom: 10px;
    }
    #colorPickDiv {
      background-color: WhiteSmoke;
      border: 1px solid LightGrey;
      padding-top: 20px;
      padding-bottom: 20px;
      padding-right: 30px;
    }
    #hueTipDiv {
      margin: 0 0 10px 70px;
    }
    #luminanceTipDiv {
      margin-top: 20px
    }
    #colorDiv {
      width: 100px;
      height: 100px;
      background-color: black;
    }
    #valueDiv {
      box-shadow: 0px -5px 10px LightGrey;
      background-color: WhiteSmoke;
      border: 1px solid LightGrey;
      border-top-width: 0;
      padding-right: 10px;
      padding-bottom: 10px;
    }
  </style>
  <body>
    <div>
      <div id="colorPickDiv">
        <div class="childDiv">
          <div id="hueTipDiv">Hue:0</div>
          <canvas id="canvas" width="200" height="200">Your browser does not support canvas</canvas>
        </div>
        <div class="childDiv">
          <div id="saturationTipDiv" class="divMarginBottom">Saturation:0%</div>
          <input id="saturationRange" onChange="onHSLRangeChange()" type="range" min="0" max="100" step="1" value="100"/>
          <div id="luminanceTipDiv" class="divMarginBottom">Luminance:0%</div>
          <input id="luminanceRange" onChange="onHSLRangeChange()" type="range" min="0" max="100" step="1" value="50"/>
        </div>
        <div id="colorDiv" class="childDiv"></div>
      </div>
      <div id="valueDiv">
        <div class="childDiv">
          <div id="hexadecimalTipDiv" class="divMarginBottom">Hexadecimal:</div>
          <input id="hexadecimalValueDiv" type="text" disabled="disabled"/>
        </div>
        <div class="childDiv">
          <div id="rgbTipDiv" class="divMarginBottom">RGB:</div>
          <input id="rgbValueDiv" type="text" readonly="readonly"/>
        </div>
        <div class="childDiv">
          <div id="hslTipDiv" class="divMarginBottom">HSL:</div>
          <input id="hslValueDiv" type="text" readonly="readonly"/>
        </div>
      </div>
    </div>
    <script>
      var c = document.getElementById("canvas");
      var ctx = c.getContext("2d");
      var colorDiv = document.getElementById("colorDiv");
      var hexadecimalValueDiv = document.getElementById("hexadecimalValueDiv");
      var rgbValueDiv = document.getElementById("rgbValueDiv");
      var hslValueDiv = document.getElementById("hslValueDiv");
      var hexadecimalTipDiv = document.getElementById("hexadecimalTipDiv");
      var saturationTipDiv = document.getElementById("saturationTipDiv");
      var saturationRange = document.getElementById("saturationRange");
      var luminanceTipDiv = document.getElementById("luminanceTipDiv");
      var luminanceRange = document.getElementById("luminanceRange");

      //十字光标颜色
      var crossCursorColor = "black";
      //十字光标线宽
      var crossCursorLineWidth = 2;
      //十字光标某一边线段长
      var crossCursorHalfLineLen = 5;
      //十字光标中间断裂处长度
      var crossCursorHalfBreakLineLen = 2;

      //画布中心点X坐标
      var centerX = c.width / 2;
      //画布中心点Y坐标
      var centerY = c.height / 2;
      //缩放绘制比例
      var scaleRate = 10;
      //画布的内切圆半径(之所以减去一个数是为了可以显示完整的十字光标)
      var innerRadius = Math.min(centerX, centerY) - crossCursorHalfLineLen - crossCursorHalfBreakLineLen;
      //内切圆半径的平方
      var pow2InnerRadius = Math.pow(innerRadius, 2);
      //缩放绘制时的绘制半径,即画布的外径除以缩放比例
      var scaledRadius = Math.sqrt(Math.pow(c.width / 2, 2) + Math.pow(c.height / 2, 2)) / scaleRate;
      //由于该圆是由绕圆心的多条线段组成,该值表示将圆分割的份数
      var count = 360;
      //一整个圆的弧度值
      var doublePI = Math.PI * 2;
      //由于圆心处是多条线段的交汇点,Composite是source-over模式,所以后绘制的线段会覆盖前一个线段。另外由于采用线段模拟圆,英雌
      var deprecatedRadius = innerRadius * 0.3;
      //废弃圆半径的平方
      var pow2DeprecatedRadius = Math.pow(deprecatedRadius, 2);

      //色相(0-360)
      var hue;
      //饱和度(0%-100%)
      var saturation;
      //亮度luminance或明度lightness(0%-100%)
      var luminance;

      //当前色相位置X坐标
      var currentHuePosX = centerX + innerRadius - 1;
      //当前色相位置Y坐标
      var currentHuePosY = centerY;

      //填充圆
      function fillCircle(cx, cy, r, color) {
        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.arc(cx, cy, r, 0, doublePI);
        ctx.fill();
      }

      //绘制线条
      function strokeLine(x1, y1, x2, y2) {
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();
      }

      //将整数转为16进制,至少保留2位
      function toHexString(intValue) {
        var str = intValue.toString(16);
        if(str.length == 1) {
          str = "0" + str;
        }
        return str;
      }

      //判断坐标(x,y)是否在合法的区域内
      function isInValidRange(x, y) {
        var pow2Distance = Math.pow(x-centerX, 2) + Math.pow(y-centerY, 2);
        return pow2Distance >= pow2DeprecatedRadius && pow2Distance <= pow2InnerRadius;
      }

      //绘制十字光标
      function strokeCrossCursor(x, y) {
        ctx.globalCompositeOperation = "source-over";
        ctx.strokeColor = crossCursorColor;
        ctx.lineWidth = crossCursorLineWidth;
        strokeLine(x, y-crossCursorHalfBreakLineLen, x, y-crossCursorHalfBreakLineLen-crossCursorHalfLineLen);
        strokeLine(x, y+crossCursorHalfBreakLineLen, x, y+crossCursorHalfBreakLineLen+crossCursorHalfLineLen);
        strokeLine(x-crossCursorHalfBreakLineLen, y, x-crossCursorHalfBreakLineLen-crossCursorHalfLineLen, y);
        strokeLine(x+crossCursorHalfBreakLineLen, y, x+crossCursorHalfBreakLineLen+crossCursorHalfLineLen, y);
      }

      //将对象中的hsl分量组成一个hsl颜色(h在0到360之间,s与l均在0到1之间)
      function formHslColor(obj) {
        return "hsl(" + obj.h + "," + Math.round(obj.s * 1000)/10 + "%," + Math.round(obj.l * 1000)/10 + "%)";
      }

      //将对象中的rgb分量组成一个rgb颜色(r,g,b在0到255之间)
      function formRgbColor(obj) {
        return "rgb(" + [obj.r, obj.g, obj.b].join(",") + ")";
      }

      //从画布的某点获取存储RGB的对象
      function getRgbObj(x, y) {
        var w = 1;
        var h = 1;
        var imgData = ctx.getImageData(x,y,w,h);
        var obj = {
          r: imgData.data[0],
          g: imgData.data[1],
          b: imgData.data[2],
          a: imgData.data[3]
        }
        return obj;
      }

      //将rgb转换为hsl对象()
      function rgbToHslObj(r, g, b) {
        r /= 255;
        g /= 255;
        b /= 255;
        var max = Math.max(r, g, b);
        var min = Math.min(r, g, b);
        var diff = max - min;
        var twoValue = max + min;
        var obj = {h:0, s:0, l:0};
        if(max == min) {
          obj.h = 0;
        } else if(max == r && g >= b) {
          obj.h = 60 * (g - b) / diff;
        } else if(max == r && g < b) {
          obj.h = 60 * (g - b) / diff + 360;
        } else if(max == g) {
          obj.h = 60 * (b - r) / diff + 120;
        } else if(max == b) {
          obj.h = 60 * (r - g) / diff + 240;
        }
        obj.l = twoValue / 2;
        if(obj.l == 0 || max == min) {
          obj.s = 0;
        } else if(0 < obj.l && obj.l <= 0.5) {
          obj.s = diff / twoValue;
          //obj.s = diff / (2 * obj.l);
        } else {
          obj.s = diff / (2 - twoValue);
          //obj.s = diff / (2 - 2 * obj.l);
        }
        obj.h = Math.round(obj.h);
        return obj;
      }

      //创建Hue颜色圆环
      function createHueRing() {
        ctx.globalCompositeOperation = "source-over";
        ctx.clearRect(0,0,c.width,c.height);
        ctx.save();
        //将绘制原点移动到画布中心
        ctx.translate(centerX, centerY);
        //将画布放大相应比例,restore后,绘制内容会缩小
        ctx.scale(scaleRate, scaleRate);
        for(var i=0; i<count; i++) {
          var degree = i / count * 360;
          var radian = Math.PI * degree / 180;
          var x = scaledRadius * Math.cos(radian);
          var y = scaledRadius * Math.sin(radian);
          ctx.lineWidth=1;
          ctx.strokeStyle = "hsl(" + degree +"," + saturation + "," + luminance + ")";
          ctx.beginPath();
          ctx.moveTo(x, y);
          ctx.lineTo(0,0);
          ctx.stroke();
        }
        ctx.restore();
        ctx.globalCompositeOperation = "destination-out";
        fillCircle(centerX, centerY, deprecatedRadius, "black");

        ctx.globalCompositeOperation = "destination-in";
        fillCircle(centerX, centerY, innerRadius, "black");
      }

      //点击canvas中的Hue拾色圈
      function onCanvasClick() {
        var x = event.offsetX;
        var y = event.offsetY;
        if(!isInValidRange(x, y)) {
          return;
        }
        currentHuePosX = x;
        currentHuePosY = y;
        //创建hue背景圆环
        createHueRing();
        setColorValue(x, y);
        strokeCrossCursor(x, y);
      }

      function setColorValue(x, y) {
        //获取包含rgb的颜色对象
        var rgbObj = getRgbObj(x, y);
        var rgbColor = formRgbColor(rgbObj);
        colorDiv.style.backgroundColor = rgbColor;
        rgbValueDiv.value = rgbColor;
        var hex = "#" + toHexString(rgbObj.r) + toHexString(rgbObj.g) + toHexString(rgbObj.b);
        hexadecimalValueDiv.value = hex;

        var hslObj = rgbToHslObj(rgbObj.r, rgbObj.g, rgbObj.b);
        hslValueDiv.value = formHslColor(hslObj);
        hueTipDiv.innerHTML = ("Hue:" + hslObj.h);
      }

      function onHSLRangeChange() {
        //event.target.value;
        saturation = saturationRange.value + "%";
        luminance = luminanceRange.value + "%";
        saturationTipDiv.innerHTML = ("Saturation:" + saturation);
        luminanceTipDiv.innerHTML = ("Luminance:" + luminance);
        createHueRing();
        setColorValue(currentHuePosX, currentHuePosY)
        strokeCrossCursor(currentHuePosX, currentHuePosY);
      }

      function init() {
        c.addEventListener("click", onCanvasClick);
        onHSLRangeChange();
      }

      init();

    </script>
  </body>
</html>

有几个缺陷:

- 不能根据颜色值来设置HSL。
- 由于HSL的值是根据从Hue环形调色板中取出的RGB颜色值换算为HSL的,因此跟滑动条上的值可能会有出入(如果是5舍6入那就一样了)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • js实现拾色器插件(ColorPicker)

    对一个前端来说,颜色选择的插件肯定不陌生,许多小伙伴对这类插件的实现可能会比较好奇,这里奉上原生js版本的拾色器. 效果图: 讲下实现方式: 1.颜色除了RGB跟十六进制的表现外,还有一个HSV的表现形式.H(hue)是色相,值域是0度到360度,这个值控制的是你看到的是什么颜色,通俗点讲就是红橙黄绿...:S(saturation)是饱和度,值域是0到1,这个值控制颜色的鲜艳程度,可以理解为大红跟淡红的差别:V(value)可以理解为亮度,值域也是0到1. 2.rgb颜色跟hsv颜色的相互转化

  • HTML Color Picker(js拾色器效果)

    File Name : colorpicker.html Requirement : Internet Explorer or Mozilla Author : Jean-Luc Antoine Submitted : 26/03/2005 Category : 4K 复制代码 代码如下: <form name="recherche" method="post" action="yourpage.html"><input typ

  • JS实现的网页上的颜色拾色器

    使用Js代码编写一个网页上用的颜色拾色器,也就是选择颜色用的,用鼠标单击任意颜色块,将弹出颜色值,当你想使用某种颜色而不知道颜色值的时候,用这个小特效可以告诉你颜色值是多少,比较方便. 颜色拾色器 红 绿 蓝 灰 用鼠标单击下面的颜色块,将弹出颜色值 for(i=0;i '+ishex(i*17) +' ') document.all['Ltd' + i].num=i } function ishex(which){ return which.toString(16); } document.w

  • JQuery 拾色器插件发布-jquery.icolor.js

    以前我一直用的那个(eyecon.ro) 功能完整也简易,但是不尽符合上面的要求,于是 google了N下,结果没找到现成的jquery拾色器插件很好的支持以下功能: 简单易用,仅显示常用的那些色块给用户选择,另外提供一个输入框方便用户输入自定义的色值 于是我写了icolor这个插件,除了支持上面的要求,还有别的一些特性如下: 1,默认提供的色值为"常用的浏览器安全的色值".相当于整合了下面最后一个prototype版本的颜色拾取器.关于浏览器安全色值,可参考维基文档http://en

  • JavaScript实现HSL拾色器

    HSL 和 HSV 在数学上定义为在 RGB 空间中的颜色的 R, G 和 B 的坐标的变换. 从 RGB 到 HSL 或 HSV 的转换 设 (r, g, b) 分别是一个颜色的红.绿和蓝坐标,它们的值是在 0 到 1 之间的实数.设 max 等价于 r, g 和 b 中的最大者.设 min 等于这些值中的最小者.要找到在 HSL 空间中的 (h, s, l) 值,这里的 h ∈ [0, 360)是角度的色相角,而 s, l ∈ [0,1] 是饱和度和亮度,计算为: h 的值通常规范化到位于

  • jQuery soColorPacker 网页拾色器

    未采用生僻的jquery特性,能兼容jquery1.2.6以上所有版本 实例预览 引入文件 <link type="text/css" rel="stylesheet" media="all" href="soColorPacker/css/style.css" /> <script type="text/javascript" src="jquery1.8.0.min.js&q

  • Android Studio设置颜色拾色器工具Color Picker教程

    你可能下载过一些获取颜色值的一些小工具, 这种方式获取颜色,需要先切换窗口转跳到桌面,然后打开拾色器小工具程序,然后去拾取颜色: 你可能也知道Android Studio自带一个颜色拾色器,通过下面这种方式才能找到 这种方式获取颜色值限制性很强,需要特定的窗口,需要点击那么一小块颜色才能弹出窗口,才能使用 那有没有更好的方式? 答案是肯定的,不然这些个干嘛~~ 不用向上面那样去打开拾色器小工具程序,不用在特定的窗口点击特定的位置弹出拾色器工具,是用我们最喜欢的快捷键的方式打开 Android S

  • javascript编程开发中取色器及封装$函数用法示例

    本文实例讲述了javascript编程开发中取色器及封装$函数用法.分享给大家供大家参考,具体如下: 1.封装$函数 function $(str){ //如果传入的是'#' 则选择id标签 //如果传入的是'.' 则选择所有的类名标签 //如果传入的既不是'#也不是'.' 选择复合标签 //判断传入的值 if(typeof str !='string'){ console.log('传入的参数有误!'); return null; } //获取参数的第一个字母 var firstChar=st

  • javascript实现Table间隔色以及选择高亮(和动态切换数据)的方法

    本文实例讲述了javascript实现Table间隔色以及选择高亮(和动态切换数据)的方法.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1

  • JavaScript实现简单生成随机颜色的方法

    本文实例讲述了JavaScript实现简单生成随机颜色的方法.分享给大家供大家参考,具体如下: 如果要做出如下效果,每次刷新网页则产生一种颜色 其实非常简单,产生随机颜色的根本核心就是随机构造出一个六位数,JavaScript的随机数的问题 而且这个六位数的每一个数位0~f之内,因此就有了如下的方法: 1.首先是一个HTML布局,p标签是是用来放当前颜色的,div的背景颜色就是这个颜色 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN&quo

随机推荐