Is it possible to run two different animations on one SVG element? - javascript

I'm using Snap.svg to do this animation. Basically, I want to rotate an element around a point but I want the element to still face the same way when it's rotating. Please check this http://jsfiddle.net/mabotofu/MpEu4/6/
<svg id="test">
<circle transform="translate(200,200)" r="10" fill="transparent" stroke="#aaa" />
<g>
<circle cx="0" cy="50" r="10" />
<circle cx="0" cy="150" r="10" />
<text x="0" y="100" fill="red">TEST</text>
</g>
</svg>
var paper = Snap(test),
container = paper.select("g");
container
.attr({
fill: "transparent",
stroke: "#aaa",
transform: "translate(200,200)"
})
.animate({
transform: "t200,200r720,0,0"
}, 6000);
In this example, I need the "TEST" text to still stay horizontally even when it's rotating.
toransform="rotate()" is already applied to the element so I can't use rotate again on the lement but I don't know how I can rotate around the center point then also rotate the text itself so it stays horizontally. Please help! Thank you

You can apply the rotation in the opposite direction to the text element:
...
container = paper.select("g");
text = container.select("text");
...
text.animate({transform: "t0,0r-720"}, 6000);
See: JSFiddle

Related

Restrict CSS in .SVG file to that SVG only

We use Umbraco for our customers, and we want to allow them to change icons for certain content.
It's possible to upload and select a custom SVG.
Because we work on a template base, we want to control the color of the icons.
Using javascript, we transform the <img> with an SVG to a HTML <svg>-tag.
That way, we can alter the fill of stroke in the SVG's using regular CSS.
But we ran into an issue, where a customer had uploaded multiple SVG icons which were all having internal CSS and using the same class-names for paths, circles and what not.
The problem is, the last SVG that's on the page overrules the CSS for all SVG's.
For example:
<svg ...>
<defs>
<style>.a{fill: red;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
<svg ...>
<defs>
<style>.a{fill: blue;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
The customer expects a red and a blue circle, because that's what he selected within the CMS.
But this renders to 2 blue circles.
Is there any way to keep CSS found in an SVG within that same SVG?
With a hint from #Lain, I have changed the to script.
It now add's a random-generated classname to the SVG, and prepends that classname to every class in the tag like this:
let styleTag = $svg.find('style');
if (styleTag.length) {
let svgClass = GenerateClassname(8);
const regex = /\.([a-z]{1})/ig; // Get every . followed by a letter
styleTag[0].innerHTML = styleTag[0].innerHTML.replace(regex, "." + svgClass +" .$1");
}
When you inject the svg into the html document, you can add a unique id to each svg and then use it in the css selector.
<svg id="svg-1">
<defs>
<style>#svg-1 .a{fill: red;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
<svg id="svg-2">
<defs>
<style>#svg-2 .a{fill: blue;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
And then, in your near future, you do want to style those individual elements with (global) styling.
shadowDOM (optional part of the native Web Components spec aka Custom Elements)
was created for use-cases like these
supported in all modern browsers
"outside/global" CSS does not leak in
"inside" CSS does not leak out
and inheritable styles, CSS properties and CSS :part can style shadowDOM
customElements.define("svg-circle", class extends HTMLElement{
connectedCallback(){
this.style.display = "inline-block";
this.style.width = "15vw";
this.attachShadow({mode:"open"})
.innerHTML = `<svg viewBox="0 0 100 100">
<style>.a { fill:${this.getAttribute("color")} }</style>
<circle class="a" cx="50" cy="50" r="45" />
<circle part="inner" class="a" cx="50" cy="50" r="20" />
</svg>`;
}
});
<style>
*::part(inner){ fill:rebeccapurple } /* higher Specificity */
</style>
<h2>Who is afraid of</h2>
<svg-circle color="red" ></svg-circle>
<svg-circle color="yellow" ></svg-circle>
<svg-circle color="blue" ></svg-circle>

SVG graph and Javascript: Which is the best way to add animation to and SVG file?

I'm new at coding.
I'm studying the way to make an animated portfolio like Sean Halpin or Stephanie Walter one. I want to put a face, in which, blinking eyes and a moving the mouth would be the animated elements. Basically, I want to play with the visibility of the closed eyes and open mouth. As an example, I drew a face as follows:
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 429 429">
<defs>
<style>
.cls-1 {
fill: #fff;
}
.cls-2 {
fill: none;
stroke: #000;
stroke-miterlimit: 10;
}
</style>
</defs>
<g id="face">
<path class="cls-1" d="M611,608.5a214,214,0,1,1,151.32-62.68A212.6,212.6,0,0,1,611,608.5Z" transform="translate(-396.46 -180)" />
<path d="M611,181a212.9,212.9,0,1,1-83.1,16.78A212.11,212.11,0,0,1,611,181m0-1c-118.46,0-214.5,96-214.5,214.5S492.5,609,611,609s214.5-96,214.5-214.5S729.43,180,611,180Z" transform="translate(-396.46 -180)" />
</g>
<g id="eyes">
<g id="eye_r">
<circle class="cls-1" cx="319.15" cy="128.63" r="48.5" />
<path d="M715.61,260.62a48,48,0,1,1-48,48,48.06,48.06,0,0,1,48-48m0-1a49,49,0,1,0,49,49,49,49,0,0,0-49-49Z" transform="translate(-396.46 -180)" />
</g>
<g id="iris_r">
<circle cx="319.15" cy="128.63" r="19" />
</g>
<g id="eye_l">
<circle class="cls-1" cx="109.85" cy="128.63" r="48.5" />
<path d="M506.32,260.62a48,48,0,1,1-48,48,48.06,48.06,0,0,1,48-48m0-1a49,49,0,1,0,49,49,49,49,0,0,0-49-49Z" transform="translate(-396.46 -180)" />
</g>
<g id="iris_l">
<circle cx="109.85" cy="128.63" r="19" />
</g>
<line id="closed_eye_l" class="cls-2" x1="62.04" y1="128.5" x2="158.04" y2="128.5" />
<line id="closed_eye_r" class="cls-2" x1="270.69" y1="128.23" x2="366.69" y2="128.23" />
</g>
<g id="closed_mouth">
<ellipse cx="214.5" cy="309" rx="108.5" ry="11.5" />
<path d="M611,478c29.08,0,56.41,1.25,77,3.51,30.68,3.38,31,7.32,31,7.49s-.35,4.11-31,7.49C667.37,498.75,640,500,611,500s-56.41-1.25-77-3.51c-30.69-3.38-31-7.32-31-7.49s.35-4.11,31-7.49c20.55-2.26,47.88-3.51,77-3.51m0-1c-60.2,0-109,5.37-109,12s48.8,12,109,12,109-5.37,109-12-48.8-12-109-12Z" transform="translate(-396.46 -180)" />
</g>
</svg>
So, I thought three ways to do this:
Place the svg inside an tag, calling then a function that takes into consideration the loading of the file. An example of what I'm saying is found in the following resource: https://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/, in the "External SVG + External JavaScript" part. It didn't work. The contentDocument ALWAYS returns "null".
In my example, it would be:
HTML:
<object id="face" data="path/to/face.svg" type="image/svg+xml"></object>
JS:
<script type="text/javascript">
window.addEventListener("load", function() {
var svgObject = document.getElementById('face').contentDocument;
var svg = svgObject.getElementById('closed_eye_r');
svg.style.visibility="hidden";
});
</script>
Inline SVG - call a "transform" property. Sean Halpin does it but I'm not sure what he does.
HTML: https://www.seanhalpin.design/
JS: https://www.seanhalpin.design/js/scripts.js
Inline SVG, use getElementById and apply functions to animate the internal parts of the SVG file.
Questions:
a. Is Inline SVG a good practice?
b. Which is the best way to animate an SVG?
I hope to have been clear. Let me know if something is not well presented, I want to learn to edit questions in order to make them as clear as possible.
Thanks!

How to scale up and SVG from with in path instead of adding width and height?

I have this icon in the following code , the problem with this icons is it has a big, margin all over, and in my case I want it to get that margin to be smaller, or the icon a litter bigger, ,instead of increasing the general size as you will see the current implementation in the code.
any idea how to achieve this I tried some solutions but none has worked.
import { ReactComponent as icon } from '../../Img/icon.svg';
// style
const iconStyle = {
padding: 0,
marginTop: -5,
backgroundColor: '#ef6c00',
fill: 'white',
};
// inside the component
<icon style={iconStyle} width='24' height='24' />
you can open your svg into your editor and edit the svg tag directly.
for example here is the circle svg :
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

How do I style one of the parameters in a circle inside an SVG?

I have a SVG with circles inside it. And I want them to be increasing and decreasing in radius for ever (like a pulsating circle).
My problem is, can I do it with #keyframes? Or do I need jquery? And if so, how?
Here is my code:
<div class="mapa">
<svg (svg code here......)
<circle opacity="0.3" cx="842" cy="451.814" r="25.582" id="1"/>
<circle opacity="0.3" cx="542" cy="405.814" r="25.582" id="1"/>
</svg>
</div>
How do I style the 'r' parameter?
I read I cannot style the 'r' parameter, but this worked:
<circle cx="168" cy="179" r="59"
fill="white" stroke="black"
onmouseover="evt.target.setAttribute('r', '72');"
onmouseout="evt.target.setAttribute('r', '59');"
/>
However, I want to do it with continuous increase and decrease in radius? And not on mouseover/mouseleave. Something like (r=25, then r=30, then back to 25, and goes on forever). How do I do this?
Thanks for your time, if you can give me any tips I'd apreciate it a lot!
Try to use svg smil animate
<svg width="150" height="150">
<circle opacity="0.3" cx="84%" cy="45%" r="3" id="1">
<animate attributeName="r" values="3; 10; 3" keyTimes="0; 0.5; 1" dur="1s" repeatCount="indefinite" />
</circle>
<circle opacity="0.3" cx="50%" cy="50%" r="10" id="2">
<animate attributeName="r" values="10; 3; 10" keyTimes="0; 0.5; 1" dur="1s" repeatCount="indefinite"/>
</circle>
</svg>
The easiest solution in CSS with a little hack around SVG containers. You change the container, not the svg. The circle element just fills 100% of the container. And the container artificially makes a circle with a border-radius.
svg {
border-radius: 50%;
transition: all 1s;
}
svg:hover {
width: 200px;
height: 200px;
}
<svg width="100" height="100">
<circle cx="50" cy="50" r="100%"
fill="green" />
</svg>
You can figure out how to implement your own keyframes, if this solution works for you.
And just to be clear, JQuery is a framework. You shouldn't bring up JQuery unless this question is about JQuery's framework. The language you're looking for is "Javascript" and it's in all major browsers by default. You can use Javascript to do this.
const grow = function(radius) {
var circle = document.getElementsByTagName("circle")[0];
circle.setAttribute('r', radius);
}
setTimeout(function() {
grow(100);
setTimeout(function() {
grow(40);
}, 2000);
}, 2000);
circle {
transition: all 1s;
}
<svg width="200" height="200">
<circle cx="100" cy="100" r="40"
fill="green" />
</svg>

Changing style of SVG elements in a g group using JS

Can I change the css style, such as fill or stroke, for all elements within a g group using JS?
Here's the svg, script and the external css:
<g id="trajectories" class="trajectory">
<circle id="tr1" cx="0" cy="0" r="75" />
<circle id="tr2" cx="0" cy="0" r="110" />
<circle id="tr3" cx="0" cy="0" r="160" />
<circle id="tr4" cx="0" cy="0" r="230" />
<circle id="tr5" cx="0" cy="0" r="350" />
<circle id="tr6" cx="0" cy="0" r="475" />
<circle id="tr7" cx="0" cy="0" r="625" />
<circle id="tr8" cx="0" cy="0" r="750" />
</g>
function mouseDown() {
svgElement = document.getElementById("trajectories");
svgElement.style.stroke = "Black";
}
g.trajectory{
fill: none;
stroke: rgba(30,30,30,1);
}
The circles in the g inherit the fill and stroke of the class g.trajectory when first drawn, but attempting to change the styling of the g element does nothing. I could change the styles of the circles individually, but is it possible to change them all just by targeting the g element?
You tried targetting the circle with straight css?
I.E
g circle {color:#ff0000;}
On the fiddles below i added a little bit in between your circle tags just for demo purpose
Here is a fiddle of this http://jsfiddle.net/vTNrR/
Or with jquery
$('#trajectories circle').css('color','#ff0000');
Here is a fiddle of the JQuery approach http://jsfiddle.net/vTNrR/4/
Or with javascript
var svgElement = document.getElementById("trajectories"); // get the parent node
var circles = svgElement.getElementsByTagName('circle'); // get child nodes
You now have an array of elements in circles so can do something like
for (var i=0;i<circles.length;i++)
{
circles[i].style.color="#ff0000";
}
Here is a fiddle of the pure JS version http://jsfiddle.net/vTNrR/1/
What you are doing should work. It works for me. See here:
http://jsfiddle.net/cSk3f/
However you are changing from dark grey to black, so the change is not very noticeable. So in my demo I have used green (rgb(30,80,30)) instead.

Categories

Resources