Reputation: 18891
I'm using SVG.js to render a SVG graphic. It needs to be pixel-perfect, no fuzzy lines etc.
var draw = SVG(wrapper).size(560, 360)
draw.attr('shape-rendering', 'crispEdges');
draw.fixSubPixelOffset();
Now I don't have the weird fuzzy lines and all is good - but:
Apparently, crispEdges
rounds down in Chrome and up in firefox, so in the end, I have sharp graphics, but it's all for nothing because firefox renders some stuff 1 pixel off.
Chrome
Firefox
Notice that neither is perfect, but since I optimized for Chrome, it's broken in Firefox - and if I fix it for Firefox, it will be broken in Chrome. In particular, the "I" bar and the hour lines bother me - they need to be perfectly positioned. Also, the tooltip is a few pixels off.
I'm sure some will ask for more code - I can provide it, but it's not really relevant to the problem, i.e. here's how the I bar is rendered:
if(data.now.day == index) {
var mx = sl_BAR_HOFFSET + (sl_BAR_WIDTH / 1440)*data.now.time;
var my = sl_BAR_VOFFSET-2;
group.line(0,0,0,sl_BAR_HEIGHT+4)
.stroke({ width: 1, color: sl_COLOR_NOW })
.move(mx, my);
group.line(0,0,3,0)
.stroke({ width: 1, color: sl_COLOR_NOW })
.move(mx-1.5, my);
group.line(0,0,3,0)
.stroke({ width: 1, color: sl_COLOR_NOW })
.move(mx-1.5, my+sl_BAR_HEIGHT+3);
}
I'd appreciate some advice how to fix this cross browser incompatibility. Some shim or anything?
Upvotes: 2
Views: 4374
Reputation: 3795
I had crispEdges turned on and started writing some strokeAdjust() and browserAdjust() functions to make things look the same in Firefox and Chrome. After reading @MightyPork's comment that crispEdges seems like a good idea but is trouble, I turned it off and my rectangles became identical (but antialiased) in Firefox and Chrome. I started experimenting with positioning, sizes, and strokes to see what rules I can deduce to create a crispEdges() function.
I created a sample svg to demonstrate what effect positioning, sizing, and stroke have on how crisp edges look.
To achieve crisp edges for rectangles, it looks like the width and height must always be whole numbers (makes sense). If the stroke is an even integer, the coordinates must be whole numbers. If the stroke is an odd integer, the coordinates must be on the half-integer.
<body>
<svg id="svgHeader" style="width:300px; height: 200px; background: #f8f8f8;">
<rect class="none" x="10" y="8" width="8" height="28" style=""></rect>
<rect class="none" x="26.5" y="8.5" width="8" height="28" style=""></rect>
<rect class="none" x="42.5" y="8" width="7" height="28" style=""></rect>
<rect class="none" x="58" y="8" width="7" height="28" style=""></rect>
<rect class="none" x="74.5" y="8" width="9" height="28" style=""></rect>
<rect class="none" x="90.5" y="8.5" width="10" height="28" style=""></rect>
<rect class="none" x="106" y="8.5" width="10" height="28" style=""></rect>
<rect class="first" x="10" y="48" width="8" height="28" style=""></rect>
<rect class="first" x="26.5" y="48.5" width="8" height="28" style=""></rect>
<rect class="first" x="42.5" y="48" width="7" height="28" style=""></rect>
<rect class="first" x="58" y="48" width="7" height="28" style=""></rect>
<rect class="first" x="74.5" y="48" width="9" height="28" style=""></rect>
<rect class="first" x="90.5" y="48.5" width="10" height="28" style=""></rect>
<rect class="first" x="106" y="48.5" width="10" height="28" style=""></rect>
<rect class="second" x="10" y="88" width="8" height="28" style=""></rect>
<rect class="second" x="26.5" y="88.5" width="8" height="28" style=""></rect>
<rect class="second" x="42.5" y="88" width="7" height="28" style=""></rect>
<rect class="second" x="58" y="88" width="7" height="28" style=""></rect>
<rect class="second" x="74.5" y="88" width="9" height="28" style=""></rect>
<rect class="second" x="90.5" y="88.5" width="10" height="28" style=""></rect>
<rect class="second" x="106" y="88.5" width="10" height="28" style=""></rect>
<rect class="third" x="10" y="128" width="8" height="28" style=""></rect>
<rect class="third" x="26.5" y="128.5" width="8" height="28" style=""></rect>
<rect class="third" x="42.5" y="128" width="7" height="28" style=""></rect>
<rect class="third" x="58" y="128" width="7" height="28" style=""></rect>
<rect class="third" x="74.5" y="128" width="9" height="28" style=""></rect>
<rect class="third" x="90.5" y="128.5" width="10" height="28" style=""></rect>
<rect class="third" x="106" y="128.5" width="10" height="28" style=""></rect>
<rect class="fourth" x="10" y="168" width="8" height="28" style=""></rect>
<rect class="fourth" x="26.5" y="168.5" width="8" height="28" style=""></rect>
<rect class="fourth" x="42.5" y="168" width="7" height="28" style=""></rect>
<rect class="fourth" x="58" y="168" width="7" height="28" style=""></rect>
<rect class="fourth" x="74.5" y="168" width="9" height="28" style=""></rect>
<rect class="fourth" x="90.5" y="168.5" width="10" height="28" style=""></rect>
<rect class="fourth" x="106" y="168.5" width="10" height="28" style=""></rect>
</svg>
</body>
Some css:
rect {
stroke-width: 0px;
stroke: #222;
fill: #ddd;
}
rect.none {
fill: #222;
}
rect.first {
stroke-width: 1px;
}
rect.second {
stroke-width: 2px;
}
rect.third {
stroke-width: 3px;
}
rect.fourth {
stroke-width: 4px;
}
Upvotes: 0
Reputation: 18891
Oke so I have solved it myself ;D
I got rid of draw.attr('shape-rendering', 'crispEdges');
and draw.fixSubPixelOffset();
(the later apparently had no effect at all), and then in some places added 0.5 px offset.
Interestingly, some rects didn't need the offset, and some did.
Also worth mentioning, you can use ~~number
to convert it to integer instead of tedious Math.floor()
.
Upvotes: 3