Reputation: 611
I'm using greensock to animate an svg clippath, and it works great with one clippath, and hardcoded variables. Now I'm needing to add more clippaths, and I need each one to animate independently. So I need to build some sort of function to detect which circle is being moused over/ moused out and then call the timeline, passing it the correct parameters (the clippath and overlay circle). I'm sure I could probably do that with 'this' but I'm still at the point where 'this' makes my brain melt. Here's the codepen I'm working on.
http://codepen.io/kathryncrawford/pen/JYvdzx
HTML
<svg class="svg-graphic" width="500" height="500" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<clipPath id="clippath">
<circle id="clip1" cx="200" cy="200" r="2.5"/>
<circle id="clip2" cx="400" cy="200" r="3.2"/>
</clipPath>
</defs>
<image class="svg-image1" xlink:href="http://lorempixel.com/300/300/" width="300" height="300" x="80" y="80"/>
<circle id="circle1" fill="#CC66FF" cx="200" cy="200" r="30"/>
<image class="svg-image2" xlink:href="http://lorempixel.com/300/300/" width="300" height="300" x="380" y="80"/>
<circle id="circle2" fill="#CC66FF" cx="400" cy="200" r="30"/>
JS
var clip = document.getElementById("clip1");
var circles = document.getElementById("circle1");
circles.addEventListener("mouseenter", expand);
circles.addEventListener("mouseleave", contract);
var tl = new TimelineMax({paused: true});
tl.to(clip, 0.5, {
attr: {
r: 120
},
transformOrigin: "50% 50%",
ease: Power4.easeInOut
})
.to(circles, 0.5, {alpha:0, ease:Power4.easeInOut}, '-0.1');
function expand() {
tl.play();
}
function contract() {
tl.reverse();
}
Upvotes: 0
Views: 97
Reputation: 5737
All right, this is what I was able to create by forking your pen.
And here is what has changed:
circle
HTML elements present inside the clipPath
HTML element i.e. clipPath
's children. Instead, I have given all of these circle
tags a clip
class.circle
elements that are siblings of the said clipPath
i.e. present on the same level as clipPath
element, have been given a circle
class.image
elements, I have done similar thing. Removed unique IDs from them and instead gave them a common svg-image
class.#circle1
, #circle2
, #svg-image1
and #svg-image2
, I have removed them from CSS as well and instead applied exactly the same rules they had on the newly created classes i.e. .circle
and .svg-image
respectively.clip
and circle
elements as well as the total number of clip
elements are first stored in variables clips
, circles
and numClips
respectively.timelines
created initially.numClips
and which does two things:
createTimeline
as the name suggests, is supposed to create a TimelineMax
instance which looks similar to what you previously had i.e. it adds two tweens, one for animating the opacity
on the current circle
element (remember, we are inside a loop and we have a reference of current circle
element by the use of circles[i]
) and the other for animating r
of the current clip
element.assignListeners
is for listening to mouseenter
and mouseleave
events on each of the circle
elements.expand
and collapse
methods are for playing or reversing the current timeline instance. (again, we have the reference of the timeline
that should be playing when hovered or out using timelines[i]
reference).HTML:
<svg class="svg-graphic" width="500" height="500" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<clipPath id="clippath">
<circle class="clip" cx="200" cy="200" r="20" />
<circle class="clip" cx="400" cy="200" r="20" />
<circle class="clip" cx="600" cy="200" r="20" />
</clipPath>
</defs>
<image class="svg-image" xlink:href="http://lorempixel.com/300/300/" width="300" height="300" x="80" y="80" />
<circle class="circle" fill="#CC66FF" cx="200" cy="200" r="20" />
<image class="svg-image" xlink:href="http://lorempixel.com/300/300/" width="300" height="300" x="380" y="80" />
<circle class="circle" fill="#CC66FF" cx="400" cy="200" r="20" />
<image class="svg-image" xlink:href="http://lorempixel.com/300/300/" width="300" height="300" x="680" y="80" />
<circle class="circle" fill="#CC66FF" cx="600" cy="200" r="20" />
</svg>
CSS:
*{
box-sizing: border-box;
}
body{
margin: 0;
padding: 0
}
.circle{
position: absolute;
margin: 0;
z-index: 1;
clip-path: url("#clippath");
}
.svg-image {
z-index: 3;
clip-path: url(#clippath);
}
svg{
overflow: visible;
}
.svg-graphic {
position: absolute;
}
.imgContainer {
position: relative;
width: 800px;
height: 800px;
}
JavaScript:
var clips = document.getElementsByClassName('clip');
var circles = document.getElementsByClassName('circle');
var numClips = clips.length;
var timelines = [];
for (var i = 0; i < numClips; i += 1) {
createTimeline(i);
assignListeners(i);
}
function createTimeline(i) {
var timeline = new TimelineMax({ paused: true });
timeline.to(circles[i], 0.6, { opacity: 0, ease: Expo.easeInOut }, 0);
timeline.to(clips[i], 0.6, {
attr: { r: 120 },
transformOrigin: '50% 50%',
ease: Expo.easeInOut
}, 0.1);
timelines[i] = timeline;
}
function assignListeners(i) {
(function(i) {
circles[i].addEventListener('mouseenter', function(e) { expand(e, i); }, false);
circles[i].addEventListener('mouseleave', function(e) { contract(e, i); }, false);
}(i));
}
function expand(e, i) { timelines[i].play(); }
function contract(e, i) { timelines[i].reverse(); }
Hope this helps.
Upvotes: 1