Search code examples
javascripthtmlmousemoveelement

How to make smooth elements dragging by mouse if their position set in percents?


I doing elements dragging possibility in my page. User should drag any element with % or px set position. The dragging of px positioned elements works good, but the dragging of % positioned elements is too fast and element runs away from mouse.

Which way I can fix this? I think I probably need to do some calculations, so the element will not move until mouse has run some distance, but I don't understand what exactly calculations I should make. This probably should be dependent from how much pixels in 1%.

<html style="height: 100%;">
<head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    <title>test export</title>
    <script type='text/javascript'>
        var curr_moving_elem;
        var last_x, last_y;

        function getIndexOfFirstNonDigitSymbolInString(str) {
            if (!str)
                return -1;

            var index = -1;

            for (var i = 0; i < str.length; i++)
                if (str[i] != '-' && (str[i] < '0' || str[i] > '9')) {
                    index = i;
                    break;
                }

            return index;
        }

        function getIntegerFromAnyHTMLValue(str_val) {
            int_val = 0;
            var first_non_digit = getIndexOfFirstNonDigitSymbolInString(str_val);

            if (first_non_digit < 0)
                return NaN;

            var digits_only = str_val.substring(0, first_non_digit);

            return Number(digits_only);
        }

        function getStrSuffixFromAnyHTMLValue(str_val, suffix) {
            suffix = "";
            var first_non_digit = getIndexOfFirstNonDigitSymbolInString(str_val);

            if (first_non_digit < 0)
                return "";

            return str_val.substring(first_non_digit);
        }

        function handleMouseDown(e) {
            if (e.button == 0) {
                var main_elem_under_mouse = getMainElemUnderMouseClickOrDownOrMoveOrUp(e);

                if (main_elem_under_mouse && (main_elem_under_mouse.style.position.toLowerCase() == "absolute" || main_elem_under_mouse.style.position.toLowerCase() == "relative" || main_elem_under_mouse.style.position.toLowerCase() == "fixed")) {
                    curr_moving_elem = main_elem_under_mouse;
                    last_x = e.x;
                    last_y = e.y;
                }
            }
        }

        function handleMouseMove(e) {
            if (curr_moving_elem && e.button == 0) {
                var curr_top = curr_moving_elem.style.top;
                var curr_left = curr_moving_elem.style.left;

                var int_top = getIntegerFromAnyHTMLValue(curr_top);
                var top_suffix = getStrSuffixFromAnyHTMLValue(curr_top);

                var int_left = getIntegerFromAnyHTMLValue(curr_left);
                var left_suffix = getStrSuffixFromAnyHTMLValue(curr_left);

                var new_top = (int_top + (e.y - last_y)) + top_suffix;
                curr_moving_elem.style.top = new_top;

                var new_left = (int_left + (e.x - last_x)) + left_suffix;
                curr_moving_elem.style.left = new_left;

                last_x = e.x;
                last_y = e.y;
            }
        }

        function handleMouseUp(e) {
            //if (e.button == 0)
            //{
            curr_moving_elem = null;
            last_x = null;
            last_y = null;
            //}
        }

        function getMainElemUnderMouseClickOrDownOrMoveOrUp(e) {
            var elem;
            var evt = e || window.event;

            if (!evt)
                return null;

            if (evt.target)
                elem = evt.target;
            else if (evt.srcElement)
                elem = evt.srcElement;

            if (elem && elem.nodeType == 3) // defeat Safari bug
                elem = elem.parentNode;

            if (elem)
                if (elem.getAttribute('data-mainElem'))
                    return elem;
                else {
                    var parent = elem.parentElement;

                    while (parent && !parent.getAttribute('data-mainElem'))
                        parent = parent.parentElement;

                    if (parent && parent.getAttribute('data-mainElem'))
                        return parent;
                }
        }
    </script>
</head>
<body style="height: 100%; margin: 0px;" onmousedown="handleMouseDown(event);" onmousemove="handleMouseMove(event);"
    onmouseup="handleMouseUp(event);">
    <div data-mainelem='true' id='Div_107' style="position: ABSOLUTE; height: 20%; width: 35%;
        top: 10px; left: 5px; background-color: #800000; background-position: left top;
        background-repeat: repeat;">
    </div>
    <div data-mainelem='true' id='Div_108' style="position: ABSOLUTE; height: 40%; width: 25%;
        top: 10%; left: 5%; background-color: #00FF00; background-position: left top;
        background-repeat: repeat;">
    </div>
</body>
</html>

Solution

  • I think your problem is here: e.x - last_x. This will return distance of mouse in pixel, but you need it in percentage. What you would need to to is set this to percentage of screen. Something like:

    var percent_x = ((e.x - last.x)/window.innerWidth)*100
    

    But then you'll have to differentiate between percentage or pixel.