JS中如何拖动图片

How to drag images in JS

我有一张大背景图片和一些小得多的图片供用户在背景上拖动。我需要它在性能方面是高效的,所以我试图避免使用库。如果效果好,我可以接受拖动 'n' 下降,但我正在尝试拖动。

我非常想做 this. 但 8 年后一定有更清洁的方法来做这件事对吗?

我目前有一个拖放 'n' 拖放系统,几乎可以正常工作,但是当我拖放较小的图像时,它们会稍微偏离一点,这很烦人。有没有办法修复我的代码,或者我需要采取完全不同的方法?

到目前为止,这是我的代码:

var draggedPoint;

function dragStart(event) {
  draggedPoint = event.target; // my global var
}


function drop(event) {
  event.preventDefault();

  let xDiff = draggedPoint.x - event.pageX;
  let yDiff = draggedPoint.y - event.pageY;

  let left = draggedPoint.style.marginLeft; // get margins
  let top = draggedPoint.style.marginTop;

  let leftNum = Number(left.substring(0, left.length - 2)); // cut off px from the end
  let topNum = Number(top.substring(0, top.length - 2));

  let newLeft = leftNum - xDiff + "px" // count new margins and put px back to the end
  let newTop = topNum - yDiff + "px"

  draggedPoint.style.marginLeft = newLeft;
  draggedPoint.style.marginTop = newTop;
}

function allowDrop(event) {
  event.preventDefault();
}


let imgs = [
"https://upload.wikimedia.org/wikipedia/commons/6/67/Orange_juice_1_edit1.jpg",
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Solid_blue.svg",
"https://upload.wikimedia.org/wikipedia/commons/b/b4/Litoria_infrafrenata_-_Julatten.jpg"
]

/* my smaller images: */
for (let i = 0; i < 6; i++) {
    let sensor = document.createElement("img");
    sensor.src = imgs[i % imgs.length];
    sensor.alt = i;
    sensor.draggable = true;
    sensor.classList.add("sensor");

    sensor.style.marginLeft = `${Math.floor(Math.random() * 900)}px`
    sensor.style.marginTop = `${Math.floor(Math.random() * 500)}px`

    sensor.onclick = function() {
       sensorClick(logs[i].id)
    };
    sensor.addEventListener("dragstart", dragStart, null);

    let parent = document.getElementsByClassName("map")[0];
    parent.appendChild(sensor);
}
<!-- my html: -->
<style>
     .map {
         width: 900px;
         height: 500px;
         align-content: center;
         margin: 150px auto 150px auto;
    }

     .map .base {
          position: absolute;
          width: inherit;
          height: inherit;
      }

    .map .sensor {
         position: absolute;
         width: 50px;
         height: 50px;
    }
</style>

<div class="map" onDrop="drop(event)" ondragover="allowDrop(event)">
  <img src='https://upload.wikimedia.org/wikipedia/commons/f/f7/Plan-Oum-el-Awamid.jpg' alt="pohja" class="base" draggable="false">
<div>

有了 here 的回答,并且有一段时间我能够使用纯 js 进行平滑的拖动和点击。

这里有一个 JSFiddle 可以看到它的实际效果。

let maxLeft;
let maxTop;
const minLeft = 0;
const minTop = 0;
let timeDelta;
let imgs = [
    "https://upload.wikimedia.org/wikipedia/commons/6/67/Orange_juice_1_edit1.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/f/ff/Solid_blue.svg",
    "https://upload.wikimedia.org/wikipedia/commons/b/b4/Litoria_infrafrenata_-_Julatten.jpg"
]
var originalX;
var originalY;

window.onload = function() {
    document.onmousedown = startDrag;
    document.onmouseup = stopDrag;
}
    
function sensorClick () {
    if (Date.now() - timeDelta < 150) { // check that we didn't drag
        createPopup(this);
    }
}

