Responsive spacing in SVG group? - css

I've got a SVG exported from Adobe XD, it is a collection of five "cards" showing some people's faces arranged in a particular pattern. Here is how the code is structured:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="700" height="430" viewBox="0 0 700 430">
<defs>
...
</defs>
<g id="USERS" clip-path="url(#clip-USERS)">
<g id="Group" transform="translate(-793.227 -295.708)">
<g id="User_5" data-name="User 5" transform="translate(1340.921 326.103) rotate(-14)">
...
</g>
<g id="User_4" data-name="User 4" transform="translate(1052.907 570.449) rotate(16.024)">
...
</g>
<g id="User_3" data-name="User 3" transform="translate(1170.434 426.218) rotate(-14)">
...
</g>
<g id="User_2" data-name="User 2" transform="translate(984.139 426.348) rotate(-14)">
...
</g>
<g id="User_1" data-name="User 1" transform="translate(827.868 347.168) rotate(16.024)">
...
</g>
</g>
</g>
</svg>
I need to place the image on a website which has a responsive background, and I am trying to make the size of the image responsive as well.
With Adobe XD, I can resize the group without changing the aspect ratio of the cards - that is, only the space between them is affected. I am trying to achieve the same with the SVG on my website.
Here is a GIF of what I'd like to obtain specifically:
So far, I've tried substituting width="700" height="430" with width="100%" height="auto" in the SVG header, maybe even adding preserveAspectRatio="none", but that affects the entire image, not only the space between objects.
Any help?

What you want is not possible just by messing with viewBox and preserveAspectRatio. Anything inside the SVG will be scaled along with the SVG itself.
You would need to use Javascript, then either:
Don't use viewBox and instead reposition the cards yourself according to the current width and height, or
Let SVG reposition and scale them (using viewBox etc) , and then apply the inverse scaling transform to each card to counteract the scaling that SVG applied.
Alternatively, make each card a separate SVG image and use CSS to position them relative to the parent width and height.

Related

SVG filters outside of a bounding box/clip path/shape

I have filters working inside <g> elements with clip-paths.
<g ref="backSphere" id="backSphere"></g>
<g style="clip-path: url(#clip)">
<use xlink:href="#backSphere" style="filter: url(#blur)"></use>
</g>
Is there a simple way to "invert" this, so that the filters effectively apply to everything "outside" the clip path?
My current use case is a rectangle, but a more general answer would also be appreciated.
I know I can, for the most part:
Cover the entire SVG with one filter, then try to calculate the inverses for the applied filters with another: not ideal because of calculations, probably double-filter performance hits, and it might not math out precisely.
Create a piecemeal set of filter elements to patchwork in the coverage around the shape I want: not ideal because of individual positioning, and with either movement or more complex shapes this would be a bear.
Invert the clip path, not the filter.
SVG clip paths can contain multiple grafical primitives, like two rectangles. In this case,
the silhouettes of the child elements are logically OR’d together to create a single silhouette
But if you use a single <path> element, the path can be composed of multiple subpaths, and what is clipped then is ruled by the clip-rule property.
<clipPath id="clip" clipPathUnits="userSpaceOnUse">
<rect x="0" y="0" width="100" height="100"/>
<rect x="30" y="30" width="40" height="40"/>
</clipPath>
would just clip to the first, larger rectangle. But exchanging the rects with equivalent subpaths,
<clipPath id="clip" clipPathUnits="userSpaceOnUse">
<path d="M0,0 h100 v100 h-100 z M30,30 h40 v40 h-40 z" clip-rule="evenodd"/>
</clipPath>
clips to everything in between the two rectangular subpaths.
And that is your solution: Add an outer rectangle covering your complete viewport (or at least the filter region) to your clip path.
If you want to stay with grafical primitives, you can use a <mask> instead of a clip-path. White areas will be visible, black areas get hidden:
<mask id="clip">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<rect x="30" y="30" width="40" height="40" fill="black"/>
</mask>
This has the additional benefit that you can write the large rectangle with percentage units, usefull for responsive behavior.

Tailwind transition width

I'm having trouble understanding how I can use TailwindCSS transition utilities to perform a simple width transition in this Angular component. For example, the button below usually displays an SVG icon. However, occasionally, it displays a text message. When the text message is displayed instead of the SVG icon, the width of the button changes. I would like to add a transition to the width change (in both directions) but I cannot figure out how. Any help appreciated!
<button class="bg-green-600 text-green-100 ring-green-400 p-4 rounded-full focus:outline-none">
<span *ngIf="buttonText" class="font-semibold">{{buttonText}}</span>
<svg *ngIf="!buttonText" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</button>
I think you need the transition-duration css property which corresponds to a transition-{number} tailwind class https://tailwindcss.com/docs/transition-duration. You can also use a transition timing function https://tailwindcss.com/docs/transition-timing-function
EDIT
The problem isn't with tailwind, but rather with css itself take a look at this css-trick https://css-tricks.com/using-css-transitions-auto-dimensions/ Sorry I didn't notice this earlier.
One way to fix this issue is to set the width css property to it's actual computed width.

How to click through a transparent SVG object to a SVG object that it overlays?

