Specify baseline position in SVG - svg

Is there a possibility, in SVG, to determine a vertical position as being the "baseline" for that SVG graphics?
Context: we include a lot of inline SVG in tasks I prepare for students (see the attached screenshot, in which the circled 2 and 3 are actually SVG data). This text with inline SVG is published as HTML and in LaTeX. I'd like to find a way to include in my SVG files some marker such that later I don't have to manually specify a vertical offset for each graphic files to be perfectly aligned.
In this example, for instance, the bottom of the "2" within the circle should be determined as baseline, such that it can be automatically aligned with the bottom the of other characters that have no descender.

No, there is no such marker. The best you can do for a workaround is probably this: Set the bottom of the viewBox such that it represents the baseline. Then, if you globally set overflow: visible for all of your SVG icons, it doesn't matter if you have grafical content outside the viewBox, especially below the baseline.
p {
font-size: 40px;
}
svg {
width: 1em;
overflow: visible;
}
circle {
fill: none;
stroke: black;
}
text {
font-size: 14px;
}
<p>Example<svg viewBox="0 0 20 15">
<circle r="8.5" cx="10" cy="10" />
<text x="6" y="15">1</text>
</svg>text</p>

Related

css solution for responsive SVG chart (polyline coordinates)

I'm using javascript to generate the points coordinates of a polyline element inside a line chart. The chart must have a fixed height (210px) and a responsive width (always 100% of its parent div).
Problem is the points coordinates of the polyline don't change when resizing the window.
Is there a way to set the coordinates of the polyline as percentage of its parent div so that the horizontal coordinates change when resizing the window ?
I know I could use javascript to listen for window resize and recalculate the points coordinates of the polyline but it seems somewhat overkill so I was hoping there was a lighter, pure CSS solution.
Fiddle: https://jsfiddle.net/Hal_9100/1cnq389g/
You need to add a viewBox to your SVG. If you want the graph to stretch horizontally, to fit the box, then you'll also want to add a suitable preserveAspectRatio value.
* {padding: 0; margin: 0;}
#container {
width: 60%; height: 210px;
background: #fff;
}
svg {
width: 100%; height: 210px;
position: relative;
border: 2px solid black;
}
<div id="container">
<svg viewBox="0 0 450 210" preserveAspectRatio="none">
<polyline id="myLine" fill="none" stroke="#2681DC" stroke-width="2" points="0,210 50,67 100,174 150,198 200,202 250,190 300,205 350,207 400,198 450,19 "></polyline>
</svg>
</div>
https://jsfiddle.net/1cnq389g/2/

SVG is generating a viewbox even though there isn't one specified

I'm trying to create an SVG play button that is only the size of the button itself, but it seems that there is some kind of viewbox being auto-generated. This phantom viewbox isn't even the same dimensions as the the play button and seems to be a 2:1 ratio.
#play-button {
border: 1px dashed gray;
}
<svg id="play-button">
<style type="text/css">
.st0{fill:none;stroke:#010101;stroke-miterlimit:10;}
.st1{fill:#010101;}
</style>
<circle id="button-border" class="st0" cx="30" cy="29.9" r="29.3"/>
<polygon id="play-triangle" class="st1" points="21.9,15.7 46.6,29.9 21.9,44.1 "/>
</svg>
How can I size the viewbox to the size of the SVG without specifying a viewBox or a height/width?
The outer SVG element is a replaced element. If you don't provide anything to go on for size you'll get the default width which is 300px and the default height which is 50% of the width so if you've not supplied a width value either, that ends up being 150px.
There are a number of ways to indicate the height and width you want. The most obvious would be height and width attributes or CSS properties of the same name but you can also use a viewBox attribute to define a width and height.
#RobertLongson's answer explains why this is happening. Here are some things you can do about it:
Your circle's r="29.3" does in effect "specify a height/width" in the markup. If you can put a value there, I would imagine you actually can the same value in the svg's width or height instead. Here's a different approach you could take with that in mind. It does require a viewbox but one that doesn't change: 0 0 100 100 just lets us use percentage values for the polygon's points. To calculate them, I did yourpointvalue/yourradius (e.g. 21.9/58.6). Using a border on the svg instead of a circle element makes this lighter weight and makes the markup easier to read. I've specified the width in the CSS, but it could also be inline; you could also only specify the height, or have it relative to a parent, etc etc.
(If you check the svg with your browser's inspector, you'll see it's the same width and height as the circle)
#play-button {
fill: #010101;
border: 1px solid #000;
border-radius: 50%;
display: block;
/* specify a width or a height either here or inline */
width: 58.6px;
}
<svg id="play-button" viewbox="0 0 100 100">
<polygon points="37.3,26.8 79.5,50 37.3,73.2" />
</svg>
If you really can't use viewbox, width, or height, and need to keep all that markup, you can achieve this with javascript. This is adapted from a solution by #Almis (but see #PaulLeBeau's take on the issue). The overflow: visible is necessary because the circle's stroke extends a little beyond the bounds of the svg. (Eventually we may be able to specify where a stroke is drawn, but not yet.)
var playButton = document.getElementById('play-button');
var boundingRect = document.getElementById('button-border').getBoundingClientRect();
playButton.style.height = boundingRect.height + 'px';
playButton.style.width = boundingRect.width + 'px';
#play-button {
border: 1px dashed gray;
overflow: visible; /* added */
}
<svg id="play-button">
<style type="text/css">
.st0 {
fill: none;
stroke: #010101;
stroke-miterlimit: 10;
}
.st1 {
fill: #010101;
}
</style>
<circle id="button-border" class="st0" cx="30" cy="29.9" r="29.3" />
<polygon id="play-triangle" class="st1" points="21.9,15.7 46.6,29.9 21.9,44.1 " />
</svg>
It looks like the answer is that the default size of an SVG is 300x150, which seems bizarre to me.
If you don't want that sizing (and you probably shouldn't rely on that default) you have to specify the size as detailed in this CSS Tricks article:
https://css-tricks.com/scale-svg/

