Search code examples
javascripthtmlcssdrag-and-dropkonva

JS: draggable object speed


I want to slow down speed of the draggable HTML object to make it kind of lazy dragging.

enter image description here

Is there any way to implement this feature with native HTML/CSS?

Or may be there are some existing JS libraries which have such ability?

Can't find any library with such simple feature..


Solution

  • I've made one possible solution but also not forgot to share ;)

    The point is to apply mouse position to the circle on mousemove event to emulate dragging effect.

    Also I've added transition CSS property to the circle for smooth movement.

    The main thing here is to update circle position not continuously right in the mousemove event listener. But in case with transition property you should update circle position at some intervals to give CSS transition time to animate circle displacement smoothly. Otherwise CSS transition animation will be overloaded by continuous update from mousemeove event and become glitchy.

    var cirlce = document.querySelector('.circle');
    
    function getTranslateX(myElement) {
       var style = window.getComputedStyle(myElement);
       var matrix = new WebKitCSSMatrix(style.webkitTransform);
       return matrix.m41; // 'm41' is translateX position
    }
    
    function getTranslateY(myElement) {
       var style = window.getComputedStyle(myElement);
       var matrix = new WebKitCSSMatrix(style.webkitTransform);
       return matrix.m42; // 'm42' is translateY position
    }
    
    var mouseDown = false;
    var mousePos = {
       x: 0,
       y: 0,
    }
    var mouseLastPos = {
       x: 0,
       y: 0,
    }
    var circlePos = {
       x: getTranslateX(cirlce),
       y: getTranslateY(cirlce),
    }
    
    window.addEventListener('mouseup', e => {
       mouseDown = false;
       circlePos = {
          x: getTranslateX(cirlce),
          y: getTranslateY(cirlce),
       }
    });
    window.addEventListener('mousedown', e => {
       mouseDown = true;
       mouseLastPos.x = e.clientX;
       mouseLastPos.y = e.clientY;
    });
    window.addEventListener('mousemove', e => {
       mousePos.x = e.clientX;
       mousePos.y = e.clientY;
       if (mouseDown) {
          // cirlce.style.transform = 'translateX('+(mousePos.x-mouseLastPos.x+circlePos.x)+'px) translateY('+(mousePos.y-mouseLastPos.y+circlePos.y)+'px)'; // doesn't work with 'transition' CSS property
       }
    });
    
    // main trick here to make 'transition' work properly
    setInterval(() => {
       if (mouseDown) {
          cirlce.style.transform = 'translateX('+(mousePos.x-mouseLastPos.x+circlePos.x)+'px) translateY('+(mousePos.y-mouseLastPos.y+circlePos.y)+'px)';
       }
    }, 50);
    .circle {
       position: absolute;
       width: 100px;
       height: 100px;
       top: 0;
       left: 0;
       background-color: red;
       border: 2px solid black;
       border-radius: 50%;
       transform: translateX(5px) translateY(5px);
       transition: transform 0.3s;
    }
    <div class="circle"></div>