Famo.us' GestureHandler doesn't seem to be catching on mobile devices. Even with the very simple test:
var FamousEngine = require('famous/core/FamousEngine');
var DOMElement = require('famous/dom-renderables/DOMElement');
var GestureHandler = require('famous/components/GestureHandler');
FamousEngine.init();
var scene = FamousEngine.createScene();
var rootNode = scene.addChild();
var backgroundNode = rootNode.addChild();
var backgroundElement = new DOMElement(rootNode, {
classes: ['background'],
});
var gestures = new GestureHandler(rootNode);
gestures.on('drag', function(e) {
console.log(e);
.
.
.
});
the drag gesture callback is firing on desktop when you drag with the mouse, but in a mobile browser dragging just scrolls the document around.
The event passed to the callback, e in my example, is a custom famous thing and doesn't have the usual .stopPropagation method.
What gives?
Turns out the answer had nothing to do with the event handling. Inside my event handler I was creating a few variables using ES6's new destructuring syntax:
var [x, y] = node.getPosition();
and while my code is being "babelified" and this works perfectly on desktop browsers, it was failing on iOS.
The issue also described here:
https://github.com/babel/babelify/issues/22
The solution is just to do it the old fashioned way...
:(
Related
Here is the thing.
I'm need to open a new tab and draw something on the new opened tab.
I add event listener like that:
div3.addEventListerner("onmousedown",MouseDown(NewWindow.event),false);
But the firefox throw errors about the code in the MouseDown() function when the page is loading. The error is not throwed when I move the mouse.
function MouseDown(event)
{
if(!event)
{
var event = window.event;
}
X = event.pageX;//Throw error here.
Y = event.pageY;
So, there is anyone who knows how to fix this Problem?????
Remove the var from var event = window.event. The variable is already declared (as an argument), so re-declaring it with var can only lead to problems.
To be specific, due to hoisting, here is what your code boils down to:
function MouseDown(event) {
var event; // = undefined
if( !event) { // always true
event = window.event; // undefined in modern browsers
}
X = event.pageX; // ERROR!
}
Without the var, all is well!
When you're using addEventListener(), Event object is passed automatically in all browsers supporting the said method. However, you're calling your eventhandler immediately in argument. Instead you should pass a reference:
div3.addEventListener("mousedown", MouseDown, false);
Notice also "mousedown" without on. In the handlerfunction, event always exists, no need to check it for older IEs, since they don't support addEventListener.
I developed a Javascript web application using dojo and the ESRI Javascript API. The main page of the application is a map view where the user can add points on the map.
On my desktop web browser, when I click the map a single new point is added and if I debug I can see that my onClick handler is called only once.
On my iPad, when I tap the map 2 points are added in the exact same location. When I debug the app on the iPad via Safari on my Macbook Pro I can see that the onClick handler is being called twice. Upon further debugging, I have made sure that the code that creates my onClick handler is only being called once.
startEditing : function(template) {
main.selectHandle.pause();
main.moveHandle.pause();
var drawingTool = template.template.drawingTool;
switch(drawingTool) {
case FeatureTemplate.TOOL_POINT:
drawingTool = Draw.POINT;
break;
}
this.drawEndHandle = on(this.drawingToolbar, "draw-end", lang.hitch(this, this.createFeature, template));
this.drawingToolbar.activate(drawingTool);
},
stopEditing : function() {
this.drawingToolbar.deactivate();
this.drawEndHandle.remove();
main.selectHandle.resume();
main.moveHandle.resume();
},
createFeature : function(template, evt) {
var featureLayer = template.featureLayer;
template = template.template;
var prototype = template.prototype;
var geometry = evt.geometry;
var graphic = new Graphic(prototype.toJson());
graphic.setGeometry(geometry);
this.initAttributes(graphic, featureLayer).then(function() {
var features = [graphic];
featureLayer.applyEdits(features).then(function(addResults) {
var objectIds = array.map(addResults, function(addResult) {
return addResult.objectId;
});
var q = new Query();
q.objectIds = objectIds;
featureLayer.selectFeatures(q).then(function(features) {
main.openForm(features);
});
});
});
},
The drawingToolbar in the startEditing function above is provided by the ESRI Javascript API, but handles the onClick event internally and passes it onto the onDrawEnd event that I am handling in my code. I have other code that handles the onClick event directly and it also fires twice.
UPDATE
I just tested the same functionality on my Android smartphone and it is also firing the onClick event twice with a single tap.
I have the exact same issue in an application I am building. I am also using the ESRI Javascript API.
I feel like there must be an event handler in either the map, the feature layer, or one of the dijit containers that passes along a tap event differently than the click.
In the end, I just debounced my click handler as described here: http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
I'm working on the plugin flot.touch.js which add touch interactivity (pan and zoom) on the chart for webkit browsers.
I want to make it work on IE10 too but I don't know how to retrieve the space between my touch points (I need this for calculate the scale).
On webkit browsers, we can do this by using these variables :
evt.originalEvent.touches[0].pageX
evt.originalEvent.touches[0].pagey
evt.originalEvent.touches[1].pageX
evt.originalEvent.touches[1].pageY
With IE's pointer events, a separate event is fired for each touch point. Unlike iOS touch events (as implemented by other browsers too), the state of each "pointer" is tracked separately. Consider it a more generic event that groups several pointer-based input devices.
Each event object is given a pointerId property that can be used to track its state. To track multiple touches, you'll need to store that pointerId along with any other variables in an object outside the scope of the event handler's function, along with any other data you might need. For example:
var pointers = {};
function pointerDown(evt) {
if (evt.preventManipulation)
evt.preventManipulation();
pointers[evt.pointerId] = [evt.PageX, evt.PageY];
for (var k in pointers) {
// loop over your other active pointers
}
}
function pointerUp(evt) {
delete pointers[evt.pointerId];
}
Further reading:
IEBlog - Handling Multi-touch and Mouse Input in All Browsers
Like Andy E said. Track how many pointers you have on your screen and store properties from each of them (in your case x and y coordinates, acquired form event)
A nice example of multitouch can be found here: http://ie.microsoft.com/testdrive/Graphics/TouchEffects/ and you can go into the code with F12 tools and get all the code under the Script tag: http://ie.microsoft.com/testdrive/Graphics/TouchEffects/Demo.js
There you can find this part of code:
function addTouchPoint(e) {
if(touchCount == 0) {
document.addEventListener(moveevent, moveTouchPoint, false);
}
var pID = e.pointerId || 0;
if(!touchPoints[pID]) {
touchCount++;
touchPoints[pID] = {x : e.clientX, y : e.clientY};
}
}
Hope it helps
If you're on a Windows 8 platform, IE10 supports the MSGesture object. This object can be used like the iOS version of gesture events. To initialize the object, we have to set the target object as well as add the MSPointer on MSPointerDown. For example:
var myGesture = new MSGesture();
var myElement = document.getElementById("MyCanvas");
myGesture.target = myElement; //sets target
myElement.addEventListener("MSPointerDown", function (event){
redGesture.addPointer(evt.pointerId); // adds pointer to the MSGesture object
}, false);
From here, you can add an event listener for the MSGestureChange function to process the event.scale property. Note that if the target is not set, an InvalidStateError exception will occur.
I am trying to simulate keypresses in a web application, it is for an embedded system but it uses a Webkit derived browser. I have tested the code in Chrome and get the same error.
I tried to use code snippets from this example from Yahoo, but I keep getting the same error when firing the event using dispatchEvent. "target" is an HTML element in the DOM tree.
function fireEvent(target) {
var evt = document.createEvent("UIEvent");
evt.initEvent("keypress", true, true);
target.dispatchEvent(evt);
}
It always throws:
"Error: UNSPECIFIED_EVENT_TYPE_ERR: DOM Events Exception 0"
I have tried createEvent("Events") as well and it always boils down to the same exception, both on the embedded system and in Chrome.
Ok, when doing further testing, it seemed that when all key event parameters was properly initialised, then dispatchEvent worked without fireing an exception.
The following code works.
function fireEvent(target) {
var evt = document.createEvent("Events");
evt.initEvent("keypress", true, true);
evt.view = window;
evt.altKey = false;
evt.ctrlKey = false;
evt.shiftKey = false;
evt.metaKey = false;
evt.keyCode = 0;
evt.charCode = 'a';
target.dispatchEvent(evt);
}
Keypress is an UIEvent. You should use initUIEvent( 'type', bubbles, cancelable, windowObject, detail ) rather than initEvent(). But for firefox, which implements a keyEvents, you should create a KeyEvents and initKeyEvents().
This one is old thread, just to update it I am adding another answer so that it makes more sense to any one.
initEvent() is deprecated It is still supported in some browsers but avoid using it.
There is better concise way to create events like this
function fireEvent(target) {
var event = new Event('build');
// Listen for the event.
target.addEventListener('build', function (e) { ... }, false);
// Dispatch the event.
target.dispatchEvent(event);
}
To add more data to the event object, the CustomEvent interface exists and the detail property can be used to pass custom data.
For example, the event could be created as follows:
var event = new CustomEvent('build', { 'detail': target.dataset.time });
Reference: Creating and Triggering Events
I am working with a map that uses a large set of vector features. In some browsers, there is significant lag when the OpenLayers is handling pointermove events interactions. For example:
function selectOnHover(map, handler, styleFn) {
var selectMove = new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
style: styleFn
});
map.addInteraction(selectMove);
selectMove.on('select', handler);
}
In other situations that handle continuous input (e.g. handling scroll events) and require significant processing, I would normally debounce the handler for the event - so that significant work is only done when the input has paused (in this case, determining the intersecting features). Is there a way to insert a debounce between browser event dispatch and OpenLayers checking intersections without circumventing OpenLayers interaction handling?
I've tried handling the pointermove/mousemove events directly, debouncing them (redispatching manually created synthetic events) and then using the interaction's condition to handle only the synthetic ones. This worked except that Internet Explorer's synthetic events weren't picked up by OpenLayers.
I'm considering circumventing OpenLayers interaction - for example by using forEachFeatureAtPixel and manually updating the style.
In fact, even using the standard API you can wrap a select interaction into a custom interaction and debounce the handleEvent function:
var app = {};
app.DebounceSelect = function() {
this.selectInteraction = new ol.interaction.Select({
condition: ol.events.condition.pointerMove
});
var handleEventDebounce = debounce(function(evt) {
return ol.interaction.Select.handleEvent.call(this.selectInteraction, evt);
}.bind(this), 100);
ol.interaction.Interaction.call(this, {
handleEvent: function(evt) {
handleEventDebounce(evt);
// always return true so that other interactions can
// also process the event
return true;
}
});
};
ol.inherits(app.DebounceSelect, ol.interaction.Interaction);
app.DebounceSelect.prototype.setMap = function(map) {
this.selectInteraction.setMap(map);
};
var select = new app.DebounceSelect();
map.addInteraction(select);
http://jsfiddle.net/n9nbrye8/3/
For reference an example on how to write custom interactions: http://openlayers.org/en/master/examples/custom-interactions.html
And the documentation for ol.interaction.Select.handleEvent