Использование <animate> в SVG само ViewBox работает только дважды
Я пытался использовать 2 разных s в SVG viewBox для циклического переключения между размерами, но хотя обе анимации работают независимо, вторая не запустится, если первая начинается снова после нее. Что странно для меня, так это то, что первый будет продолжать работать, указывая, что он "распознает" конец другой анимации, даже если он не отображается. Если я удалю "small.end", он будет работать так, как они должны… но это означает, что они не будут повторяться одно за другим.
<svg viewBox = "0 0 300 300">
<animate id = "big" attributeName = "viewBox" begin = "0;small.end" dur = "0.96s" from = "0 0 300 300" to = "0 0 650 390" fill = "freeze" />
<animate id = "small" attributeName = "viewBox" begin = "big.end" dur = "0.96s" from = "0 0 650 390" to = "0 0 300 300" fill = "freeze" />
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
Я смотрел на различные вещи, такие как система координат, аддитивная и накопительная анимация и т. Д., Но не могу понять, почему это происходит именно так. Я подозреваю, что это может быть проблема "сброса" состояния анимации, но я немного теряю глубину - я не против использования javascript или каких-либо библиотек для достижения этой цели. Любая помощь или указатели будут высоко оценены. Спасибо!
2 ответа
Предложение Майкла Муллани, безусловно, является более простым способом сделать это, но оно стоит немного более детального изучения:
Первое, что нужно упомянуть, это то, что проблема возникает только в браузерах Webkit/Blink; в Firefox вы получаете анимацию, как и ожидалось.
Похоже, что в Chrome (и других браузерах webkit) происходит то, что он допускает, чтобы значение "замораживания" первой анимации перекрывало любые изменения, сделанные второй анимацией. Если вы избавитесь от атрибута стоп-кадра в первой анимации, то значение стоп-кадра второй анимации блокирует отображение первой анимации.
Это не то, как это должно работать, поведение по умолчанию для двух анимаций, влияющих на одно и то же свойство, заключается в том, что более поздние анимации должны иметь более высокий приоритет, чем более ранние. В частности, спецификации SMIL говорят:
Кажется, проблема связана с тем, что additive
атрибут (или, по крайней мере, возможность указания additive="sum"
) применяется только к определенным типам анимированных свойств: длинам, цветам и векторам. Это не относится к сложным атрибутам, таким как "viewBox". Поэтому браузеры webkit, похоже, игнорируют настройки по умолчанию additive="replace"
поведение.
Для демонстрации, если мы добавим анимацию, которая потенциально может быть аддитивной, например, изменение цвета, тогда две анимации корректно заменяют друг друга, несмотря на настройку "заморозки":
Одно это, однако, не объясняет, почему ваша вторая анимация работает нормально, если первая анимация не настроена на перезапуск после окончания второй анимации. Я предполагаю, что это связано с ошибкой в способе, которым webkit вычисляет "приоритет" нескольких анимаций. Для нескольких анимаций, которые запускаются одновременно, приоритет определяется путем определения того, зависит ли время начала одного от другого. Однако этот расчет не должен влиять на анимацию, которая запускалась в разное время - в этом случае более поздняя анимация всегда должна иметь приоритет.
В любом случае, я бы назвал это ошибкой в реализации webkit. В веб-наборе Bugzilla я не нашел соответствующих сообщений об ошибках. Возможно, вы захотите выполнить более тщательный поиск и зарегистрировать проблему, если не можете ее найти.
Что касается того, как решить проблему в то же время:
Как и предполагалось, вы можете объединить обе анимации в одну многозначную анимацию. Это, вероятно, самый простой подход и очищает ваш код.
Поскольку вы на самом деле не "замораживаете" значение на любом конце, другой способ сделать то, что вы хотите, это просто удалить fill="freeze"
параметр из обоих:
<svg viewBox = "0 0 300 300">
<animate id = "big" attributeName = "viewBox" begin = "0;small.end"
dur = "0.96s" from = "0 0 300 300" to = "0 0 650 390" />
<animate id = "small" attributeName = "viewBox" begin = "big.end"
dur = "0.96s" from = "0 0 650 390" to = "0 0 300 300" />
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
Однако это не сработает, если вы захотите запустить анимацию, заморозить ее, а затем подождать указанное время, прежде чем начинать обратную анимацию. Чтобы заставить это работать, вам нужно либо
- определить его как отдельную анимацию с несколькими значениями, некоторые из которых повторяются дважды, чтобы "заморозить" это значение, и заданными временными интервалами для каждого шага; или
- определять
set
элементы анимации, которые запускаются после завершения каждой из анимаций перехода и удерживают указанное значение в течение заданного времени, не останавливая его на неопределенный срок.
Используйте один элемент animate с массивом значений.
<svg viewBox = "0 0 300 300">
<animate attributeName = "viewBox" dur="1.92s" values="0 0 300 300; 0 0 650 390;0 0 300 300" fill="freeze"/>
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>