我有一个raindow HSV渐变画布,当你点击它时,会在该位置添加一个元素,其背景为所点击像素的颜色。
我想要的是让它反向运作。例如,如果你有一个十六进制颜色,我想在画布上找到那个像素并在那个位置创建一个元素。
我的第一个想法是以某种方式使用矩阵/象限系统。我的下一个想法是,因为我使用HSV,我可以使用我的HSV梯度位置点来计算位置。问题是我的观点彼此不等,这使得它变得更难。最重要的是,我有一个白色渐变和黑色渐变覆盖主色渐变,我需要考虑到这一点。
所以我的问题是,如何通过使用十六进制代码找到彩色像素的位置或者至少它是否匹配最近?
到目前为止,这是我的代码: 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:
$(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
});
});
**更新**
我实际上是想在HSV而不是HSL中这样做。除了使用photoshop生成平滑的渐变之外,我没有其他偏好。
另外,我已经添加了一个新例子,我已经创建了。下面的一个最高投票的答案暗示了如何完成我想要做的事情,但到目前为止我还没能成功地做到这一点。
更新的代码将在此链接上,我还更新了上面的代码: http://codepen.io/shelbywhite/pen/EyqPWY?editors=1000
答案 0 :(得分:3)
要获取您需要HSL值的位置
// 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轴从中到下的位置(以你的例子为准);
答案 1 :(得分:1)
您可以遍历整个ImageData
并比较两种颜色。
var findPixelByHex = function(imageData, hex) {
var d = imageData.data
var w = imageData.width
var h = imageData.height
for (var y = 0; y < h; ++y) {
for (var x = 0; x < w; ++x) {
var i = (y * w + x) * 4
if (hex === rgbToHex(d[i], d[i + 1], d[i + 2])) {
setColorAtPixel(x, y, hex)
}
}
}
}
请注意,这非常慢,不是最好的主意。