Jump to content
GreenSock

swampthang

drawSVG mask out to reveal image

Go to solution Solved by swampthang,

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

I'm using Blake's awesome gradient colors code used to create this older codepen.

See the Pen wWPRzW by swampthang (@swampthang) on CodePen

 

I need to make it look like the SVG draws in while the lines animate and then, after a period of time, draw out. I was able to create something that approximates this here:

See the Pen jAQkqv by swampthang (@swampthang) on CodePen

 

Problem is, the client wants the lines to be animating as they draw in. So I thought, hmm, if I can create a mask for each path and assign it to each of the paths in the SVG, I could use a staggerFromTo to draw out the mask to reveal the animating gradients in the masked paths and then draw them back in to hide them again.

 

I'm attempting to dynamically add mask paths to an SVG to cover up the initial image but am unable to get this to work. Anyone know what I'm missing? Do the masks have to be in the same grouping structure as the paths to which they're assigned?

 

See the Pen BzrarZ by swampthang (@swampthang) on CodePen

Link to comment
Share on other sites

How many loops is it supposed to do? And are you going to using a gradient, or just a few colors?

Link to comment
Share on other sites

I've decided to just try to draw in the lines, animated them for a set number of repeats and then draw them out but I'm not having success with chaining these things together. Here's the codepen I'm using 

See the Pen ZOkEpk?editors=1010 by swampthang (@swampthang) on CodePen

 

I've tried creating separate timelines for each stage and adding them to a master timeline as well as just calling the first one and adding an onCompleteAll/onComplete to the other stages but the onCompleteAll (added to a staggerFromTo) is never being called. Scratching my head because no more hair left to pull out.

 

In fact, my first attempt was better so I'm kind of back where I started from: 

See the Pen jAQkqv by sw...hang (@sw...hang) on CodePen

Link to comment
Share on other sites

I don't have time at the moment to dig into your code and offer suggestions, but I wanted to quickly chime in and explain why your onCompleteAll wasn't working. There is no such thing :) It looks like you're literally trying to add an "onCompleteAll" property to the array that gets returned by the TweenMax.staggerFromTo() which won't do anything. There is, however, a parameter you can pass in to the staggerFromTo() method that'll act as an onCompleteAll. It's the 6th parameter. http://greensock.com/docs/#/HTML5/GSAP/TweenMax/staggerFromTo/

 

Oh, and it also looks like you're trying to add an "onComplete" property to timeline instances. There is no such thing - you define an onComplete either in the vars object you pass in, or you can use timeline.eventCallback("onComplete", yourFunction). 

  • Like 2
Link to comment
Share on other sites

Geez, where is @PointC when you need him? He usually responds to every question about SVG masking.

 

How about this...

See the Pen 4e75c43b04d5f0a91e54b5fda9c73105?editors=0010 by osublake (@osublake) on CodePen

 

To collapse the segments individually, each color would need it's own mask.

See the Pen 462717bc2444e5ee0df6989932cceedc?editors=0010 by osublake (@osublake) on CodePen

  • Like 4
Link to comment
Share on other sites

Hey, Blake. Those are exactly what I'm looking for! I'm trying to dynamically implement them to work with any SVG and running in to some problems.

 

I'm using the code from the second one you referenced above in a loop to create the mask nodes giving each pair an id and mask id reference. Your original single line SVG works using this new implementation but I haven't found any other SVGs that do. I tried several different ones but there are always some pieces that don't get masked properly. As always, I'm sure I'm doing something stupid. I start getting cross-eyed and go code blind I guess. 

 

I've learned so much from all you guys. What an awesome community this is. Maybe soon I'll be able to contribute some myself. Don't want to end up being the Dead Sea!

 

Btw, I added a reset button that restores the SVG back to its original state for debugging, etc.

 

See the Pen QEPvzq by swampthang (@swampthang) on CodePen

 

UPDATE: I did find one that works but the stroke is a little squirrely. The one that's not commented out works good but right at the end there's a bit of the last stroke that shows for an extra second. Weird. Trying to figure out what I have to do to assure that I'm covering all the bases in terms of what SVGs might get thrown at me.

Link to comment
Share on other sites

This is the getDash function he is referring to...

http://greensock.com/forums/topic/12201-draw-svg-plugin-to-animate-a-dashed-line/?p=50312

 

I couldn't find where, but there is something funky going on in your code or markup. When I looked at your example earlier, the svg looked messed up even when I removed the mask and all the animations. You changed what you had earlier, but you can see that my path gets messed up in your code.

