Jump to content
Search Community

Non-inline SVG, mouseover transform

Smudger test
Moderator Tag

Go to solution Solved by Jonathan,

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi! I've just started with GSAP and I might be asking an impossible thing - it was trying to achieve it that led me to GSAP.

 

I have a super-complex SVG that I have as an <object> in an HTML doc. (I read that this was the best way to include SVGs, plus the code really is too large to put inline).

 

I have successfully used code from this topic http://greensock.com/forums/topic/12321-non-inline-svg-and-control-with-gsap/ to select a class in the SVG.

 

What I need is to implement something like this http://greensock.com/forums/topic/6435-simple-hoverzoom-on-multiple-divs/ on the class, as I want those elements to scale from centre on mouseover.

 

But I can't get it to work! Applying a transform on page load works, but not on mouseover. If anyone has any ideas - or a different way to achieve the requirement - I would be extremely grateful.

 

(My class isn't really called 'class'; that's just to keep things simple)

<div class="diagram_container">
    <object id="diagram" type="image/svg+xml" data="images/software_diagram.svg"></object>			
</div>
function foo(){
    var svgObject = document.getElementById("diagram"),
    svgDoc = svgObject.contentDocument,
    svgChild = svgDoc.querySelectorAll(".class");
    TweenMax.to(svgChild, 1, {rotation:360, transformOrigin:"50% 50%", repeat:2});//not actually used, but works on page load
}
//wait until object is loaded (lazy)
TweenLite.delayedCall(1, foo);

//Doesn't seem to work:
    $('.class').hover(
    function() {
    TweenMax.to(this, .5, {css: {scale: 2},ease: Circ.easeOut});
    }, function() {
    TweenMax.to(this, .5, {css: {scale: 1},ease: Circ.easeOut});
});

//Also doesn't seem to work:
    $(document).on("mouseenter", ".class", function(){
    var $this = $(this);
    TweenMax.to($this, .5, {scale:2});
    }).on("mouseleave", ".class", function(){
    var $this = $(this);
    TweenMax.to($this, .5, {scale:1});
});
Link to comment
Share on other sites

Hello Smudger, and Welcome to the GreenSock forum!

 

There might be an issue if you are binding events first with jQuery hover() and then again with jQuery on() for mouseleave  and mouseenter for the same element.

 

Do you have an code example so we can see your code example in context?

Here is a video tut on how to create a codepen example.



This way we can test your code live on codepen to better help you!

Thanks!
  • Like 1
Link to comment
Share on other sites

Hi Jonathan, and thanks for the quick reply.

 

I understand the principle of using codepen to identify errors but I'm not sure I can use it in this case as my SVG is not inline?

 

There isn't really much more code to show anyway - the page is basically a div with the SVG <object> inside. The only jquery used is that shown in my post above. That, plus <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>, is placed at the end of the <body>.

Link to comment
Share on other sites

Hi Smudger,

 

You should just use the mouseenter and mouseleave, and get rid of the hover() event handler, this way you don't have to worry about event bubbling.

// create a timeline in a paused state
var tl = new TimelineMax({
   paused: true
});

// set any initial CSS properties and values that are not set in your CSS stylesheet
TweenLite.set(".class",{scale:1});

// your GSAP tweens go here
// tl is your new TimelineMax instance
tl.to(".class", 0.5, {scale:2}); 

$(document).on("mouseenter", ".class", function(){
    // play this puppy
    tl.play();
}).on("mouseleave", ".class", function(){
    // bring that puppy back
    tl.reverse();
});

Here are some examples of mousenter and mouseleave working for a single element:

 

See the Pen tukhf by jonathan (@jonathan) on CodePen

See the Pen NxVMBx by jonathan (@jonathan) on CodePen

See the Pen obRyBr by jonathan (@jonathan) on CodePen

 

And hovering over multiple elements:

 

See the Pen rOgVEd by jonathan (@jonathan) on CodePen

See the Pen KdYqWo by jonathan (@jonathan) on CodePen

 

All those codepen's above just play() the timeline on mouseenter and then reverse() when mouseleave, creating only one tween. This way you are only creating one timeline instead of creating new tweens on each mouseenter and mouseleave. This way you one timeline to rule them all.

 

If you are still having an issue then try making a codepen with the svg inline. Since to me it could be an issue of the obj not fully loading the svg within the object element. But that would be difficult to debug without testing the code live like in codepen.

 

Hope this helps!

  • Like 4
Link to comment
Share on other sites

Thanks again for the help!

 

It's likely that I won't need to achieve transforms on non-inline SVG after all, having read that including SVG as <object> is bad for accessibility. The mouseover code will still come in very handy of course.

  • Like 1
