Tudo sobre animações SVG

Neste artigo, quero destacar os meandros do trabalho com gráficos SVG, animação SVG (incluindo caminho), problemas e métodos para resolvê-los, bem como várias armadilhas, das quais existem muitos SVGs. Posiciono este artigo como um guia detalhado.



Não haverá plugins, bibliotecas, etc., falaremos apenas sobre SVG puro.
A única ferramenta que vou usar é o Adobe Illustrator.

Prefácio


Tudo começou com uma palestra chata e, na esperança de me divertir com pelo menos alguma coisa, decidi estudar gráficos SVG, ou seja, animação. Para minha surpresa, havia muito pouca informação na Internet. Em todos os lugares havia informações duplicadas explicando o básico, mas sobre animação em geral, a partir da força de 2-3 links com informações absolutamente idênticas, que é uma tradução do artigo Um Guia para Animações SVG (SMIL) de Sarah Suydan.

O artigo dela fala sobre tudo, mas superficialmente. No entanto, eu recomendo fortemente que você se familiarize com isso. * Link para tradução *

Nas semanas seguintes, passei coletando informações, peça por peça, de várias fontes. O resultado dessas pesquisas é este artigo.

Exportação SVG adequada do Illustrator


Esta seção se concentra nos recursos e problemas do Adobe Illustrator, portanto, se você não estiver usando o Illustrator, poderá pular esta parte.

A preparação de um documento para animação é uma etapa muito importante, cuja negligência pode resultar em consequências muito desagradáveis. Para ensiná-lo a desenhar melhor no Illustrator, não vou. A única coisa que direi é que, ao desenhar formas, você deve seguir os valores, é desejável que eles tenham apenas um número após o ponto decimal e é melhor ser inteiro. Não é necessário seguir esta regra, mas reduzirá o tamanho do arquivo, simplificará mais animações e reduzirá visualmente a quantidade de informações. Dê uma olhada

<path d="M 17.7 29 C 28.2 12.9 47 5.6 62.8 10.4 c 28.2 8.5 30 50.5 24.8 53.1 c -2.6 1.3 -10.4 -6.1 -29.2 -34.6"/> <path d="M 17.651 28.956 c 10.56 -16.04 29.351 -23.359 45.12 -18.589 c 28.151 8.516 29.957 50.5 24.841 53.063 c -2.631 1.318 -10.381 -6.148 -29.235 -34.643"/> 

No exemplo, a mesma curva, mas no primeiro caso, um dígito após o ponto decimal e no segundo três. Essa curva possui apenas 4 pontos e o segundo exemplo é um terço a mais que o primeiro. Imagine quanto espaço uma curva de 20 pontos levará.

Depois que o wireframe é desenhado, você precisa salvar a imagem como um arquivo SVG. Há duas maneiras de fazer isso - Salvar como ou Exportar como. Mas qual o caminho a escolher? Se você confia em mim, é melhor usar "salvar como". Se você quiser saber o motivo, implante um spoiler.

Então porque?
À primeira vista, não faz diferença, porque no final obtemos um arquivo.svg com nossa imagem. No entanto, as diferenças começam no estágio de configurações de exportação.


Não vejo sentido em explicar todos os parâmetros em detalhes. O Illustrator faz isso muito bem na seção "Descrição".

Como você pode ver, "salvar" tem mais configurações do que "exportar" e, para alguns, será um bom motivo para recusar a exportação, mas continuaremos.

Se abrirmos os arquivos salvos nos dois sentidos em um navegador, não perceberemos a diferença. No entanto, no momento, estamos mais interessados ​​não na aparência, mas no preenchimento; portanto, faremos o mesmo, mas através de um editor de texto. Aqui as diferenças se tornarão mais aparentes. Sugiro que você veja e tire conclusões, não mudei nada nos arquivos, apenas copiei o todo como está.

