Как правильно задать центр вращения для анимации SVG элемента?

129
17 февраля 2021, 04:40

Есть rect, которому нужно задать анимацию поворота "туда-обратно", неважно через CSS-анимации или через SMIL, анимация всё равно простая. Но возникает трудность с определением точки, от которой производится поворот фигуры. Нужно чтобы он производился от середины нижней грани прямоугольника, но как определить эти координаты? Для наглядности я привёл свой ошибочный пример, где circle отображает точку от которой нужно совершить поворот.

<svg> 
  <style> 
    svg { 
      height: 300px; 
      width: 300px; 
      background-color: grey; 
    } 
    rect { 
      animation: anim 2s linear 3 alternate; 
    } 
    @keyframes anim { 
    0% {  transform-origin: 75% 75%; 
    transform: rotate(-15deg); } 
    100% { transform-origin: 75% 75%; 
    transform: rotate(15deg); } 
    } 
  </style> 
  <rect width="30" height="50" fill="black" x="150" y="120"/> 
  <circle r="3" cx="165" cy="170" fill="white"/> 
</svg>

Answer 1

Задайте transform-origin в пикселях, как и центр круга...

svg { 
  height: 300px; 
  width: 300px; 
  background-color: grey; 
} 
rect { 
  animation: anim 2s ease-in-out infinite; 
  transform-origin: 165px 170px; 
} 
@keyframes anim { 
  0%   {transform: rotate(-10deg)} 
  50%  {transform: rotate(370deg)} 
  100% {transform: rotate(-10deg)} 
}
<svg viewbox="100 100 140 140" style="height:90vh"> 
  <rect width="30" height="50" fill="black" x="150" y="120"/> 
  <rect width="30" height="50" fill="black" x="150" y="120" style="animation-delay:0.2s"/> 
  <rect width="30" height="50" fill="black" x="150" y="120"  style="animation-delay:0.4s"/> 
  <circle r="3" cx="165" cy="170" fill="white"/> 
</svg>

Answer 2

Вариант SVG smil

Но возникает трудность с определением точки, от которой производится поворот фигуры. Нужно чтобы он производился от середины нижней грани прямоугольника, но как определить эти координаты?

  • Определение координат центра вращения

Для прямоугольника <rect width="30" height="50" fill="black" x="150" y="120"/>

координата X - центра вращения: координата левого верхнего угла прямоугольника (x) + width/2

x = 150+30/2 = 165px

координата Y центра вращения:

