import { window } from 'ssr-window'; import { requestAnimationFrame, cancelAnimationFrame } from './utils'; function animate(initialProps, initialParams) { const els = this; const a = { props: Object.assign({}, initialProps), params: Object.assign({ duration: 300, easing: 'swing', // or 'linear' /* Callbacks begin(elements) complete(elements) progress(elements, complete, remaining, start, tweenValue) */ }, initialParams), elements: els, animating: false, que: [], easingProgress(easing, progress) { if (easing === 'swing') { return 0.5 - (Math.cos(progress * Math.PI) / 2); } if (typeof easing === 'function') { return easing(progress); } return progress; }, stop() { if (a.frameId) { cancelAnimationFrame(a.frameId); } a.animating = false; a.elements.each((index, el) => { const element = el; delete element.dom7AnimateInstance; }); a.que = []; }, done(complete) { a.animating = false; a.elements.each((index, el) => { const element = el; delete element.dom7AnimateInstance; }); if (complete) complete(els); if (a.que.length > 0) { const que = a.que.shift(); a.animate(que[0], que[1]); } }, animate(props, params) { if (a.animating) { a.que.push([props, params]); return a; } const elements = []; // Define & Cache Initials & Units a.elements.each((index, el) => { let initialFullValue; let initialValue; let unit; let finalValue; let finalFullValue; if (!el.dom7AnimateInstance) a.elements[index].dom7AnimateInstance = a; elements[index] = { container: el, }; Object.keys(props).forEach((prop) => { initialFullValue = window.getComputedStyle(el, null).getPropertyValue(prop).replace(',', '.'); initialValue = parseFloat(initialFullValue); unit = initialFullValue.replace(initialValue, ''); finalValue = parseFloat(props[prop]); finalFullValue = props[prop] + unit; elements[index][prop] = { initialFullValue, initialValue, unit, finalValue, finalFullValue, currentValue: initialValue, }; }); }); let startTime = null; let time; let elementsDone = 0; let propsDone = 0; let done; let began = false; a.animating = true; function render() { time = new Date().getTime(); let progress; let easeProgress; // let el; if (!began) { began = true; if (params.begin) params.begin(els); } if (startTime === null) { startTime = time; } if (params.progress) { // eslint-disable-next-line params.progress(els, Math.max(Math.min((time - startTime) / params.duration, 1), 0), ((startTime + params.duration) - time < 0 ? 0 : (startTime + params.duration) - time), startTime); } elements.forEach((element) => { const el = element; if (done || el.done) return; Object.keys(props).forEach((prop) => { if (done || el.done) return; progress = Math.max(Math.min((time - startTime) / params.duration, 1), 0); easeProgress = a.easingProgress(params.easing, progress); const { initialValue, finalValue, unit } = el[prop]; el[prop].currentValue = initialValue + (easeProgress * (finalValue - initialValue)); const currentValue = el[prop].currentValue; if ( (finalValue > initialValue && currentValue >= finalValue) || (finalValue < initialValue && currentValue <= finalValue)) { el.container.style[prop] = finalValue + unit; propsDone += 1; if (propsDone === Object.keys(props).length) { el.done = true; elementsDone += 1; } if (elementsDone === elements.length) { done = true; } } if (done) { a.done(params.complete); return; } el.container.style[prop] = currentValue + unit; }); }); if (done) return; // Then call a.frameId = requestAnimationFrame(render); } a.frameId = requestAnimationFrame(render); return a; }, }; if (a.elements.length === 0) { return els; } let animateInstance; for (let i = 0; i < a.elements.length; i += 1) { if (a.elements[i].dom7AnimateInstance) { animateInstance = a.elements[i].dom7AnimateInstance; } else a.elements[i].dom7AnimateInstance = a; } if (!animateInstance) { animateInstance = a; } if (initialProps === 'stop') { animateInstance.stop(); } else { animateInstance.animate(a.props, a.params); } return els; } function stop() { const els = this; for (let i = 0; i < els.length; i += 1) { if (els[i].dom7AnimateInstance) { els[i].dom7AnimateInstance.stop(); } } } export { animate, stop };