SVG - have line centered vertically without knowing svg height - svg

I have different SVGs in the project. I need to be able to programatically add a line element at the exact vertical middle of each SVG.
I tried to set the y1 and y2 coordinates as ‘50%’ but that is not honored when the SVG is scaled either by transform scale or viewBox. One of my other requirements is to have those SVGs scaled often.
I could ,of course, start calculating bounding box of each SVG on each scale change, and from there the vertical input but that sounds not elegant
The example is just something to work on. It has a line vertical coordinates set to 50% which are not honoured when a viewBox is set (button click). The blue line is no longer at the middle of the SVG when scaled...
function myFunction(){
document.getElementById("maxi").setAttribute("viewBox","0,0,492,124");
}
<svg id="maxi" version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="246" height="62" font-size="23px" xml:space="preserve" >
<line id="greenline" x1="0" y1="31" x2="232" y2="31" stroke="#00FF00" stroke-width="4"/>
<line id="blueline" x1="0" y1="50%" x2="232" y2="50%" stroke="#0000FF"/>
<path class="cutContour" fill="none" stroke="#EC008C" stroke-miterlimit="3.8637" d="M6.8,2.3H225
c2.3,0,4.3,1.9,4.3,4.3v48.2c0,2.3-1.9,4.3-4.3,4.3H6.8c-2.3,0-4.3-1.9-4.3-4.3V6.6C2.5,4.2,4.4,2.3,6.8,2.3z"/>
</svg>
<input type="button" value="Click Me" onClick="myFunction();">

If the position of the line in the image doesn't need to vary - in other words if it's a static image - then transforms or viewBox manipulation is not required to resize the image. You can vary the CSS (or HTML attributes) of the SVG tag itself to resize the image. It is common to express the coordinates of the line as absolute values rather than percentages, but as you can see from #line2 below, the effect is identical:
For example (with jQuery):
<style>
svg {
outline: 1px dotted grey;
width: 300px;
}
#shrink {
display: none;
}
#line1 {
stroke: red;
stroke-width: 5px;
}
#line2 {
stroke: white;
stroke-width: 2px;
}
</style>
<p>
<button id="grow">Grow</button>
<button id="shrink">Shrink</button>
</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-100 0 300 100">
<line x1="-50" y1="50" x2="150" y2="50" id="line1"/>
<line x1="-40" y1="50%" x2="140" y2="50%" id="line2"/>
</svg>
<script>
$(function() {
$('#grow').click(function() {
$('svg').animate({
width: "800px"
}, 500, function() {
$('#grow').hide();
$('#shrink').show();
});
});
$('#shrink').click(function() {
$('svg').animate({
width: "300px"
}, 500, function() {
$('#shrink').hide();
$('#grow').show();
});
});
});
</script>
Codepen: https://codepen.io/MSCAU/pen/eLMOVj with additional CIRCLE and RECT behind the lines.

I'm not very sure I understand what you are asking. Please take a look & tell me if this is what you need.
function myFunction(){
let newWidth = 492;
document.getElementById("maxi").setAttribute("viewBox",`0,0,${newWidth},124`);
blueline.setAttributeNS(null,"x1", newWidth/2);
blueline.setAttributeNS(null,"x2", newWidth/2);
blueline.setAttributeNS(null,"y2", 124);
}
svg{border:1px solid;}
<svg id="maxi" version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="246" height="62" font-size="23px" xml:space="preserve" >
<line id="greenline" x1="0" y1="31" x2="232" y2="31" stroke="#00FF00" stroke-width="4"/>
<line id="blueline" x1="123" y1="0" x2="123" y2="62" stroke="#0000FF"/>
<path class="cutContour" fill="none" stroke="#EC008C" stroke-miterlimit="3.8637" d="M6.8,2.3H225
c2.3,0,4.3,1.9,4.3,4.3v48.2c0,2.3-1.9,4.3-4.3,4.3H6.8c-2.3,0-4.3-1.9-4.3-4.3V6.6C2.5,4.2,4.4,2.3,6.8,2.3z"/>
</svg>
<input type="button" value="Click Me" onClick="myFunction();">

Related

Mask Image with SVG Shape and add a Border

