Разрушение мифов — CSS анимации vs. JavaScript

Дневник админа
Разрушение мифов - CSS анимации vs. JavaScript

Разрушение мифов: CSS vs. JavaScript

 var $ start = $ (& quot; # start & quot;),
$ dotQtyInput = $ ("# dotQuantity"),
$ engineInput = $ ("# двигатель"),
$ propertiesInput = $ ("# свойств"),
$ инструкций = $ (& quot; # инструкций & quot;),
$ field = $ (& quot; # поле & quot;),
$ window = $ (окно),
$ input = $ (& quot; выбрать & quot;),
inProgress = false,
tests = {},
длительность, радиус, centerX, centerY, точки, rawDots, currentTest, startCSS;

/**
* Цель этого теста - сравнить, как разные инструменты создания анимации работают под нагрузкой, получая относительно общие задачи анимации и выполняя их в большом количестве, чтобы увидеть чистую производительность. Цель состоит не в том, чтобы найти наиболее эффективный способ перемещения точек по схеме звездного поля.
*
* Один и тот же код используется для всего, кроме самих анимаций. Каждый тест в объекте «test» имеет 4 свойства:
*
* - миллисекунды [логическое] - истина, если продолжительность должна быть указана в миллисекундах
*
* - wrapDot [функция] - когда каждый & lt; img & gt; точка создается, ее необходимо передать методу wrapDot (), а то, что возвращает функция, сохраняется в массиве точек для анимации. Это полезно для повышения производительности таких вещей, как jQuery, потому что вместо передачи элемента DOM методу tween () (который потребовал бы, чтобы jQuery запрашивал DOM и заключал элемент в объект, специфичный для движка, перед вызовом animate ()) , можно использовать природный объект. Проще говоря, это позволит кэшировать перенос точек для повышения производительности.
*
* - tween [функция] является ядром всего теста. tween () вызывается для каждой точки, точка передается как параметр. Функция tween () должна установить cssText точки на начальное значение CSS (которое просто помещает точку в центр экрана и устанавливает значение для ее ширины и высоты на 1 пиксель), а затем после произвольной задержки 0 для продолжительность анимации, функция должна анимировать точку под произвольным углом, изменяя значения left/top или translate (), и устанавливать ее размер на 32 пикселя в ширину и в высоту, используя width/height или scale (). Затем, после завершения анимации, метод tween () должен быть вызван снова для той же точки. Таким образом, одна и та же точка будет продолжать удаляться от центра под случайным углом и с произвольно выбранным временем задержки.
*
* - stop [функция] - эта функция вызывается, когда пользователь останавливает тест. Точка передается как параметр. Функция должна немедленно остановить/уничтожить анимацию (или анимацию), запущенную для этой точки (или для всех точек - это тоже нормально).
*
* - nativeSize [Boolean] - установите значение true, если начальная ширина/высота изображения должна быть в его собственном размере (обычно требуется для преобразований, но не при анимации ширины/высоты).
*
* Я не претендую на звание эксперта по различным движкам анимации, поэтому, если есть способы оптимизации, которые вы можете применить для повышения производительности тестирования, дайте мне знать. Я постарался сделать это максимально беспристрастным.
**/
//стандартный jQuery нормальный (вверху/слева/ширина/высота)
tests.jquery_normal = {
миллисекунды: истина,
wrapDot: function (точка) {
вернуть jQuery (точка);//оборачиваем точку в объект jQuery для повышения производительности (таким образом нам не нужно запрашивать DOM каждый раз при анимации - мы можем просто вызвать animate () непосредственно для объекта jQuery)
},
tween: function (точка) {
var angle = Math.random () * Math.PI * 2;
точка [0] .style.cssText = startCSS;
dot.delay (Math.random () * duration) .animate ({left: Math.cos (угол) * радиус + centerX,
вверху: Math.sin (угол) * радиус + centerY,
ширина: 32,
height: 32}, duration, "cubicIn", function () {tests.jquery_normal.tween (точка)})
},
stop: function (period) {
для остановки (истина);
},
nativeSize: false
};
//стандартный GSAP (вверху/слева/ширина/высота)
tests.gsap_normal = {
миллисекунды: ложь,
wrapDot: функция (точка){
точка возврата;//не нужно переносить
},
tween: function (точка) {
var angle = Math.random () * Math.PI * 2;
dot.style.cssText = startCSS;
TweenLite.to (точка, продолжительность, {css: {left: Math.cos (угол) * радиус + centerX,
вверху: Math.sin (угол) * радиус + centerY,
ширина: 32,
высота: 32},
задержка: Math.random () * продолжительность,
легкость: Cubic.easeIn,
перезапись: & quot; отсутствует & quot;,
onComplete: tests.gsap_normal.tween,
onCompleteParams: [точка]});

},
stop: function (period) {
TweenLite.killTweensOf (точка);
},
nativeSize: false
};
//преобразования GSAP (translate ()/scale ())
tests.gsap_transforms = {
миллисекунды: ложь,
wrapDot: function (точка) {
точка возврата;//не нужно переносить
},
tween: function (точка) {
var angle = Math.random () * Math.PI * 2;
TweenLite.set (точка, {css: {x: 0, y: 0, масштаб: 0,06}, перезапись: "нет"});
TweenLite.to (точка, продолжительность, {css: {x: (Math.cos (угол) * радиус),
y: (Math.sin (угол) * радиус),
масштаб X: 2,
scaleY: 2},
задержка: Math.random () * продолжительность,
легкость: Cubic.easeIn,
перезапись: & quot; отсутствует & quot;,
onComplete: tests.gsap_transforms.tween,
onCompleteParams: [точка]});
},
stop: function (period) {
TweenLite.killTweensOf (точка);
},
nativeSize: true
};
//стандартный Zepto (сверху/слева/ширина/высота)
tests.zepto_normal = {
миллисекунды: истина,
wrapDot: function (точка) {
вернуть Zepto (точка);//wrapDot в jQuery для повышения производительности (таким образом нам не нужно опрашивать DOM каждый раз при анимации - мы можем просто вызвать animate () непосредственно в jQuery)
},
tween: function (точка) {
var angle = Math.random () * Math.PI * 2;
точка [0] .style.cssText = startCSS;
//Функция задержки давления в Zepto работает ПЛОХО, поэтому вместо этого мы используем setTimeout () для повышения производительности.
setTimeout (function () {
if (! dot.isKilled) {//Zepto не имеет функции, которая позволяет нам убивать запущенную анимацию, поэтому мы просто устанавливаем для нашего собственного свойства isKilled значение true, когда анимация собирается остановиться, а затем останавливаем рекурсию, давая нам эффект, который мы хотим.
dot.animate ({слева: Math.cos (угол) * радиус + centerX,
вверху: Math.sin (угол) * радиус + centerY,
ширина: 32,
высота: 32}, продолжительность, «кубический безье (0,550, 0,055, 0,675, 0,190)», функция () {tests.zepto_normal.tween (точка)});
}
}, продолжительность * Math.random ());
},
stop: function (period) {
isKilled = true;
},

nativeSize: false
};
//Zepto преобразует (translate ()/scale ())
tests.zepto_transforms = {
миллисекунды: истина,
wrapDot: function (точка) {
вернуть Zepto (точка);//wrapDot в jQuery для повышения производительности (таким образом нам не нужно опрашивать DOM каждый раз при анимации - мы можем просто вызвать animate () непосредственно в jQuery)
},
tween: function (точка) {
//Не удалось установить функцию css () в Zepto (сбой), поэтому пришлось использовать вызов animate () с нулевой продолжительностью. Хорошо, потому что в TweenLite мы также делаем анимацию с нулевой продолжительностью.
aboutanimate ({translateX: "0px", translateY: "0px", rotateY: "0rad", rotateX: "0rad", scale: "0,06, 0,06 & quot;}, 0);
//Функция задержки под давлением Zepto работает ПОЛНОСТЬЮ, поэтому вместо этого мы используем setTimeout () для повышения производительности.
setTimeout (function () {
if (! dot.isKilled) {//Zepto не имеет функции, которая позволяет нам убивать запущенную анимацию, поэтому мы просто устанавливаем для нашего собственного свойства isKilled значение true, когда анимация собирается остановиться, а затем останавливаем рекурсию, давая нам эффект, который мы хотим.
var angle = Math.random () * Math.PI * 2;
dot.animate ({translateX: (Math.cos (угол) * радиус) + & quot; px & quot;,
translateY: (Math.sin (угол) * радиус) + & quot; px & quot;,
Масштаб: «2,2»
delay: duration * Math.random ()}, duration, «кубическая шкала Безье (0,550, 0,055, 0,675, 0,190)», function () {tests.zepto_transforms.tween (точка); });
}
}, продолжительность * Math.random ());
},
stop: function (period) {
isKilled = true;
},

nativeSize: true

Разрушение мифов - CSS анимации vs. JavaScript

};
function toggleTest () {
var i, size;inProgress =!
if (inProgress) {
$ inputs.prop ("отключено", истина);
$ field.css ({pointerEvents: & quot; none & quot;});//улучшение производительности - игнорировать события указателя во время анимации
$ start.html ("СТОП");
$ start.css ({фон: & quot; # C00 & quot;});
TweenLite.to ($ instructions, 0.7, {autoAlpha: 0, overwrite: & quot; all & quot;});
currentTest = тесты [$ engineInput.val () + & quot; _ & quot; + $ propertiesInput.val ()];
size = (currentTest.nativeSize? "16px ":" 1px ");
centerX = $ field.width ()/2;
centerY = $ field.height ()/2;
startCSS = & quot; позиция: абсолютная; слева: & quot; + centerX + & quot; px; вверху: & quot; + centerY + & quot; px; ширина: & quot; + размер + & quot; высота: & quot; + размер
& quot ;; & quot ;;
радиус = Math.sqrt (centerX * centerX + центры * центры);
продолжительность = currentTest.milliseconds? 750: 0,75;
//ждем миллисекунду перед построением точек и запуском анимации, чтобы пользовательский интерфейс воспроизводился вперед (превращая кнопку «старт» в кнопку «стоп»), иначе пользователи могут запутаться во время долгой паузы, когда Zepto и преобразование выбираются с помощью из-за того, что браузеру может потребоваться некоторое время, чтобы поместить все точки на свои слои.
setTimeout (function () {
createDots ();
i = длина точки;
while (--i & gt; -1) {
currentTest.tween (точки [я]);
}
}, 1);
} еще {
$ start.html (& quot; НАЧАТЬ & quot;);
$ start.css ({backgroundColor: "# 9af600", background: "linear-gradient (to bottom, # 9af600 0%, # 71B200 100%"});
TweenLite.to ($ инструкции, 0,7, {autoAlpha: 1, задержка: 0,2});
$ inputs.prop ("отключено", ложь);
calibrateInputs ();
$ field.css ({pointerEvents: & quot; auto & quot;});
//остановить анимацию и удалить точки.
i = длина точки;
while (--i & gt; -1) {
currentTest.stop (точки [i]);
$ field [0] .removeChild (rawDots [i]);//удаляем точку (и)
}
точки = ноль;
rawDots = ноль;
}

}
function createDots () {
var i = parseInt ($ dotQtyInput.val ()),
точка;
точки = [];
rawDots = [];
while (--i & gt; -1) {
точка = документ.createElement (& quot; img & quot;);
dot.src = & quot; https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/dot.png" ;;
для ширины = 1;
reheight = 1;
dot.id = "точка" + и;
dot.style.cssText = startCSS;
$ field [0] .appendChild (период);
rawDots.push (точка);
dots.push (currentTest.wrapDot (точка))
}

}
function calibrateInputs (e) {
if ($ engineInput.val () == & quot; jquery & quot;) {//jQuery не может анимировать преобразования без стороннего плагина, поэтому отключите эту опцию.
$ propertiesInput [0] .selectedIndex = 0;
$ propertiesInput.prop ("отключено", истина);
} еще {
$ propertiesInput.prop ("отключено", ложь);
}
}
$ start.click (toggleTest);
$ inputs.change (calibrateInputs);
jQuery.easing.cubicIn = $ .easing.cubicIn = function (p, n, firstNum, diff) {//нам нужно добавить стандартную функцию смягчения CubicIn в jQuery
вернуть firstNum + p * p * diff;
}

jQuery.fx.interval = 16;//обеспечивает обновления jQuery со скоростью около 60 кадров в секунду, аналогично GSAP и другим, чтобы показывать более равномерные/предвзятые результаты.

Оцените статью