How to get precise position of HTML element after scrolling

74 Views Asked by At

I'm writing a tampermonkey script to add speed buttons next to Facebook videos. The script get all the video elements in the page, get their position, and bases on that position to place the button next to them. The script runs fine at the beginning. But as I scroll and the page loads more videos, the button position doesn't match their video anymore. As a result, videos won't have speed buttons next to them. I suspect that by loading more videos, the code messed up somewhere and calculate the video position from the top of the page wrong, so that the button is placed wrong consequently. Can someone suggest a way to fix this? My code is as below:

function addButton(){

function getOffset( el ) {//get the position of the element respective to the top and the left of the page

    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

    function setButton(video){//add buttons next to the videos
      var elDistanceToTop = window.pageYOffset + video.getBoundingClientRect().top
      var y=elDistanceToTop;//get the distance from the element to the TOP of the page
        //var y = getOffset( video ).top;
        var x=getOffset( video ).left;//get the distance from the element to the LEFT of the page
      var button1 = document.createElement('button');
      button1.textContent = '1x';
      // Set button position
      button1.style.position = 'absolute';
      button1.style.left = x+video.getBoundingClientRect().width+ 'px';//place button to the left of video
      button1.style.top = y+ 'px';//position from the top of the page to place the button
        button1.style.width='58px';
        button1.style.height=video.getBoundingClientRect().height/3+'px';
        button1.addEventListener('click', function () {
      // Increase speed by 1, maximum speed is 4.0
                video.playbackRate = 1;
    });
      // Add button to the document body
      document.body.appendChild(button1);

        var button2 = document.createElement('button');
      button2.textContent = '1.5x';
      // Set button position
      button2.style.position = 'absolute';
      button2.style.left = x+video.getBoundingClientRect().width+ 'px';
      button2.style.top = y+video.getBoundingClientRect().height/3+ 'px';
        button2.style.width='58px';
        button2.style.height=video.getBoundingClientRect().height/3+'px';
        button2.addEventListener('click', function () {
      // Increase speed by 1.5, maximum speed is 4.0
                video.playbackRate = 1.5;
    });
      // Add button to the document body
      document.body.appendChild(button2);

         var button3 = document.createElement('button');
      button3.textContent = '2x';
      // Set button position
      button3.style.position = 'absolute';
      button3.style.left = x+video.getBoundingClientRect().width+ 'px';
      button3.style.top = y+video.getBoundingClientRect().height*2/3+ 'px';
        button3.style.width='58px';
        button3.style.height=video.getBoundingClientRect().height/3+'px';
        button3.addEventListener('click', function () {
      // Increase speed by 2, maximum speed is 4.0
                video.playbackRate = 2;
    });
      // Add button to the document body
      document.body.appendChild(button3);
    }
   const videoElement = document.querySelectorAll('video');

       videoElement.forEach((video, index) => {
    //check to see if the video had had buttons
    const loadedBefore = video.getAttribute('data-loaded') === 'true';

    if (loadedBefore) {//if it has, do nothing

    } else {//if it doesn't have buttons, add them
       setButton(video);
    }
});

       videoElement.forEach((video, index) => {//mark all exsisting video on the page as button-having,
           //so as not to add button to them again
    video.setAttribute('data-loaded', 'true');
    
});

   }

setInterval(addButton, 3000);//the loop to check and add button again and again

I attached 2 image of how the button looks like at the beginning and how they look after a few scrolls on the page before After

1

There are 1 best solutions below

2
cssyphus On

In this case, I suspect the problem to be where you are adding your buttons.

Instead of adding them a certain distance from the top of the page, try to identify a parent container that bounds that group of elements and add it in there. Then, as the that parent containers change places on the screen, your buttons will change with them.

Otherwise, you will need to update the screen locations for all buttons in a loop. More work and a little more difficult. However, if you choose such a route then OOKWUDILI's reference to the mutation observer would be helpful.