Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a simple left/right swipe gesture

I need to add a simple left/right swipe gesture so that the 'selected' image cycles when swiped on mobile, similar to clicking the buttons in the hero component, also similar to pressing the left/right arrow keys on a keyboard

I don't have the most experience with JavaScript so if anyone could tell me what exactly to write and where so that I can completely wrap up this project.

Here is a demo: http://nufaith.ca/justinatkins/

Code:

Vue.component('hero-bg', {
  template: `
    <div class="hero-bg">
      <div class="hero">
        <img id="pushed" :src="selected"/>
      </div>
    </div>
    `,
  props: ['selected']
});

Vue.component('hero-bg-empty', {
  template: `
    <div class="hero-bg">
      <div class="hero">
      <span style="display:block;height:100px;"></span>
      </div>
    </div>
    `
});

Vue.component('hero', {
  template: `
    <div>
      <topbar v-if="!gridEnabled"></topbar>
      <topbar2 v-if="gridEnabled"></topbar2>
      <hero-bg :selected="selectedItem.img" v-if="!gridEnabled"></hero-bg>
      <hero-bg-empty v-if="gridEnabled"></hero-bg-empty>
      <div class="hero-container" v-if="!gridEnabled">
        <div class="hero">
          <img :src="selectedItem.img" v-if="thing" alt=""/>
        </div>

        <div class="hero-desc">
          <button class="control left" @click="previous">
            <i class="zmdi zmdi-chevron-left"></i>
          </button>
          <span class="hero-desc-title" v-html="title"></span>
          <button class="control right" @click="next">
            <i class="zmdi zmdi-chevron-right"></i>
          </button>
          <br/>
          <button class="view-all-button" @click="enableGrid">OVERVIEW</button>
        </div>
      </div>
    </div>
    `,
  data() {
    return {
      gridEnabled: false,
      selected: 0,
      thing: true
    };
  },
  computed: {
    selectedItem() {
      return info[this.selected];
    },
    title() {
      const comma = this.selectedItem.title.indexOf(',');
      const len = this.selectedItem.title.length;
      const strBeginning = this.selectedItem.title.substring(comma, 0);
      const strEnd = this.selectedItem.title.substring(comma, len);
      if (this.selectedItem.title.includes(',')) {
        return `<span>${strBeginning}<span class="font-regular font-muted">${strEnd}</span></span>`;
      }
      return this.selectedItem.title;
    },
    maxImages() {
      return info.length - 1;
    }
  },
  created() {
    window.addEventListener('keydown', e => {
      if (e.keyCode === 37) {
        this.previous();
        return;
      }

      if (e.keyCode === 39) {
        this.next();
        return;
      }
    });
    Event.$on('updateImg', index => {
      this.selected = index;
      this.gridEnabled = !this.gridEnabled;
    });
  },
  methods: {
    next() {
      this.selected === this.maxImages ? (this.selected = 0) : (this.selected += 1);
    },
    previous() {
      this.selected === 0 ? (this.selected = this.maxImages) : (this.selected -= 1);
    },
    enableGrid() {
      this.gridEnabled = !this.gridEnabled;
      window.scroll(0, 0);
      Event.$emit('enableGrid');
    }
  }
});
like image 792
James Bameron Avatar asked Jul 09 '20 20:07

James Bameron


2 Answers

This is how I implemented a simple swipe gesture in one of my projects. You may check this out.

Code:

touchableElement.addEventListener('touchstart', function (event) {
    touchstartX = event.changedTouches[0].screenX;
    touchstartY = event.changedTouches[0].screenY;
}, false);

touchableElement.addEventListener('touchend', function (event) {
    touchendX = event.changedTouches[0].screenX;
    touchendY = event.changedTouches[0].screenY;
    handleGesture();
}, false);


function handleGesture() {
    if (touchendX < touchstartX) {
        console.log('Swiped Left');
    }

    if (touchendX > touchstartX) {
        console.log('Swiped Right');
    }

    if (touchendY < touchstartY) {
        console.log('Swiped Up');
    }

    if (touchendY > touchstartY) {
        console.log('Swiped Down');
    }

    if (touchendY === touchstartY) {
        console.log('Tap');
    }
}

Basically, touchableElement mentioned here, refers to the DOM Element that will receive the touch event. If you want to activate swipe options on your entire screen, then you may use your body tag as the touchable element. Or you may configure any specific div element as the touchable element, in case you just want the swipe gesture on that specific div.

