Calculate horizontal distance of an element

2

I'm trying to customize a submit button using Bootstrap 4 Beta 3 .

The idea was to do something like "slide to unlock" style ; however, it is only working in a resolution above 992px ... I believe this is due to break-point of Bootstrap and because I do not know how to get the correct reference to calculate the margin-left to be applied to the button.

I'm getting the reference x from the% event of mousemove plus as "I believe" that this measure is of the element because of the screen break-point of Bootstrap breaks my logic. >

I believe there is a better way but I could not get into it. Because of the said break-point I have added all the containers that I use because the removal (of one or the other) breaks the calculation to the code snippet below.

NOTE : When running the code below the resolution is less than 992px and therefore the slide will not work ... run on "whole page" will be above 992px and will work; then resize the window to test.

Or the same code in a github page .

var m = document.querySelector('button[type="submit"][data-slide-button="slide"]');
m.addEventListener('click', clickHandler, false)
m.addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);




function mouseUp() {
    window.removeEventListener('mousemove', move, true);
}

function mouseDown(e) {
    window.addEventListener('mousemove', move, true);
}



function clickHandler(e) {
    e.preventDefault();


    let buttonWidth = e.target.offsetWidth // 41
    let buttonMarginLeft = e.target.offsetLeft

    let containerWidth = e.target.parentNode.clientWidth

    if ( buttonMarginLeft < (containerWidth - buttonWidth) ) {
        m.style.left = 0
        m.style.borderLeft = 0
        m.style.borderRight = '1px solid #ced4da'
    }

    console.log('end of click')



}



function move(e) {

    let buttonWidth = e.target.offsetWidth // 41
    let buttonMarginLeft = e.target.offsetLeft

    let containerWidth = e.target.parentNode.clientWidth



    if ( buttonMarginLeft > (containerWidth - buttonWidth) ) {
        // fix left
        m.style.left = (containerWidth - buttonWidth) +1 + 'px'
        m.style.borderLeft = '1px solid #ced4da'
        m.style.borderRight = 0
        // remove handler
        window.removeEventListener('mousemove', move, true)
        window.removeEventListener('click', clickHandler, true)
        e.target.parentNode.setAttribute('data-content', 'sending form')
        console.log('ok truta')
    } else {
        if ( buttonMarginLeft < 0 ) {
            m.style.left = 0
            m.style.borderLeft = 0
            m.style.borderRight = '1px solid #ced4da'
            window.removeEventListener('mousemove', move, true)

            console.log('negative')
        } else {
            let calculate = e.x - (containerWidth + buttonWidth )

            if ( calculate < 0 ) {
                console.log('adjust is negative')
                m.style.left = 0
            } else {
                console.log('adjust')
                m.style.left =  calculate + 'px'
            }

        }

    }

};
.submit-slide-button {
  width: 100%;
  transition: opacity 0.5s;
  border: 1px solid #ced4da;
  margin: 0 auto;
  background-color: #28a745;
  color: white;
}
.submit-slide-button:before {
  content: attr(data-content) !important;
  color: white;/*#8a8a8a;*/
  position: absolute;
  left: 35%;
  top: .5rem;
  z-index: 1;
  font-size: 1rem;
}
.submit-slide-button button {
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  background-color: #e9ecef;
  position: relative;
  cursor: pointer;
  z-index: 1;
  border-right: 1px solid #ced4da;
  color: #495057;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet"/>


<section class="container-fluid px-0 pt-5">

    <div class="col mx-auto mt-4 ct">

        <div class="col mx-0 text-left">

            <div class="col col-sm-8 col-md-5 col-lg-4 mx-auto px-0 mb-5">        

                <form id="signin-form" action="#" method="post" accept-charset="utf-8" validate="true">        

                    <div class="form-group mb-2">
                        <label class="mb-1">Email</label>
                        <div class="input-group">
                            <div class="input-group-prepend">
                                <span class="input-group-text rounded-0 fa fa-at"></span>
                            </div>
                            <input id="user-email" type="email" autocomplete="user-email" placeholder="Email" class="form-control rounded-0" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" required focus>
                        </div>
                    </div>
                    <div class="form-group mb-2">
                        <label class="mb-1">Password</label>
                        <div class="input-group">
                            <div class="input-group-prepend">
                                <span class="input-group-text rounded-0 fa fa-lock"></span>
                            </div>
                            <input id="user-password" type="password" autocomplete="current-password" placeholder="Password" class="form-control rounded-0" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,50}" required>
                        </div>
                    </div>
                    <div class="checkbox pt-1">
                        <label>
                            <input id="remember" type="checkbox" name="remember"> Remember-me
                        </label>
                    </div>
                    <div class="form-group mb-2">
                        <div class="input-group">
                            <div class="submit-slide-button" data-content="slide to submit">
                                <button data-slide-button="slide" type="submit" class="fa fa-arrow-circle-right"></button>
                            </div>
                        </div>
                    </div>
                    <a href="./recover" class="float-left mt-4">Recover?</a>        

                </form>        

            </div>

        </div>
        
    </div> 

