Calculate horizontal distance of an element

Asked

Viewed 381 times

2

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

The idea was to do something stylish "slide to Unlock"; however, it is only working in a resolution above 992px... I believe this is due to break-point of Bootstrap and the fact that I am not knowing how to pick the correct reference to calculate the margin-left to be applied to the button.

I’m getting the reference x of the event mousemove but 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 bad way I could not reach her. Because of the saying break-point added to the code snippet below all the containers I use because the removal (of one or the other) breaks the calculation.

NOTE: when executing the code below the resolution is less than 992px and so the slide will not work... run in "whole page" which will be above 992px and it 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

1 answer

1


I thank you in advance for the reply and comments I received on this question, helped me to guide the reasoning 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 reset these values each time the event was triggered.

  • 2: was using the property "x" event (Event.x) to calculate the portion moved in comparison of the element and its container when the correct one should be, use "pageX" because the break-point of Bootstrap hides some classes with display:none; and therefore the property "x" cannot compute the exact length. I came to this understanding by finding this reference in the 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>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.