// create a popup when we click
function createPopup(parent) {
    let p = document.getElementById("popup");
    if (p) {
        p.parentNode.removeChild(p);
    }

    let popup = document.createElement("div");
    popup.id = "popup";
    popup.className = "popup";
    popup.style.top = parent.y - 110 + "px";
    popup.style.left = parent.x - 75 + "px";

    let text = document.createElement("span");
    text.textContent = parent.id;
    popup.appendChild(text);
    
    var map = document.getElementsByClassName("map")[0];
    map.appendChild(popup);
}

// when our base is loaded
function baseOnLoad() {
    var map = document.getElementsByClassName("map")[0];
    let base = document.getElementsByClassName("base")[0];
    maxLeft = base.width - 50;
    maxTop = base.height - 50;

    /* my smaller images: */
    for (let i = 0; i < 6; i++) {
        let sensor = document.createElement("img");
        sensor.src = imgs[i % imgs.length];
        sensor.alt = i;
        sensor.id = i;
        sensor.draggable = true;
        sensor.classList.add("sensor");
        sensor.classList.add("dragme");
        sensor.style.left = `${Math.floor(Math.random() * 900)}px`
        sensor.style.top = `${Math.floor(Math.random() * 500)}px`
        sensor.onclick = sensorClick;

        let parent = document.getElementsByClassName("map")[0];
        parent.appendChild(sensor);
    }
}

function startDrag(e) { 
    timeDelta = Date.now(); // get current millis

    // determine event object
    if (!e) var e = window.event;

    // prevent default event
    if(e.preventDefault) e.preventDefault();

    // IE uses srcElement, others use target
    targ = e.target ? e.target : e.srcElement;

    originalX = targ.style.left;
    originalY = targ.style.top;

    // check that this is a draggable element
    if (!targ.classList.contains('dragme')) return;
    
    // calculate event X, Y coordinates
    offsetX = e.clientX;
    offsetY = e.clientY;

    // calculate integer values for top and left properties
    coordX = parseInt(targ.style.left);
    coordY = parseInt(targ.style.top);
    drag = true;

    document.onmousemove = dragDiv; // move div element
    return false; // prevent default event
}

function dragDiv(e) {
    if (!drag) return;
    if (!e) var e = window.event;

    // move div element and check for borders
    let newLeft = coordX + e.clientX - offsetX;
    if (newLeft < maxLeft && newLeft > minLeft) targ.style.left = newLeft + 'px'
    
    let newTop = coordY + e.clientY - offsetY;
    if (newTop < maxTop && newTop > minTop) targ.style.top = newTop + 'px'

    return false; // prevent default event
}

function stopDrag() {
    if (typeof drag == "undefined") return;

    if (drag) {
        if (Date.now() - timeDelta > 150) { // we dragged
            let p = document.getElementById("popup");
            if (p) {
                p.parentNode.removeChild(p);
            }
        } else {
            targ.style.left = originalX;
            targ.style.top = originalY;
        }
    }

    drag = false;
}
.map {
    width: 900px;
    height: 500px;
    margin: 50px
    position: relative;
}

.map .base {
    position: absolute;
    width: inherit;
    height: inherit;
}

.map .sensor {
    display: inline-block;
    position: absolute;
    width: 50px;
    height: 50px;
}

.dragme {
    cursor: move;
    left: 0px;
    top: 0px;
}

.popup {
    position: absolute;
    display: inline-block;
    width: 200px;
    height: 100px;
    background-color: #9FC990;
    border-radius: 10%;
}


.popup::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    margin-left: -10px;
    border-width: 10px;
    border-style: solid;
    border-color: #9FC990 transparent transparent transparent;
}

.popup span {
    width: 90%;
    margin: 10px;
    display: inline-block;
    text-align: center;
}
<div class="map" width="950px" height="500px">
    <img src='https://upload.wikimedia.org/wikipedia/commons/f/f7/Plan-Oum-el-Awamid.jpg' alt="pohja" class="base" draggable="false" onload="baseOnLoad()">
<div>