Animated growing arrow link - css

Hi, I was wondering how one would go about animating an svg arrow like above (on hover).
I have tried playing around with CSS transforms, but they also scale the arrow-head which is no good. I assume the correct way to do this is using SVGs animations, but I don't know where to start.
For example I would the following arrow (line only) to grow and arrow head to move accordingly.
<svg width="600px" height="100px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<line x1="50" y1="50" x2="100" y2="50" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>
Any help is very much appreciated!

You can create growing arrow by using "respoinsive" SVG like this.
svg{
width: 20px;
height: 20px;
transition:width 2s ease;
overflow: visible;
}
svg:hover{
width: 100px;
}
<svg>
<defs>
<marker id="m" markerWidth="4" markerHeight="8"
refX="0" refY="1" viewBox="0 0 1 2">
<polygon points="0,0 1,1 0,2" fill="black"/>
</marker>
</defs>
<line x1="0" y1="50%" x2="100%" y2="50%"
stroke-width="2" marker-end="url(#m)" stroke="black"/>
</svg>
There are some points to implement.
svg has no viewBox (so it is "responsive" SVG).
Line of arrow is defined by relative position of (root) svg size.
Arrow head is defined by marker element.
Growing animation is defined by CSS transition which animate width of svg. So, arrow grows with svg size.

In order to animate the individual SVG elements like HTML elements, you'll need to embed the SVG directly into the page like this:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174"
xml:space="preserve" class="logo">
<ellipse class="ground" cx="283.5" cy="487.5" rx="259" ry="80"/>
<path class="kiwi" d="M210.333,65.331C104.367,66.105-12.349,150.637,1.056,276.449c4.303,40.393,18.533,63.704,52.171,79.03
c36.307,16.544,57.022,54.556,50.406,112.954c-9.935,4.88-17.405,11.031-19.132,20.015c7.531-0.17,14.943-0.312,22.59,4.341
c20.333,12.375,31.296,27.363,42.979,51.72c1.714,3.572,8.192,2.849,8.312-3.078c0.17-8.467-1.856-17.454-5.226-26.933
c-2.955-8.313,3.059-7.985,6.917-6.106c6.399,3.115,16.334,9.43,30.39,13.098c5.392,1.407,5.995-3.877,5.224-6.991
c-1.864-7.522-11.009-10.862-24.519-19.229c-4.82-2.984-0.927-9.736,5.168-8.351l20.234,2.415c3.359,0.763,4.555-6.114,0.882-7.875
c-14.198-6.804-28.897-10.098-53.864-7.799c-11.617-29.265-29.811-61.617-15.674-81.681c12.639-17.938,31.216-20.74,39.147,43.489
c-5.002,3.107-11.215,5.031-11.332,13.024c7.201-2.845,11.207-1.399,14.791,0c17.912,6.998,35.462,21.826,52.982,37.309
c3.739,3.303,8.413-1.718,6.991-6.034c-2.138-6.494-8.053-10.659-14.791-20.016c-3.239-4.495,5.03-7.045,10.886-6.876
c13.849,0.396,22.886,8.268,35.177,11.218c4.483,1.076,9.741-1.964,6.917-6.917c-3.472-6.085-13.015-9.124-19.18-13.413
c-4.357-3.029-3.025-7.132,2.697-6.602c3.905,0.361,8.478,2.271,13.908,1.767c9.946-0.925,7.717-7.169-0.883-9.566
c-19.036-5.304-39.891-6.311-61.665-5.225c-43.837-8.358-31.554-84.887,0-90.363c29.571-5.132,62.966-13.339,99.928-32.156
c32.668-5.429,64.835-12.446,92.939-33.85c48.106-14.469,111.903,16.113,204.241,149.695c3.926,5.681,15.819,9.94,9.524-6.351
c-15.893-41.125-68.176-93.328-92.13-132.085c-24.581-39.774-14.34-61.243-39.957-91.247
c-21.326-24.978-47.502-25.803-77.339-17.365c-23.461,6.634-39.234-7.117-52.98-31.273C318.42,87.525,265.838,64.927,210.333,65.331
z M445.731,203.01c6.12,0,11.112,4.919,11.112,11.038c0,6.119-4.994,11.111-11.112,11.111s-11.038-4.994-11.038-11.111
C434.693,207.929,439.613,203.01,445.731,203.01z"/>
<filter id="pictureFilter" >
<feGaussianBlur stdDeviation="15" />
</filter>
</svg>
After doing this, you can use CSS animations on any of the individual SVG elements, just like HTML elements. For example, you could do the following:
svg ellipse { animate: grow 3s infinite; }
Without having the exact SVG code for your arrow, I can't give you more specific direction than that, but can point you in the direction of this article: https://css-tricks.com/using-svg/

Related

Draw a circle in svg with preserveAspectRatio="none"

