SVG text - total length changes depending on zoom - firefox

In SVG (for web-browsers), if i add a <text>-element and add some text to it the total rendered width of the text string will change depending on the scale of the text.
Lets say i add "mmmmmmmmmmmmmmmmmmmmmmmmmmA" as text, then i want to draw a vertical line(or other exactly positioned element) intersecting the very last character. Works fine but if i zoom out the text will become shorter or longer and the line will not intersect the text in the right place anymore. The error can be as much as +/- 5 characters width which is unacceptable. The error is also unpredictable, 150% and 160% zoom can add 3 characters length while 155% is 2 charlengths shorter.
My zoom is implemented as a scale-transform on the root element of my canvas which is a <g>.
I have tried to multiply the font-size with 1000x and scale down equally on the zoom-transform and vice versa in case it was a floating point error but the result is the same.
I found the textLength-attribute[1] which is supposed to adjust the total length so the text always end where i choose but it only works in Webkit. Firefox and Opera seems to not care at all about this value (haven't tried in IE9 yet).
Is there any way to render text exactly positioned without resorting to homemade filling of font-outlines?
[1] http://www.w3.org/TR/SVG11/text.html#TextElementTextLengthAttribute
Update
Snippet of the structure i'm using
<svg>
<g transform="scale(1)"> <!--This is the root, i'm changing the scale of this element to zoom -->
<g transform="scale(0.014)"> <!--This is a wrapper for multi-line text, scaling, other grouping etc -->
<text font-size="1000" textLength="40000">ABDCDEFGHIJKLMNOPQRSTUVXYZÅÄÖabcdefghijklmnopqrstxyzåäö1234567890</text>
</g>
</g>

Interesting, since the webkit builds I have seem to fail on textLength (w3c testcase). Could you post your example?
Speaking for Opera we do support the 'textLength' attribute, as documented here.
The other option you have is to use the getBBox method to find a good position for drawing your line, that should work in all the browsers.

Related

First word in sentence has bigger font-size: container element cuts it off on top

The main text of my website's first word has a significant larger font-size than the rest. For some reason or another the container that contains the text cuts the first word off on top. Probably because the line-height of the first word is identical to the rest of the text and thus the container is not able to calculate its own height properly.
Codepen snippet: http://codepen.io/sardasht/pen/maJup (I've included the full contents of my css file to be able to debug properly, so will not embed this here. If this is requested, I'd happily edit my post to include it, but it will be ~300 lines of text)
If I increase the line-height of the first word, the rest of the text which is on the same line gains the same line-height and thus jumps up from the rest of the text below. If I add a margin-top to the container element, the first word is not cut off anymore, but then the bottom line of the text is cut off.
I played with overflow: visible/hidden as well on all parent elements, but to no avail.
The p element has line-height: 1.5em, which will set the height of the text lines inside it. Because of the em unit, the height is determined based on the font size, and it's the font size set for the p element that is used, so the line height won't increase because of the larger font size set on a child element.
I would try using a line-height declaration that isn't set in px, or ems.
p, span { line-height:1 }
I also tried
span { line-height:0.8 }
which seemed to give the very least amount of top "push", but I only viewed it in FF on a Mac.
I've noticed, with fonts, that their heights and widths are rendered differently from browser to browser. And this can be exacerbated with fonts that haven't been given proper leading, kerning, etc. This can cause "odd" line breaks, which causes a 'problem' with set block heights -- especially going from FF, and Chrome to IE. FWIW.
EDIT:
http://jsfiddle.net/mvf6j/
Setting the line-height to 1 (of the child) equates to 100% of the parent's line-height; thus, in your example code 1 = 1.5em. In my fiddle/example, 1 = 1em (even with the child being a 2em font). It's inheritance. It makes the child relative to the parent. And takes the guess work out, if you should want to change the parent's size. All of that ease in sizing/relationships disappears when you set explicit line-heights to the children.

How to find pixel height of a div with a consistent result between FF and Chrome

Back story: I have an SVG canvas with some polylines on it. I also have some HTML <span> and <textarea> elements that need to be positioned precisely in relation to those polylines.
I started by putting the HTML elements in the SVG in <foreignElement> tags, but I had a problem there because IE doesn't see them at all and Firefox doesn't see the <textarea>s. So I took them out of the SVG and now every browser sees them.
So far so good. Now the only way I know to make sure they position correctly with the polylines is to give both the HTML elements and the SVG canvas absolute positions with CSS.
Here's my problem. Above all these elements is a header div. I want the whole SVG business to sit at a reasonable distance below the header. Say 15px. But since the SVG is absolutely positioned, I need to know the height of that header div to get the SVG and related HTML elements into the right place.
I've tried jQuery's .height() method and some related methods. The problem with all of them is that Firefox and Chrome give two different results. I know this doesn't reflect a real pixel height difference between the two, because I can see visually that the header is slightly taller in FF, yet FF gives a smaller height reading.
How can I get a browser-consistent height reading for my header div? Or at least one that I can use to absolutely position other elements at the same distance below it in every browser.
You could try with this function
function getHeight() {
return Math.min(
Math.min(document.body.scrollHeight, document.documentElement.scrollHeight),
Math.min(document.body.offsetHeight, document.documentElement.offsetHeight),
Math.min(document.body.clientHeight, document.documentElement.clientHeight)
);
}
or simply with document.documentElement.clientHeight, which usually does the trick for me in all the browsers I use for testing (Chrome, Firefox, Safari and Opera)
[edit] The function above returns the width and height of the body, in order to use it for any div, use this one
function getHeight(div) {
return Math.min(div.scrollHeight, div.offsetHeight, div.clientHeight);
}
You can use it like this
var myDiv = document.getElementById('myDivId');
console.log('the height is ' + getHeight(myDiv));
[edit2]Keep in mind that the divs might actually have a different size depending on the browser.
Let's say this is google chrome and the green bar at top is the navigation bar, with a height of 75px. You have it at 100%, filling up your screen, who has 1000px height, and you place an 100 pixels div to the top and also stick an 100px div to the bottom of the screen (with blue). The purple div between them will have an 725px height.
And this below is firefox. It's placed on the same 1000px screen, also at 100%, but its navigation bar has 100px height. With the same 100px blue divs to the top and the bottom, the purple div will have a height of 700px here, different from chrome.
Of course, this is a very, very simple example and I doubt this is your case. But you might have a similar problem with div placements and it's something you should try to check.

SVG tricky keyTimes behaviour

I am making an animated SVG donut chart. My best try for the moment is here. But this is not exactly what i want. I want the elements appear at the start, then fade out before another one has appeared on the screen, then wait for all other elements to appear and fade out, and then to start this cycle again from the first element. As you see, now elements are fading in/out together, only their animation start times differ. I tried values/keyTimes attributes in another try. But the animation is not working in any browser i know.
Here is the problem code in first SVG:
<animate
attributeName="opacity"
begin="0ms" //This is for the first element, for anothers it differs
//I wish there is `pause` attribute, to pause animation repiting...
dur="3000ms"
from="0.7"
to="0"
repeatCount="indefinite"/>
Here is another code sample
<animate
attributeName="opacity"
begin="0ms"
keyTimes="0,0.2,1"
values="0.7,0,0"
dur="15000ms"
repeatCount="indefinite"/>
As you see, i tried to increase animation duration, but to end fading of element at 20% (i have five elements to fade) of this time. But it does not work.
Tried reordering attributes, using from and to with two-valued keyTimes and long dur with no effect. There must be some cunning trick here...
P.S. This is almost what i want, but i need animation to repeat.
The problem is commas in keyTimes and value attributes - need to use semicolons and read docs twice.

Unstyled DIV with VIDEO child has higher height than it should

For some reason a basic unstyled DIV element has extra height tacked onto the bottom when it contains a VIDEO element (and possibly other elements - I haven't tested with many types).
<div><video src="my_movie.ogv"></video></div>
I have the above line of code in a barebones base HTML file. With Firefox or Safari/Chrome's (if I use an .mp4 file instead of course) DOM inspectors on I see that the computed height of the DIV element is anywhere from 2-5 pixels more than the height of the VIDEO element.
This doesn't seem like expected and intentional behavior. If I put a P element in there instead of a VIDEO element, for example, the DIV doesn't have any of the extra height.
Does anyone know why the browsers are rendering this configuration of DOM elements in this way?
If your markup is as above and there are no special styles applied to it, then the behavior you see is required by the CSS box model; the space is the size of the font's descent, because the bottom of the video is placed by default on the baseline, not at the bottom of the text. In particular, see https://bugzilla.mozilla.org/show_bug.cgi?id=22274#c55 for an explanation in spec terms and https://bugzilla.mozilla.org/show_bug.cgi?id=22274#c37 for how to get rid of the space if you want to. You could also set line-height on the block to 0 to get rid of the space; which approach you take should depend on your other design constraints.

Is there a Gecko equivalent to -webkit-mask or a fancy way of degrading for Gecko browsers?

I'm looking for a solid answer on whether or not there is an equivalent to -webkit-mask in Gecko browsers/Firefox?
If not, is there any way of degrading -webkit-mask in CSS to a straight background-image deal or should I just give up and use Javascript?
Thanks a lot!
If you're targeting firefox, it has great SVG support, so you can now use SVG masks instead of CSS. Here is Mozillas documentation on how to do a mask in SVG Webkit masks aren't standards track - so I have a personal doubt that you'll ever see them cross-browser.
After struggling with this for many hours, I was finally able to apply a complex SVG path as a mask for a div element on my site, and it works in Firefox. Here's what I did:
First, for Webkit browsers, the solution was ideal, and I simply had to make a flattened png file with the same size (or really the same shape, could be different scale) as the div I want to mask, and with the area I want to be visible in black, and the parts I want clipped out transparent. Then, I added the following line to the CSS for the div element I want to mask:
-webkit-mask-box-image: url(path/to/mask.png);
That was easy! Now let's get to the fun part of getting this working in Firefox. For this method to work, the vector shape must be the exact same size as the area you want to mask. So my mask is a relatively complex vector path designed in Fireworks, and I need to get it converted to an SVG path, and thankfully, I have Illustrator available. Otherwise, use your favorite SVG editor to convert your shape path to SVG. If you're also using Fireworks to draw your vector shapes, you can right-click on the vector shape you want to use, go to 'Edit' -> 'Copy Path Outlines', and then you can paste it into a sufficiently large document in Illustrator, or whatever SVG editor you're using.
Next, you need to export it to an SVG file. In Illustrator, I used the 'Export for Web' function, selected SVG format, version 1.0, and exported it to an SVG file. The position and document size don't really matter, as we're just after the path description, and we'll discard the rest.
So, now open that SVG file you just made with a text editor, such as Text Edit or Notepad. You'll see some XHTML-formatted content, and one element in particular is something like:
<path fill-rule="evenodd" clip-rule="evenodd" d="M0,43v0.5V44v0.5v1V46v0.5v1V48v0..."/>
The d="..." portion will probably be many lines long for a complex shape. This is the only portion of this SVG file that we care about.
Next, we must embed an SVG mask describing this path into our site HTML. First, let's add the following elements to our HTML:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="maskid" maskUnits="userSpaceOnUse">
<path fill="white" d=""/>
</mask>
</defs>
</svg>
Now, we simply copy the contents of the d="" property of the path element from the SVG file we saved earlier (i.e. M0,43v0...) and paste into the same d="" property of the path element in the embedded SVG's mask element. Then, we can add the following entry to the CSS for the element we want to mask:
mask: url("#maskid");
That's it. The path should now be applied as a mask to the element you specified.
Here is the trick , you need to convert all points generated in your svg file to ratio that is equal the point path divided by mask dimension .
For easier explaination , i have made a quick tool to help designers convert their svg into a mask that is compatible with firefox , you can see a live demo on my website ( http://www.prollygeek.com ) , for example the facebook logo , and twitter logo are just masks , and here is the tool that you can use to convert your svg to a mask:
http://prollygeek.com/svg-mask/
for example:
<mask id="fb" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<path d="M236.626,120.827v27.295h-14.851c-4.416,0-7.225,1.204-8.63,3.612c-1.003,1.604-1.405,4.415-1.405,8.229v12.442h25.287l-3.01,27.494H211.74v79.273h-32.712v-79.273h-16.055v-27.494h16.055v-16.457c0-16.858,5.82-27.695,17.259-32.311
c5.619-2.208,10.436-2.811,15.453-2.811H236.626z"/>
will be turned to:
<mask id="fb" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<path d="M0.59,0.3v0.0675h-0.035c-0.01,0-0.0175,0.0025-0.02,0.0075c-0.0025,0.0025-0.0025,0.01-0.0025,0.02v0.03h0.0625l-0.0075,0.0675H0.5275v0.1975h-0.08v-0.1975h-0.04v-0.0675h0.04v-0.04c0-0.04,0.0125-0.0675,0.0425-0.08c0.0125-0.005,0.025-0.005,0.0375-0.005H0.59z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#ffffff;"/>
Please dont forget to add this attribute style="fill-rule:evenodd;clip-rule:evenodd;fill:#ffffff;"
and fill with any color , it doesnt matter.
afterwards link your mask to the css element you desire:
for example:
mask:url(images/fb.svg#fb);
the calculator is free to use , but please dont copy or publish anywhere else.
You can apply svg filters with css to HTML content in Gecko. Here is an example from a guy who likes to fiddle with mozilla code. It is from 2008 so it might be a bit outdated.

Resources