Javascript color gradient

2019-01-04 23:52发布

Using javascript with or without Jquery, I need to a create a gradient of colours based on a start and finish color. Is this possible to do programmatically?

The end colour is only ever going to be darker shade of the start colour and it's for an unordered list which I have no control over the number of li items. I'm looking for a solution that allows me to pick a start and end color, convert the hex value into RGB so it can be manipulated in code. The starting RGB values gets incremented by a step value calculated based upon the number of items.

so if the list had 8 items then the it needs to increment the seperate Red Green Blue values in 8 steps to achieve the final colour. Is there a better way to do it and if so where can I find some sample code?

9条回答
等我变得足够好
2楼-- · 2019-01-05 00:11

I needed to create a large enough array of color options for an unknown set of dynamic elements, but I needed each element to increment their way through a beginning color and an ending color. This sort of follows the "percent fade" approach except I had a difficult time following that logic. This is how I approached it using inputs of two rgb color values and calculating the number of elements on the page.

Here is a link to a codepen that demonstrates the concept.

Below is a code snippet of the problem.

    <style>
      #test {
          width:200px;
          height:100px;
          border:solid 1px #000;
      }

      .test {
          width:49%;
          height:100px;
          border:solid 1px #000;
          display: inline-block;
      }
    </style>
</head>
<body>

<div id="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

<div class="test"></div>

    <script>

      var GColor = function(r,g,b) {
          r = (typeof r === 'undefined')?0:r;
          g = (typeof g === 'undefined')?0:g;
          b = (typeof b === 'undefined')?0:b;
          return {r:r, g:g, b:b};
      };


      // increases each channel by the difference of the two
      // divided by 255 (the number of colors stored in the range array)
      // but only stores a whole number
      // This should respect any rgb combinations
      // for start and end colors

      var createColorRange = function(c1) {
          var colorList = [], tmpColor, rr = 0, gg = 0, bb = 0;
          for (var i=0; i<255; i++) {
            tmpColor = new GColor();
              if (rExp >= 0) {

                tmpColor.r = Math.floor(c1.r - rr);
                rr += rAdditive;

              } else {

                tmpColor.r = Math.floor(c1.r + rr);
                rr += rAdditive;
              }

              if (gExp >= 0) {

                tmpColor.g = Math.floor(c1.g - gg);
                gg += gAdditive;

              } else {

                tmpColor.g = Math.floor(c1.g + gg);
                gg += gAdditive;
              }

              if (bExp >= 0) {

                tmpColor.b = Math.floor(c1.b - bb);
                bb += bAdditive;

              } else {

                tmpColor.b = Math.floor(c1.b + bb);
                bb += bAdditive;

              }

              console.log(tmpColor);


              colorList.push(tmpColor);
          }
          return colorList;
      };

      /* ==================
         Testing Code Below
         ================== */


      var firstColor = new GColor(255, 24, 0);
      var secondColor = new GColor(255, 182, 0);

      // Determine the difference
      var rExp = firstColor.r - secondColor.r;

      // Divide that difference by length of the array
      // you would like to create (255 in this case)
      var rAdditive = Math.abs(rExp)/255;

      var gExp = firstColor.g - secondColor.g;
      var gAdditive = Math.abs(gExp)/255;

      var bExp = firstColor.b - secondColor.b;
      var bAdditive = Math.abs(bExp)/255;

      var range = createColorRange(firstColor, secondColor);
      console.log(range);
      var pointer = 0;


      // This gently cycles through
      // all the colors on a single element
      function rotateColors() {
          var currentColor = range[pointer];
          document.getElementById("test").style.backgroundColor = "rgb("+currentColor.r+","+currentColor.g+","+currentColor.b+")";
          pointer++;
          if (pointer < range.length) window.setTimeout(rotateColors, 5);
      }

       rotateColors();

      // say I have 5 elements
      // so I need 5 colors
      // I already have my first and last colors
      // but I need to locate the colors between
      // my start color and my end color
      // inside of this range
      // so I divide the range's length by the
      // number of colors I need
      // and I store the index values of the middle values

      // those index numbers will then act as my keys to retrieve those values
      // and apply them to my element

      var myColors = {};
      var objects = document.querySelectorAll('.test');
        myColors.num = objects.length;


      var determineColors = function(numOfColors, colorArray) {
        var colors = numOfColors;

        var cRange = colorArray;
        var distance = Math.floor(cRange.length/colors);
        var object = document.querySelectorAll('.test');

        var j = 0;
        for (var i = 0; i < 255; i += distance) {

          if ( (i === (distance*colors)) ) {
            object[j].style.backgroundColor = "rgb(" + range[255].r + ", " + range[255].g + ", " + range[255].b + ")";

            j = 0;
            // console.log(range[i]);
          } else {

                // Apply to color to the element
                 object[j].style.backgroundColor = "rgb(" + range[i].r + ", " + range[i].g + ", " + range[i].b + ")";


                  // Have each element bleed into the next with a gradient
               // object[j].style.background = "linear-gradient( 90deg, rgb(" + range[i].r + ", " + range[i].g + ", " + range[i].b + "), rgb(" + range[i+distance].r + ", " + range[i+distance].g + ", " + range[i+distance].b + "))";

            j++;
          }

        }
      };


      setTimeout( determineColors(myColors.num, range), 2000);

    </script>
