title: Wrong rectangle size in canvas
body: <p>I'm implementing a color picker. There is problem with the rendering. When I call <code>c.fillRect(0, 0, 100, 80);</code> the size of that rectangle is 103x42 px instead of 100x80. What is wrong here? </p>
  
  <p>Also, rectangles are antialiased. Do I need offset the position by (0.5, 0.5) to avoid AA? I didn't use any kind of the coordinate system transformations.</p>
  
  <pre><code>colorSlider = function($e, color) {
      this._$canvas = $('&lt;canvas&gt;&lt;/canvas&gt;');
      this._c = this._$canvas[0].getContext('2d');
      this._color = color || { r: 0, g: 0, b: 0 };
      this._$canvas.width('310px');
      this._$canvas.height('80px');
      $e.append(this._$canvas);
      this._render();
      var me = this;
      this._$canvas.mousedown(function(e) { me._mouseDown.call(me, e) });
      this._$canvas.mouseup(function(e) { me._mouseUp.call(me, e) });
      this._$canvas.mousemove(function(e) { me._mouseMove.call(me, e) });
      this._dragChannel = 0;
  }
  
  colorSlider.prototype._pointInRect = function(x, y, rect) {
      return x &gt;= rect.x &amp;&amp; x &lt;= rect.x + rect.w &amp;&amp; y &gt;= rect.y &amp;&amp; y &lt;= rect.y + rect.h;
  }
  
  colorSlider.prototype._findTarget = function(event) {
      var x = event.offsetX;
      var y = event.offsetY;
      console.log(x, y, this._rectR);
      if (this._pointInRect(x, y, this._rectRThumb)) {
          return { target: 1, value: x - this._rectR.x };
      }
      if (this._pointInRect(x, y, this._rectGThumb)) {
          return { target: 2, value: x - this._rectG.x };
      }
      if (this._pointInRect(x, y, this._rectBThumb)) {
          return { target: 3, value: x - this._rectB.x };
      }
      if (this._pointInRect(x, y, this._rectR)) {
          return { target: 4, value: x - this._rectR.x };
      }
      if (this._pointInRect(x, y, this._rectG)) {
          return { target: 5, value: x - this._rectG.x };
      }
      if (this._pointInRect(x, y, this._rectB)) {
          return { target: 6, value: x - this._rectB.x };
      }
      return null;
  }
  
  colorSlider.prototype._mouseDown = function(event) {
      this._dragChannel = 0;
      var target = this._findTarget(event);
      if (target) {
          switch (target.target) {
              case 1:
                  this._dragChannel = 1;
                  break;
              case 2:
                  this._dragChannel = 2;
                  break;
              case 3:
                  this._dragChannel = 3;
                  break;
              case 4:
                  this._color.r = target.value;
                  break;
              case 5:
                  this._color.g = target.value;
                  break;
              case 6:
                  this._color.b = target.value;
                  break;
          }
          this._render();
      }
  };
  
  colorSlider.prototype._mouseUp = function(event) {
      //console.log('mouseUp');
  };
  
  colorSlider.prototype._mouseMove = function(event) {
      //console.log('mouseMove', event);
  };
  
  colorSlider.prototype.padding = 4;
  
  colorSlider.prototype._render = function() {
      var padding = this.padding;
      var thickness = 16;
      var c = this._c;
      var w = 255;
      var h = this._$canvas.height();
  
      c.clearRect(0, 0, this._$canvas.width(), this._$canvas.height());
  
      var gradient = c.createLinearGradient(padding, 0, w, 0);
      c.fillStyle = gradient;
  
      gradient.addColorStop(0, this.colorToHex({ r: 0, g: this._color.g, b: this._color.b }));
      gradient.addColorStop(1, this.colorToHex({ r: 255, g: this._color.g, b: this._color.b }));
      c.fillRect(padding, padding, w, thickness);
      c.lineWidth = 0;
      c.fillRect(0, 0, 100, 80);
      this._rectR = { x: padding, y: padding, w: w, h: thickness };
  
      gradient = c.createLinearGradient(padding, 0, w, 0);
      c.fillStyle = gradient;
      gradient.addColorStop(0, this.colorToHex({ r: this._color.r, g: 0, b: this._color.b }));
      gradient.addColorStop(1, this.colorToHex({ r: this._color.r, g: 255, b: this._color.b }));
      c.fillRect(padding, padding + thickness + 2 * padding, w, thickness);
      this._rectG = { x: padding, y: padding + thickness + 2 * padding, w: w, h: thickness };
  
      gradient = c.createLinearGradient(padding, 0, w, 0);
      c.fillStyle = gradient;
      gradient.addColorStop(0, this.colorToHex({ r: this._color.r, g: this._color.g, b: 0 }));
      gradient.addColorStop(1, this.colorToHex({ r: this._color.r, g: this._color.g, b: 255 }));
      c.fillRect(padding, padding + 2 * (thickness + 2 * padding), w, thickness);
      this._rectB = { x: padding, y: padding + 2 * (thickness + 2 * padding), w: w, h: thickness };
  
      c.lineWidth = 2;
      c.fillStyle = "white";
      c.strokeStyle = "#888888";
  
      this._rectRThumb = { x: padding + this._color.r - 2, y: padding / 2, w: 8, h: 20, r: 2 };
      this.drawRoundedRectangle(c, this._rectRThumb);
  
      this._rectGThumb = { x: padding + this._color.g - 2, y: padding / 2 + 2 * padding + thickness, w: 8, h: 20, r: 2 };
      this.drawRoundedRectangle(c, this._rectGThumb);
  
      this._rectBThumb = { x: padding + this._color.b - 2, y: padding / 2 + 2 * (2 * padding + thickness), w: 8, h: 20, r: 2 };
      this.drawRoundedRectangle(c, this._rectBThumb);
  };
  
  colorSlider.prototype.colorToHex = function(color) {
      var c = '#'
      + (color.r + 256).toString(16).substr(1, 2)
      + (color.g + 256).toString(16).substr(1, 2)
      + (color.b + 256).toString(16).substr(1, 2);
      console.log(c);
      return c;
  };
  
  // http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
  colorSlider.prototype.drawRoundedRectangle = function(c, rect) {
      var x = rect.x;
      var y = rect.y;
      var width = rect.w;
      var height = rect.h;
      var radius = rect.r;
      c.beginPath();
      c.moveTo(x + radius, y);
      c.lineTo(x + width - radius, y);
      c.quadraticCurveTo(x + width, y, x + width, y + radius);
      c.lineTo(x + width, y + height - radius);
      c.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
      c.lineTo(x + radius, y + height);
      c.quadraticCurveTo(x, y + height, x, y + height - radius);
      c.lineTo(x, y + radius);
      c.quadraticCurveTo(x, y, x + radius, y);
      c.closePath();
      c.stroke();
      c.fill();
  };
  </code></pre>
  
  <p>index.html</p>
  
  <pre><code>&lt;script&gt;
  $(function() {
      $("#directionalLight,#ambientLight").each(function() {
          new colorSlider($(this));
      });
  
  });
  &lt;/script&gt;
  
  &lt;body&gt;
  &lt;div&gt;Directional light&lt;/div&gt;
  &lt;div id="directionalLight"&gt;&lt;/div&gt;
  &lt;div&gt;Ambient light&lt;/div&gt;
  &lt;div id="ambientLight"&gt;&lt;/div&gt;
  &lt;/body&gt;
  </code></pre>