web-dev-qa-db-ja.com

キャンバスに1ピクセルの太い線を描画すると、2ピクセルの太い線が作成されます

このjsfiddleには、lineWidthが1の行があります。

http://jsfiddle.net/mailrox/9bMPD/350/

例えば:

ctx.lineWidth = 1;

ただし、キャンバスに線を描画するときの線の太さは2pxです。太さ1pxの線を作成するにはどうすればよいですか。

長方形(1pxの高さ)を描くこともできますが、線を対角線でも機能させたいです。では、この行を1pxの高さにするにはどうすればよいですか?

ありがとう!

44
MintDeparture

キャンバスはピクセルの半分から計算します

ctx.moveTo(50,150.5);
ctx.lineTo(150,150.5);

だから半分から始めるとそれは修正されます

修正バージョン: http://jsfiddle.net/9bMPD/357/

この答え なぜそのように機能するのかを説明しています。

91
Ferry Kobus

また、X方向とY方向に半ピクセルずつ変換し、座標に値全体を使用することもできます(場合によっては、それらを丸める必要があります)。

context.translate(0.5, 0.5)

context.moveTo(5,5);
context.lineTo(55,5);

キャンバスのサイズを変更すると、翻訳がリセットされるので、再度翻訳してください。

この答え なぜそのように機能するのかを説明しています。

30
Richard

または this answerの状態として、幅1を取得するには、半ピクセルから開始する必要があります。

ctx.moveTo(50.5,150.5);
ctx.lineTo(150.5,150.5);

http://jsfiddle.net/9bMPD/355/

8
tonycoupland

googleの最初のヒット を見ましたか? (検索する canvas line width 1px)。私はこれを正確に「きれい」または「無駄のない」と認めなければなりませんが。 Ferry Kobus ' 解決策ははるかに優れています。繰り返しますが、そもそも「ハーフピクセル」を使用する必要があります...

3
RobIII

Canvasは、fillRect()を使用してきれいな直線を描画できます。 1pxの高さまたは1pxの幅の長方形が仕事をします。ハーフピクセル値は必要ありません:

var ctx = document.getElementById("myCanvas").getContext("2d");

ctx.drawVerticalLine = function(left, top, width, color){
    this.fillStyle=color;
    this.fillRect(left, top, 1, width);
};

ctx.drawHorizontalLine = function(left, top, width, color){
    this.fillStyle=color;
    this.fillRect(left, top, width, 1);
}

ctx.drawVerticalLine(150, 0, 300, "green");
ctx.drawHorizontalLine(0, 150, 300, "red");

https://jsfiddle.net/ynur1rab/

1
Tom Ah

これらの答えがどれもうまくいかない場合は、ブラウザのズームを確認してください。私はどういうわけか125%だったので、1ピクセルごとに4ピクセルの線が2ピクセルの幅で描かれました。

私はインターネット上のすべてのフィドルが機能したのになぜ機能しなかったのかを理解しようとして何時間も費やしました(ズームは私の開発タブにのみ設定されました)

1
Curtis

私にとって、異なる「ピクセルパーフェクト」技術の組み合わせのみが結果のアーカイブに役立ちました。

  1. ピクセル比でキャンバスを取得およびスケーリングします。

    pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio

  2. キャンバスのサイズを変更します(キャンバスのデフォルトのストレッチスケーリングを回避します)。

  3. lineWidthとpixelRatioを乗算して、適切な「実際の」ピクセル線の太さを見つけます。

    context.lineWidth = thick * pixelRatio;

  4. 線の太さが奇数か偶数かを確認します。奇数の太さの値の場合、pixelRatioの半分を行の位置に追加します。

    x = x + pixelRatio/2;

奇数ラインはピクセルの中央に配置されます。上記の行は、少し移動するために使用されます。

function getPixelRatio(context) {
  dpr = window.devicePixelRatio || 1,
    bsr = context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio || 1;

  return dpr / bsr;
}


var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
var pixelRatio = getPixelRatio(context);
var initialWidth = canvas.clientWidth * pixelRatio;
var initialHeight = canvas.clientHeight * pixelRatio;


window.addEventListener('resize', function(args) {
  rescale();
  redraw();
}, false);

function rescale() {
  var width = initialWidth * pixelRatio;
  var height = initialHeight * pixelRatio;
  if (width != context.canvas.width)
    context.canvas.width = width;
  if (height != context.canvas.height)
    context.canvas.height = height;

  context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
}

function pixelPerfectLine(x) {

  context.save();
  context.beginPath();
  thickness = 1;
  // Multiple your stroke thickness  by a pixel ratio!
  context.lineWidth = thickness * pixelRatio;

  context.strokeStyle = "Black";
  context.moveTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 0));
  context.lineTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 200));
  context.stroke();
  context.restore();
}

function pixelPerfectRectangle(x, y, w, h, thickness, useDash) {
  context.save();
  // Pixel perfect rectange:
  context.beginPath();

  // Multiple your stroke thickness by a pixel ratio!
  context.lineWidth = thickness * pixelRatio;
  context.strokeStyle = "Red";
  if (useDash) {
    context.setLineDash([4]);
  }
  // use sharp x,y and integer w,h!
  context.strokeRect(
    getSharpPixel(thickness, x),
    getSharpPixel(thickness, y),
    Math.floor(w),
    Math.floor(h));
  context.restore();
}

function redraw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  pixelPerfectLine(50);
  pixelPerfectLine(120);
  pixelPerfectLine(122);
  pixelPerfectLine(130);
  pixelPerfectLine(132);
  pixelPerfectRectangle();
  pixelPerfectRectangle(10, 11, 200.3, 443.2, 1, false);
  pixelPerfectRectangle(41, 42, 150.3, 443.2, 1, true);
  pixelPerfectRectangle(102, 100, 150.3, 243.2, 2, true);
}

function getSharpPixel(thickness, pos) {

  if (thickness % 2 == 0) {
    return pos;
  }
  return pos + pixelRatio / 2;

}

rescale();
redraw();
canvas {
  image-rendering: -moz-crisp-edges;
  image-rendering: -webkit-crisp-edges;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  width: 100vh;
  height: 100vh;
}
<canvas id="canvas"></canvas>

サイズ変更イベントはスニペットでは発生しないため、 github でファイルを試すことができます

0
Ievgen Naida