Not sure this is possible, so I have a back-up plan (use a background image and :after to mask one of 3x transarent PNGs with the border in the image and use nth-child to change them).
Here's what I'm trying to accomplish. I know clip-path will give me the image mask, but I need the curved edges and the border color, too. Which I don't think is possible in pure CSS.
<!DOCTYPE html>
<html>
<style>
img {
max-width: 100%;
display: block;
}
.container {
width: 300px;
height: 300px;
margin: 1em auto;
}
.frame-border {
stroke: #10c020;
stroke-width: 4;
}
</style>
<body>
<div class="container">
<svg viewBox="-10 -10 120 120">
<defs>
<mask id="mask">
<rect fill="#000000" x="0" y="0" width="300" height="300"></rect>
<path id="Path_611" data-name="Path 611" d="M1,38a12.225,12.225,0,0,1,2.558-3.025L41.351,13.462A21.12,21.12,0,0,1,46.733,12.4a14.319,14.319,0,0,1,4.81.765L89.2,34.814A7.333,7.333,0,0,1,92,37a7.273,7.273,0,0,1,1,3.4v45.3A6.741,6.741,0,0,1,92,89a12.9,12.9,0,0,1-3.015,2.945L50.42,110.628a8.953,8.953,0,0,1-3.688.786,13.383,13.383,0,0,1-4.153-.992L4.2,92.012A12.105,12.105,0,0,1,1,89a7.112,7.112,0,0,1-1-3.581V41.534A9.569,9.569,0,0,1,1,38Z" transform="translate(1.502 -10.892)" fill="#FFFFFF"/>
</mask>
</defs>
<image mask="url(#mask)"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://randomuser.me/api/portraits/women/47.jpg" width="100" height="100">
</image>
<g class="frame-border" fill="none">
<path id="Path_611" data-name="Path 611" d="M1,38a12.225,12.225,0,0,1,2.558-3.025L41.351,13.462A21.12,21.12,0,0,1,46.733,12.4a14.319,14.319,0,0,1,4.81.765L89.2,34.814A7.333,7.333,0,0,1,92,37a7.273,7.273,0,0,1,1,3.4v45.3A6.741,6.741,0,0,1,92,89a12.9,12.9,0,0,1-3.015,2.945L50.42,110.628a8.953,8.953,0,0,1-3.688.786,13.383,13.383,0,0,1-4.153-.992L4.2,92.012A12.105,12.105,0,0,1,1,89a7.112,7.112,0,0,1-1-3.581V41.534A9.569,9.569,0,0,1,1,38Z" transform="translate(1.502 -10.892)" stroke-linecap="round" />
</g>
</svg>
</div>
</body>
</html>

Inline SVG inside flex div container (which may have percentage size)

I have three flex columns, each one with relative size to the page itself (width 7%, height 60%). Each column contains three flex items (116px x 140px) with justify-content: space-between; align-items: center;, so they are centered.
Inside each flex item is a SVG containing an image (116px x 140px) because I want to apply some filters to those images (among other things).
I want to have the whole page responsive - not just the flex columns but SVGs as well. I've tried to set those SVGs with width and height 100% respectively and (obviously) didn't work.
I know I should use viewBox. min-x and min-y will be 0 (no pan/offset) but what values width and height should have?
I have another column - same size as the others (width 7%, height 60%). It contains a single SVG which has inside a path used to flow a gradient on it. How to make this SVG (path) responsive too?
viewBox should be the solution but again: What values width and height should have? I know their values can't be percentages but pixels - again, the column container has percentage sizes.
I don't want to use CSS for that (from what I've read it's cumbersome to use in this situation and I wan't my code to have a simple and clean flow). So all SVG animations are managed using Tweenmax.
This was my original code (using width and height 100% for SVGs, which is wrong)
:root {
--flexColumnPosTop: 10%;
}
.flex-container {
display: flex;
flex-flow: column;
justify-content: space-between;
align-items: center;
}
.flex-container-column {
position: absolute;
/* background-color: cyan; */
top: calc(var(--flexColumnPosTop) * 2);
width: 7%;
height: 60%;
}
.flex-container-column-posleft{
left: var(--flexColumnPos);
}
.divImagePNG {
width: 116px;
height: 110px;
}
<svg>
<defs>
<linearGradient id="linearGradient" x1="0" y1="0" x2="100%" y2="0" spreadMethod="pad" gradientUnits="userSpaceOnUse">
<stop id="offset_start" offset="0" stop-color="rgb(249, 59, 120)" stop-opacity="1" />
<stop id="offset_mid" offset="0" stop-color="rgb(250, 250, 250)" stop-opacity="1" />
<stop id="offset_end" offset="0" stop-color="rgb(116, 161, 230)" stop-opacity="1"/>
</linearGradient>
<path id="gradientPath" d="M20 70 h18 v85 h19" fill="none" stroke="rgb(116, 161, 230)" stroke-width="5" stroke-dasharray="122" stroke-dashoffset="0" />
<pattern id="patternImagePNG" patternUnits="userSpaceOnUse" width="116px" height="110px">
<image id="imagePNG" preserveAspectRatio="none" href="image.png" width="116px" height="110px"></image>
</pattern>
<rect id="rectImagePNG" x="0" y="0" width="116px" height="110px" fill="url(#patternImagePNG)" stroke-width="5" stroke="rgb(201, 28, 240)"
stroke-dasharray="452" stroke-dashoffset="0" fill-opacity="1" />
</defs>
</svg>
<div class="flex-container flex-container-column flex-container-column-posleft">
<div class="divImagePNG">
<svg width="100%" height="100%">
<use href="#rectImagePNG"></use>
</svg>
</div>
<div class="divImagePNG">
<svg width="100%" height="100%">
<use href="#rectImagePNG"></use>
</svg>
</div>
<div class="divImagePNG">
<svg width="100%" height="100%">
<use href="#rectImagePNG"></use>
</svg>
</div>
</div>
<div class="flex-container flex-container-column flex-container-column-pospathleft">
<svg width="100%" height="100%">
<use href="#gradientPath"></use>
</svg>
</div>

