7

Необходимо создать SVG прелоадер для сайта, но не умею работать с самими SVG (рисовать правильно). Идея такая:

введите сюда описание изображения

При загрузке индикатором выступает градиентная полоска, которая постепенно заполняет объект, попыток решения нет, т.к. для этого нужно нарисовать саму SVG и как-то через path (наверно) выставлять уже значения заполнения.

Подскажите, как можно это сделать?

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • а как должны выглядеть другие кадры? почему линия скошенная, это имитация воды? – Stranger in the Q Aug 26 '19 at 17:03

3 Answers3

4

Вот вариант с маской, путь ровный т.к. подбирал точки дуги и кривой Безье перебором =)

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

requestAnimationFrame(frame);

function frame(t){ fill.setAttribute('stroke-dasharray', ${t/40} 1000); let p1 = fill.getPointAtLength(t/40); let p2 = fill.getPointAtLength(t/40+2); let dy = p2.y - p1.y; let dx = p2.x - p1.x; let a = dy - dx ? Math.atan2(dy, dx)180/Math.PI+90+Math.sin(t/280)20 : 90; end.setAttribute('transform', translate(${p1.x},${p1.y})rotate(${a})); requestAnimationFrame(frame); }

<svg viewbox=0,0,100,100 height=100vh>
  <defs>
    <linearGradient id="Grad1" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
        <stop offset="10%" stop-color="#D3D0FB" />
        <stop offset="100%" stop-color="#FDE4E2" />
    </linearGradient>
    <mask id="mask">
      <path stroke=white stroke-width=10 fill=none d='
        m20,80
        v-45
        a11,11,0,0,1,20,-5
        c5,5,5,35,10,40
        a11,11,0,0,0,20,-5
        v-45
      '></path>
    </mask>
  </defs>
  <rect width=100 height=100 mask=url(#mask) fill="url(#Grad1)"/>
  <path mask=url(#mask) id=fill stroke=blue stroke-width=11 fill=none d='
      m20,81
      v-46
      a11,11,0,0,1,20,-5
      c5,5,5,35,10,40
      a11,11,0,0,0,20,-5
      v-46
  '></path>
  <g mask=url(#mask)>
    <rect id=end fill=blue x=-10 y=-3 width=20 height=6></rect>
  </g>
</svg>
  • тут основная трудность закрасить фигуру SVG, которая имеет градиент. А для этого это должен быть замкнутый контур а не широкая, одиночная кривая линия, как в твоем примере. – Alexandr_TT Aug 26 '19 at 20:21
  • @Alexandr_TT теперь как надо – Stranger in the Q Aug 26 '19 at 20:38
  • нормально, на мой взгляд чуть медленнее надо – Alexandr_TT Aug 26 '19 at 20:40
  • @Андрей нет проблем, главное -разобрались, однако вариантов как это сделать -не один, как Вы догададись – Stranger in the Q Aug 27 '19 at 05:06
4

Решение SVG filter

Как возможный вариант решения, так как ТС не указал в деталях способ заполнения лоадера.

Горизонтальное заполнение:

.container {
width:50%;
height:50%;

} #path1 { fill:url(#Grad1); filter: url(#violet-fill);

}

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="286" height="274" viewBox="0 0 143 137" preserveAspectRatio="xMinYMin meet">
<defs>
 <linearGradient id="Grad1" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
        <stop offset="10%" stop-color="#D3D0FB" />
        <stop offset="100%" stop-color="#FDE4E2" />

      </linearGradient>

<filter  id="violet-fill" x="0%" y="0%">
      <feFlood flood-color="#5050E1" />
      <feOffset dx="-120">
        <animate
          id="anim"
          attributeName="dx"
          values="-120;0"
          dur="5s"
          begin="0s"
          repeatCount="indefinite"
          restart="whenNotActive"
          fill="freeze"/> 
      </feOffset>
      <feComposite operator="in" in2="SourceGraphic" />
      <feComposite operator="over" in2="SourceGraphic" />
    </filter> 

</defs>
<path id="path1" fill="url(#Grad1)" d="m17 108c0 0-0.2-31.9 0.4-49 1-29.5 40.3-35.3 47.7-11.3 2.7 8.8 8.1 29.3 12.4 36.5 9.9 16.9 24.1 7.7 24.2-0.4 0.1-13.4 0.1-49.5 0.1-49.5l13.8 0c0 0 0.7 34.5 0.4 49.7-0.2 8.9-5.8 19.6-14.2 22.8-18.6 7.2-32.6 2.1-40.8-22.8-2.9-8.7-3.5-11.5-7-25-3.5-13.4-21-13.4-22.6 0-1.3 11.4-0.2 48.2-0.2 48.2z" />


</svg>
</div>

Вертикальное заполнение:

.container {
width:50%;
height:50%;

} #path1 { fill:url(#Grad1); filter: url(#violet-fill);

}

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="286" height="274" viewBox="0 0 143 137" preserveAspectRatio="xMinYMin meet">
<defs>
 <linearGradient id="Grad1" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
        <stop offset="10%" stop-color="#D3D0FB" />
        <stop offset="100%" stop-color="#FDE4E2" />

      </linearGradient>

<filter  id="violet-fill" x="0%" y="0%">
      <feFlood flood-color="#5050E1" />
      <feOffset dy="-120">
        <animate
          id="anim"
          attributeName="dy"
          values="-120;0"
          dur="5s"
          begin="0s"
          repeatCount="indefinite"
          restart="whenNotActive"
          fill="freeze"/> 
      </feOffset>
      <feComposite operator="in" in2="SourceGraphic" />
      <feComposite operator="over" in2="SourceGraphic" />
    </filter> 

</defs>
<path id="path1" fill="url(#Grad1)" d="m17 108c0 0-0.2-31.9 0.4-49 1-29.5 40.3-35.3 47.7-11.3 2.7 8.8 8.1 29.3 12.4 36.5 9.9 16.9 24.1 7.7 24.2-0.4 0.1-13.4 0.1-49.5 0.1-49.5l13.8 0c0 0 0.7 34.5 0.4 49.7-0.2 8.9-5.8 19.6-14.2 22.8-18.6 7.2-32.6 2.1-40.8-22.8-2.9-8.7-3.5-11.5-7-25-3.5-13.4-21-13.4-22.6 0-1.3 11.4-0.2 48.2-0.2 48.2z" />


</svg>
</div>
Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
2

Может программу какую-нибудь посоветуете или что-то в этом роде? ресурс?

Чтобы нарисовать svg фигуру нужен векторный редактор или для рисования кривых Безье какой-нибудь генератор. В этом топике даны примеры и ссылки на подобного рода инструменты для рисования патчей.

Создание патча по заданной форме на рисунке:

  • Загружаем картинку кривой в векторный редактор и наносим узловые точки с помощью инструмента - Рисовать кривые Безье На рисунке это красные стрелки

введите сюда описание изображения

  • Рычагами управления (синие стрелки) придаем нужную форму кривой, чтобы она совпадала с контурами фигуры.
  • Сохраняем файл в формате *.svg
  • Добавляем градиент

.container {
width:50%;
height:50%;

} #path1 { fill:url(#Grad1); }

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="286" height="274" viewBox="0 0 143 137" preserveAspectRatio="xMinYMin meet">
<defs>
 <linearGradient id="Grad1" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
        <stop offset="10%" stop-color="#D3D0FB" />
        <stop offset="100%" stop-color="#FDE4E2" />
 </linearGradient>
</defs>
<path id="path1" fill="url(#Grad1)" d="m17 108c0 0-0.2-31.9 0.4-49 1-29.5 40.3-35.3 47.7-11.3 2.7 8.8 8.1 29.3 12.4 36.5 9.9 16.9 24.1 7.7 24.2-0.4 0.1-13.4 0.1-49.5 0.1-49.5l13.8 0c0 0 0.7 34.5 0.4 49.7-0.2 8.9-5.8 19.6-14.2 22.8-18.6 7.2-32.6 2.1-40.8-22.8-2.9-8.7-3.5-11.5-7-25-3.5-13.4-21-13.4-22.6 0-1.3 11.4-0.2 48.2-0.2 48.2z" />


</svg>
</div>

Создание анимации

Можно использовать анимацию с помощью изменения stroke-dashoffset от максимума до нуля.

Для создания path, кривой линии, вдоль которой будет идти анимация закраски фигуры, снова используем векторный редактор:

введите сюда описание изображения

Чтобы линия заполняла всю фигуру по ширине, задаем - stroke-width:15.5px;

.container {
width:50%;
height:50%;

}

#path2 { stroke-width:15.5; stroke:#5050E1; fill:none; stroke-dasharray: 240 240; stroke-dashoffset: 240; animation: draw 6s 1s ease infinite; }

@keyframes draw { from { stroke-dashoffset: 240; }

to { stroke-dashoffset: 0; } }
</style>

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="286" height="274" viewBox="0 0 143 137" preserveAspectRatio="xMinYMin meet">


<path id="path2" d="m23.2 107.6c0 0 0.4-31.5 0.2-48.6-0.2-24 32.7-26.2 39.9 0.4 2.4 8.8 3.1 16.6 5.8 24.6 7.8 23 39.2 23.8 39.1-0.4-0.1-17 0.3-47.7 0.3-47.7" />
</svg>
</div>

Собираем всё вместе

Фигуру svg c градиентом и анимацию её заполнения:

.container {
width:50%;
height:50%;

} #path1 { fill:url(#Grad1);

} #path2 { stroke-width:15.5; stroke:#5050E1; fill:none; stroke-dasharray: 240 240; stroke-dashoffset: 240; animation: draw 6s 1s ease infinite; }

