Comparing version 0.4.4 to 0.5.1
@@ -1,262 +0,281 @@ | ||
var EasingFactory = require("./ease"), | ||
Helper = require("./helper"), | ||
Constants = require("./constants"); | ||
/* @flow */ | ||
/* global __DEV__ */ | ||
import Animation from './animation'; | ||
import Attribute from './attribute'; | ||
import Element from './element'; | ||
var Animar = function() { | ||
this.elementMap = new Map(); | ||
this.ticking = false; | ||
if (__DEV__) { | ||
var Helpers = require('./helpers'); | ||
var getStartValue = Helpers.getStartValue; | ||
} | ||
type ElementMap = Map<HTMLElement, Element>; | ||
type AnimationOptions = { // user-provided so can't assume correct type or existance | ||
delay: ?any, | ||
easingFunction: ?any, | ||
duration: ?any, | ||
loop: ?any | ||
}; | ||
type AttributesOptions = { [key: string]: number | Array<number> }; | ||
type ChainOptions = { | ||
delay: number, | ||
currentDuration: number, | ||
totalDuration: number | ||
} | ||
type FullChainObject = { | ||
start: Function, | ||
loop: Function, | ||
add: Function, | ||
then: Function | ||
}; | ||
type ThenChainObject = { | ||
add: Function | ||
}; | ||
type LoopChainObject = { | ||
start: Function | ||
} | ||
type AddChainObject = FullChainObject; | ||
Animar.prototype.add = function(element, attributes, options) { | ||
return this._add(element, attributes, options, { delay: 0, currentDuration: 0, totalDuration: 0, animationList: [] }); | ||
const EMPTY_ANIMATION_OPTIONS = { | ||
delay: null, | ||
easingFunction: null, | ||
duration: null, | ||
loop: null | ||
}; | ||
Animar.prototype._add = function(element, attributes, options, chainOptions) { | ||
var self = this; | ||
module.exports = class Animar { | ||
ticking: boolean; | ||
elementMap: ElementMap; | ||
defaults: { delay: number, easingFunction: Function, duration: number, loop: boolean }; | ||
timescale: number; | ||
// manage options defaults | ||
options = options || {}; | ||
options.delay = options.delay || 0; | ||
options.easing = options.easing || 'linear'; | ||
constructor() { | ||
this.ticking = false; | ||
this.elementMap = new Map(); | ||
this.defaults = { | ||
delay: 0, | ||
easingFunction: (t, b, c, d) => { return c * t / d + b; }, // linear easing function | ||
duration: 60, | ||
loop: false | ||
}; | ||
this.timescale = 1; | ||
} | ||
options.easing = typeof options.easing === 'string' ? EasingFactory[options.easing]() : options.easing; | ||
add(element: HTMLElement, attributes: AttributesOptions, options: AnimationOptions): FullChainObject { | ||
let resolvedOptions = options == null ? EMPTY_ANIMATION_OPTIONS : options; | ||
options.duration = options.duration || 60; | ||
options.loop = options.loop || false; | ||
if (__DEV__) { | ||
if (element == null) { | ||
throw 'Missing or null parameter: element'; | ||
} | ||
if (!element instanceof HTMLElement) { | ||
throw "Parameter 'element' should be of type HTMLElement"; | ||
} | ||
if (typeof attributes === 'undefined') { | ||
throw 'Missing or null parameter: attribtues'; | ||
} | ||
if (typeof attributes !== 'object') { | ||
throw "Parameter 'attributes' should be of type Object"; | ||
} | ||
// TODO: Validate attributes contents | ||
} | ||
for (var attribute in attributes) { | ||
/* istanbul ignore else */ | ||
if (attributes.hasOwnProperty(attribute)) { | ||
var start, destination; | ||
var attributeValue = attributes[attribute]; | ||
return this._add( | ||
element, | ||
attributes, | ||
resolvedOptions, | ||
{ | ||
delay: 0, | ||
currentDuration: 0, | ||
totalDuration: 0 | ||
}, | ||
new Map() | ||
); | ||
} | ||
if (typeof attributeValue === 'number') { | ||
destination = attributeValue; | ||
mergeElementMaps(src: ElementMap, target: ElementMap): ElementMap { | ||
let result = new Map(src); | ||
target.forEach((element, elementRef) => { | ||
let mergedElement; | ||
if (result.has(elementRef)) { | ||
mergedElement = result.get(elementRef).merge(element); | ||
} else { | ||
start = attributeValue[0]; | ||
destination = attributeValue[1]; | ||
mergedElement = element; | ||
} | ||
result.set(elementRef, mergedElement); | ||
}); | ||
var attrOptions = { | ||
start: start, | ||
duration: options.duration, | ||
easing: options.easing, | ||
delay: options.delay + chainOptions.delay, | ||
loop: options.loop, | ||
wait: 0 | ||
}; | ||
return result; | ||
} | ||
var currentAnimation = this._addAnimation(element, attribute, destination, attrOptions); | ||
chainOptions.animationList.push(currentAnimation); | ||
resolveStartValue(start: ?number, element: HTMLElement, attribute: string, currentChain: ElementMap): ?number { | ||
if (currentChain.has(element) && currentChain.get(element).hasAttribute(attribute)) { | ||
start = currentChain.get(element).getModelFromAttribute(attribute); | ||
} else if (this.elementMap.has(element) && this.elementMap.get(element).hasAttribute(attribute)) { | ||
start = this.elementMap.get(element).getModelFromAttribute(attribute); | ||
} else { | ||
if (__DEV__) { | ||
start = getStartValue(element, attribute); | ||
} | ||
} | ||
return start; | ||
} | ||
chainOptions.currentDuration = Math.max(chainOptions.currentDuration, options.delay + options.duration); | ||
_add(element: HTMLElement, | ||
attributes: { [key: string]: number | Array<number> }, | ||
options: AnimationOptions, | ||
chainOptions: ChainOptions, | ||
currentChain: ElementMap): FullChainObject | ||
{ | ||
const resolvedOptions = { | ||
delay: options.delay == null ? | ||
this.defaults.delay : options.delay, | ||
easingFunction: options.easingFunction == null ? | ||
this.defaults.easingFunction : options.easingFunction, | ||
duration: options.duration == null ? | ||
this.defaults.duration : options.duration, | ||
loop: options.loop == null ? | ||
this.defaults.loop : options.loop | ||
}; | ||
return this._chainFunctions(chainOptions); | ||
}; | ||
for (const attribute in attributes) { | ||
if (attributes.hasOwnProperty(attribute)) { | ||
const attributeValue = attributes[attribute]; | ||
let start, destination; | ||
Animar.prototype._chainFunctions = function(chainOptions) { | ||
return { | ||
and: this._andChainFunction(chainOptions), | ||
then: this._thenChainFunction(chainOptions), | ||
loop: this._loopChainFunction(chainOptions), | ||
wait: this._waitChainFunction(chainOptions) | ||
}; | ||
}; | ||
if (typeof attributeValue === 'number') { | ||
destination = attributeValue; | ||
} else { | ||
start = attributeValue[0]; | ||
destination = attributeValue[1]; | ||
} | ||
Animar.prototype._andChainFunction = function(chainOptions) { | ||
var self = this; | ||
return function(element, attributes, options) { | ||
return self._add(element, attributes, options, chainOptions); | ||
}; | ||
}; | ||
start = this.resolveStartValue(start, element, attribute, currentChain); | ||
Animar.prototype._thenChainFunction = function(chainOptions) { | ||
var self = this; | ||
return function(element, attributes, options) { | ||
chainOptions.totalDuration = chainOptions.totalDuration + chainOptions.currentDuration; | ||
chainOptions.currentDuration = 0; | ||
chainOptions.delay = chainOptions.totalDuration; | ||
return self._add(element, attributes, options, chainOptions); | ||
}; | ||
}; | ||
if (start == null) { | ||
throw 'Animation start value is not provided and cannot be infered'; | ||
} else { | ||
start -= destination; | ||
let newAnimation = new Animation( | ||
0 - (resolvedOptions.delay + chainOptions.delay), | ||
start, | ||
0 - start, | ||
resolvedOptions.duration, | ||
resolvedOptions.easingFunction, | ||
resolvedOptions.loop, | ||
resolvedOptions.delay + chainOptions.delay, | ||
0 | ||
); | ||
Animar.prototype._loopChainFunction = function(chainOptions) { | ||
var self = this; | ||
return function() { | ||
chainOptions.totalDuration = chainOptions.totalDuration + chainOptions.currentDuration; | ||
for (var i = 0; i < chainOptions.animationList.length; i++) { | ||
var anim = chainOptions.animationList[i]; | ||
anim.loop = true; | ||
anim.wait = chainOptions.totalDuration - anim.delay - anim.totalIterations; | ||
} | ||
self._requestTick(); | ||
}; | ||
}; | ||
let newAttribute = new Attribute(attribute, destination); | ||
newAttribute.addAnimation(newAnimation); | ||
Animar.prototype._waitChainFunction = function(chainOptions) { | ||
var self = this; | ||
return function(numFrames) { | ||
chainOptions.totalDuration = chainOptions.totalDuration + chainOptions.currentDuration + numFrames; | ||
chainOptions.currentDuration = 0; | ||
chainOptions.delay = chainOptions.totalDuration; | ||
return self._chainFunctions(chainOptions); | ||
}; | ||
}; | ||
let newElement = new Element(element); | ||
newElement.addAttribute(attribute, newAttribute); | ||
Animar.prototype._addAnimation = function(element, attribute, destination, options) { | ||
var newAnimation = { | ||
element: element, | ||
attribute: attribute, | ||
start: options.start, | ||
destination: destination, | ||
duration: options.duration, | ||
ease: options.easing, | ||
delay: options.delay, | ||
loop: options.loop, | ||
wait: options.wait | ||
}; | ||
var currentAnimation = this._addAnimationToMap(newAnimation); | ||
this._requestTick(); | ||
return currentAnimation; | ||
}; | ||
let tempEMap = new Map(); | ||
tempEMap.set(element, newElement); | ||
Animar.prototype._addAnimationToMap = function(args) { | ||
if (!this.elementMap.has(args.element)) { | ||
this.elementMap.set(args.element, new Map()); | ||
currentChain = this.mergeElementMaps(currentChain, tempEMap); | ||
} | ||
} | ||
} | ||
chainOptions.currentDuration = Math.max(chainOptions.currentDuration, resolvedOptions.delay + resolvedOptions.duration); | ||
return this.fullChainObjectFactory(chainOptions, currentChain); | ||
} | ||
return this._addAnimationToElement(this.elementMap.get(args.element), args); | ||
}; | ||
fullChainObjectFactory(chainOptions: ChainOptions, chain: ElementMap): FullChainObject { | ||
return { | ||
start: this.startChainFunctionFactory(chain), | ||
loop: this.loopChainFunctionFactory(chainOptions, chain), | ||
add: this.addChainFunctionFactory(chainOptions, chain), | ||
then: this.thenChainFunctionFactory(chainOptions, chain) | ||
}; | ||
} | ||
Animar.prototype._addAnimationToElement = function(attributeMap, args) { | ||
if (!attributeMap.has(args.attribute)) { | ||
attributeMap = this._createAttribute(attributeMap, args); | ||
thenChainFunctionFactory(chainOptions: ChainOptions, chain: ElementMap): Function { | ||
return (wait=0) => { | ||
chainOptions.totalDuration += (chainOptions.currentDuration + wait); | ||
chainOptions.currentDuration = 0; | ||
chainOptions.delay = chainOptions.totalDuration; | ||
return { | ||
add: this.addChainFunctionFactory(chainOptions, chain) | ||
}; | ||
}; | ||
} | ||
var currentAttribute = attributeMap.get(args.attribute), | ||
startValue = currentAttribute.model - args.destination, | ||
changeInValue = 0 - startValue; | ||
currentAttribute.model = args.destination; | ||
addChainFunctionFactory(chainOptions: ChainOptions, chain: ElementMap): Function { | ||
return (element, attributes, options) => { | ||
let resolvedOptions = typeof options === 'undefined' ? EMPTY_ANIMATION_OPTIONS : options; | ||
return this._add(element, attributes, resolvedOptions, chainOptions, chain); | ||
}; | ||
} | ||
var currentAnimation = { | ||
currentIteration: 0 - args.delay, | ||
startValue: startValue, | ||
changeInValue: changeInValue, | ||
totalIterations: args.duration, | ||
easingFunction: args.ease, | ||
loop: args.loop, | ||
delay: args.delay, | ||
wait: args.wait | ||
}; | ||
currentAttribute.animations.push(currentAnimation); | ||
return currentAnimation; | ||
}; | ||
loopChainFunctionFactory(chainOptions: ChainOptions, chain: ElementMap): Function { | ||
return () => { | ||
chainOptions.totalDuration += chainOptions.currentDuration; | ||
Animar.prototype._createAttribute = function(attributeMap, args) { | ||
var start = (args.start === undefined ? Helper.getStartValue([args.element, args.attribute]) : args.start); | ||
var newAttributeObject = { | ||
model: start, | ||
animations: [] | ||
}; | ||
let newElementMap = new Map(); | ||
attributeMap.set(args.attribute, newAttributeObject); | ||
return attributeMap; | ||
}; | ||
chain.forEach((element, elementRef) => { | ||
element.forEachAnimationInAttribute(animation => { | ||
if (animation != null) { | ||
animation.loop = true; | ||
animation.wait = chainOptions.totalDuration - animation.delay - animation.totalIterations; | ||
return animation; | ||
} | ||
}); | ||
newElementMap.set(elementRef, element); | ||
}); | ||
Animar.prototype._update = function() { | ||
var animationsRemaining = this._renderDOM(); | ||
this._stepFrame(); | ||
this.ticking = false; | ||
if (animationsRemaining) { | ||
this._requestTick(); | ||
chain = newElementMap; | ||
return { | ||
start: this.startChainFunctionFactory(chain) | ||
}; | ||
}; | ||
} | ||
}; | ||
Animar.prototype._requestTick = function() { | ||
if (!this.ticking) { | ||
window.requestAnimationFrame(this._update.bind(this)); | ||
this.ticking = true; | ||
startChainFunctionFactory(chain: ElementMap): Function { | ||
return () => { | ||
console.log(chain); | ||
this.elementMap = this.mergeElementMaps(this.elementMap, chain); | ||
this.requestTick(); | ||
}; | ||
} | ||
}; | ||
Animar.prototype._calculateAnimationValue = function(animations) { | ||
var result = 0; | ||
animations.forEach(function(value) { | ||
var currentIteration = value.currentIteration; | ||
if (value.currentIteration < 0) { | ||
currentIteration = 0; | ||
requestTick() { | ||
if (!this.ticking) { | ||
window.requestAnimationFrame(this.update.bind(this)); | ||
this.ticking = true; | ||
} | ||
if (value.currentIteration >= value.totalIterations) { | ||
currentIteration = value.totalIterations; | ||
} | ||
update() { | ||
this.ticking = false; | ||
var hasChanged = this.step(); | ||
if (hasChanged) { | ||
this.render(); | ||
this.requestTick(); | ||
} | ||
result += value.easingFunction(currentIteration, value.startValue, value.changeInValue, value.totalIterations); | ||
}); | ||
return result; | ||
}; | ||
} | ||
Animar.prototype._applyStyle = function(element, attribute, value) { | ||
switch(attribute) { | ||
case("transform"): | ||
Helper.setTransform(element, value); | ||
break; | ||
case("opacity"): | ||
element.style.opacity = value; | ||
break; | ||
case("perspective"): | ||
element.style.perspective = value; | ||
element.style.webkitPerspective = value; | ||
break; | ||
render() { | ||
this.elementMap.forEach((element, domElement) => { | ||
element.render(domElement); | ||
}); | ||
} | ||
}; | ||
Animar.prototype._renderDOM = function() { | ||
var self = this; | ||
var animated = false; | ||
self.elementMap.forEach(function(value, key) { | ||
var targetElement = key; | ||
var transformValue = ""; | ||
value.forEach(function(value, key) { | ||
var targetAttribute = String(key); | ||
if ( value.animations.length !== 0 ) { | ||
animated = true; | ||
var targetValue = value.model + self._calculateAnimationValue(value.animations), | ||
pxRegex = /(perspective)|(translate[XYZ])/, | ||
degRegex = /rotate[XYZ]?/; | ||
if (Constants.TRANSFORM_ATTRIBUTES.indexOf(targetAttribute) !== -1) { | ||
var unit = ((pxRegex.test(targetAttribute)) ? "px" : (degRegex.test(targetAttribute) ? "deg" : "")); | ||
transformValue += targetAttribute + "(" + targetValue + unit + ") "; | ||
} else { | ||
self._applyStyle(targetElement, targetAttribute, targetValue); | ||
} | ||
step(): boolean { | ||
let somethingChanged = false; | ||
this.elementMap.forEach(element => { | ||
if (element.step(this.timescale)) { | ||
somethingChanged = true; | ||
} | ||
}); | ||
if (transformValue !== "") { | ||
transformValue += "translateZ(0)"; | ||
self._applyStyle(targetElement, "transform", transformValue); | ||
} | ||
}); | ||
return animated; | ||
return somethingChanged; | ||
} | ||
}; | ||
Animar.prototype._stepFrame = function() { | ||
var elementMap = this.elementMap; | ||
elementMap.forEach(function(value) { | ||
value.forEach(function(value) { | ||
var updatedAnimations = []; | ||
value.animations.forEach(function(value) { | ||
if (value.currentIteration < (value.totalIterations + value.wait)) { | ||
value.currentIteration += 1; | ||
updatedAnimations.push(value); | ||
} else if (value.loop) { | ||
value.currentIteration = 0 - value.delay; | ||
updatedAnimations.push(value); | ||
} | ||
}); | ||
value.animations = updatedAnimations; | ||
}); | ||
}); | ||
}; | ||
module.exports = Animar; |
The MIT License (MIT) | ||
Copyright (c) <year> <copyright holders> | ||
Copyright (c) 2015 Vincent Riemer | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "animar", | ||
"version": "0.4.4", | ||
"version": "0.5.1", | ||
"description": "a modern, focused, flexible javascript animation library.", | ||
@@ -26,23 +26,11 @@ "keywords": [ | ||
"scripts": { | ||
"clean": "rimraf dist", | ||
"clean-coverage": "rimraf coverage", | ||
"clean-dist": "rimraf dist", | ||
"clean": "npm run clean-coverage && npm run clean-dist", | ||
"lint": "jshint **.js", | ||
"build": "./scripts/build.sh", | ||
"test": "jest", | ||
"pretest": "npm run clean-coverage && npm run lint", | ||
"prebuild": "npm run clean-dist" | ||
"lint": "eslint lib", | ||
"typecheck": "./node_modules/.bin/flow check", | ||
"prebuild": "npm run clean", | ||
"test": "./node_modules/babel-cli/bin/babel-node.js ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha", | ||
"pretest": "npm run clean-coverage && npm run lint && npm run typecheck" | ||
}, | ||
"jest": { | ||
"collectCoverage": true, | ||
"testFileExtensions": [ | ||
"js" | ||
], | ||
"moduleFileExtensions": [ | ||
"js" | ||
], | ||
"testPathDirs": [ | ||
"lib" | ||
] | ||
}, | ||
"directories": { | ||
@@ -53,9 +41,25 @@ "lib": "lib" | ||
"devDependencies": { | ||
"compression-webpack-plugin": "^0.1.2", | ||
"jest-cli": "^0.4.0", | ||
"jshint": "^2.6.0", | ||
"babel-cli": "^6.2.0", | ||
"babel-core": "^6.2.1", | ||
"babel-eslint": "^4.1.5", | ||
"babel-loader": "^6.2.0", | ||
"babel-plugin-transform-class-properties": "^6.2.2", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.2.0", | ||
"babel-plugin-transform-flow-strip-types": "^6.1.18", | ||
"babel-preset-es2015": "^6.1.18", | ||
"chai": "^3.4.1", | ||
"compression-webpack-plugin": "^0.2.0", | ||
"eslint": "^1.10.1", | ||
"eslint-plugin-flow-vars": "0.0.1", | ||
"flow-bin": "^0.18.1", | ||
"isparta": "^4.0.0", | ||
"jsdom": "^7.0.2", | ||
"lodash": "^3.3.1", | ||
"mocha": "^2.3.4", | ||
"rimraf": "^2.3.1", | ||
"webpack": "^1.6.0" | ||
"sinon": "^1.15.4", | ||
"travis-weigh-in": "^1.0.2", | ||
"tsd": "^0.6.3", | ||
"webpack": "^1.12.8" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
[![Build Status](https://img.shields.io/travis/vincentriemer/animar/master.svg?style=flat)](https://travis-ci.org/vincentriemer/animar) [![Dependency Status](https://img.shields.io/david/vincentriemer/animar.svg?style=flat)](https://david-dm.org/vincentriemer/animar) [![devDependency Status](https://img.shields.io/david/dev/vincentriemer/animar.svg?style=flat)](https://david-dm.org/vincentriemer/animar#info=devDependencies) [![npm version](https://img.shields.io/npm/v/animar.js.svg?style=flat)](http://badge.fury.io/js/animar) [![Code Climate](https://img.shields.io/codeclimate/github/vincentriemer/animar.svg?style=flat)](https://codeclimate.com/github/vincentriemer/animar) [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/vincentriemer/animar.svg?style=flat)](https://codeclimate.com/github/vincentriemer/animar) | ||
[![Build Status](https://img.shields.io/travis/vincentriemer/animar/master.svg?style=flat)](https://travis-ci.org/vincentriemer/animar) [![Dependency Status](https://img.shields.io/david/vincentriemer/animar.svg?style=flat)](https://david-dm.org/vincentriemer/animar) [![devDependency Status](https://img.shields.io/david/dev/vincentriemer/animar.svg?style=flat)](https://david-dm.org/vincentriemer/animar#info=devDependencies) [![npm version](https://img.shields.io/npm/v/animar.js.svg?style=flat)](http://badge.fury.io/js/animar) [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/vincentriemer/animar.svg?style=flat)](https://codeclimate.com/github/vincentriemer/animar) | ||
@@ -3,0 +3,0 @@ # Animar |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
43598
22
16
1096
1