</section>


<script
  src="https://code.jquery.com/jquery-3.2.1.min.js"integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
  crossorigin="anonymous"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.bundle.min.js"></script>
  

PS: I'm not looking for solutions with jQuery UI (draggable), I'm looking for something in Vanilla or jQuery only

    
asked by anonymous 02.01.2018 / 09:12

1 answer

1

In advance, I appreciate the response and comments I received on this issue, helped me to guide the thinking process and find the solution.

The problem consisted of two distinct errors:

  • 1 : I was defining variables that should receive fixed values (coming from the first event: mousedown ) within the event mousemove this in turn redefined these values every time the event was triggered.

  • 2 : You were using the "x" property of the event (event.x) to compute the moved portion against the element and its container when the should be, use "pageX" because break-point of Bootstrap hides some classes with display:none; and therefore the property "x" can not compute the exact length. I came to this understanding by finding this reference in SOen .

The following code now works correctly and supports touch :

var m = document.querySelector('button[type="submit"][data-slide-button="slide"]'),
    initX,
    firstX,
    buttonWidth,
    containerWidth,
    finish = false // definir o encerramento    

m.addEventListener('click', clickHandler, {capture: false, passive: false})
m.addEventListener('mousedown', mouseDown, {capture: false, passive: true});
window.addEventListener('mouseup', mouseUp, {capture: false, passive: true});    

function mouseUp() {
    if ( !finish ) {
        m.classList.remove('border-0')
    }
    m.style.left = 0
    window.removeEventListener('mousemove', move, {capture: false, passive: true});
}    

function mouseDown(e) {
    initX = this.offsetLeft;
    firstX = e.pageX;
    buttonWidth = e.target.offsetWidth
    containerWidth = e.target.parentNode.clientWidth

    window.addEventListener('mousemove', move, {capture: false, passive: true});
}    

function clickHandler(e) {
    e.preventDefault()
    let calculate = initX + e.pageX - firstX
    // se o botão não chegou ao fim... ajuste
    if ( calculate < (containerWidth - buttonWidth) ) {
        if ( !finish ) {
            m.classList.remove('border-0')
        }
        m.style.left = 0
    }
}    

function move(e) {
    // verificar se já não foi encerrado
    if ( !finish ) {
        m.classList.add('border-0')
        let calculate = initX + e.pageX - firstX
        // se o botão chegou ao fim do contêiner (maior ou igual ao limite)
        if ( calculate >= (containerWidth - buttonWidth) ) {
            finish = true
            // fix left
            m.style.left = 0
            m.classList.add('border-0')
            m.classList.add('w-100')
            m.innerHTML = ' sending form'
            // remover handler
            m.removeEventListener('mousemove', move, true)

            console.log('enviando formulário')
        } else {
            // verificar se o margin é negativo... se for fixar
            if ( calculate < 0 ) {
                m.style.left = 0
                m.classList.remove('border-0')
            } else {
                // verificar se a área percorrida é menor que o limite
                if ( calculate < (containerWidth - buttonWidth) ) {
                    m.style.left =  calculate + 'px'
                }
            }
        }
    }
}    

