SVG Как отобразить несколько путей и вращать их вокруг центра?

Я пытаюсь определить "шаблон" с path в defs и повторно использовать его.
Я хочу, чтобы пути вращались вокруг центра с равным интервалом между ними.

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

Вот, что у меня получилось. Красная точка — центр вращения.

Ниже мой код:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
        <rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
        
       <defs>
            <path id="rotor" d="M140,140 
                   c0,0,-40,-20,-100,0
                   c0,0,50,-10,50,20
                   c0,0,0,-5,50,-20"  
                fill="none" 
                stroke-width="2" 
                stroke="white"/>
        </defs>

        <g>
          <use href="#rotor" x="-2" y="0"/>          
          <use href="#rotor" x="54" y="-160" transform="rotate(50)"/> 
          <use href="#rotor" x="-32" y="-305" transform="rotate(100)"/>  
          <use href="#rotor" x="-198" y="-332" transform="rotate(150)"/>    
          <use href="#rotor" x="-326" y="-223" transform="rotate(200)"/>   
          <use href="#rotor" x="-325" y="-55" transform="rotate(250)"/>    
          <use href="#rotor" x="-195" y="53" transform="rotate(300)"/>    
        </g>

        <circle cx="150" cy="150" r="2" fill="red"></circle>
    </svg>

Как сделать в SVG, чтобы пути вращались вокруг центра с равным интервалом между ними.

Свободный перевод вопроса SVG: How can I display multiple paths and rotate them around the center? от участника @S Mxller.


Ответы (3 шт):

Автор решения: Alexandr_TT

Вам необходимо указать центр вращения для поворота одного фрагмента.
Вы можете использовать атрибут transform-origin или свойство CSS, или вы можете указать эту точку в атрибуте rotate() напрямую как 2. и 3. аргументы, например, rotate(50 150 150).

Кроме того, вы можете настроить положение формы ротора, отрегулировав первые координаты в атрибуте d атрибута path (M150 150).

Таким образом, вам не нужны дополнительные смещения x и y для каждого экземпляра . Мы можем переместить весь path таким образом, потому что он основан на относительных командах. Если вы не уверены, является ли ваш путь полностью относительным, вы можете преобразовать данные пути с помощью инструмента вроде svg-path-editor

M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
    <rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
    
   <defs>
        <path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20"  
            fill="none" 
            stroke-width="2" 
            stroke="white"/>
     <style>
    </defs>

    <g >
      <use href="#rotor" />          
      <use href="#rotor"  transform="rotate(50 150 150)" /> 
      <use href="#rotor"  transform="rotate(100 150 150)"/>  
      <use href="#rotor"  transform="rotate(150 150 150)"/>    
      <use href="#rotor"  transform="rotate(200 150 150)"/>   
      <use href="#rotor"  transform="rotate(250 150 150)"/>    
      <use href="#rotor"  transform="rotate(300 150 150)"/>    
    </g>

    <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

Использование CSS transform-origin

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
    <rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
    
   <defs>
        <path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20"  
            fill="none" 
            stroke-width="2" 
            stroke="white"/>
     <style>
      
       use{
         transform-origin: 150px 150px;
       }
       
     </style>
    </defs>

    <g >
      <use href="#rotor" />          
      <use href="#rotor"  transform="rotate(50)" /> 
      <use href="#rotor"  transform="rotate(100)"/>  
      <use href="#rotor"  transform="rotate(150)"/>    
      <use href="#rotor"  transform="rotate(200)"/>   
      <use href="#rotor"  transform="rotate(250)"/>    
      <use href="#rotor"  transform="rotate(300)"/>    
    </g>

    <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

Вращение с большим количеством стилей CSS

Расчет угла немного странный — 7 лопастей ротора со смещением в 50 градусов не очень хорошо совпадают (покрывают только 350 градусов).

Кроме того, вы можете легко избежать использования фонового элемента <rect>, применив фон непосредственно к самому внешнему элементу SVG.

:root {
  --blades: 7;
  --blade: 0;
}

/* base style for rotor blades */
.b {
  transform-origin: 150px 150px;
  stroke-width: 2px;
  stroke: #fff;
  transform: rotate(calc(360deg / var(--blades) * var(--blade)));
}


.b1 {
  --blade: 1;
}

.b2 {
  --blade: 2;
}

.b3 {
  --blade: 3;
}

.b4 {
  --blade: 4;
}

.b5 {
  --blade: 5;
}

