Tilt on hover image

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite
1












I am asking for a review of this code to see if I am following common best practices or if there is a better way to accomplish the goal set for this code.



My purpose was to create an image that would CSS3 rotateY() to your mouse's position over it with as close to a semantic approach as I could get and scalable to any size.



My approach was a simple Div->Img tag structure, the div's size is indirectly the image's size due to the design limitation of listeners in JS being attached to the div (this is so the rotation's effect on size doesn't jitter the image around).



Anyway, if I could get some critique I would be very appreciative. Thank you for reading!



Live Version



HTML index.html



<!DOCTYPE html>
<html lang="en">
<head>
<title>Hover Card</title>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<div class="hover-card">
<img src="images/me.jpg" alt="A picture of Torben Leif.">
</div>
</div>

<script src="scripts/main.js"></script>
</body>
</html>


css/style.css



.container 
margin: calc(50vh - 125px) auto;
width: 250px;
height: 250px;


.hover-card
width: 230px;
height: 230px;


.hover-card img
width: 100%;
height: 100%;

border-radius: 20px;
overflow: hidden;
object-fit: cover;
object-position: center 20%; /* Specific To Avatar Image */

transition: .2s linear;
transform-style: preserve-3d;
transform: perspective(600px) rotateY(var(--js-hover-rotate-val));



scripts/main.js



var card = document.querySelector('.hover-card');
var img = document.querySelector('.hover-card img');
var hoverComplete = true; // Used For Smooth Transitions While Rotating.
var degrees = 0; // External For Freeze Fix.

img.addEventListener('transitionend', (e) =>
if(e.propertyName == 'transform')
hoverComplete = true;
);

card.addEventListener('mousemove', (e) =>
if(hoverComplete)
let newDegrees = Math.floor((1 - (e.pageX - card.getBoundingClientRect().left) / card.offsetWidth) * 90 - 45) * -1;
if(newDegrees !== degrees) // Freeze Fix
degrees = newDegrees;
img.style.setProperty('--js-hover-rotate-val', degrees + 'deg');
hoverComplete = false;


);

card.addEventListener('mouseleave', (e) =>
img.style.setProperty('--js-hover-rotate-val', '0deg')
hoverComplete = false;
);






