使用Javascript基于十六进制颜色计算渐变上的X,Y像素位置 [英] Calculate X,Y pixel position on gradient based on hex color using Javascript

查看:115
本文介绍了使用Javascript基于十六进制颜色计算渐变上的X,Y像素位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个raindow HSV渐变画布,当你点击它时,会在该位置添加一个元素,其背景为所点击像素的颜色。

I have a raindow HSV gradient canvas that when you click it, an element is added at that location with its background as the color of the clicked pixel.

什么我想让它反向运作。例如,如果您有一个十六进制颜色,我想在画布上找到该像素并在该位置创建一个元素。

What I'd like is to have it work in reverse as well. For example if you had a hex color, I'd like to find that pixel on the canvas and create an element at that position.

我的第一个想法是以某种方式使用矩阵/象限系统。我的下一个想法是,因为我正在使用HSV,我可以使用我的HSV渐变位置点来计算出位置。问题是我的点彼此不等,这使得它变得更难。最重要的是,我有一个白色渐变和黑色渐变覆盖主色渐变,我需要考虑到这一点。

My first thought was to somehow use a matrix/quadrant system. My next thought was that since I'm using HSV, I could use my HSV gradient location points to figure out the location. The problem is that my points aren't equidistant from each other which makes it harder. On top of that, I have a white gradient and black gradient covering the main color gradient and I need that to be accounted for.

所以我的问题是,如何通过使用十六进制代码找到颜色像素的位置或至少它最接近的匹配?

这是我的代码到目前为止:
http://codepen.io/shelbywhite/pen/EyqPWY?editors=1000

Here is my code thus far: http://codepen.io/shelbywhite/pen/EyqPWY?editors=1000

HTML:

<div class="container">
    <canvas class="colorSpectrum"></canvas>
    <div class="circle"></div>
</div>

CSS:

.container {
    background: grey;
    height: 350px;
    width: 400px;
}

.circle {
    background: transparent;
    box-shadow: 0 0 8px rgba(0,0,0,0.2);
    border-radius: 50%;
    border: 2px solid #fff;
    height: 20px;
    margin: -12px;
    width: 20px;
    position: absolute;
}

.colorSpectrum {
    display: block;  
    height: 100%;
    transform: translateZ(0);
    width: 100%;
}

Javascript:

Javascript:

