I try to make this work on iOS / Safari:
var map = L.map('map').setView([51.505, -0.09], 13);
map.on('touchstart', function() {
// does not get here when touching the map
alert('touchstart')
})
But couldn't figure out how. It's not listed in the API reference but I wonder if there is any way to support this event?
Or maybe there is even a better way to achieve the following:
I want to add a marker to a map, by touch and holding for a second. It was easy to set this up for mouse events, but I can't find a way to make the same for touch events.
Any idea?
I found a workaround on the mailing list:
https://groups.google.com/forum/?fromgroups=#!topic/leaflet-js/M-6fIg7K1CU
Here it is, slightly adjusted, so it adds support for both, touchstard & touchend:
L.Map.mergeOptions({
touchExtend: true
});
L.Map.TouchExtend = L.Handler.extend({
initialize: function (map) {
this._map = map;
this._container = map._container;
this._pane = map._panes.overlayPane;
},
addHooks: function () {
L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this);
L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this);
},
removeHooks: function () {
L.DomEvent.off(this._container, 'touchstart', this._onTouchStart);
L.DomEvent.off(this._container, 'touchend', this._onTouchEnd);
},
_onTouchStart: function (e) {
if (!this._map._loaded) { return; }
var type = 'touchstart';
var containerPoint = this._map.mouseEventToContainerPoint(e),
layerPoint = this._map.containerPointToLayerPoint(containerPoint),
latlng = this._map.layerPointToLatLng(layerPoint);
this._map.fire(type, {
latlng: latlng,
layerPoint: layerPoint,
containerPoint: containerPoint,
originalEvent: e
});
},
_onTouchEnd: function (e) {
if (!this._map._loaded) { return; }
var type = 'touchend';
this._map.fire(type, {
originalEvent: e
});
}
});
L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend);
But maybe there is a more elegant solution?
If you just want to listen to a long press on the map, then add a 'contextmenu' event listener. The event fires on a right click or a long press on the map
Closing as contextmenu should work perfectly for the original case.
contextmenu doesn't really work well...
contextmenu should work, what doesn't work about it?
The code above didn't work for me because this._map.mouseEventToContainerPoint(e) didn't work on touch events. Instead (coffeescript):
L.Map.mergeOptions
touchExtend: true
L.Map.TouchExtend = L.Handler.extend
initialize: (map) ->
this._map = map
this._container = map._container
this._pane = map._panes.overlayPane
addHooks: ->
L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this)
L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this)
L.DomEvent.on(this._container, 'touchmove', this._onTouchMove, this)
removeHooks: () ->
L.DomEvent.off(this._container, 'touchstart', this._onTouchStart)
L.DomEvent.off(this._container, 'touchend', this._onTouchEnd)
L.DomEvent.off(this._container, 'touchmove', this._onTouchMove)
_onTouchEvent: (e, type) ->
return unless this._map._loaded
touch = e.touches[0]
containerPoint = L.point(touch.clientX, touch.clientY)
layerPoint = this._map.containerPointToLayerPoint(containerPoint)
latlng = this._map.layerPointToLatLng(layerPoint)
this._map.fire type,
latlng: latlng
layerPoint: layerPoint
containerPoint: containerPoint
originalEvent: e
_onTouchStart: (e) ->
@_onTouchEvent(e, 'touchstart')
_onTouchEnd: (e) ->
return unless this._map._loaded
this._map.fire 'touchend',
originalEvent: e
_onTouchMove: (e) ->
@_onTouchEvent(e, 'touchmove')
L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend)
Expanding on the post above... for touch events the touch.clientX and touch.clientY may not be accurate if the map is not full screen. When I tried the above code the coordinates were off by a bit. I took a look at the way Leaflet figures out the coordinates from event data in L.DomEvent. getMousePosition() and replicated the logic with touch events.
Instead of doing
touch = e.touches[0]
containerPoint = L.point(touch.clientX, touch.clientY)
I did
var touch = e.touches[0],
rect = this._container.getBoundingClientRect(),
lat = touch.clientX - rect.left - this._container.clientLeft,
lng = touch.clientY - rect.top - this._container.clientTop,
containerPoint = L.point(lat, lng),
Most helpful comment
I found a workaround on the mailing list:
https://groups.google.com/forum/?fromgroups=#!topic/leaflet-js/M-6fIg7K1CU
Here it is, slightly adjusted, so it adds support for both, touchstard & touchend:
But maybe there is a more elegant solution?