1

I have created a svg image animation. I am trying to make some nice effects with mouseover. I want to move the svg depending on mouse position. The rotate part works fine so far. But I also want to move the <g> inside the svg in z-axis (popout) so they comes out in "different layers". Should be possible with translateZ(). But I can not get it to work.

const container = document.querySelector('.container');
const image = document.querySelector('.image');

const sun = document.querySelector('.sun');
const cloudBehind = document.querySelector('.cloud-center');
const cloudLeft = document.querySelector('.cloud-left');
const cloudRight = document.querySelector('.cloud-right');

const devideAxis = 10;

container.addEventListener('mousemove', e => {
  let xAxis = ~(window.innerWidth / 2 - e.pageX) / devideAxis;
  let yAxis = (window.innerHeight / 2 - e.pageY) / devideAxis;
  
    image.style.transform = `rotateY(${xAxis}deg) rotateX(${yAxis}deg)`;
});

container.addEventListener('mouseenter', e => {
    image.style.transition = 'none';
  //popout
  cloudLeft.style.transform = 'translateZ(400px)'
})

container.addEventListener('mouseleave', e => {
    image.style.transition = 'all 0.5s ease';
    image.style.transform = `rotateY(0deg) rotateX(0deg)`
  
  cloudLeft.style.transform = 'translateZ(0)'
})
body,html {
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
  perspective: 300px;
}