@keyframes draw { from { stroke-dashoffset: 240; }

to { stroke-dashoffset: 0; } }

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="286" height="274" viewBox="0 0 143 137" preserveAspectRatio="xMinYMin meet">
<defs>
 <linearGradient id="Grad1" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
        <stop offset="10%" stop-color="#D3D0FB" />
        <stop offset="100%" stop-color="#FDE4E2" />

      </linearGradient>
</defs>
<path id="path1" fill="url(#Grad1)" d="m17 108c0 0-0.2-31.9 0.4-49 1-29.5 40.3-35.3 47.7-11.3 2.7 8.8 8.1 29.3 12.4 36.5 9.9 16.9 24.1 7.7 24.2-0.4 0.1-13.4 0.1-49.5 0.1-49.5l13.8 0c0 0 0.7 34.5 0.4 49.7-0.2 8.9-5.8 19.6-14.2 22.8-18.6 7.2-32.6 2.1-40.8-22.8-2.9-8.7-3.5-11.5-7-25-3.5-13.4-21-13.4-22.6 0-1.3 11.4-0.2 48.2-0.2 48.2z" />

<path id="path2" d="m23.2 107.6c0 0 0.4-31.5 0.2-48.6-0.2-24 32.7-26.2 39.9 0.4 2.4 8.8 3.1 16.6 5.8 24.6 7.8 23 39.2 23.8 39.1-0.4-0.1-17 0.3-47.7 0.3-47.7" />
</svg>
</div>
Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • Кривовато получается на сгибах.. Что если само "заполнение" сделать шире и поверх неё сделать маску формы? – De.Minov Aug 26 '19 at 19:32
  • @CbIPoK2513 нужно просто аккуратней нарисовать, а с маской хороший вариант, но её тоже нужно аккуратно нарисовать :) – Alexandr_TT Aug 26 '19 at 19:35
  • ну тогда проще просто аккуратнее нарисовать "заполнение")) – De.Minov Aug 26 '19 at 19:48
  • @Андрей Рад, что помогло и вам спасибо за интересный вопрос. Андрей, а ещё можно благодарить, отвечающих участников плюсиками, если понравились ответы. – Alexandr_TT Aug 27 '19 at 05:11