entangle-doc
Version:
Reactive documents in markdown
201 lines (162 loc) • 5.5 kB
JavaScript
//
// BVTouchable.js
// ExplorableExplanations
//
// Created by Bret Victor on 3/10/11.
// (c) 2011 Bret Victor. MIT open-source license.
//
const { addEvents, removeEvents } = require('./shim')
require('mootools');
var BVTouchable = this.BVTouchable = new Class({
initialize: function (el, delegate) {
this.element = el;
this.delegate = delegate;
this.setTouchable(true);
},
//----------------------------------------------------------------------------------
//
// touches
//
setTouchable: function (isTouchable) {
if (this.touchable === isTouchable) { return; }
this.touchable = isTouchable;
this.element.style.pointerEvents = (this.touchable || this.hoverable) ? "auto" : "none";
if (isTouchable) {
if (!this._mouseBound) {
this._mouseBound = {
mouseDown: this._mouseDown.bind(this),
mouseMove: this._mouseMove.bind(this),
mouseUp: this._mouseUp.bind(this),
touchStart: this._touchStart.bind(this),
touchMove: this._touchMove.bind(this),
touchEnd: this._touchEnd.bind(this),
touchCancel: this._touchCancel.bind(this)
};
}
this.element.addEventListener("mousedown", this._mouseBound.mouseDown);
this.element.addEventListener("touchstart", this._mouseBound.touchStart);
}
else {
this.element.removeEvents("mousedown");
this.element.removeEvents("touchstart");
}
},
touchDidGoDown: function (touches) { this.delegate.touchDidGoDown(touches); },
touchDidMove: function (touches) { this.delegate.touchDidMove(touches); },
touchDidGoUp: function (touches) { this.delegate.touchDidGoUp(touches); },
_mouseDown: function (event) {
event.stopPropagation();
event.preventDefault();
addEvents({
mousemove: this._mouseBound.mouseMove,
mouseup: this._mouseBound.mouseUp
})(document);
this.touches = new BVTouches(event);
this.touchDidGoDown(this.touches);
},
_mouseMove: function (event) {
event.stopPropagation();
event.preventDefault();
this.touches._updateWithEvent(event);
this.touchDidMove(this.touches);
},
_mouseUp: function (event) {
event.stopPropagation();
event.preventDefault();
this.touches._goUpWithEvent(event);
this.touchDidGoUp(this.touches);
delete this.touches;
removeEvents({
mousemove: this._mouseBound.mouseMove,
mouseup: this._mouseBound.mouseUp
})(document);
},
_touchStart: function (event) {
event.stopPropagation();
event.preventDefault();
// if (this.touches || event.length > 1) { this._touchCancel(event); return; } // only-single touch for now
if (this.touches) { this._touchCancel(event); return; }
addEvents({
touchmove: this._mouseBound.touchMove,
touchend: this._mouseBound.touchEnd,
touchcancel: this._mouseBound.touchCancel
})(document);
this.touches = new BVTouches(event);
this.touchDidGoDown(this.touches);
},
_touchMove: function (event) {
event.stopPropagation();
event.preventDefault();
if (!this.touches) { return; }
this.touches._updateWithEvent(event);
this.touchDidMove(this.touches);
},
_touchEnd: function (event) {
event.stopPropagation();
event.preventDefault();
if (!this.touches) { return; }
this.touches._goUpWithEvent(event);
this.touchDidGoUp(this.touches);
delete this.touches;
removeEvents({
touchmove: this._mouseBound.touchMove,
touchend: this._mouseBound.touchEnd,
touchcancel: this._mouseBound.touchCancel
})(document);
},
_touchCancel: function (event) {
this._touchEnd(event);
}
});
//====================================================================================
//
// BVTouches
//
var BVTouches = this.BVTouches = new Class({
initialize: function (event) {
this.globalPoint = { x:event.clientX, y:-event.clientY };
this.translation = { x:0, y:0 };
this.deltaTranslation = { x:0, y:0 };
this.velocity = { x:0, y:0 };
this.count = 1;
this.event = event;
this.timestamp = Date.now();
this.downTimestamp = this.timestamp;
},
_updateWithEvent: function (event, isRemoving) {
this.event = event;
if (!isRemoving) {
var dx = event.clientX - this.globalPoint.x; // todo, transform to local coordinate space?
var dy = -event.clientY - this.globalPoint.y;
this.translation.x += dx;
this.translation.y += dy;
this.deltaTranslation.x += dx;
this.deltaTranslation.y += dy;
this.globalPoint.x = event.clientX;
this.globalPoint.y = -event.clientY;
}
var timestamp = Date.now();
var dt = timestamp - this.timestamp;
var isSamePoint = isRemoving || (dx === 0 && dy === 0);
var isStopped = (isSamePoint && dt > 150);
this.velocity.x = isStopped ? 0 : (isSamePoint || dt === 0) ? this.velocity.x : (dx / dt * 1000);
this.velocity.y = isStopped ? 0 : (isSamePoint || dt === 0) ? this.velocity.y : (dy / dt * 1000);
this.timestamp = timestamp;
},
_goUpWithEvent: function (event) {
this._updateWithEvent(event, true);
this.count = 0;
var didMove = Math.abs(this.translation.x) > 10 || Math.abs(this.translation.y) > 10;
var wasMoving = Math.abs(this.velocity.x) > 400 || Math.abs(this.velocity.y) > 400;
this.wasTap = !didMove && !wasMoving && (this.getTimeSinceGoingDown() < 300);
},
getTimeSinceGoingDown: function () {
return this.timestamp - this.downTimestamp;
},
resetDeltaTranslation: function () {
this.deltaTranslation.x = 0;
this.deltaTranslation.y = 0;
}
});
//====================================================================================
module.exports = BVTouchable