Functional Gradients

In this example below you will see how to do a Functional Gradients with some HTML / CSS and Javascript

Exploring the difference between RGB and HSV gradients with a sprinkling of functional javascript programming

Thumbnail
This awesome code was written by 32bitkid, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright 32bitkid ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Functional Gradients</title>
  
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">

  <link rel='stylesheet prefetch' href='https://fonts.googleapis.com/css?family=Open+Sans:700'>

      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <h1>RGB Gradient</h1>
<ul class="grad rgb">
  <li><li><li><li><li><li><li><li><li><li><li>
</ul>

<h1>HSV Gradient</h1>
<ul class="grad hsv">
  <li><li><li><li><li><li><li><li><li><li><li> 
</ul>
  <script src='http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/32bitkid/functional-gradients-lCDLB */
body {
  margin: 2em;
  font-family: Consolas, monospace;
}
h1 {
  font-family: 'Open Sans', sans-serif;
  margin: 1em 0;
  font-weight: 700;
  font-size: 2em;
}
.grad li {
  width: 8%;
  height: 20vh;
  display: inline-block;
}


/*Downloaded from https://www.codeseek.co/32bitkid/functional-gradients-lCDLB */
var lerp = function(a, b, t) { return (1-t)*a + t*b; };

// TODO there must be a better wrapping lerp function:
var clerp = function(max,a,b,t) {
  if(Math.abs(a+max-b) < Math.abs(a-b)) {
    return lerp(a+max,b,t) % max
  } else if (Math.abs(b+max-a) < Math.abs(b-a))  {
    return lerp(a, b+max, t) % max;
  }
  return lerp(a,b,t);
};

var multiLerp = function(lerps, map, reduce, a, b, t) {
  var values = _.map(map, function(fn,i) { return lerps[i](fn(a), fn(b), t); });
  return reduce.apply(undefined, values);
};

var prop = function(prop) { return function(obj) { return _.result(obj,prop); }; };

var rgbLerps = [lerp, lerp, lerp]
var rgbProps = [prop("r"), prop("g"), prop("b")];
var rgbReduce = function() { return color.rgb.apply(this, arguments); };
var rgbLerp = _.partial(multiLerp, rgbLerps, rgbProps, rgbReduce);

var hsvLerps = [_.partial(clerp, 360), lerp, lerp]
var hsvProps = [prop("h"), prop("s"), prop("v")];
var hsvReduce = function() { return color.hsv.apply(this, arguments); };
var hsvLerp = _.partial(multiLerp, hsvLerps, hsvProps, hsvReduce);

var color = (function() {
  var toHex = function(v, len) { v = (v|0).toString(16); return "00".slice(v.length) + v; };
  
  var hexString = function(c) { return function() { return c.toRGB().hexString(); }; }
  var bound = function(v,max) { return v/max;  }
  
  var rgb2hsv = function(c) { 
    return function() {
      var r = bound(c.r(),255), g = bound(c.g(),255), b = bound(c.b(), 255);
      
      var max = Math.max(r, g, b), min = Math.min(r, g, b);
      var h, s, v = max;

      var d = max - min;
      s = max === 0 ? 0 : d / max;
      
      if(max == min) {
        h = 0; // achromatic;
      }
      else {
        switch(max) {
          case r: h = (g - b) / d + (g < b ? 6 : 0); break;
          case g: h = (b - r) / d + 2; break;
          case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
      }
      
      return space.hsv(h*360,s*100,v*100);
    };
  };
  var hsv2rgb = function(c) {
    return function() {
      var h = bound(c.h(),360) * 6;
      var s = bound(c.s(),100);
      var v = bound(c.v(),100);

      var i = Math.floor(h),
          f = h - i,
          p = v * (1 - s),
          q = v * (1 - f * s),
          t = v * (1 - (1 - f) * s),
          mod = i % 6,
          r = [v, q, p, p, t, v][mod],
          g = [t, v, v, q, p, p][mod],
          b = [p, p, t, v, v, q][mod];

        return space.rgb(r * 255, g * 255,  b * 255 );
    };
  };
  
  var space = {
    hsv: function(h,s,v) {
      var c = {
        h: function() { return h; },
        s: function() { return s; },
        v: function() { return v; }
      };
      
      c.toRGB = hsv2rgb(c);
      c.toHSV = _.identity(c);
      c.hexString = hexString(c);
      
      return c;
    },
    rgb: function(r,g,b) {
      var c = {
        r: function() { return r; },
        g: function() { return g; },
        b: function() { return b; }
      };
      
      c.toRGB = _.identity(c);
      c.toHSV = rgb2hsv(c);
      c.hexString = function() { return "#"+toHex(r,2)+toHex(g,2)+toHex(b,2); };
      
      return c;
    }
  };
  return space;
}).call();

var start = color.hsv(250,100,45).toRGB(),
    end = color.hsv(255,0,90).toRGB();
var rgbGrad = _.partial(rgbLerp, start, end);
var hsvGrad = _.partial(hsvLerp, start.toHSV(), end.toHSV());

var slice = Array.prototype.slice;
slice.call(document.querySelectorAll(".hsv li")).forEach( function(e,i,a) {
  var t = i/(a.length-1);
  var c = hsvGrad(t);
  console.log(c.hexString())
  e.style.backgroundColor = c.hexString()
});

slice.call(document.querySelectorAll(".rgb li")).forEach( function(e,i,a) {
  var t = i/(a.length-1);
  var c = rgbGrad(t);
  e.style.backgroundColor = c.hexString()
});

Comments