</body>
查看更多
在下西门庆
3楼-- · 2019-01-05 00:13

Yes, absolutely.

I do this in Java, should be fairly simple to do in JavaScript too.

First, you'll need to break the colors up into RGB components.

Then calculate the differences between start and finish of the components.

Finally, calculate percentage difference and multiply by the start color of each component, then add it to the start color.

Assuming you can get the RGB values, this should do it:

var diffRed = endColor.red - startColor.red;
var diffGreen = endColor.green - startColor.green;
var diffBlue = endColor.blue - startColor.blue;

diffRed = (diffRed * percentFade) + startColor.red;
diffGreen = (diffGreen * percentFade) + startColor.green;
diffBlue = (diffBlue * percentFade) + startColor.blue;

The "percentFade" is a floating decimal, signifying how far to fade into the "endColor". 1 would be a full fade (thus creating the end color). 0 would be no fade (the starting color).

查看更多
你好瞎i
4楼-- · 2019-01-05 00:14

Correct function to generate array of colors!

function hex (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);
}

/* Convert an RGB triplet to a hex string */
function convertToHex (rgb) {
  return hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
}

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

/* Convert a hex string to an RGB triplet */
function convertToRGB (hex) {
  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;
}

function generateColor(colorStart,colorEnd,colorCount){

	// The beginning of your gradient
	var start = convertToRGB (colorStart);    

	// The end of your gradient
	var end   = convertToRGB (colorEnd);    

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

	//Alpha blending amount
	var alpha = 0.0;

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

		saida.push(convertToHex (c));
		
	}
	
	return saida;
	
}

// Exemplo de como usar


var tmp = generateColor('#000000','#ff0ff0',10);

for (cor in tmp) {
  $('#result_show').append("<div style='padding:8px;color:#FFF;background-color:#"+tmp[cor]+"'>COLOR "+cor+"° - #"+tmp[cor]+"</div>")
 
}
	
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result_show"></div>

查看更多
欢心
5楼-- · 2019-01-05 00:21

desau's answer is great. Here it is in javascript:

function hexToRgb(hex) {
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : null;
}

function map(value, fromSource, toSource, fromTarget, toTarget) {
  return (value - fromSource) / (toSource - fromSource) * (toTarget - fromTarget) + fromTarget;
}

