2012-02-15 130 views
3

我正在实施颜色选择器。渲染存在问题。当我拨打c.fillRect(0, 0, 100, 80);时,该矩形的大小为103x42像素,而不是100x80。这里有什么问题?画布中的矩形尺寸错误

此外,矩形是antialiased。我是否需要通过(0.5,0.5)偏移位置以避免AA?我没有使用任何类型的坐标系转换。

colorSlider = function($e, color) { 
    this._$canvas = $('<canvas></canvas>'); 
    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 >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= 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(); 
}; 

的index.html

<script> 
$(function() { 
    $("#directionalLight,#ambientLight").each(function() { 
     new colorSlider($(this)); 
    }); 

}); 
</script> 

<body> 
<div>Directional light</div> 
<div id="directionalLight"></div> 
<div>Ambient light</div> 
<div id="ambientLight"></div> 
</body> 

回答

18

知道的第一件事是,一个canvas元件具有固有维度 =在内部的像素数坐标空间(由widthheight设置属性和属性)。它也有非固有尺寸style.widthstyle.height),它是图像在网页中所占的像素数。内在像素被缩放以适应外部空间。

这很令人困惑,因为img也有内在和外在维度,但属性的名称完全不同于canvas。如果您在图像上设置了widthheight,则它与设置style.widthstyle.height基本相同;他们都设置外部尺寸来缩放页面内的图像。同时,您只能使用新的naturalWidthnaturalHeight(仅限HTML5浏览器)属性获取固有尺寸img

如果外部尺寸未在imgcanvas上设置,则图像将按与固有尺寸相同的尺寸布置(即比例因子为1)。

现在,当您使用jQuery时,$(canvas).width('310px')$(canvas).css('310px')相同,它设置外部尺寸。您必须致电$(canvas).prop('width', 310)或简单地设置canvas.width = 310以设置固有宽度。