I have a simple SVG that animates when it comes into viewport (via added class in Javascript). It's a simple bar chart that is supposed to animate the height of 2 rect elements.
It works fine everywhere except iPad Safari 11.1.2 (and maybe below)
When I remove the animation the SVG displays fine. The class is being added via javascript and webkit vendor prefixes are added for browser support.
<style type="text/css">
#keyframes draw {
from {
height: 0;
}
to {
height: 110px;
}
}
#keyframes drawBig {
from {
height: 0;
}
to {
height: 360px;
}
}
#-webkit-keyframes draw {
from {
height: 0;
}
to {
height: 110px;
}
}
#-webkit-keyframes drawBig {
from {
height: 0;
}
to {
height: 360px;
}
}
.animate-bar {
animation: draw 1s linear forwards;
animation-play-state: paused;
-webkit-animation: draw 1s linear forwards;
-webkit-animation-play-state: paused;
}
.animate-bar.bar-large {
animation-name: drawBig;
-webkit-animation-name: drawBig;
}
.play .animate-bar {
animation-play-state: running;
-webkit-animation-play-state: running;
}
</style>
<svg id="diagram" viewBox="0 0 290 472" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="svg" stroke="none" stroke-width="1" fill="#000000" fill-rule="evenodd">
<g id="left">
<rect class="animate-bar" x="0" y="283" width="132" height="107" rx="3" transform="scale(1,-1) translate(0,-676)">
</rect>
<text font-weight="bold">
<tspan x="47.384" y="263">1129</tspan>
</text>
</g>
<g id="right" transform="translate(152,0)">
<rect class="animate-bar bar-large" fill="#EEE6E2" x="0" y="33" width="132" height="360" rx="3" transform="scale(1,-1) translate(0,-426)">
</rect>
<text font-weight="bold">
<tspan x="36.56" y="17">4000</tspan>
</text>
</g>
</g>
</svg>
The CSS is just manipulating the height of the bars in the animation (which is paused until the class is added).
On iOS 11 though the bars just never animate so both heights appear to be 0 and you can't see either.
When I look in dev tools I can see the <rect> elements flashing in the DOM indicating something is happening to them (even though the only thing that should manipulate them is the CSS animation) but they are flashing very fast so I can't see what.
I'm at a loss of what else to try.
Here is a fiddle of the code:
http://jsfiddle.net/peuzdL2n/7/
Works in everything except iOS Safari 11 and below as far as I can see
Related
so I have found this animation and I was trying it, it works perfectly on my computer but once I switch to my phone the animation is just frozen on one frame.
I don't see why it's doing this...
By the way, I am using React, I don't think it matters but we never know.
CSS :
.loader {
max-width: 15rem;
width: 100%;
height: auto;
stroke-linecap: round;
}
circle {
fill: none;
stroke-width: 3.5;
animation-name: preloader;
animation-duration: 3s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
transform-origin: 170px 170px;
will-change: transform;
}
circle:nth-of-type(1) {
stroke-dasharray: 550px;
}
circle:nth-of-type(2) {
stroke-dasharray: 500px;
}
circle:nth-of-type(3) {
stroke-dasharray: 450px;
}
circle:nth-of-type(4) {
stroke-dasharray: 300px;
}
circle:nth-of-type(1) {
animation-delay: -0.15s;
}
circle:nth-of-type(2) {
animation-delay: -0.3s;
}
circle:nth-of-type(3) {
animation-delay: -0.45s;
}
circle:nth-of-type(4) {
animation-delay: -0.6s;
}
#keyframes preloader {
50% {
transform: rotate(360deg);
}
}
HTML :
import React from 'react'
function Animation() {
return (
<div>
<svg class="loader" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 340 340">
<circle cx="170" cy="170" r="160" stroke="#0000FF"/>
<circle cx="170" cy="170" r="135" stroke="#404041"/>
<circle cx="170" cy="170" r="110" stroke="#0000FF"/>
<circle cx="170" cy="170" r="85" stroke="#404041"/>
</svg>
</div>
)
}
export default Animation
Edit : So after trying on my brother's phone, it works, I don't know why it's doing that on my phone but working on others...
I think this happens because you use class instead of className. In React.JS we use className and the only reason behind the fact that it uses className over class is that the class is a reserved keyword in JavaScript and since we use JSX in React which itself is the extension of JavaScript, so we have to use className instead of the class attribute.
import React from 'react';
function Animation() {
return (
<div>
<svg className="loader" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 340 340">
<circle cx="170" cy="170" r="160" stroke="#0000FF"/>
<circle cx="170" cy="170" r="135" stroke="#404041"/>
<circle cx="170" cy="170" r="110" stroke="#0000FF"/>
<circle cx="170" cy="170" r="85" stroke="#404041"/>
</svg>
</div>
)
}
export default Animation
I'm working on some animated SVGs with CSS animations that triggers on hover.
I'm being able to have the SVG animate on hover the way I want to for Chrome but I'm facing a Firefox and Safari issue.
Apparently, the pointer-events property applied to groups <g></g> doesn't give same behavior on this browser than on the other modern ones, at least when trying to set the value to bounding-box.
I'm doing
g {
pointer-events: bounding-box;
}
but the hover only gets triggered when the actual <path> element is hovered, not the whole group <g> as I would need to.
Can I use doesn't say anything about this, it mentions svgs also have support for this property.
Below there's a sample code for you to see how one of my SVGs looks like.
On chrome hovering the main containing group area will trigger the hover animation, on Firefox the actual path (the icon lines in this case) needs to be hovered in order to that to happen.
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<style>
g {
pointer-events: bounding-box;
//not working on FF
}
#mobile:hover .flip {
transform-origin:55% 50%;
-moz-transform-origin:55% 50%;
animation: flip_left 1.6s forwards;
}
#keyframes flip_left {
0% {transform: perspective(2000px) rotateY(90deg) skewY(-1deg)}
30% {transform:perspective(2000px) rotateY(-25deg) skewY(-0.8deg)}
50% {transform:perspective(2000px) rotateY(20deg) skewY(0.8deg)}
70% {transform:perspective(2000px) rotateY(-10deg) skewY(-0.8deg)}
100% {transform:perspective(2000px) rotateY(0deg)}
}
</style>
<!-- Generator: Sketch 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
<title>Mobile solutions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="mobile" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="MS_HP_Usecase_Based_Page-Desktop-2A" transform="translate(-766.000000, -418.000000)" stroke="#00A0DF" stroke-width="1.25">
<g id="Asset-5" transform="translate(766.000000, 418.000000)">
<g class="flip">
<rect id="Rectangle-path" stroke-linecap="round" stroke-linejoin="round" x="12.35" y="7.41" width="15.32" height="25.33" rx="2.03"></rect>
<circle id="Oval" stroke-linecap="round" stroke-linejoin="round" cx="20.01" cy="28.72" r="1.58"></circle>
<path d="M18.43,10.72 L21.48,10.72" id="Shape" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
<circle id="Oval" cx="19.67" cy="19.67" r="19.04"></circle>
</g>
</g>
</g>
</svg>
I would like to find a workaround for this, since I want to make this animations work cross browser. I would like to eventually make it work for IE11 and Edge too.
Thanks,
So pointer-events: bounding-box seems to not be supported by most browsers.
I implemented the workaround #ccprog suggested on the comments section of my question.
I added a <rect fill="none"> element to svg, that is same dimensions than the SVG itself. I added a :hover selector for that element and sibling selector ~ to select its sibling group with the flip class inside.
See CSS:
#mobile-hover {
visibility: visible;
pointer-events: visible;
}
#mobile-hover:hover ~ .group .flip {
-moz-transform-origin:55% 50%;
-webkit-transform-origin: 55% 50%;
transform-origin:55% 50%;
-webkit-animation: flip_left 1.6s forwards;
animation: flip_left 1.6s forwards;
}
I found out I had to add pointer-events: visible to the rect element so it would detect the :hover. I added visibility: visible as a requirement to pointer-events: visible to work.
Below the full new SVG code:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mobile-icon">
<style>
#mobile-hover {
visibility: visible;
pointer-events: visible;
}
#mobile-hover:hover ~ .group .flip {
-moz-transform-origin:55% 50%;
-webkit-transform-origin: 55% 50%;
transform-origin:55% 50%;
-webkit-animation: flip_left 1.6s forwards;
animation: flip_left 1.6s forwards;
}
#keyframes flip_left {
0% {transform: perspective(2000px) rotateY(90deg) skewY(-1deg)}
30% {transform:perspective(2000px) rotateY(-25deg) skewY(-0.8deg)}
50% {transform:perspective(2000px) rotateY(20deg) skewY(0.8deg)}
70% {transform:perspective(2000px) rotateY(-10deg) skewY(-0.8deg)}
100% {transform:perspective(2000px) rotateY(0deg)}
}
</style>
<!-- Generator: Sketch 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
<title>Mobile solutions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="mobile" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" >
<rect fill="none" width="40" height="40" id="mobile-hover">
</rect>
<g id="MS_HP_Usecase_Based_Page-Desktop-2A" transform="translate(-766.000000, -418.000000)" stroke="#00A0DF" stroke-width="1.25" class="group">
<g id="Asset-5" transform="translate(766.000000, 418.000000)">
<g class="flip">
<rect id="Rectangle-path" stroke-linecap="round" stroke-linejoin="round" x="12.35" y="7.41" width="15.32" height="25.33" rx="2.03"></rect>
<circle id="Oval" stroke-linecap="round" stroke-linejoin="round" cx="20.01" cy="28.72" r="1.58"></circle>
<path d="M18.43,10.72 L21.48,10.72" id="Shape" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
<circle id="Oval" cx="19.67" cy="19.67" r="19.04"></circle>
</g>
</g>
</g>
</svg>
Works on Chrome, Safari and Firefox and I'm attempting to test IE11 and Edge next.
Many thanks,
Assuming I have an svg made with inkscape.
In this SVG set with a viewbox, I want to animate each element inside the SVG.
There is no problem for translate or opacity ... but when I need to rotate or scale a single element, it acting weird.
I try to correctly understand the concept of the viewbox but I need some help.
I understand that I have only one origin point when I have only one viewbox should I set multiple viewbox ?
<?xml version="1.0" encoding="UTF-8"?>
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
// rotate or scale acting weird
<ellipse id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
// rotate or scale acting weird
<rect id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00;paint-order:normal"/>
// rotate or scale acting weird
<path id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;paint-order:normal"/>
</svg>
I'm using anime.js 3.0 or CSS or I can try anything else
In Svg, the coordinates of any figure always have an absolute value that is calculated from the upper left corner of the SVG canvas.
Therefore, when applying the scale (2) command, the coordinates of the center of the figure will also be doubled and the figure will shift to the right and down.
<svg id="SVGRoot" version="1.1" width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" style="border:1px solid grey;">
<rect id="rect9240" transform="scale(2)" x="100" y="100" width="100" height="100" style="fill-rule:evenodd;fill:#f00;> stroke:#000; paint-order:normal">
<animateTransform
xlink:href="#rect9240"
attributeName="transform"
type="scale"
values="1;2;2;1;1"
dur="8s"
fill="freeze"
repeatcount="indefinite"
/>
</rect>
<circle cx="150" cy="150" r="3" fill="black" />
<circle cx="300" cy="300" r="3" fill="dodgerblue" />
<text x="150" y="140" font-size="16px" text-anchor="middle" > Center (150,150) </text>
<text x="300" y="290" font-size="16px" text-anchor="middle" > Center (300,300) </text>
</svg>
To return the enlarged figure to its original position, you must use the command translate (X, Y)
There is a great post here by #Paul LeBeau where this is explained in detail.
CSS solution
In order not to calculate the position of the center of the figure, you can use the CSS rule transform-box: fill-box
When the value of the fill-box attribute is selected
The object bounding box is used as the reference box.
Below is an example of increasing and decreasing the size of figures:
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: scale 3s linear infinite alternate;
animation-direction: alternate;
transform-origin:50% 50%;
}
#keyframes scale {
0% { transform: scale(0.5); }
100% { transform: scale(1); }
}
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
Rotation example
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: spin 4s linear infinite alternate;
transform-origin:50% 50%;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
Increase and rotation
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: scale1 4s linear, spin 4s linear 4s infinite alternate;
transform-origin:50% 50%;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#keyframes scale1 {
0% { transform: scale(0.5);}
100% { transform: scale(1);}
}
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
I guess you mean the transform-origin CSS propierty. It is related to the center point of the svg file. Then, you need to calculate the center point of the element to animate related to document's center point.
For the animations you can use CSS animations.
The basics of viewBox is that the 4 numbers are "x y width height”. Generally the x/y coordinates are 0 which keeps your origin in the top left corner. Something people often do is place the origin in the middle.
In order to do that you move your viewBox top left by half of the width and half the height. In your case "-350 -250 700 500".
How to create an cross browser (Mozilla, Chrome, Safari), animated SVG donut?
Currently I got this: https://jsfiddle.net/odnmhvm6/1/
This seems to be fine and exactly what I want (macOS, Chrome) but some problems appear: (ordered by priority)
Its oversized r="3200" to fit mostly all resolutions, how to make it responsive? -> Later I would add content in the inner-circle (solved by viewBox attribute )
Do not work on mobile (iPhone 6, Safari & Chrome) (done by using fixed values instead of calc())
Without the CSS Offset of .circle > stroke-dashoffset > -50 it laggs at start
I'm not that comfortable with SVG and that's the best result I reached so far, maybe I made it completly wrong for my purpose?
It should be responsive, fill out the complete screen always and work well with the common browsers. JS would be fine too, but is it necessary to reach it?
.item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
svg {
width: 100%;
height: 100%;
}
.circle {
stroke-dasharray: 20106.192982975;
stroke-dashoffset: 20106.192982975;
-webkit-animation: circle-in 3s ease-in-out forwards, fade-in 0.5s ease-out forwards;
}
#-webkit-keyframes circle-in {
to {
stroke-dashoffset: 0;
}
}
<div class="item">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<g>
<circle id="circle" class="circle" r="3200" cy="50%" cx="50%" stroke-width="6200" stroke="#000000" fill="none"/>
</g>
</svg>
</div>
How to create a power bar which will toggle automatically up and down and will stop when i click on the screen.
http://i.stack.imgur.com/L3JSH.jpg
You will need to be more specific about what exactly you have tried and what is not working. However, this should get you started. This example uses sgv but could easily be translated into a more div oriented approach.
The objective is to hit the toggle button when the circle is in the center region. Good Luck!
Note: This might only work in chrome at the moment.
document.getElementById("toggler").addEventListener("click", function(){
var el = document.querySelector("circle");
var className = "stopped";
el.classList.toggle(className);
if (!el.classList.contains(className)) { return }
var currentCX = parseFloat(getComputedStyle(el).getPropertyValue("cx"));
if (currentCX >= 240 && currentCX <= 260 ) {
console.log("hit");
} else {
console.log("miss");
}
});
#keyframes sweep {
from { cx: 5; }
to { cx: 495; }
}
circle{
animation-duration: 3s;
animation-timing-function: ease-in-out;
animation-name: sweep;
animation-iteration-count: infinite;
animation-direction: alternate;
}
circle.stopped{
animation-play-state: paused;
}
<svg id="lineWithDots" width="500px" height="20px">
<g transform="translate(0,10)">
<rect width="490" height="2" y="-1" x="5" />
<rect width="20" height="10" y="-5" x="240" />
<circle r="4" cx="5" stroke="rgb(0, 0, 0)" fill="rgb(255, 255, 255)" />
</g>
</svg>
<div>
<button id="toggler">toggle</button>
</div>