See the Pen gryjEv?editors=1010 by osublake (@osublake) on CodePen

 

Any artifacts you see are probably caused by the round linecap. If I remove it, look at how it crops the path at the end of the animation.

See the Pen EyJpqP?editors=0010 by osublake (@osublake) on CodePen

 

That's because it's making your stroke longer. See this comparison between the different types of linecaps...

See the Pen 25688253f88307f661e64491a1dea538?editors=1000 by osublake (@osublake) on CodePen

 

To make that work, you're probably need to make some adjustments to some of your values by the however much the linecap is adding to the path.

 

When all else fails, you can manually draw a path using the BezierPlugin. I'm animating a simple object with a head and tail property from 0 to 1, and then on every update I convert those values into a polyline by manipulating a paused bezier tween.

See the Pen 4b7d24a5c99772b218fd09658847766d?editors=0010 by osublake (@osublake) on CodePen

  • Like 2
Link to comment
Share on other sites

See the Pen bZJvEo?editors=1010 by swampthang (@swampthang) on CodePen

shows a couple of SVGs at the top of the HTML section with straight lines that don't animate in the same way as the others. In fact, no straight line works even though they have stroke-width set. What I'm doing is converting everything to paths and wrapping in a defs tag to use for duping a copy for each color. The script gets the total length of each path and calculates the stroke-dasharray so that each colored dup animates in view adjacent to each other. 

 

The first SVG in the codepen gets converted to this (prior to the 4 paths being cloned - 1 clone for each of 4 colors) ...

<svg id="main" xmlns="http://www.w3.org/2000/svg" width="753.93" height="148.68" viewBox="0 0 753.93 148.68">
  <defs>
    <path style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px" id="bottom-line" d="M651.61,123.7 L101.89,123.7"></path>
    <path style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px" id="left-bracket" d="M120.33,24.98 L10.08,24.98,55.02,84.52,10.08,143.68,224.05,143.68"></path>
    <path style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px" id="right-bracket" d="M633.17,24.98 L743.8,24.98,698.48,84.52,743.8,143.68,529.45,143.68"></path>
    <path style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px" id="top-line" d="M101.89,5 L651.61,5"></path>
  </defs>
</svg>

The 2 paths labeled ```bottom-line``` and ```top-line``` aren't being calculated properly. I'm trying to debug this but banging my head against the wall. Any idea why this in happening? If I run a basic drawSVG on the same thing it works just fine.

 

Also, aside from the top 2 SVGs (one of which is commented out), the others (all commented out as well) work fine. Btw, could the lingering piece of line at the end of the animation be a result of the rounded linecap causing the totalLength calculation to be less than the actual length with the linecap and miterlimit?

 

Just to add some extra info from degugger, here's what the mask and path for the ```bottom-line``` path look like:

<mask id="mask-0">
  <path style="fill: none; stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px;" id="bottom-line" d="M651.61,123.7 L101.89,123.7" class="mask-path"></path>
</mask>

and here are the 4 masks and paths that result after the animation runs...

<mask id="path-0-mask0">
  <path style="fill: none; stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dashoffset: -550.72; stroke-dasharray: 1e-05px, 560.72px;" id="bottom-line" d="M651.61,123.7 L101.89,123.7" class="mask-path"></path>
</mask>
<path style="fill: none; stroke: rgb(234, 67, 53); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dasharray: 138.43, 411.29; stroke-dashoffset: -550px;" d="M651.61,123.7 L101.89,123.7" mask="url(#path-0-mask0)"></path>

<mask id="path-0-mask1">
  <path style="fill: none; stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dashoffset: -550.72; stroke-dasharray: 1e-05px, 560.72px;" id="bottom-line" d="M651.61,123.7 L101.89,123.7" class="mask-path"></path>
</mask>
<path style="fill: none; stroke: rgb(251, 188, 5); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dasharray: 138.43, 411.29; stroke-dashoffset: -687px;" d="M651.61,123.7 L101.89,123.7" mask="url(#path-0-mask1)"></path>

<mask id="path-0-mask2">
  <path style="fill: none; stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dashoffset: -550.72; stroke-dasharray: 1e-05px, 560.72px;" id="bottom-line" d="M651.61,123.7 L101.89,123.7" class="mask-path"></path>