SVG - inherit multiple colors/animations

What I try to do:
Using a <use> element to copy an icon, and color the icon in two different colors when a specific class is added to the <use> element.
The Icon:
<symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
id="red5" x="0px" y="0px" viewBox="0 0 48.1 50.8">
<style type="text/css">
.st0{
fill:#D73647;
stroke:#000000;
stroke-miterlimit:10;
}
/* use.active .color-a{
fill: green;
}
use.active .color-b{
fill: blue;
}*/ // Not working...
</style>
<g>
<path class="st0 color-a" d="M2.3,20.2L11.8,20.2C11.8,20.2 12.5,10.9 22.3,11.2C22.3,11.2 28.5,11.1 32.3,16L26.3,22.4L47.5,22.4L47.5,2.7L40.4,9C40.4,9 36.1,0.4 23.6,0.5C23.6,0.5 4.8,-0.2 2.3,20.2z">
</path>
<path class="st0 color-b" d="M45.8,30.6L36.3,30.6C36.3,30.6 35.6,39.9 25.8,39.6C25.8,39.6 19.6,39.7 15.8,34.8L21.8,28.4L0.5,28.4L0.5,48.1L7.7,41.7C7.7,41.7 12,50.3 24.5,50.2C24.5,50.3 43.3,51 45.8,30.6z">
</path>
</g>
</symbol>
The Use Element:
<use id="svg_16"
xlink:href="#red5" transform="matrix(0.6730555893894703,0,0,0.7071457914654147,-239.09557391490307,-165.87702520953462) "
y="269.9999919533732"
x="473.99998587369964"
class="default-state"
fill="black"></use>
When the class of the <use> is changed from "default-state" to "active", I want the colors of the arrows to change (each to its own color).
What I've tried so far:
I understood that for the paths to change their color from the <use> element I have to change their CSS class to this:
.st0{
fill: inherit; // <- changed
stroke: #000000;
stroke-miterlimit: 10;
}
and the color classes to this:
use.active {
fill: green;
}
but then when I set the class of <use> to "active" they both get the same color...
I would like to do the same thing for animations.
What am I missing? How do I achive this?
This is how I would do it: I would create one symbol and I would reuse twice the same path: once as it is and once rotated 180 degs. For the "default" state please remove the active class of the g element.
.st0{
stroke-miterlimit:10;
}
.active .color-a{
fill: green;
}
.active .color-b{
fill: blue;
}
svg{width:90vh;border:1px solid}
<svg viewBox="0 0 140 150" >
<symbol id="a" viewBox="0 0 48.1 50.8">
<path class="st0 color-a" id="k" d="M2.3,20.2L11.8,20.2C11.8,20.2 12.5,10.9 22.3,11.2C22.3,11.2 28.5,11.1 32.3,16L26.3,22.4L47.5,22.4L47.5,2.7L40.4,9C40.4,9 36.1,0.4 23.6,0.5C23.6,0.5 4.8,-0.2 2.3,20.2z">
</path>
</symbol>
<g class="active" id="svg_16" >
<use class="color-a"
xlink:href="#a">
</use>
<use class="color-b" transform="rotate(180 70 75)"
xlink:href="#a"> </use>
</g>
</svg>