On that touchableElement, we are adding 2 event-listeners here:

  1. touchstart: this is when user starts swiping. We take that initial coordinates (x,y) and store them into touchstartX, touchstartY respectively.
  2. touchend: this is when user stops swiping. We take that final coordinates (x, y) and store them into touchendX, touchendY respectively.

Keep in mind that, the origin of these coordinates is the top left corner of the screen. x-coordinate increases as you go from left to right and y-coordinate increases as you go from top to bottom.

Then, in handleGesture(), we just compare those 2 pair of coordinates (touchstartX, touchstartY) and (touchendX, touchendY), to detect different types of swipe gesture (up, down, left, right):

  • touchendX < touchstartX: says that, user started swiping at a higher X value & stopped swiping at a lower X value. That means, swiped from right to left (Swiped Left).

  • touchendX > touchstartX: says that, user started swiping at a lower X value & stopped swiping at a higher X value. That means, swiped from left to right (Swiped Right).

  • touchendY < touchstartY: says that, user started swiping at a higher Y value & stopped swiping at a lower Y value. That means, swiped from bottom to top (Swiped Up).

  • touchendY > touchstartY: says that, user started swiping at a lower Y value & stopped swiping at a higher Y value. That means, swiped from top to bottom (Swiped Down).

You may add the code for these 4 different events (Swipe Up/Down/Left/Right), on the corresponding if blocks, as shown on the code.

like image 150
smmehrab Avatar answered Oct 04 '22 15:10

smmehrab


I took smmehrab’s answer, added some thresholds to avoid accidental swipes, and turned it into a little library. Might come in handy, so here it is:

export default class TouchEvent
{
    static SWPIE_THRESHOLD = 50 // Minumum difference in pixels at which a swipe gesture is detected

    static SWIPE_LEFT   = 1
    static SWIPE_RIGHT  = 2
    static SWIPE_UP     = 3
    static SWIPE_DOWN   = 4

    constructor(startEvent, endEvent)
    {
        this.startEvent = startEvent
        this.endEvent = endEvent || null
    }

    isSwipeLeft()
    {
        return this.getSwipeDirection() == TouchEvent.SWIPE_LEFT
    }

    isSwipeRight()
    {
        return this.getSwipeDirection() == TouchEvent.SWIPE_RIGHT
    }

    isSwipeUp()
    {
        return this.getSwipeDirection() == TouchEvent.SWIPE_UP
    }

    isSwipeDown()
    {
        return this.getSwipeDirection() == TouchEvent.SWIPE_DOWN
    }

    getSwipeDirection()
    {
        let start = this.startEvent.changedTouches[0]
        let end = this.endEvent.changedTouches[0]

        if (!start || !end) {
            return null
        }

        let horizontalDifference = start.screenX - end.screenX
        let verticalDifference = start.screenY - end.screenY

        // Horizontal difference dominates
        if (Math.abs(horizontalDifference) > Math.abs(verticalDifference)) {
            if (horizontalDifference >= TouchEvent.SWPIE_THRESHOLD) {
                return TouchEvent.SWIPE_LEFT
            } else if (horizontalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
                return TouchEvent.SWIPE_RIGHT
            }

        // Verical or no difference dominates
        } else {
            if (verticalDifference >= TouchEvent.SWPIE_THRESHOLD) {
                return TouchEvent.SWIPE_UP
            } else if (verticalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
                return TouchEvent.SWIPE_DOWN
            }
        }

        return null
    }

    setEndEvent(endEvent)
    {
        this.endEvent = endEvent
    }
}

How to use

Simply feed it the events from touchstart and touchend:

import TouchEvent from '@/TouchEvent'

let touchEvent = null;

document.addEventListener('touchstart', (event) => {
    touchEvent = new TouchEvent(event);
});

document.addEventListener('touchend', handleSwipe);

function handleSwipe(event)
{
    if (!touchEvent) {
         return;
    }

    touchEvent.setEndEvent(event);

    if (touchEvent.isSwipeRight()) {
        // Do something
    } else if (touchEvent.isSwipeLeft()) {
        // Do something different
    }

    // Reset event for next touch
    touchEvent = null;
}
like image 23
Rob Avatar answered Oct 04 '22 16:10

Rob