Você está na página 1de 21

Capítulo 11.

Animação e Scripting SVG

Até este ponto temos produzido imagens estáticas; Uma vez construídas, elas nunca mudam. Dentro
deste capítulo, examinaremos dois métodos de fazer imagens gráficas móveis. O primeiro método,
animação, é o movimento que é controlado por você, o autor. O segundo método, scripting, permite
que a pessoa que vê o gráfico interaja até possa modificar a imagem.

No Capítulo 10, sugerimos que os filtros devem ser usadas como um meio para melhorar um gráfico de
mensagem, não como um fim em si mesmos. Esta sugestão é ainda mais crucial com animação.
Embriagado com o poder da animação, você será tentado fazer cada gráfico dançar na tela, todos
cantando, Broadway espetacular. Enquanto o seu objetivo é experimentação, isso é bom. Se seu objetivo
é transmitir uma mensagem, no entanto, nada é pior do que a utilização gratuita ou uso excessivo de
animação.

Neste capítulo, a nossa mensagem é a animação, por isso a maioria dos nossos exemplos serão
notavelmente livre de qualquer conteúdo. Vamos, naturalmente, evitar animação gratuita e exagerada
tanto quanto possível.

11.1 Animação básica

Os recursos de animação em SVG são baseados no World Wide Web Consortium de Synchronized
Multimedia Integration Language Nível 2 (SMIL2) Especificação http://www.w3.org/TR/smil20/.
Neste sistema, você especifica os valores inicial e final do atributo, cor, movimento, ou a transformação
que você deseja animar; o momento em que a animação deve começar; e a duração da animação.

<rect x="10" y="10" width="200" height="20" stroke="black" fill="none">[1]


<animate [2]
attributeName="width" [3]
attributeType="XML" [4]
from="200" to="20" [5]
begin="0s" dur="5s" [6]
fill="freeze" /> [7]
</rect>

[1] O elemento <rect> sem o término />. A animação estará contida dentro do elemento.
[2] Começa a especificação da animação
[3] Especifica o atributo cujo valor deve mudar ao longo do tempo.
[4] A largura é um atributo XML no elemento <rect>. O outro valor comum de "attributeType" é CSS,
que indica que a propriedade que queremos mudar é uma propriedade CSS. Se você deixar isso
desligado, o valor padrão de "auto" é usado; Procura-se nas propriedades CSS primeiro, e depois em
atributos XML.
[5] Os atributos com os valores de início e fim. Neste exemplo, o valor de início é 200 e o valor final é
20. Há também um atributo "by", que você pode usar em vez de "to"; é um deslocamento que é
adicionado ao valor de início "from"; o resultado é o valor final.
[6] O início e tempos de duração para a animação. Neste exemplo, nós medimos tempo em segundos,
especificado pela letra "s" após o número. Para mais detalhes, consulte a Seção 11.2.
[7] Após os cinco segundos de duração, mantenha o atributo no seu valor final. Se você remover esta
linha, o atributo irá retornar ao seu valor original de 200 após os cinco segundos de animação
terminarem. Este é o atributo SMIL "fill", que diz ao motor de animação como preencher o tempo
restante. Não confundir com o atributo de preenchimento de SVG, que conta SVG para pintar um
objeto.
[8] Nós temos que fechar o elemento <rect>, uma vez que é agora um elemento container.

Múltiplas animações para um objeto

<rect x="10" y="10" width="20" height="20" style="stroke: black; fill: green; style: fill-opacity: 0.25;">
<animate attributeName="width" attributeType="XML" from="20" to="250" begin="0s" dur="8s" fill="freeze"/>
<animate attributeName="height" attributeType="XML" from="20" to="200" begin="0s" dur="8s" fill="freeze"/>
<animate attributeName="fill-opacity" attributeType="CSS" from="0.25" to="1" begin="0s" dur="3s"
fill="freeze"/>
<animate attributeName="fill-opacity" attributeType="CSS" from="1" to="0.25" begin="3s" dur="3s"
fill="freeze"/>
</rect>

Uma animação para múltiplos objetos

<rect x="10" y="10" width="20" height="20" style="stroke: black; fill: #cfc;">


<animate attributeName="width" attributeType="XML" begin="0s" dur="8s" from="20" to="120" fill="freeze"/>
<animate attributeName="height" attributeType="XML" begin="0s" dur="8s" from="20" to="120" fill="freeze"/>
</rect>
<circle cx="70" cy="70" r="20" style="fill: #ccf; stroke: black;">
<animate attributeName="r" attributeType="XML" begin="2s" dur="4s" from="20" to="50" fill="freeze"/>
</circle>

11.2 Como o tempo é medido

O relógio de animação do SVG começa a contar quando o SVG termina de carregar, e ele pára
assinalando quando o usuário sai da página. Você pode especificar um início ou duração de um
determinado segmento de animação como um valor numérico em uma das seguintes formas:
• Um valor integral de relógio em horas, minutos e segundos (1:20:23).
• Um valor de relógio parcial em minutos e segundos (2:15).
• Um valor de tempo, seguido por um "métrica", que é um h (hora), min (minutos), s
(segundos), ou ms (milissegundos), por exemplo dur = "3.5s" begin = "1min".
Se a métrica não for especificada, o padrão é segundos. Você não pode colocar qualquer espaço em
branco entre o valor e a métrica.
Você também pode amarrar a hora de início de uma animação para o início ou fim de uma outra
animação. O exemplo a seguir mostra dois círculos; o segundo começará a expandir mais rapidamente
quando o primeiro parar de encolher.

<circle cx="60" cy="60" r="30" style="fill: #f9f; stroke: gray;">


<animate id="c1" attributeName="r" attributeType="XML" begin="0s" dur="4s" from="30" to="10"
fill="freeze"/>
</circle>
<circle cx="120" cy="60" r="10" style="fill: #9f9; stroke: gray;">
<animate attributeName="r" attributeType="XML" begin="c1.end" dur="4s" from="10" to="30"
fill="freeze"/>
</circle>

É também possível adicionar um deslocamento para esta sincronização. Para fazer uma animação iniciar
dois segundos depois de outra animação, você poderia usar uma construção assim: "begin" =
"otherAnim.end + 2s". (Você pode adicionar um espaço em branco em torno do sinal de mais.) O
deslocamento deve ser positivo; para fazer ponto de partida de uma animação: begin = "otherAnim.end
– 2s" exigiria o computador olhar para o futuro, e não há tal coisa como gráficos vetoriais físicos. No
próximo exemplo, o segundo círculo começa a crescer e um quarto de segundos após, o primeiro círculo
começa a encolher.

<circle cx="60" cy="60" r="30" style="fill: #f9f; stroke: gray;">