y = 120 + 50 = 170px

  • Вращение одного прямоугольника

 svg { 
      height: 300px; 
      width: 300px; 
      background-color: grey; 
 
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
	     width="300" height="300" viewBox="0 0 300 300" >   
<circle r="3" cx="165" cy="170" fill="white"/> 
<rect id="rect1" width="30" height="50" fill="black" x="150" y="120"/>   
  <animateTransform  
   xlink:href="#rect1" 
   attributeName="transform" 
   type="rotate" 
   dur="4s" 
   values="0 165 170;360 165 170;0 165 170;0 165 170" 
   repeatCount="indefinite" 
</svg>	 

  • Вращение нескольких прямоугольников

Каждый прямоугольник поворачивается на разный угол.
Первый прямоугольник поворачивается на 45град, - values="0 160 170;45 160 170"
Второй на 90 град - values="0 160 170;90 160 170" и так далее

svg { 
      height: 45%; 
      width: 45%; 
      background-color: #d3d3d3;
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
	      viewBox="0 0 300 300" >    
		  
<rect id="rect1" fill="#485AE4" width="20" height="50"  x="150" y="120" rx="7"> 
</rect>  
    <rect id="rect2" fill="#DCE44C" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform   attributeName="transform"  type="rotate" begin="3s" dur="0.5s"  
        values="0 160 170;45 160 170" fill="freeze" />  
	</rect>  
<rect id="rect3" fill="#4EE9DF" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform   attributeName="transform"  type="rotate" begin="2.5s" dur="0.5s"  
        values="0 160 170;90 160 170" fill="freeze" />  
	 </rect>   
     <rect id="rect4" fill="purple" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform   attributeName="transform"  type="rotate" begin="2s" dur="0.5s"  
        values="0 160 170;135 160 170" fill="freeze" />  
	 </rect>  
  <rect id="rect5" fill="yellowgreen" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform   attributeName="transform"  type="rotate" begin="1.5s" dur="0.5s"  
        values="0 160 170;180 160 170" fill="freeze" />  
	 </rect>	  
<rect id="rect6" fill="dodgerblue" width="20" height="50"  x="150" y="120" rx="7">   
      <animateTransform   attributeName="transform"  type="rotate" begin="1s" dur="0.5s"  
      values="0 160 170;225 160 170" fill="freeze" />  
</rect> 
   <rect id="rect7" fill="gold" width="20" height="50"  x="150" y="120" rx="7">   
      <animateTransform   attributeName="transform"  type="rotate" begin="0.5s" dur="0.5s"  
      values="0 160 170;270 160 170" fill="freeze" />  
   </rect>    
  	  
<rect id="rect8" fill="red" width="20" height="50"  x="150" y="120" rx="7">   
  <animateTransform   attributeName="transform"  type="rotate" begin="0s" dur="0.5s"  
   values="0 160 170;315 160 170" fill="freeze"/>  
</rect>  
    
 
<circle r="4" cx="160" cy="170" fill="white"/> 
</svg>

Вариант открытия веером. Запуск анимации от кнопки "Start"

<style> 
    .container { 
	 width:50%; 
	 height:50% 
     	  } 
  svg {background-color: #d3d3d3;} 
	   
</style>	 
<div class="container">   
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
	     viewBox="0 0 300 300" >    
 
   
<rect id="rect1" fill="#485AE4" width="20" height="50"  x="150" y="120" rx="7"> 
</rect>  
    <rect id="rect2" fill="#DCE44C" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform id="an2"   attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
        values="0 160 170;45 160 170" fill="freeze" />  
	</rect>  
<rect id="rect3" fill="#4EE9DF" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform id="an3"   attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
        values="0 160 170;90 160 170" fill="freeze" />  
	 </rect>   
     <rect id="rect4" fill="purple" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform id="an4"   attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
        values="0 160 170;135 160 170" fill="freeze" />  
	 </rect>  
  <rect id="rect5" fill="yellowgreen" width="20" height="50"  x="150" y="120" rx="7">   
        <animateTransform id="an5"   attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
        values="0 160 170;180 160 170" fill="freeze" />  
	 </rect>	  
<rect id="rect6" fill="dodgerblue" width="20" height="50"  x="150" y="120" rx="7">   
      <animateTransform  id="an6" attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
      values="0 160 170;225 160 170" fill="freeze" />  
</rect> 
   <rect id="rect7" fill="gold" width="20" height="50"  x="150" y="120" rx="7">   
      <animateTransform  id="an7" attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
      values="0 160 170;270 160 170" fill="freeze" />  
   </rect>    
  	  
<rect id="rect8" fill="red" width="20" height="50"  x="150" y="120" rx="7">   
  <animateTransform   attributeName="transform"  type="rotate" begin="gr1.click" dur="0.8s"  
   values="0 160 170;315 160 170" fill="freeze"/>  
</rect>  
   
<circle r="4" cx="160" cy="170" fill="white"/> 
<g id="gr1" text-anchor="middle" >   
   <!-- кнопка --> 
 <rect id="rect1" x="0" y="0" width="100%" height="30"  fill="#1A2153"/> 
  <text id="txt1" x="150" y="22" font-size="28" stroke="white" fill="white"  pointer-events="none" > Start</text> 
  </g> 
 
</svg> 
</div>

READ ALSO
ul&gt;li&gt;a padding top/bottom

ul>li>a padding top/bottom

Пытался задать padding ссылке в списке, но работает только правый и левыйВерхний и нижний тоже задаётся, но ссылка не растягивает при этом высоту...

108
Как через js записать стиль css?

Как через js записать стиль css?

Я пробовал через documentwrite() записать в тег <style></style> стиль css, но не вышло

103
Двоичное дерево поиска. Почему вывод не упорядочен от меньшего к большему?

Двоичное дерево поиска. Почему вывод не упорядочен от меньшего к большему?

Вывод двоичного дерева поиска всегда упорядочен от наименьшего к большемуТо есть если дерево растянуть в прямую линию, слева будет наименьшее...

96
Массово изменять свойства QComboBox

Массово изменять свойства QComboBox

Имеется Ui-шка с некоторым количество набросанных comboBox на нейМне необходимо допустим в коде одновременно у всех поменять какое-либо свойство...

75