Выполнение анимации SVG вдоль пути

229
23 апреля 2018, 23:37

У меня есть SVG-файл, который представляет собой плоскую фигуру.
Я хотел бы создать анимацию, чтобы фигура постепенно появлялась.
Такой пример анимации, как с логотипом «S» от бренда Samsung Galaxy S: https://codepen.io/anon/pen/MGawzy

@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 
   xmlns:dc="http://purl.org/dc/elements/1.1/" 
   xmlns:cc="http://creativecommons.org/ns#" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
   xmlns:svg="http://www.w3.org/2000/svg" 
   xmlns="http://www.w3.org/2000/svg" 
   xml:space="preserve" 
   enable-background="new 0 0 841.89 595.28" 
   viewBox="0 0 172.22023 242.623" 
   height="242.623" 
   width="172.22023" 
   y="0px" 
   x="0px" 
   id="Layer_1" 
   version="1.1"><metadata 
   id="metadata183"><rdf:RDF><cc:Work 
       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type 
         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs 
   id="defs181"> 
	 
			 
		</defs> 
<path 
   d="m 118.47279,116.80051 c -0.66437,0.0302 -16.42393,1.41842 -33.508628,3.99025 -14.046204,2.10151 -21.705778,1.74314 -26.785987,1.07134 C 47.450313,120.0293 40.205108,115.79638 37.678081,109.00284 28.977095,85.602387 79.350162,40.89571 150.20833,9.15625 157.64779,5.82666 164.98264,2.777 172.22023,0 159.60363,4.02397 146.54657,8.74193 133.2581,14.15446 53.669005,46.54682 -3.4079733,91.063371 5.7521203,113.5978 c 4.6211097,11.35868 25.2070687,14.94208 54.6918287,11.57516 0.05177,-0.01 0.122937,-0.01 0.178963,-0.01 17.15178,-1.60883 37.685548,-5.86787 50.406688,-4.83764 12.38894,1.53042 20.76507,5.90142 23.51606,13.30341 8.6938,23.39979 -41.686817,68.09918 -112.537605,99.84973 C 14.594923,236.80366 7.2340098,239.86079 0,242.623 c 12.616586,-4.00147 25.673652,-8.74948 38.965851,-14.147 79.585309,-32.38135 136.662329,-76.90897 127.498439,-99.45087 -4.25138,-10.46653 -22.1089,-14.33738 -47.9915,-12.22462 z" 
   id="path85" 
   style="fill:#000000;stroke-width:3.73272276" /> 
 
 
</svg>

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

Но если у меня очень сложная форма, которую я не могу анимировать, например, как это - (возможно, красная линия на эмблеме НАСА: https://upload.wikimedia.org/wikipedia/commons/e/e5/NASA_logo.svg), то нужно лучшее решение, чем у меня.

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

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

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

Примечание переводчика:
В данном топике применена оригинальная техника, которая позволяет анимировать рисование фигур с разной шириной на отдельных участках. Использовать технику рисования линий с изменением значений атрибута патча stroke-dashofset в данном примере не получится, так как нужно прорисовывать не контур фигуры, а сразу всю ширину.
Но одновременное применение масок и изменение stroke-dashoffset даёт нужный результат.
Берите данную технику на вооружение.

Answer 1

Вариант CSS

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

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

.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>

Answer 2

Вариант SVG

Переносим анимацию из стилей непосредственно в патчи масок и фигур.

Команды реализующие анимацию однотипны для всех патчей:

<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>

READ ALSO
Выровнять текст [требует правки]

Выровнять текст [требует правки]

http://prntscrcom/j8jct1 как можно выравнять текст по правому краю, чтобы буква отзыВ была на равне с буквой работЕ

205
Фиксированная подсказка в input

Фиксированная подсказка в input

Как можно сделать так, чтобы Ваше имя было постоянно, например:

194
Не отображается коллекция в template angularjs

Не отображается коллекция в template angularjs

Здравствуйте, недавно начала изучать angularjs и столкнулась с трудностьюСоздала отдельный компонент для формы некой сущности (поля: объект,...

210