<animate id="c1" attributeName="r" attributeType="XML" begin="0s" dur="4s" from="30" to="10" fill="freeze"/>
</circle>
<circle cx="120" cy="60" r="10" style="fill: #9f9; stroke: gray;">
<animate attributeName="r" attributeType="XML" begin="c1.begin+1.25s" dur="4s" from="10" to="30"
fill="freeze"/>
</circle>

Agora que sabemos sobre sincronização de animações, podemos introduzir o atributo final, que define
um horário de término para uma animação. Este não é um substituto para o atributo "dur". A seguinte
animação vai começar seis segundos após a página ser carregada, e terá a duração de doze segundos ou
até uma animação chamada "otherAnim" terminar; o que quer que venha primeiro.

<animate attributeName="width" attributeType="XML" begin="6s" dur="12s" end="otherAnim.end"


from="10" to="100" fill="freeze"/>

Você pode, é claro, definir o valor final para um número; isto é útil para travar uma animação a meio
para que você possa ver se está tudo no lugar certo. Assim é como fomos capazes de criar a figura a
seguir. A próxima animaçãocomeça em seis segundos, e deve durar por doze segundos, mas é
interrompida em nove segundos.

<animate attributeName="width" attributeType="XML" begin="6s" dur="12s" end="9s" from="10" to="100"


fill="freeze"/>

11.3 Ação repetida

As animações que produzimos até agora ocorrem exatamente uma vez; Definimos o atributo "fill" como
"freeze" para manter a fase final da animação. Se quisermos ter o retorno do objeto para o seu estado de
pré-animação omitimos o atributo. (Isto é equivalente a definir "fill" com o valor padrão de "remove".)

Dois outros atributos permitem que você repita uma animação. O primeiro deles, "repeatCount", é
definido para um valor inteiro contando quantas vezes você quiser repetir uma animação em especial.
A segunda, "repeatDur", é definida como um período que nos diz quanto tempo a repetição deve durar.
Se vocês querem repetir uma animação até que o usuário deixe a página, defina tanto "repeatCount"
quanto "repeatDur" para valor "idefinite". A animação no exemplo a seguir mostra dois círculos. Os
movimentos circulares superiores da esquerda para a direita em duas repetições de cinco segundos de
cada vez. O segundo círculo se move da direita para a esquerda, para um total de oito segundos.

<circle cx="60" cy="60" r="30" style="fill: none; stroke: red;">


<animate attributeName="cx" attributeType="XML" begin="0s" dur="5s" repeatCount="2" from="60" to="260"
fill="freeze"/>
</circle>
<circle cx="260" cy="130" r="30" style="fill: #ccf; stroke: black;">
<animate attributeName="cx" attributeType="XML" begin="0s" dur="5s" repeatDur="8s" from="260" to="60"
fill="freeze"/>
</circle>
Assim como foi possível sincronizar uma animação com o início ou o fim de outra animação, podemos
amarrar o início de uma animação para o início de uma repetição específica de outra animação. Você dá
à primeira animação um "id", em seguida, define o início da segunda animação para
"id.repeat(contagem)", onde a contagem é um número começando em zero para a primeira repetição.
No exemplo a seguir, temos um círculo superior movendo-se da esquerda para a direita três vezes,
exigindo cinco segundos para cada repetição. O quadrado menor vai da direita para a esquerda apenas
uma vez, e não começará até a meio da segunda repetição. (Usamos um deslocamento para atingir este
efeito.)

<circle cx="60" cy="60" r="30" style="fill: none; stroke: red;">


<animate id="circle-anim" attributeName="cx" attributeType="XML" begin="0s" dur="5s"
repeatCount="3" from="60" to="260" fill="freeze"/>
</circle>
<rect x="230" y="100" width="60" height="60" style="fill: #ccf; stroke: black;">
<animate attributeName="x" attributeType="XML" begin="circle-anim.repeat(1) + 2.5s" dur="5s"
from="230" to="30" fill="freeze"/>
</rect>

11.4 O elemento "set"

Todas estas animações têm valores numéricos modificado ao longo do tempo. Você pode querer definir
um atributo ou propriedade que não seja numérico. Por exemplo, você pode querer que um item de
texto, inicialmente invisível, torne-se visível em um determinado momento; não há nenhuma
necessidade real tanto do "from" quanto do "to". O elemento <set> pode substituir esses dois atributos,
atribuindo-lhe apenas a informação de tempo adequada. O exemplo abaixo encolhe um círculo para até
zero, em seguida, revela o texto meio segundo depois que o círculo se foi.

<circle cx="60" cy="60" r="30" style="fill: #ff9; stroke: gray;">


<animate id="c1" attributeName="r" attributeType="XML" begin="0s" dur="4s" from="30" to="0" fill="freeze"/>
</circle>
<text text-anchor="middle" x="60" y="60" style="visibility: hidden;">
<set attributeName="visibility" attributeType="CSS" to="visible" begin="4.5s" dur="1s" fill="freeze"/>
All gone!
</text>

11.5 O elemento animateColor

O elemento <animate> não funciona com cores, uma vez que a cor não é representado como um valor
numérico simples. Em vez disso, o elemento especial <animateColor> preenche essa finalidade. Seus
atributos "from" e "to" são valores de cor, conforme descrito no Capítulo 3, na Seção 3.2.2. No
exemplo a seguir nós animaremos as cores de preenchimento e traçado de um círculo, alterando o
preenchimento de amarelo claro para o vermelho e o contorno, de cinza para o azul. Ambas as
animações iniciam dois segundos depois que a página é carregada; Isso lhes dá tempo para ver as cores
originais.

<circle cx="60" cy="60" r="30" style="fill: #ff9; stroke: gray; stroke-width: 10;">
<animateColor attributeName="fill" begin="2s" dur="4s" from="#ff9" to="red" fill="freeze"/>
<animateColor attributeName="stroke" begin="2s" dur="4s" from="gray" to="blue" fill="freeze"/>
</circle>
Se você tem várias animações para um objeto específico, uma animação pode referir-se a uma anterior
com a palavra-chave "prev". Poderíamos reescrever o exemplo anterior assim, amarrando duas
animações relacionadas em conjunto com "prev" permite que você altere os dois editando apenas a
primeira.

11.6 O elemento <animateTransform>

Assim como <animate> não funciona com as cores, ele não funciona com transformações de rotação,
translação, escala, ou inclinação, uma vez que todos eles são "embrulhados" no interior do atributo
"transform". O elemento <animateTransform> vem para corrigir esta falta. Você define o seu
"attributeName" para "transform". O valor do atributo "type", em seguida, especifica a transformação
cujos valores devem mudar (um dos "translate", "scale", "rotate", "skewX", ou skewY). Os valores
"form" e "to" são especificados conforme apropriado para a transformação que você está animando.

