wake-up-neo.com

Wenn Sie eine 1px dicke Linie in der Leinwand zeichnen, wird eine 2px dicke Linie erstellt

In diesem jsfiddle gibt es eine Zeile mit einer LineWidth von 1.

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

z.B: 

ctx.lineWidth = 1;

Die Linie ist jedoch 2px dick, wenn sie auf der Leinwand gezeichnet wird. Wie wird eine 1px dicke Linie erstellt?.

Ich könnte ein Rechteck zeichnen (mit 1px Höhe), aber ich möchte, dass die Linie auch auf Diagonalen funktioniert. Wie bekommt man diese Linie also 1px hoch?

Vielen Dank!

39
Smickie

Canvas berechnet sich aus einem halben Pixel

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

Mit einer halben Minute zu beginnen, wird es beheben

Feste Version: http://jsfiddle.net/9bMPD/357/

Diese Antwort erklärt, warum es so funktioniert.

86
Ferry Kobus

Sie können auch in X- und Y-Richtung um ein halbes Pixel übersetzen und dann ganze Werte für Ihre Koordinaten verwenden (möglicherweise müssen Sie sie in einigen Fällen runden):

context.translate(0.5, 0.5)

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

Denken Sie daran, dass bei einer Änderung der Leinwandgröße die Übersetzung zurückgesetzt wird - Sie müssen also erneut übersetzen.

Diese Antwort erklärt, warum es so funktioniert.

27
Richard

Oder als diese Antwortzustände, um eine Breite von 1 zu erhalten, müssen Sie mit einem halben Pixel beginnen.

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

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

7
tonycoupland

Haben Sie den ersten Treffer bei Google gesehen? (Suche nach canvas line width 1px) . Obwohl ich zugeben muss, dass dies nicht genau "sauber" oder "mager" ist. Ferry Kobus ' Lösung ist viel besser. Und dann nochmal: Es ist scheiße, dass man zuerst "halbe Pixel" verwenden muss ...

3
RobIII

Der Canvas-Bereich kann mit fillRect () ..__ saubere gerade Linien zeichnen. Ein Rechteck mit einer Höhe von 1px oder 1px erledigt den Job ..__ Es ist kein halber Pixelwert erforderlich:

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

Die Methode fillRect () kann verwendet werden, um dünne horizontale oder vertikale Linien in der Leinwand zu zeichnen (ohne die +0,5-Verschiebung auf Koordinaten anwenden zu müssen):

this.fillRect(left, top, 1, height);
this.fillRect(left, top, width, 1);

Sie können die Zeilen sogar noch dünner machen, indem Sie einfach diesen Code durch Folgendes ersetzen: 

this.fillRect(left, top, 0.7, height);
this.fillRect(left, top, width, 0.7);

Die Linien werden dünner (tendenziell 1 Pixel breit), ihre Farbe wird jedoch etwas gedämpft.

-> Arbeitsbeispiel

Wenn Sie ctx.lineWidth = 0,7 setzen (für die klassische beginPath/moveTo/lineTo/-Zeichenfolge), funktioniert dies nicht bei Chrome (0,7 und 1 werden auf dieselbe Weise interpretiert). Daher ein Interesse an dieser Methode fillRect ().

0
Ghislain

Wenn keine dieser Antworten für Sie zutrifft, überprüfen Sie den Zoom Ihres Browsers. Meines lag irgendwie bei 125%, also wurde jede vierte 1px-Linie 2px breit gezogen.

Ich habe stundenlang versucht herauszufinden, warum jede Geige im Internet funktioniert hat und meine nicht (der Zoom wurde nur für meinen Dev-Tab festgelegt)

0
Curtis

Für mich hat nur eine Kombination verschiedener 'pixelperfekter' Techniken geholfen, die Ergebnisse zu archivieren:

  1. Erhalte und skaliere die Leinwand mit dem Pixelverhältnis:

    pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio

  2. Skalieren Sie die Leinwand in der Größenänderung (vermeiden Sie die standardmäßige Dehnungsskalierung der Leinwand).

  3. multiplizieren Sie die Zeilenbreite mit pixelRatio, um die richtige "echte" Pixel-Liniendicke zu ermitteln:

    context.lineWidth = thickness * pixelRatio;

  4. Überprüfen Sie, ob die Liniendicke ungerade oder gerade ist. Addieren Sie die Hälfte des Pixelverhältnisses zur Zeilenposition für die ungeraden Dickenwerte.

    x = x + pixelRatio/2;

Die ungerade Linie wird in der Mitte des Pixels platziert. Die obige Zeile wird verwendet, um sie ein wenig zu verschieben.

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>

Das Größenänderungsereignis wird im Snipping nicht ausgelöst, sodass Sie die Datei im github ausprobieren können

0
Ievgen Naida