I have a windows application ( no source code ) that allows you to import stencils ( SVG ) into a SQL database. From there, the application let's you insert them into a drawing surface. You could have multiple stencils layer on top of each other. If there is any transparency, you should be able to click through to the select the stencil underneath.
There is a stored procedure that runs every so often that changes out stencils for a different version based on certain criteria. I've had issues with distortion going from one stencil's height/width to another's as well as inserted stencils not centering over the stencil it's being layered upon.
I had to figure out a way to solve both problems. What I came up with probably isn't the correct way, but I am no SVG guru. Just setting the height and width of the root svg object in the stencils didn't fix anything, so I added (what I thought was) a transparently filled rect and set the height and width of that to the same value as the root svg object. This way, no matter what the stored procedure switched to, the stencil was guaranteed to be centered.
Everything looked great and I thought I was done. However, the fixed width created a rectangle that had clickable blank space, even though I had set the rect to fill:none;stroke:none;stroke-width:0;; you can't click anything underneath that stencil.
What do I need to do to be able to truly make the stencil respect its height and width on resize while allowing click through on "transparent" blank space to select the stencil underneath?
CodePen
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1"
width="60" viewBox="0 0 60 30" preserveAspectRatio="xMidYMid meet">
<style type="text/css">
<![CDATA[
.st1 {fill:none;stroke:#0000ff;stroke-dasharray:1.2,2.4;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.2}
.st2 {fill:none;stroke:none;stroke-width:0;}
]]>
</style>
<g>
<rect class="st2" height="30" width="60" x="0" y="0" />
</g>
<g>
<path class="st1" d="m 20,15 a 10,10 0 1 1 20,0 10,10 0 1 1 -20,0 z" />
</g>
</svg>
P.S. I seemingly have to use path instead of circle, as the application does not handle the newer version of SVG very well.
I'm even worst at SVG, but would pointer-events:none work for you? This would make the element not accept any mouse events: click, hover, etc.

Draw a vertical line upward with CSS3 SVG animation

I am very new in SVG animation. How can I grow a vertical line with CSS3 SVG animation? The line should start from the bottom and grow upward to custom height (Ex. 0 to 100). I have the code below:
<svg height="210" width="10">
<line x1="0" y1="0" x2="0" y2="0" style="stroke:rgb(255,0,0);stroke-width:3" />
</svg>
This is the initial position. I have tried increasing the y2 value, but then it grows downward, which I do not want. Please show me an example with CSS3 keyframe animation. Thanks in advance.
Usually to animate the process of drawing a curve one, one animates the stroke-dashoffset. Here's a fairly simple example:
<path fill="url(#rg)" transform="translate(7,5) scale(.62)" stroke="url(#rg)" stroke-opacity=".6" stroke-width="15" stroke-dasharray="45 45" fill-rule="evenodd"
d="M64,33 c27 -16,89,0,68,22 C103,84,41,39,13,67 c-24,24,20,49,42,43 C103,97,78,0,36,1 C10,1.5 -3,28,2,52 c3,12,10,22,21,27 c8,3,21,5,29,2 c16-4,8-26,16 -36 c7-10,26-7,34.73 0 c21,16,11,64-1,83 c-6,9-20,17-31,13 c-14 -5-12-24-14-36 C52,82,39,47,64,33z">
<animate attributeName="stroke-dashoffset" values="0;900;1800" dur="45s" repeatCount="indefinite"/>
</path>
(same thing for a line -- just a simple case of a path -- just make sure the values are large enough to cover the whole line.
Working example: http://cs.sru.edu/%7Eddailey/tangles/drawingcurve.svg
(the gradient is only there to make it pretty)
You can't use CSS animation for this because, currently, SVG geometry attributes are not modifiable with CSS. Only styling properties are.
The origin of an SVG is at the top left, not the bottom-left as you might be expecting. So if you want to draw a line that starts at the bottom and grows upwards you need to start with a high Y coordinate value and then reduce it.
Here's an example SVG with two lines. The green one is half the height of the other, and the both start at the same bottom coordinate.
<svg height="210" width="10">
<line x1="2" y1="0" x2="2" y2="210" style="stroke:rgb(255,0,0);stroke-width:3" />
<line x1="8" y1="100" x2="8" y2="210" style="stroke:rgb(0,128,0);stroke-width:3" />
</svg>

Cutting an SVG Mask into an image

I'm having a problem with a new website I'm developing. It's the first time I'm using SVG's. Basicly I need to cut a circle that is always centered in the page out of my image to show the image under the element. I have tried working with my clipping and everything was great. I can't seem to find the error in my mask code. Here's the link to a quick fiddle that I setup. Thanks!
<div class="bg-gradient">
<img src="http://www.redhdwallpapers.com/wp-content/uploads/2014/05/red-background-6.jpg"/>
</div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<mask id="mask">
<circle cx="50%" cy="50%" r="45%" fill="none" />
</mask>
</defs>
</svg>
A mask with fill="none" is no mask at all. Try fill="white" instead.
If you want a hole then you'll want to make your mask the inverse of what it is now so use a path with fill-rule: evenodd property and first trace out a rectangle using M, h and v round the edge of the image and then trace out a circle using arcs or bezier curves in the opposite direction to the direction you traced the edge so that the fill-rule makes a hole in the path.
You'd be better off switching back to a clipPath though since it uses far less memory than a mask if all you want to do is clip.

Resources