UNPKG

d2js-anim-lib

Version:

Lightweight animation library with support for React, Vue, and Angular

574 lines (560 loc) 25 kB
(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