I have an svg with viewBox="0 0 100 100" preserveAspectRatio="none" since I need to draw some elements with reference to percentages.
If I now draw a <circle cx="30" cy="50" r="0.5" stroke="white"/> though it becomes stretched/distorted as well.
Is there a way to tell the circle element to preserve its own aspect ratio?
If all you need is a circle you can use a very short, very wide line like in the following example.
This will work because
stroke-linecap="round" will give the illusion of a circle and because
strokes can take a vector-effect="non-scaling-stroke".
non-scaling-stroke
This value modifies the way an object is stroked. Normally stroking involves calculating stroke outline of the shape's path in current user coordinate system and filling that outline with the stroke paint (color or gradient). The resulting visual effect of this value is that the stroke width is not dependent on the transformations of the element (including non-uniform scaling and shear transformations) and zoom level.
div {
width: 300px;
height: 50px;
background-color: lime;
}
svg {
width:100%;
height:100%;
}
<div>
<svg viewBox="0 0 100 100" preserveAspectRatio="none">
<!--<circle cx="30" cy="50" r="20"></circle>-->
<line x1="30" y1="50" x2="30.1" y2="50" stroke-width="40" stroke="black" stroke-linecap="round" vector-effect="non-scaling-stroke" />
</svg>
</div>
If you need a white stroke too you can add a white line behind the black one with a bigger stroke width
div {
width: 300px;
height: 50px;
background-color: lime;
}
svg {
width:100%;
height:100%;
}
<div>
<svg viewBox="0 0 100 100" preserveAspectRatio="none">
<line x1="30" y1="50" x2="30.1" y2="50" stroke-width="45" stroke="white" stroke-linecap="round" vector-effect="non-scaling-stroke" />
<line x1="30" y1="50" x2="30.1" y2="50" stroke-width="40" stroke="black" stroke-linecap="round" vector-effect="non-scaling-stroke" />
</svg>
</div>

How to change svg path width on hover

I have an issue I can't find an helpful answer. I have a svg arrow, the arrow has to grow when the user hovers over with the mouse. The problem is that only the line has to change size not the arrow head. I just want the line to grow horizontally.
This is the svg code
<svg width="51" height="8" viewBox="0 0 51 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M50.3536 4.35355C50.5488 4.15829 50.5488 3.84171 50.3536 3.64645L47.1716 0.464466C46.9763 0.269204 46.6597 0.269204 46.4645 0.464466C46.2692 0.659728 46.2692 0.976311 46.4645 1.17157L49.2929 4L46.4645 6.82843C46.2692 7.02369 46.2692 7.34027 46.4645 7.53553C46.6597 7.7308 46.9763 7.7308 47.1716 7.53553L50.3536 4.35355ZM0 4.5H50V3.5H0V4.5Z" fill="black"/>
</svg>
And this is the code the I have working right now
svg {
width: 50px;
overflow: visible;
transition: width 0.5s ease;
}
svg:hover {
width: 100px;
}
I also have a Codepen link
https://codepen.io/godhandkiller/pen/xxRZeYv
The problem here is that I'm manipulating the whole SVG but I only need to change the like size.
A possible solution: you can use a line path with a marker-end. The marker is the tip of the arrow. For the animation I'm using SMIL animations changing the d attribute of the path from M1,4L25,4 to M1,4L50,4. The animate element has a begin attribute making the animation to begin when you mouse over the overlaying rectangle: begin="theRect.mouseover". Another animate element animates the path on mouse out: begin="theRect.mouseout"
svg {
border: 1px solid red;
transition: width 0.5s ease;
}
<svg id="theSVG" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 51 8" stroke="#000" stroke-linecap="round">
<defs>
<marker id="m" overflow="visible" markerUnits="userSpaceOnUse">
<path d="M-3,-3L0,0 -3,3" />
</marker>
</defs>
<path d="M1,4L25,4" marker-end="url(#m)">
<animate attributeName="d" to="M1,4L50,4" dur="1s" begin="theRect.mouseover" repeatCount="1" fill="freeze" />
<animate attributeName="d" to="M1,4L25,4" dur="1s" begin="theRect.mouseout" repeatCount="1" fill="freeze" />
</path>
<rect width="100%" height="100%" stroke="none" pointer-events="all" id="theRect" />
</svg>

How to animate an svg line from the center point?

