Add gestures, and mouse events
This commit is contained in:
@@ -12,6 +12,16 @@
|
|||||||
import Dots from '../Dots/Dots.svelte'
|
import Dots from '../Dots/Dots.svelte'
|
||||||
import Arrow from '../Arrow/Arrow.svelte'
|
import Arrow from '../Arrow/Arrow.svelte'
|
||||||
import { NEXT, PREV } from '../direction'
|
import { NEXT, PREV } from '../direction'
|
||||||
|
import { swipeable } from '../swipeable'
|
||||||
|
import {
|
||||||
|
addResizeEventListener,
|
||||||
|
removeResizeEventListener
|
||||||
|
} from '../utils/event'
|
||||||
|
|
||||||
|
const directionFnDescription = {
|
||||||
|
[NEXT]: showNextPage,
|
||||||
|
[PREV]: showPrevPage
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable Next/Prev arrows
|
* Enable Next/Prev arrows
|
||||||
@@ -37,6 +47,7 @@
|
|||||||
* Transition speed (ms)
|
* Transition speed (ms)
|
||||||
*/
|
*/
|
||||||
export let speed = 500
|
export let speed = 500
|
||||||
|
let _speed = speed
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables auto play of slides
|
* Enables auto play of slides
|
||||||
@@ -61,8 +72,8 @@
|
|||||||
let currentPageIndex = 0
|
let currentPageIndex = 0
|
||||||
let pagesCount = 0
|
let pagesCount = 0
|
||||||
let pageWidth = 0
|
let pageWidth = 0
|
||||||
let offset
|
let offset = 0
|
||||||
let pageWindow
|
let pageWindowElement
|
||||||
let pagesElement
|
let pagesElement
|
||||||
|
|
||||||
const unsubscribe = store.subscribe(value => {
|
const unsubscribe = store.subscribe(value => {
|
||||||
@@ -71,7 +82,7 @@
|
|||||||
|
|
||||||
function applySlideSizes() {
|
function applySlideSizes() {
|
||||||
const children = pagesElement ? pagesElement.children : []
|
const children = pagesElement ? pagesElement.children : []
|
||||||
pageWidth = pageWindow.clientWidth
|
pageWidth = pageWindowElement.clientWidth
|
||||||
|
|
||||||
const slidesCount = children.length
|
const slidesCount = children.length
|
||||||
pagesCount = getPagesCount({ slidesCount, slidesToShow })
|
pagesCount = getPagesCount({ slidesCount, slidesToShow })
|
||||||
@@ -87,14 +98,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyAutoplay() {
|
function applyAutoplay() {
|
||||||
const autoplayDirectionFnDescription = {
|
|
||||||
[NEXT]: showNextPage,
|
|
||||||
[PREV]: showPrevPage
|
|
||||||
}
|
|
||||||
let interval
|
let interval
|
||||||
if (autoplay) {
|
if (autoplay) {
|
||||||
interval = setInterval(() => {
|
interval = setInterval(() => {
|
||||||
autoplayDirectionFnDescription[autoplayDirection]()
|
directionFnDescription[autoplayDirection]()
|
||||||
}, autoplaySpeed)
|
}, autoplaySpeed)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -105,14 +112,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
store.init(initialPageIndex)
|
|
||||||
applySlideSizes()
|
applySlideSizes()
|
||||||
|
store.init(initialPageIndex)
|
||||||
|
applyOffset()
|
||||||
|
|
||||||
const { teardownAutoplay } = applyAutoplay()
|
const { teardownAutoplay } = applyAutoplay()
|
||||||
|
|
||||||
window.addEventListener('resize', applySlideSizes)
|
addResizeEventListener(applySlideSizes)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('resize', applySlideSizes)
|
removeResizeEventListener(applySlideSizes)
|
||||||
teardownAutoplay()
|
teardownAutoplay()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -141,6 +149,21 @@
|
|||||||
store.next({ infinite, pagesCount })
|
store.next({ infinite, pagesCount })
|
||||||
applyOffset()
|
applyOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSwipeStart() {
|
||||||
|
_speed = 0
|
||||||
|
}
|
||||||
|
function handleThreshold(event) {
|
||||||
|
_speed = speed
|
||||||
|
directionFnDescription[event.detail.direction]()
|
||||||
|
}
|
||||||
|
function handleSwipeMove(event) {
|
||||||
|
offset += event.detail.dx
|
||||||
|
}
|
||||||
|
function handleSwipeEnd() {
|
||||||
|
_speed = speed
|
||||||
|
showPage(currentPageIndex)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
@@ -154,17 +177,22 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<div
|
<div
|
||||||
class="content-container"
|
class="content-container"
|
||||||
bind:this={pageWindow}
|
bind:this={pageWindowElement}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
use:swipeable="{{ thresholdProvider: () => pageWidth/3 }}"
|
||||||
|
on:start={handleSwipeStart}
|
||||||
|
on:move={handleSwipeMove}
|
||||||
|
on:end={handleSwipeEnd}
|
||||||
|
on:threshold={handleThreshold}
|
||||||
style="
|
style="
|
||||||
transform: translateX({offset}px);
|
transform: translateX({offset}px);
|
||||||
transition-duration: {speed}ms;
|
transition-duration: {_speed}ms;
|
||||||
"
|
"
|
||||||
bind:this={pagesElement}
|
bind:this={pagesElement}
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if arrows}
|
{#if arrows}
|
||||||
<slot name="next" {showNextPage}>
|
<slot name="next" {showNextPage}>
|
||||||
|
|||||||
@@ -94,6 +94,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.color-container > p {
|
.color-container > p {
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
|||||||
77
src/swipeable.js
Normal file
77
src/swipeable.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { NEXT, PREV } from './direction'
|
||||||
|
import {
|
||||||
|
addStartEventListener,
|
||||||
|
removeStartEventListener,
|
||||||
|
addMoveEventListener,
|
||||||
|
removeMoveEventListener,
|
||||||
|
addEndEventListener,
|
||||||
|
removeEndEventListener,
|
||||||
|
createDispatcher
|
||||||
|
} from './utils/event'
|
||||||
|
|
||||||
|
function getCoords(event) {
|
||||||
|
if (event instanceof TouchEvent) {
|
||||||
|
const touch = event.touches[0]
|
||||||
|
return {
|
||||||
|
x: touch ? touch.clientX : 0,
|
||||||
|
y: touch ? touch.clientY : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: rename to slidable
|
||||||
|
export function swipeable(node, { thresholdProvider }) {
|
||||||
|
const dispatch = createDispatcher(node)
|
||||||
|
let x
|
||||||
|
let y
|
||||||
|
let moved = 0
|
||||||
|
|
||||||
|
function handleMousedown(event) {
|
||||||
|
moved = 0
|
||||||
|
const coords = getCoords(event)
|
||||||
|
x = coords.x
|
||||||
|
y = coords.y
|
||||||
|
dispatch('start', { x, y })
|
||||||
|
addMoveEventListener(window, handleMousemove)
|
||||||
|
addEndEventListener(window, handleMouseup)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMousemove(event) {
|
||||||
|
const coords = getCoords(event)
|
||||||
|
const dx = coords.x - x
|
||||||
|
const dy = coords.y - y
|
||||||
|
x = coords.x
|
||||||
|
y = coords.y
|
||||||
|
dispatch('move', { x, y, dx, dy })
|
||||||
|
|
||||||
|
if (dx !== 0 && Math.sign(dx) !== Math.sign(moved)) {
|
||||||
|
moved = 0
|
||||||
|
}
|
||||||
|
moved += dx
|
||||||
|
if (Math.abs(moved) > thresholdProvider()) {
|
||||||
|
dispatch('threshold', { direction: moved > 0 ? PREV : NEXT })
|
||||||
|
removeEndEventListener(window, handleMouseup)
|
||||||
|
removeMoveEventListener(window, handleMousemove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseup(event) {
|
||||||
|
const coords = getCoords(event)
|
||||||
|
x = coords.x
|
||||||
|
y = coords.y
|
||||||
|
dispatch('end', { x, y })
|
||||||
|
removeEndEventListener(window, handleMouseup)
|
||||||
|
removeMoveEventListener(window, handleMousemove)
|
||||||
|
}
|
||||||
|
|
||||||
|
addStartEventListener(node, handleMousedown)
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
removeStartEventListener(node, handleMousedown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/utils/event.js
Normal file
46
src/utils/event.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// start event
|
||||||
|
export function addStartEventListener(source, cb) {
|
||||||
|
source.addEventListener('mousedown', cb)
|
||||||
|
source.addEventListener('touchstart', cb)
|
||||||
|
}
|
||||||
|
export function removeStartEventListener(source, cb) {
|
||||||
|
source.removeEventListener('mousedown', cb)
|
||||||
|
source.removeEventListener('touchstart', cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// end event
|
||||||
|
export function addEndEventListener(source, cb) {
|
||||||
|
source.addEventListener('mouseup', cb)
|
||||||
|
source.addEventListener('touchend', cb)
|
||||||
|
}
|
||||||
|
export function removeEndEventListener(source, cb) {
|
||||||
|
source.removeEventListener('mouseup', cb)
|
||||||
|
source.removeEventListener('touchend', cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// move event
|
||||||
|
export function addMoveEventListener(source, cb) {
|
||||||
|
source.addEventListener('mousemove', cb)
|
||||||
|
source.addEventListener('touchmove', cb)
|
||||||
|
}
|
||||||
|
export function removeMoveEventListener(source, cb) {
|
||||||
|
source.removeEventListener('mousemove', cb)
|
||||||
|
source.removeEventListener('touchmove', cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize event
|
||||||
|
export function addResizeEventListener(cb) {
|
||||||
|
window.addEventListener('resize', cb)
|
||||||
|
}
|
||||||
|
export function removeResizeEventListener(cb) {
|
||||||
|
window.removeEventListener('resize', cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDispatcher(source) {
|
||||||
|
function dispatch(event, data) {
|
||||||
|
source.dispatchEvent(new CustomEvent(event, {
|
||||||
|
detail: data
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return dispatch
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user