Animate parts of SVG with CSS on hover

I have a menu-icon in svg where I want a part of the icon to animate on hover, not the entire icon. How can I target with a keyframe-animation when hovering the icon?
I have another menu-icon where I'm animating the entire icon on hover, but the one I'm askin here only needs one part of it to move...
You can target inner svg elements by giving them id's and then you can select them with css.
i made this short fiddle to show how you can select the right element. i did not include keyframes because im not a animation guru with css.
http://jsfiddle.net/Z6zKd/
<svg width="100px" height="100px">
<rect id="rectangle" width="100px" height="100px" fill="#000"></rect>
<rect x="30px" id="subrectangle" width="50px" height="50px" fill="#DDD"></rect>
</svg>
css:
svg:hover #subrectangle{
transform: rotate(60deg);
transition: all 0.5s;
fill: #FFF;
left: 50px;
}

Auto height for a foreignObject in SVG

I have, in my SVG, a foreignObject which contains a p element. I want the height of this structure to be adapted to the height of my text.
The p element is already adapted : I've done nothing for that.
But I have troubles for the foreignObject. If I remove the field height, it doesn't work. height:auto doesn't work either.
Since there is no real use of scaling up and down the foreignObject itself, then you can set both foreignObject height and width to 1, and via CSS set foreignObject { overflow: visible; } to make its content visible whatever it is and do whatever you need to do it with it.
You can set height of the foreignObject element in em units, maybe that could help?
Right now the width and height attributes of a foreignObject are required, and must have values > 0, otherwise the element will not be rendered.
Update: An alternative is to just set the dimensions of the foreignObject to 100%, and use the fact that the foreignObject has a transparent background per default. Since other elements in svg are laid out in an absolute manner anyway they don't depend on the foreignObject size.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
p { position: absolute; top: 50%; left: 50%; width: 100px; }
</style>
<circle cx="50%" cy="50%" r="25%" fill="lightblue"/>
<foreignObject width="100%" height="100%">
<p xmlns="http://www.w3.org/1999/xhtml">
some wrapped text...
some wrapped text...
some wrapped text...
some wrapped text...
</p>
</foreignObject>
</svg>

SVG image with a border / stroke

I'm trying to add a border around a svg image. I have tried 2 approaches but both failed...
Attempt 1 : Draws image but no border..
<image id="note-0" xlink:href="http://example.com/example.png" x="185" y="79" height="202" width="150" style="stroke:#ac0d0d; stroke-width:3;"></image>
Attempt 2 : Draws image but no border..
<defs>
<image id="image1352022098990svg" height="202" width="150" xlink:href="http://example.com/example.png"></image>
</defs>
<use xmlns="http://www.w3.org/2000/svg" id="note-0" xlink:href="#image1352022098990svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="185" y="79" height="202" width="150" style="stroke:#ac0d0d; stroke-width:3;"/>
So my question is, is it possible to define a image on a svg element and have a border/stroke around it at the same time?
Futhermore it seems i can position svg elements with translate and with the x/y attribute. Which is preffered and why?
stroke does not apply to <image> or <use>, only shapes and text. If you want to draw a border round it, draw a <rect> after the image with the same x,y,width and height as the image and give that a stroke and a fill of "none".
As to translate vs x/y - it depends on your use case.
If for some reason you cannot change the SVG elements, there is a workaround using the outline CSS property:
#note-0 {
outline: 6px solid white;
}
If you need it to wrap around a circular image (svg shape for example), and you just need some color to outline it, you may find something like this useful:
image {
filter: drop-shadow(0px 0px 1px red);
}

Resources