231 Stimmen

Wie kann ich am besten ein einzelnes Pixel in einem HTML5-Canvas setzen?

Der HTML5-Canvas hat keine Methode zum expliziten Setzen eines einzelnen Pixels.

Es könnte möglich sein, ein Pixel mit einer sehr kurzen Zeile zu setzen, aber dann könnten Antialisierung und Zeilenbegrenzung stören.

Eine andere Möglichkeit wäre die Erstellung eines kleinen ImageData Objekt und verwenden:

context.putImageData(data, x, y)

um sie einzurichten.

Kann jemand einen effizienten und zuverlässigen Weg beschreiben, dies zu tun?

45voto

PAEz Punkte 8176

Eine Methode, die nicht erwähnt wurde, ist die Verwendung von getImageData und dann putImageData.
Diese Methode eignet sich gut, wenn Sie schnell und viel auf einmal zeichnen wollen.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
var id = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var pixels = id.data;

var x = Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
var off = (y * id.width + x) * 4;
pixels[off] = r;
pixels[off + 1] = g;
pixels[off + 2] = b;
pixels[off + 3] = 255;

ctx.putImageData(id, 0, 0);

23voto

Alnitak Punkte 324207

Ich hatte nicht bedacht, dass fillRect() aber die Antworten haben mich dazu veranlasst, sie zu vergleichen mit putImage() .

Die Platzierung von 100.000 zufällig gefärbten Pixeln an zufälligen Stellen dauert mit Chrome 9.0.597.84 auf einem (alten) MacBook Pro weniger als 100 ms mit putImage() aber fast 900ms mit fillRect() . (Benchmark-Code unter http://pastebin.com/4ijVKJcC ).

Wenn ich stattdessen eine einzelne Farbe außerhalb der Schleifen wähle und diese Farbe an zufälligen Stellen auftrage, putImage() dauert 59ms gegenüber 102ms für fillRect() .

Es scheint, dass der Aufwand für das Generieren und Parsen einer CSS-Farbspezifikation in rgb(...) Die Syntax ist für den größten Teil des Unterschieds verantwortlich.

Die Eingabe von RGB-Rohwerten direkt in eine ImageData Block hingegen erfordert keine Zeichenkettenverarbeitung oder -parsing.

17voto

Vit Kaspar Punkte 161
function setPixel(imageData, x, y, r, g, b, a) {
    var index = 4 * (x + y * imageData.width);
    imageData.data[index+0] = r;
    imageData.data[index+1] = g;
    imageData.data[index+2] = b;
    imageData.data[index+3] = a;
}

7voto

Salvador Dali Punkte 197375

Es scheint seltsam, aber obwohl HTML5 das Zeichnen von Linien, Kreisen, Rechtecken und vielen anderen Grundformen unterstützt, gibt es nichts, was sich für das Zeichnen eines Punktes eignet. Die einzige Möglichkeit, dies zu tun, ist die Simulation eines Punktes mit dem, was Sie haben.

Es gibt also grundsätzlich 3 mögliche Lösungen:

  • Punkt als Linie zeichnen
  • Punkt als Polygon zeichnen
  • Punkt als Kreis zeichnen

Jede dieser Möglichkeiten hat ihre Nachteile


Leitung

function point(x, y, canvas){
  canvas.beginPath();
  canvas.moveTo(x, y);
  canvas.lineTo(x+1, y+1);
  canvas.stroke();
}

Denken Sie daran, dass wir in Richtung Süd-Ost zeichnen, und wenn dies der Rand ist, kann es ein Problem geben. Sie können aber auch in jede andere Richtung zeichnen.


Rechteck

function point(x, y, canvas){
  canvas.strokeRect(x,y,1,1);
}

oder auf schnellere Weise mit fillRect, da die Rendering-Engine nur ein Pixel füllen wird.

function point(x, y, canvas){
  canvas.fillRect(x,y,1,1);
}

Kreis


Eines der Probleme mit Kreisen ist, dass es für einen Motor schwieriger ist, sie zu rendern

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.stroke();
}

die gleiche Idee wie bei Rechteck können Sie mit Füllung erreichen.

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.fill();
}

Probleme mit all diesen Lösungen:

  • Es ist schwierig, den Überblick über alle Punkte zu behalten, die Sie ziehen werden.
  • Wenn man hineinzoomt, sieht es hässlich aus.

Wenn Sie sich fragen: "Was ist die beste Art, einen Punkt zu zeichnen? ", würde ich ein gefülltes Rechteck nehmen. Sie können meine jsperf hier mit Vergleichstests .

7voto

Daniel Punkte 71

Da verschiedene Browser unterschiedliche Methoden zu bevorzugen scheinen, wäre es vielleicht sinnvoll, einen kleineren Test mit allen drei Methoden als Teil des Ladevorgangs durchzuführen, um herauszufinden, welche am besten geeignet ist, und diese dann in der gesamten Anwendung zu verwenden?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X