Showing posts with label color. Show all posts
Showing posts with label color. Show all posts

Monday, February 1, 2016

Generating Color Gradients with JavaScript

The comic frames with the color
gradient backgrounds.
For the comic on Friday, I had to generate a color gradient between the full-brightness daylight color in the third frame and the nighttime darkness color in the fourth frame. Since the point of the comic was to adjust the brightness using a slider with 20 positions, I needed 40 colors (including the 2 starting colors) so that when the brightness was all the way down both frames would have the same background. They would meet in the middle.

It was actually a very nice comic. On the right you can see the frames with the color gradients, but the real comic is interactive - go play around with it if you haven't yet!

To generate the gradient of colors, I found a set of JavaScript functions which I will share here. I can't take credit for it, all I did was rearrange some of the code and re-order the output (the original seemed backwards to me) but it is very nice. I am keeping it in the source code for the Amphibian.com comic editor in case I ever need it again.

Here is the function. Calling it should be self-explanatory. Note that the colorCount parameter will be the total size of the output array INCLUDING the start and end colors.

function generateColorGradient(colorStart, colorEnd, colorCount) {

    /* Convert a hex string to an RGB triplet */
    var convertToRGB = function(hex) {

        /* Remove '#' in color hex string */
        var trim = function(s) {
            return (s.charAt(0) == '#') ? s.substring(1, 7) : s;
        };

        var color = [];
        color[0] = parseInt((trim(hex)).substring(0, 2), 16);
        color[1] = parseInt((trim(hex)).substring(2, 4), 16);
        color[2] = parseInt((trim(hex)).substring(4, 6), 16);
        return color;

    };

    /* Convert an RGB triplet to a hex string */
    var convertToHex = function(rgb) {

        var hex = function(c) {
            var s = "0123456789abcdef";
            var i = parseInt(c);
            if (i == 0 || isNaN(c))
                return "00";
            i = Math.round(Math.min(Math.max(0, i), 255));
            return s.charAt((i - i % 16) / 16) + s.charAt(i % 16);
        };

        return hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);

    };

    var start = convertToRGB(colorStart);
    var end = convertToRGB(colorEnd);

    // The number of colors to compute
    var len = colorCount - 1;

    //Alpha blending amount
    var alpha = 0.0;

    var ret = [];
    ret.push(convertToHex(start));

    for (i = 0; i < len; i++) {
        var c = [];
        alpha += (1.0 / len);
        c[0] = end[0] * alpha + (1 - alpha) * start[0];
        c[1] = end[1] * alpha + (1 - alpha) * start[1];
        c[2] = end[2] * alpha + (1 - alpha) * start[2];
        ret.push(convertToHex(c));
    }

    ret[len] = convertToHex(end); // last color might be slightly off

    return ret;

}

One thing that I noticed is that for colorCount values greater than 13 the final color was not quite the requested final color. Rounding error I suppose. That's why I explicitly set the last element in the return array to the end color, if you were wondering.

Using jQuery, I wrote a simple demonstration of the gradient function:

    var things = generateColorGradient("#CC0033", "#FFFF66", 15);
    for (var i = 0; i < things.length; i++) {
        $("body").append("<div style='background-color: #" + things[i] + ";'>test</div>");
    }


...which produces the following output on a web page. Beautiful, isn't it?


Today's comic, on the other hand, contains absolutely nothing of any technical interest. You should still read it though. And if you haven't read all the other Amphibian.com comics, what are you waiting for? They don't take that long to read. Start today!

Amphibian.com comic for 1 February 2016

Monday, October 26, 2015

Animate Colors with jQuery

While working on an upcoming comic, I wanted to add a color-change effect to an element. I soon learned that jQuery's animate() function doesn't support animation of non-numeric CSS properties. So while I can animate a width between 100px and 200px, for example, I can't animate a color between #000000 and #FF00FF.

But all is not lost! There is a plugin, appropriately named jQuery Color, which adds the color animation feature. It is trivial to use and extremely small to download.

To start using it, just download the .js file from their GitHub page. I am using the minified version. Include it in your page after jQuery. Then, just animate colors the same way you would animate other CSS properties and it will magically work!

