Build a Tilemap with Angular 6
Using touch and mouse events for web and mobile
My goal was to show a tilemap and be able to select some tiles, whether it was on desktop or mobile. I stumbled upon a problem that included the touch
event, some CSS and many div tags.
MouseEvent
Beginning with the desktop, I used MouseEvents. mousedown
and mouseup
are used to begin and end the selection, and mouseenter
to give the row and column of the last tile.
I bind each MouseEvent to each tile.
This may seems like much, but don’t worry, it is simple. When we press the mouse button, we begin selecting the tiles. I keep the bounds and I update the tiles consequently (the selected property). It continues until we release the button, and the selection stops. It worked great on desktop 👌.
Then, I switched to responsive design mode on Firefox to see what happens. If I click, it selects a tile, alright, but if I keep going to select several tiles, it doesn’t work 😭.
The Problem
The problem comes from the way the TouchEvent
is implemented. You see, there is an order in which the events are fired.
1 : touchstart
2 : touchmove (0 or more)
3 : touchend
4 : mousedown
5 : mouseup
6 : click
So when I tried to select some tiles, only touchstart
and touchmove
had been fired at this point, and mouseenter
could not possibly be fired.
To resolve this problem, I had to use these TouchEvents.
TouchEvent
We can implement the TouchEvents on the TilemapComponent, and not on each tile element, thanks to the changedTouches property which gives the global coordinates of the touch
You can see much of my type assertion for the TouchEvents use any
: that’s because on desktop Firefox, TouchEvent is undefined
🙄. Besides, we need the type TouchEvent
or any
in order to use event.changedTouches
.
document.elementFromPoint()
My solution was to use the document.elementFromPoint(x,y)
. This function allows us to get the element with the higher z-index (usually the most nested one). As I can have some Elements before my tiles (as a div showing an image upon my selection), I have to check if the parentElement (the element behind) is my tile or not.
So, I’ve got my tile. Now I need a way to identify it. I could not have access to the object inside the tiles
array, only the HTML Element
representing this tile. I just had to give my tiles some id that could inform of the row and the column and my problem was solved. I could get this id back and slice it to have the row and the column of the tile.
So, here you go 😁, a foundation upon which many things can be built. Now it’s your turn.