// "touch" suporte
m.addEventListener('touchstart', function(e) {    

    e.preventDefault();
    initX = this.offsetLeft;
    var touch = e.touches;
    firstX = touch[0].pageX;
    buttonWidth = e.target.offsetWidth
    containerWidth = e.target.parentNode.clientWidth   

    this.addEventListener('touchmove', swipeIt, {capture: false, passive: false})

    window.addEventListener('touchend', function(e) {
        e.preventDefault()
        if ( !finish ) {
            m.classList.remove('border-0')
            m.style.left = 0
        }
        m.removeEventListener('touchmove', swipeIt, {capture: false, passive: false})
    }, {capture: false, passive: false})    

}, {passive: false})



function swipeIt(e) {
    if ( !finish ) {
        let contact = e.touches
        m.classList.add('border-0')
        let calculate = initX + contact[0].pageX - firstX    

        if ( calculate >= (containerWidth - buttonWidth) ) {
            finish = true
            // fix left
            m.style.left = 0
            m.classList.add('border-0')
            m.classList.add('w-100')
            m.innerHTML = ' sending form'
            // remover handler
            m.removeEventListener('mousemove', move, true)

            console.log('enviando formulário')
        } else {
            if ( calculate < 0 ) {
                console.log('negative margin')
                m.style.left = 0
                m.classList.remove('border-0')
            } else {
                if ( calculate < (containerWidth - buttonWidth) ) {
                    m.style.left =  calculate + 'px'
                }
            }
        }
    }
}
.submit-slide-button {
  width: 100%;
  border: 1px solid #ced4da;
  margin: 0 auto;
  background-color: #28a745;
  color: white;
}
.submit-slide-button:before {
  content: attr(data-content) !important;
  color: white;/*#8a8a8a;*/
  position: absolute;
  left: 35%;
  top: .3rem;
  z-index: 1;
  font-size: 1rem;
}
.submit-slide-button button {
  -webkit-appearance: button-bevel;
  -moz-appearance: button-bevel;
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  background-color: #e9ecef;
  position: relative;
  cursor: pointer;
  z-index: 1;
  border: none;
  border-right: 1px solid #ced4da;
  color: #495057;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet"/>


<section class="container-fluid px-0 pt-5">

    <div class="col mx-auto mt-4 ct">

        <div class="col mx-0 text-left">

            <div class="col col-sm-8 col-md-5 col-lg-4 mx-auto px-0 mb-5">        

                <form id="signin-form" action="#" method="post" accept-charset="utf-8" validate="true">        

                    <div class="form-group mb-2">
                        <label class="mb-1">Email</label>
                        <div class="input-group">
                            <div class="input-group-prepend">
                                <span class="input-group-text rounded-0 fa fa-at"></span>
                            </div>
                            <input id="user-email" type="email" autocomplete="user-email" placeholder="Email" class="form-control rounded-0" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" required focus>
                        </div>
                    </div>
                    <div class="form-group mb-2">
                        <label class="mb-1">Password</label>
                        <div class="input-group">
                            <div class="input-group-prepend">
                                <span class="input-group-text rounded-0 fa fa-lock"></span>
                            </div>
                            <input id="user-password" type="password" autocomplete="current-password" placeholder="Password" class="form-control rounded-0" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,50}" required>
                        </div>
                    </div>
                    <div class="checkbox pt-1">
                        <label>
                            <input id="remember" type="checkbox" name="remember"> Remember-me
                        </label>
                    </div>
                    <div class="form-group mb-2">
                        <div class="input-group submit-slide-button" data-content="slide to submit">
                            <button data-slide-button="slide" type="submit" class="fa fa-arrow-circle-right"></button>
                        </div>
                    </div>
                    <a href="./recover" class="float-left mt-4">Recover?</a>        

                </form>        

            </div>

        </div>
        
    </div> 

</section>


<script
  src="https://code.jquery.com/jquery-3.2.1.min.js"integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
  crossorigin="anonymous"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.bundle.min.js"></script>
    
06.01.2018 / 15:31