1291 lines
43 KiB
JavaScript
1291 lines
43 KiB
JavaScript
defineSuite([
|
|
'Core/ScreenSpaceEventHandler',
|
|
'Core/Cartesian2',
|
|
'Core/clone',
|
|
'Core/combine',
|
|
'Core/defined',
|
|
'Core/FeatureDetection',
|
|
'Core/KeyboardEventModifier',
|
|
'Core/ScreenSpaceEventType',
|
|
'Specs/DomEventSimulator'
|
|
], function(
|
|
ScreenSpaceEventHandler,
|
|
Cartesian2,
|
|
clone,
|
|
combine,
|
|
defined,
|
|
FeatureDetection,
|
|
KeyboardEventModifier,
|
|
ScreenSpaceEventType,
|
|
DomEventSimulator) {
|
|
'use strict';
|
|
|
|
var usePointerEvents;
|
|
var element;
|
|
var handler;
|
|
|
|
function createCloningSpy(name) {
|
|
var spy = jasmine.createSpy(name);
|
|
|
|
var cloningSpy = function() {
|
|
// deep clone arguments so they are captured correctly by the spy
|
|
var args = [].slice.apply(arguments).map(function(arg) {
|
|
return clone(arg, true);
|
|
});
|
|
|
|
spy.apply(this, args);
|
|
};
|
|
|
|
function createPropertyDescriptor(prop) {
|
|
return {
|
|
get : function() {
|
|
return spy[prop];
|
|
},
|
|
set : function(value) {
|
|
spy[prop] = value;
|
|
}
|
|
};
|
|
}
|
|
|
|
for ( var prop in spy) {
|
|
if (spy.hasOwnProperty(prop)) {
|
|
Object.defineProperty(cloningSpy, prop, createPropertyDescriptor(prop));
|
|
}
|
|
}
|
|
|
|
return cloningSpy;
|
|
}
|
|
|
|
var eventsToStop = 'pointerdown pointerup pointermove pointercancel mousedown mouseup mousemove touchstart touchend touchmove touchcancel dblclick wheel mousewheel DOMMouseScroll'.split(' ');
|
|
|
|
function stop(event) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
}
|
|
|
|
beforeAll(function(){
|
|
usePointerEvents = FeatureDetection.supportsPointerEvents();
|
|
});
|
|
|
|
beforeEach(function() {
|
|
// ignore events that bubble up to the document.
|
|
// this prevents triggering the browser's "middle click to scroll" behavior
|
|
eventsToStop.forEach(function(e) {
|
|
document.addEventListener(e, stop, false);
|
|
});
|
|
|
|
element = document.createElement('div');
|
|
element.style.position = 'absolute';
|
|
element.style.top = '0';
|
|
element.style.left = '0';
|
|
document.body.appendChild(element);
|
|
element.disableRootEvents = true;
|
|
|
|
if (usePointerEvents) {
|
|
spyOn(element, 'setPointerCapture');
|
|
}
|
|
|
|
handler = new ScreenSpaceEventHandler(element);
|
|
});
|
|
|
|
afterEach(function() {
|
|
document.body.removeChild(element);
|
|
handler = !handler.isDestroyed() && handler.destroy();
|
|
|
|
eventsToStop.forEach(function(e) {
|
|
document.removeEventListener(e, stop, false);
|
|
});
|
|
});
|
|
|
|
describe('setInputAction', function() {
|
|
it('throws if action is undefined', function() {
|
|
expect(function() {
|
|
handler.setInputAction();
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it('throws if type is undefined', function() {
|
|
expect(function() {
|
|
handler.setInputAction(function() {
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
});
|
|
|
|
describe('getInputAction', function() {
|
|
it('throws if type is undefined', function() {
|
|
expect(function() {
|
|
handler.getInputAction();
|
|
}).toThrowDeveloperError();
|
|
});
|
|
});
|
|
|
|
describe('removeInputAction', function() {
|
|
it('throws if type is undefined', function() {
|
|
expect(function() {
|
|
handler.removeInputAction();
|
|
}).toThrowDeveloperError();
|
|
});
|
|
});
|
|
|
|
var MouseButton = {
|
|
LEFT : 0,
|
|
MIDDLE : 1,
|
|
RIGHT : 2
|
|
};
|
|
|
|
function keyForValue(obj, val) {
|
|
for ( var key in obj) {
|
|
if (obj[key] === val) {
|
|
return key;
|
|
}
|
|
}
|
|
}
|
|
|
|
function createMouseSpec(specFunction, eventType, button, modifier) {
|
|
var specName = keyForValue(ScreenSpaceEventType, eventType) + ' action';
|
|
if (defined(modifier)) {
|
|
specName += ' with ' + keyForValue(KeyboardEventModifier, modifier) + ' modifier';
|
|
}
|
|
it(specName, function() {
|
|
var eventOptions = {
|
|
button : button,
|
|
ctrlKey : modifier === KeyboardEventModifier.CTRL,
|
|
altKey : modifier === KeyboardEventModifier.ALT,
|
|
shiftKey : modifier === KeyboardEventModifier.SHIFT
|
|
};
|
|
specFunction(eventType, modifier, eventOptions);
|
|
});
|
|
}
|
|
|
|
function createAllMouseSpecCombinations(specFunction, possibleButtons, possibleModifiers, possibleEventTypes) {
|
|
for (var i = 0; i < possibleButtons.length; ++i) {
|
|
var eventType = possibleEventTypes[i];
|
|
var button = possibleButtons[i];
|
|
for (var j = 0; j < possibleModifiers.length; ++j) {
|
|
var modifier = possibleModifiers[j];
|
|
createMouseSpec(specFunction, eventType, button, modifier);
|
|
}
|
|
}
|
|
}
|
|
|
|
function simulateMouseDown(element, options) {
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine(options, {
|
|
pointerType : 'mouse'
|
|
}));
|
|
} else {
|
|
DomEventSimulator.fireMouseDown(element, options);
|
|
}
|
|
}
|
|
|
|
function simulateMouseUp(element, options) {
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerUp(element, combine(options, {
|
|
pointerType : 'mouse'
|
|
}));
|
|
} else {
|
|
DomEventSimulator.fireMouseUp(element, options);
|
|
}
|
|
}
|
|
|
|
function simulateMouseMove(element, options) {
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerMove(element, combine(options, {
|
|
pointerType : 'mouse'
|
|
}));
|
|
} else {
|
|
DomEventSimulator.fireMouseMove(element, options);
|
|
}
|
|
}
|
|
|
|
describe('handles mouse down', function() {
|
|
function testMouseDownEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
simulateMouseDown(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [MouseButton.LEFT, MouseButton.MIDDLE, MouseButton.RIGHT];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.LEFT_DOWN, ScreenSpaceEventType.MIDDLE_DOWN, ScreenSpaceEventType.RIGHT_DOWN];
|
|
createAllMouseSpecCombinations(testMouseDownEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
describe('handles mouse up', function() {
|
|
function testMouseUpEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
// down, then up
|
|
function simulateInput() {
|
|
simulateMouseDown(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
simulateMouseUp(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
action.calls.reset();
|
|
|
|
// down, move, then up
|
|
function simulateInput2() {
|
|
simulateMouseDown(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
simulateMouseMove(element, combine({
|
|
clientX : 10,
|
|
clientY : 11
|
|
}, eventOptions));
|
|
simulateMouseUp(element, combine({
|
|
clientX : 10,
|
|
clientY : 11
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput2();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(10, 11)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
simulateInput2();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [MouseButton.LEFT, MouseButton.MIDDLE, MouseButton.RIGHT];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.LEFT_UP, ScreenSpaceEventType.MIDDLE_UP, ScreenSpaceEventType.RIGHT_UP];
|
|
createAllMouseSpecCombinations(testMouseUpEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
describe('handles mouse click', function() {
|
|
function testMouseClickEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
// down, then up
|
|
function simulateInput() {
|
|
simulateMouseDown(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
simulateMouseUp(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// mouse clicks are not fired if the mouse moves too far away from the down position
|
|
action.calls.reset();
|
|
simulateMouseDown(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
simulateMouseUp(element, combine({
|
|
clientX : 10,
|
|
clientY : 11
|
|
}, eventOptions));
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [MouseButton.LEFT, MouseButton.MIDDLE, MouseButton.RIGHT];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.LEFT_CLICK, ScreenSpaceEventType.MIDDLE_CLICK, ScreenSpaceEventType.RIGHT_CLICK];
|
|
createAllMouseSpecCombinations(testMouseClickEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
describe('handles mouse double click', function() {
|
|
function testMouseDoubleClickEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
DomEventSimulator.fireDoubleClick(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [MouseButton.LEFT];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.LEFT_DOUBLE_CLICK];
|
|
createAllMouseSpecCombinations(testMouseDoubleClickEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
describe('handles mouse move', function() {
|
|
function testMouseMoveEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
simulateMouseMove(element, combine({
|
|
clientX : 1,
|
|
clientY : 2
|
|
}, eventOptions));
|
|
simulateMouseMove(element, combine({
|
|
clientX : 2,
|
|
clientY : 3
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(2);
|
|
expect(action).toHaveBeenCalledWith({
|
|
startPosition : new Cartesian2(1, 2),
|
|
endPosition : new Cartesian2(2, 3)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [undefined];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.MOUSE_MOVE];
|
|
createAllMouseSpecCombinations(testMouseMoveEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
describe('handles mouse wheel', function() {
|
|
|
|
if ('onwheel' in document) {
|
|
|
|
describe('using standard wheel event', function() {
|
|
function testWheelEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
DomEventSimulator.fireWheel(element, combine({
|
|
deltaY : 120
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
|
|
// NOTE: currently the action is passed the value of 'wheelDelta' which is inverted from the standard 'deltaY'
|
|
expect(action).toHaveBeenCalledWith(-120);
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [undefined];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.WHEEL];
|
|
createAllMouseSpecCombinations(testWheelEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
} else if (document.onmousewheel !== undefined) {
|
|
|
|
describe('using legacy mousewheel event', function() {
|
|
function testMouseWheelEvent(eventType, modifier, eventOptions) {
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType, modifier);
|
|
|
|
expect(handler.getInputAction(eventType, modifier)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
DomEventSimulator.fireMouseWheel(element, combine({
|
|
wheelDelta : -120
|
|
}, eventOptions));
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith(-120);
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType, modifier);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
}
|
|
|
|
var possibleButtons = [undefined];
|
|
var possibleModifiers = [undefined, KeyboardEventModifier.SHIFT, KeyboardEventModifier.CTRL, KeyboardEventModifier.ALT];
|
|
var possibleEventTypes = [ScreenSpaceEventType.WHEEL];
|
|
createAllMouseSpecCombinations(testMouseWheelEvent, possibleButtons, possibleModifiers, possibleEventTypes);
|
|
});
|
|
|
|
}
|
|
});
|
|
|
|
it('handles touch start', function() {
|
|
var eventType = ScreenSpaceEventType.LEFT_DOWN;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles touch move', function() {
|
|
var eventType = ScreenSpaceEventType.MOUSE_MOVE;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// start, then move
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchMovePosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerMove(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchMovePosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchMove(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchMovePosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
startPosition : new Cartesian2(1, 2),
|
|
endPosition : new Cartesian2(10, 11)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles touch end', function() {
|
|
var eventType = ScreenSpaceEventType.LEFT_UP;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// start, then end
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerUp(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchEnd(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
action.calls.reset();
|
|
|
|
// start, move, then end
|
|
function simulateInput2() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchMovePosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerMove(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchMovePosition));
|
|
DomEventSimulator.firePointerUp(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchMove(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchMovePosition)]
|
|
});
|
|
DomEventSimulator.fireTouchEnd(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput2();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(10, 11)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
simulateInput2();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('treats touch end as touch cancel', function() {
|
|
var eventType = ScreenSpaceEventType.LEFT_UP;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// start, then end
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerCancel(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchCancel(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
action.calls.reset();
|
|
|
|
// start, move, then end
|
|
function simulateInput2() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchMovePosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerMove(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchMovePosition));
|
|
DomEventSimulator.firePointerCancel(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchMove(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchMovePosition)]
|
|
});
|
|
DomEventSimulator.fireTouchCancel(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput2();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(10, 11)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
simulateInput2();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles touch pinch start', function() {
|
|
var eventType = ScreenSpaceEventType.PINCH_START;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// touch 1, then touch 2
|
|
function simulateInput() {
|
|
var touch1StartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touch2StartPosition = {
|
|
clientX : 3,
|
|
clientY : 4
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touch1StartPosition));
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 2
|
|
}, touch2StartPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touch1StartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touch1StartPosition), combine({
|
|
identifier : 1
|
|
}, touch2StartPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position1 : new Cartesian2(1, 2),
|
|
position2 : new Cartesian2(3, 4)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles touch pinch move', function() {
|
|
var eventType = ScreenSpaceEventType.PINCH_MOVE;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// touch 1, then touch 2, then move
|
|
function simulateInput() {
|
|
var touch1StartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touch2StartPosition = {
|
|
clientX : 4,
|
|
clientY : 3
|
|
};
|
|
var touch1MovePosition = {
|
|
clientX : 10,
|
|
clientY : 11
|
|
};
|
|
var touch2MovePosition = {
|
|
clientX : 21,
|
|
clientY : 20
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touch1StartPosition));
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 2
|
|
}, touch2StartPosition));
|
|
DomEventSimulator.firePointerMove(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touch1MovePosition));
|
|
DomEventSimulator.firePointerMove(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 2
|
|
}, touch2MovePosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touch1StartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touch1StartPosition), combine({
|
|
identifier : 1
|
|
}, touch2StartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchMove(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touch1MovePosition), combine({
|
|
identifier : 1
|
|
}, touch2MovePosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
// original delta X: 3
|
|
// original delta Y: 1
|
|
// final delta X: 11
|
|
// final delta Y: 9
|
|
|
|
if (usePointerEvents) {
|
|
// because every pointer event is separate, one touch moves, then the other.
|
|
expect(action.calls.count()).toEqual(2);
|
|
|
|
// intermediate delta X: -6
|
|
// intermediate delta Y: -8
|
|
expect(action).toHaveBeenCalledWith({
|
|
distance : {
|
|
startPosition : new Cartesian2(0, Math.sqrt(3 * 3 + 1 * 1) * 0.25),
|
|
endPosition : new Cartesian2(0, Math.sqrt(-6 * -6 + -8 * -8) * 0.25)
|
|
},
|
|
angleAndHeight : {
|
|
startPosition : new Cartesian2(Math.atan2(1, 3), (3 + 2) * 0.125),
|
|
endPosition : new Cartesian2(Math.atan2(-8, -6), (3 + 11) * 0.125)
|
|
}
|
|
});
|
|
expect(action).toHaveBeenCalledWith({
|
|
distance : {
|
|
startPosition : new Cartesian2(0, Math.sqrt(-6 * -6 + -8 * -8) * 0.25),
|
|
endPosition : new Cartesian2(0, Math.sqrt(11 * 11 + 9 * 9) * 0.25)
|
|
},
|
|
angleAndHeight : {
|
|
startPosition : new Cartesian2(Math.atan2(-8, -6), (3 + 11) * 0.125),
|
|
endPosition : new Cartesian2(Math.atan2(9, 11), (11 + 20) * 0.125)
|
|
}
|
|
});
|
|
} else {
|
|
// touch events can move both touches simultaneously
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
distance : {
|
|
startPosition : new Cartesian2(0, Math.sqrt(3 * 3 + 1 * 1) * 0.25),
|
|
endPosition : new Cartesian2(0, Math.sqrt(11 * 11 + 9 * 9) * 0.25)
|
|
},
|
|
angleAndHeight : {
|
|
startPosition : new Cartesian2(Math.atan2(1, 3), (3 + 2) * 0.125),
|
|
endPosition : new Cartesian2(Math.atan2(9, 11), (11 + 20) * 0.125)
|
|
}
|
|
});
|
|
}
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles touch pinch release', function() {
|
|
var leftDownEventType = ScreenSpaceEventType.LEFT_DOWN;
|
|
var leftDownAction = createCloningSpy('LEFT_DOWN');
|
|
handler.setInputAction(leftDownAction, leftDownEventType);
|
|
|
|
var pinchStartEventType = ScreenSpaceEventType.PINCH_START;
|
|
var pinchStartAction = createCloningSpy('PINCH_START');
|
|
handler.setInputAction(pinchStartAction, pinchStartEventType);
|
|
|
|
var pinchEndEventType = ScreenSpaceEventType.PINCH_END;
|
|
var pinchEndAction = createCloningSpy('PINCH_END');
|
|
handler.setInputAction(pinchEndAction, pinchEndEventType);
|
|
|
|
var touch1Position = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touch2Position = {
|
|
clientX : 4,
|
|
clientY : 3
|
|
};
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine(
|
|
{
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
},
|
|
touch1Position
|
|
));
|
|
DomEventSimulator.firePointerDown(element, combine(
|
|
{
|
|
pointerType : 'touch',
|
|
pointerId : 2
|
|
},
|
|
touch2Position
|
|
));
|
|
|
|
// Releasing one of two fingers should not trigger
|
|
// PINCH_END or LEFT_DOWN:
|
|
leftDownAction.calls.reset();
|
|
DomEventSimulator.firePointerUp(element, combine(
|
|
{
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
},
|
|
touch1Position
|
|
));
|
|
expect(pinchEndAction).not.toHaveBeenCalled();
|
|
expect(leftDownAction).not.toHaveBeenCalled();
|
|
pinchEndAction.calls.reset();
|
|
|
|
// Putting another finger down should not trigger
|
|
// PINCH_START:
|
|
pinchStartAction.calls.reset();
|
|
DomEventSimulator.firePointerDown(element, combine(
|
|
{
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
},
|
|
touch2Position
|
|
));
|
|
expect(pinchStartAction).not.toHaveBeenCalled();
|
|
|
|
// Releasing both fingers should trigger PINCH_END:
|
|
DomEventSimulator.firePointerUp(element, combine(
|
|
{
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
},
|
|
touch2Position
|
|
));
|
|
DomEventSimulator.firePointerUp(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 2
|
|
}, touch2Position));
|
|
expect(pinchEndAction).toHaveBeenCalled();
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [
|
|
combine({ identifier : 0 }, touch1Position),
|
|
combine({ identifier : 1 }, touch2Position)
|
|
]
|
|
});
|
|
leftDownAction.calls.reset();
|
|
|
|
// Releasing one of two fingers should not trigger
|
|
// PINCH_END or LEFT_DOWN:
|
|
DomEventSimulator.fireTouchEnd(element, {
|
|
changedTouches : [
|
|
combine({ identifier : 0 }, touch1Position)
|
|
]
|
|
});
|
|
|
|
expect(pinchEndAction).not.toHaveBeenCalled();
|
|
expect(leftDownAction).not.toHaveBeenCalled();
|
|
|
|
// Releasing both fingers should trigger PINCH_END:
|
|
pinchEndAction.calls.reset();
|
|
DomEventSimulator.fireTouchEnd(element, {
|
|
changedTouches : [
|
|
combine({ identifier : 1 }, touch2Position)
|
|
]
|
|
});
|
|
expect(pinchEndAction).toHaveBeenCalled();
|
|
}
|
|
});
|
|
|
|
it('handles touch click', function() {
|
|
var eventType = ScreenSpaceEventType.LEFT_CLICK;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// start, then end
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerUp(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchEnd(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('treats touch cancel as touch end for touch clicks', function() {
|
|
var eventType = ScreenSpaceEventType.LEFT_CLICK;
|
|
|
|
var action = createCloningSpy('action');
|
|
handler.setInputAction(action, eventType);
|
|
|
|
expect(handler.getInputAction(eventType)).toEqual(action);
|
|
|
|
// start, then end
|
|
function simulateInput() {
|
|
var touchStartPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
var touchEndPosition = {
|
|
clientX : 1,
|
|
clientY : 2
|
|
};
|
|
|
|
if (usePointerEvents) {
|
|
DomEventSimulator.firePointerDown(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchStartPosition));
|
|
DomEventSimulator.firePointerCancel(element, combine({
|
|
pointerType : 'touch',
|
|
pointerId : 1
|
|
}, touchEndPosition));
|
|
} else {
|
|
DomEventSimulator.fireTouchStart(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchStartPosition)]
|
|
});
|
|
DomEventSimulator.fireTouchCancel(element, {
|
|
changedTouches : [combine({
|
|
identifier : 0
|
|
}, touchEndPosition)]
|
|
});
|
|
}
|
|
}
|
|
|
|
simulateInput();
|
|
|
|
expect(action.calls.count()).toEqual(1);
|
|
expect(action).toHaveBeenCalledWith({
|
|
position : new Cartesian2(1, 2)
|
|
});
|
|
|
|
// should not be fired after removal
|
|
action.calls.reset();
|
|
|
|
handler.removeInputAction(eventType);
|
|
|
|
simulateInput();
|
|
|
|
expect(action).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('sets isDestroyed when destroyed', function() {
|
|
expect(handler.isDestroyed()).toEqual(false);
|
|
handler.destroy();
|
|
expect(handler.isDestroyed()).toEqual(true);
|
|
});
|
|
|
|
it('unregisters event listeners when destroyed', function() {
|
|
handler = handler.destroy();
|
|
|
|
spyOn(element, 'addEventListener').and.callThrough();
|
|
spyOn(element, 'removeEventListener').and.callThrough();
|
|
|
|
handler = new ScreenSpaceEventHandler(element);
|
|
|
|
expect(element.addEventListener.calls.count()).not.toEqual(0);
|
|
expect(element.removeEventListener.calls.count()).toEqual(0);
|
|
|
|
handler.destroy();
|
|
|
|
expect(element.removeEventListener.calls.count()).toEqual(element.addEventListener.calls.count());
|
|
});
|
|
});
|