在拖动 - 触摸事件期间保持图像居中

问题描述 投票:0回答:1

是之前未答复的post的延续,其中我想将图像居中于拖动它的触摸位置。例如,如果用户触摸图像的右上角,图像将自动移动,因此其中心位于该触摸上。

在第一个代码片段中,这是我试图实现的行为:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta name="viewport" content=width=device-width,user-scalable=no>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            let shiftX;
            let shiftY;
            let img = document.createElement('img');
            img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Location_dot_blue.svg/1200px-Location_dot_blue.svg.png";
            img.style.position = "absolute";
            img.style.height = "20%";
            img.addEventListener('touchstart', function(e) {
              start = e.target.parentNode.id;
              img.style.zIndex = 1;
            });
            img.addEventListener("touchmove", function(e) {
              e.preventDefault();
              img.style.left=e.touches[0].clientX-img.width/2+"px";
              img.style.top=e.touches[0].clientY-img.height/2+"px";

            });
            document.body.appendChild(img);
        </script> 
    </body>
</html>

但是我在实际代码中实现这一目标的最佳尝试是这样的:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta name="viewport" content=width=device-width,user-scalable=no>
        <meta charset="UTF-8">
        <style>
          html, body {
            height: 100%;
            margin: 0;
            padding: 0;  
          }
          @media screen and (orientation: landscape) {
          .chessboard {
            height: 90%;
            aspect-ratio : 1 / 1;     
            margin: 0 auto;
            display: flex;
            flex-wrap: wrap;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
          }
          }
          @media screen and (orientation: portrait) {
            .chessboard {
              width: 90%;
              aspect-ratio : 1 / 1;
              margin: 0 auto;
              display: flex;
              flex-wrap: wrap;
              position: absolute;
              top: 50%;
              left: 50%;
              transform: translate(-50%, -50%);
            }
            }
          .row{
            height: 12.5%;
            width: 100%;
            display: flex;
          }
          .square {
            height: 100%;
            width: 12.5%;
            position: relative;
            box-sizing: border-box;
          }
          .white {
            background-color: #f1d8b0;
          }
          img{
            position: absolute;
            width: 90%;
            height: 90%;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
          }          
        </style>
    </head>
    <body>
        <script>
            let initialX;
            let initialY;
            let d = document.createElement('div');
            d.setAttribute('class','chessboard')
            for (let i = 0; i <8; i++){
              let e = document.createElement('div');
              e.setAttribute('class','row');
              let f = document.createElement('div');
              f.setAttribute('class','square white');
              let img = document.createElement('img');
              img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Location_dot_blue.svg/1200px-Location_dot_blue.svg.png";
              img.addEventListener('touchstart', function(e) {
                start = e.target.parentNode.id;
                img.style.zIndex = 1;
                initialX = e.touches[0].clientX;
                initialY = e.touches[0].clientY;
              });
              img.addEventListener("touchmove", function(e) {
                e.preventDefault();
                img.style.left=(e.touches[0].clientX-initialX)+img.width/2+"px";
                img.style.top=(e.touches[0].clientY-initialY)+img.height/2+"px";
              });
              document.body.appendChild(d);
              d.appendChild(e);
              e.appendChild(f);
              f.appendChild(img);
            }
        </script> 
    </body>
</html>

注:

忽略第二次触摸圆圈时的行为,这是在主代码中修复的

这里我们必须使用InitialX和InitialY,就像前面的例子一样,它是0,0(对于style.left,style.top,我们需要改变x和y坐标)

虽然这个解决方案很好,但因为它消除了偏移,所以它没有获得我想要的中心功能(也许我在这里有点完美主义)。

我很不确定下一步该做什么,我尝试添加不同的偏移量但无济于事。

我发现这个网站非常有用。

请评论我可以对此问题做出的任何改进。

javascript html css touch touch-event
1个回答
0
投票

一种可能的解决方案是使用

touchstart
touchmove
touchend
事件来模拟拖放功能。您可以使用
getBoundingClientRect
方法获取元素的位置和大小,并将它们与触摸坐标进行比较以检测重叠。

还可以尝试使用

translate
属性相对于原始位置移动图像,并将其调整到触摸点。

let initialX, initialY, offsetX, offsetY;
let img = document.querySelector('img');
let divs = document.querySelectorAll('div');

img.addEventListener('touchstart', function(e) {
  e.preventDefault();
  let rect = img.getBoundingClientRect();
  initialX = e.touches[0].clientX - rect.left;
  initialY = e.touches[0].clientY - rect.top;
  offsetX = rect.left;
  offsetY = rect.top;
  img.style.zIndex = 1;
});

img.addEventListener('touchmove', function(e) {
  e.preventDefault();
  let x = e.touches[0].clientX - initialX;
  let y = e.touches[0].clientY - initialY;
  img.style.transform = `translate(${x}px, ${y}px)`;
});

img.addEventListener('touchend', function(e) {
  e.preventDefault();
  let rect = img.getBoundingClientRect();
  let target = null;
  for (let div of divs) {
    let divRect = div.getBoundingClientRect();
    if (rect.left < divRect.right && rect.right > divRect.left && rect.top < divRect.bottom && rect.bottom > divRect.top) {
      target = div;
      break;
    }
  }
  if (target) {
    let temp = target.innerHTML;
    target.innerHTML = img.outerHTML;
    img.outerHTML = temp;
    img = document.querySelector('img');
    img.addEventListener('touchstart', touchstart);
    img.addEventListener('touchmove', touchmove);
    img.addEventListener('touchend', touchend);
  }
  img.style.transform = 'none';
  img.style.zIndex = 0;
});

© www.soinside.com 2019 - 2024. All rights reserved.