web-dev-qa-db-fra.com

Dessiner un point sur la toile HTML5

Tracer une ligne sur le canevas HTML5 est assez simple avec les fonctions context.moveTo() et context.lineTo().

Je ne sais pas s'il est possible de dessiner un point, c'est-à-dire de colorer un seul pixel. La fonction lineTo ne dessine pas une seule ligne de pixel (évidemment).

Y at-il une méthode pour faire cela?

106
infiniteloop

Pour des raisons de performances, ne tracez pas de cercle si vous pouvez l'éviter. Il suffit de dessiner un rectangle avec une largeur et une hauteur de un:

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

Si vous prévoyez de dessiner beaucoup de pixels, il est beaucoup plus efficace d’utiliser les données d’image du canevas pour dessiner au pixel.

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);
}

Alors vous pouvez l'utiliser de cette façon:

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

Pour plus d'informations, vous pouvez consulter cet article du blog Mozilla: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/

142
HoLyVieR

Cela semble étrange, mais malgré tout, HTML5 prend en charge le dessin de lignes, de cercles, de rectangles et de nombreuses autres formes de base, il n’a rien qui convienne pour dessiner le point de base. La seule façon de le faire est de simuler un point avec tout ce que vous avez.

Donc, fondamentalement, il y a 3 solutions possibles:

  • dessiner un point comme une ligne
  • dessiner un point comme un polygone
  • dessiner un point comme un cercle

Chacun d'entre eux a ses inconvénients.


Ligne

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

N'oubliez pas que nous nous dirigeons vers le sud-est et que, s'il s'agit du bord, il peut y avoir un problème. Mais vous pouvez aussi dessiner dans une autre direction.


Rectangle

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

ou de manière plus rapide en utilisant fillRect car le moteur de rendu ne remplira qu'un pixel.

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

Cercle

L’un des problèmes des cercles est qu’il est plus difficile pour un moteur de les rendre

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

la même idée que pour le rectangle que vous pouvez réaliser avec le remplissage.

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

Problèmes avec toutes ces solutions:

  • il est difficile de garder une trace de tous les points que vous allez dessiner.
  • quand vous zoomez, ça a l'air moche

Si vous vous demandez quelle est la meilleure façon de dessiner un point , je choisirais un rectangle plein. Vous pouvez voir mon jsperf ici avec des tests de comparaison

38
Salvador Dali

L’affirmation ci-dessus selon laquelle "si vous prévoyez de dessiner beaucoup de pixels, il est beaucoup plus efficace d’utiliser les données d’image du canevas pour dessiner au pixel" semble tout à fait fausse, du moins avec Chrome 31.0.1650.57 m ou selon votre définition de "lot de pixels". J'aurais préféré commenter directement cet article - mais malheureusement, je n'ai pas encore assez de points de dépassement de pile:

Je pense que je dessine "beaucoup de pixels" et c'est pourquoi j'ai d'abord suivi les conseils respectifs pour faire bonne mesure. Plus tard, j'ai modifié mon implémentation en un simple ctx.fillRect (..) pour chaque point dessiné, voir http: //www.wothke.ch/webgl_orbittrap/Orbittrap.htm

Fait intéressant, il s'avère que l'implémentation stupide de ctx.fillRect () dans mon exemple est au moins deux fois plus rapide que l'approche à double tampon basée sur ImageData.

Au moins pour mon scénario, il semble que les fonctions intégrées ctx.getImageData/ctx.putImageData soient incroyablement LENTES. (Il serait intéressant de connaître le pourcentage de pixels à toucher avant qu'une approche basée sur ImageData puisse prendre les devants.)

Conclusion: Si vous souhaitez optimiser les performances, vous devez profiler votre code et agir sur vos résultats.

6
wothke

Dans mon Firefox, cette astuce fonctionne:

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

Un petit décalage n'est pas visible à l'écran, mais force le moteur de rendu à dessiner un point.

6
milet

Cela devrait faire le travail

//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