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 percentage position, and i want to get the hex or rgb color code based on this value.
My idea was to create an array with the start/stop positions and colors defined, then find two values from this array based on the slider position, then somehow find the color between: this is where i can't move forward.
Demo: http://jsfiddle.net/pdu8rpfv/
var gradient = [
[
0,
'ff0000'
],
[
28,
'008000'
],
[
72,
'0000ff'
],
[
100,
'ff0000'
]
];
$( "#slider" ).slider({
min: 1,
slide: function( event, ui ) {
var colorRange = []
$.each(gradient, function( index, value ) {
if(ui.value<=value[0]) {
colorRange = [index-1,index]
return false;
}
});
$('#result').css("background-color", 'red');
}
});
Linear Gradient - Transparency To add transparency, we use the rgba() function to define the color stops. The last parameter in the rgba() function can be a value from 0 to 1, and it defines the transparency of the color: 0 indicates full transparency, 1 indicates full color (no transparency).
Gradients can be used to fill rectangles, circles, lines, text, etc. Shapes on the canvas are not limited to solid colors. There are two different types of gradients: createLinearGradient(x,y,x1,y1) - creates a linear gradient.
Select the Gradient tool in the toolbar. In the selected artwork you'll see the gradient annotator, which shows the gradient slider and the color stops. Double-click a color stop on the artwork to edit the color, drag the color stops, click beneath the gradient slider to add new color stops, and more.
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/
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)
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>
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) {
console.log('>> fade: ', fadeFraction)
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 EXAMPLE:
var spans = $('.gradient-test');
var count = spans.length, color;
var color1 = {
red: 19, green: 233, blue: 19
};
var color3 = {
red: 255, green: 0, blue: 0
};
var color2 = {
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 = +g === 100 ? 1 : +('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>
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.
Using similar logic as Felipe Ribeiro's top answer,
I have created a Javascript color-scales
that handles it for you. You are also able to input multiple color stops as well as set a transparency level.
A live demo is here: https://codepen.io/dalisc/pen/yLVXoeR
Link to the package is here: https://www.npmjs.com/package/color-scales
Example usage:
const ColorScale = require("color-scales");
let colorScale = new ColorScale(0, 100, ["#ffffff", "#000000"], 0.5);
let rgbaStr = colorScale.getColor(50).toRGBAString(); // returns "rgba(127,127,127, 0.5)"
The package is able to output a hex, rgb, or rgba string depending on your needs. It can also output a custom Color object ({r,g,b,a}) in case you need to cherry-pick the individual color components.
I came across a similar issue when trying to mimick a Tableau dashboard on a Javascript-based application. I realised it is a common feature of data visualization tools such as Tableau and Microsoft Excel, so I have created an npm package to handle it on Javascript application. If you would like to reduce your code, you could use the package.
This is my realization for multiple color gradient set RGB. (Without alpha channel). Extended variant of previous answer.
r1.addEventListener('change',(ev)=>{
let res = test(ev.target.value)
d2.innerText=ev.target.value +' color: '+res
d2.style.backgroundColor = res
})
function test(value){
let colorPicked = pickRgbRange(value,
{color:[255,0,228,1], position:0},
{color:[0,194,255,1,1], position:15},
{color:[35,200,0,1], position:35},
{color:[255, 250, 164], position:50},
{color:[255,0,0,1], position:75},
{color:[0,0,0,1], position:100}
);
let resultRgba = `rgba(${colorPicked[0]},${colorPicked[1]},${colorPicked[2]},${colorPicked[3]})`;
return resultRgba
}
//(ildarin cc0) Start copy from here: ----------------------------------
/** @description usage
let colorPickedRgba = pickRgbRange(value,
{color:[255,0,228,1], position:0},
{color:[0,194,255,1,0.5], position:.15},
{color:[35,200,0,1], position:.35},
{color:[255, 250, 164], position:.50},
{color:[255,0,0,1], position:.75},
{color:[0,0,0,1], position:.100}
)
let resultRgba = `rgba(${colorPicked[0]},${colorPicked[1]},${colorPicked[2]},${colorPicked[3]})`
*/
function pickRgbRange(position, ...elements) {
var [left, right, weight] = pickClosest(position, ...elements);
return pickRgba(left.color, right.color, weight);
}
function pickRgba(color1, color2, weight) {
var w1 = weight;
var w2 = 1 - w1;
var rgba = [
Math.round(color1[0] * w2 + color2[0] * w1),
Math.round(color1[1] * w2 + color2[1] * w1),
Math.round(color1[2] * w2 + color2[2] * w1),
1
];
return rgba;
}
function pickClosest(position, ...elements) {
var left = elements[0],
right = { color: [0, 0, 0], position: Number.MAX_VALUE };
var leftIndex = 0;
for (var i = 0; i < elements.length; i++) {
if (position >= elements[i].position && position > left.position){
left = elements[i];
leftIndex = i;
}
}
if (elements.length - 1 === leftIndex) {
right = elements[leftIndex];
}
else {
right = elements[leftIndex + 1];
}
if(left == right){
return [right, right, 0];
}
var dleft = position - left.position;
var sum = dleft + right.position - position;
var weight = dleft / sum;
return [left, right, weight];
}
#r1{
width:100%;
}
#d1,
#d2 {
width: 100%;
height: 50px;
}
#d1 {
background: linear-gradient(90deg,
rgb(255, 0, 228) 0%,
rgb(0, 194, 255) 15%,
rgb(35, 200, 0) 35%,
rgb(255, 250, 164) 50%,
rgb(255, 0, 0) 75%,
rgb(0, 0, 0) 100%);
}
#d2 {
text-shadow:0 0 4px #fff;
background-color: #ccc;
}
<div id='d1'></div>
<input id='r1' type='range' />
<div id='d2'></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With