function getColour(startColour, endColour, min, max, value) {
  var startRGB = hexToRgb(startColour);
  var endRGB = hexToRgb(endColour);
  var percentFade = map(value, min, max, 0, 1);

  var diffRed = endRGB.r - startRGB.r;
  var diffGreen = endRGB.g - startRGB.g;
  var diffBlue = endRGB.b - startRGB.b;

  diffRed = (diffRed * percentFade) + startRGB.r;
  diffGreen = (diffGreen * percentFade) + startRGB.g;
  diffBlue = (diffBlue * percentFade) + startRGB.b;

  var result = "rgb(" + Math.round(diffRed) + ", " + Math.round(diffGreen) + ", " + Math.round(diffBlue) + ")";
  return result;
}

function changeBackgroundColour() {
  var count = 0;
  window.setInterval(function() {
    count = (count + 1) % 200;

    var newColour = getColour("#00FF00", "#FF0000", 0, 200, count);

    document.body.style.backgroundColor = newColour;
  }, 20);
}

changeBackgroundColour();

查看更多
孤傲高冷的网名
6楼-- · 2019-01-05 00:22

You can retrieve the list of elements. I'm not familiar with jQuery, but prototypejs has Element.childElements() which will return an array. Once you know the length of the array, you can determine how much to change the pixel components for each step. Some of the following code I haven't tested out in the form I'm presenting it in, but it should hopefully give you an idea.

function hex (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);
}

/* Convert an RGB triplet to a hex string */
function convertToHex (rgb) {
  return hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
}

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

/* Convert a hex string to an RGB triplet */
function convertToRGB (hex) {
  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);
}


/* The start of your code. */
var start = convertToRGB ('#000000');    /* The beginning of your gradient */
var end   = convertToRGB ('#ffffff');    /* The end of your gradient */
var arr = $('.gradientList').childElements();
var len = arr.length();                  /* The number of colors to compute */
var alpha = 0.5;                         /* Alpha blending amount */

for (i = 0; i < len; i++) {
    var c = [];

    c[0] = start[0] * alpha + (1 - alpha) * end[0];
    c[1] = start[1] * alpha + (1 - alpha) * end[1];
    c[2] = start[2] * alpha + (1 - alpha) * end[2];

    /* Set the background color of this element */
    arr[i].setStyle ({ 'background-color': convertToHex (c) });
}
查看更多
走好不送
7楼-- · 2019-01-05 00:24

I use this function based on @desau answer:

 getGradientColor = function(start_color, end_color, percent) {
   // strip the leading # if it's there
   start_color = start_color.replace(/^\s*#|\s*$/g, '');
   end_color = end_color.replace(/^\s*#|\s*$/g, '');

   // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF`
   if(start_color.length == 3){
     start_color = start_color.replace(/(.)/g, '$1$1');
   }

   if(end_color.length == 3){
     end_color = end_color.replace(/(.)/g, '$1$1');
   }

   // get colors
   var start_red = parseInt(start_color.substr(0, 2), 16),
       start_green = parseInt(start_color.substr(2, 2), 16),
       start_blue = parseInt(start_color.substr(4, 2), 16);

   var end_red = parseInt(end_color.substr(0, 2), 16),
       end_green = parseInt(end_color.substr(2, 2), 16),
       end_blue = parseInt(end_color.substr(4, 2), 16);

   // calculate new color
   var diff_red = end_red - start_red;
   var diff_green = end_green - start_green;
   var diff_blue = end_blue - start_blue;

   diff_red = ( (diff_red * percent) + start_red ).toString(16).split('.')[0];
   diff_green = ( (diff_green * percent) + start_green ).toString(16).split('.')[0];
   diff_blue = ( (diff_blue * percent) + start_blue ).toString(16).split('.')[0];

   // ensure 2 digits by color
   if( diff_red.length == 1 ) diff_red = '0' + diff_red
   if( diff_green.length == 1 ) diff_green = '0' + diff_green
   if( diff_blue.length == 1 ) diff_blue = '0' + diff_blue

   return '#' + diff_red + diff_green + diff_blue;
 };

Example:

getGradientColor('#FF0000', '#00FF00', 0.4);
=> "#996600"
查看更多
登录 后发表回答