Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing a dot on HTML5 canvas [duplicate]

Tags:

html

canvas

People also ask

Is HTML5 Canvas still used?

The HTML5 canvas has the potential to become a staple of the web, enjoying ubiquitous browser and platform support in addition to widespread webpage support, as nearly 90% of websites have ported to HTML5.

Can you have multiple canvases HTML?

A webpage may contain multiple canvas elements. Each canvas may have an id using which you may target a specific canvas through JavaScript. Each canvas element has a 2D Context. This again has objects, properties, and methods.

Does HTML5 support canvas element?

With the exception of Internet Explorer 8, HTML5 Canvas is supported in some way by most modern web browsers, with specific feature support growing on an almost daily basis. The best support seems to be from Google Chrome, followed closely by Safari, Firefox, and Opera.


If you are planning to draw a lot of pixel, it's a lot more efficient to use the image data of the canvas to do pixel drawing.

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

Then, you can use it in this way :

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

For more information, you can take a look at this Mozilla blog post : http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/


For performance reasons, don't draw a circle if you can avoid it. Just draw a rectangle with a width and height of one:

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

It seems strange, but nonetheless HTML5 supports drawing lines, circles, rectangles and many other basic shapes, it does not have anything suitable for drawing the basic point. The only way to do so is to simulate a point with whatever you have.

So basically there are 3 possible solutions:

  • draw point as a line
  • draw point as a polygon
  • draw point as a circle

Each of them has their drawbacks.


Line

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

Keep in mind that we are drawing to South-East direction, and if this is the edge, there can be a problem. But you can also draw in any other direction.


Rectangle

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

or in a faster way using fillRect because render engine will just fill one pixel.

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

Circle

One of the problems with circles is that it is harder for an engine to render them

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

the same idea as with rectangle you can achieve with fill.

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

Problems with all these solutions:

  • it is hard to keep track of all the points you are going to draw.
  • when you zoom in, it looks ugly

If you are wondering, what is the best way to draw a point, I would go with filled rectangle. You can see my jsperf here with comparison tests


In my Firefox this trick works:

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

Small offset is not visible on screen, but forces rendering engine to actually draw a point.


The above claim that "If you are planning to draw a lot of pixel, it's a lot more efficient to use the image data of the canvas to do pixel drawing" seems to be quite wrong - at least with Chrome 31.0.1650.57 m or depending on your definition of "lot of pixel". I would have preferred to comment directly to the respective post - but unfortunately I don't have enough stackoverflow points yet:

I think that I am drawing "a lot of pixels" and therefore I first followed the respective advice for good measure I later changed my implementation to a simple ctx.fillRect(..) for each drawn point, see http://www.wothke.ch/webgl_orbittrap/Orbittrap.htm

Interestingly it turns out the silly ctx.fillRect() implementation in my example is actually at least twice as fast as the ImageData based double buffering approach.

At least for my scenario it seems that the built-in ctx.getImageData/ctx.putImageData is in fact unbelievably SLOW. (It would be interesting to know the percentage of pixels that need to be touched before an ImageData based approach might take the lead..)

Conclusion: If you need to optimize performance you have to profile YOUR code and act on YOUR findings..


This should do the job

//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();