Monday, September 14, 2015

Not a Chance

Luck has nothing to do with it.
Did you ever sit down to do something that you thought would be easy, only to give up in frustration many hours later? That's the story of today's Amphibian.com comic.

Well, maybe not the whole story. It started because I wanted to make a comic that included three things: scratch-off lottery tickets, a reference to The Lottery by Shirley Jackson, and a statement about the odds of winning the lottery.

One of my uncles gives a big stack of scratch-off lottery tickets to one lucky family member every year for Christmas. Everyone loves them for some reason. I've often wondered about the cost-to-wins ratio on those things, and how much time it would take to play a whole bunch of them. I thought I would make a comic where several of the frames were hidden beneath a silvery covering that could be "scratched" off with the mouse cursor on desktop browsers or your finger on mobile browsers.

The desktop, mouse-based interaction was fairly easy. There were just a few quirks that had to be addressed. Since the user would be holding down the mouse button and dragging a "coin" cursor all over the cell, there were the unfortunate side-effects of having the speech bubble text selected and the frog images getting drug around with that "ghost" effect.

To prevent text on a web page from being selected by the mouse cursor, there is some CSS that can be used. Here it is (with all the possible browser-specific versions):

.noselect {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

I simply applied this .noselect class to the text in the scratch-off frames. To prevent the image drag ghosting, the solution is to set a handler for the dragstart event on all the images which simply returns false. No drags allowed. I use jQuery in my comic to do these tasks, as is reflected by the following code snippets:

$('.myclass').addClass("noselect");
$('.myclass img').on("dragstart", function() { return false; });

With those two issues out of the way it worked great on the desktop. Oh, but those mobile browsers... I had thought that I could make the page perform pretty much the same way on mobile by using touch events in addition to mouse events. I was wrong. So very wrong.

On the desktop it works by detecting the mouseenter event. When the mouse cursor enters on the cover elements (a bunch of rounded divs), the element is removed if the mouse button is down. In a mobile browser, there is of course no mouse cursor so I attempted to use a touchmove event instead. If the user is touching the screen and moves over one of the cover elements, it should vanish. Except that doesn't work.

It turns out that the target of a touchmove event is always the same element - the one where the touch started. Not that helpful, but I thought I could deal with it. Instead of capturing a finger moving across the cover divs, I could track the page X/Y of the touches on the comic cell div and use the little-known document.elementFromPoint(x, y) function to figure out which cover elements to remove.

var elem = document.elementFromPoint(x - window.scrollX, y - window.scrollY);
$(elem).remove();

Well, that maybe sorta worked. To get the right element you have to adjust for the page scroll, but the performance was terrible on my phone. I could have probably worked on it some more, but it was time to cut my losses. I'd spent too much time on this problem already. I made a mobile-specific, not-quite-as-cool, auto-scratch-off effect and called it a day.

I hate it when this happens, but it's worse to not ship than to ship with a sub-optimal product. At least in my opinion. That's why there are comics 3 times per week, even if some are terrible.

Amphibian.com comic for 14 September 2015