O próximo exemplo apresenta a transformação de um retângulo de escala normal a uma escala de


quatro vezes na direção horizontal e duas vezes na direção vertical. Note que centramos o retângulo em
torno da origem para que ele não se mova com a escala; nós colocá-lo dentro de um <g> por isso pode
ser movido para um local mais conveniente.

<g transform="translate(120,60)">
<rect x="-10" y="-10" width="20" height="20" style="fill: #ff9; stroke: black;">
<animateTransform attributeType="XML" attributeName="transform" type="scale" from="1" to="4 2"
begin="0s" dur="4s" fill="freeze"/>
Stretch
</rect>
</g>

Se você pretende animar mais de uma transformação, você deve usar o atributo "additive". O valor
padrão de "additive" é "replace", que substitui a transformação especificada no objeto que está sendo
animado. Isso não vai funcionar em uma série de animações, desde que a segunda animação iria
substituir a primeira. Ao definir "additive" para "sum", o SVG irá acumular as transformações.

<rect x="-10" y="-10" width="20" height="20" style="fill: #ff9; stroke: black;">


<animateTransform attributeName="transform" attributeType="XML" type="scale" from="1" to="4 2"
additive="sum" begin="0s" dur="4s" fill="freeze"/>
<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="45"
additive="sum" begin="0s" dur="4s" fill="freeze"/>
</rect>

11.7 O elemento <animateMotion>

Usando "translate" com o elemento <animateTransform>, você pode fazer um objeto se mover ao longo
de um caminho em linha reta. O elemento <animateMotion> permite que você faça isso também; Só
que, além disso, ele permite que você anime um objeto ao longo de um caminho arbitrário.

Se você quiser usar <animateMotion> para movimento em linha reta, você simplesmente define os
atributos "from e "to" com um par de (x, y) coordenadas para cada um.
<g>
<rect x="0" y="0" width="30" height="30" style="fill: #ccc;"/>
<circle cx="30" cy="30" r="15" style="fill: #cfc; stroke: green;"/>
<animateMotion from="0,0" to="60,30" dur="4s" fill="freeze"/>
</g>

Se você quiser seguir um caminho mais complexo, use o atributo <path>; seu valor está no mesmo
formato que o atributo "d" no elemento <path>.

<!-- mostra o caminho ao longo do qual o triângulo se moverá -->


<path d="M50,125 C 100,25 150,225, 200, 125" style="fill: none; stroke: blue;"/>
<!-- Triângulo para ser deslocado ao longo do caminho de movimento. Define-se com uma orientação vertical com a
base do triângulo centrado horizontalmente logo acima da origem. -->
<path d="M-10,-3 L10,-3 L0,-25z" style="fill: yellow; stroke: red;">
<animateMotion path="M50,125 C 100,25 150,225, 200, 125" dur="6s" fill="freeze"/>
</path>

Se você preferir que o objeto de inclinação em seu eixo-x seja sempre paralelo à inclinação do
caminho, basta adicionar o atributo "rotate" com um valor de "auto" para o elemento
<animateMotion>.

<!-- mostra o caminho ao longo do qual o triângulo se moverá -->


<path d="M50,125 C 100,25 150,225, 200, 125" style="fill: none; stroke: blue;"/>
<!-- Triângulo para ser deslocado ao longo do caminho de movimento. Define-se com uma orientação vertical com a
base do triângulo centrado horizontalmente logo acima da origem. -->
<path d="M-10,-3 L10,-3 L0,-25z" style="fill: yellow; stroke: red;" >
<animateMotion path="M50,125 C 100,25 150,225, 200, 125" rotate="auto" dur="6s"
fill="freeze"/>
</path>

Simplificando, quando você deixar de fora o atributo "rotate", você terá o valor padrão de zero, e o
objeto funcionará como um balão de ar quente que flutua ao longo do caminho. Se você definir "rotate"
para "auto", o objeto funciona como um carro em uma montanha russa, inclinando cima e para baixo
seguindo o caminho faz.

Você também pode definir "rotate" para um valor numérico, que irá definir a rotação do objeto em toda
a animação. Assim, se você queria um objecto rodado 45 graus não importa que direção o caminho
tomou, você usaria rotate = "45".

No Exemplo anterior, traçamos o caminho em azul para que ele seja visível, e, em seguida, duplicamos o
path no elemento <animateMotion>. Você pode evitar essa duplicação, adicionando um elemento
<Mpath> dentro do elemento <animateMotion>.
O <mpath> contém um atributo "xlink: href" que referencia o caminho que você deseja usar. Isto
também vem a calhar quando você tem um caminho que deseja usar para animar vários objetos. Aqui
está o exemplo anterior, reescrito como usando <mpath>.

<path id="cubicCurve" d="M50,125 C 100,25 150,225, 200, 125" style="fill: none; stroke: blue;"/>
<path d="M-10,-3 L10,-3 L0,-25z" style="fill: yellow; stroke: red;" >
<animateMotion dur="6s" rotate="auto" fill="freeze">
<mpath xlink:href="#cubicCurve"/>
</animateMotion>
</path>
11.8 Usando links em SVG

Até este ponto, você, o autor do documento SVG, tomou todas as decisões sobre os gráficos. Você
decide com o que a imagem deve se parecer, e, se houver animações, você decide quando iniciar e
quando parar. Nesta seção, vamos ver como entregar alguns dos controles para a pessoa que está vendo o
seu documento.

O tipo mais fácil de interatividade para fornecer é o "link", realizado com o elemento <a>. Delimitando
um gráfico com este elemento, o o gráfico torna o link ativo; quando clicado, você vai para o URL
especificado no atributo "xlink: href". Você pode conectar-se a outro arquivo SVG ou, dependendo do
seu ambiente, a uma página web. No Exemplo a seguir, clicando na palavra "Gato" você vai conectar-se
a um desenho SVG de um gato; clicando nas formas de vermelho, verde e azul vai para a página SVG
do Consórcio World Wide Web. Todos os itens dentro da segunda ligação são individualmente ligados
ao mesmo destino, e não toda a caixa delimitadora. Quando você testar este exemplo e mover o cursor
entre as formas, você vai ver que aquelas áreas não estão ligadas.

<a xlink:href="cat.svg">
<text x="100" y="30" style="font-size: 12pt;">Cat</text>
</a>
<a xlink:href="http://www.w3.org/SVG/">
<circle cx="50" cy="70" r="20" style="fill: red;"/>
<rect x="75" y="50" width="40" height="40" style="fill: green;"/>
<path d="M120 90, 140 50, 160 90 Z" style="fill: blue;"/>
</a>

