vevet
Version:
Vevet is a JavaScript library for creative development that simplifies crafting rich interactions like split text animations, carousels, marquees, preloading, and more.
446 lines • 16.7 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwipeCoords = void 0;
var initVevet_1 = require("../../../global/initVevet");
var isFiniteNumber_1 = require("../../../internal/isFiniteNumber");
var unwrapAngle_1 = require("../../../internal/unwrapAngle");
var utils_1 = require("../../../utils");
var START_VEC3 = { x: 0, y: 0, angle: 0 };
var START_STATE = __assign(__assign({}, START_VEC3), { time: 0 });
var SwipeCoords = /** @class */ (function () {
function SwipeCoords(ctx) {
this.ctx = ctx;
/** Event timestamp. */
this._timestamp = 0;
/** Start position. */
this._start = __assign({}, START_STATE);
/** Previous position. */
this._prev = __assign({}, START_STATE);
/** Current position. */
this._current = __assign({}, START_STATE);
/** Movement offset from start. */
this._diff = __assign({}, START_STATE);
/** Movement offset from previous position. */
this._step = __assign({}, START_STATE);
/** Total accumulated movement since swipe start. */
this._accum = __assign({}, START_VEC3);
/** Movement with rubber and snap applied (movement space). */
this._movement = __assign({}, START_VEC3);
/** Previous movement with rubber and snap applied (movement space). */
this._prevMovement = __assign({}, START_VEC3);
/** Raw accumulated displacement (before rubber). */
this._rawMovement = __assign({}, START_VEC3);
/** Raw atan2 angle and unwrapped cumulative angle. */
this._tempAngle = { raw: 0, unwrapped: 0 };
/** Active snap target per axis, if any. */
this._snap = {};
/** Cached normalized bounds (refreshed on swipe start). */
this._bounds = null;
/** Current scale modifier. */
this._scale = 1;
}
Object.defineProperty(SwipeCoords.prototype, "timestamp", {
get: function () {
return this._timestamp;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "start", {
get: function () {
return this._start;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "prev", {
get: function () {
return this._prev;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "current", {
get: function () {
return this._current;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "diff", {
get: function () {
return this._diff;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "step", {
get: function () {
return this._step;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "accum", {
get: function () {
return this._accum;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "movement", {
/** Displacement in movement space (rubber + snap). */
get: function () {
return this._movement;
},
set: function (value) {
var newValue = __assign(__assign({}, this.movement), value);
this._movement.x = newValue.x;
this._movement.y = newValue.y;
this._movement.angle = newValue.angle;
this._rawMovement.x = newValue.x;
this._rawMovement.y = newValue.y;
this._rawMovement.angle = newValue.angle;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "prevMovement", {
/** Previous displacement in movement space (rubber + snap). */
get: function () {
return this._prevMovement;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "rawMovement", {
/** Raw movement before rubber (same space as `bounds`). */
get: function () {
return this._rawMovement;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "bounds", {
/** Normalized movement limits (`[min, max]` per defined axis). */
get: function () {
if (this._bounds) {
return this._bounds;
}
return this.calculateBounds();
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "overflow", {
get: function () {
return this.ctx.props.overflow ? Math.abs(this.ctx.props.overflow()) : 0;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "scale", {
/** Current scale modifier */
get: function () {
return this._scale;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "coords", {
get: function () {
var _a = this, timestamp = _a.timestamp, start = _a.start, prev = _a.prev, current = _a.current, diff = _a.diff, step = _a.step, accum = _a.accum, movement = _a.movement, prevMovement = _a.prevMovement, scale = _a.scale;
return {
timestamp: timestamp,
start: start,
prev: prev,
current: current,
diff: diff,
step: step,
accum: accum,
movement: movement,
prevMovement: prevMovement,
scale: scale,
};
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "snap", {
/** Resolved snap target per axis during the current gesture. */
get: function () {
return this._snap;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SwipeCoords.prototype, "exceeds", {
/**
* Overflow past `bounds` per axis in movement space.
* Zero when inside limits; used for bounce-back.
*/
get: function () {
var _a = this, movement = _a._rawMovement, bounds = _a.bounds;
if (!bounds) {
return null;
}
var xDiff = 0;
var yDiff = 0;
var aDiff = 0;
if (bounds.x) {
if (movement.x < bounds.x[0]) {
xDiff = movement.x - bounds.x[0];
}
else if (movement.x > bounds.x[1]) {
xDiff = movement.x - bounds.x[1];
}
}
if (bounds.y) {
if (movement.y < bounds.y[0]) {
yDiff = movement.y - bounds.y[0];
}
else if (movement.y > bounds.y[1]) {
yDiff = movement.y - bounds.y[1];
}
}
if (bounds.angle) {
if (movement.angle < bounds.angle[0]) {
aDiff = movement.angle - bounds.angle[0];
}
else if (movement.angle > bounds.angle[1]) {
aDiff = movement.angle - bounds.angle[1];
}
}
return {
x: xDiff,
y: yDiff,
angle: aDiff,
};
},
enumerable: false,
configurable: true
});
/** Parses pointer coordinates relative to the container */
SwipeCoords.prototype.decode = function (event) {
var vevet = (0, initVevet_1.initVevet)();
var _a = this.ctx, props = _a.props, container = _a.container;
var clientX = 0;
var clientY = 0;
if ('touches' in event) {
clientX = event.touches[0].clientX;
clientY = event.touches[0].clientY;
}
else if ('type' in event) {
clientX = event.clientX;
clientY = event.clientY;
}
else {
clientX = event.x;
clientY = event.y;
}
var x = clientX;
var y = clientY;
var centerX = vevet.width / 2;
var centerY = vevet.height / 2;
if (props.relative) {
var bounding = container.getBoundingClientRect();
x = clientX - bounding.left;
y = clientY - bounding.top;
centerX = bounding.left + bounding.width / 2;
centerY = bounding.top + bounding.height / 2;
}
var angleRad = Math.atan2(clientY - centerY, clientX - centerX);
var angle = (angleRad * 180) / Math.PI;
return {
x: x,
y: y,
angle: angle,
time: performance.now(),
};
};
/** Apply scale and optionally zoom toward an origin in movement space. */
SwipeCoords.prototype.applyScale = function (value, originProp) {
if (this._scale === value) {
return;
}
if (originProp) {
var origin_1 = this.decode(originProp);
var ratio = value / this._scale;
this.movement = {
x: origin_1.x - (origin_1.x - this._movement.x) * ratio,
y: origin_1.y - (origin_1.y - this._movement.y) * ratio,
};
}
this._scale = value;
};
/** Set start coordinates */
SwipeCoords.prototype.setStart = function (state) {
this._tempAngle = { raw: state.angle, unwrapped: state.angle };
this._timestamp = performance.now();
this._start = __assign({}, state);
this._prev = __assign({}, state);
this._current = __assign({}, state);
this._diff = __assign(__assign({}, START_VEC3), { time: 0 });
this._step = __assign(__assign({}, START_VEC3), { time: 0 });
this._accum = __assign({}, START_VEC3);
};
/** Sync temp angle */
SwipeCoords.prototype.syncTempAngle = function () {
this._tempAngle.raw = this._current.angle;
this._tempAngle.unwrapped = this._current.angle;
};
/** Update coordinates */
SwipeCoords.prototype.update = function (_a, applyRatio) {
var x = _a.x, y = _a.y, angle = _a.angle, time = _a.time;
if (applyRatio === void 0) { applyRatio = true; }
// Vars
var _b = this, start = _b.start, ctx = _b.ctx;
var stepRatio = applyRatio ? ctx.props.ratio : 1;
// Update bounds
if ((ctx.hasInertia() && ctx.recalculateBoundsOnInertia()) ||
!ctx.hasInertia()) {
this.calculateBounds();
}
// Save
this._timestamp = performance.now();
this._prev = __assign({}, this.current);
this._current = { x: x, y: y, angle: angle, time: time };
var _c = this, current = _c._current, prev = _c._prev, overflow = _c.overflow;
// Update angle
this._updateTempAngle(angle);
current.angle = this._tempAngle.unwrapped;
// Update coords
this._step = {
x: current.x - prev.x,
y: current.y - prev.y,
angle: current.angle - prev.angle,
time: current.time - prev.time,
};
this._diff = {
x: current.x - start.x,
y: current.y - start.y,
angle: this._diff.angle + this._step.angle,
time: current.time - start.time,
};
this._accum = {
x: this._accum.x + Math.abs(this._step.x),
y: this._accum.y + Math.abs(this._step.y),
angle: this._accum.angle + Math.abs(this._step.angle),
};
this._rawMovement = {
x: this._rawMovement.x + this._step.x * stepRatio,
y: this._rawMovement.y + this._step.y * stepRatio,
angle: this._rawMovement.angle + this._step.angle * stepRatio,
};
this._prevMovement.x = this._movement.x;
this._prevMovement.y = this._movement.y;
this._prevMovement.angle = this._movement.angle;
this._movement.x = this._applyRubber('x', overflow);
this._movement.y = this._applyRubber('y', overflow);
this._movement.angle = this._applyRubber('angle', overflow);
this._snapMovementAxis('x');
this._snapMovementAxis('y');
this._snapMovementAxis('angle');
};
/** Snap movement axis */
SwipeCoords.prototype._snapMovementAxis = function (axis) {
var _a;
var _b = this.ctx, props = _b.props, hasInertia = _b.hasInertia;
var snap = (_a = props.snap) === null || _a === void 0 ? void 0 : _a.call(props);
if (!snap) {
this._snap[axis] = undefined;
return;
}
var snaps = snap[axis];
if (!(snaps === null || snaps === void 0 ? void 0 : snaps.length)) {
this._snap[axis] = undefined;
return;
}
var value = this._movement[axis];
var target = (0, utils_1.closest)(value, snaps);
var radius = props.snapRadius;
if ((0, isFiniteNumber_1.isFiniteNumber)(radius) && Math.abs(target - value) > Math.abs(radius)) {
this._snap[axis] = undefined;
return;
}
this._snap[axis] = target;
if (!hasInertia()) {
this._movement[axis] = target;
}
};
/** Calculate bounds */
SwipeCoords.prototype.calculateBounds = function () {
var props = this.ctx.props;
if (!props.bounds) {
this._bounds = null;
return;
}
var bounds = props.bounds(this.coords);
var d = [-Infinity, Infinity];
var x = (bounds === null || bounds === void 0 ? void 0 : bounds.x)
? [Math.min.apply(Math, bounds.x), Math.max.apply(Math, bounds.x)]
: __spreadArray([], d, true);
var y = (bounds === null || bounds === void 0 ? void 0 : bounds.y)
? [Math.min.apply(Math, bounds.y), Math.max.apply(Math, bounds.y)]
: __spreadArray([], d, true);
var a = (bounds === null || bounds === void 0 ? void 0 : bounds.angle)
? [Math.min.apply(Math, bounds.angle), Math.max.apply(Math, bounds.angle)]
: __spreadArray([], d, true);
this._bounds = { x: x, y: y, angle: a };
return this._bounds;
};
/** Unwrap raw atan2 angle and accumulate into _angle */
SwipeCoords.prototype._updateTempAngle = function (rawAngle) {
this._tempAngle.unwrapped += (0, unwrapAngle_1.unwrapAngleDelta)(rawAngle, this._tempAngle.raw);
this._tempAngle.raw = rawAngle;
};
/** Apply rubber-band past movement bounds. */
SwipeCoords.prototype._applyRubber = function (axis, overflow) {
var _a;
var temp = this._rawMovement[axis];
var bounds = (_a = this.bounds) === null || _a === void 0 ? void 0 : _a[axis];
if (!bounds) {
return temp;
}
var min = bounds[0], max = bounds[1];
if (temp >= min && temp <= max) {
return temp;
}
if (temp < min) {
return min - this._rubberDistance(min - temp, overflow);
}
return max + this._rubberDistance(temp - max, overflow);
};
/**
* Overscroll → rubber displacement
*/
SwipeCoords.prototype._rubberDistance = function (overscroll, limit) {
if (overscroll <= 0 || limit <= 0) {
return 0;
}
return (limit * overscroll) / (limit + overscroll);
};
return SwipeCoords;
}());
exports.SwipeCoords = SwipeCoords;
//# sourceMappingURL=index.js.map