SVG will not display in browser

I am trying to display a simple bar in the browser using svg but for some reason it is not displaying. Here is the code I am using. It does not display the bar.
<h3>SVG Bar</h3>
<svg>
<rect with="50" height="200" style="fill: blue"/>
</svg>
What am I missing?
You've written your width attribute as "with".
But even correcting the typo, you can make a few more improvements:
svg {
border: 1px solid black;
width: 20vw;
height: 20vw;
}
<h3>SVG Bar</h3>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 1000 1000">
<rect x="0" y="0" width="200" height="500" style="fill: blue">
</svg>

Using SVG logo as mask

I'm basing my exercise on the accepted answer in: Creating transparent text to show gradient color of underlying div
Here's my rendition in jsfiddle: http://jsfiddle.net/skrln/zSjgL/
The svg code of my logo:
<svg width="190" height="121">
<mask id="cutouttext">
<rect width="190" height="121" x="0" y="0" fill="white" />
<path id="number-two" d="M75.3,56.1c7.3-3,14.2-12.5,14.2-24c0-17.7-15.1-32.1-36.8-32.1H0v121.5h52.4c30,0,43.4-16.5,43.4-36.8
C95.8,72.3,87,59.8,75.3,56.1z M66.5,94.6h-49V79.7h0.1l27-22.1c3.5-2.8,5.3-6.1,5.3-9c0-4-3.2-7.6-8.4-7.6c-6.4,0-9.1,5.7-10.2,9
l-14.6-3.9c2.9-10.8,11.8-19.1,25.2-19.1c14.4,0,24.5,9.4,24.5,21.5c0,12.4-9,18.1-17.1,23.8l-10.4,7.3h27.6V94.6z" />
<polygon id="filler" points="190,33.9 190,0 101.6,0 101.6,121.5 190,121.5 190,87.6 141.4,87.6 141.4,74.7 177.1,74.7 177.1,46.6
141.4,46.6 141.4,33.9 " />
</mask>
<rect width="190" height="121" x="0" y="0" fill="white" mask="url(#cutouttext)" />
</svg>
The result so far:
Issue:
The mask isn't behaving the way I want to; I want the inner parts of the "B" and "E" to mask out the gray underlying div so you can see the background image like the image below:
I'm having trouble knowing what part of the logo is the and which one is the . Also I can't seem to figure out the logic behind the <mask> in the SVG.
There's nothing wrong with your SVG. You placed it on a grey background, so the bits that are masked out are grey.
What you want to do is remove the grey background from below the SVG image. There may be neater ways of doing this, but one approach is to use a table layout with the logo in one cell and the grey background in another.
Here's a JSFiddle link
HTML
<div class="gray">
<svg width="190" height="121">
<mask id="cutouttext">
<rect width="190" height="121" x="0" y="0" fill="white" />
<path d="M75.3,56.1c7.3-3,14.2-12.5,14.2-24c0-17.7-15.1-32.1-36.8-32.1H0v121.5h52.4c30,0,43.4-16.5,43.4-36.8
C95.8,72.3,87,59.8,75.3,56.1z M66.5,94.6h-49V79.7h0.1l27-22.1c3.5-2.8,5.3-6.1,5.3-9c0-4-3.2-7.6-8.4-7.6c-6.4,0-9.1,5.7-10.2,9
l-14.6-3.9c2.9-10.8,11.8-19.1,25.2-19.1c14.4,0,24.5,9.4,24.5,21.5c0,12.4-9,18.1-17.1,23.8l-10.4,7.3h27.6V94.6z" />
<polygon points="190,33.9 190,0 101.6,0 101.6,121.5 190,121.5 190,87.6 141.4,87.6 141.4,74.7 177.1,74.7 177.1,46.6
141.4,46.6 141.4,33.9 " />
</mask>
<rect width="190" height="121" x="0" y="0" fill="white" mask="url(#cutouttext)" />
</svg>
<div></div>
</div>
CSS
.body {
background: #550000 url('http://sciencelakes.com/data_images/out/7/8788677-red-background-wallpaper.jpg');
display: block;
height: 500px;
margin: 0;
}
.gray {
display:table-row;
width:100%;
height:121px;
}
.gray div, .gray svg {
display:table-cell;
}
.gray div {
background:gray;
width:100%;
}

Resources