rxjs-gestures
Version:
A library for reacting to future user input.
183 lines (160 loc) • 7.24 kB
JavaScript
import { Point } from '../support';
import { Subscriber } from 'rxjs/Subscriber';
export class NormalizeOperator {
constructor(origin, Gestures, scheduler) {
this.origin = origin || undefined;
this.Gestures = Gestures;
this.scheduler = scheduler;
}
call(subscriber, source) {
return source.subscribe(new NormalizeSubscriber(subscriber, this.origin, this.Gestures, this.scheduler));
}
}
export class NormalizeSubscriber extends Subscriber {
constructor(subscriber, origin, Gestures, scheduler) {
super(subscriber);
this.origin = origin;
this.previous = origin;
this.Gestures = Gestures;
this.scheduler = scheduler;
this.sampleX = 0;
this.sampleY = 0;
this.sampleT = scheduler.now();
}
_next(multitouchEvent) {
if (multitouchEvent instanceof Point) {
return super._next(this.previous = multitouchEvent);
}
const time = this.scheduler.now();
let { origin, lastWindowTime } = this;
const { type, index, event, touch, target, screenX, screenY,
pageX, pageY, clientX, clientY, deltaX, deltaY, deltaZ,
button, buttons, radiusX = 1, radiusY = 1, rotationAngle = 0 } = multitouchEvent;
if (!origin) {
this.origin = origin = NormalizeSubscriber.createOrigin(
multitouchEvent, touch, time, this.Gestures
);
}
const { previous = origin } = this;
const { pageX: prevX, pageY: prevY } = previous;
const movementX = pageX - prevX;
const movementY = pageY - prevY;
const movementT = time - previous.time;
const movementXTotal = movementX + previous.movementXTotal;
const movementYTotal = movementY + previous.movementYTotal;
const movementTTotal = movementT + previous.movementTTotal;
const sampleTTotal = time - this.sampleT;
const sampleXTotal = pageX - this.sampleX;
const sampleYTotal = pageY - this.sampleY;
if (sampleTTotal >= 100) {
this.sampleT = time;
this.sampleX = pageX;
this.sampleY = pageY;
}
const distance = Math.sqrt(sampleXTotal * sampleXTotal + sampleYTotal * sampleYTotal) || 0;
const speed = Math.sqrt((distance / (sampleTTotal || 1)) / 5) || 0;
const direction = Math.atan2(movementY / movementT, movementX / movementT) || 0;
const point = origin.clone();
point.type = type;
point.time = time;
point.index = index;
point.touch = touch;
point.event = event;
point.pageX = pageX;
point.pageY = pageY;
point.button = button;
point.buttons = buttons;
point.movementT = movementT;
point.movementX = movementX;
point.movementY = movementY;
point.deltaX = deltaX;
point.deltaY = deltaY;
point.deltaZ = deltaZ;
point.clientX = clientX;
point.clientY = clientY;
point.screenX = screenX;
point.screenY = screenY;
point.radiusX = radiusX;
point.radiusY = radiusY;
point.speed = speed;
point.direction = direction;
point.rotationAngle = rotationAngle;
point.movementXTotal = movementXTotal;
point.movementYTotal = movementYTotal;
point.movementTTotal = movementTTotal;
point.x += movementXTotal;
point.y += movementYTotal;
point.targetX += movementXTotal;
point.targetY += movementYTotal;
point.targetPageX += movementXTotal;
point.targetPageY += movementYTotal;
point.targetClientX += movementXTotal;
point.targetClientY += movementYTotal;
point.targetScreenX += movementXTotal;
point.targetScreenY += movementYTotal;
super._next(this.previous = point);
}
static createOrigin(event, touch, time, Gestures) {
const { identifier } = touch;
const { topLevelElement } = Gestures;
const { type, target, pageX, pageY,
clientX, clientY, screenX, screenY,
radiusX = 1, radiusY = 1, rotationAngle = 0 } = event;
const { scrollTop, scrollLeft } = target;
const parent = target.offsetParent || target.parentNode || topLevelElement;
const { top: targetTop, left: targetLeft,
right: targetRight, bottom: targetBottom } = target.getBoundingClientRect();
const { top: parentTop, left: parentLeft,
right: parentRight, bottom: parentBottom } = parent.getBoundingClientRect();
let { offsetLeft, offsetTop } = target;
('ownerSVGElement' in target) && (
{ x: offsetLeft, y: offsetTop } = target.getBBox());
const x = clientX - targetLeft - scrollLeft;
const y = clientY - targetTop - scrollTop;
const targetPageX = targetLeft - scrollLeft + topLevelElement.pageXOffset;
const targetPageY = targetTop - scrollTop + topLevelElement.pageYOffset;
const targetX = targetLeft - parentLeft - offsetLeft - scrollLeft;
const targetY = targetTop - parentTop - offsetTop - scrollTop;
const targetClientX = targetLeft - scrollLeft;
const targetClientY = targetTop - scrollTop;
const targetScreenX = (screenX - clientX) + targetLeft - scrollLeft;
const targetScreenY = (screenY - clientY) + targetTop - scrollTop;
const origin = new Point(time, null, null, target, identifier,
radiusX, radiusY, rotationAngle,
x, y,
pageX, pageY,
clientX, clientY,
screenX, screenY,
targetX, targetY,
targetPageX, targetPageY,
targetClientX, targetClientY,
targetScreenX, targetScreenY);
origin.type = type;
origin.origin = origin;
origin.xOrigin = origin.x;
origin.yOrigin = origin.y;
origin.targetTop = targetTop;
origin.targetLeft = targetLeft;
origin.targetRight = targetRight;
origin.targetBottom = targetBottom;
origin.parentTop = parentTop;
origin.parentLeft = parentLeft;
origin.parentRight = parentRight;
origin.parentBottom = parentBottom;
origin.pageXOrigin = origin.pageX;
origin.pageYOrigin = origin.pageY;
origin.clientXOrigin = origin.clientX;
origin.clientYOrigin = origin.clientY;
origin.screenXOrigin = origin.screenX;
origin.screenYOrigin = origin.screenY;
origin.targetXOrigin = origin.targetX;
origin.targetYOrigin = origin.targetY;
origin.targetPageXOrigin = origin.targetPageX;
origin.targetPageYOrigin = origin.targetPageY;
origin.targetClientXOrigin = origin.targetClientX;
origin.targetClientYOrigin = origin.targetClientY;
origin.targetScreenXOrigin = origin.targetScreenX;
origin.targetScreenYOrigin = origin.targetScreenY;
return origin;
}
}