Exportar

 <svg id="_1" data-name=" 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 51 51"> <defs> <style> .cls-1 { fill: none; stroke: #4ec931; stroke-miterlimit: 10; } .cls-2 { fill: #4ec931; } .cls-3 { fill: #fff; } </style> </defs> <title>my_icon_E</title> <circle class="cls-1" cx="25.5" cy="25.5" r="20"/> <circle class="cls-1" cx="25.5" cy="25.5" r="25"/> <g id="_2" data-name=" 2"> <circle class="cls-2" cx="25.5" cy="25.5" r="15"/> <polygon class="cls-3" points="25.5 34.8 34 20.3 17 20.3 25.5 34.8"/> </g> </svg> 

Salvar

 <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"> <style type="text/css"> .st0{fill:none;stroke:#4EC931;stroke-miterlimit:10;} .st1{fill:#4EC931;} .st2{fill:#FFFFFF;} </style> <circle class="st0" cx="50" cy="50" r="20"/> <circle class="st0" cx="50" cy="50" r="25"/> <g id="_2"> <circle class="st1" cx="50" cy="50" r="15"/> <polygon class="st2" points="50,59.3 58.5,44.8 41.5,44.8 "/> </g> </svg> 

Além das diferenças em nomear classes CSS e design em geral, que alguns podem considerar de bom gosto, existem outros problemas. Ao "exportar", a imagem inteira foi reduzida em 2 vezes. Você pode julgar isso pelo tamanho das formas e pelo atributo viewBox . Como se trata de gráficos vetoriais, não piorou, mas ainda é desagradável. "Salvar" deixou as dimensões especificadas no Illustrator.

Mas tudo isso são flores em comparação com o tipo de "exportação" de suínos que pode ser colocado. Especificamente, esses exemplos não têm esse problema, provavelmente porque a imagem é muito simples. No entanto, eu encontrei isso ao exportar meu outro trabalho. Aqui está a captura de tela dela



O tamanho do arquivo é grande o suficiente, então darei apenas a parte do problema

 <g id="-21" data-name=""> <path class="cls-9" d="M477.94,456.75a1.83,1.83,0,0,1-.9,1.36l-4.91,3.1a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M477,451.19l-16.38-9.5a7.28,7.28,0,0,0-7.32,0l-5,2.9a1.88,1.88,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36v-.51A1.88,1.88,0,0,0,477,451.19Z" transform="translate(-5.5 -5.5)"/> </g> <g id="-22" data-name=""> <path class="cls-9" d="M525.37,557.86a1.85,1.85,0,0,1-.9,1.36l-33.22,19.64a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M524.45,552.3l-16.38-9.51a7.31,7.31,0,0,0-7.32,0l-33.27,19.44a1.89,1.89,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36v-.5A1.86,1.86,0,0,0,524.45,552.3Z" transform="translate(-5.5 -5.5)"/> </g> 

Notou algo incomum? Se você olhar desconfiado para o atributo transform , estará certo. É ele quem estraga a framboesa inteira. Quando você "exporta" uma imagem, o Illustrator a atribui a TODOS os elementos <caminho> . No entanto, esse problema não é observado com a "conservação".

Se você ainda não entende minha indignação, explicarei: se você deseja animar o movimento de um elemento desse tipo, ele mudará para o lado. Nesse caso, 5,5 nos dois eixos. Isso ocorre porque a animação do movimento altera o atributo transform , redefinindo todos os valores passados. Obviamente, isso pode ser contornado, mas não é melhor evitar o problema do que corrigir suas consequências posteriormente ...

No momento, eu só notei esse problema, mas isso não significa que seja o único. Se você avaliar a situação de maneira sensata, acontece que "salvar como" vence em tudo. É por isso que eu aconselho você a usá-lo.

Maneiras de importar um documento SVG para HTML


Antes de começar diretamente com a animação, quero falar sobre como incorporar o SVG em uma página. Cada método tem seus próprios "recursos" que têm um impacto direto na animação. E se você não falar sobre eles, o artigo ficará incompleto.
Suponha que você já tenha um SVG pronto com animação interativa e que resta incorporar este documento no site. Como fazer isso?

A opção número um é lembrar que o SVG também é uma imagem e pode ser importado usando ferramentas HTML padrão. Você pode criar uma tag <img> com um link para um documento

 <img src="Hello_SVG.svg" /> 

Ou defina SVG como imagem de fundo

 #box { background-image: url("Hello_again.svg"); } 

A principal desvantagem desse método é o isolamento da imagem. SVG como uma exposição no museu - você pode assistir, sem tocar. A animação interna funcionará, mas não se pode falar em interatividade. Se, por exemplo, uma animação é acionada por um clique do usuário ou se é necessário alterar dinamicamente o conteúdo de um documento SVG, esse método não é para você.

A opção número dois é criar um objeto a partir do SVG usando as tags <object> ou <embed> . Também é possível usar <iframe> para criar um quadro, mas eu não recomendo usar esse método, porque é necessária uma muleta para todos os navegadores, para que esta opção seja exibida corretamente

 <object data="My_SVG.svg" type="image/svg+xml"></object> <embed src="My_SVG.svg" type="image/svg+xml" /> <iframe src="My_SVG.svg"></iframe> 

Aqui as coisas estão melhores. As animações têm a oportunidade de serem interativas, mas somente se forem declaradas em um documento SVG e o conteúdo estiver disponível para JavaScript externo. Ainda assim, <object> e <iframe> podem mostrar um esboço se de repente a imagem não carregar.

A opção número três é simplesmente colar o conteúdo do documento SVG diretamente no HTML. Sim você pode. O suporte ao SVG apareceu no padrão HTML5 . Como o SVG é essencialmente parte da própria página, o acesso a ela está em toda parte. Animações e estilos de elementos podem ser declarados dentro do SVG e em arquivos externos. A desvantagem é que essas imagens simplesmente não são armazenadas em cache separadamente da página

 <body> ... <svg> <!--  --> </svg> </body> 

Animação SVG


Existem duas maneiras principais de animar um elemento SVG:

  • Animação CSS
  • Animação SMIL incorporada ao SVG (na verdade, é uma animação SVG baseada no SMIL e estende sua funcionalidade)

Pessoalmente, separo-os como animações de "externo" e "interno". Essa divisão é condicional, mas ainda tem diferenças funcionais. Se falamos sobre as diferenças em geral: CSS - suporta melhor os navegadores; SMIL - tem ótima funcionalidade. É difícil dizer qual é o melhor para usar, porque eles são muito parecidos. A escolha depende da tarefa, então eu apenas direi os principais motivos para usar o SMIL em vez de CSS

SMIL - quando necessário:

  1. O que o CSS não pôde fazer (animar um atributo não suportado etc.)
  2. Tenha um controle mais preciso sobre a animação.
  3. Tornar o caminho morphing (animação do atributo d na tag path )
  4. Sincronizar animações
  5. Faça animações interativas

Se eu escrevi que o SMIL deveria ser usado para animações interativas, isso não significa que o mesmo não possa ser feito com CSS. Simplesmente SMIL é uma ferramenta mais funcional e sofisticada. E é por isso que deve ser usado apenas quando necessário. Se a animação é simples e o CSS pode ser dispensado, isso deve ser feito.

Animação CSS


Nada de novo aqui. Podemos animar qualquer elemento SVG da mesma maneira que fazemos com HTML. Todas as animações são criadas usando @keyframes . Como a animação CSS é outro tópico, não vou me debruçar sobre esse ponto em detalhes, a rede está cheia de documentação e guias sobre esse tópico. Tudo o que é descrito lá se aplica ao SVG, mas vou apenas dar alguns exemplos.

O documento SVG possui folhas de estilo internas, portanto, escreveremos animações

 <svg> <style> <!--   --> </style> <!--   SVG  --> </svg> 

Animar um atributo SVG é tão simples quanto os atributos CSS

 @keyframes reduce_radius { from { r: 10; } to { r: 3; } } @keyframes change_fill { 0% { fill: #49549E; } 75% { fill: #1bceb1; } 100% { fill: #1bce4f; } } 

Você pode especificar valores como uma porcentagem e construir de-para

Resta apenas aplicar as animações criadas ao elemento desejado

 .circle { animation: change_fill 1s, popup 2s; } 

Tudo o que eu descrevi acima são animações estáticas, não há cheiro de interatividade lá. Mas e se você realmente quiser? Bem, algo ainda pode ser feito interativamente e em CSS. Por exemplo, se você usar a transição em combinação com a pseudo classe suspensa

 .circle { fill: #49549E; transition: .3s; } .circle:hover { fill: #1bceb1; } 
Quando você passa o mouse sobre um item, ele muda de cor de azul para azul por 300ms

Animação de atributos e um pequeno pedaço de interatividade - é aqui que os recursos da animação CSS terminam. Mas essa funcionalidade é suficiente, porque a maioria das tarefas se resume a animar algum atributo. Quase qualquer atributo SVG pode ser animado. E quando eu escrevo "quase qualquer", quero dizer que, se você escolher um atributo aleatório e ele não for invariante, terá muita sorte.

Animação SMIL


Vale dizer imediatamente que a animação SMIL é tão antiga quanto o mundo e está acabando, o suporte ao navegador é decente, mas ainda menos que a Animação CSS, mas há uma razão pela qual o SMIL ainda é atraente - pode porque o CSS não pode.

Vou falar mais sobre o SMIL, porque existem muitas armadilhas sobre as quais eles raramente escrevem. E este tópico é menos popular que CSS. As principais tags de animação são <animate> , <set> , <animateTransform> , <animateMotion> .

<animado>


Vamos começar com artilharia pesada. <animate> - usado para animar qualquer atributo e é a ferramenta principal. As tags restantes são altamente especializadas, mas as primeiras são as primeiras.

Como aplicar animação a um elemento?

Existem duas maneiras de especificar o elemento ao qual a animação será aplicada.

  1. Coloque a etiqueta dentro do elemento. Esse método permite encapsular a animação dentro do objeto, o que facilita a leitura do código

     <circle ...> <animate .../> </circle> 
    Nesse caso, a animação será aplicada ao elemento do círculo .
  2. Passe o link para o item. Útil se você deseja que todas as animações sejam coletadas em um só lugar

     <svg xmlns:xlink="http://www.w3.org/1999/xlink"> <circle id="blue" .../> ... <animate xlink:href="#blue" .../> </svg> 
    O atributo xlink: href é usado aqui, no qual especificamos o ID do elemento ao qual a animação deve ser aplicada. Para que este método funcione, você deve definir o espaço para nome do xlink . Isso é feito na tag <svg>.

Com o SVG 2, o atributo xlink: href foi descontinuado, a especificação recomenda o uso de href , o que não requer um espaço para nome do xlink .

 <circle id="blue" .../> ... <animate href="#blue" .../> 

Mas aqui, nem tudo é tão tranquilo - o href não é suportado pelo Safari. Acontece uma situação de impasse, um atributo está desatualizado e o outro não é parcialmente suportado. Então, qual método usar, todo mundo decide por si mesmo.

Para aqueles que notaram semelhanças com os seletores de CSS: lamento desapontar, não poderei acessar elementos por classe

 <circle class="blue_circle" .../> <animate href=".blue_circle" .../> 
Isso não funciona!

Como especificar um atributo para animação?

Existe attributeName para isso. O valor é o nome do atributo que iremos animar.

 <circle r="25" ...> <animate attributeName="r" ... /> </circle> 
Ao especificar r em attributeName , relatamos que vamos animar o raio do círculo

O que é attributeType e por que você não precisa?

Porque ele é inútil
Em teoria, pode surgir um momento em que os nomes dos atributos em CSS e XML coincidem, o que pode levar a problemas. E para resolver esse conflito, você deve especificar explicitamente um espaço para nome. Existem cadeiras de mão dupla: especifique um prefixo ou use attributeType . Vamos começar com o prefixo.

Em todos os lugares eles escrevem algo como o seguinte:
Você pode especificar um prefixo XMLNS para um atributo para especificar explicitamente seu espaço para nome
Este método é mencionado de passagem e sem exemplos. Então eu não vou mudar tradições. (Aconselho que você pare aqui, esqueça os prefixos como um pesadelo e vá para attributeType , eu avisei)

"Eu sou masoquista"
O conteúdo deste spoiler é bastante divertido e de natureza exploratória. Nenhuma informação útil, além do fato de que os prefixos não funcionarem, você não encontrará aqui

Primeiro, você precisa encontrar uma definição mais precisa e, como você sabe, as definições mais precisas nas especificações e padrões.

Um pequeno guia sobre como desistir da vida
  1. Abrimos a especificação para animação SVG para 14 de março de 2019
  2. Na seção attributeName , vemos que ele herda o padrão SMIL Animation para 2001 (horror)
  3. Leia a definição de attributeName
  4. Lucro!

A tradução da definição é a seguinte:
“Define o nome do atributo de destino. O prefixo XMLNS pode ser usado para especificar o espaço para nome XML para um atributo. O prefixo será interpretado no escopo do elemento de animação. ”
Hmm, não ficou mais fácil. O que vem à mente de uma pessoa que não conhece XML depois de ler essa definição? Certo. O mesmo que eu.

Eu peguei literalmente e pensei que deveria ficar assim

 <animate attributeName="xmlns:* *"/> 

Pensei e esqueci com segurança esse método antes de escrever este artigo. Os problemas começaram quando eu decidi testá-lo na prática. Acho que não vou surpreender ninguém se disser que isso não funciona. Após várias horas de pesquisas malsucedidas, pesquisei o “prefixo xmlns” e, para minha surpresa, vi que xmlns não é o prefixo em si, mas (concentre-se, será difícil agora) o design do espaço para nome com prefixos .

É o seguinte:

 <** xmlns:**="* url *" ...> 
Então percebi que não entendia nada ... no começo ... e agora, em princípio, também

Depois de mais algumas horas, finalmente encontrei o que estava procurando nos Namespaces em XML . Aqui está um exemplo original:

 <x xmlns:n1="http://www.w3.org" xmlns="http://www.w3.org" > <good a="1" n1:a="2" /> </x> 

Mas você sabe qual é a coisa mais engraçada? Ainda não funciona. Embora tudo seja feito de acordo com o livro

 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:n1="http://www.w3.org/2000/svg"> <circle id="www" n1:r="10" .../> <animate href="#www" attributeName="n1:r" .../> </svg> 

Não há erros e não deveria existir, porque tudo é feito de acordo com as regras, mas o problema é que conseguimos um círculo sem raio. O mesmo resultado será se você simplesmente não escrever o atributo r .

Epílogo : SVG ignora atributos prefixados. Como resultado, mesmo se o SMIL realmente animar o atributo com um prefixo, você não verá o resultado dessa animação.
Em minha defesa, direi que lidei apenas com o SVG, principalmente com a animação, para que o guru do XML deixasse as tochas e o forcado de lado. Se você sabe como fazer esse método funcionar, comentários bem-vindos

Para indicar explicitamente a que o atributo animado pertence, attributeType é usado. São necessários 3 valores: CSS , XML , automático . A menos que attributeType seja especificado explicitamente, auto será usado. Nesse caso, as propriedades CSS são verificadas primeiro e, se não houver correspondências, os atributos do elemento de destino serão verificados. No exemplo, indicamos que vamos animar exatamente a propriedade CSS

 <animate attributeType="CSS" attributeName="opacity" .../> 

Bem, attributeType permite que você facilmente e sem muletas para indicar a que pertence o atributo animado, resolvendo o "problema", que nem sequer existe.

Inesperadamente, certo? Como eu disse no começo do capítulo - o SMIL está morrendo e isso se deve ao fato de a animação ser transferida para os trilhos do CSS. A maioria dos atributos duplicados são absolutamente idênticos, ou seja, não importa se o atributo CSS ou SMIL pertence - o resultado será o mesmo. E em combinação com o valor automático padrão, a necessidade de definir explicitamente attributeType não é mais necessária.

Um momento de fatos interessantes: attributeType não é suportado pelo SVG. De onde ele veio então? Ele veio da SMIL Animation, onde a animação SVG é baseada. E também attributeType é removido após o SVG 1.1 Second Edition. Todas as provas aqui

Como determinar valores de animação?

A especificação de um atributo para animação não é suficiente; você deve definir seus valores. Aqui vêm de , para , por , valores .

Vamos começar com um casal que está sempre junto: de e para . O significado de sua existência é óbvio, desde indica o começo até o fim

 <circle r="25" ...> <animate attributeName="r" from="10" to="45" .../> </circle> 
O resultado da animação será uma mudança suave no raio do círculo de 10 para 45

Embora eu tenha dito que eles estão sempre juntos, também pode ser usado sem declarar explicitamente. Nesse caso, from assumirá o valor definido no elemento de destino. Para o exemplo acima, a animação começará em 25.

Se for necessário especificar um conjunto de vários valores, os valores serão utilizados. Os valores são listados com ponto e vírgula.

 <circle r="25" ...> <animate attributeName="r" values="15;50;25" .../> </circle> 
O valor do raio diminui para 15, depois aumenta para 50 e depois retorna à sua posição original.

Última na fila por . Ele não se importa "onde" e "onde", tudo o que lhe interessa é "quanto". Em outras palavras, em vez de valores absolutos, ele trabalha com

 <circle r="25" ...> <animate attributeName="r" by="15" .../> </circle> 
Como resultado da animação, o raio aumentará em 15, ou seja, obterá 25 + 15 = 40

Uma lenda percorre as extensões de manuais que "podem ser usados ​​para indicar a quantidade pela qual as animações devem avançar" . Entendo assim: se de = 20 a = 50 e dado por = 10 , esse caminho deve ser superado "pulando" em 10, ou seja, 20, 30, 40, 50. Mas não importa como eu tentei, com e sem, a animação não mudou um pouco. Além disso, não encontrei confirmação na especificação. Parece que é apenas um erro.

Os valores têm a prioridade mais alta, depois de - para , duram por . A prioridade mais baixa explica por que uma “lenda” não pode funcionar em princípio. No entanto, ao trabalhar em conjunto com from , neste caso, simplesmente substitui a posição atual do elemento

 <circle cy="50" ...> <animate attributeName="cy" from="70" by="30" .../> </circle> 
Aqui a animação em vez de 50 começa em 70 e termina em 100

Mais sobre animações relativas

Você pode fazer com que outros atributos funcionem da mesma forma que por . Isso é feito usando o atributo aditivo , que possui duas posições - substituir e somar .O primeiro é o padrão, por isso estamos interessados ​​no segundo. Com um valor de soma, todos os atributos serão adicionados ao valor atual do elemento de destino, ou seja, ao animar um raio de 20 com os valores forma = 5 e até = 15 , a animação será de 20 + 5 a 20 + 15

 <circle r="20" ...> <animate attributeName="r" from="5" to="15" additive="sum" .../> </circle> 

Ao executar a animação, haverá um salto acentuado para a posição 25, o que não é bom (a menos que, é claro, isso se destine). Isso pode ser evitado com a forma = 0 , mas o significado do uso de soma é perdido , porque o mesmo efeito pode ser obtido sem aditivo usando por

 <animate attributeName="r" from="0" to="15" additive="sum" .../> <animate attributeName="r" by="15" .../> 
Quanto a mim, o segundo método é muito mais compreensível e conveniente:

onde especificar a duração da animação?

O último atributo necessário é deixado para criar animação de trabalho - e isso é dur . O valor do atributo determina a duração da animação, que pode ser especificada em segundos e em milissegundos

 <animate dur="0.5s" .../> <animate dur="500ms" .../> <animate dur="00:00:00.5" .../> 
A partir da última linha, você pode adivinhar que há algo mais ...

Você também pode indicar os valores em minutos e até horas

 <animate dur="1.2min" .../> <animate dur="0.02h" .../> 
Foda-se, por que diabos você conseguiu indicar os valores em horas, mas eu não entro nos assuntos de outras pessoas, se você quiser, significa por que ...
Para outros atributos, os valores temporários são definidos da mesma forma

O que posso fazer para impedir que a animação retorne ao início?

O atributo de preenchimento (não confunda esse atributo com seu xará) é responsável pelo comportamento do elemento após o final da animação. Existem duas opções:

  • remove (valor padrão) - assim que a animação chega ao fim, todas as transformações são redefinidas e o elemento assume um estado como antes da animação
  • congelar - o elemento congela na posição final da animação

É possível fazer loop de animação?

A resposta é sim. Para fazer isso, o atributo repeatCount especifica um valor indefinido . O atributo determina o número de repetições da animação e o padrão é 1, mas você pode especificar qualquer número

 <animate repeatCount="indefinite" .../> <animate repeatCount="3" .../> 
O primeiro se repetirá sem parar, o segundo funcionará três

vezes.Agora, inúmeras animações me irritam, posso desligá-las depois de um tempo?

Para pessoas tão irritantes, repetiu Dur . Este atributo interrompe a animação após um certo tempo desde o início da animação! Simplificando, repeatDur limita a duração da animação. A principal diferença de repeatCount é que a animação pode ser parada no meio

 <animate dur="2s" repeatCount="indefinite" repeatDur="3s" .../> 
A animação será interrompida no meio da segunda iteração.

E se eu quiser que a animação não comece imediatamente?

Então, para você, meu amigo, o atributo begin é fornecido. Ele é responsável por quando a animação começa. Este atributo é muito útil porque também é usado para sincronizar várias animações, mas mais sobre isso posteriormente.

Se você precisar especificar o atraso usual no lançamento, escreveremos em que período a animação deve começar após a abertura do documento.

 <animate begin="1.5s" .../> 
A reprodução inicia após 1,5 segundos.Você

também pode especificar um valor negativo. Então a animação começará não do começo, mas no local em que estaria após um período de tempo especificado

 <animate begin="-2s" dur="4s" .../> 
A animação começará com a abertura do documento, mas será reproduzida a partir do meio.

Tornamos as animações interativas.

À medida que o valor começa, você pode especificar o evento quando a animação começar, mas sem o prefixo “on”. Por exemplo, se você deseja fazer uma animação por clique, em vez de "onclick", escrevemos clique

 <circle ...> <animate begin="click" .../> </circle> 

No exemplo acima, a animação inicia quando você clica no elemento ao qual a animação é aplicada. Se você deseja iniciar uma animação em um evento a partir de outro elemento, especifique seu ID

 <circle id="button" .../> ... <animate begin="button.click" .../> 

Você também pode especificar várias condições para o início da animação. Para fazer isso, liste-os separados por ponto e vírgula.

 <animate begin="click; 0s" .../> 
A animação será iniciada quando o documento for carregado e clicando em

.. Nem todos os eventos são suportados, mas a maioria dos eventos relacionados ao mouse funciona. Não vou listar todos, os eventos disponíveis podem ser encontrados em algum lugar aqui . Além disso, ninguém cancelou o método de cutucada científica.

A animação é reiniciada sem chegar ao fim, como posso corrigi-la?

Vou dar um exemplo simples. Aqui a animação começa por clique. Se o usuário ainda não pressionar, o início automático será fornecido em 3 segundos

 <animate begin="click; 3s" dur="7s" .../> 

Mas há um problema: se o usuário pressionar antes do timer automático, depois de 3 segundos, a animação será reiniciada e nunca chegará ao fim. O atributo de reinicialização no valor whenNotActive chegará ao resgate . No total, ele tem três deles

  • sempre é o padrão - permite reiniciar a animação a qualquer momento
  • whenNotActive - a animação pode ser iniciada se ainda não estiver sendo reproduzida
  • never - proíbe reiniciar a animação

 <animate begin="click; 3s" dur="7s" restart="whenNotActive" .../> 
O problema está resolvido, embora, na maioria dos casos, você possa ficar sem esse atributo simplesmente construindo dependências com competência

Sincronização de animações

Além dos eventos padrão, pelo tipo de clique, há eventos de início, fim e repetição da animação. Para vincular um evento, você deve especificar o ID da animação e, através do ponto, iniciar , terminar , repetir, respectivamente

 <animate id="pop" begin="click" .../> <animate begin="pop.begin" .../> <animate begin="pop.end" .../> 

Se com os dois primeiros tudo estiver claro, com a repetição tudo não será tão óbvio. O número de repetições é escrito entre parênteses, após o qual você precisa iniciar a animação (esse número não pode ser a última repetição)

 <animate id="flip" repeatCount="5" .../> <animate begin="flip.repeat(2)" .../> 
A animação começará após duas repetições e não a cada 2.

Você também pode especificar um atraso em relação ao evento. Por exemplo, se eu quiser reproduzir a animação 2 segundos após o início de outra

 <animate id="another" .../> <animate begin="another.begin + 2s" .../> 

Ou inicie a animação um segundo antes do final de outra

 <animate begin="another.end - 1s" .../> 

O que mais pode começar ...
Eu queria chamar esta seção, mas é mais correto chamá-la de "O que ele deveria, mas não pode?". De acordo com minha especificação favorita , o begin deve ter mais dois valores que ele deve receber. O primeiro é accessKey , que inicia a animação pressionando uma tecla especificada no formato Unicode. O segundo é o relógio de parede , que determina o início da animação em tempo real. E aí você pode especificar não apenas o relógio, mas também o mês e o ano, em geral, um conjunto completo.

Infelizmente, nenhum deles queria trabalhar. Embora a perda não seja grande, porque a necessidade deles ainda é duvidosa

 <animate begin="accessKey(\u0077)" .../> <animate begin="wallclock(2019-04-09T19:56:00.0Z);" .../> 
Não sei qual é o problema, talvez meu navegador não os suporte ou talvez outra coisa ...

Posso interromper a animação?

Isso pode ser feito com o atributo final . Em seu uso, é idêntico ao início , você também pode especificar a hora, os eventos etc. Como você pode ver, essa não é a primeira (e não a última) maneira de interromper a animação, porque há repeatDur , onde você também pode fixar a duração da animação. Eembora você também possa especificar o tempo diretamenteno final , seus recursos distintos são a associação de eventos e a capacidade de especificar uma lista de valores.

Suponha que tenhamos um elemento que tenha um estado de descanso e atividade. O segundo é ativado quando clicado. E queremos interromper a animação restante com o início da atividade. Você pode implementar uma ideia semelhante como esta

 <animate id="idle" end="action.begin" begin="0s" repeatCount="indefinite" .../> <animate id="action" begin="click" .../> 
A animação restante é iniciada por padrão. Quando você clica em um elemento, uma animação de atividade inicia e interrompe a animação restante.

Combinando os atributos fim e começo

Como você já sabe, o começo e o fim podem receber uma lista de valores, mas ainda não está claro como a animação se comportará se você especificar uma lista nos dois atributos. E resultará, de certa forma, uma repetição com duração configurável e intervalos entre eles ... não está claro? Eu vou explicar tudo agora.

A primeira coisa a saber é que o número de valores nas listas deve corresponder. Cada par de valores de início e fimdefine uma "repetição". E o tempo entre o final de uma "repetição" e o início da próxima determina o atraso. Eu os chamo de "repetições" por um motivo, a animação não pausa e continua, mas é interrompida e começa do começo. Acontece que podemos ajustar separadamente a duração de cada repetição e definir atrasos diferentes após cada repetição

 <animate dur="3s" begin="1s; 5s; 9s" end = "2s; 8s; 11s" .../> 
No exemplo, a animação possui 3 "repetições". O primeiro começará um segundo após o carregamento do documento e durará apenas um segundo em três. Depois, um atraso de 3 segundos e depois uma animação completa de 3 segundos. Mais uma vez, um atraso, mas em 1 segundo. A última repetição será interrompida após dois segundos de animação.

Ainda é possível interromper a animação?
Alguns atributos inúteis para o cofrinho
Keeneeee, existem mais dois atributos - mínimo e máximo . Como o nome indica, min define o mínimo e max define aduração máxima. Primeiro, a duração da animação é calculada usando os valores dur , repeatCount , repeatDur ,fim . E depois disso, a duração obtida é ajustada para os quadros especificados por min e max . Tudo é bonito no papel, vamos ver como funciona na prática.

Com max, tudo é simples, esse é outro atributo que define o limite superior. Se a duração calculada for menor que max , ela será ignorada e, se for mais longa, a duração da animação se tornará igual a max

 <animate dur="10s" repeatDur="7s" end="5s" max="4s" .../> 
Ele será interrompido por 4 segundos,

mas min teve menos sorte. Se a duração calculada da animação for maior que min , ela será ignorada, o que é lógico. No entanto, se a duração calculada for menor que min , ela será ... às vezes ignorada e outras vezes não.
Porque porque ?! É muito fácil ficar confuso neste momento, portanto leia com atenção.

Temos duas opções quando a duração calculada é menor que min :

  1. Como a animação em si acabou, ou seja, dur * repeatCount < min

     <animate dur="2s" repeatCount="2" min="5s" .../> 
    Nesta opção, o atributo min é simplesmente ignorado, a animação para no quarto segundo
  2. repeatDur end .

    • repeatDur , , min , min

       <animate dur="1s" repeatCount ="indefinite" repeatDur="3s" end="5s" min="4s" .../> 
      repeatDur , min , 3
    • repeatDur , end min , end , min

       <animate dur="1s" repeatCount ="indefinite" end="2s" min="4s" .../> 
      4 , .. min end

Devido à abundância de atributos que interrompem a animação, há muita confusão. Como resultado, não há grande sentido em max e min , porque a animação bem escrita elimina a necessidade deles.

Como gerenciar quadros-chave e onde indicar a função de tempo?

Para fazer isso, você precisa conhecer os atributos keyTimes , keySplines , calcMode . Depois de especificar a lista em valores , declaramos quadros-chave, mas eles são distribuídos uniformemente. Graças ao atributo keyTimespodemos acelerar ou desacelerar a transição de um estado para outro. Nele, também na forma de uma lista, são indicados os valores para cada quadro. Os valores representam a posição do quadro-chave no eixo do tempo como uma porcentagem, relativa à duração de toda a animação (0 - 0%; 0,5 - 50%; 1 - 100%).

Existem várias regras: cada valor representa um número de ponto flutuante de 0 a 1, o número de valores nas listas deve corresponder, o primeiro valor deve ser 0 e o último 1, cada valor seguinte deve ser maior que o anterior. Eu acho que você entende que não faz sentido usar keyTimes sem valores . E agora um exemplo

 <animate values="15; 10; 45; 55; 50" keyTimes="0; 0.1; 0.6; 0.9; 1" .../> 

Por padrão, todas as conversões ocorrem linearmente. Para alterar isso, é necessário especificar um modo diferente no calcMode . E não há muitas opções:

  • linear - valor padrão, nenhuma explicação necessária
  • estimulado - os intervalos de tempo são calculados para que a velocidade entre os quadros-chave seja constante
  • discreto - animação alterna entre quadros-chave em saltos, sem interpolação
  • spline - podemos dizer que este é um modo de controle manual (sobre isso mais tarde)

Infelizmente, essas são todas as funções integradas; aqui você não encontrará facilidade como \ em CSS. Então, essas necessidades terão que satisfazer o regime, que chamei de "manual".

O mais difícil de entender é o ritmo , por isso vou explicar mais detalhadamente. Para começar, veja como a animação funciona no modo padrão. A animação dura 2 segundos e temos 3 quadros-chave - inicial, intermediário, final

 <animate dur="2s" values="100; 200; 150" .../> 

Se você assistir a animação, ficará óbvio que a movimentação entre os quadros principais ocorre em intervalos regulares. A distância entre o primeiro e o segundo é 100 e entre o segundo e o terceiro é 50, isto é, metade do primeiro caminho. Por meio de cálculos simples, fica claro que o elemento passará pelo segundo segmento duas vezes mais lento que o primeiro.Agora adicione calcMode = "paced" e veja o que mudou.

 <animate dur="2s" values="100; 200; 150" calcMode="paced" .../> 

E a velocidade do elemento mudou. Agora ele foi projetado de forma a cobrir toda a distância na mesma velocidade, ou seja, o elemento moverá os dois segmentos uniformemente.

Agora, vejamos o modo spline e o atributo keySplines . Eles têm algumas semelhanças ... hmm ...


Se o spline definir um modo manual, o atributo keySplines definirá os valores para esse modo. Obviamente, um não funciona sem o outro. Os valores em keySplines são definidos por uma lista em que as coordenadas de dois pontos para Bezier cúbico são indicadas.

Mais sobre a função cúbica de Bezier
, . 4 0 1 : cubic-bezier(x1, y1, x2, y2). , .

cubic-bezier . , .

O número de valores em keySplines deve ser 1 menor que os valores . Isso se deve ao fato de indicarmos valores não para quadros-chave, mas para intervalos entre eles.

 <animate values="100; 200; 150" keySplines=".25 .1 .25 1; 0 0 .58 1" calcMode="spline" .../> 
As coordenadas dos pontos da função Bézier são separadas por espaços ou vírgulas, e os valores da lista são separados por ponto

e vírgula.O primeiro e o mais desagradável menos é que você não pode definir uma função de tempo comum para todos os quadros-chave, será necessário duplicar a função para cada quadro.
Segundo - se você quiser definir a função de tempo para os atributos de - para ou por , precisará de uma muleta: terá que definir keyTimes com os valores "0; 1"

 <animate from="10" to="50" keyTimes="0; 1" keySplines=".25 .1 .25 1;" calcMode="spline" .../> 
Se, em vez de partir - para usar os valores dos dois valores, em seguida, este problema não será

Como realizar economias de animação?

Primeiro, um pouco de teoria - a próxima repetição da animação cumulativa continuará onde a anterior terminou. Seria legal, mas não muito ... O fato de as animações cumulativas funcionarem apenas em repetições é decepcionante.

Agora, sobre como tornar a animação cumulativa: você precisa definir o atributo acumular (que não é nenhum por padrão) para somar

 <animate by="100" repeatCount="3" accumulate="sum".../> 

Deve-se ter em mente que, se você usar valores ou de - para , todas as repetições, exceto a primeira, se comportarão como se aditivo = "soma" . E acumular é ignorado se apenas um for especificado .

Compreendemos a transformação do contorno

Agora que expliquei o básico, é hora de seguir para coisas realmente legais e complexas. Estou certo de que alguém abriu este artigo apenas para o propósito desta seção.

A transformação de caminho é uma animação do atributo d da marca de caminho , que permite criar o efeito de alterar suavemente a forma da forma. Atualmente, com ferramentas internas, isso só pode ser feito usando o SMIL. Emvalues indica a lista de valores para o atributo d através do qual o elemento passa. Você também pode usar de - para . Em geral, o esquema de transformação se parece com isso

 <animate attributeName="d" values=" 1;  2; ..." .../> 

E agora vamos aos meandros desse processo:

para aqueles que estão no tanque, o atributo d contém um conjunto de pontos que são subsequentemente conectados, por sua vez, para formar uma figura. Uma análise mais detalhada revela que a lista de valores é semelhante ao conjunto de instruções para a máquina CNC (ou "robô" nas aulas de ciência da computação). Existem muitas equipes, algumas são responsáveis ​​por "mover o cursor", outras por "desenhar", outras por quanto a curva será a linha, etc. ( todas as equipes estão aqui ).

Para que a transformação funcione, o número de comandos deve corresponder e deve ser do mesmo tipo . Se você ignorar essa condição, não haverá interpolação - a animação passará de um estado para outro, como acontece comcalcMode = "discreto" . À primeira vista, não é nada complicado, e é assim se você animar formas sem curvas. Caso contrário, as dificuldades começam.

Ao criar gráficos complexos, todos usam editores de vetores e costumam otimizar o "código" o máximo possível. Isso geralmente é uma vantagem, mas não no nosso caso. Na saída, que pode ser uma longa lista, mas com equipes de vários tipos, e é uma violação de uma das regras. Usei o Adobe Illustrator e não encontrei uma opção que pudesse consertar as coisas. Às vezes, pela vontade dos deuses da vertigem, esse problema está ausente. Mas, falando sério, a probabilidade de um problema é diretamente proporcional à complexidade da figura e da transformação.

No momento, a única solução para o problema é a conversão do “código incorreto” no aplicativo da web Shape Shifter . Esta é a opção que eu uso. Além de corrigir o código quebrado, o Shape Shifter permite ver o resultado, adicionar opcionalmente outro tipo de animação e exportar o resultado em um formato conveniente.

A seguir, mostrarei um tutorial passo a passo, onde eu mostrarei como fazer uma animação tão bonita

Ensina-me!
: SVG Adobe Illustrator, , Shape Shifter . CSS, SMIL .

. Illustrator. , . 200x200 .

, , . , , «». ,

. . « »

, . , , ,

. , , . , . SVG , . …

. , . SVG . ( Illustrator )

, , Illustrator <path> , <circle> . , . , , . - ( SVGO ), . .

d , )

 <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve"> <style type="text/css"> .st0{fill:#D38911;} .st1{fill:#87872B;} .st2{fill:#CEB629;} .st3{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <g id="Pulse"> <g> <path class="st0" d="M100,87c44.1,0,80,35.9,80,80s-35.9,80-80,80s-80-35.9-80-80S55.9,87,100,87 M100,82c-46.9,0-85,38.1-85,85 s38.1,85,85,85s85-38.1,85-85S146.9,82,100,82L100,82z"/> </g> </g> <g id="_x3F__1_"> <path id="side" class="st1" d="   "/> <path id="front" class="st2" d="   "/> </g> <g id="Particles"> <line class="st3" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="st3" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="st3" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="st3" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="st3" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="st3" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="st3" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg> 

 <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"> <style type="text/css"> #Pulse{fill: none; stroke: #D38911; stroke-width: 5;} #side{fill:#87872B;} #front{fill:#CEB629;} .particles{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <circle id="Pulse" cx="100" cy="167" r="85"/> <g id="Sign"> <path id="side" d="   "/> <path id="front" d="   "/> </g> <g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="particles" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="particles" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="particles" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="particles" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="particles" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg> 
, . , ,

CSS , . . , . . CSS . :

 #Pulse{fill: none; stroke: #D38911; stroke-width: 5; transform: rotateX(80deg);} ._transformer{transform-box: fill-box; transform-origin: center;} 

, _transformer , , . «» <animateTransform> .

- : , Illustrator? …

– , . , . , <path> , .

, ! – , . , – . circle , . animate , 3

 <circle id="Pulse" class="_transformer" cx="100" cy="167" r="0"> <animate id="doPulse" attributeName="r" values="0;85;" dur=".8s" begin="Sign.click" calcMode="spline" keySplines="0,0,.58,1"/> <animate attributeName="stroke-width" values="5;12;" dur=".8s" begin="doPulse.begin"/> <animate attributeName="opacity" values="0.5;1;1;0" keyTimes="0;0.2;0.5;1" dur=".8s" begin="doPulse.begin"/> </circle> 
, CSS


, . : , , . - :


. - , . ,

 <linearGradient id="light-gradient"> <stop offset="0%" stop-color="#ffffff00"/> <stop offset="10%" stop-color="#FFF"/> <stop offset="90%" stop-color="#FFF"/> <stop offset="100%" stop-color="#ffffff00"/> </linearGradient> <mask id="light-mask"> <rect y="0" x="90" class="_transformer" width="20" height="220" fill="url(#light-gradient)" /> </mask> 

, . , , . , <use> , <path> <defs>

 <defs> <path id="question" d="     "/> </defs> ... <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/> 



, , . . ,

 #light-mask rect{ animation: highlight 4s infinite; } @keyframes highlight { 0% { transform: translate(-100px,0) rotate(-50deg); } 30% { transform: translate(100px,0) rotate(-50deg); } 100% { transform: translate(100px,0) rotate(-50deg); } } 

. . CSS , SMIL.

, . — , . ,

 <g id="Sign" class="_transformer"> <path id="side" d="     "/> <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/> <animateTransform id="idle" attributeName="transform" type="translate" values="0,0;0,-5;0,0" dur="6s" begin="0s; jump.end" end="click" repeatCount="indefinite" /> <animateTransform id="jump" attributeName="transform" type="translate" calMode="spline" values="0,0;0,10;0,-35;0,5;0,0" keyTimes="0;0.1;0.35;0.6;1" keySpline="0,0,.58,1;0,0,.58,1;.42,0,1,1;0,0,.58,1" dur="1s" begin="idle.end" /> </g> 
,

, , . , additive="sum"

 <animateTransform attributeName="transform" type="scale" additive="sum" values="1,1;1.1,0.8;0.9,1.2;1.1,0.8;1,1" keyTimes="0;0.1;0.35;0.7;1" dur="1s" begin="idle.end" /> 

, , . Resultado:

.
? - , , . stroke-dashoffset , . ,

- . ,

 <g id="Particles"> ... </g> <g id="Sign" class="_transformer"> ... </g> 

, ,

 .particles{ opacity:.7; stroke-width:0; ... } 

, . ,

 @keyframes sparks { 0% { stroke-dasharray: 20,200; stroke-width: 5px; } 100% { stroke-dasharray: 4,200; stroke-width: 0px; stroke-dashoffset: -180; } } 

, . , , «». : CSS , , . SMIL, 3 , , 7. , , …

– , - , . CSS, SMIL.

Particles_active ,

 .Particles_active .particles{ animation: sparks .7s; } 

<set> , , ( set )

 <g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> ... <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> <set attributeName="class" to="Particles_active" dur=".7s" begin="jump.begin + .5s"/> </g> 

:

  • ;
  • ;
  • , , , , , ;
  • ;


. , , . 3D , . , , .

Adobe Illustrator, . , . - , . ,

d .


, . Shape Shifter.

, , . , Shape Shifter

, SVG . Shape Shifter , «» SVG. Illustrator. , . , pathData


, , toValue. . «»

. ,

, , Shape Shifter , , , , . , toValue fromValue .

. ,

 <animate attributeName="d" calMode="spline" values="  1;  2;  1" dur="5s" keySpline=".42,0,.58,1;.42,0,.58,1" repeatCount="indefinite" /> 

1 – , 2 –


. Codepen.

, SVG – , . , ,

<set>


A tag set é uma versão abreviada do animate , exceto que não pode interpolar. É usado para alterar instantaneamente o atributo por um determinado período de tempo, ou seja, trabalha com o princípio de um switch. Como resultado, ele ignora os atributos associados à interpolação e não suporta animações cumulativas ou relativas. O valor é definido exclusivamente pelo atributo para , atributo valores , a partir , por ignorado

 <set attributeName="cx" to="200" begin="click" dur="5s" .../> 
O elemento altera a posição clicando em, após 5 segundos, retorna à sua posição original.Se

você não especificar o atributo dur , o elemento permanecerá nesse estado até que o documento seja recarregado. Caso contrário, é semelhante a animar .

<animateTransform>


Como o nome indica, é usado para aplicar várias transformações a um elemento. Todos os tipos de transformações são idênticas às transformações CSS. Com o uso simultâneo de transformações CSS e SMIL, elas se substituem, portanto, é melhor usar uma coisa ou assistir para que não se sobreponham.

Como transformar?

O atributo animado é transformar . O modo de transformação é indicado no atributo type e utiliza 4 tipos de valores - movimento, rotação, escala, deslocamento ao longo dos eixos.

translate - move um elemento em relação à sua posição atual. Leva um deslocamento no formato [x, y] , onde y é um parâmetro opcional

 <animateTransform attributeName="transform" type="translate" from="0, -10" to="0, 10" .../> 
Move o elemento ao longo da

rotação do eixo Y - gira o elemento em relação ao centro de rotação. Toma como ângulo o ângulo de rotação e as coordenadas do centro de rotação [deg, x, y] ; as coordenadas do centro são opcionais. Por padrão, o centro de rotação está no canto superior esquerdo do documento SVG

 <animateTransform attributeName="transform" type="rotate" from="0, 150, 150" to="45, 150, 150" .../> 
Gire 45 graus em torno de um ponto com as coordenadas 150, 150

Além disso, o centro de rotação pode ser alterado usando a propriedade CSS de origem da transformação , onde, além das coordenadas, você pode especificar porcentagens. Por padrão, as porcentagens são calculadas pelo tamanho de todo o documento. Para que as porcentagens sejam calculadas em relação ao elemento, é necessário definir a propriedade CSS da caixa de transformação com o valor da caixa de preenchimento .

escala - escala o item. Como valores, são aceitos números de ponto flutuante no formato [escala] para ambos os eixos ou separadamente para cada eixo [escalaX, escalaY] (1 corresponde ao tamanho normal do elemento). Se você não alterar a caixa de transformaçãoComo mencionei acima, o elemento é escalado em relação ao documento inteiro. O espaço vazio ao redor do elemento também muda com ele, então, visualmente, parece que o elemento é deslocado para o lado

 <animateTransform attributeName="transform" type="scale" from="1, 1" to="2, 1" .../> 
elemento trechos no eixo x

skewX ou skewY - desloca o elemento sobre o eixo. O valor assume o ângulo de inclinação [deg] . Por padrão, o centro de cisalhamento - no canto superior esquerdo, por isso aqui funciona o mesmo truque com a transformar-box e a origem transformar , como em outras transformações

 <animateTransform attributeName="transform" type="skewX" from="0" to="45" .../> <animateTransform attributeName="transform" type="skewY" from="90" to="0" .../> 
Um se desloca ao longo de X, outro ao longo de Y

Somatório e redefinição de transformações

No animateTransform , você ainda pode fazer animações cumulativas e relativas, mas aqui o atributo aditivo se comporta de maneira diferente. No valor de substituir, a transformação substitui todas as anteriores. No valor da soma , atransformação é somada com a anterior

 <rect transform="skewY(115)" ...> <animateTransform type="translate" from="-10" to="10" additive="replace" .../> <animateTransform type="rotate" from="0" to="90" additive="sum" .../> </rect> 
Neste exemplo, o deslocamento do retângulo será redefinido para mover e girar

<animateMotion>


Necessário para animar o movimento de um elemento ao longo de um caminho. animateMotion suporta atributos animados e tem 3 da sua própria - caminho , a rotação , Keypoints .

Opções para definir uma trajetória

Você pode definir uma trajetória de movimento de várias maneiras - use os atributos familiares de , para , por ou valores , o novo atributo de caminho ou uma marca filho <mpath> . Listei maneiras de aumentar a prioridade e vou explicá-las na mesma ordem.

Para atributos de , para, Por especificado coordenadas de pontos, valoriza o mesmo, mas já em uma lista

 <animateMotion from="0,0" to="50,100" .../> <animateMotion values="0,0; 0,100; 100,100; 0,0" .../> 

O efeito deste método é comparável à transformação usual de deslocamento. Um elemento se move retilínea de um ponto para outro. E aqui, assim como no animateTransform , as coordenadas são relativas . O ponto 0,0 não indica o canto superior esquerdo do documento, mas a posição atual do elemento de destino. Esse recurso está presente em outros métodos para determinar a trajetória.

O atributo path especifica um conjunto de comandos, como para o atributo d . Se no atributo d os comandos são interpretados como o contorno da figura, no atributo path eles são a linha pela qual o elemento se moverá. As coordenadas dos pontos também são relativas, portanto o caminho começa no ponto 0,0

 <animateMotion path="M 0 0 c 3.4 -6.8 27.8 -54.2 56 -37.7 C 73.3 -27.5 89.6 -5.1 81.9 5.9 c -5.8 8.3 -24.7 8.7 -45.4 -0.4" .../> 

Esse caminho descreve essa curva


A última maneira é usar um elemento <caminho> de terceiros como o caminho . Para fazer isso, você deve especificar um link para esse elemento na tag <mpath> , e a própria tag deve ser colocada dentro de <animateMotion> . Esta opção possui o mesmo recurso com coordenadas relativas. Na sua essência, esse método "copia" o valor do atributo d do elemento no atributo <path>

 <path id="movement" .../> ... <animateMotion ...> <mpath href="#movement"/> </animateMotion> 
O elemento que define o caminho pode nem aparecer no documento. Você pode simplesmente defini-lo em <defs>

Girar um elemento em relação à trajetória.É

possível fazer o elemento girar na direção do movimento usando o atributo rotate . Aceita 3 tipos de valores: automático , reverso automático e um número indicando rotação em graus

 <animateMotion rotate="auto" .../> 

Por padrão, girar é 0. Qualquer valor numérico captura o ângulo em toda a animação. Modo Automático automático e auto-inverter a mudança do elemento de ângulo, respectivamente tangente à trajectória. E eles diferem na direção dessa tangente. No automático, ele é direcionado para frente, enquanto no reverso automático , é direcionado para trás.


Como controlar o movimento ao longo do caminho?

A trajetória é uma curva que tem um começo e um fim, esses pontos são indicados pelos números 0 e 1, respectivamente. Qualquer posição na curva pode ser determinada por um número nesse intervalo. Ao listar os pontos no atributo keyPoints , você pode definir qualquer tipo de movimento ao longo do caminho. Mas isso não é suficiente para controlar o movimento, para isso você precisa de um sistema inteiro de atributos.

Primeiro, você precisa definir calcMode como linear ou spline . Ao contrário de outras tags, o animateMotion padroniza o ritmo (por algum motivo, a animação não deseja trabalhar nesse modo). Você também deve especificar um atributo.keyTimes . Somente concluindo essas etapas, a animação funcionará como deveria

 <animateMotion keyPoints="0.5; 1; 0; 0.5" keyTimes="0; 0.25; 0.75; 1" calcMode="linear" .../> 
No exemplo, a animação começa no meio do caminho, move-se para o fim, depois para o início e termina o movimento novamente no meio

PS

Ao lidar com o animateMotion , deparei- me com informações de que a mesma coisa pode ser feita em CSS. Mas no final deste artigo, eu não tinha força nem desejo de lidar com isso. Para os entusiastas, deixo um link para a documentação.


Agradecimentos especiais


Bhudh pelo tremendo trabalho de correção do artigo

Source: https://habr.com/ru/post/pt450924/


All Articles