Я пытаюсь заставить объект в анимированном изображении SVG двигаться по идеальному синусоидальному движению по одной оси (вверх и вниз или влево и вправо). Например: x(t) = a + b * sin(t * 2PI*f)
(Я также пытаюсь анимировать таким образом один атрибут сплайна, но это кажется еще сложнее или невозможным).
Я знаю, что для облегчения движения можно использовать сплайны, но это лишь приближение. Мне нужен идеальный синус.
Я попробовал несколько вещей:
Сначала я попытался заставить animateMotion следовать по эллиптической траектории. Вы можете использовать два эллипса, чтобы создать идеальный круг. Проблема в том, что он линейно движется по своей траектории. Поэтому, если вы установите нулевую ширину или высоту, движение будет линейным!
Во-вторых, я попытался растянуть движение, масштабируя ширину окна просмотра независимо от высоты. Это правильно масштабирует движение, а также объект. Вы можете компенсировать масштабирование объекта, масштабируя объект с обратным масштабированием, но вы никогда не сможете добиться того, чтобы это масштабирование достигло 0, поскольку для этого потребуется объект конечного размера. Ниже приведен мой фрагмент кода, который делает это
<svg viewBox = "0 0 5000 5000" width = "2000" height = "200" preserveAspectRatio = "none">
<path d = "M25,-250v500h-50v-500z">
<animateMotion path = "M1000,600 A200,200 0 1 1 300,600 A200,200 0 1 1 1000,600"
width = "5000"
height = "500"
preserveAspectRatio = "none"
begin = "0s" dur = "3s" repeatCount = "indefinite"/>
</path>
<path d = "M1000,600 A200,200 0 1 1 300,600 A200,200 0 1 1 1000,600" fill = "none"
stroke = "black" stroke-width = "20"/>
</svg>
У меня недостаточно опыта работы с SVG-анимацией, чтобы решить эту проблему, но у меня возникли некоторые идеи:
Как это можно сделать? (Опять же, я не ищу приближений.)
Мне удалось заставить его работать с помощью группировки. С помощью группировки вы можете вкладывать элементы, а затем дважды применять animateMotion к одному и тому же объекту.
Я использовал одну и ту же дугу для обеих анимаций, но одна перевернута по вертикали и обе имеют половинную амплитуду. По горизонтали они складываются до полной амплитуды, а по вертикали нейтрализуют друг друга.
Я использовал половину единичного круга и использовал поле просмотра для масштабирования, чтобы упростить расчеты (общая длина движения равна 1).
<svg xmlns = "http://www.w3.org/2000/svg" width = "175" height = "175" viewBox = "-0.1 -0.1 1.2 1.2" border = "1px solid blue">
<path id = "lineAC" d = "M0,0.5 A0.5,0.5 0 1,1 1,0.5" stroke = "blue" stroke-width = "0.02" fill = "none"/>
<path id = "lineAC" d = "M0,0.5 A0.5,0.5 0 1,0 1,0.5" stroke = "green" stroke-width = "0.02" fill = "none"/>
<g>
<g>
<rect width = "0.1" height = "0.1" x = "-0.05" y = "-0.05" rx = "0" ry = "0" fill = "black" />
<animateMotion path = "M0,0.25 A0.25,0.25 0 1,1 0.5,0.25
A0.25,0.25 0 1,1 0.0,0.25" dur = "3s" repeatCount = "indefinite"/>
</g>
<animateMotion path = "M0,0.25 A0.25,0.25 0 1,0 0.5,0.25
A0.25,0.25 0 1,0 0.0,0.25" dur = "3s" repeatCount = "indefinite"/>
</g>
</svg>
Использование CSS для анимации атрибутов представления — гораздо более простое решение.
Начиная с Firefox 128, все основные браузеры поддерживают типизированные пользовательские свойства с помощью @property . Это позволяет передать анимированный <angle>
в функцию CSS sin().
Полученное анимированное число можно использовать либо для анимации transform
, либо для одного из свойств геометрии (здесь x
). Следующий пример демонстрирует оба варианта.
@property --a {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@keyframes round {
from {--a: 0deg}
to {--a: 360deg}
}
#moved1 {
animation: round 4s linear infinite;
transform: translateX(calc(sin(var(--a)) * 250px));
}
#moved2 {
animation: round 4s linear infinite;
x: calc(sin(var(--a)) * 250px - 30px);
}
<svg viewBox = "-300 0 600 200">
<path id = "moved1" d = "M-30 20h60v60h-60z"/>
<rect id = "moved2" x = "-30" y = "120" width = "60" height = "60"/>
</svg>
Я искал способы сделать это в SVG, а не в CSS. Таким образом, это не анимированный SVG, а анимированная веб-страница.
За пределами веб-браузеров не так уж много средств визуализации, поддерживающих анимацию. (Ява/Батик — единственное, о чем я могу думать). Если вы откроете изображение в браузере, оно будет работать независимо от того, имеет ли оно тип MIME text/html
или image/svg+xml
.
Я знаю, что не так уж много средств визуализации поддерживают анимацию SVG. На самом деле существует не так много средств визуализации, которые поддерживают полную спецификацию SVG. И у некоторых есть ошибки. Но я намерен разработать автономный механизм рендеринга SVG, который будет реализовывать большую часть крошечной спецификации SVG.
@Danny '365CSI' Энгельман, спасибо за исправление моего поста!