Link to comment
Share on other sites

New problem..!

 

I used one of the examples you provided to animate a scale transform on mouseenter/mouseleave, which worked.

 

I needed to add code to bring the item being hovered to the 'front' each time, so I added "el.parentNode.appendChild(el);" within the mouseenter function. This works, but not in IE... the reverse animation doesn't seem to fire on mouseleave so the items stay in the scaled-up mouseenter state.

 

I'm sure it's my crappy knowledge of jquery to blame. If someone could advise how to fix I'd be most grateful.

// set some global properties
TweenMax.set(".zoom", {transformOrigin:"50% 50%"});

// loop through each element
$(".zoom").each(function(i, el) {

// create a timeline for this element in paused state
var tl = new TimelineMax({paused: true});

// create your tween of the timeline in a variable
tl
.set(el,{willChange:"transform"})
.to(el, 0.4, {scale:2, ease:Power1.easeInOut});

// store the tween timeline in the javascript DOM node
el.animation = tl;

//create the event handler
$(el).on("mouseenter",function(){
//this.style.willChange = 'transform';
this.animation.play();
el.parentNode.appendChild(el);
}).on("mouseleave",function(){
//this.style.willChange = 'auto';
this.animation.reverse();
el.parentNode.insertBefore(el,el.parentNode.firstChild);
});
});
Link to comment
Share on other sites

Hello Smudger

 

Can you please set your new question and example in a new codepen. So this way we can better assist you with this new issue you are seeing in IE. And i presume that you are seeing this in IE11, right?

 

So this way we can see if your still animating DOM elements or SVG DOM elements. If they are not SVG then to bring forward or backwards you can just simply change the z-index. If they are SVG child elements then you must append or prepend to move forward and backward.

 

Also you wont need to use will-change CSS property, that was there in my example for a special purpose. ;)

 

Thanks! :)

Link to comment
Share on other sites

Hi Jonathan

 

Yes, it's in IE11 and the elements are SVG. Here's a codepen with the essentials, though the scaling doesn't work at all there... my coding is so crappy.

 

See the Pen VKkEAr by Smudger (@Smudger) on CodePen

 

The principle of what I want to achieve is: inline SVG with multiple rects, each rect scales x2 on mouseenter, scales back to 1x on mouseleave.

 

Thanks for any help!

Link to comment
Share on other sites

From what i See this is a not a GSAP issue but an event binding issue. The original example used DOM elements, and did not remove elements from the DOM. But in your example your using SVG DOM elements. And in order for you to bring front or back in SVG you must append or prepend elements to fake z-index. There seems to be some weird jQuery on() bug in IE11 is causing it to stop listening for the changes to the DOM. In this case the removal of .zoom <rect> SVG element.

 

If you comment out your appendChild() and the insertBefore() you can see that IE11 works.

 

See the Pen vXBqZb by jonathan (@jonathan) on CodePen

 

But with appendChild() and insertBefore() it does not work in IE11 after first mouseenter:

 

See the Pen GjKbdV by jonathan (@jonathan) on CodePen

 

If you look in the browser console you will see that my console.log("mouseleave") text does not even output in the console. Only console.log("mouseenter") outputs showing that the event handler is not firing, The same goes if you use mouseout. So this is a IE11 bug. You can try and clone the element and make sure event handlers are cloned along with it once it it is appended or inserted. But either way it looks like IE11 loses it attached event handlers after an SVG element is appeneded or inserted. IE11 is notorious for not playing nice with SVG.

 

For example if you target SVG elements with jQuery in IE11 you should not use .zoom as selector. You have to use an attribute selector like this [class=zoom], Otherwise your in bug city since jQuery when in IE11 does not use getElementByClassName for child SVG elements, which are used in its selector engine called Sizzle: https://github.com/jquery/sizzle/issues/322

  • Like 2
Link to comment
Share on other sites

  • 3 years later...

@Jonathan @Carl How how would this work if you want to hover over one object, and it triggers the scaling animation of a different object? Is it possible to do that without parenting the second object to the first object? For example, I want to hover text, which then scales an image.

Link to comment
Share on other sites

6 hours ago, Chronic said:

How how would this work if you want to hover over one object, and it triggers the scaling animation of a different object? Is it possible to do that without parenting the second object to the first object? For example, I want to hover text, which then scales an image.

Sure, it's quite simple. Something like this should work:

myText.addEventListener("mouseenter", function() {
  gsap.to(myImage, {scale: 0.5});
});

If something is not working for you then you should create a new thread and include a minimal demo of the setup. This thread talks more about how to do so:

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...