In the following example, the page starts out containing a DIV with a black background. As soon as jQuery is ready, an animation changes the background color to purple over a span of 10 seconds.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Color Animation</title>
</head>

<body>

  <div id="test-div" style="width: 500px; height: 300px; background-color: #000000;"></div>

</body>

<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
<script>

$(function() {

    $('#test-div').animate({backgroundColor: '#FF00FF'}, 10000);

});

</script>

</html>

It doesn't get much easier than that! But what comic prompted me to use this? It's not for today's. You'll just have to wait to find out (or look in the repository on GitHub).

Amphibian.com comic for 26 October 2015

Friday, August 8, 2014

JavaScript Colors: RGB to HEX

In my web comic editor, I needed to be able to both read and set the background color values on HTML elements. Since I've been working with colors as hex codes since, umm, forever, I thought it would be good to work with the colors that way. But to my dismay, I found that you can set the color of an element using a hex string (e.g. #ff0000), an RGB string (e.g. rgb(255,0,0)), or an HSL string (e.g. hsl(360,100%,50%)) but when you read the value it is always in RGB format. Here's an example:

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Color Test</title>
</head>

<body>

<div id="hextest" style="background-color: #FF0000; width: 100px; height: 100px;"></div>

<div id="rgbtest" style="background-color: rgb(0,255,0); width: 100px; height: 100px;"></div>

<div id="hsltest" style="background-color: hsl(240,100%,50%); width: 100px; height: 100px;"></div>

</body>

<script>

var a = document.getElementById('hextest').style.backgroundColor;
var b = document.getElementById('rgbtest').style.backgroundColor;
var c = document.getElementById('hsltest').style.backgroundColor;

console.log(a);
console.log(b);
console.log(c);

</script>

</html>


Maybe you've had this problem yourself. Fortunately, I found a handy JavaScript function that will convert RGB strings back into hex. It is a very compact and interesting function. Let's take a look at it.

function rgb2hex(rgb) {
 
 function hex(x) {
  return ("0" + parseInt(x).toString(16)).slice(-2);
 }
 var r = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
 var h = '#' + hex(r[1]) + hex(r[2]) + hex(r[3]);
 return h.toUpperCase();

}

There's a lot of good JavaScript to learn about here. First, you may notice that the function has another function declared inside of it. The inner function, hex, is essentially private to the rgb2hex function the same as a variable definition would be. It's like an anonymous inner function that isn't so anonymous. So what's the hex function doing?

It assumes, first of all, that you give it a String representation of an integer. Like "35" or something. The parseInt() function turns that into a JavaScript Number so that you can call toString(16) on it. What does that do, you ask? The parameter "16" is the radix. Without going into too much detail about what a radix is, just know that using radix 2 will give you the number's value in binary, radix 8 will give you the number's value in octal, and radix 16 gives you the number's value in hexadecimal. So calling toString(16) on a Number object with value 28 will give you the String "1c". But what's up with the fact that "0" is prepended to that value and then the whole thing is sliced with a slice parameter of -2? That's just a simple way of making sure that the return value of the function is always 2 characters and is left-padded with zeros. If the input to the function is less than 16, then the toString(16) call will return a String that is only 1 character long. But if the input is greater than 15, the result will be at least 2 characters. So if we always put a "0" in front and then just return the last two characters of the String, it will ensure that the hex value is 0-padded. Using slice() with a negative value as the parameter is a trick that returns the characters from the end of the String instead of the beginning. For example, "whatnot".slice(-3) returns "not".

Wow, that's quite a lot going on in that one line of JavaScript. The rest of the rgb2hex function isn't quite so tricky. Line 6 just uses a regular expression to find the 3 numbers in the RGB string. For example, with an input String of "rgb(100,200,150)" the value for r will be an array containing the values "100", "200", and "150". Line 7 just uses those three values as parameters to the hex function and sticks the "#" on the front. The last line returns the complete value in all upper case, since I like #FFFFFF better than #ffffff.

Anyway, I hope this function is as helpful to you as it was to me.

Amphibian.com comic for August 8, 2014