7

I am using EaselJS as an API for HTML5 canvas.

I noticed that the following code:

line.graphics.setStrokeStyle(1).beginStroke("black").moveTo(100,100).lineTo(200,200);
stage.addChild(line);

...produces following line:

enter image description here

I set the thickness to 1 - but the line is still fuzzy. If you zoom in with the snapshot, you can see it actually occupies 3 pixels. I believe I read somewhere canvas draws a point between two pixels, so that both pixels will be colored in fact. And you need to shift where you draw the point by half the pixel width so it falls on the entire pixel.

I need sharp image for my applications, please advise.

VividD
  • 10,456
  • 6
  • 64
  • 111
William Sham
  • 12,849
  • 11
  • 50
  • 67
  • 1
    Have you tried changing `moveTo(100,100)` to `moveTo(100.5,100.5)`? – kangax Jul 13 '11 at 02:14
  • Yes. It works! But doesn't Easel have a bulit in SnapToPixel property..so that'll make my math easier? Do you know of any code snippet for JS in general that'll do it throughout, so i dont have to do .5 for every coordinate I enter? – William Sham Jul 13 '11 at 20:24
  • 1
    Well, you could have a helper for that. E.g.: `moveTo(coerce(100), coerce(100))` or `moveTo('100'.toCanvas(), '100'.toCanvas())` — both of which are kind of ugly (and confusing), of course :) I'm not familiar with EaselJS, and whether it has anything to work around this issue. I know that in my library (fabric.js, http://kangax.github.com/fabric.js/demos/kitchensink) there's also nothing to take care of this... – kangax Jul 14 '11 at 00:11
  • I've previously considered having Graphics support the snapToPixel property, but it would have fairly noticeable performance implications, is unnecessary for anything other than straight lines, and is fairly easily solved by offsetting your shape by 0.5. For example: myShape.regX = myShape.regY = 0.5; – gskinner Feb 01 '15 at 03:02

1 Answers1

9

EaselJS is just an abstraction for the canvas APIs - which draws all lines on the specified coordinates. The snapToPixel API is specifically for doing automatic rounding, but doesn't take into account the half-pixel issue you are describing.

The best practice approach is to put everything into a Container, and put the container at positive or negative (0.5,0.5) - which will adjust everything, and you can work in a normal coordinate space, rather than offsetting all your calculations.

Lanny
  • 106
  • 1
  • 2
  • Is there a better way to do this? Will adding the container increase the repaint bounds to ALWAYS be the entire container rect, as opposed to possibly being only the rect of the actual objects that changed? Either way that seems like you will need to manually apply a {x: 0.5, y:0.5} offset to things like dragging event co-ords that provide parameters direct from the stage (evt.stageX and evt.stageY). – Ashley Coolman Apr 24 '13 at 13:10
  • 3
    Just a note, you can set the stage.regX and stage.regY to -.5 and that will have the same effect without using a container. – Brent Sep 12 '13 at 01:10
  • Even works for the rectangle: `shape_rec.graphics.drawRect(x+0.5, y+0.5, widthx, widthy);` - great! – Avatar Dec 08 '17 at 14:56
  • Nice tip @UltimateBrent Code: `stage_a.regX = -0.5; stage_a.regY = -0.5; stage_a.update();` – Avatar Dec 08 '17 at 15:02