share|improve this question



























    up vote
    3
    down vote

    favorite
    1












    I am asking for a review of this code to see if I am following common best practices or if there is a better way to accomplish the goal set for this code.



    My purpose was to create an image that would CSS3 rotateY() to your mouse's position over it with as close to a semantic approach as I could get and scalable to any size.



    My approach was a simple Div->Img tag structure, the div's size is indirectly the image's size due to the design limitation of listeners in JS being attached to the div (this is so the rotation's effect on size doesn't jitter the image around).



    Anyway, if I could get some critique I would be very appreciative. Thank you for reading!



    Live Version



    HTML index.html



    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>Hover Card</title>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
    <div class="container">
    <div class="hover-card">
    <img src="images/me.jpg" alt="A picture of Torben Leif.">
    </div>
    </div>

    <script src="scripts/main.js"></script>
    </body>
    </html>


    css/style.css



    .container 
    margin: calc(50vh - 125px) auto;
    width: 250px;
    height: 250px;


    .hover-card
    width: 230px;
    height: 230px;


    .hover-card img
    width: 100%;
    height: 100%;

    border-radius: 20px;
    overflow: hidden;
    object-fit: cover;
    object-position: center 20%; /* Specific To Avatar Image */

    transition: .2s linear;
    transform-style: preserve-3d;
    transform: perspective(600px) rotateY(var(--js-hover-rotate-val));



    scripts/main.js



    var card = document.querySelector('.hover-card');
    var img = document.querySelector('.hover-card img');
    var hoverComplete = true; // Used For Smooth Transitions While Rotating.
    var degrees = 0; // External For Freeze Fix.

    img.addEventListener('transitionend', (e) =>
    if(e.propertyName == 'transform')
    hoverComplete = true;
    );

    card.addEventListener('mousemove', (e) =>
    if(hoverComplete)
    let newDegrees = Math.floor((1 - (e.pageX - card.getBoundingClientRect().left) / card.offsetWidth) * 90 - 45) * -1;
    if(newDegrees !== degrees) // Freeze Fix
    degrees = newDegrees;
    img.style.setProperty('--js-hover-rotate-val', degrees + 'deg');
    hoverComplete = false;


    );

    card.addEventListener('mouseleave', (e) =>
    img.style.setProperty('--js-hover-rotate-val', '0deg')
    hoverComplete = false;
    );






    share|improve this question























      up vote
      3
      down vote

      favorite
      1









      up vote
      3
      down vote

      favorite
      1






      1





      I am asking for a review of this code to see if I am following common best practices or if there is a better way to accomplish the goal set for this code.



      My purpose was to create an image that would CSS3 rotateY() to your mouse's position over it with as close to a semantic approach as I could get and scalable to any size.



      My approach was a simple Div->Img tag structure, the div's size is indirectly the image's size due to the design limitation of listeners in JS being attached to the div (this is so the rotation's effect on size doesn't jitter the image around).



      Anyway, if I could get some critique I would be very appreciative. Thank you for reading!



      Live Version



      HTML index.html



      <!DOCTYPE html>
      <html lang="en">
      <head>
      <title>Hover Card</title>

      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="css/style.css">
      </head>
      <body>
      <div class="container">
      <div class="hover-card">
      <img src="images/me.jpg" alt="A picture of Torben Leif.">
      </div>
      </div>

      <script src="scripts/main.js"></script>
      </body>
      </html>


      css/style.css



      .container 
      margin: calc(50vh - 125px) auto;
      width: 250px;
      height: 250px;


      .hover-card
      width: 230px;
      height: 230px;


      .hover-card img
      width: 100%;
      height: 100%;

      border-radius: 20px;
      overflow: hidden;
      object-fit: cover;
      object-position: center 20%; /* Specific To Avatar Image */

      transition: .2s linear;
      transform-style: preserve-3d;
      transform: perspective(600px) rotateY(var(--js-hover-rotate-val));



      scripts/main.js



      var card = document.querySelector('.hover-card');
      var img = document.querySelector('.hover-card img');
      var hoverComplete = true; // Used For Smooth Transitions While Rotating.
      var degrees = 0; // External For Freeze Fix.

      img.addEventListener('transitionend', (e) =>
      if(e.propertyName == 'transform')
      hoverComplete = true;
      );

      card.addEventListener('mousemove', (e) =>
      if(hoverComplete)
      let newDegrees = Math.floor((1 - (e.pageX - card.getBoundingClientRect().left) / card.offsetWidth) * 90 - 45) * -1;
      if(newDegrees !== degrees) // Freeze Fix
      degrees = newDegrees;
      img.style.setProperty('--js-hover-rotate-val', degrees + 'deg');
      hoverComplete = false;


      );

      card.addEventListener('mouseleave', (e) =>
      img.style.setProperty('--js-hover-rotate-val', '0deg')
      hoverComplete = false;
      );






      share|improve this question













      I am asking for a review of this code to see if I am following common best practices or if there is a better way to accomplish the goal set for this code.



      My purpose was to create an image that would CSS3 rotateY() to your mouse's position over it with as close to a semantic approach as I could get and scalable to any size.



      My approach was a simple Div->Img tag structure, the div's size is indirectly the image's size due to the design limitation of listeners in JS being attached to the div (this is so the rotation's effect on size doesn't jitter the image around).



      Anyway, if I could get some critique I would be very appreciative. Thank you for reading!



      Live Version



      HTML index.html



      <!DOCTYPE html>
      <html lang="en">
      <head>
      <title>Hover Card</title>

      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="css/style.css">
      </head>
      <body>
      <div class="container">
      <div class="hover-card">
      <img src="images/me.jpg" alt="A picture of Torben Leif.">
      </div>
      </div>

      <script src="scripts/main.js"></script>
      </body>
      </html>


      css/style.css



      .container 
      margin: calc(50vh - 125px) auto;
      width: 250px;
      height: 250px;


      .hover-card
      width: 230px;
      height: 230px;


      .hover-card img
      width: 100%;
      height: 100%;

      border-radius: 20px;
      overflow: hidden;
      object-fit: cover;
      object-position: center 20%; /* Specific To Avatar Image */

      transition: .2s linear;
      transform-style: preserve-3d;
      transform: perspective(600px) rotateY(var(--js-hover-rotate-val));



      scripts/main.js



      var card = document.querySelector('.hover-card');
      var img = document.querySelector('.hover-card img');
      var hoverComplete = true; // Used For Smooth Transitions While Rotating.
      var degrees = 0; // External For Freeze Fix.

      img.addEventListener('transitionend', (e) =>
      if(e.propertyName == 'transform')
      hoverComplete = true;
      );

      card.addEventListener('mousemove', (e) =>
      if(hoverComplete)
      let newDegrees = Math.floor((1 - (e.pageX - card.getBoundingClientRect().left) / card.offsetWidth) * 90 - 45) * -1;
      if(newDegrees !== degrees) // Freeze Fix
      degrees = newDegrees;
      img.style.setProperty('--js-hover-rotate-val', degrees + 'deg');
      hoverComplete = false;


      );

      card.addEventListener('mouseleave', (e) =>
      img.style.setProperty('--js-hover-rotate-val', '0deg')
      hoverComplete = false;
      );








      share|improve this question












      share|improve this question




      share|improve this question








      edited Feb 6 at 7:47









      Billal BEGUERADJ

      1




      1









      asked Feb 6 at 6:54









      TorbenLeif

      183




      183




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          I find the calculation of tilt a bit complicated. If you know maximum tilt in degrees that shall happen on the left and right edges, you could declare it and a calculation function as



          const MAX_INCLINE = 28; // <- just a guess

          const shift = (w, x, limit = MAX_INCLINE) => (x / w * 2 - 1) * limit;


          Next, Element#getBoundingClientRect, in my opinion, is unnecessary, because you receive all the necessary information in the instance of Event passed to your event listener function:




          • event.target.width is the width of target element that listens to mouse event, meaning the image in your case, and


          • event.offsetX is the position of mouse on X-axis relative to the element, meaning it's closer to 0 when the cursor is closer to the left edge, and closer to X when the cursor is closer to the right edge, where X is width of the element (image).

          Considering this, the event listener function would look as simple as



          (event) => 
          const width = event.target;
          const offsetX = event;

          image.style.setProperty('--js-hover-rotate-val', `$shift(width, offsetX)deg`);
          ;



          A codepen with the final code might be also useful.






          share|improve this answer

















          • 1




            Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
            – TorbenLeif
            Feb 6 at 20:02










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186890%2ftilt-on-hover-image%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          I find the calculation of tilt a bit complicated. If you know maximum tilt in degrees that shall happen on the left and right edges, you could declare it and a calculation function as



          const MAX_INCLINE = 28; // <- just a guess

          const shift = (w, x, limit = MAX_INCLINE) => (x / w * 2 - 1) * limit;


          Next, Element#getBoundingClientRect, in my opinion, is unnecessary, because you receive all the necessary information in the instance of Event passed to your event listener function:




          • event.target.width is the width of target element that listens to mouse event, meaning the image in your case, and


          • event.offsetX is the position of mouse on X-axis relative to the element, meaning it's closer to 0 when the cursor is closer to the left edge, and closer to X when the cursor is closer to the right edge, where X is width of the element (image).

          Considering this, the event listener function would look as simple as



          (event) => 
          const width = event.target;
          const offsetX = event;

          image.style.setProperty('--js-hover-rotate-val', `$shift(width, offsetX)deg`);
          ;



          A codepen with the final code might be also useful.






          share|improve this answer

















          • 1




            Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
            – TorbenLeif
            Feb 6 at 20:02














          up vote
          2
          down vote



          accepted










          I find the calculation of tilt a bit complicated. If you know maximum tilt in degrees that shall happen on the left and right edges, you could declare it and a calculation function as



          const MAX_INCLINE = 28; // <- just a guess

          const shift = (w, x, limit = MAX_INCLINE) => (x / w * 2 - 1) * limit;


          Next, Element#getBoundingClientRect, in my opinion, is unnecessary, because you receive all the necessary information in the instance of Event passed to your event listener function:




          • event.target.width is the width of target element that listens to mouse event, meaning the image in your case, and


          • event.offsetX is the position of mouse on X-axis relative to the element, meaning it's closer to 0 when the cursor is closer to the left edge, and closer to X when the cursor is closer to the right edge, where X is width of the element (image).

          Considering this, the event listener function would look as simple as



          (event) => 
          const width = event.target;
          const offsetX = event;

          image.style.setProperty('--js-hover-rotate-val', `$shift(width, offsetX)deg`);
          ;



          A codepen with the final code might be also useful.






          share|improve this answer

















          • 1




            Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
            – TorbenLeif
            Feb 6 at 20:02












          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          I find the calculation of tilt a bit complicated. If you know maximum tilt in degrees that shall happen on the left and right edges, you could declare it and a calculation function as



          const MAX_INCLINE = 28; // <- just a guess

          const shift = (w, x, limit = MAX_INCLINE) => (x / w * 2 - 1) * limit;


          Next, Element#getBoundingClientRect, in my opinion, is unnecessary, because you receive all the necessary information in the instance of Event passed to your event listener function:




          • event.target.width is the width of target element that listens to mouse event, meaning the image in your case, and


          • event.offsetX is the position of mouse on X-axis relative to the element, meaning it's closer to 0 when the cursor is closer to the left edge, and closer to X when the cursor is closer to the right edge, where X is width of the element (image).

          Considering this, the event listener function would look as simple as



          (event) => 
          const width = event.target;
          const offsetX = event;

          image.style.setProperty('--js-hover-rotate-val', `$shift(width, offsetX)deg`);
          ;



          A codepen with the final code might be also useful.






          share|improve this answer













          I find the calculation of tilt a bit complicated. If you know maximum tilt in degrees that shall happen on the left and right edges, you could declare it and a calculation function as



          const MAX_INCLINE = 28; // <- just a guess

          const shift = (w, x, limit = MAX_INCLINE) => (x / w * 2 - 1) * limit;


          Next, Element#getBoundingClientRect, in my opinion, is unnecessary, because you receive all the necessary information in the instance of Event passed to your event listener function:




          • event.target.width is the width of target element that listens to mouse event, meaning the image in your case, and


          • event.offsetX is the position of mouse on X-axis relative to the element, meaning it's closer to 0 when the cursor is closer to the left edge, and closer to X when the cursor is closer to the right edge, where X is width of the element (image).

          Considering this, the event listener function would look as simple as



          (event) => 
          const width = event.target;
          const offsetX = event;

          image.style.setProperty('--js-hover-rotate-val', `$shift(width, offsetX)deg`);
          ;



          A codepen with the final code might be also useful.







          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered Feb 6 at 15:23









          rm-

          306311




          306311







          • 1




            Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
            – TorbenLeif
            Feb 6 at 20:02












          • 1




            Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
            – TorbenLeif
            Feb 6 at 20:02







          1




          1




          Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
          – TorbenLeif
          Feb 6 at 20:02




          Thank you for your reply and analysis, I greatly appreciate the feedback. Your shift function is undoubtedly more elegant than mine, I was also unaware offsetX worked in this manner. I'll take your advice into consideration in the future.
          – TorbenLeif
          Feb 6 at 20:02












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186890%2ftilt-on-hover-image%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          Will my employers contract hold up in court?