d2js-anim-lib
Version:
Lightweight animation library with support for React, Vue, and Angular
574 lines (560 loc) • 25 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :
typeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.D2js = {}, global.ng.core));
})(this, (function (exports, core) { 'use strict';
// Core animations and utilities
// Animation types that the library supports
exports.AnimationType = void 0;
(function (AnimationType) {
AnimationType["ROTATE"] = "rotate";
AnimationType["BOUNCE"] = "bounce";
AnimationType["DRAG"] = "drag";
})(exports.AnimationType || (exports.AnimationType = {}));
// Main animation controller
var AnimationController = /** @class */ (function () {
function AnimationController(element) {
this.element = null;
if (element) {
this.element = element;
}
}
AnimationController.prototype.setElement = function (element) {
this.element = element;
return this;
};
// Rotation animation
AnimationController.prototype.rotate = function (options) {
var _this = this;
if (options === void 0) { options = {}; }
if (!this.element)
return;
var _a = options.degrees, degrees = _a === void 0 ? 360 : _a, _b = options.duration, duration = _b === void 0 ? 1000 : _b, _c = options.easing, easing = _c === void 0 ? 'ease-in-out' : _c, _d = options.delay, delay = _d === void 0 ? 0 : _d, _e = options.iterations, iterations = _e === void 0 ? 1 : _e, _f = options.direction, direction = _f === void 0 ? 'clockwise' : _f;
var rotationDegrees = direction === 'clockwise' ? degrees : -degrees;
this.element.style.transition = "transform ".concat(duration, "ms ").concat(easing, " ").concat(delay, "ms");
this.element.style.transform = "rotate(".concat(rotationDegrees, "deg)");
// Reset after animation completes if it's not infinite
if (iterations !== Infinity) {
setTimeout(function () {
if (_this.element) {
_this.element.style.transition = '';
_this.element.style.transform = '';
}
}, duration + delay);
}
};
// Bounce animation
AnimationController.prototype.bounce = function (options) {
var _this = this;
if (options === void 0) { options = {}; }
if (!this.element)
return;
var _a = options.intensity, intensity = _a === void 0 ? 20 : _a, _b = options.duration, duration = _b === void 0 ? 500 : _b, _c = options.easing, easing = _c === void 0 ? 'cubic-bezier(0.68, -0.55, 0.27, 1.55)' : _c, _d = options.delay, delay = _d === void 0 ? 0 : _d; options.iterations; var _f = options.direction, direction = _f === void 0 ? 'up' : _f;
// Save original styles
var originalTransition = this.element.style.transition;
var originalTransform = this.element.style.transform;
// Set initial position
this.element.style.transition = "transform ".concat(duration / 2, "ms ").concat(easing, " ").concat(delay, "ms");
// Direction-based transform
var transform;
switch (direction) {
case 'up':
transform = "translateY(-".concat(intensity, "px)");
break;
case 'down':
transform = "translateY(".concat(intensity, "px)");
break;
case 'left':
transform = "translateX(-".concat(intensity, "px)");
break;
case 'right':
transform = "translateX(".concat(intensity, "px)");
break;
default:
transform = "translateY(-".concat(intensity, "px)");
}
this.element.style.transform = transform;
// Return to original position
setTimeout(function () {
if (_this.element) {
_this.element.style.transition = "transform ".concat(duration / 2, "ms ").concat(easing);
_this.element.style.transform = originalTransform;
}
}, duration / 2 + delay);
// Reset after animation completes
setTimeout(function () {
if (_this.element) {
_this.element.style.transition = originalTransition;
}
}, duration + delay);
};
// Drag effect within bounds
AnimationController.prototype.enableDrag = function (options) {
var _this = this;
if (options === void 0) { options = {}; }
if (!this.element)
return;
var _a = options.bounds, bounds = _a === void 0 ? {} : _a, _b = options.axis, axis = _b === void 0 ? 'both' : _b, _c = options.returnToOrigin, returnToOrigin = _c === void 0 ? true : _c;
var originalPosition = {
x: 0,
y: 0
};
var isDragging = false;
var startX = 0;
var startY = 0;
var offsetX = 0;
var offsetY = 0;
var onMouseDown = function (e) {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
// Calculate current transform position
var transform = window.getComputedStyle(_this.element).transform;
if (transform && transform !== 'none') {
var matrix = new DOMMatrix(transform);
offsetX = matrix.e;
offsetY = matrix.f;
}
else {
offsetX = 0;
offsetY = 0;
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
e.preventDefault();
};
var onMouseMove = function (e) {
if (!isDragging || !_this.element)
return;
var dx = e.clientX - startX;
var dy = e.clientY - startY;
// Apply axis constraints
if (axis === 'x')
dy = 0;
if (axis === 'y')
dx = 0;
// Apply bounds constraints
var newX = offsetX + dx;
var newY = offsetY + dy;
if (bounds.left !== undefined && newX < bounds.left)
dx = bounds.left - offsetX;
if (bounds.right !== undefined && newX > bounds.right)
dx = bounds.right - offsetX;
if (bounds.top !== undefined && newY < bounds.top)
dy = bounds.top - offsetY;
if (bounds.bottom !== undefined && newY > bounds.bottom)
dy = bounds.bottom - offsetY;
// Apply transform
_this.element.style.transform = "translate(".concat(offsetX + dx, "px, ").concat(offsetY + dy, "px)");
};
var onMouseUp = function () {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
// Return to original position if enabled
if (returnToOrigin && _this.element) {
_this.element.style.transition = 'transform 0.3s ease-out';
_this.element.style.transform = "translate(".concat(originalPosition.x, "px, ").concat(originalPosition.y, "px)");
// Remove transition after it completes
setTimeout(function () {
if (_this.element) {
_this.element.style.transition = '';
}
}, 300);
}
};
// Clean up any previous listeners
this.disableDrag();
// Add new listeners
this.element.addEventListener('mousedown', onMouseDown);
// Store the mouse down handler for later cleanup
this.element.__dragMouseDownHandler = onMouseDown;
};
// Disable drag functionality
AnimationController.prototype.disableDrag = function () {
if (!this.element)
return;
var mouseDownHandler = this.element.__dragMouseDownHandler;
if (mouseDownHandler) {
this.element.removeEventListener('mousedown', mouseDownHandler);
delete this.element.__dragMouseDownHandler;
}
};
return AnimationController;
}());
// Factory function to create an animation controller
function createAnimationController(element) {
return new AnimationController(element);
}
function useReactAnimations() {
return {
rotate: function (el, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(el);
controller.rotate(options);
},
bounce: function (el, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(el);
controller.bounce(options);
},
enableDrag: function (el, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(el);
controller.enableDrag(options);
return function () { return controller.disableDrag(); };
}
};
}
// Create a Vue directive for animations
var vAnimate = {
mounted: function (el, binding) {
// Setup animation controller
var controller = new AnimationController(el);
// Store controller in element
el.__animationController = controller;
// Setup animations
setupAnimations(el, binding);
},
updated: function (el, binding) {
// Update animations when directive value changes
setupAnimations(el, binding);
},
unmounted: function (el) {
// Clean up
var controller = el.__animationController;
if (controller) {
controller.disableDrag();
delete el.__animationController;
}
}
};
// Helper to setup animations based on binding
function setupAnimations(el, binding) {
// Get animation controller
var controller = el.__animationController;
if (!controller)
return;
var value = binding.value || {};
// Handle rotation
if (value.rotate) {
var rotateOptions_1 = value.rotate;
// Apply rotation on mount if specified
if (rotateOptions_1.trigger === 'mount' && !el.__hasRotated) {
controller.rotate(rotateOptions_1);
el.__hasRotated = true;
}
// Setup click handler for rotation
if (rotateOptions_1.trigger === 'click') {
// Remove existing handler if any
if (el.__rotateClickHandler) {
el.removeEventListener('click', el.__rotateClickHandler);
}
// Create and store new handler
var clickHandler = function () { return controller.rotate(rotateOptions_1); };
el.__rotateClickHandler = clickHandler;
el.addEventListener('click', clickHandler);
}
// Setup hover handlers for rotation
if (rotateOptions_1.trigger === 'hover') {
// Remove existing handlers if any
if (el.__rotateHoverHandler) {
el.removeEventListener('mouseenter', el.__rotateHoverHandler);
}
// Create and store new handler
var hoverHandler = function () { return controller.rotate(rotateOptions_1); };
el.__rotateHoverHandler = hoverHandler;
el.addEventListener('mouseenter', hoverHandler);
}
}
// Handle bounce
if (value.bounce) {
var bounceOptions_1 = value.bounce;
// Apply bounce on mount if specified
if (bounceOptions_1.trigger === 'mount' && !el.__hasBounced) {
controller.bounce(bounceOptions_1);
el.__hasBounced = true;
}
// Setup click handler for bounce
if (bounceOptions_1.trigger === 'click') {
// Remove existing handler if any
if (el.__bounceClickHandler) {
el.removeEventListener('click', el.__bounceClickHandler);
}
// Create and store new handler
var clickHandler = function () { return controller.bounce(bounceOptions_1); };
el.__bounceClickHandler = clickHandler;
el.addEventListener('click', clickHandler);
}
// Setup hover handlers for bounce
if (bounceOptions_1.trigger === 'hover') {
// Remove existing handlers if any
if (el.__bounceHoverHandler) {
el.removeEventListener('mouseenter', el.__bounceHoverHandler);
}
// Create and store new handler
var hoverHandler = function () { return controller.bounce(bounceOptions_1); };
el.__bounceHoverHandler = hoverHandler;
el.addEventListener('mouseenter', hoverHandler);
}
}
// Handle drag
if (value.drag) {
controller.enableDrag(value.drag);
// Set position to relative if not already set
if (window.getComputedStyle(el).position === 'static') {
el.style.position = 'relative';
}
}
else {
controller.disableDrag();
}
}
// Vue composable for using animations in Vue components
function useAnimations() {
var createController = function (element) {
return new AnimationController(element);
};
return {
rotate: function (el, options) {
if (options === void 0) { options = {}; }
var controller = createController(el);
controller.rotate(options);
},
bounce: function (el, options) {
if (options === void 0) { options = {}; }
var controller = createController(el);
controller.bounce(options);
},
enableDrag: function (el, options) {
if (options === void 0) { options = {}; }
var controller = createController(el);
controller.enableDrag(options);
return function () { return controller.disableDrag(); };
}
};
}
// Plugin for Vue
var D2jsPlugin = {
install: function (app) {
app.directive('animate', vAnimate);
}
};
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __metadata(metadataKey, metadataValue) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
// Rotation directive
var RotateDirective = /** @class */ (function () {
function RotateDirective(el) {
this.el = el;
this.options = {};
this.trigger = 'click';
this.controller = new AnimationController(el.nativeElement);
}
RotateDirective.prototype.ngOnInit = function () {
if (this.trigger === 'mount') {
this.controller.rotate(this.options);
}
};
RotateDirective.prototype.onClick = function () {
if (this.trigger === 'click') {
this.controller.rotate(this.options);
}
};
RotateDirective.prototype.onMouseEnter = function () {
if (this.trigger === 'hover') {
this.controller.rotate(this.options);
}
};
RotateDirective.prototype.ngOnDestroy = function () {
// No cleanup needed for rotation
};
__decorate([
core.Input('d2jsRotate'),
__metadata("design:type", Object)
], RotateDirective.prototype, "options", void 0);
__decorate([
core.Input(),
__metadata("design:type", String)
], RotateDirective.prototype, "trigger", void 0);
__decorate([
core.HostListener('click'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], RotateDirective.prototype, "onClick", null);
__decorate([
core.HostListener('mouseenter'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], RotateDirective.prototype, "onMouseEnter", null);
RotateDirective = __decorate([
core.Directive({
selector: '[d2jsRotate]'
}),
__metadata("design:paramtypes", [core.ElementRef])
], RotateDirective);
return RotateDirective;
}());
// Bounce directive
var BounceDirective = /** @class */ (function () {
function BounceDirective(el) {
this.el = el;
this.options = {};
this.trigger = 'click';
this.controller = new AnimationController(el.nativeElement);
}
BounceDirective.prototype.ngOnInit = function () {
if (this.trigger === 'mount') {
this.controller.bounce(this.options);
}
};
BounceDirective.prototype.onClick = function () {
if (this.trigger === 'click') {
this.controller.bounce(this.options);
}
};
BounceDirective.prototype.onMouseEnter = function () {
if (this.trigger === 'hover') {
this.controller.bounce(this.options);
}
};
BounceDirective.prototype.ngOnDestroy = function () {
// No cleanup needed for bounce
};
__decorate([
core.Input('d2jsBounce'),
__metadata("design:type", Object)
], BounceDirective.prototype, "options", void 0);
__decorate([
core.Input(),
__metadata("design:type", String)
], BounceDirective.prototype, "trigger", void 0);
__decorate([
core.HostListener('click'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], BounceDirective.prototype, "onClick", null);
__decorate([
core.HostListener('mouseenter'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], BounceDirective.prototype, "onMouseEnter", null);
BounceDirective = __decorate([
core.Directive({
selector: '[d2jsBounce]'
}),
__metadata("design:paramtypes", [core.ElementRef])
], BounceDirective);
return BounceDirective;
}());
// Drag directive
var DragDirective = /** @class */ (function () {
function DragDirective(el) {
this.el = el;
this.options = {};
this.controller = new AnimationController(el.nativeElement);
}
DragDirective.prototype.ngOnInit = function () {
// Set position to relative if not already set
var element = this.el.nativeElement;
if (window.getComputedStyle(element).position === 'static') {
element.style.position = 'relative';
}
this.controller.enableDrag(this.options);
};
DragDirective.prototype.ngOnDestroy = function () {
this.controller.disableDrag();
};
__decorate([
core.Input('d2jsDrag'),
__metadata("design:type", Object)
], DragDirective.prototype, "options", void 0);
DragDirective = __decorate([
core.Directive({
selector: '[d2jsDrag]'
}),
__metadata("design:paramtypes", [core.ElementRef])
], DragDirective);
return DragDirective;
}());
// Animation service for Angular
var D2jsService = /** @class */ (function () {
function D2jsService() {
}
D2jsService.prototype.rotate = function (element, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(element);
controller.rotate(options);
};
D2jsService.prototype.bounce = function (element, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(element);
controller.bounce(options);
};
D2jsService.prototype.enableDrag = function (element, options) {
if (options === void 0) { options = {}; }
var controller = new AnimationController(element);
controller.enableDrag(options);
// Return disable function
return function () { return controller.disableDrag(); };
};
D2jsService = __decorate([
core.Injectable({
providedIn: 'root'
})
], D2jsService);
return D2jsService;
}());
// Module for Angular
var D2jsModule = /** @class */ (function () {
function D2jsModule() {
}
D2jsModule = __decorate([
core.NgModule({
declarations: [RotateDirective, BounceDirective, DragDirective],
exports: [RotateDirective, BounceDirective, DragDirective],
providers: [D2jsService]
})
], D2jsModule);
return D2jsModule;
}());
exports.AnimationController = AnimationController;
exports.BounceDirective = BounceDirective;
exports.D2jsModule = D2jsModule;
exports.D2jsPlugin = D2jsPlugin;
exports.D2jsService = D2jsService;
exports.DragDirective = DragDirective;
exports.RotateDirective = RotateDirective;
exports.createAnimationController = createAnimationController;
exports.useAnimations = useAnimations;
exports.useReactAnimations = useReactAnimations;
exports.vAnimate = vAnimate;
}));
//# sourceMappingURL=index.umd.js.map