Drawing a color wheel... faster?
I like the idea of drawing it using arc segments, but it's probably not the most efficient. There's no doubt some extra loss in coverting to a CSS-style rgb(...) string, which then has to be parsed again. And, as you say, it causes the Moiré artefacts. Otherwise, the code looks pretty good.

While I won't guarantee it's always faster (and there are some browser support issues), you can try drawing the the color wheel pixel by pixel to an ImageData object, and pushing that to the canvas all at once. It seems faster, but I've also left out clipping the data to a wheel shape here.

You might also consider a square color field (rather than a wheel). That what this is of course, but the corners of it aren't too useful. Photoshop, for instance, defaults to a square field with saturation / lightness along the axes, and the slider determining the hue.

But Photoshop also has an RGB mode, where two of the components are used for the axes, and the last one is controlled by the slider. If you can construct a field that only requires you to update 1 byte per pixel, that'd probably be faster still.



var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var rangeEl = document.getElementById('range');

function drawPicker() {
  // grab the current ImageData (or use createImageData)
  var bitmap = context.getImageData(0, 0, 150, 150);

  for (var y = 0; y &lt; 150; y++) {
    for (var x = 0; x &lt; 150; x++) {
      // offset for the 4 RGBA values in the data array
      var offset = 4 * ((y * 150) + x);

      var hue = 180 + Math.atan2(y - 75, x - 75) * (180 / Math.PI);
      var saturation = Math.sqrt(Math.pow(y - 75, 2) + Math.pow(x - 75, 2)) / 75;
      var value = rangeEl.value;

      saturation = Math.min(1, saturation);

      var hsv = hsv2rgb(hue, saturation, value);

      // fill RGBA values
      bitmap.data[offset + 0] = hsv[0];
      bitmap.data[offset + 1] = hsv[1];
      bitmap.data[offset + 2] = hsv[2];
      bitmap.data[offset + 3] = 255; // no transparency

    }
  }

  // update the canvas
  context.putImageData(bitmap, 0, 0);
}

// setup
drawPicker();
rangeEl.addEventListener("change", drawPicker);

// =========

function hsv2rgb(h, s, v) {
  var c = v * s;
  var h1 = h / 60;
  var x = c * (1 - Math.abs((h1 % 2) - 1));
  var m = v - c;
  var rgb;

  if (typeof h == 'undefined') rgb = [0, 0, 0];
  else if (h1 &lt; 1) rgb = [c, x, 0];
  else if (h1 &lt; 2) rgb = [x, c, 0];
  else if (h1 &lt; 3) rgb = [0, c, x];
  else if (h1 &lt; 4) rgb = [0, x, c];
  else if (h1 &lt; 5) rgb = [x, 0, c];
  else if (h1 &lt;= 6) rgb = [c, 0, x];

  var r = 255 * (rgb[0] + m);
  var g = 255 * (rgb[1] + m);
  var b = 255 * (rgb[2] + m);

  return [r, g, b];
}
&lt;canvas id="picker" width="150" height="150"&gt;&lt;/canvas&gt;
&lt;br&gt;
&lt;input id="range" type="range" min="0" max="1" value="1" step="0.01"&gt;




Alternative to that: Cheat! Make the CSS background of the canvas black, and fade the color wheel in front of it using the slider. That's one way to get away with just changing 1 byte per pixel, and letting the browser handle compositing.



var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var rangeEl = document.getElementById('range');
var colorWheel = null;

// update the alpha bytes of the color wheel
function updatePicker() {
  var bitmap = context.getImageData(0, 0, 150, 150);
  for (var y = 0; y &lt; 150; y++) {
    for (var x = 0; x &lt; 150; x++) {
      var offset = ((y * 150) + x) * 4 + 3;
      colorWheel.data[offset] = rangeEl.value | 0;
    }
  }

  // update the canvas
  context.putImageData(colorWheel, 0, 0);
}

// setup
drawPicker();
rangeEl.addEventListener("change", updatePicker);

// =========

function hsv2rgb(h, s, v) {
  var c = v * s;
  var h1 = h / 60;
  var x = c * (1 - Math.abs((h1 % 2) - 1));
  var m = v - c;
  var rgb;

  if (typeof h == 'undefined') rgb = [0, 0, 0];
  else if (h1 &lt; 1) rgb = [c, x, 0];
  else if (h1 &lt; 2) rgb = [x, c, 0];
  else if (h1 &lt; 3) rgb = [0, c, x];
  else if (h1 &lt; 4) rgb = [0, x, c];
  else if (h1 &lt; 5) rgb = [x, 0, c];
  else if (h1 &lt;= 6) rgb = [c, 0, x];

  var r = 255 * (rgb[0] + m);
  var g = 255 * (rgb[1] + m);
  var b = 255 * (rgb[2] + m);

  return [r, g, b];
}

// create the initial color wheel
function drawPicker() {
  colorWheel = context.getImageData(0, 0, 150, 150);

  for (var y = 0; y &lt; 150; y++) {
    for (var x = 0; x &lt; 150; x++) {
      var offset = 4 * ((y * 150) + x);

      var hue = 180 + Math.atan2(y - 75, x - 75) * (180 / Math.PI);
      var saturation = Math.sqrt(Math.pow(y - 75, 2) + Math.pow(x - 75, 2)) / 75;

      saturation = Math.min(1, saturation);

      var hsv = hsv2rgb(hue, saturation, 1); // fixed value

      colorWheel.data[offset + 0] = hsv[0];
      colorWheel.data[offset + 1] = hsv[1];
      colorWheel.data[offset + 2] = hsv[2];
      colorWheel.data[offset + 3] = 255;
    }
  }
  context.putImageData(colorWheel, 0, 0);
}
#picker {
  background: black
}
&lt;canvas id="picker" width="150" height="150"&gt;&lt;/canvas&gt;
&lt;br&gt;
&lt;input id="range" type="range" min="0" max="255" value="255" step="1"&gt;




Or better yet: Cheat completely. Just put an image of a color wheel on top of a black box, and fade the image using the slider. No canvas, no pixel manipulation, none of that.



var wheel = document.getElementById("wheel"),
    slider = document.getElementById("slider");

slider.addEventListener("change", function () {
  wheel.style.opacity = this.value;
});
#picker {
  width: 150px;
  background: black;
}
&lt;div id="picker"&gt;
  &lt;img id="wheel" alt="" src="http://i.stack.imgur.com/TBVWx.png"&gt;
&lt;/div&gt;
&lt;input id="slider" type="range" value="1" min="0" max="1" step="0.01"&gt;




That's probably the simplest :)

Note: I haven't benchmarked any of the above. That's left as an exercise to the reader.