.container {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.image {
  width: 50%;
  transform-style: preserve-3d;
}

.cloud-left {
  transition: all .5s ease-out
}

.cloud-left,
.cloud-right,
.cloud-center {
  transition: transform .5s;
}

.cloud-center{
  fill:url(#CLOUD-CENTER);
}
.cloud-right{
  fill:url(#CLOUD-FRONT);
}
.cloud-left{
  fill:url(#CLOUD-FRONT);
}
.sun{
  fill:url(#SUN);
}
.shine{
  fill:url(#SHINE);
}
<div class="container">
  <div class="image">
    <?xml version="1.0" encoding="utf-8"?>
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
       viewBox="0 0 500 250" >
    
    
    <g id="wheather">
      <radialGradient id="SHINE" cx="100" cy="100" r="100" gradientUnits="userSpaceOnUse">
        <stop  offset="0.7568" style="stop-color:#FFFFFF"/>
        <stop  offset="1" style="stop-color:#FFF3AB"/>
      </radialGradient>
      <linearGradient id="SUN" gradientUnits="userSpaceOnUse" x1="27.6083" y1="98.0519" x2="169.5758" y2="98.0519">
        <stop  offset="0" style="stop-color:#FFF3AB"/>
        <stop  offset="1" style="stop-color:#FFF2C0"/>
      </linearGradient>
      <linearGradient id="CLOUD-CENTER" gradientUnits="userSpaceOnUse" x1="0" y1="66.2549" x2="288.0558" y2="66.2549">
        <stop  offset="0" style="stop-color:#8EABBF"/>
        <stop  offset="1" style="stop-color:#ECF1F7"/>
      </linearGradient>
      <linearGradient id="CLOUD-FRONT" gradientUnits="userSpaceOnUse" x1="0" y1="62.1091" x2="294.4617" y2="62.1091">
        <stop  offset="5.759445e-07" style="stop-color:#FFFFFF"/>
        <stop  offset="1" style="stop-color:#C5D6E5"/>
      </linearGradient>
      
      
      
      <!-- SUN -->
      <g transform="translate(250 0)" class="sun">
        <path class="shine" d="M162.4,147.8l22,0.9l-9.8-15.5c-0.2-0.5-0.5-1-0.8-1.5v0c-3.1-4.9-1.6-11.1,3-14.2l20.3-8.1l-14.9-9.9
          c-0.5-0.5-1-0.9-1.5-1.3h0c-4.9-3.3-6-9.8-2.8-14.5l15-15.3l-17.3-2.9c-0.7-0.3-1.4-0.5-2.2-0.6h0c-6-1-9.7-6.9-8.4-12.6l7.3-19.6
          l-16.9,4.3c-0.7,0-1.5,0.1-2.2,0.3h0c-6.3,1.6-12.5-2.9-12.9-9.4v0c0-0.2,0-0.3,0-0.4l-1.2-19.1l-13.8,10.9
          c-0.6,0.3-1.1,0.7-1.7,1.1c-5.1,4-12.6,2.4-15.6-3.3l0,0c-0.2-0.5-0.5-0.9-0.8-1.3L98.6,0l-8.4,16c-0.3,0.4-0.6,0.9-0.8,1.3v0
          c-3,5.8-10.5,7.4-15.6,3.3h0c-0.5-0.4-1.1-0.8-1.7-1.1L58.3,8.6l-1.2,19.1c0,0.1,0,0.3,0,0.4v0c-0.4,6.5-6.6,11-12.9,9.4h0
          c-0.8-0.2-1.5-0.3-2.2-0.3l-16.9-4.3l7.3,19.6c1.3,5.7-2.4,11.6-8.4,12.6h0c-0.8,0.1-1.5,0.3-2.2,0.6L4.3,68.5l15,15.3
          c3.2,4.7,2.1,11.2-2.8,14.5c-0.6,0.4-1.1,0.8-1.5,1.3L0,109.5l20.3,8.1c4.6,3,6.1,9.3,3,14.2l0,0c-0.3,0.5-0.6,1-0.8,1.5l-9.8,15.5
          l22-0.9c5.4,0.9,9.3,6,8.4,11.7v0c0,0.3-0.1,0.6-0.1,0.9l-2.8,19l19.7-9.8c5-1.3,10.3,1.3,12.2,6.1l5.7,20.4l13.8-16.7
          c3.9-3.4,9.7-3.4,13.5,0l13.8,16.7l5.7-20.4c2-4.9,7.3-7.4,12.2-6.1l19.7,9.8l-2.8-19c0-0.3,0-0.6-0.1-0.9v0
          C153.2,153.8,157,148.7,162.4,147.8z">
          <animateTransform 
            attributeName="transform"
            attributeType="XML"
            type="rotate"
            from="0 100 100"
            to="360 100 100"
            dur="80s"
            repeatCount="indefinite"
          />

        </path>
        <circle class="sun-inside" cx="98.6" cy="98.1" r="71"/>
      </g>
      <!-- / SUN -->
      
      
      
      <!-- CLOUD BEHIND -->
      <g transform="translate(70 70)">
        <path class="cloud-center" style="transform: " d="M261.5,79.4c-3.4,0-6.6,0.6-9.6,1.8c-1.9-5.5-6-10-11.3-12.5c0-0.2,0-0.3,0-0.5c0-27.1-21.9-49-49-49
          c-0.6,0-1.2,0-1.8,0c-9-11.7-23.1-19.2-39-19.2c-18,0-33.8,9.7-42.3,24.1c-3.8-3.1-8.6-5-13.8-5c-11.1,0-20.3,8.4-21.6,19.2
          c-3.7-1.1-7.7-1.7-11.7-1.7C39,36.6,21,54.6,21,76.9c0,2.8,0.3,5.6,0.9,8.3C9.6,86.1,0,96.3,0,108.8c0,13.1,10.6,23.7,23.7,23.7
          h237.8c14.7,0,26.6-11.9,26.6-26.6S276.2,79.4,261.5,79.4z">
          <animateMotion
            path="M50,0 -50,0 50,0 z"
            dur="80s"
            repeatCount="indefinite"
          />
        </path>
      </g>
      <!-- / CLOUD BEHIND -->
      
      
      
      <!-- CLOUD LEFT -->
      <g transform="translate(10 126)">
        <path class="cloud-left" d="M270.4,76.2C270.4,76.2,270.4,76.2,270.4,76.2c-1.1-22-19.3-39.6-41.6-39.6c-5.1,0-9.9,0.9-14.4,2.6
          C206.9,16.4,185.5,0,160.2,0c-20.6,0-38.6,10.9-48.6,27.3c-4.6-1.5-9.4-2.3-14.5-2.3c-23.4,0-42.8,16.9-46.7,39.1
          c-5.1-3.3-11.2-5.2-17.7-5.2C14.6,58.9,0,73.5,0,91.6c0,18,14.6,32.7,32.7,32.7h237.8c13.3,0,24-10.8,24-24
          C294.5,86.9,283.7,76.2,270.4,76.2z M194.9,102.4h-0.2c0.1,0,0.1-0.1,0.2-0.1C194.9,102.4,194.9,102.4,194.9,102.4z">
          <animateMotion
            path="M30,0 0,0 00,0 30,0 z"
            dur="15s"
            repeatCount="indefinite"
          />
        </path>
      </g>
      <!-- / CLOUD LEFT -->



      <!-- CLOUD RIGHT -->
      <g transform="translate(260 140)">
        <path class="cloud-right" d="M228.8,73.7c0-19.9-16.1-36-36-36c-3.5,0-6.8,0.5-10,1.4c-4.4-18.7-21.2-32.7-41.3-32.7c-10.7,0-20.5,4-28,10.6
          C104.6,6.6,91.4,0,76.7,0C49.9,0,28.3,21.7,28.3,48.4c0,1.6,0.1,3.2,0.2,4.8c-0.1,0-0.2,0-0.2,0C12.7,53.2,0,65.9,0,81.5
          s12.7,28.3,28.3,28.3H198v-0.4C215.4,106.8,228.8,91.8,228.8,73.7z">
          <animateMotion
            path="M-40,0 0,0 -100,0 -40,0 z"
            dur="60s"
            repeatCount="indefinite"
          />
        </path>
      </g>
      <!-- / CLOUD RIGHT -->
      
      
    </g>
    </svg>
  </div>
</div>

Main code things:

So I have body, which has perspective: 300px;. Then I have .image which has transform-style: preserve-3d; and inside that element I have the <g>'s with classes.

As an example I have a .cloud-left.

So the structure is basically:

<body>
  <div class="container">
    <div class="image">
      <svg>
        <g id="wheather">
          <g class="cloud-left">...</g>

          ...

       </g>
      </svg>
    </div>
  </div>
</body>

In javascript I have this (Shortned, to see all code, please see the fiddle above):

const cloudLeft = document.querySelector('.cloud-left'); // get the element

container.addEventListener('mouseenter', e => {
  //popout
  cloudLeft.style.transform = 'translateZ(400px)'
})

container.addEventListener('mouseleave', e => {
  //popback
  cloudLeft.style.transform = 'translateZ(0)'
})

But this does not work as I want.

I have also tried to set transform-style: preserve-3d; on <g id="weather"> which is the direct parent to the other <g>'s, but no difference.

I am not getting the <g> to move/popout in z-axis. Am I missing something in the svg or does this not work in svg groups?

I have another example where this works, but it is not an svg: https://jsfiddle.net/saturday99/94o5j8ts/

JoakimB
  • 157
  • 1
  • 11
  • Probably svg path still does not support 3d transform. Have you tried tranforming circle or rect in z-axis ? – mahan Apr 21 '21 at 08:00
  • No I have not, but it still does not solve my problem even if it does work. I think I will try to break out each into an svg, and then try translateZ on each svg instead. A bit of work, but do not know what else to try out. – JoakimB Apr 21 '21 at 08:31
  • 1
    Seems that your answer helped me a bit anyway. Searched "translateZ svg path", since you mentioned "path" and found the answer: https://stackoverflow.com/questions/23230218/why-is-it-not-possible-to-use-transform-translatez-on-svg-path-element. So maybe I can get it to work with separated svg's. – JoakimB Apr 21 '21 at 08:41

1 Answers1

1

Ok, so as I suspected. It worked with svg's instead of groups/paths. Paths/groups are 2D only, as figured out. But svg's are possible to make 3D and use translateZ on. Down here is the answer for the future ones looking for answer. Ps. The code could be cleaned up a bit, but it works.

So the basic structure is now split into many svg's instead of one svg containing many groups:

<body>
  <div class="container">
    <div class="image">
      <svg class="sun">
        <g>

          ...

       </g>
      </svg>
      <svg class="cloud-left">
        <g>

          ...

       </g>
      </svg>

      ...

    </div>
  </div>
</body>

And here is the "finale" code and solution: https://jsfiddle.net/saturday99/fkrh6bzm/. Feel free to fork the code.

JoakimB
  • 157
  • 1
  • 11