Анимация SVG выполняется линейно вдоль длины пути

nulldev спросил: 28 марта 2018 в 01:44 в: css

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

Пример того, что я говорю с логотипом 'S' от Samsung Galaxy S https://codepen.io/anon/pen/MGawzy

Анимационный код (потому что StackOverflow заставляет меня включать его):

@keyframes test {
  0% {
    clip-path: inset(0px 0px 300px 0px);
  }
  80% {
    clip-path: inset(0px 0px 0px 0px);
  }
  100% {
    clip-path: inset(0px 0px 0px 0px);
  }
}svg {
  animation: test;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

Простой SVG в приведенном выше примере легко оживить, я могу просто медленно обрезать SVG сверху вниз. Но если у меня очень сложная форма, которая не может быть анимирована таким образом (возможно, красная линия в логотипе NASA: https://upload.wikimedia.org/wikipedia/commons/e/e5/NASA_logo.svg), мне нужно лучшее решение.

Чтобы снова прояснить, я не хочу анимировать удар. Я хочу, чтобы иметь возможность анимировать заполнение, как будто оно начинается.

Есть ли общее решение для этого? Если общего решения нет, как бы я мог сделать это самостоятельно в разумные сроки?

EDIT: Чтобы дать некоторое представление, я пытаясь оживить скрипичный ключ: https://upload.wikimedia.org/wikipedia/commons/e/e8/G-clef.svg

2 ответа

Есть решение
ccprog ответил: 28 марта 2018 в 04:28

Вы можете сделать это (проще описать, чем сделать, так как это требует много работы):

  1. Нарисуйте плавный контур поверх фигуры, который следует тому, что вы считаете "Путь" и выберите такую ​​ширину штриха, чтобы траектория покрывала фигуру повсюду.
  2. Я бы полностью исключил последнюю точку, поскольку она намного толще остальных.
  3. Разделите путь таким образом, чтобы он не имел перекрывающихся частей. Расположите детали в порядке отрисовки, убедитесь, что каждый частичный путь нарисован в правильном направлении.
  4. Теперь разделите фигуру таким же образом, убедившись, что каждая часть находится точно под контуром сверху.
  5. Свяжите каждую из фигур с одним из путей сверху, определив путь в качестве маски для фигуры. Путь должен иметь stroke:white. Сохранить порядок.
  6. Теперь вы можете анимировать пути, определяющие маски, с помощью анимации stroke-dashoffset.
  7. Я бы просто скрывал последнюю точку до псевдолинии. анимация завершается, а затем сразу ее раскрывает.

Edit: Сегодня у меня определенно слишком много времени, вот рабочий результат:

.clef {
    fill: black;
    stroke: black;
    stroke-width: 0.1;
}
mask path {
    fill: none;
    stroke: white;
    stroke-width: 6;
}
#mask1 path {
    stroke-dasharray: 100.8186 100.8186;
    stroke-dashoffset: 100.8186;
    animation: draw1 1s linear forwards;
}
@keyframes draw1 {
    from { stroke-dashoffset: 100.8186; }
    to { stroke-dashoffset: 0; }
}
#mask2 path {
    stroke-dasharray: 83.6713 83.6713;
    stroke-dashoffset: 83.6713;
    animation: draw2 1s 1s linear forwards;
}
@keyframes draw2 {
    from { stroke-dashoffset: 83.6713; }
    to { stroke-dashoffset: 0; }
}
.dot {
    opacity: 0;
    animation: reveal 0s 2.5s forwards;
}
@keyframes reveal {
    from { opacity: 0; }
    to { opacity: 1; }
}
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="200" viewBox="0 0 44 75">
  <defs>
  <mask id="mask1" maskUnits="userSpaceOnUse">
      <path d="M 24.3018,49.658 C 15.0191,46.9092 18.5393,38.1126 25.6256,38.2163 35.5458,38.3614 34.8431,54.3874 22.6943,54.1023 12.0123,53.8516 7.34095,40.0402 18.4391,30.1787 29.5373,20.3173 29.9235,12.5622 27.8005,9.28112" />
  </mask>
  <mask id="mask2" maskUnits="userSpaceOnUse">
      <path d="M 27.8005,9.28112 C 25.1382,5.16638 17.6602,8.86888 20.5194,22.1412 L 28.1788,57.6956 C 31.6264,73.699 16.4903,72.3627 15.035,62.329" />
  </mask>
  </defs>
  <path class="clef" mask="url(#mask1)" d="M 26.8522,9.90048 C 26.912,9.95039 26.9649,10.0085 27.0101,10.075 27.4815,10.7683 28.6214,14.0098 25.3767,19.8157 22.846,24.3437 11.0718,30.2815 10.2077,40.9075 9.45969,50.1477 19.1325,56.9723 27.4811,54.2894 33.0239,52.5081 35.8812,44.0959 32.4504,39.7568 23.3964,28.3057 8.87616,45.8309 22.9422,50.6319 21.4126,49.4286 20.37,48.4968 20.1759,47.3578 18.286,36.2692 34.9591,39.1968 30.4666,49.7165 28.6194,54.0421 21.1577,54.879 16.9085,51.0198 13.3489,47.787 11.7693,41.5593 15.7305,37.0885 21.0956,31.0332 27.4302,25.5974 29.1125,17.3081 29.7841,13.9988 29.4887,10.9357 28.6445,8.70078 Z" />
  <path class="clef" mask="url(#mask2)" d="M 15.7311,63.3465 C 15.3353,65.46 17.5402,69.8491 21.9764,69.9924 27.3392,70.1658 30.7655,66.0634 29.1692,59.3682 L 21.164,22.4229 C 20.2111,18.0249 20.9262,15.6394 21.4351,14.2178 22.7185,10.6326 25.8192,9.03863 26.8522,9.90048 L 28.6445,8.70078 C 26.9883,4.31578 23.2199,3.11893 20.4997,9.50576 19.1217,12.7412 18.6085,15.989 19.9279,22.2128 L 27.9268,59.9444 C 28.4995,62.6457 28.1161,66.3629 25.595,68.0714 24.3461,68.9177 19.9267,69.5001 18.8455,67.48" />
  <path class="clef dot" d="M 15.6702,63.6634 A 3.77139,3.8362 1.075 0 1 19.5129,59.8986 3.77139,3.8362 1.075 0 1 23.2116,63.8049 3.77139,3.8362 1.075 0 1 19.3689,67.5697 3.77139,3.8362 1.075 0 1 15.6702,63.6634 Z" />
