Создание прелоадера SVG не круглой формы

102
21 июня 2021, 19:30

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

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

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

Answer 1

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

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

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>

Answer 2

Решение 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>

Answer 3

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

Чтобы нарисовать 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>

READ ALSO
Как сверстать стул как на картинке?

Как сверстать стул как на картинке?

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

106
библиотека fullpage js

библиотека fullpage js

Скачал и подключил библиотеку fullpagejs, в консоль пишет

108
Почему не применяются стики к тексту input type=email который выбираю из всплывающих подсказок?

Почему не применяются стики к тексту input type=email который выбираю из всплывающих подсказок?

После того как я получаю ответ от сервера с ошибкойЯ присваиваю

113
Как создать мобильную версию сайта

Как создать мобильную версию сайта

Мне нужно создать мобильную версию сайта, которая кардинально отличается от компьютерной по верстке и cssЭто не просто адаптивный шаблон

123