13.2 Drag items
Detta kapitel tar upp Pointer events, för att hantera drag-and-drop och andra pekaroperationer. I detta exempel går vi dock endast igenom hantering av drag items (de element som dras). Sedan fortsätter vi med hantering av drop zones (de element man kan släppa på) i nästa exempel. Genom att använda pointer events, kan vi skapa en kod som fungerar både på en dator med mus och på en pekskärm.
Vi tar upp två olika sätt att dra ett element. I det ena fallet skapas en klon av elementet och man drar sedan klonen. I det andra fallet dras originalet.
Del a och b — 38 min.
Del c och d — 19 min.
Sammanfattning
För hantering av mus finns Mouse Events och för hantering av pekskärm finns Touch Events. Pointer Events kombinerar dessa båda, så att vi inte behöver dubblera händelselyssnare eller kod för olika typer av enheter, utan istället används endast de händelser som finns i Pointer Events. Det finns flera olika händelser definierade, men i detta och kommande exempel är det de fyra följande som används:
pointerdown
— pekaren trycks ner och vi påbörjar operationen.pointermove
— inträffar varje gång pekaren dras, medan den fortfarande är nedtryckt.pointerup
— pekaren släpps upp och vi avslutar operationen.pointercancel
— pekaren kan inte längre detekteras, t.ex. om man drar utanför skärmen.
Kodens struktur och hantering av händelselyssnare
I init
-funktionen lägger vi endast på händelselyssnare för pointerdown
. Detta läggs på alla element som ska kunna dras. Den funktion som då anropas kallar vi pointerStart
.
I pointerStart
förbereder vi för pekaroperationen och lägger på övriga händelselyssnare. Dessa läggs oftast på document
. Vid pointermove
anropar vi en funktion kallad pointerMove
och vid både pointerup
och pointercancel
anropar vi funktionen pointerEnd
.
Funktionerna pointerMove
och pointerEnd
läggs inuti funktionen pointerStart
. Därmed kan de lokala variabler som införs i pointerStart
användas i alla tre funktionerna. Samtidigt ger denna struktur en gruppering och inneslutning av den kod som hanterar hela pekaroperationen.
I pointerMove
känner man av pekarens position och flyttar med elementet till den positionen. Det är det övre vänstra hörnet som positioneras, så för att pekaren ska ligga kvar inom elementet på samma plats som då den trycktes ner, får man kompensera för pekarens startposition, som tas fram i pointerStart
.
I pointerEnd
städar man upp genom att ta bort händelselyssnarna som lades på i pointerStart
. Man kan också behöva göra en del annan "uppstädning", beroende på vad som gjorts i pointerStart
.
Event-objektet
Event-objektet för pekaren ärver egenskaper från Mouse Event, bl.a. olika par av X- och Y-koordinater, men det innehåller också en del egenskaper som endast är specifika för Pointer Events, t.ex. isPrimary
. Denna egenskap är true
för den första pekaren som trycks ner och false
för övriga. I exemplet används den för att se till att vi på en pekskärm endast bryr oss om den första pekaren i den operation som hanteras här.
För att avläsa pekarens position används i detta exempel pageX
och pageY
, som är pekarens position inom hela dokumentet.
Koordinater för element
För element kan vi använda offsetLeft
och offsetTop
, för att avläsa positionen för dess övre vänstra hörn. Om elementet ligger inom ett annat element som har en annan poisition
än static
, är offset
-värdena avstånd till det omgivande elementets vänster- och överkant. I annat fall är de avstånd till dokumentets vänster- och överkant. De avlästa värdena är alltid i pixel och är numeriska värden. De kan endast avläsas, så man kan inte tilldela dem nya värden.
Man kan också använda en funktion kallad getBoundingClientRect()
för att få fram elementets placering inom webbläsarens fönster. Även dessa är numeriska värden i enheten pixel och de kan endast avläsas.
För att ge ett element en ny position måste man använda CSS-egenskaperna left
och top
. Det är enda möjligheten som finns för att lägga in nya värden för elementets placering.
CSS-egenskaperna user-select och touch-action
Båda dessa egenskaper kan sättas till none
eller auto
, där auto
är default-värdet. För de element man ska kunna dra brukar man lägga in none
på båda. Man tar med user-select:none
, för att det inte ska gå att markera innehållet i ett elementen som ska dras. Det kan annars se konstigt ut om man t.ex. råkar trycka ner pekaren utanför elementet och drar över det. Man tar med touch-action:none
, för att förhindra en del standardoperationer på en pekskärm. Normalt scrollar man webbsidan då man på en pekskärm trycker ner fingret och drar, men ska man dra ett element på sidan, vill man ju inte att dokumentet ska scrollas.
Händelsen touchstart och preventDefault()
För att förhindra att det poppar upp en markering eller meny för att dela eller spara, då man på en pekskärm trycker ner och håller pekaren nedtryckt en liten stund på en text eller bild, tar man också med en händelselyssnare för touchstart
i de element som ska kunna dras. I händelselyssnarens funktion utför man e.preventDefault()
.
Egna övningar
Övning på detta ingår i övningen i nästa exempel.