É interessante notar que "xlink: href" tem um prefixo "namespace"; embora este atributo seja duplicado
na especificação SVG, que pertence à especificação "xlink". A DTD SVG lida com a declaração de
"namespace".

11.9 Scripting SVG

O próximo passo da ligação - e é um grande passo - é o scripting. Você pode escrever um programa em
ECMA Script (padrão European Computer Manufacturer's Association, comumente chamada de
JavaScript) para interagir com um gráfico SVG. A interação ocorre quando objetos gráficos respondem a
eventos.

Os objetos podem responder a eventos do mouse associados ao clicar no botão do mouse: "click",
"mousedown", "mouseup" e eventos associados ao mover o mouse: "mouseover" (o ponteiro do mouse
está dentro do objeto), "mouseout" (o ponteiro do mouse deixa o objeto), e "mousemove"; eventos
associados ao status de um objeto: "load" (o objeto foi totalmente analisado e está pronto para ser
renderizado); e os eventos não-padronizados associados ao pressionar das teclas do teclado: "keydown" e
"keyup".

Para permitir que um objeto responda a um evento, você adiciona um atributo "OnEventName" ao
elemento em questão. O valor do atributo será uma declaração ECMA Script, normalmente uma
chamada de função. Esta função geralmente toma a palavra reservada "evt" como um dos seus
parâmetros.
A palavra reservada "evt" tem propriedades e métodos que descrevem o caso em que tenha ocorrido. Os
três métodos que você usará com mais freqüência são "getTarget()", que retorna uma referência para o
objeto gráfico que responde a este evento, e "getClientX()" e "getClientY()", que retornam as
coordenadas X e Y do mouse onde o evento ocorreu. Um valor de (0,0) indica o canto superior
esquerdo da janela de exibição SVG. Essas funções retornam a posição na janela de visualização,
independentemente de qualquer "zoom" ou "pan" que o usuário tenha feito.

11.9.1 Mudando atributos de um único objeto

O tipo mais simples de manipulação de eventos é o lugar onde um evento que ocorreu em um objeto X
modificou algum atributo do objeto. Vejamos no exemplo a seguir, o que responde o objeto círculo para
o evento "mouseover", fazendo o raio do círculo maior. O círculo vai responder ao "mouseout"
tornando o raio menor.

<script type="text/ecmascript"> [1]