</mask>
<path style="fill: none; stroke: rgb(52, 168, 83); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dasharray: 138.43, 411.29; stroke-dashoffset: -825px;" d="M651.61,123.7 L101.89,123.7" mask="url(#path-0-mask2)"></path>

<mask id="path-0-mask3">
  <path style="fill: none; stroke: rgb(255, 255, 255); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dashoffset: -550.72; stroke-dasharray: 1e-05px, 560.72px;" id="bottom-line" d="M651.61,123.7 L101.89,123.7" class="mask-path"></path>
</mask>
<path style="fill: none; stroke: rgb(66, 133, 244); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 10px; stroke-dasharray: 138.43, 411.29; stroke-dashoffset: -962px;" d="M651.61,123.7 L101.89,123.7" mask="url(#path-0-mask3)"></path>
Link to comment
Share on other sites

Oh, hey, Blake. I didn't see your post until after I added the one above. That is weird with the line. Wasn't happening before. Btw, Blake, I replied to your email.

Link to comment
Share on other sites

I couldn't find where, but there is something funky going on in your code or markup. When I looked at your example earlier, the svg looked messed up even when I removed the mask and all the animations. You changed what you had earlier, but you can see that my path gets messed up in your code.

See the Pen gryjEv?editors=1010 by osublake (@osublake) on CodePen

 

 

I figured out what was happening to your path. I had removed some of the css specific to that path so fill was no longer set to "none" and the reason it was getting cut off at the end was because the path moves to 100 before it starts and the svg had no definition so it was cutting off the line. I added these things directly to your SVG and it's fine now. Straight lines still don't work though. 

See the Pen KrYAdo by swampthang (@swampthang) on CodePen

 

That's the latest version of the code.

Link to comment
Share on other sites

Blake, here's your original pen with a single path that's a straight line. 

See the Pen yJAXdm?editors=1010 by swampthang (@swampthang) on CodePen

Looks like the line segments are being positioned right but the masks aren't. Still trying to debug.

Link to comment
Share on other sites

Figured out why the straight lines aren't working. The browser sees them (and the masks) as having height == 0. I even tried testing for horizontal lines and adding a height of the stroke-width but even with a height attribute and a style height, they still show up as having height==0. Gonna have to process all the SVGs having any lone, straight-line paths through something like SVGOMG - https://jakearchibald.github.io/svgomg/ into a single path.

 

This is working now where it wasn't before... 

See the Pen KrYAdo?editors=1010 by swampthang (@swampthang) on CodePen

 

The first (commented out) SVG in the HTML section wasn't working. Had to combine paths to get it to work.

 

Doesn't work...

<svg id="main" xmlns="http://www.w3.org/2000/svg" width="753.93" height="148.68" viewBox="0 0 753.93 148.68">
  <line id="bottom-line" x1="651.61" y1="123.7" x2="101.89" y2="123.7" style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px"/>
  <polyline id="left-bracket" points="120.33 24.98 10.08 24.98 55.02 84.52 10.08 143.68 224.05 143.68" style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px"/>
  <polyline id="right-bracket" points="633.17 24.98 743.8 24.98 698.48 84.52 743.8 143.68 529.45 143.68" style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px"/>
  <line id="top-line" x1="101.89" y1="5" x2="651.61" y2="5" style="fill: none;stroke: #000;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 10px"/>
</svg>

This works. It's the same SVG processed to combine lines into a single path.

<svg xmlns="http://www.w3.org/2000/svg" width="753.93" height="148.68" viewBox="0 0 753.93 148.68">
  <path fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="10" stroke-width="10" d="M651.61 123.7H101.89M120.33 24.98H10.08l44.94 59.54-44.94 59.16h213.97M633.17 24.98H743.8l-45.32 59.54 45.32 59.16H529.45M101.89 5h549.72"/>
</svg>
Link to comment
Share on other sites

  • Solution

Geez, where is @PointC when you need him? He usually responds to every question about SVG masking.

 

How about this...

See the Pen 4e75c43b04d5f0a91e54b5fda9c73105?editors=0010 by osublake (@osublake) on CodePen

 

To collapse the segments individually, each color would need it's own mask.

See the Pen 462717bc2444e5ee0df6989932cceedc?editors=0010 by osublake (@osublake) on CodePen

The solution to the issue in this post is definitely Blake's post quoted above. The final, working version with the single paths not drawing issue fixed is here...

See the Pen KrYAdo?editors=1010 by swampthang (@swampthang) on CodePen

Link to comment
Share on other sites

Lookin' good!

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.
×