Re-using Tooltip text - svg

I have a number of shapes that I want to display browser tooltips when I hover over them. However, because they contain images and caption texts, it means duplicating the same tooltip on each of their contents because they are higher in the Z-Order than the shape.
I was hoping to put them in a <defs> so that I could re-use them. For instance:
<defs>
<title id='t1'>This is my tooltip</title>
</defs>
<image ...etc...>
<use xlink:href="#t1"/>
</image>
but this doesn't work. Although it sounds like a fairly obvious use-case, I'm guessing that defs only helps with graphic elements. Is that true? Is there another way I can do this?

Having the same tooltip for my rectangle captions (or any text) is unnecessary if I include the CSS text { pointer-events: none; }.
Duplicating the tooltip across the combined shapes can be done by putting a transparent rectangle over them all and giving that a (single instance) tooltip.

Related

Shift all objects in an SVG down and to the right by a given number of pixels

Is there some kind of a wrapper object in SVG that I can use to shift all objects (lines, polygons, circles, text etc) down and to the right in a simple easy fashion? I realize now that I have not left enough space in the top left corner of my SVG definition.
Maybe there is a margin or padding element in SVG that I can use. Please note that I do not desire to wrap this inside HTML or use CSS trickery to achieve this, but ideally I would like to do this with pure SVG if possible.
You can either alter the viewBox attribute to reveal different portion of the infinite plane, i.e. changing e.g.
<svg viewBox="0 0 100 100">
to
<svg viewBox="-10 -10 110 110">
will bring extra 10 point rows and columns to top an left, effectively shifting content to bottom right (and shrinking it).
Or you can wrap all root elements of your SVG into <g> element and apply (add) single transform to all its children through it:
<g transform="translate(10, 10)">
<!-- content -->
</g>

How can I remove spaces around a SVG?

I know there are a lots of posts related to this, I had checked all of them and I was not able to get a proper solution for my problem that's why I post this question.
I have a SVG like this:
As you can see that this SVG has no spaces around left and top, but it has some spaces around right and bottom. How can I remove the spaces which at bottom and right side of it?
SVG's source code: stackoverflow's body can have only up-to 30000 characters only but the SVG's source code has more characters than the limitation. Due to reason I had to upload the code at this Gist. I am really sorry for the inconvenience :(
To see the borders of the SVG canvas I added to the header of the SVG file red border style
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 768" version="1.1"
style="border:1px solid red;">
Your image is shifted left and up so there are empty spaces on the right and bottom
jsfiddle
The image shift is performed by the command:
<g id="girl" transform="translate(-35.000000, -89.000000)">
Remove this command or set the coordinates to zero
<g id="girl" transform="translate(0, 0)">
jsfiddle
As a result, the empty spaces will disappear and the image will occupy the entire SVG canvas.

Why are the SVG Text elements too high?

I noticed the the root coordinates for a text element are not at the top left corner like a rect element:
Is there a way to set it such that when a text element is at (0,0), it fits inside the parent element?
If I understood you well, you can use this:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dominant-baseline
A) Chromium browsers
svg {
dominant-baseline: hanging;
}
https://jsfiddle.net/e7vc4bqj/
B) Chromium and Firefox
.text {
dominant-baseline: hanging;
}
https://jsfiddle.net/3zskd148/
SVG text coordinates are used to define its left bottom corner by default:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
Hope this help :)
Why are the SVG Text elements too high?
The x and y coordinates of a <text> element specify the start of the baseline of the text. This makes complete sense. You wouldn't want it to be the top left of the first character - because it would then be a difficult job to get text of different sizes and styles to line up.
There is no global option in SVG that changes that behaviour. However see below for alternatives)
Is there a way to set it such that when a text element is at (0,0), it fits inside the parent element?
Normally you would just adjust the y coordinate based on the font size.
However there are a couple of alternatives you can use:
One is the xxx-baseline properties (as #gengns has pointed out), that can alter how the character glyphs are positioned relative to the baseline. Note however, that those attributes are not entirely reliable, due to mixed browser support. Plus they depend on the font containing the correct data tables. Not all fonts have those tables.
A better option IMO is to use the dy attribute. This adds a relative offset to the text position. Meaning the text is actually positioned at (x, y + dy). And it is supported by all browsers.
<svg width="200" height="150">
<rect x="0" y="0" width="200" height="150" fill="skyblue"/>
<text x="0" y="0"
font-size="25px" dy="1em">asd</text>
</svg>

Can't see SVG text

I lack a basic understanding of <svg> and <text> within.
I would expect to see 39 svg sub-elements, 100px tall, with legible text in each.
http://jsfiddle.net/pn5sj8ge/
The reason this is happening is mainly because you are using nested <svg> elements.
When you don't specify an x and y in your <text> elements, they default to (0,0). This means that the bottom-left of your text is at the top-left of each <svg> element. Nested/child <svg> elements default to overflow: hidden, so each text element is off the top of each SVG. All you are seeing is a few pixels where the glyphs drop below the baseline.
You can verify this by setting overflow="visible" or style="overflow: visible" on your child <svg> elements. The text will become visible again. Well all except the first one because it is off the top of the window.
http://jsfiddle.net/pn5sj8ge/5/
Unless you have a special reason for using nested <svg> elements, there is no need for it. Just use <text> elements.
The text at 0, 0 and above the elements. Just give the text elements a y attribute:
<svg width="100%" height="3900px">
<svg y="0" height="100px" width="100%">
<text y="50">calories</text>
</svg>
</svg>
http://jsfiddle.net/pn5sj8ge/4/

SVG mask doesn't work if a media query is present

TL;DR: I need to mask out a portion of one rectangle in SVG, based on the size and position of another existing rectangle, which will be changing dynamically. A Chrome bug is blocking the mask + use approach I tried. How can I do a mask or inverted clip path based on an existing shape?
Full Overview:
I'm using D3.js, and I am using the brush control to add a brush to a rectangle in an embedded SVG. By default, this adds some extra elements to the SVG, including a rect with class extent that shows the size of the brushed area.
Rather than have the brush extent be rendered as a semi-transparent overlay on top of the rectangle, as in most D3 examples, I am trying to "cut out" the extent from a semi-transparent overlay, so that the brush area shows the true color below. Per this question, I am trying to do this with a mask element, with a child use element referencing the extent. With some D3 magic, I now have a structure like this:
<svg width="100" height="100">
<g class="brush-layer inverted">
<defs>
<mask id="mask835">
<rect fill="#fff" width="100%" height="100%"></rect>
<use fill="#000" xlink:href="#extent848"></use>
</mask>
</defs>
<g class="brush" style="pointer-events: none;">
<rect class="overlay" mask="url(#mask835)" width="100%" height="17"></rect>
<rect class="extent" x="30" width="52" height="17" id="extent848"></rect>
</g>
</g>
</svg>
This works great... sort of. It turns out that there appears to be a tricky Chrome bug, which I've filed here, which prevents the mask from being applied if there's a #media query in the CSS. You can see the working version here and the failing version here (fails in Chrome, works in FF).
I need this to work in Chrome, and can't drop the #media query. I also need to make the use element work, because D3 will automatically resize the extent rectangle, and that's the shape I need to mask out.
So, how can I mask out a portion of one rect, based on another rect, without using the mask + use strategy above?
One possible workaround might be to use a custom clip-path, but it's probably not going to be as elegant. Some examples of how to do do this with clip-path can be found in this question.

Resources