Нативный JS реализует параболическую анимацию и эффект динамического размытия.

Байду внешний интерфейс JavaScript SVG
  • суг команда
  • Автор: Джейсон

предисловие

Однажды я получил сообщение WeChat от продукта. Сяо X, нашему бизнесу теперь нужна анимация падения, похожая на добавление в корзину.После тщательного рассмотрения организации это требование будет передано вам. Отсюда и эта статья. В этой статье описываются не многие передовые технологии, а скорее мысли автора о принципах анимации при создании анимации и некоторые идеи о том, как оптимизировать анимацию. Эффект следующий:

Качество изображения ограничено, пожалуйста, поймите

технический анализ

Есть много способов реализовать анимацию во внешнем интерфейсе. Будь то анимация JS, анимация CSS, анимация Canvas или анимация SVG, даже анимации GIF для получения простой параболы достаточно. Но, учитывая потребности бизнес-сценария и играбельность, мы, наконец, решили использовать JS для реализации этой анимации.

Анализ реализации

По мнению автора, большинство анимационных эффектов, в конечном счете, все ещеПрименение математических формул. Так называемая параболическая анимация — это не что иное, как приведение движения элементов в соответствие с траекторией параболы.
Уравнение параболы:Y = A*X*X + B*X + CМожет быть, всем эта формула покажется немного незнакомой. Но однажды учитель физики продекламировал словаL(距离) = 1/2*A(加速度)*T*T(时间)Каждый должен быть с ним знаком. Автор использует эту формулу для завершения параболической анимации.

Реализация

Шаг 1 Получите начальную и конечную точки параболы

Из-за особенности самого бизнеса необходимо получить абсолютное положение элемента в окне, когда пользователь нажимает на элемент. То есть x, y координаты элемента относительно видимой области браузера. Здесь автор рекомендует использоватьgetBoundingClientRect()Функция вычисляет абсолютную позицию в сочетании с конкретным бизнесом. Конечно, в некоторых сценариях вы можете напрямую использовать положение щелчка мыши или любой другой метод, чтобы получить начальную точку анимации.

Шаг 2 Установите параболические параметры

1. Ускорение

Ускорение A определяет скорость элемента в заданном направлении (заменено вертикальным направлением ниже). Когда начальная и конечная точки анимации фиксированы, формулаL(垂直距离) = 0.5 * A(加速度) * T * T(时间)Можно сделать вывод, что в это времяУскорение А обратно пропорционально квадрату времени Т..
Следует отметить, что положительное ускорение A всегда будет увеличивать расстояние вертикального перемещения между кадрами, поэтому чрезмерное ускорение A может вызватьВ конце анимации шарик мерцает.

2. Время T и начальная скорость оси X.

В параболической анимации мы обычно думаем, что элементГоризонтальная скорость движения фиксирована. Затем та же формулаL(水平距离) = T * Xspeed(水平速度)Можно сделать вывод, что горизонтальная скорость Xspeed фактически определяет время выполнения анимации.
Объединяя понятие ускорения, можно сделать следующие выводы:
Когда начальная и конечная точки анимации фиксированы, если мы установим начальную скорость оси X на фиксированное значение, время выполнения анимации будет фиксированным, чтобы мяч достиг заданного положения. Ускорение A необходимо рассчитать и сгенерировать.Конкретная формула расчета выглядит следующим образом:

// 确定动画起始点和终点
let XStart = 0, YStart = 0, XEnd = 1000, YEnd = 1000;
// 确定关键参数
let Xspeed = XX;
// 根据关键参数Xpeed计算动画时间与垂直加速度
let Time = (XEnd - XStart) / Xspeed; 
let A = 2 * (YEnd - YStart ) / (Time * Time); 

Что, если продолжительность выполнения анимации фиксирована?

// 确定关键参数
let Time = XX;
// 根据关键参数Time计算水平速度与垂直加速度
let Xpeed = (XEnd - XStart) / Time; 
let A = 2 * (YEnd - YStart ) / (Time * Time); 

Что делать, если ускорение требуется зафиксировать?
Нет, тебе не нужно...

3. Начальная скорость оси Y

Начальная скорость по оси Y, то есть вертикальная скорость при броске параболы. Обычно я ставлюНачальная скорость по оси Y отрицательна. В это время будет анимация подбрасывания, а затем естественного падения, что немного ярко... В это время формула расчета ускорения A будет выглядеть так:

let A = 2 * (YEnd - YStart - Yspeed * Time) / (Time * Time); 

Здесь следует отметить, что установка различных соотношений Xspeed и Yspeed можетИзменить форму кривой. Принцип, лежащий в основе этого: скорость Y и ускорение A (возможно, контролируемое скоростью X) совместно определяют количество времени, которое мяч может достичь на стадии подъема после того, как мяч был брошен.наивысшая точка, а Xspeed определяет положение оси X в это время.

Шаг 3 Заставьте его двигаться

Для обычных анимаций JS мы обычно используемsetTimeOut или requestAnimationFramдостигать. Ниже мы используемrequestAnimationFramвыполнитьИсправлено время выполнения анимацииНапример.

1. Сначала сгенерируйте шар и определите начальную и конечную точки анимации, а также ключевые параметры

// 起点和终点请自由设定
let XStart = 0, YStart = 0, XEnd = 1000, YEnd = 1000; 
let Time = T;
let Xpeed = (XEnd - XStart) / Time; 
let Ypeed = -YY; 
let A = 2 * (YEnd - YStart - Yspeed * Time) / (Time * Time); 
// 生成元素
let Node = document.createElement('div');
// 自由控制形体,定位一般设定为Fixed
Node.className = 'myNode';
document.body.appendChild(Node);
Node.style.top = YStart + 'px';
Node.style.left = XStart + 'px';

