Search code examples
javascriptsvgtweensvg-animatesmil

Reverse radialGradient SVG animation on mouseout on hovered element


I want the radialGradient animation to apply to the single hexagon only that you are hovering over and then onmouseout I want the animation to reverse.

How can I make the radialGradient trigger on the hexagon you hover on only (not all the hexagons) and then reverse the animation on mouseout/mouseleave? Thank you.

I tried adding

{   fill: url(#myRadialGradient4);}

to

.filter-class

But obviously as soon as mouseout happens the class is removed stopping the smooth reverse animation on mouseout.

I have tried this:

https://codepen.io/daneli84/pen/OJVZmeJ

// 
var flagBlur = document.querySelector('.flag-blur');
var flags = document.querySelectorAll('.flag');


// 
function startPage() {
  flags.forEach(flag => {
    flag.onmouseover = function() {
      flag.classList.add('filter-class')
      TweenMax.fromTo(flagBlur, 19, {
        attr: {
          stdDeviation: 0.5
        }
      }, {
        attr: {
          stdDeviation: 1
        },
        ease: Power1.easeInOut
      });
    }

    flag.onmouseleave = function() {
      flag.classList.remove('filter-class')
    }
  })
}

startPage();
/* grid styling */
use {-webkit-transition: 5s;
    
 -webkit-transition: all 5s ease;
  transition: all 5s ease;
 
}
use:hover {
  cursor: pointer;
  
 
}

g {   fill: url(#myRadialGradient4);}

#pod { -webkit-transition: all 5s ease;
  transition: all 5s ease;}

text{pointer-events:none;color:white!important;}

.filter-class {
filter: url(#filter-1);

}


/* other styling */
svg {
  width: 800px!important;
  flex: 1;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  margin: 0;
  height: 100vh;
  font-weight: 700;
  font-family: sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg viewBox="0 0 100 100">
  <defs>
    
        <radialGradient id="myRadialGradient4"
           fx="15%" fy="5%" r="65%"
           spreadMethod="pad">
          
          <stop offset="0%"  stop-color="#fff" ></stop>
          <stop offset="100%" stop-color="#50287C"  ></stop>
              <animate attributeName="fy" dur="2s" from="90%" to="0%"  begin="pod.mouseover" end="pod.mouseout;indefinite" fill="freeze"/>
          
          <animate attributeName="fy" dur="2s" from="0%" to="90%"    begin="pod.mouseout" end="pod.mousover;indefinite" fill="freeze"/>
          
       
    </radialGradient>

    
    <filter id="innershadow" x0="20%" y0="5%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur"></feGaussianBlur>
			<feOffset dy="0.2" dx="-0.1"></feOffset>
			<feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite>
			
           <feFlood flood-color="#E5E5C5" flood-opacity="-15"></feFlood>
		   <feComposite in2="shadowDiff" operator="in"></feComposite>
		   <feComposite in2="SourceGraphic" operator="over" result="firstfilter"></feComposite>
          
          
          <feGaussianBlur in="firstfilter" stdDeviation="0.9" result="blur2"></feGaussianBlur>
			<feOffset dy="0.1" dx="0.1"></feOffset>
			<feComposite in2="firstfilter" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite>
			
           <feFlood flood-color="#fff" flood-opacity="0.5"></feFlood>
			<feComposite in2="shadowDiff" operator="in"></feComposite>
			<feComposite in2="firstfilter" operator="over"></feComposite>
		</filter>

      
    </linearGradient>
       <linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(20,0,12);stop-opacity:1;" />
      <stop offset="100%" style="stop-color:rgb(8,20,128);stop-opacity:1" />
    </linearGradient>

    
    
         <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-1">
            <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
            <feGaussianBlur stdDeviation="1" class="flag-blur" in="shadowOffsetOuter1" result="shadowBlurOuter1">
           
           </feGaussianBlur>

            <feColorMatrix values="200 150 255 0 0   255 255 200 0 0   255 0 0 0 0  0 0 0 1 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix>
            <feMerge>
                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
                <feMergeNode in="SourceGraphic"></feMergeNode>
            </feMerge>
        </filter>
    
    <g id="pod">
      <polygon  stroke="#000000" stroke-width="0.1" points="5,-9 -5,-9 -10,0 -5,9 5,9 10,0" />
    </g>
        
        <!-- a transparent grey drop-shadow that blends with the background colour -->
        
  </defs>
  
  <g class="pod-wrap">
    
    <g transform="translate(65, 68)" filter="url(#innershadow)">

      <use xlink:href="#pod" class="h1 flag">
</use>
      <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="2.3" fill="white">TRANSPORT</text>
    </g>
    
    <g transform="translate(50, 41)" filter="url(#innershadow)">
       

      <use xlink:href="#pod" class="h1 flag">
        
</use>
      <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
  
  </g>
    
    
    <g transform="translate(35, 50)" filter="url(#innershadow)" >
       
      <use xlink:href="#pod" class="h1 flag">
</use>
      <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
  
  </g>
    
    <g transform="translate(65, 50)" filter="url(#innershadow)">
       

      <use xlink:href="#pod" class="h1 flag">
</use>
      <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
  
        </g>
    

    <g transform="translate(50, 59)"  filter="url(#innershadow)">
       

      <use xlink:href="#pod" class="h1 flag">
</use>
      <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
  
  </g>


  </g>

</svg>


Solution

  • The radial gradient you are animating would need to be a separate one from the one you are using for the rest of the hexagons.

    On hover you would switch to the alternate gradient and start the <animation> by calling beginElement() on it. You might also need a third <animation> for the reverse animation.

    But that approach is complicated, and I don't think it would produce a very satisfactory result.

    A different approach

    I would recommend a different approach.

    • Make the background of each hexagon a rectangle that has the gradient applied to it
    • then animate that background on hover
    • use a hexagon shaped clipping path on that rect

    You can do that with pure CSS. And it is a lot simpler.

    Note: in the example below I've stripped out the filter to make things simpler to follow for this example.

    .pod-bg {
      -webkit-transition: 5s;
      -webkit-transition: all 5s ease;
      transition: all 5s ease;
    }
    
    .pod-bg:hover {
      transform: translate(0, -16px);
    }
    
    .h1.flag {
      fill: url(#myRadialGradient4);
    }
    
    .pod-stroke {
      stroke: #000000;
      stroke-width: 0.1;
      fill: none;
      pointer-events: none;
      cursor: pointer;
    }
    
    text {
      pointer-events: none;
      color: white;
    }
    
    /* other styling */
    svg {
      width: 800px!important;
      flex: 1;
    }
    
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      margin: 0;
      height: 100vh;
      font-weight: 700;
      font-family: sans-serif;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <svg viewBox="0 0 100 100">
      <defs>
        
        <radialGradient id="myRadialGradient4h" fx="15%" fy="45%" r="65%" spreadMethod="pad">
          <stop offset="0%"  stop-color="#fff" ></stop>
          <stop offset="100%" stop-color="#50287C"  ></stop>
        </radialGradient>
    
        <polygon id="pod" points="5,-9 -5,-9 -10,0 -5,9 5,9 10,0" />
        
        <!-- a rect the same width and double the height of a pod hexagon -->
        <rect id="bg-rect" x="-10" y="-9" width="20" height="36" fill="url(#myRadialGradient4h)"/>
        
        <!-- a clipping path version of the pod hexagon -->
        <clipPath id="pod-clip">
          <use xlink:href="#pod"></use>
        </clipPath>
            
      </defs>
      
      <g class="pod-wrap">
        <g transform="translate(65, 68)">
          <g clip-path="url(#pod-clip)">
            <use xlink:href="#bg-rect" class="pod-bg"/>
          </g>
          <use xlink:href="#pod" class="pod-stroke"></use>
          <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="2.3" fill="white">TRANSPORT</text>
        </g>
        
        <g transform="translate(50, 41)">
          <g clip-path="url(#pod-clip)">
            <use xlink:href="#bg-rect" class="pod-bg"/>
          </g>
          <use xlink:href="#pod" class="pod-stroke"></use>
          <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
        </g>
        
        <g transform="translate(35, 50)">
          <g clip-path="url(#pod-clip)">
            <use xlink:href="#bg-rect" class="pod-bg"/>
          </g>
          <use xlink:href="#pod" class="pod-stroke"></use>
          <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
        </g>
        
        <g transform="translate(65, 50)">
          <g clip-path="url(#pod-clip)">
            <use xlink:href="#bg-rect" class="pod-bg"/>
          </g>
          <use xlink:href="#pod" class="pod-stroke"></use>
          <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
        </g>
        
        <g transform="translate(50, 59)">
          <g clip-path="url(#pod-clip)">
            <use xlink:href="#bg-rect" class="pod-bg"/>
          </g>
          <use xlink:href="#pod" class="pod-stroke"></use>
          <text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5" fill="white">CNI</text>
        </g>
      </g>
    
    </svg>