1

Am trying to achieve this (built using webflow) animation and interaction when hovering on an element but am not able to do so. I've found this answer here but when I tried to refactor it with on hover function I still couldn't make it work.

Here's what I've tried.

// Maximum offset for image
        var maxDeltaX = 50,
            maxDeltaY = 50,
            viewportWidth = 0,
            viewportHeight = 0,
            mouseX = 0,
            mouseY = 0,
            translateX = 0,
            translateY = 0;
        // Bind mousemove event to document
        jQuery('.image-content-right').on('mousemove', function(e) {
            // Get viewport dimensions
            viewportWidth = document.documentElement.clientWidth,
                viewportHeight = document.documentElement.clientHeight;
            // Get relative mouse positions to viewport
            // Original range: [0, 1]
            // Should be in the range of -1 to 1, since we want to move left/right
            // Transform by multipling by 2 and minus 1
            // Output range: [-1, 1]
            mouseX = e.pageX / viewportWidth * 2 - 1,
            mouseY = e.pageY / viewportHeight * 2 - 1;
            // Calculate how much to transform the image
            translateX = mouseX * maxDeltaX,
            translateY = mouseY * maxDeltaY;
            jQuery('.cyan').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
            jQuery('.small-cyan').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
            jQuery('.small-darktangirine').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
        }).hover(function() {
            jQuery('.cyan').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
            jQuery('.small-cyan').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
            jQuery('.small-darktangirine').css('transform', 'translate(' + translateX + 'px, ' + translateY + 'px)');
        })

It's a little bit clunky and not as smooth as what I want to achieve and also I would want it to go back to its original position when not hovered.

leonardeveloper
  • 1,813
  • 1
  • 34
  • 58

2 Answers2

0

I'm not too sure how you'd really do much more to make that function a little smoother really considering its really depending on how often jQuery itself would execute its events. For now maybe I'd consider splitting all the code within your jQuery event declaration into their own respective functions. It'll be a lot easier and cleaner for you to work on :)

function animateElementOnMouseMove() {
   // your translate code
}
function animateElementOnMouseHover() {
   // your initial hover animation code
}
$('.image-content-right').on('mousemove', animateElementOnMouseMove)
                         .on('hover', animateElementOnMouseHover);

for it to return back to the position you had it at before you could either save an original untranslated position of each of the elements OR, you could save each of the translations into a count variable, then "undo" the translations after the element has become unfocused.

like:

var elementTranslateCountX = 0;
var elementTranslateCountY = 0;

// ON TRANSLATE
elementTranslateCountX += translateX;
elementTranslateCountY += translateY;

0

By the looks and feel of the webflow thing (if I understand your goal correctly) you want to be able to move your object by the full maxDeltaX/Y within the hover area. If that's the case, your math needs some adjustments: you need to define an origin (the center of the moving object most likely) and normalize to [-1, 1] the hover area around the origin. Placing the object in the dead center of the hover box simplifies calculations. I'm posting the code in a snippet, but it should be run on a full page because the coordinates are not correctly calculated. Funnily enough, if I run it on codepen, it works as expected on Chrome, but not on Safari. To avoid this issue you should wrap everything in a parent div and calculate coordinates relative to it

const page = document.getElementById("page-id");
const area = document.getElementById("area-id");
const box = document.getElementById("box-id");

// we want to move the object by 50px at most
const maxDeltaX = 50;
const maxDeltaY = 50;

let pageBox = page.getBoundingClientRect();
let pageTopLeft = {
  x: pageBox.x,
  y: pageBox.y
};

let areaBox = area.getBoundingClientRect();
let areaRange = {
  w: areaBox.width / 2.0,
  h: areaBox.height / 2.0
};

let boxBox = box.getBoundingClientRect();
let transformOrigin = {
  x: boxBox.x + (boxBox.width / 2.0),
  y: boxBox.y + (boxBox.height / 2.0)
};

// multipliers allow the full delta displacement within the hover area range
let multX = maxDeltaX / areaRange.w;
let multY = maxDeltaY / areaRange.h;

area.addEventListener("mousemove", onMove);
area.addEventListener("mouseleave", onLeave);
window.addEventListener("resize", onResize);

// mouse coords are computed wrt the wrapper top left corner and their distance from the object center is normalized
function onMove(e) {
  let dx = (((e.clientX - pageTopLeft.x) - transformOrigin.x));
  let dy = (((e.clientY - pageTopLeft.y) - transformOrigin.y));
  box.style.transform = "translate3d(" + (dx * multX) + "px, " + (dy * multY) + "px, 0)";
  
  /*
  // or you can add some fancy rotation as well lol
  let rotationDeg = Math.atan2(dy,dx) * (180/Math.PI);
  let rotationString = "rotate(" + rotationDeg + "deg)"; 
  box.style.transform = "translate3d(" + (dx * multX) + "px, " + (dy * multY) + "px, 0) " + rotationString;
  */
}

function onLeave(e) {
  box.style.transform = "translate3d(0, 0, 0)";
}

function onResize(e) {
  // redefine all the "let" variables
}
* {
  margin: 0;
  padding: 0;
}

.page {
  position: relative;
  width: 100%;
  height: 100vh;
  background-color: #ddd;
  display: grid;
  place-items: center;
}

.hover-area {
  position: relative;
  width: 50%;
  height: 100%;
  background-color: #888;
}

.box {
  position: absolute;
  left: calc(50% - 25px);
  top: calc(50% - 25px);
  width: 50px;
  height: 50px;
  border-radius: 25px;
  background-image: linear-gradient(45deg, #000, #aaa);
  transform: translate3d(0, 0, 0);
  transition: all 0.2s;
  will-change: transform;
}
<div id="page-id" class="page">
  <div id="area-id" class="hover-area">
    <div id="box-id" class="box" />
  </div>
</div>

Note that is runs smoother on Chrome than on Safari. I'm not sure divs and css is the best way to go here for performance. If I misunderstood the final result, explain more and I'll try to help.

Danielozzo
  • 76
  • 1
  • 4
  • how about we remove the initial animation? when I hover over the element it goes far down. I just want to make it move a little bit when hovering – leonardeveloper Oct 27 '19 at 02:05
  • I've wrapped everything in a div and added the relative coordinates in the onMove function. Now it seems to work ok in codepen and snippet, yet the performance on Safari is lousy as far as I can tell – Danielozzo Oct 27 '19 at 02:32