r3plica r3plica - 4 months ago 9
Javascript Question

HTML5 Draggable control without using jQuery

I have an issue which I am hoping someone can help me with.
I have created the HTML and CSS for a sort of slider:

<div class="pk-slider">
<div class="pk-slider-base">
<div>
<div class="pk-slider-point">
<p class="pk-label">Family holidays</p>
<a href="#">
<div class="point"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label">Sporting activities</p>
<a href="#">
<div class="point"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label">Travel</p>
<a href="#">
<div class="point"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label active">Photography is my passion</p>
<a href="#">
<div class="point active"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label">Nights out</p>
<a href="#">
<div class="point"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label">Special occasions</p>
<a href="#">
<div class="point"></div>
</a>
</div>

<div class="pk-slider-point">
<p class="pk-label">Family holidays</p>
<a href="#">
<div class="point"></div>
</a>
</div>

</div>
</div>
</div>


Here is an example on codepen so you can see it.

http://codepen.io/r3plica/pen/XKzWZa?editors=1101#0

Now, I have the buttons already working (so if I click them they animate the active class).
What I would like to do is to be able to drag the entire control so that it moves left and right like this:

enter image description here

I have to be able to do this without using jQuery, does anyone have any idea how I might go about it?

Answer

A lot of the problem when rolling your own is handling mouse drag events while preventing accidental clicks and keeping track of where things have been dragged to. You can use transform: translateX(); to accomplish the movement via CSS.

I did something like this a while back for rotation on mouse drag in pure javascript when I was playing around at making a roguelike using pure HTML5:

https://dl.dropboxusercontent.com/u/12933950/gridTest/grid.html

(I added some jQuery later but luckily I did the mouse rotation in JS).

For some reason I felt the impulse to spend an hour fitting it to your solution. I'd have given you a direction and left it at that but I wanted to make sure it worked, and it'd be nice for one of my first javascript projects to actually benefit someone.

You'll probably need to fix this for your needs (if this approach works for you at all), like by using transform on the buttons as they approach the middle of the screen (and you'll want to change the speed variable, or maybe make it more 1:1 with mouse drag through some refinement), so I don't think there's harm throwing it all out there for you to play with.

http://codepen.io/jackarbiter/pen/jAaPAQ?editors=1111

Note that I added an ID to the pk-slider-base, but the rest was all js changes.

I can't remember if my old solution worked on phones for dragging - one of the reasons a lot of people use jQuery-UI is so that they can do what they want for mouse events and then add touchpunch for mobile and be done with it.

Also, it has some comments that explain what's going on but isn't fully commented (I was bad about that back then) so if you have any questions let me know.

    var started = 0,
      xOff = 0,
      oldX = 0,
      pageX = 0,
      yourTrans = "",
      dragData = 0,
      downTime = 0,
      finalX = 0,
      mySpeed = window.innerWidth,
      yourElement = document.getElementById('pk-slider-base');

    function updateView() {
      "use strict";
      finalX = pageX * mySpeed;
      yourTrans = 'translateX(' + finalX + 'px)';
      yourElement.style.transform = yourTrans;
    }

    function setDrag() {
      "use strict";
      if (dragData === 0) {
        dragData = 1;
      }
    }

    function startDrag(ev) {
      "use strict";
      downTime = window.setTimeout(setDrag, 100);
      ev.preventDefault();
    }

    function drag(ev) {
      "use strict";
      if (dragData === 1) {

        if (started === 0) {
          //offset initial start position to result in 0
          xOff = (ev.clientX / window.innerWidth);
          //initial position (first drag) or last position
          oldX = pageX;
          started = 1;
        }
        pageX = ((ev.clientX / window.innerWidth) - xOff) + oldX;
        //set new offset or the position will exponentially increase
        xOff = (ev.clientX / window.innerWidth);
        updateView();
        oldX = pageX;
      }
    }

    function stopDrag(ev) {
      "use strict";
      window.clearTimeout(downTime);
      if (dragData === 1) {
        dragData = 0;
      }
      //setup for next drag
      started = 0;
    }

    window.addEventListener('mousedown', startDrag, false);
    window.addEventListener('mousemove', drag, false);
    window.addEventListener('mouseup', stopDrag, false);

    updateView();
.pk-slider {
  height: 100px; }
  .pk-slider .pk-slider-base {
    height: 1px;
    background-color: #c8cfd9;
    margin-top: 55px;
    margin-bottom: 10px;
    width: 10000px;
    margin-left: -5000px;
    text-align: center; }
    .pk-slider .pk-slider-base > div {
      display: inline-block; }
    .pk-slider .pk-slider-base .pk-slider-point {
      height: 50px;
      width: 50px;
      float: left;
      text-align: center;
      margin-top: -25px;
      margin-left: 200px;
      margin-right: 200px;
      position: relative; }
      .pk-slider .pk-slider-base .pk-slider-point > a {
        display: block;
        height: 50px;
        width: 50px; }
      .pk-slider .pk-slider-base .pk-slider-point .point {
        display: block;
        float: left;
        text-align: center;
        margin: 16px;
        height: 18px;
        width: 18px;
        line-height: 18px;
        border-radius: 9px;
        background-color: #c8cfd9;
        -webkit-transition: all 0.5s ease;
        /* Safari */
        transition: all 0.5s ease; }
        .pk-slider .pk-slider-base .pk-slider-point .point.active {
          height: 50px;
          width: 50px;
          line-height: 50px;
          border-radius: 25px;
          background-color: #3f4c5f;
          margin: 0; }
      .pk-slider .pk-slider-base .pk-slider-point .pk-label {
        z-index: -1;
        position: absolute;
        text-align: center;
        width: 1000px;
        top: 38px;
        left: -475px;
        color: #c8cfd9;
        -webkit-transition: all 0.5s ease;
        /* Safari */
        transition: all 0.5s ease; }
        .pk-slider .pk-slider-base .pk-slider-point .pk-label.active {
          top: 50px;
          color: #3f4c5f; }
<div class="pk-slider">
    <div class="pk-slider-base" style="margin-left: -4100px;" id="pk-slider-base">
        <div>
            <div class="pk-slider-point">                
                <p class="pk-label">Family holidays</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label">Sporting activities</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label">Travel</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label active">Photography is my passion</p>                
                <a href="#">
                    <div class="point active"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label">Nights out</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label">Special occasions</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
            <div class="pk-slider-point">                
                <p class="pk-label">Family holidays</p>                
                <a href="#">
                    <div class="point"></div>
                </a>
            </div>
            
        </div>
    </div>
</div>

Comments