<![CDATA[ [2]
function enlarge_circle(evt) [3]
{
var circle = evt.getTarget(); [4]
circle.setAttribute("r", 50); [5]
}
function shrink_circle(evt) [6]
{
var circle = evt.getTarget();
circle.setAttribute("r", 25);
}
// ]]> [7]
</script>
<circle cx="150" cy="100" r="25" fill="red" [8] onmouseover="enlarge_circle(evt)" [9]
onmouseout="shrink_circle(evt)"/>
<text x="150" y="175" style="text-anchor: middle;"> Ao passar o mouse (mouseover), o círculo muda o seu
tamanho.</text>

[1] A tag de início <script> indica que você está se preparando para deixar o mundo da SVG / XML e
entrar no ambiente ECMA Script. O atributo "type" informa qual linguagem de script que você está
usando.

[2] Em XML, o sinal "<" introduz uma tag, e o símbolo comercial é usado para evitar o uso de
caracteres (ver Apêndice A na Seção A.2.5). Desde que o ECMA Script não é XML, queremos desativar
esse comportamento especial. O "<! [CDATA [" diz ao XML para parar de tratar o símbolo "<" e o
símbolo comercial como especiais; eles se tornam conteúdo comum, que é como o ECMA Script gosta.
Isto conclui a nossa saída do mundo do SVG/XML e nos imerge no ambiente ECMA Script.

[3] A primeira função, "enlarge_circle()", assume um parâmetro; o evento que desencadeou a chamada
da função.

[4] Usamos o "evt.getTarget" para retornar uma referência para o objeto gráfico que desencadeou o
evento, e armazená-lo na variável círculo.

[5] Para alterar um atributo de um objeto gráfico, chamamos a função "setAttribute" do objeto com
dois parâmetros: o nome do atributo que você deseja mudar, e seu novo valor. "setAttribute" é uma
função vazia; ele não retorna nenhum valor. Há uma função correspondente "getAttribute" que toma
como parâmetro o nome do atributo; ela retorna uma representação string do valor atual do atributo.
Estas funções são parte do DOM, ou Document Object Model. O DOM é uma API padrão para
acessar, modificar e rearranjar os elementos em um documento XML.

[6] Esta função, modelada exatamente como a anterior, irá definir o atributo "r" do evento-alvo para
25.

[7] A "]]>" termina a "<! [CDATA [" iniciada na segunda linha do script. Ele retorna o símbolo "<" e
comercial para o seu estado XML, apenas a tempo para fechar o script </ script> na linha seguinte,
deixando o ECMA Script e retornando ao mundo do SVG / XML. As barras à esquerda na linha 16
introduzem um comentário ECMAScript, assegurando que o resto da linha não é interpretado como
parte do script. (Isso não é necessário com a versão 2.0 do Adobe plugin, mas outras aplicações XML
podem exigir as barras.)

[8] Uma vez que será a criação de um atributo para mudar a cor, nós especificamos a cor de
preenchimento com um atributo de apresentação. Nós não podemos usar o estilo, porque a sua
definição substitui o valor de um atributo de apresentação.

[9] Aqui é a nossa ponte entre o mundo do SVG e do mundo ECMA Script. O manipulador de
eventos " onmouseover" irá chamar a função "enlarge_circle()", eo manipulador de eventos
"onmouseout" vai chamar a função "shrink_circle()". Neste contexto, "evt" é fornecido pelo ambiente
visualizador SVG.

11.9.2 Mudando Atributos de vários objetos

Às vezes você vai querer que um evento que ocorre no objeto A afete os atributos um outro objeto B. O
exemplo a seguir mostra uma camiseta cujo tamanho é alterado à medida que o usuário clica em cada
botão rotulado. O tamanho do botão selecionado atualmente é destaque na luz amarela.

<svg width="400" height="250" viewBox="0 0 400 250" onload="init(evt)"> [1]


<script type="text/ecmascript">
<![CDATA[
var scaleChoice = 1; [2]
var scaleFactor = new Array(1.25, 1.5, 1.75);
function init(evt)
{
transformShirt();
}
function setScale(n)
{
obj = svgDocument.getElementById("scale" + scaleChoice); [3]
obj.setAttribute("fill", "white");
scaleChoice = n;
obj = svgDocument.getElementById("scale" + scaleChoice);
obj.setAttribute("fill", "#ffc");
transformShirt();
}
function transformShirt()
{
var obj = svgDocument.getElementById("shirt"); [4]
obj.setAttribute("transform",
"scale(" + scaleFactor[scaleChoice] + ")"
);
obj.setAttribute("stroke-width",
1 / scaleFactor[scaleChoice]);
}
// ]]>
</script>
<defs>
<path id="shirt" [5]
d="M -6 -30, -32 -19, -25.5 -13, -22 -14, -22 30, 23 30, 23 -14, 26.5 -13, 33 -19, 7 -30 A 6.5 6 0 0 1 -6
-30" fill="white" stroke="black"/> [6]
</defs>
<use xlink:href="#shirt" x="150" y="150"/>
<g onclick="setScale(0)"> [7]
<rect id="scale0" x="100" y="10" width="30" height="30" fill="white" stroke="black"/>
<text x="115" y="30" text-anchor="middle">S</text>
</g>
<g onclick="setScale(1)">
<rect id="scale1" x="140" y="10" width="30" height="30" fill="#ffc" stroke="black"/> [8]
<text x="155" y="30" text-anchor="middle">M</text>
</g>
<g onclick="setScale(2)">
<rect id="scale2" x="180" y="10" width="30" height="30" fill="white" stroke="black"/>
<text x="195" y="30" text-anchor="middle">L</text>
</g>
</svg>

[1] Assim que o documento terminar de carregar, ocorre a carga do evento, e o manipulador "onload"
irá chamar a função "init", passando as informações do evento. A maioria vai usar scripts com esse
manipulador de eventos para se certificar de que todas as suas variáveis serão configuradas corretamente.

[2] Este script funciona para atribuir o controle ao botão (S, M ou L) que for escolhido, e indexar na
entrada correspondente da matriz "ScaleFactor". O padrão é índice número um, médio.

[3] "svgDocument" é uma referência para todo o documento SVG, e nós usaremos as suas propriedades
e métodos para acessar as partes do documento que precisamos. O script inteiro depende da utilização
da função "getElementById" do documento. A função "getElementById" recebe uma string como
parâmetro, e retorna o objeto que tem essa string como seu "id". A função "setScale" encontra o botão
atualmente escolhido e volta sua cor de preenchimento para branco. Em seguida, atualiza a escolha
atual, e muda a cor de preenchimento do botão para luz amarela. Finalmente, ele atualiza a imagem da
camisa.

[4] Depois, a função "transformShirt()" insta "getElementById" do documento para acessar o objeto
gráfico com "id" da camisa, e muda seu atributo "transform" para a escala apropriada. Também define o
"stroke-width" para a recíproca do fator de escala de modo que a largura do traçado da borda da camisa
seja sempre igual a um.

[5] Está aqui a camisa; ela está centrada em torno de (0,0) então ela vai aparecer para expandir em torno
do seu centro.

[6] Uma vez que estamos mudando os atributos no script, temos que usar os atributos de apresentação
em vez de estilos. (Se usássemos estilos, eles iriam substituir quaisquer definições de atributos.)

[7] Cada um dos botões irá chamar a função "setScale" Quando clicado; o parâmetro dá o índice para o
fator de escala, e elemento de cada botão <rect> é nomeado com o número correspondente no final.

[8] O botão padrão tem um fundo definido como amarelo-leve quando o documento carrega.

11.9.3 Arrastar objetos (dragging)

Vamos expandir esse exemplo adicionando "Sliders" que podem ser arrastados para definir a cor da
camisa, como mostrado na figura abaixo.

Vamos precisar de algumas variáveis globais a mais no script. A primeira delas, o "slideChoice", para
quando o "slider" (0, 1, ou 2) está sendo arrastado; o seu valor inicial é -1, significando que o controle
deslizante não está ativo. Também vamos usar um array chamado "rgb" para manter o percentual de
vermelho, verde, e azul; os valores iniciais são 100, uma vez que a camisa é inicialmente branca.

var slideChoice = -1;


var rgb = new Array(100, 100, 100);

Vamos agora desenhar os controles deslizantes. A barra de cores e o indicador de slides são desenhados
em um fundo branco, e estão agrupados. O atributo "id" vai sobre o elemento indicador <line>, uma
vez que suas coordenadas y estarão mudando. Os manipuladores de eventos serão ligados ao elemento
delimitador <g>. O grupo, então, irá capturar os eventos de mouse que acontecerem em qualquer um
dos seus elementos filho. (É por isso que fundo desenhado é branco; o mouse ainda irá acompanhar,
mesmo se você arrastar fora da barra colorida.)

<g onmousedown="startColorDrag(0)" onmouseup="endColorDrag()" onmousemove="doColorDrag(evt,0)"


transform="translate(230, 10)">
<rect x="-10" y="-5" width="40" height="110" style="fill: white;"/>
<rect x="5" y="0" width="10" height="100" style="fill: red;"/>
<line id="slide0" x1="0" y1="0" x2="20" y2="0" style="stroke: gray; stroke-width: 2;"/>
</g>
<g onmousedown="startColorDrag(1)" onmouseup="endColorDrag()" onmousemove="doColorDrag(evt,1)"
transform="translate(280, 10)">
<rect x="-10" y="-5" width="40" height="110" style="fill: white;"/>
<rect x="5" y="0" width="10" height="100" style="fill: green;"/>
<line id="slide1" x1="0" y1="0" x2="20" y2="0" style="stroke: gray; stroke-width: 2;"/>
</g>
<g onmousedown="startColorDrag(2)" onmouseup="endColorDrag()" onmousemove="doColorDrag(evt,2)"
transform="translate(330, 10)">
<rect x="-10" y="-5" width="40" height="110" style="fill: white;"/>
<rect x="5" y="0" width="10" height="100" style="fill: blue;"/>
<line id="slide2" x1="0" y1="0" x2="20" y2="0" style="stroke: gray; stroke-width: 2;"/>
</g>

As funções correspondentes são os seguintes:

/*
Para ao arrastar o cursor atual (se houver) e define o controle deslizante atual para o especificado.
* (0 = red, 1 = green, 2 = blue)
*/
function startColorDrag(which)
{
endColorDrag();
slideChoice = which;
}
/*
* Define o slider escolhido para -1, indicando que o slider começa a ser arrastado
*/
function endColorDrag()
{
slideChoice = -1;
}
/*
* Move o cursor especificado em resposta ao evento "MouseMove"
*/
function doColorDrag(evt, which)
{
/*
* Se o controle deslizante não estiver ativo, ou o evento é em um slider diferente daquele ativo, não
faça nada
*/
if (slideChoice < 0 || slideChoice != which)
{
return;
}
/*
* Obtém o objeto linha indicadora do controle deslizante e a posição do mouse (em relação à parte
superior da barra de cores)
*/
var obj = evt.getTarget();
var pos = evt.getClientY() - 10;
/* Valores entre 0..100 */
if (pos < 0) { pos = 0; }
if (pos > 100) { pos = 100; }
/* Move a linha de controle deslizante para a nova posição do mouse*/
obj = svgDocument.getElementById("slide" + slideChoice);
obj.setAttribute("y1", pos);
obj.setAttribute("y2", pos);
/* Calcula o novo valor de cor para esse slider */
rgb[slideChoice] = 100-pos;
/*
* Junta todos os valores de cor e muda a cor da camisa conforme a escolha.
*/
var colorStr = "rgb(" + rgb[0] + "%," +
rgb[1] + "%," + rgb[2] + "%)";
obj = svgDocument.getElementById("shirt");
obj.setAttribute("fill", colorStr);
}

Há apenas um ponto de menor importância para cuidar - o documento responderá a um "onmouseup"


somente se ele ocorre dentro da área do controle deslizante. Então, se você clicar com o mouse sobre a
barra de cores vermelho, arrastar o mouse para baixo para a camisa, em seguida, soltar o botão do
mouse, o documento não reagirá a isso. Quando você, em seguida, mover o mouse sobre o nível
vermelho de novo, ele ainda vai seguir o mouse. Para resolver este problema, insira um retângulo
transparente que cubra completamente a janela de exibição, faça-o responder a um evento "mouseup"
chamando "stopColorDrag". Ele será o primeiro, e, portanto, mais inferior objeto no gráfico. Faça o
retângulo o mais discreto possível, será definido para style = "fill: none;". "Mas espere", você interpõe.
"A área transparente não pode responder a um evento!" Não, ordinariamente não pode, mas podemos
definir o atributo "pointer-event" como "visible", o que significa que um objeto pode ser reservado a
responder a eventos, desde que seja visível, não importa qual a sua opacidade.

<rect x="0" y="0" width="400" height="300" style="fill: none;" onmouseup="endColorDrag()" pointer-


events="visible"/>

11.9.4 Modificando Texto

Embora os controles deslizantes nos dêm a interatividade que queremos, é difícil julgar as porcentagens
por olho. Nós prefirimos muito mais mostrar as porcentagens de vermelho, verde e azul por baixo de
cada controle deslizante, como representado na figura abaixo.
Aqui está o SVG para o texto embaixo do controle deslizante vermelho; os controles deslizantes sob o
azul e verde têm ids de PCT1 e PCT2. Este elemento vai entrar em um grupo separado da barra de
cores e linha de controles deslizantes de modo que também não se torna clicável.

<text id="pct0" x="10" y="120" style="font-size: 9pt; text-anchor: middle;">100%</text>

O número que queremos mudar à medida que arrastamos o mouse não é um atributo; é o filho do
elemento <text>, por isso não podemos usar "setAttribute" para modificar o texto. Em vez disso, temos
que criar um novo nó de texto e inseri-lo na árvore do documento no lugar do antigo. Aqui está o
código que adicionamos no fim da função "ColorDrag". A primeira linha recupera o elemento <text>.
(A variável "obj" já foi declarada, por isso, não precisa escrever "var" novamente.) A segunda linha pede
ao documento para criar um novo nó de texto cujo conteúdo é a porcentagem do controle deslizante
atualmente escolhido. Este nó de texto precisa ser colocado no seu local adequado dentro da árvore do
documento. Isso é o que a terceira linha faz; ela substitui o primeiro filho do elemento de texto com o
nó recém-criado.

obj = svgDocument.getElementById("pct" + slideChoice);


var newText = svgDocument.createTextNode(rgb[slideChoice] + "%");
obj.replaceChild(newText, obj.getFirstChild());

11.9.5 Interagindo com uma página HTML

É possível incorporar um gráfico SVG em uma página da Web usando o elemento <embed>. Os
atributos relevantes são o "src" para o gráfico (a URL), o "width" e o "height" do gráfico, e o atributo
"type", que será "image/svg + xml". Uma vez incorporado, você pode adicionar código para o script
SVG e os scripts da página HTML para que eles possam se comunicar com uma outra.

Nosso objetivo neste exemplo é incorporar o exemplo SVG anterior em uma página web. A página web
terá uma forma que permite que os usuários digitem as porcentagens de vermelho, verde e azul. Os
valores que entram serão refletidos nos controles deslizantes. Se eles podem ajustar os controles
deslizantes, os valores nos campos do formulário serão atualizados em conformidade.

Aqui é o documento HTML, com referências à (ainda não escrita) função "updateSVG". Esta função
irá pegar o número digitado no campo e o valor atualmente dentro do campo de entrada.

<html>
<head>
<title>SVG e HTML</title>
</head>
<body bgcolor="white">
<h2>SVG e HTML</h2>
<div align="center">
<embed src="shirt_interact.svg" width="400" height="250" type="image/svg+xml" />
<form name="rgbForm">
Red: <input id="fld0" type="text" size="5" value="100" onchange="updateSVG(0, this.value)" />%<br />
Green: <input id="fld1" type="text" size="5" value="100" onchange="updateSVG(1, this.value)" />%<br />
Blue: <input id="fld2" type="text" size="5" value="100" onchange="updateSVG(2, this.value)" />%
</form>
</div>
</body>
</html>
Aqui está o script que vai para o cabeçalho do documento HTML. A função "updateSVG" verifica se o
valor de entrada é um número inteiro (ela irá descartar qualquer parte decimal), e, em caso afirmativo,
chama "setShirtColor". A função "setShirtColor" é realmente uma referência a uma função que existe
no Documento SVG, e será de responsabilidade do documento SVG ligar a função referência HTML
para esta.

A função "updateHTMLField" será chamada a partir dos scripts de documentos SVG. Ela vai receber
um número de campo de formulário e um valor percentual, que irá exibir no campo de formulário
adequado.

<script language="Javascript">
<!--
function updateSVG(which, amount)
{
amount = parseInt(amount);
if (!isNaN(amount))
{
window.setShirtColor(which, amount);
}
}
function updateHTMLField(which, percent)
{
document.rgbForm["fld" + which].value = percent;
}
// -->
</script>

Vamos agora voltar nossa atenção para o documento SVG. O pai do documento é a janela de navegador
na qual ele está inserido. Usamos a palavra reservada "parent" na função INIT para conectar a função
"svgSetShirtColor" do documento SVG à referência "setShirtColor" da página HTML.

function init(evt)
{
parent.setShirtColor = svgSetShirtColor;
svgDocument = evt.getTarget().getOwnerDocument();
transformShirt();
}

Uma vez que existem agora efetivamente duas maneiras de ajustar os valores de cor, vamos tornar as
coisas mais modulares reescrevendo "doColorDrag" para chamar a nova função "svgSetShirtColor":

function doColorDrag(evt, which)


{
/*Se o controle deslizante não estiver ativo, ou o evento é em um controle deslizante que não seja o ativo, não faça
nada */
if (slideChoice < 0 || slideChoice != which)
{
return;
}
/* Obtém a linha indicadora do objeto controle deslizante e a posição do mouse (em relação à parte superior da barra
de cores) */
var obj = evt.getTarget();
var pos = evt.getClientY() - 10;
/* Desde que a pos = 0 está no ponto 100% da escala, tome 100-pos e envie a informação para svgSetShirtColor
juntamente com o número de controles deslizantes.*/
svgSetShirtColor(which, 100 - pos);
}

A função "svgSetShirtColor" vai fazer o que o restante do "doColorDrag" costumava fazer, com duas
grandes diferenças. Ela usa o número deslizante que é dado como o primeiro parâmetro, não a variável
global "sliderChoice". O segundo parâmetro é agora uma percentagem; na versão original era a posição
"y" do mouse. Estes são os tipos de mudanças que você tem que fazer quando você decidir modularizar
um código simples que foi escrito para uma rede "ad-hoc" por exemplo.

function svgSetShirtColor(which, percent)


{
var obj;
var colorStr;
var newText;
/* valores de grampo 0..100 */
if (percent < 0) { percent = 0; }
if (percent > 100) { percent = 100; }
/* Mova a linha de controle deslizante para a nova posição do mouse*/
obj = svgDocument.getElementById("slide" + which);
obj.setAttribute("y1", 100-percent);
obj.setAttribute("y2", 100-percent);
rgb[which] = percent;
/* Coloque junto todos os valores de cor e altere a cor da camisa em conformidade.*/
colorStr = "rgb(" + rgb[0] + "%," + rgb[1] + "%," + rgb[2] + "%)";
obj = svgDocument.getElementById("shirt");
obj.setAttribute("fill", colorStr);
/* Mude o texto para corresponder a posição do cursor */
obj = svgDocument.getElementById("pct" + which);
newText = svgDocument.createTextNode(rgb[which] + "%");
obj.replaceChild(newText, obj.getFirstChild());
}

Este código realiza a comunicação HTML para SVG. Nosso último passo é comunicar a partir do SVG
de volta para o HTML se o usuário decidiu escolher cores com o slider. Ao invés de atualizar
continuamente os campos HTML, nós fizemos o projeto de atualizar o HTML quando tomarmos a
decisão de arrastar e soltar. Nós adicionamos o código em negrito para a função "endColorDrag". O
resultado é mostrado na figura abaixo.

function endColorDrag()
{
/* Se um controle deslizante for movido, envie o número do controle deslizante e seu valor de volta para a função
"updateHTMLField" na janela pai do navegador web. */
if (slideChoice >= 0)
{
parent.updateHTMLField(slideChoice,
rgb[slideChoice]);
}
/ * Em qualquer caso, nada está sendo arrastado agora * /
slideChoice = -1;
}
11.9.6 Scripting e Animação Juntos

Scripting e animação podem trabalhar juntos. Você pode iniciar uma animação em resposta a um
evento, e você pode usar o início, fim, ou repetição de uma animação para invocar uma função. O
exemplo a seguir mostra um trapézio e um botão. Quando você clica no botão, uma mensagem dizendo
"Animação em curso" aparece, e o trapézio gira 360 graus. Quando terminar o giro, a mensagem
desaparece.

Eu achei mais fácil projetar o SVG primeiro e adicionar o script mais tarde. Uma vantagem deste
método é que pode ver se a base do desenho parece ser boa antes de eu começar a fazê-lo reagir a
eventos.

<script type="text/ecmascript">
<![CDATA[
function init(evt)
{
/*Código de inicialização aqui*/
}
function setMessage(visStatus) [1]
{
var message = svgDocument.getElementById("message");
message.setAttribute("visibility", visStatus);
}
// ]]>
</script>
<g id="button"> [2]
<rect x="10" y="10" width="40" height="20" rx="4" ry="4" style="fill: #ddd;"/>
<text x="30" y="25" style="text-anchor: middle;">Start</text>
</g>
<text id="message" x="60" y="25" visibility="hidden"> [3]
Animation in progress.
</text>
<g transform="translate(100, 60)">
<path d="M-25 -15, 0 -15, 25 15, -25 15 Z" style="stroke: gray; fill: #699;">
<animateTransform id="trapezoid" attributeName="transform" type="rotate" from="0" to="360"
begin="button.click" [4] dur="6s" onbegin="setMessage('visible')" [5] onend="setMessage('hidden')"/>
</path>
</g>

[1] Aqui está a função, que tem o status de visibilidade que lhe foi passado, e define a propriedade de
visibilidade da mensagem de acordo com o status.

[2] O botão de início é um retângulo arredondado simples com o texto. Todo o grupo recebe o id.

[3] A mensagem, inicialmente oculta. Novamente, usamos um atributo de apresentação aqui em vez de
um estilo, uma vez que estaremos modificando o atributo.

[4] Em vez de dar a hora de início para a animação em termos de segundos, começamos sempre que um
evento de clique é detectado no objeto botão. Desde que nós estamos esperando um evento, usamos o
clique em vez do atributo manipulador de eventos "onclick".

[5] As próximas duas linhas são para os manipuladores de eventos, para que eles comecem com o
prefixo "on". Quando o animação começa (onbegin), chamamos "setMessage" com o argumento
"visble"; Quando ele termina (onend) chamamos a mesma função com o argumento de "hidden". O
manipulador de eventos "OnRepeat" é chamado cada vez que uma animação é repetida depois da
primeira iteração.

11.9.7 Animação via Scripting

Como a animação SMIL2 é integrada ao SVG, suas animações tornam-se parte da estrutura do
documento. Como é tudo XML, documentos SVG animados permanecem fácil para serem lidos por
seres humanos e serem processados por ferramentas XML. A adição de scripts, como mostramos na
seção anterior, torna possível adicionar um pouco de interação do usuário com a animação.

Enquanto a animação pode lidar com a maioria das coisas que você vai querer mover, há algumas coisas
que não se pode fazer facilmente nos elementos de animação. Por exemplo, é difícil mudar um elemento
<path> dinamicamente. Nós não estamos falando sobre fazer um objeto se mover ao longo de um
<path> (<AnimateMotion>); queremos que o próprio caminho mude ao longo do tempo. O caminho
não é uma transformação, de modo que <animateTransform> não vai funcionar; Além disso, não é um
simples valor numérico, por isso não podemos usar <animate>. Nós vamos ter que usar scripts em seu
lugar.

O exemplo abaixo usa scripting sozinho para alterar repetidamente o atributo "d" do caminho ao longo
do tempo. A chave para fazer a animação através de scripting é a função "setInterval". O "setInterval"
funciona como um "alarme" para que entre em ação várias vezes a intervalos regulares. Quando o
alarme dispara, o mecanismo de script executa as declarações ECMA Script que você deseja. A forma
mais simples é:

timer_variable = setInterval("Função ECMA Script", intervalo de tempo em milissegundos);

Esta função retorna uma referência para o temporizador que foi definido. Você deve salvar essa
referência em uma variável global para que outras funções podssam acessá-lo. Você chama "setInterval"
uma vez, e, a função ECMA Script que você especificou será chamada a cada tantos milissegundos de
intervalo especificado. A repetição continuará até que você chame "clearInterval (timer_variable)".

O exemplo abaixo mostra uma curva de Bézier cúbica. Quando o usuário clica no botão de início,
moveremos os pontos de controle a cada décimo de segundo durante cinco segundos (cinqüenta
movimentos no total). Os pontos de controle irão se mover um em direção ao outro na direção-x a
partir de cinco pixels por intervalo. Eles vão afastar-se um do outro na direção-y em três-quartos de um
pixel por intervalo. Note-se especialmente a linha em negrito e seu comentário.

<svg width="300" height="200" viewBox="0 0 300 200" onload="init(evt)">


<script type="text/ecmascript">
<![CDATA[
/ * Iniciando coordenadas de ambos os pontos de controle * /
var cp1 = new Array(100, 50);
var cp2 = new Array(200, 200);
var moveLimit = 50; // Número total de movimentos a fazer
var currentMove = 0; // Número atual de movimentos
var deltaX; // quantidade de movimento no eixo X
var deltaY; // quantidade de movimento no eixo Y
var delay = 100; // um décimo de segundo
var timer; //armazena o despertador
function init(evt)
{
/ * Fazer qualquer inicialização global aqui * /
}
/* Inicializa o movimento; define pontos de controle de volta às suas posições de partida; define o número atual de
movimentos em zero; e ajusta um temporizador de intervalo para mover os pontos de controle a cada "delay" de
milissegundos.
*/
function setupMove()
{
var i;
currentMove = 0;
deltaX = 5; /* inicializa X com 5 pixels por intervalo */
deltaY = 0.75; /* inicializa Y com 3/4 de pixels por intervalo*/
setGraphicInfo();
timer = setInterval("moveControlPoints()", delay);
}
function setGraphicInfo()
{
var obj;
var pathString;
/ * Construir um caminho descrito por uma curva Bézier cúbico usando as coordenadas atuais para os pontos de controle.* /
pathString = "M 50 120 C " +
(cp1[0] + currentMove * deltaX) + " " + (cp1[1] - currentMove * deltaY) + ", " + (cp2[0] - currentMove * deltaX) + "
" + (cp2[1] + currentMove * deltaY) + ", " + "250, 120";
obj = svgDocument.getElementById("cubic");
obj.setAttribute("d", pathString);
}
function moveControlPoints()
{
currentMove++; // Nós fizemos um movimento
setGraphicInfo(); // Ajustar os pontos de controle e caminho
/* Se tivermos terminado em movimento, limpar o temporizador, que irá parar os serviços de despertador repetidas.*/
if (currentMove >= moveLimit)
{
clearInterval(timer);
}
}
function stopMovement()
{
clearInterval(timer);
}
/ * SetInterval espera seu primeiro argumento a ser encontrado na janela principal. Nós obrigamos através da criação de uma
referência a esta função "moveControlPoints" a ser uma propriedade de janela .* /
window.moveControlPoints = moveControlPoints;
// ]]>
</script>
<g id="button" onclick="setupMove();">
<rect x="10" y="10" width="40" height="20" rx="4" ry="4" style="fill: #ddd;"/>
<text x="30" y="25" style="text-anchor: middle;">Start</text>
</g>
<g id="button" onclick="stopMovement()">
<rect x="70" y="10" width="40" height="20" rx="4" ry="4" style="fill: #ddd;"/>
<text x="90" y="25" style="text-anchor: middle;">Stop</text>
</g>
<path id="cubic" style="stroke: blue; fill: none;" d="M 50 120 C 100 50, 200 200, 250 120" />
</svg>

Neste exemplo, a função "moveControlPoints" não precisa de qualquer parâmetro. Vamos dizer que a
função necessite de dois parâmetros, "pathColor" e "pathStrokeWidth". Para assegurar que
"moveControlPoints" tenha esses parâmetros cada vez que for chamada, gostaríamos de adicioná-los no
fim da nossa chamada para configurar o temporizador de intervalo:

timer = setInterval("moveControlPoints()", delay, pathColor, pathStrokeWidth);

setInterval [5] é a única forma segura de repetir ações por scripts com um intervalo de atraso. Utilizar o
"setInterval" é como deixar uma mensagem com um funcionário da recepção em um hotel para lhe dar
uma chamada a cada hora; entre as chamadas, você está livre para dormir ou fazer outras coisas. Em
termos de script, este tipo de código deixa o computador livre para fazer outras tarefas entre as ações:

[5]Ou a sua variante, "setTimeout", que define o temporizador para sair exatamente uma vez. O
modelo genérico para chamar esta função é:

timer_variable = setTimeout("action_function(parameters)", delay);


Use clearTimeout(timer_variable) para cancelar um evento timer pendente.

function startGoodAction()
{
timer = setInterval("doGoodAction()", delay);
}
function doGoodAction()
{
obj.setAttribute("x", value);
value = value + increment;
repetitions = repetitions + 1;
if (repetitions == limit)
{
clearInterval(timer);
}
}

programadores iniciantes, muitas vezes, fazem algo parecido com isto:

function doBadAction()
{
obj.setAttribute("x", value);
value = value + increment;
if (repetitions != limit)
{
waitCount = 0;
while (waitCount < waitLimit)
waitCount++;
doBadAction();
}
}

Esta técnica é semelhante a olhar constantemente para o relógio e perguntar: "É tempo ainda?" Isto dá-
lhe tempo para dormir ou fazer qualquer outra coisa. Em um script de SVG, dá ao computador pouca
chance para atender a outras tarefas. Além disso, utiliza um estilo recursivo, que, se não for
cuidadosamente controlado, pode consumir os recursos do sistema mais rápido do que você pode
dizer "Erro: estouro de pilha."

Embora o exemplo anterior tenha sido simples, esta técnica tem um grande poder. Se vocês optarem por
usar scripts para fazer animação, então terão disponível toda a interatividade característica de scripting;
você pode fazer animação dependente da posição do mouse ou complexas condições que envolvem
múltiplas variáveis. Se você está fazendo animação simples, recomendamos que use elementos de
animação do SVG.

Você também pode gostar