.b6 {
  --blade: 6;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300" style="background:#0B3E27">
  <defs>
    <path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20" />
  </defs>
  <!-- rotor blades -->
  <use class="b b0" href="#rotor"/>
  <use class="b b1" href="#rotor"/>
  <use class="b b2" href="#rotor"/>
  <use class="b b3" href="#rotor"/>
  <use class="b b4" href="#rotor"/>
  <use class="b b5" href="#rotor"/>
  <use class="b b6" href="#rotor"/>
</svg>

Свободный перевод ответа от участника @herrstrietzel

→ Ссылка
Автор решения: Alexandr_TT

@herrstrietzel дал вам совершенно правильный ответ. Это другой подход:

  1. Я изменяю атрибут d пути так, чтобы он начинался с 0,0. Поскольку путь полностью относительный, мне нужно изменить только первые 2 значения после команды M.

d="M0,0 c0,0,-40,-20,-100,0 c0,0,50,-10,50,20 c0,0,0,-5,50,-20 z"

  1. Поскольку я хочу, чтобы он находился на расстоянии 10 единиц от центра (красной точки), я меняю первое значение на -10.

d="M-10,0 c0,0,-40,-20,-100,0 c0,0,50,-10,50,20 c0,0,0,-5,50,-20 z"

  1. Далее я использую «ротор» несколько раз, каждый раз вращая элемент transform="rotate(60)". Вращение происходит вокруг точки 0,0.
  2. Я перемещаю всю группу, где нужно. В данном случае точка 150,150
    <g transform="translate(150 150)">

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <rect x="0" y="0" width="300" height="300" fill="#0B3E27" />

  <defs>
    <path id="rotor" d="M-10,0 
               c0,0,-40,-20,-100,0
               c0,0,50,-10,50,20
               c0,0,0,-5,50,-20 z" fill="none" stroke-width="2" stroke="white" />
  </defs>



  <g transform="translate(150 150)">
    <use href="#rotor" />
    <use href="#rotor" transform="rotate(60)" />
    <use href="#rotor" transform="rotate(120)" />
    <use href="#rotor" transform="rotate(180)" />
    <use href="#rotor" transform="rotate(240)" />
    <use href="#rotor" transform="rotate(300)" />
    <use href="#rotor" transform="rotate(300)" />
  </g>

  <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

Свободный перевод ответа от участника @enxaneta.

→ Ссылка
Автор решения: Alexandr_TT

Ответ на комментарий

Так как это перевод вопроса с EnSo я не имею права, по крайней мере этического, исправлять авторский код, поэтому вынужден дать отдельный ответ.

почему в группе 7 листков а отображается 6?

Кратко:
Последняя строка повторяется дважды:

<use href="#rotor" transform="rotate(300)" />
    <use href="#rotor" transform="rotate(300)" />   

Её можно либо удалить, результат будет тот же:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <rect x="0" y="0" width="300" height="300" fill="#0B3E27" />

  <defs>
    <path id="rotor" d="M-10,0 
               c0,0,-40,-20,-100,0
               c0,0,50,-10,50,20
               c0,0,0,-5,50,-20 z" fill="none" stroke-width="2" stroke="white" />
  </defs>



  <g transform="translate(150 150)">
    <use href="#rotor" />
    <use href="#rotor" transform="rotate(60)" />
    <use href="#rotor" transform="rotate(120)" />
    <use href="#rotor" transform="rotate(180)" />
    <use href="#rotor" transform="rotate(240)" />
    <use href="#rotor" transform="rotate(300)" />
      </g>

  <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

Либо оставить, для наглядности я добавил последней строке другой стиль:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <rect x="0" y="0" width="300" height="300" fill="#0B3E27" />

  <defs>
    <path id="rotor" d="M-10,0 
               c0,0,-40,-20,-100,0
               c0,0,50,-10,50,20
               c0,0,0,-5,50,-20 z" fill="none" stroke="white" />
  </defs>



  <g transform="translate(150 150)">
    <use href="#rotor" />
    <use href="#rotor" transform="rotate(60)" />
    <use href="#rotor" transform="rotate(120)" />
    <use href="#rotor" transform="rotate(180)" />
    <use href="#rotor" transform="rotate(240)" />
    <use href="#rotor" transform="rotate(300)" />
    <use href="#rotor" transform="rotate(360)" style=" stroke-width:2; stroke-dasharray:4 4" />
  </g>

  <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

То есть последняя позиция лепестка накладывается сверху на первую позицию, которая была задана в секции <defs>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <rect x="0" y="0" width="300" height="300" fill="#0B3E27" />

  <defs>
    <path id="rotor" d="M-10,0 
               c0,0,-40,-20,-100,0
               c0,0,50,-10,50,20
               c0,0,0,-5,50,-20 z" fill="none" stroke="white" />
  </defs>

  <g transform="translate(150 150)">
    <use href="#rotor" />
    
  </g>

  <circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>

→ Ссылка