Skip to content Skip to sidebar Skip to footer

Css Linear Gradient Is Inaccurate?

For my application I'm looking to make a color palette that can serve any color hue from 0 degrees to 360 degrees. I'm currently using this code to make the palette. Let's use hue

Solution 1:

No, the gradient is returning the correct result. The top right pixel is between the start and end points of the gradient, and has an interpolated value to reflect that.

Imagine a single pixel canvas with a single horizontal or vertical gradient. The gradient's start point is [0,0] and the gradient's end is [1,0]. The middle of our sole pixel should have a value half way between the start and end values. If our start value is 255,255,255 and the end value is 0,255,0, then the sole pixel should be 128,255,128, as seen below:

functiondrawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvaswidth="1"height="1"></canvas>

If we have a ten pixel by ten pixel canvas, the gradient stretches from 0 to 10, with the middle of the last column of pixels being 9.5 pixels over. Which means, the gradient's interpolated value should be 95% of the way between the start and end values of the gradient. Using the same gradient as above, that should be: 13, 255, 13:

functiondrawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvaswidth="10"height="10"></canvas>

As the canvas gets bigger, the difference between the first/last values with the applied gradient and the gradient start/end values decreases. If you change the canvas in your example to have a size of 1000x1000, the top right pixel will have a value of 0,255,0 due to rounding:

functiondrawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  var grV = ctx.createLinearGradient(0, 0, 0, h);
  grV.addColorStop(0, 'rgba(0,0,0,0)');
  grV.addColorStop(1, '#000');

  ctx.fillStyle = grV;
  ctx.fillRect(0, 0, w, h);
  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);
  
}

drawPalette(120);
<canvaswidth="1000"height="1000"></canvas>

The gradient includes the pixels between the start and end points. If you don't want them to be gradient-ized, then you'll have to modify the gradient so that it starts one pixel later and ends one pixel sooner:

functiondrawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;
  
  // to ensure we know we're covering the whole thing:
  ctx.fillRect(0,0,w,h)
  //var grH = ctx.createLinearGradient(1, 0, w-2, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvaswidth="100"height="100"></canvas>

Post a Comment for "Css Linear Gradient Is Inaccurate?"