diff --git a/index.html b/index.html index 6546475..e5a09a9 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,7 @@

fadeIn

+
@@ -17,6 +18,7 @@

fadeIn

move

+
@@ -24,9 +26,33 @@

move

scale

+
+
+
+

moveAndHide

+ + +
+
+
+
+
+

showAndHide

+ +
+
+
+
+
+

heartBeating

+ + +
+
+
diff --git a/index.js b/index.js index 61e55f6..c784666 100644 --- a/index.js +++ b/index.js @@ -1,57 +1,23 @@ -addListeners(); - -function addListeners() { - document.getElementById('fadeInPlay') - .addEventListener('click', function () { - const block = document.getElementById('fadeInBlock'); - fadeIn(block, 5000); - }); - - document.getElementById('movePlay') - .addEventListener('click', function () { - const block = document.getElementById('moveBlock'); - move(block, 1000, {x: 100, y: 10}); - }); - - document.getElementById('scalePlay') - .addEventListener('click', function () { - const block = document.getElementById('scaleBlock'); - scale(block, 1000, 1.25); - }); +function addListeners(cycled, ...listeners) { + for (let listener of listeners) { + let block = document.getElementById(listener[0] + 'Block'); + let command = document.getElementById(listener[0] + (cycled ? 'Stop' : 'Reset')); + document.getElementById(listener[0] + 'Play') + .addEventListener('click', function () { + let element = animaster()[listener[0]](block, ...listener.slice(1)); + command.addEventListener('click', cycled ? element.stop : element.reset) + }); + } } -/** - * Блок плавно появляется из прозрачного. - * @param element — HTMLElement, который надо анимировать - * @param duration — Продолжительность анимации в миллисекундах - */ -function fadeIn(element, duration) { - element.style.transitionDuration = `${duration}ms`; - element.classList.remove('hide'); - element.classList.add('show'); -} +addListeners(false, + ['fadeIn', 5000], + ['move', 1000, {x: 100, y: 10}], + ['scale', 1000, 1.25], + ['moveAndHide', 1000, {x: 100, y: 20}], + ['showAndHide', 1000]); -/** - * Функция, передвигающая элемент - * @param element — HTMLElement, который надо анимировать - * @param duration — Продолжительность анимации в миллисекундах - * @param translation — объект с полями x и y, обозначающими смещение блока - */ -function move(element, duration, translation) { - element.style.transitionDuration = `${duration}ms`; - element.style.transform = getTransform(translation, null); -} - -/** - * Функция, увеличивающая/уменьшающая элемент - * @param element — HTMLElement, который надо анимировать - * @param duration — Продолжительность анимации в миллисекундах - * @param ratio — во сколько раз увеличить/уменьшить. Чтобы уменьшить, нужно передать значение меньше 1 - */ -function scale(element, duration, ratio) { - element.style.transitionDuration = `${duration}ms`; - element.style.transform = getTransform(null, ratio); -} +addListeners(true, ['heartBeating']); function getTransform(translation, ratio) { const result = []; @@ -63,3 +29,149 @@ function getTransform(translation, ratio) { } return result.join(' '); } + +function animaster() { + return { + _steps: [], + + buildHandler() { + let animaster = this; + return function () { + return animaster.play(this); + } + }, + + fadeIn(element, duration) { + return this.addFadeIn(duration).play(element); + }, + + fadeOut(element, duration) { + return this.addFadeOut(duration).play(element); + }, + + move(element, duration, translation) { + return this.addMove(duration, translation).play(element); + }, + + scale(element, duration, ratio) { + return this.addScale(duration, ratio).play(element); + }, + + moveAndHide(element, duration) { + return this.addMove(duration * 2 / 5, {x: 100, y: 20}) + .addFadeOut(duration * 3 / 5) + .play(element); + }, + + showAndHide(element, duration) { + return this.addFadeIn(duration / 3) + .addDelay(duration / 3) + .addFadeOut(duration / 3) + .play(element); + }, + + heartBeating(element) { + return this.addScale(500, 1.4) + .addScale(500, 1) + .play(element, true); + }, + + resetFadeIn(element) { + element.style.transitionDuration = null; + element.classList.remove('show'); + element.classList.add('hide'); + }, + + resetFadeOut(element) { + element.style.transitionDuration = null; + element.classList.remove('hide'); + element.classList.add('show'); + }, + + resetMoveAndScale(element) { + element.style.transitionDuration = null; + element.style.transform = getTransform(null, 1); + }, + + addMove(duration, translation) { + let animasterCopy = this.copy() + animasterCopy._steps.push({ + duration, + action: element => element.style.transform = getTransform(translation, null), + reset: element => this.resetMoveAndScale(element) + }) + return animasterCopy; + }, + + addScale(duration, ratio) { + let animasterCopy = this.copy() + animasterCopy._steps.push({ + duration, + action: element => element.style.transform = getTransform(null, ratio), + reset: element => this.resetMoveAndScale(element) + }) + return animasterCopy; + }, + + addFadeIn(duration) { + let animasterCopy = this.copy() + animasterCopy._steps.push({ + duration, + action: element => { + element.classList.remove('hide'); + element.classList.add('show');}, + reset: element => this.resetFadeIn(element) + }) + return animasterCopy; + }, + + addFadeOut(duration) { + let animasterCopy = this.copy() + animasterCopy._steps.push({ + duration, + action: element => { + element.classList.remove('show'); + element.classList.add('hide');}, + reset: element => this.resetFadeOut(element) + }) + return animasterCopy; + }, + + addDelay(duration) { + let animasterCopy = this.copy() + animasterCopy._steps.push({ + duration, + action: () => null, + reset: () => null + }); + return animasterCopy; + }, + + copy() { + let animasterCopy = animaster(); + animasterCopy._steps = this._steps.slice(); + return animasterCopy; + }, + + play(element, isCycled = false) { + let tick; + let timer = setTimeout(tick = index => { + element.style.transitionDuration = `${this._steps[index].duration}ms`; + this._steps[index].action(element); + if (isCycled || index < this._steps.length - 1) + timer = setTimeout(tick, Math.round(this._steps[index].duration), + (index + 1) % this._steps.length); + }, 0, 0); + + return { + stop: () => { + clearTimeout(timer); + }, + reset: () => { + element.style.transitionDuration = null; + this._steps.slice().reverse().forEach(s => s.reset(element)); + } + } + } + } +}