it-swarm-id.com

Menggambar sebuah titik di kanvas HTML5

Menggambar garis pada kanvas HTML5 cukup mudah menggunakan fungsi context.moveTo() dan context.lineTo().

Saya tidak yakin apakah mungkin menggambar satu titik, yakni mewarnai satu piksel. Fungsi lineTo tidak akan menggambar garis piksel tunggal (jelas).

Apakah ada metode untuk melakukan ini?

106
infiniteloop

Untuk alasan kinerja, jangan menggambar lingkaran jika Anda bisa menghindarinya. Cukup gambar persegi panjang dengan lebar dan tinggi satu:

ctx.fillRect(10,10,1,1); // fill in the pixel at (10,10)
129
Simon Sarris

Jika Anda berencana untuk menggambar banyak piksel, jauh lebih efisien untuk menggunakan data gambar kanvas untuk melakukan menggambar piksel.

var canvas = document.getElementById("myCanvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

// That's how you define the value of a pixel //
function drawPixel (x, y, r, g, b, a) {
    var index = (x + y * canvasWidth) * 4;

    canvasData.data[index + 0] = r;
    canvasData.data[index + 1] = g;
    canvasData.data[index + 2] = b;
    canvasData.data[index + 3] = a;
}

// That's how you update the canvas, so that your //
// modification are taken in consideration //
function updateCanvas() {
    ctx.putImageData(canvasData, 0, 0);
}

Daripada Anda bisa menggunakannya dengan cara ini:

drawPixel(1, 1, 255, 0, 0, 255);
drawPixel(1, 2, 255, 0, 0, 255);
drawPixel(1, 3, 255, 0, 0, 255);
updateCanvas();

Untuk informasi lebih lanjut, Anda dapat melihat di posting blog Mozilla ini: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/

142
HoLyVieR

Tampaknya aneh, tetapi meskipun demikian HTML5 mendukung menggambar garis, lingkaran, persegi panjang dan banyak bentuk dasar lainnya, itu tidak memiliki apa pun yang cocok untuk menggambar titik dasar. Satu-satunya cara untuk melakukannya adalah dengan mensimulasikan suatu poin dengan apa pun yang Anda miliki.

Jadi pada dasarnya ada 3 solusi yang mungkin:

  • gambar titik sebagai garis
  • gambar titik sebagai poligon
  • gambar titik sebagai lingkaran

Masing-masing dari mereka memiliki kekurangan.


Baris

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

Ingatlah bahwa kita sedang menuju ke arah Tenggara, dan jika ini Edge, mungkin ada masalah. Tapi Anda juga bisa menggambar ke arah lain.


Persegi Panjang

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

atau dengan cara yang lebih cepat menggunakan fillRect karena mesin render hanya akan mengisi satu piksel.

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

Lingkaran

Salah satu masalah dengan lingkaran adalah lebih sulit bagi mesin untuk membuat mereka

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

ide yang sama seperti dengan persegi panjang yang bisa Anda capai dengan mengisi.

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

Masalah dengan semua solusi ini:

  • sulit untuk melacak semua poin yang akan Anda gambar.
  • saat Anda memperbesar, tampilannya jelek

Jika Anda bertanya-tanya, apakah cara terbaik untuk menggambar titik , saya akan pergi dengan persegi panjang yang diisi. Anda dapat melihat jsperf saya di sini dengan tes perbandingan

38
Salvador Dali

Klaim di atas bahwa "Jika Anda berencana untuk menggambar banyak piksel, jauh lebih efisien untuk menggunakan data gambar kanvas untuk melakukan menggambar piksel" tampaknya sangat salah - setidaknya dengan Chrome 31.0.1650.57 m atau tergantung pada definisi Anda tentang "banyak piksel". Saya lebih suka berkomentar langsung ke posting masing-masing - tetapi sayangnya saya belum memiliki cukup poin stackoverflow:

Saya pikir saya menggambar "banyak piksel" dan karena itu saya pertama-tama mengikuti saran masing-masing untuk ukuran yang baik. Saya kemudian mengubah implementasi saya menjadi ctx.fillRect (..) sederhana untuk setiap titik yang ditarik, lihat http: //www.wothke.ch/webgl_orbittrap/Orbittrap.htm

Menariknya ternyata implementasi ctx.fillRect () konyol dalam contoh saya sebenarnya setidaknya dua kali lebih cepat dari pendekatan buffering ganda berbasis ImageData.

Setidaknya untuk skenario saya tampaknya built-in ctx.getImageData/ctx.putImageData sebenarnya SLOW yang luar biasa. (Akan menarik untuk mengetahui persentase piksel yang perlu disentuh sebelum pendekatan berbasis ImageData memimpin.)

Kesimpulan: Jika Anda perlu mengoptimalkan kinerja, Anda harus membuat profil kode ANDA dan menindaklanjuti temuan ANDA ..

6
wothke

Di Firefox saya, trik ini berfungsi:

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

Offset kecil tidak terlihat di layar, tetapi memaksa mesin rendering untuk benar-benar menarik titik.

6
milet

Ini harus melakukan pekerjaan

//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");

//draw a dot
ctx.beginPath();
ctx.arc(20, 20, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
3
by0