ID:1692648
 
Code:
<html>
<head>
</head>
<body>
<div id="map" byondclass="map" skinparams="zoom=1"></div>
<div id="touchControls" byondclass="touchControls"></div>
</body>
</html>

<byondclass name="touchControls">
<script>
(function() {
var touchable = 'createTouch' in document;
return {
fn: {
create: function() {
function onTouchStart(e) {
byond.fn.topic("touch=test");
}
byond.map.canvas.addEventListener( 'touchStart', onTouchStart, true);
},
winset: function(props, sub) {
if(touchable) {
byond.fn.topic("status=touchable");
} else {
byond.fn.topic("status=no_touch");
}
}
}
};
})()
</script>
</byondclass>


Problem description:

I'm trying to create touch controls, I've been testing with my iPad. I'm not sure how to add an event listener to the canvas. It causes the map not to load or the byond.fc.topic(...)s to not be sent by the web client and/or received by client/Topic()

I've also attempted to add the event listener to document, byond.map, byond.map.ui, byond.map.ui.map.
In Chrome and Firefox, you can press F12 to open the console and see why it crashed. In you case, I'm seeing "Uncaught Error: NullError: byond.map is undefined".

You can also use the command console.log(msg) to send output to the console. It will also print objects, so it's very handy for debugging.

According to the WebClient docs, the proper way to get the map canvas would be something like this:
var mapControl = byond(null, "map");
var mapCanvas = mapControl.ui.map;


This worked for me:
<byondclass name="touchControls">
<script>
(function() {
var touchable = 'createTouch' in document;
return {
fn: {
create: function() {
var mapControl = byond(null, "map");
//console.log(mapControl);
var mapCanvas = mapControl.ui.map;
//console.log(mapCanvas);
mapCanvas.addEventListener( 'touchstart', this.handleTouchStart.bind(this), true);
mapCanvas.addEventListener( 'click', this.handleClick.bind(this), true);
},
handleTouchStart: function(evt) {
//console.log("handleTouchStart");
this.input("dump \"touchstart\"");
},
handleClick: function(evt) {
//console.log("handleClick");
this.input("dump \"click\"");
}
}
};
})()
</script>
</byondclass>


Where dump is a debug verb:
client/verb/dump(t as text)
src << "Received: [t]"


Took me a minute to realize that mouse clicks don't trigger touch events, which is why I added a simple click event to test it. Also, not sure if it matters, but event names are usually all lower-case.

Also, it's probably worth mentioning that this introduces a load-order dependency. The touchControls class must always be listed after the map in the skin, or the canvas won't be created before you try to attach listeners to it.
I haven't been able to get the touch or click events to print out anything. In the console I can see it adding the click event log on my computers web browser. I can also see the click event listener in the Event Listeners, There is a click event by default, can you have multiple events for click?
(Testing in Chrome)

As for the touch event nothing happens when I touch the screen other that is being easy to scroll the page.
(Testing in Safari on a iPad 3rd gen)

Here is the latest code:

<html>
<head>
</head>
<body>
<div id="map" byondclass="map"></div>
<div id="touchControls" byondclass="touchControls"></div>
</body>
</html>

<byondclass name="touchControls">
<script>
(function() {
var touchable = 'createTouch' in document;
return {
fn: {
create: function() {
var mapControl = byond(null, "map");
console.log("*********************MapControl***********************");
console.log(mapControl);
console.log("*********************MapCanvas***********************");
var mapCanvas = mapControl.ui.map;
console.log(mapCanvas);
if(touchable) {
console.log("*********************AddTouch***********************");
mapCanvas.addEventListener( 'touchstart', this.handleTouchStart.bind(this), true);
} else {
console.log("*********************AddClick*********************");
mapCanvas.addEventListener( 'click', this.handleClick.bind(this), true);
}
},
handleTouchStart: function(evt) {
//console.log("handleTouchStart");
this.input("dump \"touchstart\"");
},
handleClick: function(evt) {
console.log("handleClick");
//this.input("dump \"click\"");
}
}
};
})()
</script>
</byondclass>


client/verb/dump(t as text)
world<<"World - received: [t]"
src << "Client - received: [t]"
Strange, it's working fine in my project. I can't see any significant difference between my setup and yours.

Does this work for you?
http://files.byondhome.com/DarkCampainger/ Web%20Touch_src.zip
I'm afraid I couldn't see anything print out. I tried joining with my iPad(Safari) and Android Phone(Chrome). Neither of them printed out anything when I touched on various parts of the game view/screen.

Also, the output looked like it was in the wrong place. It looks like it should be on the right according to your code. It's below the map for me. Here is a screenshot:


I'm hosting from BYOND Version: 507.1260
In response to Zaltron
Does it work on your desktop? I don't have any tablets handy to test with. I wonder if there's some limitation you're hitting in the mobile browsers.

Also, the child control defaults to a horizontal splitter, so although the params are called left and right, they're actually top and bottom by default.
In response to DarkCampainger
I'm afraid not. It tested clicking around with both event listeners in, then just the click event. I saw no messages in the output so I adding the console log messages. Nothing was printed out there either. I also didn't see any errors in the logs.

When it comes to the touch controls on mobile devices I tested the touch event listener outside of BYOND in a webpage that had a canvas and it worked great. It handled up to 10 touches.
The release tomorrow has some updates that should improve this stuff.