Как мне воспроизвести точную анимацию, сделанную в разделе героев flecto.io?

Я наткнулся на https://flecto.io(используйте VPN, если сайт не открывается), и сайт привлек мое внимание. Я хочу воспроизвести анимацию в разделе героев. Точнее, это та часть, где зеленый прямоугольник превратился в крестообразную форму.

Начальная форма

Окончательная форма (я удалил ненужные отвлекающие факторы)

Я понимаю, что это можно сделать с помощью плагина gsap morphSVG. Но я считаю, что использовать этот плагин для этой цели сложно. Вот ссылка на демо, над которым я работаю Здесь.

HTML

<div class = "container">
    <svg viewBox = "0 0 1900 1500" fill = "none">
      <g>
        <path id = "rectangle" d = "M0 0H1889V157V758V915H0V758V178.5V0Z" fill = "black"/>
       
         <path id = "final-stage" class = "hide" d = "M505.5 125.5H22.5H19C9.05887 125.5 1 133.559 1 143.5V774C1 783.941 9.05887 792 19 792H198.5C208.441 792 216.5 800.059 216.5 810V898C216.5 907.941 224.559 916 234.5 916H1426.5C1436.44 916 1444.5 907.941 1444.5 898V809.5C1444.5 799.559 1452.56 791.5 1462.5 791.5H1872C1881.94 791.5 1890 783.441 1890 773.5V144C1890 134.059 1881.94 126 1872 126H1385.5C1375.56 126 1367.5 117.941 1367.5 108V19C1367.5 9.05887 1359.44 1 1349.5 1H541.5C531.559 1 523.5 9.05888 523.5 19V107.5C523.5 117.441 515.441 125.5 505.5 125.5Z" fill = "black" stroke = "black" />
      </g>
    </svg>
  </div>

CSS

.container {
  width: 800px;
  height: 800px;
  display: flex;
  justify-content: center;
  align-items: center;
}
svg {
  width: 100%;
  height: 100%;
}

.hide {
  visibility: hidden;
}

Javascript (я использую плагин gsap и плагин gsap morphSVG в CodePen)

gsap.registerPlugin(MorphSVGPlugin);

// MorphSVGPlugin.defaultType = "rotational";

var tl = gsap.timeline();
const rectangle = document.getElementById("rectangle");

  tl.to(rectangle, { duration: 1, morphSVG: {shape: "#final-stage", shapeIndex: -2 }});

Вот мой результат https://streamable.com/mnh46o (в будущем этот контент может быть недоступен)

Дело в том, что после проверки сайта создатели не превратили прямоугольник в крест. Они разбили свою форму на более мелкие формы, состоящие из двух рамок разного телосложения.

Обратите внимание, что первый кадр представляет собой сплошную фигуру с вырезом креста, а второй представляет собой комбинацию нескольких фигур, образующих вырез креста. Почему они построили раздел героев таким образом? Мне еще предстоит это понять. Но я считаю, что именно этот метод делает их анимацию более плавной, чем мой метод преобразования SVG в крест.

Итак, что вы все думаете? Как я могу повторить этот дизайн? Какой лучший способ сделать это?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
116
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам нужны два пути; начальный и конечный путь. Анимацию можно создать с помощью CSS-анимации или SVG-анимации с SMIL.

В вашем коде в конечном пути 27 команд, поэтому в начальном пути у вас должно быть такое же количество команд.

Здесь я создал «грубую» версию, в которой начальный путь представляет собой просто квадрат, команды относительны, и большинство команд имеют просто нули. В готовой к эксплуатации версии вы должны согласовать все команды, чтобы они двигались правильно, а также сохранить закругленные углы.

path {
  d: path('m 1 1 h 0 h 0 c 0 0 0 0 0 0 v 915 c 0 0 0 0 0 0 h 1889 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v -915 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h -1889 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 z');
  animation-duration: 3s;
  animation-name: anim;
  animation-fill-mode: forwards;
}

@keyframes anim {
  from {
    d: path('m 1 1 h 0 h 0 c 0 0 0 0 0 0 v 915 c 0 0 0 0 0 0 h 1889 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v -915 c 0 0 0 0 0 0 h 0 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 h -1889 c 0 0 0 0 0 0 v 0 c 0 0 0 0 0 0 z');
  }
  to {
    d: path('M505.5 125.5H22.5H19C9.05887 125.5 1 133.559 1 143.5V774C1 783.941 9.05887 792 19 792H198.5C208.441 792 216.5 800.059 216.5 810V898C216.5 907.941 224.559 916 234.5 916H1426.5C1436.44 916 1444.5 907.941 1444.5 898V809.5C1444.5 799.559 1452.56 791.5 1462.5 791.5H1872C1881.94 791.5 1890 783.441 1890 773.5V144C1890 134.059 1881.94 126 1872 126H1385.5C1375.56 126 1367.5 117.941 1367.5 108V19C1367.5 9.05887 1359.44 1 1349.5 1H541.5C531.559 1 523.5 9.05888 523.5 19V107.5C523.5 117.441 515.441 125.5 505.5 125.5Z');
  }
}
<svg viewBox = "0 0 1900 1500">
  <path fill = "black" stroke = "black"/>
</svg>

Это очень мило. Хотя я не понимаю, что вы подразумеваете под командами. Вы сказали, что у меня 27 команд? Вы имеете в виду точки, использованные при формировании SVG? Мне удалось ввести ваш путь в текущий тест, и он работал точно так же, как ваш. Поэтому я считаю, что секрет заключается в том, как формируется путь. Как мне научиться прокладывать путь с помощью «команд». Если я смогу проложить путь так, чтобы начало и конец совпадали, я смогу постоянно получать лучшие результаты. Верно?

Etemire Ewoma 21.07.2024 20:15

@EtemireEwoma Команды — это точки пути. Почитайте про атрибут d . Я часто использую SvgPathEditor для создания и редактирования путей, но есть и другие.

chrwahl 21.07.2024 22:10

@chrwahi Теперь я понимаю, что ты имел в виду под командами. Мой последний вопрос: как узнать, как разместить команду как для начального, так и для финального SVG, чтобы переход от начала к финалу был плавным? Я создал несколько SVG, пытаясь получить идеальную команду, но транзакция между ними всегда плохая. Но вам удалось найти идеальное совпадение между первым и последним SVG. Как?

Etemire Ewoma 22.07.2024 20:05

@EtemireEwoma Я взял исходный конечный путь и вставил его в SvgPathEditor. Я изменил все команды на относительные и изменил все значения на ноль. Я видел, что путь идет против часовой стрелки, поэтому нашел команды v и h (вертикальные и горизонтальные линии) и изменил значение так, чтобы у меня получился квадрат. Я немного поэкспериментировал, потому что команд v и h больше... Я предлагаю вам начать все сначала и набросать все на бумаге, чтобы вы знали, сколько линий (используйте l для линии) и закругленных углов. (используйте c для кривой), которая вам нужна.

chrwahl 22.07.2024 22:13

Я знаю, что это мой второй ответ на этот вопрос, но я пересмотрел подход после более внимательного изучения веб-сайта, на который вы ссылаетесь.

В этом примере используется свойство CSS Mask, которое можно использовать для маскировки элемента. Самое замечательное в маске CSS заключается в том, что она имеет разные свойства по размеру, положению и т. д. Итак, в примере у меня есть анимация CSS для положения маски и изображение маски SVG, имеющее путь. Базовый SVG (верхний левый угол) выглядит так:

<?xml version = "1.0" encoding = "UTF-8"?>
<svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 400 100">
  <path d = "m 200 0 c -8 0 -10 2 -10 10 v 20 c 0 8 -2 10 -10 10
    h -170 c -8 0 -10 2 -10 10 v 50 h 400 v -100 z" fill = "black"/>
</svg>

И вот во фрагменте:

<svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 400 100">
  <path d = "m 200 0 c -8 0 -10 2 -10 10 v 20 c 0 8 -2 10 -10 10
    h -170 c -8 0 -10 2 -10 10 v 50 h 400 v -100 z" fill = "black"/>
</svg>

Полный пример выглядит так:

body {
  height: 200vh;
  margin: 0;
}

section {
  display: grid;
  grid-template-rows: 50px auto 50px;
  grid-template-columns: 200px auto 200px;
  height: calc(100vh - 1em);
  padding: .5em;
}

.cell {
  padding: 10px;
}

.topleft {
  grid-column: 1;
  grid-row: 1;
}

.topmiddle {
  background-color: SeaGreen;
  position: relative;
  grid-column: 2;
  grid-row: 1;
}

.topright {
  grid-column: 3;
  grid-row: 1;
}

.topmiddle:before {
  background-color: SeaGreen;
  width: 200px;
  height: 50px;
  display: block;
  position: absolute;
  top: 0;
  left: -200px;
  content: "";
  mask-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgMTAwIj4KICA8cGF0aCBkPSJtIDIwMCAwIGMgLTggMCAtMTAgMiAtMTAgMTAgdiAyMCBjIDAgOCAtMiAxMCAtMTAgMTAgaCAtMTcwIGMgLTggMCAtMTAgMiAtMTAgMTAgdiA1MCBoIDQwMCB2IC0xMDAgeiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+');
  mask-size: 400px;
  mask-repeat: no-repeat;
  mask-position: -200px -50px;
  animation-duration: 1s;
  animation-name: topleft;
  animation-fill-mode: forwards;
  animation-delay: 1s;
  border-radius: 10px 0 0 0;
}

.topmiddle:after {
  background-color: SeaGreen;
  width: 200px;
  height: 50px;
  display: block;
  position: absolute;
  top: 0;
  right: -200px;
  content: "";
  mask-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgMTAwIj4KICA8cGF0aCBkPSJtIDIwMCAwIGMgOCAwIDEwIDIgMTAgMTAgdiAyMCBjIDAgOCAyIDEwIDEwIDEwIGggMTcwIGMgOCAwIDEwIDIgMTAgMTAgdiA1MCBoIC00MDAgdiAtMTAwIHoiIGZpbGw9ImJsYWNrIi8+Cjwvc3ZnPg==');
  mask-size: 400px;
  mask-repeat: no-repeat;
  mask-position: 0px -50px;
  animation-duration: 1s;
  animation-name: topright;
  animation-fill-mode: forwards;
  animation-delay: 1s;
  border-radius: 0 10px 0 0;
}

@keyframes topleft {
  from {
    mask-position: -200px -50px;
  }
  to {
    mask-position: 0px 0px;
  }
}

@keyframes topright {
  from {
    mask-position: 0px -50px;
  }
  to {
    mask-position: -200px 0px;
  }
}

.fullmiddle {
  grid-column: 1 / span 3;
  grid-row: 2;
  background-color: SeaGreen;
}

.bottomleft {
  grid-column: 1;
  grid-row: 3;
}

.bottommiddle {
  background-color: SeaGreen;
  position: relative;
  grid-column: 2;
  grid-row: 3;
}

.bottomright {
  grid-column: 3;
  grid-row: 3;
}

.bottommiddle:before {
  background-color: SeaGreen;
  width: 200px;
  height: 50px;
  display: block;
  position: absolute;
  top: 0;
  left: -200px;
  content: "";
  mask-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgMTAwIj4KICA8cGF0aCBkPSJtIDIwMCAxMDAgYyAtOCAwIC0xMCAtMiAtMTAgLTEwIHYgLTIwIGMgMCAtOCAtMiAtMTAgLTEwIC0xMCBoIC0xNzAgYyAtOCAwIC0xMCAtMiAtMTAgLTEwIHYgLTUwIGggNDAwIHYgMTAwIHoiIGZpbGw9ImJsYWNrIi8+Cjwvc3ZnPg==');
  mask-size: 400px;
  mask-repeat: no-repeat;
  mask-position: -200px -50px;
  animation-duration: 1s;
  animation-name: bottomleft;
  animation-fill-mode: forwards;
  animation-delay: 1s;
  border-radius: 0 0 0 10px;
}

.bottommiddle:after {
  background-color: SeaGreen;
  width: 200px;
  height: 50px;
  display: block;
  position: absolute;
  top: 0;
  right: -200px;
  content: "";
  mask-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgMTAwIj4KICA8cGF0aCBkPSJtIDIwMCAxMDAgYyA4IDAgMTAgLTIgMTAgLTEwIHYgLTIwIGMgMCAtOCAyIC0xMCAxMCAtMTAgaCAxNzAgYyA4IDAgMTAgLTIgMTAgLTEwIHYgLTUwIGggLTQwMCB2IDEwMCB6IiBmaWxsPSJibGFjayIvPgo8L3N2Zz4=');
  mask-size: 400px;
  mask-repeat: no-repeat;
  mask-position: 0px 0px;
  animation-duration: 1s;
  animation-name: bottomright;
  animation-fill-mode: forwards;
  animation-delay: 1s;
  border-radius: 0 0 10px 0;
}

@keyframes bottomleft {
  from {
    mask-position: -200px -50px;
  }
  to {
    mask-position: 0px -50px;
  }
}

@keyframes bottomright {
  from {
    mask-position: 0px 0px;
  }
  to {
    mask-position: -200px -50px;
  }
}
<section>
  <div class = "cell topleft">topleft</div>
  <div class = "cell topright">topright</div>
  <div class = "cell topmiddle">topmiddle</div>
  <div class = "cell fullmiddle">
    <p>fullmiddle</p>
  </div>
  <div class = "cell bottomleft">bottomleft</div>
  <div class = "cell bottomright">bottomright</div>
  <div class = "cell bottommiddle">bottommiddle</div>
</section>

Это тоже очень приятно. Хотя я предпочитаю первый вариант из-за кастомизации. Вместо этого я использовал его с gsap morphSVG, и он работает хорошо. Мой план также предполагает выполнение аналогичных переходов между другими SVG. Спасибо

Etemire Ewoma 26.07.2024 03:05
Ответ принят как подходящий

Решение

Наконец-то я понял проблему, и вот мое решение. Благодаря ответу @chrwahi я смог понять, как это обойти.

Проблема

Проблема заключалась в анимации из одного SVG в другой. Размышляя об анимации между SVG, вам необходимо учитывать команды, используемые при создании каждого SVG. Транзакция от зеленого прямоугольника к зеленому кресту поначалу была для меня запутанной, потому что я анимировал прямоугольник с меньшими командами, чем крест.

Именно поэтому анимация была такой глючной.

Исправление

С помощью SVG-редактора вы можете увидеть все команды для пути как для креста, так и для прямоугольника.

Поигравшись с редактором я начал понимать, что сделал @chrwahi. Он использовал команды перекрестия, чтобы сформировать прямоугольник.

Обратите внимание, что это прямоугольник, но команды аналогичны кресту. Также обратите внимание, что точные значения некоторых команд для прямоугольника различаются. Изменяя значение команды так, чтобы SVG выглядел как прямоугольник, вы можете получить подходящий SVG, который можно плавно анимировать от прямоугольника к кресту.

Это означает, что крест имеет 27 команд (читайте об атрибуте d и командах здесь), а прямоугольник был построен в соответствии с 27 командами. Таким образом, настроив 27 команд креста для формирования прямоугольника, вы можете плавно анимировать прямоугольник в крест. Вот в чем секрет!

Примечание

Возможно, вам придется поэкспериментировать с этим подходом, чтобы получить анимацию без пола. Но эта идея должна направить вас на правильный путь.

Посмотрите окончательный результат на codepen (убедитесь, что вы используете вид слева/справа, а не вид сверху/снизу, изменив макет)

    // Please view the final result on codepen. I can't add a codepen link without adding codes. But this solution is not to showcase the code but to explain the idea.

Другие вопросы по теме