</svg>
nulldev ответил: 28 марта 2018 в 05:53
Вау, это очень хорошо сделано! Спасибо вам большое!
Alexandr_T ответил: 08 апреля 2018 в 04:19

SVG решение

В этом примере используются решения из ответа @ccprog, но анимация перемещается из правил CSS непосредственно в SVG Команды анимации

Команды, которые реализуют анимацию, одинаковы для всех патчей. Разница в числовом значении атрибутов stroke-dasharray и stroke-dashoffset для каждого исправления:

<animate attributeName="stroke-dashoffset" dur="1s" values="100.8186;0" fill="freeze" />

команда анимации для появления точки на конце скрипичного ключа:

<animate attributeName="opacity" dur="0.05s" values="0;1" begin="an2.end-0.05s" fill="freeze" />

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="200" viewBox="0 0 44 75">
  <defs>
    <mask id="mask1" maskUnits="userSpaceOnUse">
      <path fill="none" stroke="white" stroke-width="6" stroke-dasharray="100.8186" stroke-dashoffset="100.8186" d="M 24.3018,49.658 C 15.0191,46.9092 18.5393,38.1126 25.6256,38.2163 35.5458,38.3614 34.8431,54.3874 22.6943,54.1023 12.0123,53.8516 7.34095,40.0402 18.4391,30.1787 29.5373,20.3173 29.9235,12.5622 27.8005,9.28112">
        <animate attributeName="stroke-dashoffset" dur="1s" values="100.8186;0" fill="freeze"/>
      </path>
    </mask>
    <mask id="mask2" maskUnits="userSpaceOnUse">
      <path fill="none" stroke="white" stroke-width="6" stroke-dasharray="83.6713" stroke-dashoffset="83.6713" d="M 27.8005,9.28112 C 25.1382,5.16638 17.6602,8.86888 20.5194,22.1412 L 28.1788,57.6956 C 31.6264,73.699 16.4903,72.3627 15.035,62.329" >
        <animate id="an2" attributeName="stroke-dashoffset" dur="1s" values="83.6713;0" begin="+1s" fill="freeze"/>
      </path>
    </mask>
  </defs>
  <path class="clef" fill="black" stroke="black" stroke-width="0.1" mask="url(#mask1)" d="M 26.8522,9.90048 C 26.912,9.95039 26.9649,10.0085 27.0101,10.075 27.4815,10.7683 28.6214,14.0098 25.3767,19.8157 22.846,24.3437 11.0718,30.2815 10.2077,40.9075 9.45969,50.1477 19.1325,56.9723 27.4811,54.2894 33.0239,52.5081 35.8812,44.0959 32.4504,39.7568 23.3964,28.3057 8.87616,45.8309 22.9422,50.6319 21.4126,49.4286 20.37,48.4968 20.1759,47.3578 18.286,36.2692 34.9591,39.1968 30.4666,49.7165 28.6194,54.0421 21.1577,54.879 16.9085,51.0198 13.3489,47.787 11.7693,41.5593 15.7305,37.0885 21.0956,31.0332 27.4302,25.5974 29.1125,17.3081 29.7841,13.9988 29.4887,10.9357 28.6445,8.70078 Z"/>
  <path class="clef" fill="black" stroke="black" stroke-width="0.1" mask="url(#mask2)" d="M 15.7311,63.3465 C 15.3353,65.46 17.5402,69.8491 21.9764,69.9924 27.3392,70.1658 30.7655,66.0634 29.1692,59.3682 L 21.164,22.4229 C 20.2111,18.0249 20.9262,15.6394 21.4351,14.2178 22.7185,10.6326 25.8192,9.03863 26.8522,9.90048 L 28.6445,8.70078 C 26.9883,4.31578 23.2199,3.11893 20.4997,9.50576 19.1217,12.7412 18.6085,15.989 19.9279,22.2128 L 27.9268,59.9444 C 28.4995,62.6457 28.1161,66.3629 25.595,68.0714 24.3461,68.9177 19.9267,69.5001 18.8455,67.48"/>
  <path class="clef dot" opacity="0" d="M 15.6702,63.6634 A 3.77139,3.8362 1.075 0 1 19.5129,59.8986 3.77139,3.8362 1.075 0 1 23.2116,63.8049 3.77139,3.8362 1.075 0 1 19.3689,67.5697 3.77139,3.8362 1.075 0 1 15.6702,63.6634 Z">
    <animate attributeName="opacity" dur="0.05s" values="0;1" begin="an2.end-0.05s" fill="freeze"/>
  </path>
</svg>

Обновление SMIL SVG не работает в IE/Edge - caniuse

Arthur ответил: 29 марта 2018 в 05:20
Хороший ответ! =))
ccprog ответил: 08 апреля 2018 в 07:10
Использование SMIL-анимации всегда сопровождается тем, что они не работают в Edge / IE.
Alexandr_T ответил: 08 апреля 2018 в 04:17
@ccprog Справедливости ради, ваше решение не работает в IE11 У меня нет возможности проверить, работает ли оно в `Edge`
ccprog ответил: 09 апреля 2018 в 12:24
developer.microsoft.com/en-us/microsoft-edge/platform/status/...