KineticJS strokeWidth of 1 causes a blurred, semi-opaque line instead of a sharp 1 pixel line
Asked Answered
B

4

5

I've looked around the internet and found nothing, I've looked on other KineticJS examples that use a strokeWidth of 1 on their rectangles and they all appear to have a semi-opaque 2 pixel line rather than a nice sharp 1px opaque black line.

Now, I am guessing that as Google has nothing that the solution is either really simple or impossible, but.. do you know how I can get a one px border using KineticJS?

$(window).load(function(){
    var stage = new Kinetic.Stage({container: "kineticdiv", width: 700, height: 400});
    var layer = new Kinetic.Layer();

    var rect = new Kinetic.Rect({
        x: stage.attrs.width/2, y: stage.attrs.height/2,
        width: 100, height: 100,
        fill: "#eee", stroke: "black", strokeWidth: 1
    });

    layer.add(rect);
    stage.add(layer);
});

Fig 1

Anyone got any ideas?

Bannerol answered 27/4, 2012 at 19:28 Comment(2)
you may not be aligning your plotting with pixels. so the line is half in one pixel and half in another. try adding 0.5 to your coords.Develop
Ah, yes, I remember now. I forgot this happens, remember it happening a year or two ago when I was playing with XNA and had the same issue then with blurred fonts. Thanks guys!Bannerol
D
9

when you draw a line from (x,y1) to (x,y2) (say; the same is true for horizontal lines) you need to worry about whether x is "in the middle of a pixel". if the line is "between pixels" then it will be half in one and half in another. the result will look blurred (it's basically anti-aliasing).

graphics systems vary on whether coordinates are for corners or centres, but you can fix the issue by experimenting a little - you just need to add half a pixel width to the coord and try again.

in the case of an html5 canvas (0,0) is the top left corner, so if you have no transform i guess the top left pixel centre is at (0.5, 0.5).

Develop answered 27/4, 2012 at 19:34 Comment(1)
Yep, that fixed it. It's always the littlest bugs! ThanksBannerol
T
3

Another approach: if you use Integer numbers as coordinates and ortogonal 1px weight lines, then you can move the whole stage by [0.5, 0.5] and you dont have to add the half of a pixel to each coordinate, you can then use Integer numbers as coordinate as your whole stage will be moved half of pixel to right and the same to down.

Tomkins answered 30/1, 2014 at 8:19 Comment(0)
G
2

There is a cool approach to get exactly what you want: group two similar shapes. The one at the lower level is one pixel larger then the one at the top. Fill the bottom one with the color you want your border (in your case: Black). works fine for me and has the precision and quality of CSS

Gormand answered 13/3, 2013 at 22:38 Comment(2)
Not currently working on that project any more, however your solution makes perfect sense. Kudos!Bannerol
I haven't done this with rectangles, but I use this with text. The upper layer of text has no shadow or stroke, but I put a duplicate layer of text, with stroke and shadow, below the upper layer. Much more readable, especially for small text.Disrespectful
C
2

The easiest way of solving this with Kinetic is to use the offset properties. So, rather than shifting individual coordinates of what you're drawing, your entire line/shape/group/layer/stage is offset by that much, theoretically getting it where you want it with minimum fuss:

var rect = new Kinetic.Rect({
    x: stage.attrs.width/2, y: stage.attrs.height/2,
    width: 100, height: 100,
    fill: "#eee", stroke: "black", strokeWidth: 1,
    offsetX: 0.5,
    offsetY: 0.5
});

or, to get a whole bunch of stuff at once:

var layer = new Kinetic.Layer({
    offsetX: 0.5,
    offsetY: 0.5
});

That said, not all items benefit from this trick. Some, in fact, get fuzzier. So, make sure to apply the offset at the most atomic level that avoids contaminating shapes that don't benefit from it.

Collage answered 13/6, 2014 at 2:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.