I've been avoiding mapgen4 for a few weeks now. I ran into a really annoying bug that frustrated me enough that I wanted to give up. I still need to get back to it, but I'm “productively procrastinating”. Instead of sitting around being frustrated, I'm getting other things done: map generation on a sphere, a procedural face generator, and adding touch event support to my pathfinding pages.

When I wrote the A* tutorial, I didn't consider touch events at all. The traffic I got from mobile/tablet was small. I soon added some touch event handling, but it was incomplete. I figured I'd fix it later. Well, it's been four years now. It's time to fix it finally! (Update: I think my touch event handlers used to work, but I think they stopped working when Chrome 56 and Safari 11.1 changed event handlers to default to passive sometime in late 2017 / early 2018; see this and this)

The main problem is that although I added a touch event handler, it still scrolled the page. So you'd try to paint a wall and it'd be scrolling at the same time. Annoying!

The way mouse events work on the A* page is that I capture mousedown on any tile and then put mousemove and mouseup on the window object. On mouseup I remove the event handlers from the window object. The mousemove will get sent to the window, but it will tell me which tile is under the mouse at the time. I was using that to tell me which graph node to point to.

The way touch events work is that I capture touchstart on any tile and then receive touchmove and touchend events as you move your finger around. These events get sent to the original tile, not to the tile your finger is under. The logic has to be different for touch events. I was using some browser-specific code to map the event location to an SVG element, and then using d3.js to map the SVG element to my graph node.

For grids it's easy to map a pixel location to the grid coordinates directly, without using browser-specific code. So I only needed the browser-specific code for the non-grid map at the top of the page. I decided to implement point-in-polygon to handle the non-grid map. Although there are some easy solutions on stackoverflow and also on Paul Bourke's site, many of them are not numerically robust, as pointed out in Schirra S. (2008) How Reliable Are Practical Point-in-Polygon Strategies? (Thanks to Mikola Lysenko for this link.) I ended up spending too much time reading about this before deciding the numerical stability wasn't a problem for this page.

While working on this I also discovered:

  • Some diagrams use mouse hover, which doesn't work on touch devices.
  • Some code was populating a diagram that no longer existed. The way d3.js works, if you selectAll something that doesn't exist, it will create an empty selection. Then when you set attributes or create elements inside that empty selection, it does nothing. So this bug went unnoticed until now.
  • Some CSS was for a different diagram I no longer have.
  • The paint operation occasionally wrapped around the left/right sides of the grid. It only happened when the pixel-to-grid fallback code was called. After making this the primary path (removing the browser-specific code), it happened frequently, so I fixed it.

I also fixed touch events on some of the other pathfinding pages:

It turned out the diagrams on the making-of page were broken. I fixed them, but the mouse events aren't right. I think I need to use window.getComputedStyle(element).transform to get the 3D matrix transform, invert that, and then apply that to the mouse pixel coordinates. And it's somewhat browser specific, as there's both WebKitCSSMatrix and DOMMatrix, neither supported by all browsers. Neither is GeometryUtils. Ugh. I spent an hour on this and decided although it's a cool page, very few people see or use it, so I shouldn't spend any more time on it. I can take a look another day.

So the good news is that most of the pathfinding pages now properly work with touch screens. Try Introduction to A* on a phone or tablet. The bad news is that the "exploded diagrams" page doesn't respond to mouse events properly. Overall, a good day!

Labels:

0 comments: