I have a fixed width div with gradient applied using css. I want to build slider based color picker based on this gradient.
When i drag the slider i calculate the pe
Just in case someone wants a 3 color gradient, here's an example using red, yellow and green:
The github JS code for the colorGradient
function is available here.
function colorGradient(fadeFraction, rgbColor1, rgbColor2, rgbColor3) {
var color1 = rgbColor1;
var color2 = rgbColor2;
var fade = fadeFraction;
// Do we have 3 colors for the gradient? Need to adjust the params.
if (rgbColor3) {
fade = fade * 2;
// Find which interval to use and adjust the fade percentage
if (fade >= 1) {
fade -= 1;
color1 = rgbColor2;
color2 = rgbColor3;
}
}
var diffRed = color2.red - color1.red;
var diffGreen = color2.green - color1.green;
var diffBlue = color2.blue - color1.blue;
var gradient = {
red: parseInt(Math.floor(color1.red + (diffRed * fade)), 10),
green: parseInt(Math.floor(color1.green + (diffGreen * fade)), 10),
blue: parseInt(Math.floor(color1.blue + (diffBlue * fade)), 10),
};
return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')';
}
// Gradient Function
function colorGradient(fadeFraction, rgbColor1, rgbColor2, rgbColor3) {
var color1 = rgbColor1;
var color2 = rgbColor2;
var fade = fadeFraction;
// Do we have 3 colors for the gradient? Need to adjust the params.
if (rgbColor3) {
fade = fade * 2;
// Find which interval to use and adjust the fade percentage
if (fade >= 1) {
fade -= 1;
color1 = rgbColor2;
color2 = rgbColor3;
}
}
var diffRed = color2.red - color1.red;
var diffGreen = color2.green - color1.green;
var diffBlue = color2.blue - color1.blue;
var gradient = {
red: parseInt(Math.floor(color1.red + (diffRed * fade)), 10),
green: parseInt(Math.floor(color1.green + (diffGreen * fade)), 10),
blue: parseInt(Math.floor(color1.blue + (diffBlue * fade)), 10),
};
return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')';
}
// Implementation sample
var spans = $('.gradient-test');
var count = spans.length, color;
var color1 = {
red: 19, green: 233, blue: 19
};
var color2 = {
red: 255, green: 0, blue: 0
};
var color3 = {
red: 255, green: 255, blue: 0
};
$('.gradient-test').each(function(i, span) {
var g = Math.round(((i+1) * 100) / count);
if (g < 10){
g = '0' + g;
}
g = +('0.' + g)
color = colorGradient(g, color1, color2, color3);
$(span).css('background-color', color);
});
.gradient-test {
width: 1rem;
height: 1rem;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
<span class="gradient-test"></span>
There is a nice lib that handles variety of color manipulations chroma.js
yarn add chroma-js
And then
import chroma from 'chroma-js';
const f = chroma.scale(['yellow', 'red', 'black']);
console.log( f(0.25).toString() ); // #ff8000
console.log( f(0.5).css('rgba') ); // rgba(255,0,0,1)
console.log( f(0.75).css() ); // rgb(128,0,0)
console.log( f(1).css() ); // rgb(0,0,0)
I was able to solve this issue using this function, which is based on the less.js function: http://lesscss.org/functions/#color-operations-mix
function pickHex(color1, color2, weight) {
var w1 = weight;
var w2 = 1 - w1;
var rgb = [Math.round(color1[0] * w1 + color2[0] * w2),
Math.round(color1[1] * w1 + color2[1] * w2),
Math.round(color1[2] * w1 + color2[2] * w2)];
return rgb;
}
I just simply need to pass the two closest color codes from the gradient array and the ratio where the slider handle is located(which can be calculated easily with the help of the slider width). Here is the live example:
http://jsfiddle.net/vksn3yLL/
This is another way to convert percentage to color
This exemple make a displayed value change from red to green depending on it's value (like for example in excel conditional formating):
function(percentValue) {
$(`#output`)
// print the value
.html(percentValue)
// colorize the text, more red if it's close to 0
// and more green as it approach 100
.css({color: `rgb(${(100 - percent) *2.56}, ${percent *2.56},0)`})
}
Please see demo below:
$('button').click( e => {
const percent = Math.floor(Math.random()*100);
const newElm = $(`<b>${percent}</b><br>`)
.css({color: `rgb(${(100 - percent) *2.56},${percent *2.56},0)`})
$('body').append(newElm);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Click to make new percentage</button><br>
If your have 2, 3, 4 or twenty colors you can use this solution. Generate an HTML
element and style it with CSS
gradient background. Then look at a single pixel color value.
Create a <canvas>
element. with width of 101px (0 to 100 percent) and height 1px (we don't care about height). Then set the background-color to gradient. See method initCanvas(colorsArray)
.
Look at a single pixel of the canvas, and return it's color. See method getColor(percent)
.
At the end you can find and example of gradient made from 5 colors (red, orange, green, lime, blue).
const WIDTH = 101; // 0 to 100
const HEIGHT = 1;
let context;
function initCanvas(gradientColors) // gradientColors [colorA, colorB, ..]
{
// Canvas
const canvasElement = document.createElement("CANVAS");
canvasElement.width = WIDTH;
canvasElement.height = HEIGHT;
context = canvasElement.getContext("2d");
// Gradient
const gradient = context.createLinearGradient(0, 0, WIDTH, 0); // x0, y0, x1, y1
const step = 1 / (gradientColors.length - 1); // need to validate at least two colors in gradientColors
let val = 0;
gradientColors.forEach(color => {
gradient.addColorStop(val, color);
val += step;
});
// Fill with gradient
context.fillStyle = gradient;
context.fillRect(0, 0, WIDTH, HEIGHT); // x, y, width, height
}
function getColor(percent) // percent [0..100]
{
const color = context.getImageData(percent, 0, 1, 1); // x, y, width, height
const rgba = color.data;
return `rgb(${ rgba[0] }, ${ rgba[1] }, ${ rgba[2] })`;
}
// Test:
initCanvas(['red', 'orange', 'green', 'lime', 'blue']);
document.getElementById("color0" ).style.backgroundColor = getColor(0);
document.getElementById("color10" ).style.backgroundColor = getColor(10);
document.getElementById("color20" ).style.backgroundColor = getColor(20);
document.getElementById("color30" ).style.backgroundColor = getColor(30);
document.getElementById("color40" ).style.backgroundColor = getColor(40);
document.getElementById("color50" ).style.backgroundColor = getColor(50);
document.getElementById("color60" ).style.backgroundColor = getColor(60);
document.getElementById("color70" ).style.backgroundColor = getColor(70);
document.getElementById("color80" ).style.backgroundColor = getColor(80);
document.getElementById("color90" ).style.backgroundColor = getColor(90);
document.getElementById("color100").style.backgroundColor = getColor(100);
.example {
width: 100px;
height: 25px;
}
<h3>Gradient colors: red, orange, green, lime, blue</h3>
<div id="color0" class="example">0% </div>
<div id="color10" class="example">10% </div>
<div id="color20" class="example">20% </div>
<div id="color30" class="example">30% </div>
<div id="color40" class="example">40% </div>
<div id="color50" class="example">50% </div>
<div id="color60" class="example">60% </div>
<div id="color70" class="example">70% </div>
<div id="color80" class="example">80% </div>
<div id="color90" class="example">90% </div>
<div id="color100" class="example">100%</div>
P.S - I code with two methods initCanvs()
and getColors()
so you won't generate new canvas for each color selection. But you can merge them if you have new gradient each time.