I have the following vertical line as an svg element(made using Inkscape), now i would like to make it to draw itself from the center, instead of top to bottom or bottom to top.
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.136105mm"
height="79.598999mm"
viewBox="0 0 48.136105 79.598999"
version="1.1"
id="bluetoothIconSvg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="bluethood-break-apart-icon.svg">
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-33.604957,-76.75465)">
<path
style="fill:none;
stroke:#000000;
stroke-width:1px;
stroke-linecap:butt;
stroke-linejoin:miter;
stroke-opacity:1"
d="M 49.924165,76.866652 V 156.24165"
id="path4508"
inkscape:connector-curvature="0" />
</g>
</svg>
Also using just a normal html element such as a <div> or a <span>, this could be achieved easily like so HERE. But i would like to achieve the same using an svg.
I'm animating your path although I've removed the transformation and changed the viewBox because I wanted to see the hole path. You can use what you have.
I'm using a SMIL animation but you can use the same idea to animate it using css.
In my code 79.375 is the total length of the path. You can get the total length of path using getTotalLength().
39.69 is the half of the total length.
The main idea is this: I'm animating the stroke-dasharray from strokes = 0 gaps = 79.375 to gaps = 0 strokes = 79.375
Also I'm animating the stroke-dashoffset from="-39.69" to="0"
svg{width:50px; border:1px solid silver;}
<svg
viewBox="40 70 48.136105 95"
>
<g>
<path
style="fill:none;
stroke:#000000;
stroke-width:1px;
stroke-linecap:butt;
stroke-linejoin:miter;
stroke-opacity:1"
d="M 49.924165,76.866652 V 156.24165"
id="path4508"
stroke-dasharray="79.375 0"
stroke-dasharray="-39.69"
>
<animate attributeName="stroke-dasharray"
attributeType="XML"
from="0 79.375" to="79.375 0"
dur="5s"
repeatCount="indefinite" />
<animate attributeName="stroke-dashoffset"
attributeType="XML"
from="-39.69" to="0"
dur="5s"
repeatCount="indefinite" />
</path>
</g>
</svg>

SVG background images not in right location

I have an SVG that has a black and white image, and using paths with background images I want to overlay color images on top of it, making it look like those parts of the image turn into color when you hover over them.
The full code for the svg can be found here.
I am declaring the background images like this:
<style type="text/css">
#BosniaShape {
fill: url(#ColorPattern); /* doesn't seem to work either */
}
</style>
and:
<defs>
<pattern id="BosniaPattern" x="0" y="0" width="4800" height="2720">
<image xlink:href="bosnia.jpg" width="281" height="319" />
</pattern>
</defs>
the base image:
<image xlink:href="map_bw_2560.jpg" width="4800" height="2720" id="bw" />
and the paths:
<path id="BosniaShape" class="st0" d="M1227.5,448.5c-8.99-0.4-9-3-9-6s-5-5-6-10s-1.47-10.68-7.98-11.14s-11.44,1.4-12.56,3.91
…
C1234.43,442.38,1233.27,448.76,1227.5,448.5z"/>
However the result is that the images do not seem to be in the right location. The bosnia.jpg (and other images) do get loaded. They are smaller cutouts of the main image, but in color.
Here are the images.
What am I doing wrong?
If I am understanding you correctly, you should only need two images. The greyscale map and the colour one. Trying to have images of individual countries is just making the job much harder for yourself.
Just have the ColorPattern use the whole coloured version of the map, and use it for all the country shapes.
You didn't include the full paths for your countries, so in the following example, I've just used placeholder squares.
<svg version="1.1" id="map" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 4800 2720">
<style type="text/css">
.st0{
stroke:#000000; /* so you can see them */
stroke-width: 3px;
transition: all 0.3s ease-in-out;
opacity: 0.4;
fill: url(#ColorPattern);
}
path:hover {
opacity: 1;
}
</style>
<defs>
<pattern id="ColorPattern" patternUnits="userSpaceOnUse"
x="0" y="0" width="4800" height="2720">
<image xlink:href="https://i.imgur.com/cPCnxHa.jpg" width="4800" height="2720" />
</pattern>
</defs>
<image xlink:href="https://i.imgur.com/A0PPmdT.jpg" width="4800" height="2720" id="bw" />
<path id="SyriaContestedShape" class="st0" d="M400,400 h800 v800 h-800 Z"/>
<path id="YugoslaviaShape" class="st0" d="M2000,400 h800 v800 h-800 Z"/>
<path id="SyriaShape" class="st0" d="M3600,400 h800 v800 h-800 Z"/>
<path id="TurkeyShape" class="st0" d="M1200,1600 h800 v800 h-800 Z"/>
<path id="BosniaShape" class="st0" d="M2800,1600 h800 v800 h-800 Z"/>
</svg>

Turn off anti-aliasing on svg when applying CSS3:Zoom on the element?

I found that when the CSS3 Zoom is applied on small SVG icons (9px:9px with zoom: 1.5), the SVG icons could be blurry. Any idea to get a sharp and clean icon in this case? Thanks in advance.
The SVG:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
x="0px" y="0px" width="9px" height="9px" viewBox="0 0 9 9" enable-background="new 0 0 9 9">
<g>
<g fill="none" transform="translate(0.5, 0.5)">
<g stroke="#000000" stroke-width="0.5" stroke-linecap="square" >
<line x1="2" y1="4" x2="6" y2="4"/>
<line x1="4" y1="2" x2="4" y2="6"/>
</g>
<g stroke="#909090" stroke-width="1" stroke-linecap="square" >
<rect x="0" y="0" width="8" height="8"/>
</g>
</g>
</g>
</svg>
Got a solution myself. The trick is adding:
shape-rendering="crispEdges"
to the SVG elements.
From Mozilla MDN:
crispEdges
Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels.
See the difference on jsFilddle.

Resources