$(function() {

    var closest = function(num, arr) {
        var curr = arr[0];
        var diff = Math.abs(num - curr);

        for (var val = 0; val < arr.length; val++) {
            var newdiff = Math.abs(num - arr[val]);
            if (newdiff < diff) {
                diff = newdiff;
                curr = arr[val];
            }
        }

        return curr;
    };


    var container = $('.container');
    var containerWidth = container.width();
    var containerHeight = container.height();

    var verticalGradientsHeight = Math.round(containerHeight * .34);
    console.log('verticalGradientsHeight', verticalGradientsHeight);
    var round = function(value, decimals) {
        return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
    };


    // Draws the color spectrum onto the canvas
    var drawColorSpectrum = function() {

        // Cache canvas element
        var canvasElement = $('.colorSpectrum');

        // Cache javascript element
        var canvas = canvasElement[0];

        // Get canvas context
        var ctx = canvas.getContext('2d');

        // Cache page height
        var canvasWidth = containerWidth;

        // Cache page height
        var canvasHeight = containerHeight - 72;

        // Bottom gradient start position
        var blackStartYPos = canvasHeight - verticalGradientsHeight;

        // Bottom gradient end position
        var blackEndYPos = canvasHeight;

        // Create white gradient element
        var white = ctx.createLinearGradient(0, 0, 0, verticalGradientsHeight);

        // Create black gradient element
        var black = ctx.createLinearGradient(0, blackStartYPos, 0, blackEndYPos);

        // Create new instance of image
        var img = new Image();


        // Cache container
        _colorSpectrumContainer = canvasElement.parent();

        // Set global var
        spectrumCanvas = canvasElement;

        // Set width of canvas
        canvas.width = canvasWidth;

        // Set height of canvas
        canvas.height = canvasHeight;

        // Image load listener
        img.onload = function() {

            // Draw intial image
            ctx.drawImage(this, 0, 0, canvasWidth, canvasHeight);

            // Draw white to transparent gradient
            white.addColorStop(0, "hsla(0,0%,100%,1)");
            white.addColorStop(0.05, "hsla(0,0%,100%,1)");
            white.addColorStop(0.20, "hsla(0,0%,100%,0.89)");
            white.addColorStop(0.38, "hsla(0,0%,100%,0.69)");
            white.addColorStop(0.63, "hsla(0,0%,100%,0.35)");
            white.addColorStop(0.78, "hsla(0,0%,100%,0.18)");
            white.addColorStop(0.91, "hsla(0,0%,100%,0.06)");
            white.addColorStop(1, "hsla(0,0%,100%,0)");
            ctx.fillStyle = white;
            ctx.fillRect(0, 0, canvasWidth, verticalGradientsHeight);

            // Draw black to transparent gradient
            black.addColorStop(0, "hsla(0,0%,0%,0)");
            black.addColorStop(0.20, "hsla(0,0%,0%,0.01)");
            black.addColorStop(0.28, "hsla(0,0%,0%,0.04)");
            black.addColorStop(0.35, "hsla(0,0%,0%,0.09)");
            black.addColorStop(0.51, "hsla(0,0%,0%,0.26)");
            black.addColorStop(0.83, "hsla(0,0%,0%,0.69)");
            black.addColorStop(1, "hsla(0,0%,0%,1)");

            ctx.fillStyle = black;
            ctx.fillRect(0, blackStartYPos, canvasWidth, verticalGradientsHeight);
        }

        // Set image source
        img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAABCAYAAACbv+HiAAAA0ElEQVR4AYWSh2oDMAwFz6u7//+d2YmXalGBIBM47nnPIIEtmd8FGBTgDbPxDmbn49pX+cZX+Nz4mkZ2SECEAXTCAprlalntBC5whdUJnOfKEy5DjZYtB+o0D3XUMk0tkaZZEn2VuyiJQQQywS/P4c25ucTrfF3ndsoVdjmy3NMiuptR1eHfNcBFM2orW1ZXru00JZiBDrIII5AG5AlloX5TcG6/ywuuv0zAbyL4TWRZmIvU5TNBTjCPIIu5N3YgO7Wxtbot3q4+2LgTyFnZ/QHzBZD1KDpyqQAAAABJRU5ErkJggg==";
    };


    // 
    var hexToRgb = function(hex) {

        hex = hex.replace('#','');

        r = parseInt(hex.substring(0, 2), 16);
        g = parseInt(hex.substring(2, 4), 16);
        b = parseInt(hex.substring(4, 6), 16);

        return [r, g, b];
    };


    // 
    var rgbToHsb = function(r, g, b) {

        var rr, gg, bb,
            r = r / 255,
            g = g / 255,
            b = b / 255,
            h, s,
            v = Math.max(r, g, b),
            diff = v - Math.min(r, g, b),
            diffc = function(c){
                return (v - c) / 6 / diff + 1 / 2;
            };

        if (diff == 0) {
            h = s = 0;
        } else {
            s = diff / v;
            rr = diffc(r);
            gg = diffc(g);
            bb = diffc(b);

            if (r === v) {
                h = bb - gg;
            }else if (g === v) {
                h = (1 / 3) + rr - bb;
            }else if (b === v) {
                h = (2 / 3) + gg - rr;
            }
            if (h < 0) {
                h += 1;
            }else if (h > 1) {
                h -= 1;
            }
        }

        return {
            h: Math.round(h * 360),
            s: Math.round(s * 100),
            b: Math.round(v * 100)
        };
    };


    // Find hue in stop range
    var findHueInStopRange = function(hue) {

        // Array of hue stops with HSV, RGB, and HEX info
        var stops = [{
            h: 0,
            l: 0,
            s: 100,
            b: 100
        }, {
            h: 60,
            l: 21,
            s: 100,
            b: 100
        }, {
            h: 120,
            l: 40,
            s: 85,
            b: 85
        }, {
            h: 180,
            l: 56,
            s: 85,
            b: 85
        }, {
            h: 237,
            l: 72,
            s: 86,
            b: 96
        }, {
            h: 300,
            l: 89,
            s: 86,
            b: 96
        }, {
            h: 359,
            l: 100,
            s: 100,
            b: 100
        }];

        // Total number of stops
        var stopsLength = stops.length;

        // Loop through stops
        for (var i = 0; i < stopsLength; i += 1) {

            // Temp set
            var currentStop = stops[i];

            // Temp set
//             var nextStop = stops[i + 1];
            var nextStop = (i + 1 > stopsLength - 1) ? currentStop : stops[i + 1];

            // Location is a percentage
            var huePos;

            // Temp set
            var xPos = false;

            console.log('hue', currentStop.h, '>>', hue, '<<', nextStop.h);
            // Find which range of hue stops the current color is 
            // Hue is between current and next hue stop
            if (hue >= currentStop.h && hue <= nextStop.h) {

                // hue is current stop
                if (hue === currentStop.h) {

                    // Set as location
                    huePos = currentStop.l;

                    // hue is next stop
                } else if (hue === nextStop.h) {

                    // Set as location
                    huePos = nextStop.l;

                // Hue is somewhere between stops
                } else {

                    // Get percentage location between hue stops
                    var relativeHuePos = (hue - currentStop.h) / (nextStop.h - currentStop.h);

                    // Normalized to fit custom gradient stop locations
                    huePos = relativeHuePos * (nextStop.l - currentStop.l) + currentStop.l;
                }

                // A location was found
                if (huePos) {

                    // Convert from percentage to pixel position
                    xPos = Math.round(containerWidth * (huePos / 100));

                    return xPos;

                } else {

                    continue;
                }
            }
        }
    };


    // Find saturation in stop range
    var findSaturationInStopRange = function (saturation) {

        // Array of hue stops with HSV, RGB, and HEX info
        var stops = [{
            l: 0,
            s: 0
        }, {
            l: 0.05,
            s: 6
        }, {
            l: 0.20,
            s: 18
        }, {
            l: 0.38,
            s: 35
        }, {
            l: 0.63,
            s: 69
        }, {
            l: 0.78,
            s: 89,
        }, {
            l: 0.91,
            s: 100,
        }, {
            l: 1,
            s: 100,
        }];

        // Total number of stops
        var stopsLength = stops.length;

        // Loop through stops
        for (var i = 0; i < stopsLength; i += 1) {

            // Temp set
            var currentStop = stops[i];

            // Temp set
            var nextStop = (i + 1 > stopsLength - 1) ? currentStop : stops[i + 1];

            // Location is a percentage
            var satPos;

            // Temp set
            var yPos = false;

            // Convert location to percentage
            var currentStopLocation = currentStop.l * 100;

            // Convert location to percentage
            var nextStopLocation = nextStop.l * 100;


            // Find which range of hue stops the current color is 
            // Hue is between current and next hue stop
            if (saturation >= currentStop.s && saturation <= nextStop.s) {

                // hue is current stop
                if (saturation === currentStop.s) {

                    // Set as location
                    satPos = currentStopLocation;

                    // hue is next stop
                } else if (saturation === nextStop.s) {

                    // Set as location
                    satPos = nextStopLocation;

                // Hue is somewhere between stops
                } else {

                    // Get percentage location between gradient stops
                    var ratioBetweenSaturation = (saturation - currentStop.s) / (nextStop.s - currentStop.s);

                    // Normalized to fit custom gradient stop locations
                    satPos = ratioBetweenSaturation * (nextStopLocation - currentStopLocation) + currentStopLocation;
                }

                console.log('ratioBetweenSaturation', ratioBetweenSaturation);
                console.log('satPos', satPos);
                console.log('saturation', saturation, '>=', currentStop.s, saturation, '<=', nextStop.s);

                // A location was found
                if (satPos !== false) {

                    // Convert from percentage to pixel position
                    yPos = Math.round(verticalGradientsHeight * (satPos / 100));

                    return yPos;

                } else {

                    continue;
                }
            }
        }
    };


    // Find brightness in stop range
    var findBrightnessInStopRange = function (brightness) {

        // Array of hue stops with HSV, RGB, and HEX info
        var stops = [{
            l: 0,
            b: 100
        }, {
            l: 0.20,
            b: 88
        }, {
            l: 0.28,
            b: 69
        }, {
            l: 0.35,
            b: 26
        }, {
            l: 0.51,
            b: 9
        }, {
            l: 0.83,
            b: 4,
        }, {
            l: 1,
            b: 0,
        }];

        // Total number of stops
        var stopsLength = stops.length;

        // Loop through stops
        for (var i = 0; i < stopsLength; i += 1) {

            // Temp set
            var currentStop = stops[i];

            // Temp set
            var nextStop = (i + 1 > stopsLength - 1) ? currentStop : stops[i + 1];

            // Location is a percentage
            var brightPos;

            // Temp set
            var yPos = false;

            // Convert location to percentage
            var currentStopLocation = currentStop.l * 100;

            // Convert location to percentage
            var nextStopLocation = nextStop.l * 100;

            console.log('brightness', brightness, '>=', currentStop.b, brightness, '<=', nextStop.b);


            // Find which range of hue stops the current color is 
            // Hue is between current and next hue stop
            if (brightness <= currentStop.b && brightness >= nextStop.b) {

                // hue is current stop
                if (brightness === currentStop.b) {

                    // Set as location
                    brightPos = currentStopLocation;

                    // hue is next stop
                } else if (brightness === nextStop.b) {

                    // Set as location
                    brightPos = nextStopLocation;

                // Hue is somewhere between stops
                } else {

                    // Get percentage location between gradient stops
                    var ratioBetweenBrightness = (brightness - currentStop.b) / (nextStop.b - currentStop.b);

                    // Normalized to fit custom gradient stop locations
                    brightPos = ratioBetweenBrightness * (nextStopLocation - currentStopLocation) + currentStopLocation;
                }

                console.log('ratioBetweenBrightness', ratioBetweenBrightness);
                console.log('brightPos', brightPos);
                console.log('brightness', brightness, '>=', currentStop.b, brightness, '<=', nextStop.b);

                // A location was found
                if (brightPos !== false) {

                    // Convert from percentage to pixel position
                    yPos = Math.round(verticalGradientsHeight * (brightPos / 100));

                    return yPos;

                } else {

                    continue;
                }
            }
        }
    };


    // Get coordinates from hue, brightness, saturation
    var getColorCoordinates = function (hex) {

        // Convert hex to rgb
        var rgb = hexToRgb(hex);
        console.log('rgb', rgb);
        // Convert rgb to hsb
        var hsb = rgbToHsb(rgb[0], rgb[1], rgb[2]);
        console.log('hsb', hsb);

        // Set x position to position of hue
        var xPos = findHueInStopRange(hsb.h);
        var yPos = 0;


        //  if 100, get (containerHeight - verticalGradientHeight) + whatever position is set with bottom gradient

        // 

        // Saturation and brightness are both maxed
        if (hsb.s === 100 && hsb.b === 100) {

            // Set y position at center of container
            yPos = containerHeight * 0.5;

        } else {
                console.log('using nothing', hsb.s, hsb.b);

            //
            if (hsb.s < 100) {

                // Saturation y position (upper quadrant)
                yPos = findSaturationInStopRange(hsb.s);
                console.log('using saturation', yPos);

            } else if (hsb.b < 100) {

                // Brightness y position (lower quadrant)
                yPos = findBrightnessInStopRange(hsb.b);
                console.log('using brightness', yPos);
            }
        }

        return { x: xPos, y: yPos };
    }


    // Get hue location
    var position = false;

    // Temp set
    var hex = '42ad40';

    // Draw gradient
    drawColorSpectrum();

    // Find x position
    position = getColorCoordinates(hex); //91ff26

    console.log('location', position);

    // Draw line
    $('.circle').css({
        top: position.y + 'px',
        left: position.x + 'px',
        background: '#' + hex
    });
});

