Programmeren voor aanraakschermen:
Veegbewegingen
Hieronder zie je een foto, de eerste uit een serie van vijf. Je kunt de andere foto's bekijken door een (snelle) veegbeweging
(naar links of naar rechts) over de foto te maken. In het gewone "computer"-spraakgebruik heet dat swipen. Die
term wordt in het verdere van dit verhaal gebruikt. Op deze pagina wordt beschreven hoe je zoiets maakt.
N.B.: Het voorbeeld werkt alleen met aanraakschermen. Slepen met de muis kan dus niet. Je kunt in dit voorbeeld
alleen naar links en naar rechts swipen; op naar boven en naar beneden swipen wordt door het voorbeeld niet gereageerd.
De code van het voorbeeld kun je downloaden om zelf te gebruiken, echter zonder de foto's. Daar moet je zelf voor zorgen.
- Er worden twee items besproken:
- De werking van het script.
- Toepassen in je eigen site.
- De werking van het script
- De code bestaat uit HTML, CSS en JavaScript (in de files swipedetect. js en script.js).
- De JavaScript-code is een bewerking van code die ik heb gevonden in een tutorial op JavaScriptKit.com. Voor deze site heb ik de code een beetje gereorganiseerd. Een kleine onvolkomenheid is
gerepareerd.
- HTML
- De HTML bestaat uit een enkele <div>-tag met id="container", met daarbinnen de <img>-tags voor de plaatjes.
- De container bevat de (vijf) plaatjes. Door de positionering en de afmetingen is alleen het eerste plaatje uit de reeks zichtbaar.
- De plaatjes hebben allemaal de klasse sliding (voor de afmetingen en de opmaak) en elk een uniek id="P0", "P1", … enz., (om elk plaatje efficiënt te benaderen met JavaScript). De nummering is oplopend vanaf nul en mag geen gaten bevatten.
- Voor de melding die ontstaat als er geen aanraakscherm is, is een vereenvoudigde versie gebruikt van de techniek die wordt
beschreven in het item Aanraakscherm detecteren.
- CSS
- De CSS van het voorbeeld bestaat uit twee blokken: #container en sliding.
- container is de viewport waar het plaatje in te zien is. De afmetingen zijn gelijk aan elk van de plaatjes, die allemaal even groot moeten zijn. In dit voorbeeld is dat 250px breed en 187px hoog.
- De container wordt horizontaal gecentreerd in de regel door de marges links en rechts op auto te zetten. De marges boven en onder zijn nul. De position is relative.
- De plaatjes staan binnen de container. Ze staan naast elkaar, zonder tussenruimte. Alleen het eerste plaatje is
zichtbaar. De rest is niet zichtbaar doordat container de eigenschap overflow:hidden heeft.
- Elk van de (in het voorbeeld) vijf plaatjes heeft de klasse sliding, waarmee een aantal eigenschappen wordt ingesteld. Het gaat hier om position:absolute, dat is ten opzichte van de container, nodig om de plaatjes van plaats te laten veranderen door JavaScript.
- top is gelijk aan nul, de plaatjes worden dus bovenaan in de container gezet. left wordt door JavaScript zodanig ingesteld dat de plaatjes strak tegen elkaar aan liggen.
- De afmetingen width en height worden hier ook ingesteld.
- De plaatjes verschuiven door de waarde van left van elk plaatje door JavaScript te veranderen in stappen van de breedte
van de plaatjes. Om dat vloeiend te laten verlopen is een transition
toegevoegd.
- JavaScript <
- Het JavaScript voor deze toepassing bestaat uit drie delen:
1. De melding die ontstaat als er geen aanraakscherm aanwezig is. Zie onder het kopje HTML. Dit wordt hier niet opnieuw besproken.
2. De (algemeen toepasbare) function swipedetect() voor het onderscheppen en analyseren van aanrakingen van het scherm. Deze staat in de file swipedetect.js.
3. De code die specifiek is voor de toepassing in het voorbeeld, in de file script.js.
- De function swipedetect()
- Zoals hierboven al is gemeld is deze function algemeen toepasbaar. De function staat in de file swipedetect.js.
- swipedetect() declareert als eerste een set variabelen, te weten: touchsurface, touchobj, swipedir,
startX, startY, distX, distY, startTime, elapsedTime, threshold, restraint,
allowedTime en handleswipe. Deze variabelen worden in het volgende besproken.
- De function swipedetect() heeft twee parameters, die allebei verplicht zijn: el en callback.
• el bevat een verwijzing naar het HTML-element dat moet reageren op een swipe. Dit haal je op met document.getElementById(). De waarde van el wordt bewaard in touchsurface.
• callback is de naam van de function die moet worden uitgevoerd als swipedetect() zijn werk heeft gedaan. Als callback niet bestaat wordt een (anonieme) function gebruikt die niets doet. - swipedetect() retourneert de string swipedir, die vijf waarden kan hebben:
• left Er is naar links geswiped.
• right Er is naar rechts geswiped.
• up Er is naar boven geswiped.
• down Er is naar onderen geswiped.
• none De beweging is niet herkend als geldige swipe. - De criteria, die swipedetect() gebruikt om na te gaan of een swipe geldig is, worden gestuurd door drie variabelen:
• threshold Dit is de minimale lengte (in pixels), horizontaal of verticaal, die de vinger moet afleggen over het scherm om een beweging een swipe te maken. In het voorbeeld: 150.
• restraint Een swipe zal nooit een zuiver horizontale of verticale lijn volgen; er zal altijd een afwijking zijn, loodrecht op de veegrichting. restraint bevat de toegestane afwijking, in pixels. In het voorbeeld: 100.
• allowedTime Dit is de tijd, in milliseconde, die een geldige swipe maximaal mag duren. In het voorbeeld: 300.
Je kunt deze drie waarden naar eigen inzicht aanpassen, maar dat raad ik niet aan. De hier gebruikte waarden definiëren een prettig aanvoelende swipe.
- swipedetect() maakt drie event-listeners aan, voor achtereenvolgens touchstart, touchmove en touchend.
- De event-listener voor touchstart bereidt het verplaatsen van de plaatjes voor.
• Als eerste wordt de lijst met de laatste wijziging van het touchEvent-object opgehaald en bewaard:touchobj = e.changedTouches[0];
.
• Daarna wordt swipedir op none gezet.
• De coördinaten van de aanraking worden bewaard in startX en startY.
• Het tijdstip van de aanraking wordt opgevraagd bij de systeemklok en bewaard in startTime.
• Tenslotte wordt de default-actie voor dit event uitgeschakeld. - De event-listener voor touchmove schakelt alleen de default-actie voor dit event uit. Daardoor wordt onbedoeld scrollen voorkomen.
- De event-listener voor touchend doet het grote werk.
• Als eerste wordt de lijst met de laatste wijziging van het touchEvent-object opgehaald en bewaard in touchobj.
• De lengte van de swipe wordt berekend door startX resp. startY af te trekken van de huidige coördinaten in X- en Y-richting. De resultaten worden opgeslagen in distX resp. distY.
• De tijdsduur van de swipe wordt berekend door de starttijd af te trekken van de huidige tijd. Het resultaat wordt bewaard in elapsedTime.
• Als elapsedTime ten hoogste gelijk is aan allowedTime, wordt gekeken naar distX en distY . Anders geeft swipedir() de bij touchstart ingestelde waarde none terug.
• Als |distX| ≥ |threshold| en |distY| ≤ restraint is er horizontaal geswiped. Als distX negatief is, is de swipe naar links, anders naar rechts. swipedir krijgt de waarde left resp. right.
• Als |distY| ≥ |threshold| en |distX| ≤ restraint is er verticaal geswiped. Als distY negatief is, is de swipe naar boven, anders naar beneden. swipedir krijgt de waarde up resp. down.
• Nu bekend is of er een geldige swipe is gemaakt of niet, kan de callback- function worden aangeroepen. Dat gebeurt door de variabele handleswipe aan te roepen als function met swipedir als parameter.
• Tenslotte wordt de default-actie voor dit event uitgeschakeld.
- De event-listener voor touchstart bereidt het verplaatsen van de plaatjes voor.
- De drie event-listeners hebben een extra parameter, met de waarde false. Deze derde parameter is optioneel en heeft false als default-waarde. Om deze reden wordt deze parameter vrijwel altijd weggelaten. Als hier true wordt gebruikt, mag het event niet omhoog bubbelen in de object-boom. Zie het item Over Event-bubbling voor meer informatie.
- Merk op dat swipedetect() maar één keer wordt aangeroepen, door de event-listener voor "load",
zie hieronder.
- De code die specifiek is voor de toepassing
- De voor het voorbeeld specifieke JavaScript-code bestaat uit een enkele listener die reageert op het event "load".
- Als er een aanraakscherm beschikbaar is worden functions en instellingen gemaakt zodat de pagina op swipes kan reageren. Anders stopt de uitvoering van de listener.
- Als eerste wordt er een verwijzing naar het code-blok met id="container" gemaakt en opgeslagen in el. Deze wordt gebruikt in de aanroep van swipedetect(), samen met de callback function(swipedir).
- swipedetect() stelt swipedir in; deze wordt gebruikt in een switch(), met vier case's en een default.
- De vier cases zijn: left, right ,up en down. Als swipedir gelijk is aan none gebeurt er niets De switch gaat naar default en daar staat geen code.
- Als swipedir gelijk is aan left, wordt de function NaarLinks() aangeroepen.
- Als swipedir gelijk is aan right, wordt de function NaarRechts() aangeroepen.
- Als swipedir gelijk is aan up of down, gebeurt er niets, omdat er geen code is gemaakt voor die cases.
- De afhandeling van de swipes is nu klaar. Nu is de beurt aan de plaatjes. Allereerst wordt het aantal plaatjes opgeslagen in aantalItems (hier: 5). De breedte van de plaatjes wordt vastgelegd in itemBreedte (hier: 250).
- Er worden array's gedeclareerd: topleft voor de X-coördinaten van de afzonderlijke plaatjes en wijzer voor verwijzingen naar de unieke id's van elk plaatje. Beide arrays hebben aantalItems elementen.
- De twee arrays worden gevuld met waarden:
• topleft krijgt de waarden 0, 250, 500, 750, 1000.
• wijzer krijgt verwijzingen naar P0, P1, P2, P3, P4.
• Tegelijkertijd worden de plaatjes op hun plaats gezet door wijzer[].style.left in te vullen.
- Het daadwerkelijke verplaatsten van de plaatjes gebeurt door de functions NaarLinks() en NaarRechts().
- NaarLinks() kijkt eerst of de X-coördinaat van het laatste plaatje gelijk is aan nul. Als dat zo is kan er niet verder worden gescrolled en stopt de uitvoering.
- Als er wel kan worden gescrolled wordt van alle elementen van topleft de waarde van itemBreedte afgetrokken. De nieuwe waarden worden verwerkt in wijzer[].style.left, waardoor de plaatjes verschuiven. De CSS-transition zorgt voor het vloeiende verloop.
- NaarRechts().kijkt eerst of de X-coördinaat van het eerste plaatje gelijk is aan nul. Als dat zo is kan er niet verder worden gescrolled en stopt de uitvoering.
- Als er wel kan worden gescrolled wordt bij alle elementen van topleft de waarde van itemBreedte opgeteld.
De nieuwe waarden worden verwerkt in wijzer[].style.left, waardoor de plaatjes verschuiven. De CSS-transition zorgt
voor het vloeiende verloop.
- Toepassen in je eigen site
- Regel een set foto's (minstens twee) die allemaal dezelfde afmetingen hebben.
- Download de .zip-file en pak hem uit. Bouw de code op zoals hieronder is aangegeven.
- Pas de HTML aan: maak voor elk plaatje een <i g>t-tag aan binnen de container , met de juiste bestandsnaam, class en id.
- Pas de CSS aan: hoogte en breedte van de #container, hoogte en breedte van .sliding en eventueel de transition.
- Pas aantalItems en itemBreedte aan in script. js (regel 22 en 23).
- Pas de melding over het aanraakscherm aan, aan je eigen wensen. Je kunt hem ook gewoon weglaten.
Gebruik:
- De code staat gedeeltelijk in de <HEAD> en gedeeltelijk in de <BODY>.
De code van het voorbeeld ziet er als volgt uit:
(Zet dit in de <HEAD>).
<style>
#container {
position:relative;
margin:0 auto;
width:250px;
height:187px;
overflow:hidden;
}
.sliding {
position:absolute;
top:0;
width:250px;
height:187px;
transition: all .5s ease;
}
</style>
<script src="swipedetect.js"></script>
<script src="script.js"></script>
(Zet dit in de <BODY> op de plaats waar de melding moet verschijnen als er geen aanraakscherm is).
<p id="Melding" style="text-align:center">
<script>
if (!"ontouchstart" in document.documentElement) {
document.getElementById('Melding').innerHTML =
"<b style=\"color:maroon; font-weight:bold\">Om het voorbeeld te kunnen bekijken
is een aanraakscherm nodig. Op dit scherm werkt het dus niet.</b>";
</script>
</p>
(Zet dit in de <BODY> op de plaats waar het plaatje moet verschijnen).
<div id="container">
<img src="foto_0.jpg" id="P0" class="sliding">
<img src="foto_1.jpg" id="P1" class="sliding">
<img src="foto_2.jpg" id="P2" class="sliding">
<img src="foto_3.jpg" id="P3" class="sliding">
<img src="foto_4.jpg" id="P4" class="sliding">
</div>
Downloaden:
Druk op de knop:
File: voorb293.zip, 2660 bytes.