Анимация SVG по осям Z и X

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

Всем привет. Хочу анимировать полукруги, на css и js чтобы его элементы вращались в разных плоскостях. Если с z осью все понятно, то я с X не могу ничего придумать. Помогите, пожалуйста.


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

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

Решение на svg.

  1. Кольцо в горизонтальной плоскости релизовано через <ellipse> с анимацией stroke-dashoffset.
  2. Кольцо в профильной плоскости анимируется через scale. Есть нюанс с transform-origin для svg: вроде в Safari не работает.
  3. Вырез у фронтального и профильного колец на 1/4 сделан при помощи clip-path

<svg width="320" height="320" version="1.1" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg" fill="none">
    <clipPath id="myClip">
    <rect x="50%" y="0" width="50%" height="100%" fill="black"/>
    <rect x="0" y="50%" width="100%" height="50%" fill="black"/>
  </clipPath>
    <circle cx="160" cy="160" r="100" stroke="black" stroke-width="1" clip-path="url(#myClip)" style="transform-box: fill-box;transform-origin:center;">
        <animateTransform attributeName="transform" type="scale" begin="0" dur="2s" values="1 1;-1 1;1 1" repeatCount="indefinite" />
    </circle>
    <circle cx="160" cy="160" r="80" stroke="black" stroke-width="1" clip-path="url(#myClip)">
        <animateTransform attributeName="transform" type="rotate" begin="0" dur="2s" values="0 160 160;360 160 160" repeatCount="indefinite" />
    </circle>
    <ellipse cx="160" cy="160" rx="150" ry="42" stroke="black" stroke-width="3" stroke-dasharray="500 151.62">
        <animate attributeName="stroke-dashoffset" begin="0" dur="2s" values="0;-651.62"  repeatCount="indefinite" />
    </ellipse>
    <circle cx="160" cy="160" r="32" fill="orange" />
</svg>

Усложнённый вариант:

<svg width="320" height="320" version="1.1" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg" fill="none">
    <defs>
        <clipPath id="myClip">
            <rect x="50%" y="0" width="50%" height="100%" fill="black"/>
            <rect x="0" y="50%" width="100%" height="50%" fill="black"/>
        </clipPath>
        
        <!--маска для сокрытия кольца в горизонтальной плоскости-->
        <mask id="xmask" maskUnits="userSpaceOnUse">
            <rect width="100%" height="100%" fill="white"/>
            <circle cx="160" cy="160" r="32" fill="black" />
            <ellipse cx="160" cy="192" rx="150" ry="32" fill="white"/>
            <!-- Верстикальный радиус ry маскировочного эллипса по высоте круга. Смещение от центра на один радиус круга вниз. Так обеспечивается максимальное покрытие возможных значений ry маскируемого эллипса. -->
        </mask>
        
        <!--Динамическая обрезка кольца в профильной плоскости по контурам центрального круга -->
        <mask id="zmask" maskUnits="userSpaceOnUse">
            <rect width="100%" height="100%" fill="white"/>
            <circle cx="160" cy="160" r="32" fill="black">
                <animate attributeName="cx" begin="0" dur="8s" values="160;60;160;260;160"  repeatCount="indefinite" />
            </circle>
        </mask>
    </defs>
    
    
    <line x1="160" y1="40" x2="160" y2="60" stroke="black" />
    
    <circle cx="160" cy="160" r="32" fill="orange" />
    
    <circle cx="160" cy="160" r="100" stroke="black" stroke-width="1" clip-path="url(#myClip)" style="transform-box: fill-box;transform-origin:center;" mask="url(#zmask)">
        <animateTransform attributeName="transform" type="scale" begin="0" dur="8s" values="1 1;-1 1;1 1" repeatCount="indefinite" />
    </circle>
    <circle cx="160" cy="160" r="80" stroke="black" stroke-width="1" clip-path="url(#myClip)">
        <animateTransform attributeName="transform" type="rotate" begin="0" dur="8s" values="0 160 160;360 160 160" repeatCount="indefinite" />
    </circle>
    
    <ellipse cx="160" cy="160" rx="150" ry="20" stroke="black" stroke-width="3" stroke-dasharray="460 155.304" mask="url(#xmask)">
        <animate attributeName="stroke-dashoffset" begin="0" dur="8s" values="0;-615.304"  repeatCount="indefinite" />
        <!-- 615.304 - это длина обводки эллипса. Можно вычислить js-методом domNode.getTotalLength(); -->
    </ellipse>
    
</svg>

Предложу решение на css как более присспособленное для 3d-трансормаций и в данном случае более кроссбраузерное.

@keyframes rotate {
  from {
    transform: rotate(0)
  }
  to {
    transform: rotate(360deg)
  }
}

@keyframes rotateY {
  from {
    transform: rotate3d(0, 1, 0, 0)
  }
  to {
    transform: rotate3d(0, 1, 0, 360deg)
  }
}

.planet {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  position: relative;
  margin: 10px auto;
  background: radial-gradient(circle at center, orange 30%, transparent 0);
}

.planet:before,
.planet:after {
  content: '';
  display: block;
  position: absolute;
  border-radius: 50%;
  border: 1px solid black;
  clip-path: polygon(0 50%, 50% 50%, 50% 0, 100% 0, 100% 100%, 0 100%);
}

.planet:before {
  width: 80%;
  height: 80%;
  top: 10%;
  left: 10%;
  animation: rotate 2s linear infinite;
}

.planet:after {
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  animation: rotateY 2s linear infinite;
}

.planet__ring {
  position: absolute;
  width: 150%;
  height: 150%;
  left: -25%;
  top: -25%;
  transform: rotate3d(1, 0, 0, 70deg);
}

.planet__ring:before {
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 3px solid black;
  border-top-color: transparent;
  animation: rotate 2s linear infinite;
}
<div class="planet">
  <div class="planet__ring"></div>
</div>

→ Ссылка