**更新**

I实际上我试图在HSV而不是HSL中这样做。除了我使用photoshop生成平滑渐变之外,我没有其他偏好。

I'm actually trying to do this in HSV not HSL. I don't have preference other than I used photoshop to generate a smooth gradient.

此外,我添加了一个新示例,其中包含了我创建的内容。下面的一个最高投票的答案提示如何完成我想要做的事情,但到目前为止我还没能成功地做到这一点。

Also, I have added a new example with what I have created. One of the up-voted answers below hints at how to accomplish what I'm trying to do, but so far I haven't been able to successfully do it.

更新后的代码将在此链接中,我还更新了上面的代码:
http:// codepen .io / shelbywhite / pen / EyqPWY?editors = 1000

Updated code will be at this link, I've also updated the code above: http://codepen.io/shelbywhite/pen/EyqPWY?editors=1000

推荐答案

要获取您需要HSL值的位置

To get the location you need the HSL values

// global 
var RGB = [0,0,0]; // holds the RGB values 0-255
var LSH = [0,0,0]; // holds the LSH values (note H is normalised to 0-255)
var rgbToLSH = function(){
    var r = RGB[0]/255;
    var g = RGB[1]/255;
    var b = RGB[2]/255;
    var min = Math.min(r,g,b);
    var max = Math.max(r,g,b);
    var lum = (min+max)/2;
    if(lum > 0.5){
        var sat = (max-min)/(max+min);
    }else{
        var sat = (max-min)/(2-max-min);
    }
    if(r >= b && r >= g){
        var hue = (g-b)/(max-min);
    }else
    if(b >= b && b >= g){
        var hue = 4.0 + (r-g)/(max-min);
    }else{
        var hue = 2.0 + (b-r)/(max-min);
    }
    hue *= 60;
    if(hue < 0) hue += 360;
    hue = (hue/360);
    lum = Math.min(1,Math.max(0,lum));
    sat = Math.min(1,Math.max(0,sat));
    hue = Math.min(1,Math.max(0,hue));
    LSH[0] = lum*255;
    LSH[1] = sat*255;
    LSH[2] = hue*255;

}

Hue将给出x轴上的位置和饱和度从顶部到中途给你y,Lightness会从中间到底部给你y轴位置(以你的例子为准);

Hue will give the position on the x axis and Saturation will give you y from top to midway and Lightness will give you y axis position from midway to the bottom (going by your example);

这篇关于使用Javascript基于十六进制颜色计算渐变上的X,Y像素位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