2. Измените положение элемента в обратном вызове requestAnimationFram.

// 记录元素实时位置
let nowX = XStart;
let nowY = YEnd;
// 单位时间
let loop = 0;
// 
let move = () => {
    if (nowY >= targetTop) {
        // 销毁实例的判断可自行设定
        Node.remove();
        return;
    }
    // 当前位置等于原始位置 + 单位时间内的位移
    nowX += Xspeed;
    // 
    nowY += (A * loop + Yspeed);
    requestAnimationFram(() => {
        Node.style.top = nowY + 'px';
        Node.style.left = nowX + 'px';
        loop++;
        move();
    });
};

3. Мяч может пролететь мимо точки назначения

Согласно логике кода стоп-анимации, мяч может превысить целевую точку, которую мы установили, когда он движется в последний раз. В следующем решении setTimeOut мы остановим анимацию и уничтожим экземпляр. Решение заключается в следующем.

requestAnimationFram(() => {
    Node.style.top = Math.min(nowY, XEnd) + 'px';
    Node.style.left = Math.min(nowX, YEnd) + 'px';
    loop++;
    move();
});

Кстати: здесь вы можете использовать Math.min() или Math.max() для получения множества интересных анимаций, перейдите к своей собственнойОткройте для себя Новый Свет.

Как добиться эффекта размытия в движении

Достигается эффект динамического размытия, а качество изображения ограничено, пожалуйста, поймите

Общий эффект достигается, качество изображения ограничено, пожалуйста, поймите

Что такое размытие в движении?

Динамическое размытие, вот определение энциклопедии Baidu动态模糊或运动模糊(motion blur)是静态场景或一系列的图片像电影或是动画中快速移动的物体造成明显的模糊拖动痕迹。
Автор понимает, что это остаток зрительной информации, т.е.Визуальные источники текущего момента (такие как изображения, видео и мозговые добавки) содержат остаточную визуальную информацию из предыдущего момента.Какая от этого польза? Правильное размытие в движении приведет к непрерывной смене изображения.стать более плавным и естественным.

Как добиться размытия в движении?

Прежде всего, давайте сделаем метод исключения, мы не должны играть в кино...
Давайте посмотрим на эффект размытия в движении.造成明显的模糊拖动痕迹. То есть, если реализованы следы перетаскивания размытия, можно имитировать эффект динамического размытия. Итак, каков эффект перетаскивания размытия?

Это нормальная картина

Это размытое изображение движения

Автор считает, что эффект размытия в движении можно смоделировать какДобавьте несколько градиентов непрозрачности вокруг одного и того же элемента

Код

Прежде чем код будет реализован, нам сначала нужно определить, чего нам нужно достичь. Цельтесь в мяч в параболической анимации, т.е.Генерирует несколько шаров с градиентом прозрачности вокруг движущегося шара. Куда добавить мяч? Мысль автора такова,Вставьте шар остаточного изображения между двумя позициями шара в кадре..

упаковка первого шага

Оберните исходную реализацию в функцию

let animat = (初始位置, 结束位置) => {
    ...参数设定
    // 位置变换
    nowX += Xspeed; 
    nowY += (A * loop + Yspeed);
    requestAnimationFrame(() => {
        Node.style.top = nowY + 'px';
        Node.style.left = nowX + 'px';
        loop++;
        move();
    });
}

Цель очень проста, то есть сгенерированный остаточное изображение мяча также необходимо синхронизировать с исходной информацией о положении мяча.

Второй шаг — создание остаточных изображений.

Мышление: Положение каждого шара остаточного изображения должно быть связано с реальным мячом. (Естественная траектория мяча, заданная одним и тем же начальным значением, одинакова) Таким образом, мы не можем изменить реальное положение мяча, поэтому перевод кажется хорошим выбором.

let animat = (初始位置, 结束位置, 是否是残影) => {
    ...参数设定
    // 位置变换
    nowX += Xspeed; 
    nowY += (A * loop + Yspeed);
    requestAnimationFrame(() => {
        Node.style.top = nowY + 'px';
        Node.style.left = nowX + 'px';
        if (isShadow) {
            item.style.transform = `translate(${(0.5 * Xspeed)}px ,${-(0.5 * (A * loop + Yspeed))}px)`;
            item.style.opacity = 0.5;   
        }
    }
        loop++;
        move();
    });
}

На этом этапе следует отметить, чтоИзменения прозрачности имеют решающее значение. Значение прозрачности рекомендовано авторомМежду 0,1 и 0,5.

Третий шаг — создание нескольких остаточных изображений.

Если это просто маленький шарик, эффект размытия в движении не будет очевиден. Итак, нам нужно создать новую функцию, контролирующую количество мячей.

createShadow(初始位置, 结束位置,  num) {
    for (let i = 0; i < num; i++) {
        animat(初始位置, 结束位置, true, i / (num + 1));
    }
},

Измените функцию анимации на

let animat = (初始位置, 结束位置, 是否是残影, num) => {
    .....
    requestAnimationFrame(() => {
        ....
        if (isShadow) {
            item.style.transform = `translate(${-(num * Xspeed)}px ,${-(num * (A * loop + Yspeed))}px)`;
            item.style.opacity = (1 - num) * 0.5;   
        }
    }
    .....
    });
}

Готово.

заключительные замечания

Если у вас есть какие-либо сомнения по поводу этой статьи, вы не согласны с ней или у вас есть идеи получше, оставьте сообщение в области комментариев. Общайтесь вместе и добивайтесь прогресса вместе.