Fundamentos SVG SVG Essentials J. David Eisenberg Editora: O'Reilly Primeira edição fevereiro 2002 ISBN: 0-596-00223-8, 364 páginas Capítulo 1. Introdução SVG, que significa Scalable Vector Graphics, é uma aplicação XML que torna possível representar informações gráficas de uma forma compacta e portátil. O interesse em SVG está crescendo rapidamente, e ferramentas para criar e visualizar arquivos SVG já estão disponíveis a partir de grandes empresas. Este capítulo começa com uma descrição dos dois principais sistemas de computador gráfico, e descreve onde o SVG se encaixa no mundo dos gráficos. O capítulo termina com um breve exemplo que utiliza muitos dos conceitos que irão ser explorados em detalhes nos capítulos seguintes. 1.1 Sistemas Gráficos Os dois principais sistemas para representar informação gráfica em computadores são gráficos raster e gráficos de vetor. 1.1.1 Gráficos Raster Em gráficos de varredura, uma imagem é representada como uma matriz retangular de elementos de imagem, ou pixels. Cada pixel é representado quer pelos seus valores de cor RGB ou como um índice em uma lista de cores. Esta série de pixels, também chamada de mapa de bits, é muitas vezes armazenada num formato compactado. Como a maioria dos dispositivos de vídeo modernos são dispositivos também raster, exibir uma imagem requer um programa de visualização para fazer pouco mais do que descompactar o bitmap e transferi-lo para a tela.
1.1.2 Gráficos Vetoriais Em um sistema gráfico de vetor, uma imagem é descrita matematicamente como uma série de formas geométricas. Ao invés de receber um conjunto acabado de pixels, um programa de visualização vetorial recebe os comandos para desenhar formas em conjuntos específicos de coordenadas.
Se você pensar em produzir uma imagem em um papel gráfico, os gráficos raster trabalham descrevendo quais quadrados devem ser preenchidos com quais cores. Os gráficos vetoriais trabalham descrevendo quais pontos da grade em que as linhas ou curvas devem ser desenhadas. Algumas pessoas descrevem vetor gráfico como um conjunto de instruções para um desenho, enquanto os gráficos de bitmap são pontos de cor em lugares específicos. Os gráficos vetoriais "entendem" o que são - um quadrado "sabe" que é um quadrado e um texto "sabe" que é um texto porque eles são objetos em vez de uma série de pixels; e objetos de vetor podem mudar sua forma e cor enquanto os gráficos de bitmap não podem. Além disso, todo o texto é pesquisável, porque realmente é texto, não importa como ele se parece ou como ele é rodado ou transformado. Uma outra maneira de pensar nos gráficos raster é como uma pintura sobre uma tela, enquanto gráficos vetoriais poderiam ser linhas e formas, feitas de um material elástico, que pudessem ser movidos em torno de um fundo. 1.1.3 Utilizações de gráficos Raster Gráficos Raster são mais apropriados para uso em fotografias, que raramente são compostas de linhas e curvas distintas. As imagens digitalizadas são muitas vezes armazenadas como bitmaps; embora até o original possa ser "line art", nós queremos armazenar a imagem como um todo, e não nos preocuparmos com seus componentes individuais. Uma máquina de fax, por exemplo, não se importa com o que você tenha desenhado; ela simplesmente transmite pixels de um lugar para outro em forma de raster. Ferramentas para criar imagens em formato raster são largamente utilizados e, geralmente, mais fáceis de usar do que muitas ferramentas baseadas em vetores. Há muitas maneiras diferentes para compactar e armazenar um gráfico raster e a representação interna desses formatos é público. Bibliotecas de programa para ler e escrever imagens em formatos compactados, como JPEG, GIF e PNG são amplamente disponíveis. Estas são algumas das razões que navegadores web têm, até a chegada do SVG, para ar apenas imagens raster. 1.1.4 Utilizações de gráficos vetoriais Os gráficos vetoriais são usados em: • Programas de Desenho/Projeto Assistido por Computador (CAD), onde a medição precisa e a capacidade de zoom de um desenho para ver os detalhes são essenciais; • Programas como o Adobe Illustrator, que são usados para projetar gráficos que serão impressos em impressoras de alta resolução; • O formato de imagem e a linguagem de impressão Adobe PostScript; cada elemento que você imprime é descrito em termos de linhas e curvas; • O sistema Macromedia Flash baseado em vetor para a concepção de animações, apresentações, e web sites. É difícil para um navegador ou outro agente do usuário analisar a saída de texto incorporado, ou para um servidor, criar dinamicamente arquivos gráficos vetoriais a partir de dados externos, porque a maioria destes arquivos são codificados em formato binário ou fluxos de bits hermeticamente fechados. A maior parte das representações internas dos gráficos vetoriais são proprietárias e o código para exibilos ou criá-los não estão disponíveis.
1.2 Escalabilidade Embora eles não sejam tão populares como os gráficos raster, os gráficos vetoriais têm uma característica que os torna valiosos em muitas aplicações - eles podem ser dimensionados, sem perda de qualidade de imagem. Como um exemplo, aqui estão dois desenhos de um gato. O primeiro foi feito com quadrícula, o segundo é uma imagem vetorial. Ambos são mostrados como eles aparecem em uma tela que exibe 72 pixels por polegada.
Quando um programa de visualização amplia o gráfico de varredura, ele deve encontrar alguma maneira de expandir cada pixel. A abordagem mais simples para ampliar por um fator de quatro é fazer com que cada pixel aumente quatro vezes. O resultado, não é particularmente agradável.
Embora seja possível usar técnicas tais como a detecção de borda e anti-aliasing para fazer a imagem ampliada mais agradável, estas técnicas são demoradas. Além disso, uma vez que todos os pixels em um gráfico de varredura são igualmente anônimos, não há nenhuma garantia de que um algoritmo possa detectar corretamente as bordas das formas. Os resultados da aplicação do anti-aliasing é algo como a figura abaixo:
A expansão de uma imagem de vetor por um fator de quatro, por outro lado, requer meramente ao programa de visualização multiplicar todas as coordenadas das formas por quatro e redesenhá-las de acordo com a resolução do dispositivo de exibição. Assim, a imagem vetorial ampliada de 72 pontos por polegada, mostra nítidas as bordas claras sobre as linhas com significativamente menos efeitos de pixelação do que a imagem raster expandida.
1.3 O papel do SVG Em 1998, o World Wide Web Consortium (W3C) formou um grupo de trabalho para desenvolver uma representação de gráficos vetoriais, como aplicação XML. Como SVG é uma aplicação XML, as informações sobre uma imagem são armazenadas como texto simples, e traz as vantagens de transportabilidade e interoperabilidade, além do XML ser um sistema aberto. Programas de CAD e design gráfico, muitas vezes armazenam desenhos em um formato binário proprietário. Ao adicionar a capacidade de importar e exportar desenhos em formato SVG, as aplicações ganham um formato comum, padrão de intercâmbio de informações. Uma vez que é uma aplicação XML, o SVG coopera com outras aplicações XML. Um livro didático de matemática, por exemplo, poderia usar XSL-Formatting Objects para texto explicativo, MathML para descrever equações, e SVG para gerar os gráficos das equações. O SVG é uma especificação oficial do grupo de trabalho W3C (World Wide Web Consortium). Alguns aplicativos, como o Adobe Illustrator e Jasc WebDraw, exportam desenhos em formato SVG. Na Web, os plug-ins SVG Viewers permitem que os usuários vejam apresentações com muitas das capacidades de script e animação que o Flash tem. Uma vez que o SVG é um arquivo XML, o texto no visor SVG está disponível para qualquer agente do usuário que pode analisar XML. 1.4 Criando um gráfico SVG Nesta seção, vamos gravar um arquivo SVG, que produz a imagem do gato que mostramos no início do capítulo. Este exemplo apresenta muitos dos conceitos que vamos explicar em mais detalhes nos capítulos seguintes. Este arquivo será um bom exemplo de como gravar um arquivo que não é necessariamente a maneira que você deve escrever um arquivo SVG que fará parte de um projeto acabado.
1.4.1 Estrutura do Documento Começamos com a instrução de processamento XML padrão e declaração DOCTYPE. A raiz <svg> define a largura e a altura do gráfico em pixels. O conteúdo do elemento
está disponível para um programa de visualização usar em uma barra de título ou como uma ferramenta de dica 2l4b e o elemento <desc> permite fornecer uma descrição completa da imagem. <?xml version="1.0""> <title>Gato <desc>desenho de um gato <polyline points="108 62, 90 10, 70 45, 50 10, 32 62" style="stroke: black; fill: none;" /> <polyline points="35 110, 45 120, 95 120, 105, 110" style="stroke: black; fill: none;" />
1.4.7 Caminhos (Paths) Todas as formas básicas são realmente atalhos para o elemento <path> mais geral, que o exemplo abaixo usa para adicionar o nariz ao gato. Este elemento foi concebido para tornar específico um caminho, ou uma sequência de linhas e curvas, o mais compacto possível. O caminho no exemplo traduz, em palavras, a: "Mover para coordenada (75,90). Desenhar uma linha para coordenada (65,90). Desenhar um arco elíptico com um raio-x de 5 e um raio-y de 10, terminando de volta para coordenada (75,90). " <svg width="140" height="170">
Gato 43646h <desc>desenho de um gato
<use xlink:href="#whiskers" transform="scale(-1 1) translate(-140 0)" /> <polyline points="108 62, 90 10, 70 45, 50, 10, 32, 62" style="stroke: black; fill: none;" /> <polyline points="35 110, 45 120, 95 120, 105, 110" style="stroke: black; fill: none;" /> <path d="M 75 90 L 65 90 A 5 10 0 0 0 75 90" style="stroke: black; fill: #ffcccc" />
1.4.8 Texto Finalmente, uma vez que esta imagem é tão grosseiramente elaborada, há uma boa chance de muitas pessoas não conseguirem perceber que é um gato. Assim, acrescentaremos o texto à imagem como um rótulo. No elemento
, os atributos x e y que especificam a localização do texto são parte da estrutura. A família de fontes e tamanhos de fonte são parte da apresentação e, assim, parte do atributo de estilo. Ao contrário dos outros elementos que temos visto,
é um elemento de contêiner, e seu conteúdo é o texto que se deseja exibir. <svg width="140" height="170">
Gato 43646h <desc>dsenho de um gato
<use xlink:href="#bigodes" transform="scale(-1 1) translate(-140 0)" /> <polyline points="108 62, 90 10, 70 45, 50, 10, 32, 62" style="stroke: black; fill: none;" /> <polyline points="35 110, 45 120, 95 120, 105, 110" style="stroke: black; fill: none;" /> <path d="M 75 90 L 65 90 A 5 10 0 0 0 75 90" style="stroke: black; fill: #ffcccc" />
Cat
Isso conclui nossa breve visão geral de SVG; nos capítulos seguintes vamos examinar estes conceitos em profundidade.
Capítulo 2. Coordenadas O mundo do SVG é uma tela infinita. Neste capítulo, vamos discutir como você diz a um programa de visualização qual parte desta tela você está interessado, o que suas dimensões são, e como você faz para localizar pontos dentro dessa área. 2.1 A Viewport A área da tela que o documento pretende usar é chamada de "viewport" (janela de exibição). Você estabelece o tamanho desta janela com os atributos de largura e altura do elemento <svg>. Os valores desses atributos podem ser simplesmente um número, que se presume ser em pixels; você também pode especificar a largura e altura como um número seguido por um identificador de unidade, o qual pode ser um dos seguintes: UNIDADE em
DESCRIÇÃO O tamanho de fonte da fonte padrão, geralmente equivalente à altura de um caractere
ex
A altura da letra x
px
Pixels pt pc
Pontos (1/72 de polegada) Picas (1/6 de polegada)
cm
Centímetros
m
Milímetros ni
Polegadas
Exemplos: <svg width="200" height="150"> <svg width="200px" height="150px">
Ambos especificam uma área de 200 pixels de largura e 150 pixels de altura. <svg width="2cm" height="3cm">
Especifica uma área de dois centímetros de largura e três centímetros de altura. <svg width="2cm" height="36pt">
É possível, embora não usual, misturar unidades; este elemento especifica uma área de dois centímetros de largura e trinta e seis pontos de altura. Se você tiver um elemento <svg> aninhado em outro elemento <svg>, a tag aninhada pode também especificar a sua largura e altura como uma percentagem, medida em termos do elemento dentro do qual está localizada. Veremos elementos <svg> aninhados na seção 2.5. 2.2 Usando as Coordenadas padrão do Usuário Quando você não usar especificadores de unidade em seu elemento <svg>, o visualizador estabelece um sistema onde a horizontal, ou coordenada-x aumenta à medida que se desloca para a direita, e a vertical,
ou coordenada-y, aumenta à medida que você se move verticalmente para baixo. O canto esquerdo superior da janela está definido para ter uma coordenada (x, y) igual a (0, 0), também chamada de origem. O sistema de coordenadas é um sistema geométrico puro; Os pontos não têm largura nem altura, e as linhas de grade são consideradas infinitamente finas. Voltaremos a este assunto no Capítulo 3. O exemplo a seguir estabelece uma "viewport" de duzentos pixels de largura e duzentos pixels de altura, em seguida, desenha um retângulo cujo canto superior esquerdo está na coordenada (10, 10) com uma largura de 50 pixels e uma altura de 30 pixels. <svg width="200" height="200">
Uso explícito de unidades:
<svg width="200" height="200">
Usando unidades no elemento <svg>
<svg width="70mm" height="70mm">
2.3 Coordenadas especificadas pelo usuário para uma Viewport Nos exemplos até agora, as unidades foram consideradas pixels. Às vezes isso não é o que você quer. Por exemplo, você pode querer criar um sistema onde as coordenadas do usuário representam 1/16 cm (um dezesseis avos) de um centímetro. (Estamos usando este sistema de coordenadas para provar um ponto, não para mostrar um modelo de bom design.) Neste sistema, uma praça que é de 40 unidades por 40 unidades será exibida com 2,5 centímetros de lado. Para conseguir esse efeito, você deve definir o atributo "ViewBox" no elemento <svg>. O valor deste atributo consiste de quatro números que representam a coordenada-x mínima, a coordenada-y mínima, a largura e altura do sistema de coordenadas do usuário que você deseja sobrepor à janela de exibição.
Assim, para configurar o sistema de unidades de coordenadas de dezesseis-por-centímetros (1/16 cm), para um desenho de quatro por cinco centímetros (4 x 5 cm), você pode usar esta tag inicial: <svg width="4cm" height="5cm" viewBox="0 0 64 80">
Desenho de uma casa usando o novo sistema de coordenadas: <svg width="4cm" height="5cm" viewBox="0 0 64 80">
<polyline points="10 35, 30 7.68, 50 35" style="stroke:black; fill: none;" /> <polyline points="30 75, 30 55, 40 55, 40 75" style="stroke:black; fill: none;" />
Os números que você especificar para o valor do atributo "ViewBox" podem ser separados por vírgulas ou espaços em branco. Se a largura ou altura é zero, nada do seu gráfico será mostrado. É um erro especificar um valor negativo para a largura ou altura na "ViewBox". 2.4 Preservar as proporções (Aspect Ratio) No exemplo anterior, a relação de aspecto, ou a relação entre largura e altura, da janela de exibição e o "ViewBox" eram idênticos (4/5 = 64/80). O que acontece, no entanto, se a relação de aspecto da janela de exibição e da ViewBox não forem a mesma? como no presente exemplo, onde tem uma ViewBox com proporção de um para um, mas o visor tem uma relação de 02:59 de aspecto? <svg width="45px" height="135px" viewBox="0 0 90 90">
Há três coisas que SVG pode fazer nesta situação: • Dimensionar o gráfico uniformemente de acordo com a menor dimensão para que o gráfico caiba inteiramente na janela de exibição. No exemplo, a imagem seria metade de sua largura e altura original. Vamos mostrar-lhe exemplos disso na Seção 2.4.2. • Dimensionar o gráfico uniformemente de acordo com a dimensão maior e cortar as peças que se encontram fora do visor. No exemplo, o quadro se tornaria uma vez e meia a sua largura e altura original. Vamos mostrar-lhes exemplos na Seção 2.4.3. • Esticar e esmagar o desenho para que ele se encaixe perfeitamente na nova janela. (Isto é, não preservar a proporção) Nós vamos cobrir isso na Seção 2.4.4. No primeiro caso, uma vez que a imagem vai ser menor do que a janela de visualização em uma dimensão, você deve especificar onde posicioná-la. No exemplo, a imagem será dimensionada de maneira uniforme a uma largura e altura de 45 pixels. A largura do gráfico reduzido se encaixa na largura da "ViewPort" perfeitamente, mas você deve agora decidir se a imagem se reúne (está alinhada com) a parte superior, média ou inferior da janela de exibição com a altura de 135 pixels. No segundo caso, uma vez que a imagem vai ser maior do que a janela de visualização em uma dimensão, você deve especificar qual área deve ser cortada fora. No exemplo, a imagem será dimensionada de modo uniforme para uma largura e altura de 135 pixels. Agora, a altura do gráfico
cabe na "ViewPort" perfeitamente, mas você deve decidir se vai cortar fora do lado direito, do lado esquerdo, ou em ambas as extremidades da imagem para caber na largura da janela de visualização de 45 pixels. 2.4.1 Especificar o alinhamento para preservar o AspectRatio (relação altura x largura) O atributo "preserveAspectRatio" permite que você especifique o alinhamento da imagem dimensionada no que diz respeito à janela de exibição, e se você quer atender às bordas ou cortá-las. O modelo para esse atributo é: preserveAspectRatio="alignment [meet | slice]"
em que o alinhamento do eixo especifica a localização, e é um dos xMinYMin, xMinYMid, xMinYMax, xMidYMin, xMidYMid, xMidYMax, xMaxYMin, xMaxYMid, ou xMaxYMax. Este especificador de alinhamento é formado pela concatenação de um alinhamento-X e um alinhamento-Y, conforme mostrado. O valor padrão para "preserveAspectRatio" é "xMidYMid meet". O alinhamento y começa com uma letra maiúscula, uma vez que os alinhamentos (x,y) estão concatenados em uma única palavra.
Os valores para o alinhamento do atributo "preserveAspectRatio" Alinhamento coord. X Valor
Ação
ni Mx
Alinha a coordenada-x mínima da ViewBox com o canto esquerdo da janela de exibição.
di Mx
Alinha o ponto médio-x da ViewBox com o valor do ponto médio-x da janela de exibição.
axM
Alinha o ponto máximo-x da ViewBox com o canto direito da janela de exibição. Alinhamento coord. Y Valor
Ação
ni M Y
Alinha a coordenada-y mínima da ViewBox com a borda superior da janela de exibição.
di M Y
Alinha o ponto médio-y da ViewBox com o valor do ponto médio-y da janela de exibição.
xaYM
Alinha a coordenada-y máxima da ViewBox com a borda inferior da janela de exibição.
Então, se você quer ter a imagem com uma viewBox = "0 0 90 90" cabendo inteiramente dentro de uma "viewport" que é de 45 pixels de largura e 135 pixels de altura, alinhados na parte superior da janela de exibição, você escreveria:
<svg width="45px" height="135px" viewBox="0 0 90 90" preserveAspectRatio="xMinYMin meet">
Neste caso, uma vez que a largura se adapta precisamente, o alinhamento X é irrelevante; você poderia igualmente bem usar xMidYmin ou xMaxYMin. No entanto, por uma questão de coerência, geralmente o melhor a fazer é especificar ambos, mesmo quando somente um eixo é afetado. Isso tudo é bastante abstrato; aqui estão alguns exemplos concretos que mostram como as combinações de alinhamento e conhecimento das características do "slice" (fatia de imagem) interagem entre si. Uso do especificador "meet" <svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMaxYMax meet" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 90 90" width="135" height="45"> <svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 90 90" width="135" height="45"> <svg preserveAspectRatio="xMaxYMax meet" viewBox="0 0 90 90" width="135" height="45">
Uso do especificador Slice <svg preserveAspectRatio="xMinYMin slice" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMidYMid slice" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMaxYMax slice" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="xMinYMin slice" viewBox="0 0 90 90" width="135" height="45"> <svg preserveAspectRatio="xMidYMid slice" viewBox="0 0 90 90" width="135" height="45"> <svg preserveAspectRatio="xMaxYMax slice" viewBox="0 0 90 90" width="135" height="45">
2.4.4 Não usando um especificador Finalmente, há a terceira opção para escalar um gráfico quando a "viewBox" e a janela de exibição não têm a mesma proporção. Se você especificar preserveAspectRatio = "none", o gráfico será dimensionado de maneira não uniforme de acordo com as coordenadas de seu utilizador, de modo a caber na janela de exibição. <svg preserveAspectRatio="none" viewBox="0 0 90 90" width="45" height="135"> <svg preserveAspectRatio="none" viewBox="0 0 90 90" width="135" height="45">
2.5 Sistemas de Coordenadas aninhadas Você pode estabelecer uma nova janela de exibição e novo sistema de coordenadas a qualquer momento, colocando outro elemento <svg> em seu documento. O efeito é criar uma "mini-tela" sobre a qual você pode desenhar. Nós usamos esta técnica para criar ilustrações.
Em vez de desenhar os retângulos, em seguida, redimensionamos e posicionamos o gato dentro de cada um (a abordagem de força bruta), tomando estes os: • Desenhe os retângulos azuis na tela principal • Para cada retângulo, defina um novo elemento <svg> com o atributo apropriado "preserveAspectRatio" • Desenhe o gato em que a nova tela (com <use>), e deixe SVG fazer o trabalho pesado. Aqui está um exemplo simplificado que mostra um círculo na tela principal, em seguida, dentro de um novo canvas que é delineado por um retângulo azul que é também sobre a tela principal.
Primeiro, gere o SVG para o sistema de coordenadas principal e o círculo. Note que estabelecemos que as coordenadas do usuário coincidirão exatamente com a janela de exibição, neste documento. <svg width="200px" height="200px" viewBox="0 0 200 200">
Agora, desenhe o contorno da caixa mostrando onde queremos que a nova janela de exibição apareça: <svg width="200px" height="200px" viewBox="0 0 200 200">
Agora, adicione outro elemento <svg> para a nova janela. Além de especificar a "viewBox", largura, altura e a especificação "preserveAspectRatio", você também pode especificar os atributos x e y - em termos da inclusão do elemento <svg> - onde a nova janela de exibição deve ser estabelecida. (Se você não der valores para x e y, presume-se que seja zero). <svg width="200px" height="200px" viewBox="0 0 200 200">
<svg x="100px" y="5px" width="30px" height="80px" viewBox="0 0 50 50" preserveAspectRatio="xMaxYMax meet">
Configurar as novas coordenadas com este elemento <svg> aninhado não muda a maneira de visualização, mas ele permite que você adicione o círculo no novo sistema. <svg width="200px" height="200px" viewBox="0 0 200 200">
<svg x="100px" y="5px" width="30px" height="80px" viewBox="0 0 50 50" preserveAspectRatio="xMaxYMax meet">
Capítulo 3. Formas Básicas Uma vez que um sistema de coordenadas é estabelecido na tag <svg>, você está pronto para começar a desenhar. Neste capítulo, vamos mostrar as formas básicas que você pode usar para criar os elementos principais da maioria dos desenhos: linhas, retângulos, polígonos, círculos e elipses. 3.1 Linhas O SVG permite desenhar uma linha reta com o elemento
. Basta especificar as coordenadas (x, y) dos pontos iniciais e finais da linha. Coordenadas podem ser especificadas sem unidades, caso em que elas serão consideradas como coordenadas de usuário, ou com unidades, tal como EM, em, etc. Conforme descrito no Capítulo 2, na Seção 2.1.
<svg width="200px" height="200px" viewBox="0 0 200 200">
3.2 Características do traço As linhas são consideradas como traços de uma caneta desenhando na tela. O tamanho, cor e estilo do traço da caneta são partes da apresentação da linha. Assim, estas características são os atributos de estilo. 3.2.1 Largura do traço Como mencionado no Capítulo 2, as linhas de grade da tela são infinitamente finas. Onde, então, se faz a localização de uma linha ou traço em relação à linha de grade? A resposta é que a linha de grade localiza-se no centro do traço de uma linha. <svg width="200px" height="200px" viewBox="0 0 200 200">
3.2.2 Cor do traço Você pode especificar a cor do traço em uma variedade de formas: • Um dos nomes-chave de cor: aqua, preto, azul, fúcsia, cinzento, verde, cal, marrom, marinho, verdeoliva, roxo, vermelho, prata, cerceta, branco e amarelo. • Um especificador hexadecimal de seis dígitos no formato #RRGGBB, onde rr é o componente vermelho, gg é o componente verde, e bb é o componente azul no intervalo 0-ff. • Um especificador hexadecimal de três dígitos no formato #rgb, onde r é o componente vermelho, g é o componente verde, e b é o componente azul no intervalo de 0-f. Esta é uma forma abreviada do método anterior de cor especifica. Para produzir o equivalente de seis dígitos, cada dígito da forma curta é duplicada; assim # D6E é o mesmo que # dd66ee. • Um especificador rgb no formato rgb (valor de vermelho, valor de verde, valor de azul), onde cada valor é na gama de 0-255 ou uma percentagem na gama de 0% a 100%. <svg width="200px" height="200px" viewBox="0 0 200 200">
Também é possível usar uma das palavras-chave das cores listadas na seção 4.2 da especificação SVG disponível em http://www.w3.org/TR/SVG/types.html#ColorKeywords ou uma das cores do sistema CSS2, com palavras-chave listadas em http://www.w3.org/TR/REC-CSS2/ui.html#system-colors .
3.2.3 Opacidade do traço Até este ponto, todas as linhas dos exemplos foram sólidas, obscurecendo qualquer coisa abaixo delas. Você controla a opacidade (que é o oposto de transparência) de uma linha, dando ao traço um valor de opacidade de 0.0 a 1.0, em que 0.0 é completamente transparente e 1.0 é completamente opaca. Um valor menor que zero irá ser alterado para 0.0; um valor maior que um vai ser alterado para 1.0. <svg width="200px" height="200px" viewBox="0 0 200 200">
/> /> /> /> />
3.2.4 Atributo de linhas pontilhadas do traço (dasharray) Se você precisar de linhas pontilhadas ou tracejadas, use o atributo "stroke-dasharray", cujo valor consiste de uma lista de números, separados por vírgulas ou espaço em branco, especificando traço comprimento e lacunas. A lista deve ter um número par de entradas, mas se você der um número de entradas estranho, o SVG vai repetir a lista de modo que o número total de entradas seja o mesmo. <svg width="200px" height="200px" viewBox="0 0 200 200">
3.3 Retângulos O retângulo é a mais simples das formas básicas. Você especifica as coordenadas x e y do canto esquerdo superior do retângulo, a sua largura, e sua altura. O interior do retângulo é preenchido com a cor de preenchimento que você especificar. Se você não especificar uma cor de preenchimento, o interior da
forma é preenchido, por padrão, com preto. A cor de preenchimento pode ser especificada de qualquer uma das maneiras descritas, ou pode levar o valor "none" para deixar o interior sem preenchimento e, portanto, transparente. Você também pode especificar "fill-opacity" no mesmo formato. Ambos, "fill" e "fill-opacity" são propriedades de apresentação, e pertencem ao atributo "style". Depois que o interior é preenchido (se necessário), o contorno do retângulo é desenhado com traços, cujas características você pode especificar como com as linhas (dasharray). Se você não especificar um traço, o valor "none" se presume, e o retângulo é desenhado sem contorno. <svg width="200px" height="200px" viewBox="0 0 200 200">
Uma vez que os traços formam o contorno da grade de linhas abstratas "straddle", os traçados serão a metade dentro da forma e a metade do lado de fora da forma. A figura abaixo mostra um "close" do contorno vermelho semi-transparente que demonstra isso claramente.
Se você não especificar um valor inicial para x ou y, presume-se que seja zero. Se você especificar uma largura ou altura de zero, em seguida, o retângulo não será exibido. É um erro fornecer valores negativos
para largura ou altura. 3.3.1 retângulos arredondados Se você deseja ter retângulos com cantos arredondados, especifique o "rx" e "ry" - raio da curvatura do canto. O número máximo que você pode especificar para rx (o x-raio) é metade da largura do retângulo; o valor máximo de ry (a y-raio) é a metade da altura do retângulo. Se você especificar apenas um dos rx ou ry, presume-se que sejam iguais. <svg width="200px" height="200px" viewBox="0 0 200 200">
3.4 círculos e elipses Para desenhar um círculo, use o elemento
e especifique as coordenadas (x,y) do centro e o raio do círculo com os atributos "cx", "cy", e "r" respectivamente. Tal como acontece com um retângulo, o padrão é para preencher o círculo com a cor preta e desenhar sem contorno, a menos que você especifique alguma outra combinação de preenchimento e traçado. Uma elipse também precisa de um raio-X e um raio-Y para além das coordenadas (x, y) do centro. Os atributos para esses raios são nomeados "rx" e "ry". Em ambos, círculos e elipses, se o "cx" ou "cy" for omitido, presume-se que seja zero. Se o raio é igual a zero, a forma não será exibida; é um erro fornecer um raio negativo. <svg width="200px" height="200px" viewBox="0 0 200 200">
<ellipse cx="30" cy="80" rx="10" ry="20" style="stroke: black; fill: none;" /> <ellipse cx="80" cy="80" rx="20" ry="10" style="stroke: black; fill: none;" />
3.5 O elemento polígono Além de retângulos, círculos e elipses, você pode querer desenhar hexágonos, octógonos, estrelas, ou formas fechadas arbitrárias. O elemento <polygon> permite que você especifique uma série de de pontos que descrevem uma área geométrica para ser preenchida e fechada como descrito anteriormente. O atributo "points" consiste em uma série de pares de coordenadas X e Y separados por vírgulas ou espaços em branco. Você deve dar um número par de entradas na série de números. Você não precisa voltar ao ponto de partida; a forma será automaticamente fechada. <svg width="200px" height="200px" viewBox="0 0 200 200"> <polygon points="15,10 55, 10 45, 20 5, 20" style="fill: red; stroke: black;" /> <polygon points="35,37.5 37.9,46.1 46.9,46.1 39.7,51.5 42.3,60.1 35,55 27.7,60.1 30.3,51.5 23.1,46.1 32.1,46.1" style="fill: #ccffcc; stroke: green;" /> <polygon points="60 60, 65 72, 80 60, 90 90, 72 80, 72 85, 50 95" style="fill: yellow; fill-opacity: 0.5; stroke: black; stroke-width: 2;" />
3.5.1 Polígonos preenchidos que têm linhas cruzadas Para os polígonos mostrados até agora, tem sido fácil preencher o interior da forma. Uma vez que nenhuma das linhas do polígono se cruzam umas sobre as outras, o interior é facilmente distinto do exterior da forma. No entanto, quando as linhas se cruzam umas sobre as outras, a determinação do que está dentro do polígono não é tão fácil. <svg width="200px" height="200px" viewBox="0 0 200 200"> <polygon points="48,16 16,96 96,48 0,48 80,96" style="stroke: black; fill: none;" />
O SVG tem duas regras diferentes para determinar se um ponto está dentro ou fora de um polígono. A regra de preenchimento (que faz parte da apresentação) tem um valor de "nonzero" ou "evenodd". Dependendo da regra que você escolher, você tem um efeito diferente. <svg width="200px" height="200px" viewBox="0 0 200 200"> <polygon style="fill-rule: nonzero; fill: yellow; stroke: black;" points="48,16 16,96 96,48 0,48 80,96" /> <polygon style="fill-rule: evenodd; fill: #00ff00; stroke: black;" points="148,16 116,96 196,48 100,48 180,96" />
Explicação das regras de preenchimento Por uma questão de exaustividade, estamos descrevendo como essas regras de preenchimento funcionam, mas você não precisa saber os detalhes. A regra "nonzero" determina se um ponto está dentro ou fora de um polígono desenhando uma linha do ponto em questão para o infinito. Ele conta quantas vezes que a linha cruza as linhas do polígono, adicionando um, se a linha do polígono está indo da direita para a esquerda, e subtraindo um, se a linha do polígono está indo da esquerda para a direita. Se o total for zero, o ponto está fora do polígono. Se a soma for "diferente de zero" (daí o nome "nonzero") o ponto é dentro do polígono. A regra "eevenodd" também desenha uma linha a partir do ponto em questão para o infinito, mas simplesmente conta quantas vezes que a linha cruza as linhas do seu polígono. Se o número de agens total for ímpar, então o ponto está dentro; Se for par, então o ponto é do lado de fora. 3.6 O elemento polilinha Finalmente, para completar a nossa discussão sobre formas básicas, vamos voltar para as linhas retas. Às vezes você quer uma série de linhas que não fazem uma forma fechada. Você pode usar vários elementos
, mas se houver muitas linhas pode ser mais fácil usar o elemento
. Ele tem os mesmos atributos que o elemento
, exceto que as formas não são fechadas. <svg width="200px" height="200px" viewBox="0 0 200 200"> <polyline points="5 20, 20 20, 25 10, 35 30, 45 10, 55 30, 65 10, 75 30, 80 20, 95 20" style="stroke: black; strokewidth: 3; fill: none;" />
É melhor definir a propriedade de preenchimento para "none" quando se utiliza <polyline>; Caso contrário, o vizualizador SVG pode tentar preencher a forma, às vezes com resultados surpreendentes, como este.
3.7 Line Caps e s Quando desenhar uma
ou <polyline>, você pode especificar a forma dos pontos finais das linhas, definindo a propriedade estilo de traço "stroke-linecap" e um dos valores "butt", "round" ou "square".
style="stroke-linecap: butt; stroke-width: 15;"/> style="stroke-linecap: round; stroke-width: 15;"/> style="stroke-linecap: square; stroke-width: 15;"/> style="stroke: #999;" /> style="stroke: #999;" />
Você pode especificar como as linhas se ligam aos cantos da forma com a propriedade de estilo "strokeline", que pode ter os valores "miter" (pontas), "round" (arredondado), ou "bevel" (achatado). <polyline style="stroke-line: miter; stroke: black; stroke-width: 12; fill: none;" points="30 30, 45 15, 60 30"/> <polyline style="stroke-line: round; stroke: black; stroke-width: 12; fill: none;" points="90 30, 105 15, 120 30"/> <polyline style="stroke-line: bevel; stroke-width: 12; stroke: black; fill: none;" points="150 30, 165 15, 180 30"/>
Se as linhas se encontram em um ângulo agudo e tem a propriedade "stroke-line = miter", é possível para a parte pontiaguda se estender para além da espessura das linhas. É possível definir a proporção da "miter" para a espessura das linhas, com a propriedade "stroke-miterlimit"; seu valor padrão é 4. 3.8.2 Especificação de cores Você pode especificar a cor para preencher (fill) ou delinear (stroke) uma forma de uma das seguintes maneiras: • "none", indica que nenhum esboço deverá ser desenhado ou que a forma não é para ser preenchida. • Um nome de cor, que é um dos aqua, black, blue, fucsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, ou yellow. • Seis dígitos hexadecimais #RRGGBB, cada par descreve valores de vermelho, verde e azul. • Três dígitos hexadecimais #rgb, descrevendo os valores de vermelho, verde e azul. Isto é um atalho para o método anterior; dígitos são replicados de modo a que é #rgb equivalente a #RRGGBB. • RGB (r, g, b), cada valor que varia de 0-255 ou a partir de 0% a 100%. 3.8.3 Características de Traço (stroke) e Preenchimento (fill) A fim de ver uma linha ou o contorno de uma forma, você deve especificar as características do traçado,
utilizando os seguintes atributos. Um esboço de forma é desenhado e depois seu interior é preenchido. Todas estas características, resumidas no quadro, são propriedades de apresentação, e são definidas em um atributo de estilo. Características de traçado (stroke) Atributo
Valor
eokrts
A cor do traçado
htde-iwokrs
Largura do traçado; pode ser dada como coordenadas do utilizador ou com a especificação de comprimento. A largura do traçado é centrada ao longo das linhas de grade abstratas.
ytcipae-okrs
Um número variando de 0,0 a 1,0; 0,0 é completamente transparente, 1.0 é inteiramente opaco.
yarhes-dokt
Uma série de números que indicam o comprimento dos traços e as lacunas com a qual uma linha é desenhada. Estes números estão em coordenadas do usuário somente.
epca-nliokrts
Forma das extremidades de uma linha; valores "butt" (o padrão), "round", ou "square".
noiej-lkrts
A forma dos cantos de um polígono ou uma série de linhas; tem um dos valores "miter" (apontado; o padrão), "round" ou "bevel" (chanfrado).
tilmer-oks
Relação máxima de comprimento do "niter" em relação a largura da linha a ser desenhada; o valor padrão é 4.
É possível controlar a maneira na qual o interior de uma forma deve ser preenchida usando um dos atributos de preenchimento mostrados. Uma forma é preenchida antes de seu contorno ser desenhado. Características de preenchimento Atributo
Valor
l if
A cor de preenchimento.
ytcipal-of
Um número variando de 0,0 a 1,0; 0,0 é completamente transparente, 1.0 é inteiramente opaco.
le-urif
Este atributo pode ter os valores "nonzero" ou "evenodd", aos quais se aplicam regras diferentes para determinar se um ponto está dentro ou fora de uma forma. Estas regras geram efeitos diferentes apenas quando tem uma forma de intersecção de linhas ou "furos" na mesma.
Capítulo 4. Estrutura de Documento Nós casualmente mencionamos que o SVG permite separar a estrutura de um documento a partir da sua apresentação. Neste capítulo, vamos comparar e contrastar os dois, discutir os aspectos de apresentação de um documento em mais pormenores, e em seguida mostrar alguns dos elementos SVG que você pode usar para tornar a estrutura do seu documento mais clara, mais legível, e mais fácil de manter. 4.1 Estrutura e Apresentação Como mencionamos no Capítulo 1, na Seção 1.4.2, um dos objetivos da XML é fornecer uma maneira de estrutura de dados e separar esta estrutura de sua apresentação visual. Considere o desenho do gato desse capítulo; você reconhece-o como um gato devido à sua estrutura - a posição e o tamanho das formas geométricas que compõem o desenho. Se fôssemos fazer mudanças estruturais, tais como encurtar os bigodes, arredondar o nariz, e fazer as orelhas maiores e arredondadas, o desenho se tornaria o de um coelho, não importa o que a apresentação da superfície sugerisse. A estrutura, portanto, diz o que um gráfico é. Isso não quer dizer que a informação sobre o estilo visual não é importante; se tivéssemos desenhado o gato com linhas grossas roxas e um interior cinzento, ainda teria sido reconhecido como um gato, mas sua aparência teria sido muito menos agradável. XML encoraja a estrutura separada da apresentação; Infelizmente, muitas discussões de XML enfatizam estrutura a custo da apresentação. Vamos corrigir este erro entrando em detalhes sobre como você especifica apresentação em SVG.
4.2 Usando estilos com SVG O SVG permite especificar aspectos de apresentação de um gráfico de quatro maneiras; com estilos inline, folhas de estilo internas, folhas de estilo externas, e atributos de apresentação. Vamos examinar cada um deles. 4.2.1 estilos inline Esta é exatamente a forma como temos utilizados as informações de apresentação até agora; vamos definir o valor do atributo de estilo a uma série de propriedades visuais e os seus valores.
4.2.2 Folhas de Estilo Interna Você não precisa colocar seus estilos dentro de cada elemento SVG; você pode criar uma folha de estilo interna para coletar estilos comumente usados que podem ser aplicados a todas as ocorrências de um determinado elemento, ou a utilização como classes nomeadas para aplicar a elementos individuais. O exemplo abaixo configura uma folha de estilo interna que vai desenhar todos os círculos com um traçado de linha pontilhada, de espessura dupla, na cor azul e preenchido internamente com amarelo claro. Nós colocamos a folha de estilo dentro de um elemento <defs>, que discutiremos mais adiante neste capítulo. O exemplo, em seguida, desenha vários círculos. Os círculos na segunda fila da figura a seguir tem estilos embutidos que substituem a especificação na folha de estilo interna. <svg width="200px" height="200px" viewBox="0 0 200 200"> <defs> <style type="text/css"><![CDATA[ circle { fill: #ffc; stroke: blue; stroke-width: 2; stroke-dasharray: 5 3 } ]]>
4.2.3 Folhas de Estilo Externas Se você deseja aplicar um conjunto de estilos para vários documentos SVG, você pode copiar e colar a folha de estilo interna em cada um deles. Isto, é claro, é impraticável para um volume grande de documentos, se você precisar fazer uma mudança global para todos os documentos. Em vez disso, você deve tomar todas as informações entre o início e o fim <style> (Excluindo o ) e salvá-lo em um arquivo externo, que se torna uma folha de estilo externa. O exemplo abaixo mostra uma folha de estilo externa que foi salvo em um arquivo chamado ext_style.css. Este estilo usa uma variedade de seletores, incluindo *, que define um padrão para todos os elementos que não têm qualquer outro estilo.
* { fill:none; stroke: black; } /* padrão para todos os elementos */ rect { stroke-dasharray: 7 3; } circle.yellow { fill: yellow; } .thick { stroke-width: 5; } .semiblue { fill:blue; fill-opacity: 0.5; }
<svg width="200px" height="200px" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet">
<polygon class="thick" points="60 50, 60 80, 90 80"/> <polygon class="thick semiblue" points="100 30, 150 30, 150 50, 130 50"/>
Folhas de Estilos Inline quase sempre são executadas mais rapidamente do que os estilos em uma folha de estilo interna ou externa; folhas de estilo e classes adicionam tempo de renderização devido a análise e antecipação do evento. 4.2.4 Atributos de apresentação Embora a esmagadora maioria dos seus documentos SVG utilize estilos para informações de apresentação, o SVG permite que você especifique essa informação na forma de atributos de apresentação. Ao invés de escrever:
Você pode escrever cada propriedade como um atributo:
Se você está pensando que esta é uma mistura de estrutura e apresentação, você está certo. Atributos de apresentação vêm a calhar, no entanto, quando você está criando documentos SVG através da conversão de uma fonte de dados XML para SVG, como você verá no Capítulo 12. Nestes casos, pode ser mais fácil para criar atributos individuais para cada propriedade de apresentação do que criar o conteúdo de um único atributo de estilo. Você também pode precisar usar atributos de apresentação se o ambiente em que você estará colocando o seu SVG não ar folhas de estilo. Atributos de apresentação estão na parte inferior da lista de prioridades. Qualquer especificação de estilo que vem das folhas de estilo inline, interna ou externa vai substituir um atributo de apresentação. No documento SVG seguinte, o círculo será preenchido em vermelho, não em verde.
<svg width="200" height="200"> <defs> <style type="text/css"><![CDATA[ circle { fill: red; } ]]>
Novamente, enfatizamos que o uso de atributos de estilo ou folhas de estilo deve ser sempre a sua primeira escolha. Folhas de estilo permitem que você aplique uma série complexa de preenchimentos e traçados características de todas as ocorrências de certos elementos dentro de um documento sem ter que duplicar a informação em cada elemento, como os atributos de apresentação exigiriam. O poder e a flexibilidade das folhas de estilo permitem que você faça alterações significativas na aparência de vários documentos com um mínimo de esforço. 4.3 Estrutura do Documento - Agrupamento referência a objetos Embora seja certamente possível definir qualquer desenho como uma lista não diferenciada de formas e linhas, a maioria da arte não-abstrata consiste em grupos de formas e linhas que formam objetos com forma e nome reconhecíveis. O SVG tem elementos que permitem fazer este tipo de agrupamento para fazer seus documentos mais estruturados e compreensíveis. 4.3.1 O Elemento
O elemento
reúne todos os seus elementos filho como um grupo, e muitas vezes tem um atributo "id" para dar a esse grupo um nome único. Além disso, cada grupo pode ter sua própria
e <desc 121m2c para identificá-lo para aplicações XML baseado em texto ou para ajudar na ibilidade para usuários com deficiência visual. Além da clareza conceitual que vem da capacidade para agrupar documento e objetos, o elemento <g> também fornece conveniência de notação. Todos os estilos especificados na tag inicial <g> serão aplicados a todos os elementos filhos no grupo. No Exemplo a seguir, isto nos poupa de ter que duplicar o style = "fill:none; stroke:black;" em cada elemento mostrado. É também possível aninhar grupos um dentro do outro, embora não vamos mostrar alguns exemplos deste até o Capítulo 5. Você pode pensar do elemento <g> como análogo à função "Agrupar Objetos" em programas como o Adobe Illustrator. Serve também como uma função semelhante ao conceito de camadas; uma camada também é um agrupamento de objetos relacionados. <svg width="240px" height="240px" viewBox="0 0 240 240"> <title>Grouped Drawing <desc>Stick-figure drawings of a house and people
<desc>House with door
<polyline points="6 50, 36 9, 66 50"/> <polyline points="36 110, 36 80, 50 80, 50 110"/>
<desc>Male human
<polyline points="76 104, 85 80, 94 104" /> <polyline points="76 70, 85 76, 94 70" />
<desc>Female human
<polyline points="110 66, 110 80, 100 90, 120 90, 110 80"/>
<polyline points="101 70, 110 76, 119 70" />
4.3.2 O elemento <use> Gráficos complexos, muitas vezes têm elementos repetidos. Por exemplo, um folheto do produto pode ter o logotipo da empresa na parte superior direita e inferior esquerda de cada página. Se você fosse desenhar brochuras com um programa de design gráfico, você desenharia o logotipo uma vez, agruparia todo seus elementos juntos, em seguida, copiaria e colaria para outro local. O elemento SVG <use> dá uma capacidade análoga de copiar-e-colar com um grupo que você definiu com o elemento
. Depois de ter definido um grupo de objetos gráficos, você pode exibi-los novamente com a tag <use>. Para especificar o grupo que deseja reutilizar, dê o seu URI em um atributo "xlink:href", e especifique o local x e y, para onde o ponto (0,0) do grupo deve ser movido. (Veremos outra maneira de conseguir este efeito no Capítulo 5, no ponto 5.1.) Assim, para criar outra casa e conjunto de pessoas, conforme mostrado na Figura acima, você iria apenas colocar essas linhas antes da tag de fechamento : <use xlink:href="#house" x="70" y="100"/> <use xlink:href="#woman" x="-80" y="100"/> <use xlink:href="#man" x="-30" y="100"/>
4.3.3 O Elemento <defs> Você deve ter notado alguns inconvenientes com o exemplo anterior: • A matemática para decidir onde colocar o homem e a mulher, reutilizados, exige que você conheça as posições dos originais e use isso como sua base, em vez de usar um número simples como zero. • A cor de preenchimento e traçado para a casa foram estabelecidos pelo original, e não podem ser substituídos pelo elemento <use>. Isto significa que você não pode fazer uma linha de casas multicoloridas. • O documento chama a todos os três grupos: a mulher, o homem, e a casa. Vocês não podem "armazená-los em separado" e desenhar apenas um conjunto de casas ou apenas um conjunto de pessoas. O elemento <defs> resolve estes problemas. Ao colocar os objetos agrupados entre as marcas <defs>, você instrui o SVG para defini-los sem exibi-los. A especificação SVG, de fato, recomenda que você coloque todos os objetos que você deseja para re-uso dentro de um elemento <defs> para que os visualizadores SVG trabalhando em um ambiente de fluxo contínuo, possam processar os dados de forma mais eficiente. No Exemplo abaixo, a casa, o homem e a mulher são definidos de modo que o seu canto superior esquerdo está em (0, 0), e à casa não é dada qualquer cor de preenchimento. Uma vez que os grupos serão dentro de elementos <defs>, eles não serão atraídos na tela imediatamente, e servirão como um "modelo" para uso futuro. Nós também construímos um outro grupo chamado "couple", que, por sua vez, faz o grupo do homem e da mulher. (Note-se que na metade inferior da figura não é possível utilizar pares, uma vez que a mulher é a do lado esquerdo do homem.) <svg width="240px" height="240px" viewBox="0 0 240 240">
Desenhos agrupados 1x2u5d <desc> desenho de uma casa e pessoas <defs>
<desc>Casa com porta
<polyline points="0 41, 30 0, 60 41" /> <polyline points="30 101, 30 71, 44 71, 44 101" />
<desc>Homem
<polyline points="1 58, 10 44, 19 58" /> <polyline points="1 24, 10 30, 19 24" />
<desc>Mulher
<polyline points="10 20, 10 34, 0 44, 20 44, 10 34" />
<polyline points="1 24, 10 30, 19 24" />
<desc>Homem e mulher <use xlink:href="#man" x="0" y="0" /> <use xlink:href="#woman" x="25" y="0" />
<use xlink:href="#house" x="0" y="0" style="fill: #cfc;" /> <use xlink:href="#couple" x="70" y="40" /> <use xlink:href="#house" x="120" y="0" style="fill: #99f;" /> <use xlink:href="#couple" x="190" y="40" /> <use xlink:href="#woman" x="0" y="145" /> <use xlink:href="#man" x="25" y="145" /> <use xlink:href="#house" x="65" y="105" style="fill: #c00;" />
O elemento <use> não está ao uso de objetos do mesmo arquivo em que ocorre; o atributo "xlink:href" pode especificar qualquer arquivo válido ou URI. Isto faz com que seja possível recolher um conjunto de elementos comuns em um arquivo SVG e usá-los seletivamente de outros arquivos. Por exemplo, você pode criar um arquivo chamado "identity.svg" que contém toda a identidade gráfica que sua organização usa:
<polygon points="0 20, 20 0, 40 20, 20 40" style="fill: #696;" />
e então se referir a ele com: <use xlink:href="identity.svg#company_logo" x="200" y="200" />
4.3.4 O símbolo do elemento O elemento <symbol> fornece uma outra maneira de agrupar elementos. Ao contrário do elemento
, um <symbol> nunca é exibido, por isso você não precisa colocá-lo em uma especificação <defs>. No entanto, é habitual fazê-lo, desde que um símbolo é realmente algo que você está definindo para uso posterior. Além disso, os símbolos podem especificar "viewbox" e atributos "preserveAspectRatio", de modo que um símbolo pode caber na janela de exibição estabelecida pelo elemento de utilização. O exemplo abaixo mostra que a largura e altura são ignorados por um simples grupo (os dois primeiros octógonos), mas são usados ao exibir um símbolo. As bordas do octógono inferior direita na figura são cortadas porque o "preserveAspectRatio" foi definido para cortar. <svg width="200px" height="200px" viewBox="0 0 200 200">
Símbolos versus Grupos 611f31 <desc>Use <defs>
<desc>Octagon como grupo <polygon points="36 25, 25 36, 11 36, 0 25, 0 11, 11 0, 25 0, 36 11"/>
<symbol id="sym-octagon" style="stroke: black;" preserveAspectRatio="xMidYMid slice" viewBox="0 0 40 40"> <desc>Octagon como symbol <polygon points="36 25, 25 36, 11 36, 0 25, 0 11, 11 0, 25 0, 36 11"/> <use xlink:href="#octagon" x="40" y="40" width="30" height="30" style="fill: #c00;"/> <use xlink:href="#octagon" x="80" y="40" width="40" height="60" style="fill: #cc0;"/> <use xlink:href="#sym-octagon" x="40" y="80" width="30" height="30" style="fill: #cfc;"/> <use xlink:href="#sym-octagon" x="80" y="80" width="40" height="60" style="fill: #699;"/>
4.3.5 O Elemento
Enquanto <use> permite reutilizar uma parte de um arquivo SVG, o elemento
inclui um arquivo SVG ou raster inteiro. Se você estiver incluindo um arquivo SVG, os atributos x, y, largura e altura estabelecerão a janela de exibição em que o arquivo referenciado será desenhado; se você está incluindo um arquivo de imagem, ela será redimensionada para caber no retângulo que os atributos especificarem. Você atualmente pode incluir tanto os arquivos raster JPEG ou PNG. O exemplo abaixo mostra como incluir uma imagem JPEG com SVG: <svg width="310px" height="310px" viewBox="0 0 310 310"> <ellipse cx="154" cy="154" rx="150" ry="120" style="fill: #999999;"/> [1] <ellipse cx="152" cy="152" rx="150" ry="120" style="fill: #cceeff;"/> [2]
[5]
Capítulo 5. Transformção do Sistema de Coordenadas Até este ponto, todos os gráficos foram exibidos "tal como estão". Haverá momentos em que você terá um gráfico que você gostaria de mudar para um novo local, girar ou escalar. Para realizar essas tarefas, você deve adicionar o atributo de transformação para os elementos SVG apropriados. Este capítulo examina os detalhes dessas transformações. 5.1 A transformação "Translation" No Capítulo 4, você viu que você pode usar os atributos x e y com o elemento <uso> para colocar um grupo de objetos gráficos em um lugar específico. Olhe para o SVG no Exemplo abaixo, o que define um quadrado é desenhá-lo no canto superior esquerdo da grelha, em seguida, re-extrai-la com o canto superior esquerdo nas coordenadas (50, 50). As linhas a tracejado na figura não são parte do SVG, mas servem para mostrar a parte da tela que os objetos ocupam. <svg width="200px" height="200px" viewBox="0 0 200 200">
<use xlink:href="#square" x="50" y="50"/>
Como se constata, os valores X e Y são realmente um atalho para uma forma do mais geral e mais poderoso atributo "transform". Especificamente, os valores de x e y são convertidos em um atributo como "transform = translate (x-value, y-value)", em que "translate" é um termo técnico para "mover". O valor de x e y de valor são medidos no atual sistema de coordenadas do usuário. Vamos usar "transform" para obter o mesmo efeito de fazer um segundo quadrado com seu canto superior esquerdo em (50, 50). <svg width="200px" height="200px" viewBox="0 0 200 200">
<use xlink:href="#square" transform="translate(50,50)"/>
A exibição resultante será exatamente como a da figura abaixo. Você pode pensar que isso seria realizado movendo o quadrado para um lugar diferente na grade, como mostrado conceitualmente na figura abaixo, mas você teria errado.
O que realmente está acontecendo nos bastidores é uma história completamente diferente. Ao invés de mover o quadrado, a especificação "translate" pega toda a grade e move-a para um novo local na tela. Quanto ao quadrado, ainda está sendo desenhado com o seu canto superior esquerdo nas coordenadas (0, 0), conforme representado na Figura.
A transformação "translate" nunca muda as coordenadas na grade de um objeto gráfico; em vez disso, ela muda a posição da grade na tela. À primeira vista, usar o "translate" parece tão ridículo e ineficiente como mover o sofá para mais longe a partir da parede externa da casa movendo toda a sala de estar, e todas as paredes, para uma nova posição. Com efeito, se "translate" fosse a única transformação disponível, mover todo o sistema de coordenadas seria um desperdício. No entanto, vamos ver em breve outras transformações, e combinações de uma sequência de transformações, que são mais matematica e conceitualmente convenientes que se aplicam a todo o sistema de coordenadas. 5.2 A transformação "scale" É possível fazer um objeto parecer maior ou menor do que o tamanho em que foi definido pelo dimensionamento do sistema de coordenadas. Essa transformação é especificada como: transform="scale( value)" - Multiplica todas as coordenadas x e y pelo valor dado. transform="scale( x-value, y-value)" - Multiplica todas as coordenadas x por um valor x dado e todas as coordenadas y pelo valor y dado. <svg width="200px" height="200px" viewBox="0 0 200 200">
<use xlink:href="#square" transform="scale(2)"/>
Você pode estar pensando: "Espere um minuto - Eu posso entender porque o quadrado ficou maior. Mas eu não pedi uma "translate", então por que é o quadrado está em um lugar diferente? "Tudo se torna claro quando você olhar para a Figura abaixo para ver o que realmente ocorreu. A grade não se moveu; o ponto do sistema de coordenadas (0, 0) ainda está no mesmo lugar, mas cada coordenada de usuário é agora duas vezes maior do que costumava ser. Você pode ver a partir das linhas de grade que o canto superior esquerdo do retângulo ainda está em (10, 10) sob a nova grade, maior, uma vez que o objeto não se moveu. Isso também explica por que o contorno do quadrado maior é mais espesso. A largura do traçado (stroke) ainda é uma unidade do usuário, mas agora se tornou duas vezes maior, por isso o traçado engrossou.
A transformação de escala nunca muda as coordenadas da grade de um objeto gráfico ou a sua largura do traçado; Pelo contrário, ela altera o tamanho do sistema (grade) de coordenadas em relação à tela. É possível especificar um fator de escala diferente para o eixo y e o eixo x do sistema de coordenadas utilizando uma segunda forma da transformação "scale". O exemplo a seguir chama o quadrado com o eixo x escalonado por um fator de 3 e o eixo y escalonado por um fator de 1/2. Como você pode ver na figura, a largura do traçado de uma unidade é também dimensionada de maneira não uniforme.
Até este ponto, nós só aplicamos o atributo de transformação para o elemento <use>. Você pode aplicar uma transformação para uma série de elementos, agrupando-os, e transformar todo o grupo:
Você também pode aplicar uma transformação para um único objeto ou forma básica. Por exemplo, aqui é um retângulo cujo sistema de coordenadas é escalonado por um fator de 3:
É bastante claro que a largura e altura do retângulo escalonado deve ser três vezes maior que o retângulo não escalonado. No entanto, você pode se perguntar se as coordenadas x e y são avaliadas antes ou depois do retângulo ser dimensionado. A resposta é que SVG aplica transformações para o sistema de coordenadas antes de avaliar qualquer uma das formas de coordenadas. O exemplo a seguir é o SVG para o retângulo em escala, mostrado na figura, com linhas de grade que são desenhadas no sistema de coordenadas fora de escala.
O efeito da aplicação de uma transformação para uma forma é o mesmo que se a forma fosse colocada entre um grupo e transformada. No exemplo anterior, o retângulo em escala é equivalente a este SVG:
5.3 As sequências de transformações É possível fazer mais do que uma transformação em um objeto gráfico. É só colocar as transformações separadas por espaços em branco, no valor do atributo
. Aqui está um retângulo que a por duas transformações, uma "translate" seguida de uma "scale". (Os eixos são desenhados para mostrar que o retângulo de fato, mudou.)
Isto é o equivalente da seguinte sequência de grupos aninhados, e ambas produzirão o que se vê na figura abaixo.
O que acontece em cada estágio da transformação:
A ordem em que você fizer uma seqüência de transformações afetará o resultado. Em geral, a transformação A seguido pela transformação B não dará o mesmo resultado que a transformação B seguido pela transformação A. O exemplo abaixo produz o mesmo retângulo do exemplo anterior, apenas em uma cor cinzento claro. Em seguida, ele desenha o retângulo de novo, mas faz a "scale" antes da "translate". Como você pode ver o resultado na figura abaixo, os retângulos acabam em lugares muito diferentes na tela.
A razão porque o retângulo preto acaba mais longe da origem é que a transformação "scale" é aplicada em primeiro lugar, de modo que a transformação "translate" de 20 unidades na direção x e 10 unidades na direcção y é feita com unidades que são agora duas vezes maior.
5.4 Técnica: Conversão de coordenadas cartesianas Se você estiver transferindo dados de outros sistemas para SVG, você pode ter que lidar com desenhos vetoriais, que usam coordenadas cartesianas (as que você aprendeu em álgebra na escola) para representar dados. Neste sistema, o ponto (0, 0) é no canto inferior esquerdo da tela, e as coordenadas y aumentam à medida que se move para cima.
Uma vez que o eixo y é "invertido" relativamente ao padrão SVG, as coordenadas tem que ser recalculadas. Em vez de fazê-lo manualmente, você pode usar uma sequência de transformações para que o SVG faça todo o trabalho para você. Em primeiro lugar, traduzir a imagem SVG, com as
coordenadas exatamente como se mostra no exemplo. (Também vamos incluir os eixos como um guia.) Sem nenhuma surpresa, a imagem vai sair de cabeça para baixo. Note-se que a imagem na figura não é invertida da esquerda para a direita, uma vez que os pontos do eixo x vão na mesma direção em ambos os eixos de coordenadas cartesianas e o padrão SVG do sistema de coordenadas. <svg width="200px" height="200px" viewBox="0 0 200 200">
<polygon points="40 40, 100 40, 70 70, 40 70" style="fill: gray; stroke: black;"/>
Para terminar a conversão, siga estes os: 1. Encontre a coordenada y máxima no desenho original. Neste caso, verifica-se ser de 100, o ponto de extremidade do eixo y no original. 2. Coloque o desenho inteiro em um elemento
. 3. Insira um "translate" que move o sistema de coordenadas para baixo pelo valor máximo da coordenada y. 4. transform = "translate (0, max-y)" 5. O próximo o será transformar a escala do eixo Y por um fator de -1, para virá-lo de cabeça para baixo. 6. transform = "translate (0, max-y) scale (1, -1)" <svg width="200px" height="200px" viewBox="0 0 200 200">
<polygon points="40 40, 100 40, 70 70, 40 70" style="fill: gray; stroke: black;"/>
5.5 A transformação de rotação É também possível rodar o sistema de coordenadas por um ângulo especificado. No sistema de coordenadas padrão, a medida do ângulo aumenta à medida que você girar no sentido horário, com a linha na horizontal fazendo um ângulo de zero grau.
A menos que você especifique o contrário, o centro de rotação (um termo extravagante para o "ponto pivot") é presumido em (0, 0). O exemplo a seguir mostra um quadrado desenhado em cinza, em seguida, desenhado novamente em preto após o sistema de coordenadas ser girado em 45 graus. Os eixos são também mostrados como um guia. A Figura mostra o resultado. Se você se surpreendeu pelo quadrado ter se movido, você não deveria. Lembre-se, todo o sistema de coordenadas foi rodado. [1] [1] Todas as figuras deste capítulo são imagens estáticas. Este mostra dois quadrados; um girado e um sem rotação. Para mostrar uma animação de uma rotação, use
, que discutiremos no Capítulo 11, na Seção 11.6. <polyline points="100 0, 0 0, 0 100" style="stroke: black; fill: none;"/>
Na maioria das vezes, você não vai querer rodar todo o sistema de coordenadas ao redor da origem; você vai querer rodar um único objeto em torno de um ponto diferente da origem. Você pode fazer isso através desta série de transformações: translate (centerX, centerY); rotate (angle); translate (-centerX, -centerY). O SVG fornece outra versão de “rotate” para fazer esta tarefa comum mais fácil. Nesta segunda forma de transformação “rotate”, você especifica o ângulo e o ponto central em torno do qual você deseja girar: rotate(angle, centerX, centerY)
Isto tem o efeito de estabelecer temporariamente um novo sistema de coordenadas com a origem nos pontos x e y especificados, fazendo a rotação, e então re-estabelecendo as coordenadas originais. O exemplo abaixo mostra esta forma de rotação para criar múltiplas cópias de uma seta, mostrado na figura.
<polygon points="90 50, 85 45, 85 55" />
<use xlink:href="#arrow" transform="rotate(60, 50, 50)" /> <use xlink:href="#arrow" transform="rotate(-90, 50, 50)" /> <use xlink:href="#arrow" transform="rotate(-150, 50 50)" />
5.6 Técnica: "Scaling" em torno de um ponto central Embora seja possível girar em torno de um ponto que não seja a origem, não há correspondente capacidade de escalonar em torno de um ponto. Você pode, no entanto, fazer símbolos concêntricos com uma simples série de transformações. Para dimensionar um objeto por um determinado fator em torno de um ponto central, faça o seguinte: translate(-centerX*(factor-1), -centerY*(factor-1)) scale(factor)
Você também pode querer dividir o "stroke-width" pelo fator de escala de modo que o contorno permaneça da mesma largura enquanto o objeto torna-se maior. O exemplo a seguir chama o conjunto de retângulos concêntricos mostrado na figura. Esta é também uma imagem estática, um "alvo quadrado." Se você quiser mostrar uma animação de um quadrado em expansão, você vai usar
, que discutiremos no Capítulo 11, na Seção 11.6.
<use xlink:href="#box" transform="translate(-50,-50) scale(2)" style="stroke-width: 0.5;" /> <use xlink:href="#box" transform="translate(-75,-75) scale(2.5)" style="stroke-width: 0.4;" /> <use xlink:href="#box" transform="translate(-100,-100) scale(3)" style="stroke-width: 0.33;" />
5.7 Transformações de inclinação - "SkewX" e "SkewY" O SVG também tem duas outras transformações: "skewX" e "skewY", que permitem inclinar um dos eixos. A forma geral é skewX (angle) e skewY (angle). A transformação skewX "empurra" todas as coordenadas x por o ângulo especificado, deixando as coordenadas y inalteradas. SkewY distorce as coordenadas y, deixando inalterada as coordenadas x, como mostrado no exemplo: .oidcrhafçesnmtã qul,orsdapencmtihoãjrsnalE/
.oajdeslc rpin"továmrsI/
adinueq,mgro ltçsãf aE.u rg0e3xm-sdnoacliI/
.saendorcmtiv)0,(áes e.migaonrtbjhsd
<polyline points="50 0, 0 0, 0 50" style="fill: none; stroke: black; stroke-width: 2;"/>omsav,icrltf P/
skewX
lo.8upítahCnesdimbrá otx T/
e-qsudaynorct,xiemazsdgnroãtlE/ ort.sãae
<polyline points="50 0, 0 0, 0 50" style="fill: none; stroke: black; stroke-width: 2;"/>
skewY
Capítulo 6. Path Todas as formas básicas descritas no Capítulo 3 são, na verdade, atalhos para o mais geral dos elementos, o <path>. É extremamente aconselhável usar esses atalhos; eles ajudam a tornar o SVG mais legível e mais estruturado. O elemento <path> é mais geral; ele desenha o contorno de qualquer forma arbitrária, especificando uma série de linhas conectadas, arcos, e curvas. Este esquema pode ser preenchido e desenhado com um traçado, assim como as formas básicas são. Além disso, esses caminhos (bem como as formas básicas de estenografia) podem ser utilizados para definir o contorno de uma área de recorte ou uma máscara de transparência, como você verá no Capítulo 9. Todos os dados que descrevem um esboço estão no atributo "d" do elemento <path> ("d" significa dados). Os dados do <path> consiste em comandos de uma letra, tais como M para "moveto" ou L para "lineto", seguido da informação de coordenadas para esse comando específico. 6.1 Os comandos (M) moveto, (L) lineto e (Z) closepath Todo caminho tem de começar com um comando "moveto" (M). A letra de comando é um M maiúsculo seguido pelas coordenadas (x,y), separados por vírgulas ou espaços em branco. Este comando define o local atual da "caneta" que está desenhando o contorno. Isto é seguido por um ou mais comandos "LineTo" (L), denotada por um L maiúsculo, também seguido pelas coordenadas (x,y), separadas por vírgulas ou espaços em branco. O exemplo a seguir tem três caminhos. O primeiro chama uma única linha, o segundo desenha um ângulo direito, e o terceiro desenha dois ângulos de trinta graus. Quando você "pegar" a caneta com outro "moveto", você estará iniciando um novo subpath. Note-se que o uso de vírgulas e espaços em branco são como separadores diferentes, mas perfeitamente legal, em todos os três caminhos.
<path d="M 10 10 L 100 10" /> <path d="M 10, 20 L 100, 20 L 100,50" /> <path d="M 40 60, L 10 60, L 40 42.68, M 60 60, L 90 60, L 60 42.68" />
Examinando o último caminho mais de perto: Valor
Ação
M 40 60
Move a caneta para as coordenadas (40, 60)
L 10 60
Desenha uma linha até as coordenadas (10, 60)
L 40 42.68
Desenha uma linha até as coordenadas (40, 42.68)
M 60 60
Move a caneta para as coordenadas (60, 60)
L 90 60
Desenha uma linha até as coordenadas (90, 60)
L 60 42.68
Desenha uma linha até as coordenadas (60, 42.68)
Você pode ter notado que os dados do <path> não parecem muito os valores típicos para atributos XML. Porque todos os dados são contidos em um atributo em vez de um elemento individual para cada ponto ou segmento de linha, um caminho ocupa menos memória quando lido em uma estrutura DOM (Document Object Model) por um parser XML. Além disso, a notação compacta de um caminho permite que um gráfico complexo possa ser transmitido sem a necessidade de uma grande quantidade de largura de banda. Se você quiser usar um <path> para desenhar um retângulo, você pode desenhar todas as quatro linhas, ou você pode desenhar as três primeiras linhas e, em seguida, utilizar o comando "closepath", indicado por um Z maiúsculo, para desenhar uma linha reta de volta ao ponto de início do subpath atual. Usando o comando closepath (Z)
<path d="M 10 10, L 40 10, L 40 30, L 10 30, L 10 10" /> <path d="M 60 10, L 90 10, L 90 30, L 60 30, Z" /> <path d="M 40 60, L 10 60, L 40 42.68, Z M 60 60, L 90 60, L 60 42.68, Z" />
Examinando o último caminho mais de perto: Valor
Ação
M 40 60
Move a caneta para as coordenadas (40, 60)
L 10 60
Desenha uma linha até as coordenadas (10, 60)
L 40 42.68
Desenha uma linha até as coordenadas (40, 42.68)
Z
Fecha o caminho desenhando uma linha reta para as coordenadas (40, 60)
M 60 60
Move a caneta para as coordenadas (60, 60)
L 90 60
Desenha uma linha até as coordenadas (90, 60)
L 60 42.68
Desenha uma linha até as coordenadas (60, 42.68)
Z
Fecha o caminho desenhando uma linha reta para as coordenadas (60, 60)
6.2 "moveto" e "lineto" relativos Os comandos anteriores são todos representados por letras maiúsculas, e as coordenadas são, presumese, as coordenadas absolutas. Se você usar uma letra de comando em minúscula, as coordenadas serão interpretadas como sendo relativas à posição atual da caneta. Assim, os dois caminhos seguintes são equivalentes: <path d="M 10 10 L 20 10 L 20 30 M 40 40 L 55 35" style="stroke: black;" /> <path d="M 10 10 l 10 0 l 0 20 m 20 10 l 15 -5" style="stroke: black;" />
Se você iniciar um caminho com um "m" minúsculo (moveto), as suas coordenadas serão interpretadas como uma posição absoluta, pois não há posição de caneta anterior a partir da qual se possa calcular uma posição relativa. Todos os outros comandos neste capítulo também têm a mesma distinção de letras maiúsculas e minúsculas. As coordenadas de um comando em maiúsculas são absolutas e os comandos com coordenadas em minúsculo são relativos. Para comandos "closepath", que não tem coordenadas, tanto faz ser escrito em maiúsculas ou em minúsculas. 6.3 Atalhos de caminho <path> Se o conteúdo é rei e o design é a rainha, então a eficiência da largura de banda é o cortesão real que mantém o palácio funcionando sem problemas. Desde que qualquer desenho não-trivial terá caminhos com muitas dezenas de pares de coordenadas, o elemento <path> tem atalhos que permitem que você represente um caminho em tão poucos bytes quanto possível. 6.3.1 Os comandos "lineto" horizontal e vertical Desde que as linhas horizontais e verticais são tão comuns, um caminho <path> pode especificar uma linha horizontal com um comando "H" seguido de uma "coordenada x" absoluta ou um comando "h" seguido por uma "coordenada x" relativa. Do mesmo modo, uma linha vertical é especificada com um comando "V" seguido de uma "coordenada y" absoluta ou um comando "v" seguido por uma "coordenada y" relativa. Atalho
Equivalente a
Efeito
H 20
L 20 atual_y
Desenha uma linha à locação absoluta (20, atual_y)
h 20
l 20 0
Desenha uma linha até (atual_x + 20, atual_y)
V 20
L atual_x 20
Desenha uma linha à locação absoluta (atual_x, 20)
v 20
l atual_x 20
Desenha uma linha até (atual_x, atual_y + 20)
Assim, o caminho a seguir desenha um retângulo de 15 unidades de largura e 25 unidades de altura, com o canto superior esquerdo nas coordenadas (12, 24). <path d="M 12 24 h 15 v 25 h -15 z"/>
6.3.2 Notação de atalhos para um caminho <path> Caminhos também podem ser feitos mais curtos através da aplicação das duas regras seguintes: 1. Você pode colocar vários conjuntos de coordenadas depois de um "L" ou "l", assim como você faz no elemento
. Os seis caminhos seguintes todos desenham o mesmo diamante que é mostrado na figura; os três primeiros são em coordenadas absolutas e os três últimos em coordenadas relativas. O terceiro e sexto caminhos têm uma característica interessante - se você colocar vários pares de coordenadas depois de um "moveto", todos os pares após os primeiros presume-se que sejam precedidos por um "lineto". Você também pode colocar múltiplas coordenadas individuais após uma "lineto" horizontal ou "lineto" vertical, embora seja inútil fazê-lo, pois H 25 35 45 é o mesmo que H 45; e v 11 13 15 é o mesmo que v 39. <path <path <path <path <path <path
d="M 30 30 L 55 5 L 80 30 L 55 55 Z" /> d="M 30 30 L 55 5 80 30 55 55 Z" /> d="M 30 30 55 5 80 30 55 55 Z" /> d="m 30 30 l 25 -25 l 25 25 l -25 25 z" /> d="m 30 30 l 25 -25 25 25 -25 25 z" /> d="m 30 30 25 -25 25 25 -25 25 z" />
Qualquer espaço em branco que não é necessário, pode ser eliminado. Você não precisa de um espaço em branco após um caractere de comando já que todos os comandos são apenas letras. Você não precisa de um espaço em branco entre um número e um comando porque a letra do comando não pode ser parte de um número. Você não precisa de um espaço em branco entre um positivo e um número negativo, uma vez que o sinal de menos que conduz ao número negativo não pode ser uma parte do número positivo. Isto permite-lhe reduzir os terceiro e sexto caminhos na listagem anterior ainda mais longe: <path d="M30 30 55 5 80 30 55 55Z" /> <path d="m30 30 25-25 25 25-25 25z" />
Outro exemplo da regra de eliminação do espaço em branco em ação, é mostrado pelo exemplo que desenha um retângulo de 15 unidades de largura e 25 unidades de altura, com o canto superior esquerdo nas coordenadas (12, 24): <path d="M 12 24 h 15 v 25 h -15 z" /> <path d="M12 24h15v25h-15z" />
6.4 Arco elíptico As linhas são simples; dois pontos em um caminho determinam exclusivamente um segmento de linha entre eles. Uma vez que um número infinito de curvas podem ser estabelecidas entre dois pontos, você deve dar informações adicionais para desenhar um caminho curvo entre eles. A mais simples das curvas que vamos examinar é o arco elíptico - ou seja, puxando uma seção de uma elipse que liga dois pontos. Embora arcos sejam visualmente as curvas mais simples, a especificação de um único arco requer mais informações. As primeiras peças de informação que você precisa especificar são os raios "x" e "y" da elipse em que os pontos se encontram. Isso restringe-os a duas elipses possíveis, como você pode ver na seção (a) da figura abaixo. Os dois pontos dividem as duas elipses em quatro arcos. Dois deles, (b) e (c), são arcos que medem menos de 180 graus. Os outros dois, (d) e (e) são maiores do que 180 graus. Se você olhar para (b) e (c), você vai notar que eles são diferenciados por sua direção; (B) é desenhado no sentido de um ângulo negativo, e (c) no sentido de um ângulo positivo. A mesma relação mantém verdadeiro entre (d) e (e). Mas espere - ainda não foi especificado exclusivamente os arcos potenciais! Não há nenhuma lei que diga que a elipse tem que ter o seu raio-x paralelo ao eixo x. A parte (f ) da figura mostra os dois pontos com as suas elipses candidatos rodado trinta graus em relação ao eixo-x.
Assim, um comando "arc" começa com a abreviatura "A" para coordenadas absolutas ou um "a"para coordenadas relativas, e é seguido por sete parâmetros: • Os raios (x,y) da elipse em que os pontos se encontram. • O eixo-x de rotação da elipse.
• O grande arco de bandeira, que é zero, se a medida do arco é inferior a 180 graus, ou um, se a medida de arco é maior ou igual a 180 graus. • A varredura-bandeira, que é zero se o arco deve ser desenhado em ângulo negativo direção, ou um, se o arco deve ser desenhado em ângulo positivo. • As coordenadas X e Y do ponto final. (O ponto de partida é determinado pelo último ponto desenhado ou o último comando "moveto".) Aqui estão os caminhos <path> usados para desenhar os arcos elípticos nas seções (b) a (e) <path <path <path <path
d="M d="M d="M d="M
125,75 A100,50 125,75 A100,50 125,75 A100,50 125,75 A100,50
0 0,0 0 0,1 0 1,0 0 1,1
225,125" /> 225,125" /> 225,125" /> 225,125" />
Como mais um exemplo, vamos a fundo para completar o símbolo "yin / yang" que é parte da bandeira da Coreia. <ellipse cx="154" cy="154" rx="150" ry="120" style="fill: #999999;" />
<ellipse cx="152" cy="152" rx="150" ry="120" style="fill: #cceeff;" />
<path d="M 302 152 A 150 120, 0, 1, 0, 2 152 A 75 60, 0, 1, 0, 152 152" style="fill: #ffcccc;" />
<path d="M 152 152 A 75 60, 0, 1, 1, 302 152" style="fill: #cceeff;" />
6.5 Técnica: convertendo de outros formatos Arc Alguns sistemas gráficos vetoriais permitem que você especifique um arco definindo um ponto central para a elipse, a coordenada X e Y do raio, o ângulo de partida, e a extensão do ângulo do arco . Isto é um método simples da especificação, e é excelente para desenho de arcos como único objeto. Paradoxalmente, é exatamente por isso que o SVG escolhe um método excêntrico, aparentemente, para especificar arcos. Em SVG, um arco não se presume sozinho; ele é destinado a fazer parte de um caminho de conexão com linhas e curvas. (Por exemplo, um retângulo arredondado é precisamente isso - uma série de linhas e arcos elípticos.) Assim, faz sentido especificar um arco por seus pontos finais
(endpoints). Às vezes, porém, você quer um semicírculo isolado (ou, mais precisamente, uma semielipse). Presumindo que você tem uma elipse especificada como: <ellipse cx="cx" cy="cy" rx="rx" ry="ry"/>
Aqui estão os caminhos para desenhar os quatro possíveis semi-elipses:
<path d="M cx-rx cy A rx ry 0 1 1 cx+rx cy"/>
<path d="M cx-rx cy A rx ry 0 1 0 cx+rx cy"/>
<path d="M cx cy-ry A rx ry 0 1 1 cx cy+ry"/>
<path d="M cx cy-ry A rx ry 0 1 0 cx cy+ry"/>
Para o caso mais geral, quando se deseja desenhar um arco arbitrário que foi especificado na notação de "centro-e-ângulos" e gostaria de convertê-lo em "pontosfinais-e-varrer" do formato SVG, use o seguinte script Perl. Ele pede-lhe coordenadas do centro, raios, começando pelo ângulo e medida do ângulo. A saída é uma tag <path> que você pode inserir em seus arquivos SVG. #!/usr/bin/perl # # Convert an elliptical arc based around a central point # to an elliptical arc parameterized for SVG. # # Input is a list containing: # center x coordinate # center y coordinate # x-radius of ellipse # y-radius of ellipse # beginning angle of arc in degrees # arc extent in degrees # x-axis rotation angle in degrees # # Output is a list containing: # # x-coordinate of beginning of arc # y-coordinate of beginning of arc # x-radius of ellipse # y-radius of ellipse # large-arc-flag as defined in SVG specification # sweep-flag as defined in SVG specification # x-coordinate of endpoint of arc # y-coordinate of endpoint of arc # sub convert_to_svg { my ($cx, $cy, $rx, $ry, $theta1, $delta, $phi) = @_; my ($theta2, $pi); my ($x0, $y0, $x1, $y1, $large_arc, $sweep); # # Convert angles to radians #
$pi = atan2(1,1) * 4; # approximation of pi $theta2 = $delta + $theta1; $theta1 = $theta1 * $pi / 180.0; $theta2 = $theta2 * $pi / 180.0; $phi_r = $phi * $pi / 180.0; # # Figure out the coordinates of the beginning and # ending points # $x0 = $cx + cos($phi_r) * $rx * cos($theta1) + sin(-$phi_r) * $ry * sin($theta1); $y0 = $cy + sin($phi_r) * $rx * cos($theta1) + cos($phi_r) * $ry * sin($theta1); $x1 = $cx + cos($phi_r) * $rx * cos($theta2) + sin(-$phi_r) * $ry * sin($theta2); $y1 = $cy + sin($phi_r) * $rx * cos($theta2) + cos($phi_r) * $ry * sin($theta2); $large_arc = ($delta > 180) ? 1 : 0; $sweep = ($delta > 0) ? 1 : 0; return ($x0, $y0, $rx, $ry, $phi, $large_arc, $sweep, $x1, $y1); } # # Request input # print "Enter center x,y coordinates > "; $data = <>; $data =~ s/,/ /g; ($cx, $cy) = split /\s+/, $data; print "Enter x and y radii > "; $data = <>; $data =~ s/,/ /g; ($rx, $ry) = split/\s+/, $data; print "Enter starting angle in degrees > "; $theta = <>; chomp $theta; print "Enter angle extent in degrees > "; $delta = <>; chomp $delta; print "Enter angle of rotation in degrees > "; $phi = <>; chomp $phi; # # Echo original data # print "(cx,cy)=($cx,$cy) rx=$rx ry=$ry ", "start angle=$theta extent=$delta rotate=$phi\n"; ($x0, $y0, $rx, $ry, $phi, $large_arc_flag, $sweep_flag, $x1, $y1) = convert_to_svg($cx, $cy, $rx, $ry, $theta, $delta, $phi); # # Produce a <path> element that fits the # specifications # print "<path d=\"M $x0 $y0 ", # Moveto initial point "A $rx $ry ", # Arc command and radii, "$phi ", # angle of rotation,
"$large_arc_flag ", # the "large-arc" flag, "$sweep_flag ", # the "sweep" flag, "$x1 $y1\"/>\n"; # and the endpoint
Se você deseja converter a partir do formato SVG para um formato de "centro-e-ângulos", a matemática é consideravelmente mais complexa. Você pode ver as fórmulas em detalhe na especificação SVG. Este script Perl foi adaptado do código no projeto Apache XML Batik. #!/usr/bin/perl sub acos { atan2(sqrt(1 - $_[0] * $_[0]), $_[0]); } # # Convert an elliptical arc based around a central point # to an elliptical arc parameterized for SVG. # # Input is a list containing: # # x-coordinate of beginning of arc # y-coordinate of beginning of arc # x-radius of ellipse # y-radius of ellipse # large-arc-flag as defined in SVG specification # sweep-flag as defined in SVG specification # x-coordinate of endpoint of arc # y-coordinate of endpoint of arc # # Output is a list containing: # center x coordinate # center y coordinate # x-radius of ellipse # y-radius of ellipse # beginning angle of arc in degrees # arc extent in degrees # x-axis rotation angle in degrees # sub convert_from_svg { my ($x0, $y0, $rx, $ry, $phi, $large_arc, $sweep, $x, $y) = @_; my ($cx, $cy, $theta, $delta, $phi); # a plethora of temporary variables my ( $dx2, $dy2, $phi_r, $x1, $y1, $rx_sq, $ry_sq, $x1_sq, $y1_sq, $sign, $sq, $coef, $cx1, $cy1, $sx2, $sy2, $p, $n, $ux, $uy, $vx, $vy ); # Compute 1/2 distance between current and final point $dx2 = ($x0 - $x) / 2.0; $dy2 = ($y0 - $y) / 2.0; # Convert from degrees to radians
$pi = atan2(1, 1) * 4.0; $phi %= 360; $phi_r = $phi * $pi / 180.0; # Compute (x1, y1) $x1 = cos($phi_r) * $dx2 + sin($phi_r) * $dy2; $y1 = -sin($phi_r) * $dx2 + cos($phi_r) * $dy2; # Make sure radii are large enough $rx = abs($rx); $ry = abs($ry); $rx_sq = $rx * $rx; $ry_sq = $ry * $ry; $x1_sq = $x1 * $x1; $y1_sq = $y1 * $y1; $radius_check = ($x1_sq / $rx_sq) + ($y1_sq / $ry_sq); if ($radius_check > 1) { $rx *= sqrt($radius_check); $ry *= sqrt($adius_check); $rx_sq = $rx * $rx; $ry_sq = $ry * $ry; } # Step 2: Compute (cx1, cy1) $sign = ($large_arc == $sweep) ? -1 : 1; $sq = (($rx_sq * $ry_sq) - ($rx_sq * $y1_sq) - ($ry_sq * $x1_sq)) / (($rx_sq * $y1_sq) + ($ry_sq * $x1_sq)); $sq = ($sq < 0) ? 0 : $sq; $coef = ($sign * sqrt($sq)); $cx1 = $coef * (($rx * $y1) / $ry); $cy1 = $coef * -(($ry * $x1) / $rx); # Step 3: Compute (cx, cy) from (cx1, cy1) $sx2 = ($x0 + $x) / 2.0; $sy2 = ($y0 + $y) / 2.0; $cx = $sx2 + (cos($phi_r) * $cx1 - sin($phi_r) * $cy1); $cy = $sy2 + (sin($phi_r) * $cx1 + cos($phi_r) * $cy1); # Step 4: Compute angle start and angle extent $ux = ($x1 - $cx1) / $rx; $uy = ($y1 - $cy1) / $ry; $vx = (-$x1 - $cx1) / $rx; $vy = (-$y1 - $cy1) / $ry; $n = sqrt(($ux * $ux) + ($uy * $uy)); $p = $ux; # 1 * ux + 0 * uy $sign = ($uy < 0) ? -1 : 1; $theta = $sign * acos($p / $n); $theta = $theta * 180 / $pi; $n = sqrt(($ux * $ux + $uy * $uy) * ($vx * $vx + $vy * $vy)); $p = $ux * $vx + $uy * $vy; $sign = (($ux * $vy - $uy * $vx) < 0) ? -1 : 1; $delta = $sign * acos($p / $n); $delta = $delta * 180 / $pi; if ($sweep == 0 && $delta > 0) { $delta -= 360; } elsif ($sweep == 1 && $delta < 0) { $delta += 360; }
$delta %= 360; $theta %= 360; return ($cx, $cy, $rx, $ry, $theta, $delta, $phi); } # # Request input # print "Enter starting x,y coordinates > "; $data = <>; $data =~ s/,/ /g; ($x0, $y0) = split /\s+/, $data; print "Enter ending x,y coordinates > "; $data = <>; $data =~ s/,/ /g; ($x, $y) = split /\s+/, $data; print "Enter x and y radii > "; $data = <>; $data =~ s/,/ /g; ($rx, $ry) = split/\s+/, $data; print "Enter rotation angle in degrees "; $phi = <>; chomp $phi; print "Large arc flag (0=no, 1=yes) > "; $large_arc = <>; chomp $large_arc; print "Sweep flag (0=negative, 1=positive) > "; $sweep = <>; chomp $sweep; print "From ($x0,$y0) to ($x,$y) rotate $phi", " large arc=$large_arc sweep=$sweep\n"; ($cx, $cy, $rx, $ry, $theta, $delta, $phi) = convert_from_svg($x0, $y0, $rx, $ry, $phi, $large_arc, $sweep, $x, $y); print "Ellipse center = ($cx, $cy)\n"; print "Start angle = $theta\n"; print "Angle extent = $delta\n";
6.6 Curvas de Bézier Arcos podem ser caracterizados como limpos e funcionais, mas raramente seria usado a palavra "Gracioso" para descrevê-los. Se você quiser graciosidade, você precisa usar as curvas que são produzidas por gráficos de equações quadráticas e cúbicas. Os matemáticos têm conhecimento destas curvas por literalmente centenas de anos, mas desenhá-las sempre foi uma tarefa exigente computacionalmente. Isso mudou quando Pierre Bézier, trabalhando para a fabricante de automóveis Renault e Paul de Casteljau, um engenheiro da Citroën, independentemente, descobriu uma maneira computacionalmente conveniente para gerar estas curvas. Se você já usou programas gráficos como o Adobe Illustrator, você desenhou as curvas de Bézier especificando dois pontos e, em seguida, movendo uma "alça", como mostrado no diagrama a seguir. Este identificador é chamado de "ponto de controle", porque ele controla a forma da curva. Quando você move a alça, a curva muda de uma forma que, para os não iniciados, é completamente incompreensível. Mike Woodburn, um designer gráfico em Key Point Software, sugere na figura a seguir uma maneira de visualizar como o ponto de controle interage na curva:
imagine que a linha é feita de metal flexível. O ponto de controle possui um ímã em seu interior; quanto mais perto o ponto de controle é de um ponto, mais forte é a atração da linha.
6.6.1 Curvas de Bézier quadrática A mais simples das curvas Bézier é a curva quadrática. Você especifica um ponto de início, um ponto de chegada e um ponto de controle. Imagine dois postes de tenda colocados nas extremidades da linha. Estes postes da barraca se encontram no ponto de controle. Esticada entre os centros da tenda uma faixa de borracha. O local onde as curvas da curva estão ligadas é o centro exato do elástico de borracha.
Programas como o Adobe Illustrator mostram-lhe apenas um dos "postes da tenda." A próxima vez que você usar um programa desse tipo, mentalmente adicione no segundo poste e o resultado da curva será muito menos misterioso. Este é o conceito; agora vamos para a questão prática de realmente produzir uma curva em SVG. Você especifica uma curva quadrática em um <path> com o comando Q ou q. O comando é seguido por dois conjuntos de coordenadas que especificam um ponto de controle e um ponto final. O comando em maiúsculas implica coordenadas absolutas; em minúsculas implica coordenadas relativas. A curva na figura abaixo foi desenhada a partir de (30, 75) a (300, 120) com o ponto de controle no (240, 30), e foi especificada em SVG como segue: <path d="M30 75 Q 240 30, 300 120" style="stroke: black; fill: none;"/>
Você pode especificar vários conjuntos de coordenadas depois de um comando de curva quadrática. Isso vai gerar uma curva "PolyBézier". Supondo que você queira um <path> que desenhe uma curva a partir de (30, 100) até (100, 100) com um ponto de controle no (80, 30) e, em seguida, continue com uma curva (200, 80) com um ponto de controle no (130, 65). Aqui está o SVG para este <path>, com as coordenadas dos pontos de controle em itálico. O resultado é mostrado na metade esquerda da figura ; os pontos de controle e linhas são mostradas na metade direita da figura. <path d="M30 100 Q 038
, 100 100, 56031
, 200 80" />
Você provavelmente está se perguntando, "O que aconteceu com a 'graciosidade?' Essa curva é apenas irregular. " Esta é uma avaliação precisa. Só porque as curvas estão ligadas não significa que elas ficarão bem juntas. É por isso que o SVG fornece o comando curva quadrática suave, que é representado pela letra "T" (ou "t", se você quiser usar coordenadas relativas). O comando é seguido pela próxima extremidade da curva; o ponto de controle é calculado automaticamente, como a especificação diz, por "reflexo do ponto de controle no comando anterior, em relação ao ponto atual". Para as curvas oblíquas, o novo ponto de controle (x2, y2) é calculado a partir do ponto de partida da curva (x, y) e o ponto de controle anterior (x1, y1) com estas fórmulas: x2 = 2 * x - x1 y2 = 2 * y – y1
Aqui é uma curva Bézier quadrática elaborado a partir de (30, 100) a (100, 100) com um ponto de controle em (80, 30) e, em seguida, continua suavemente (200, 80). A metade esquerda mostra a curva; a metade direita mostra os pontos de controle. O ponto de controle refletido é mostrado com uma linha tracejada. A graciosidade voltou! <path d="M30 100 Q 80 30, 100 100 T 200 80" />
6.6.2 Curvas de Bézier cúbicas Uma única curva Bézier quadrática tem exatamente um ponto de inflexão (o ponto onde a curva muda de direção). Enquanto estas curvas são mais versáteis do que os arcos simples, podemos fazer ainda melhor usando curvas de Bézier cúbicas, que podem ter um ou dois pontos de inflexão. A diferença entre as curvas quadráticas e cúbicas é que a curva cúbica tem dois pontos de controle, um para cada terminal. A técnica para gerar a curva cúbica é semelhante a usada para gerar a curva quadrática. Você desenha três linhas que ligam a terminais e pontos de controle (a), e conecta seus pontos médios. Isto produz duas linhas (b). Ligando os pontos médios, produz uma linha (C), cujo ponto central determina um dos pontos da curva final.
Para especificar uma curva cúbica, use o comando "C" ou "c". O comando é seguido por três conjuntos de coordenadas que especificam o ponto de controle para o ponto de início, o ponto de controle para o ponto final, e o ponto final. Tal como acontece com todos os outros comandos de <path>, um comando com letra maiúscula implica coordenadas absolutas; minúsculas implica coordenadas relativas. A curva, no diagrama anterior, foi desenhada a partir de (20, 80) até (200, 120) com pontos de controle em (50, 20) e (150, 60). <path d="M20 80 C 50 20, 150 60, 200 120" style="stroke: black; fill: none;"/>
Há muitas curvas interessantes que você pode desenhar, dependendo da relação dos pontos de controle. Para fazer o gráfico do limpador, nós mostramos apenas as linhas a partir de cada ponto final para o seu ponto de controle:
Tal como acontece com as curvas quadráticas, você pode construir uma "PolyBézier" cúbica especificando vários conjuntos de coordenadas depois de um comando de curva cúbica. O último ponto da primeira curva torna-se o primeiro ponto da curva seguinte, e assim por diante. Aqui, <path> que desenha uma curva cúbica de (30, 100) até (100, 100) com pontos de controle em (50, 50) e (70, 20); é imediatamente seguido por uma curva que funciona de volta para (65, 100) com pontos de controle em (110, 130) e (45, 150). Aqui está o SVG para este <path>, com as coordenadas do ponto de controle em itálico. O resultado é mostrado na metade esquerda da figura; os pontos de controle e linhas são mostrados na metade direita do diagrama. <path d="M30 100 C 50 50, 70 20, 100 100, 110, 130, 45, 150, 65, 100" />
Se você quiser garantir a boa junção entre as curvas, você pode usar o comando "S" (ou "s" para coordenadas relativas). De um modo análogo ao comando "T" para curvas quadráticas, a nova curva tomará os pontos finais das curvas anteriores como ponto de partida, e o primeiro ponto de controle será o reflexo do ponto de controle final anterior. Tudo que você precisa fornecer é o ponto de controle para o próximo ponto final na curva, seguido do próximo ponto de extremidade. Aqui, uma curva cúbica de Bézier elaborada a partir de (30, 100) a (100, 100) com pontos de controle em (50, 30) e (70, 50). Continua sem problemas para (200, 80), usando (150, 40), como seu ponto de controle final. A metade superior mostra a curva; a metade inferior mostra os pontos de controle. O ponto de controle refletido é mostrado com uma linha tracejada. <path d="M30 100 C 50 30, 70 50, 100 100 S 150 40, 200 80" />
6.7 Sumário de referências <path> Comandos <path> Comandos Argumentos
Efeitos
M, m
x, y
Move-se para a coordenada dada.
L, l
x, y
Desenha uma linha até as coordenadas dadas. Você pode fornecer múltiplos conjuntos de coordenadas para desenhar um polígono.
H, h
x
Desenha uma linha horizontal para a coordenada-x dada.
V, v
y
Desenha uma linha vertical para a coordenada-y dada.
A, a
rx, ry x-axis-rotation large-arc sweep x, y
Desenha um arco elíptico do ponto atual (x, y). Os pontos estão em uma elipse com "rx" (raio-x) e "ry" (raio-y). A elipse é rodada em graus no eixo de rotação x (x-axis-rotation). Se o arco é inferior a 180 graus, "large-arc" é igual a zero(0); se for maior que 180 graus, "large-arc" é igual a um(1). Se o arco deve ser desenhado em direção positiva, "sweep" é igual a um (1); caso contrário, é igual a zero(0).
Q, q
x, y, x1, y1
Desenha uma curva Bézier quadrática do ponto atual até (x, y) usando o ponto de controle (x1, y1).
T, t
x, y
Desenha uma curva Bézier quadrática do ponto atual até (x, y). O ponto de controle será o reflexo do ponto de controle do comando"Q" anterior. Se não houver nenhuma curva anterior, o ponto atual vai ser utilizada como o ponto de controle.
C, c
x, y, x1, y1, x2, Desenha uma curva Bézier cúbica do ponto atual até (x, y) usando o y2 ponto de controle (x1, y1) como o ponto de controle para o início da curva e (x2, y2), como o ponto de controle para o ponto final da curva.
S, s
x, y, x2, y2
Desenha uma curva Bézier cúbica do ponto atual até (x, y), usando (x2, y2) como o ponto de controle para este novo ponto final. O primeiro ponto de controle será o reflexo dos pontos de controle final dos comandos "C" anteriores. Se não houver nenhuma curva anterior, o ponto atual será utilizado como o primeiro ponto de controle.
6.8 Caminhos (path) e preenchimento (filling) As informações descritas no Capítulo 3 na Seção 3.5.1 também se aplicam a caminhos, que não podem ter apenas linhas que se intersectam, mas também podem ter "buracos" neles. Considere os caminhos no exemplo abaixo, ambos desenham quadrados aninhados. No primeiro caminho, que ambos são desenhados no sentido horário; no segundo caminho, o quadrado externo é desenhado no sentido horário e o quadrado interno é desenhado no sentido anti-horário. <path d="M 0 0, 60 0, 60 60, 0 60 Z M 15 15, 45 15, 45 45, 15 45Z"/> <path d="M 0 0, 60 0, 60 60, 0 60 Z M 15 15, 15 45, 45 45, 45 15Z"/>
A figura desenhada mostra que há uma diferença quando você usa um "fill-rule" de "nonzero", que leva em conta o sentido das linhas para determinar se um ponto está dentro ou fora de um caminho. Usar um "fill-rule" de "evenodd" produz o mesmo resultado para ambos os caminhos; ele usa o número total de linhas cruzadas e ignora sua direção.
6.9 O elemento marcador <marker> Vamos supor o seguinte caminho, que utiliza uma linha, um arco elíptico, e outra linha para desenhar o canto arredondado: <path d="M 10 20 100 20 A 20 30 0 0 1 120 50 L 120 110" style="fill: none; stroke: black;"/>
Nós gostaríamos de marcar a direção do caminho, colocando um círculo no início, um sólido triângulo, no final, e pontas de seta para os outros vértices, como mostrado na figura. Para conseguir este efeito, vamos construir três elementos <marker> e dizer ao <path> para referenciá-los.
Vamos começar com um exemplo que aumenta o marcador circular. Um marcador é um gráfico"autosuficiente" com seu próprio conjunto particular de coordenadas, então você tem que especificar a largura (markerWidth) e altura (markerHeight) no começo da tag <marker>. Isto é seguido pelos elementos SVG necessários para redigir o marcador, e termina com um fechamento . Um elemento <marker> não se apresenta, por si só, mas estamos colocando-o em um elemento <defs> porque é onde os elementos reutilizáveis pertencem. Desde que nós queremos o círculo para estar no início do caminho, nós adicionamos um marcador de início ao estilo no <path>. O valor desta propriedade é uma referência URL para o elemento <marker> que acabou de ser criado. <defs> <marker id="mCircle" markerWidth="10" markerHeight="10">
<path d="M 10 20 100 20 A 20 30 0 0 1 120 50 L 120 110" style="marker-start: url(#mCircle); fill: none; stroke: black;"/>
O motivo do círculo aparecer no lugar errado é que, por padrão, o marcador de início, ponto (0, 0) é alinhado com o início das coordenadas do caminho. O exemplo a seguir acrescenta os atributos "refX" e "refY" que dizem que coordenadas (no sistema do marcador) são para alinhar com as coordenadas de início. Uma vez que estes são adicionados, o marcador circular aparece exatamente onde ele é desejado. <marker id="mCircle" markerWidth="10" markerHeight="10" refX="5" refY="5">
Perante esta informação, podemos agora escrever o próximo exemplo, que aumenta o marcador triangular e referencia-o como o marcador de ponta para o caminho. Então, podemos adicionar o marcador de ponta de seta e referenciá-lo como o marcador médio. O marcador médio será anexado a cada vértice, exceto no início e no final do caminho. Observe que os atributos refX e ref Y foram definidos de forma que no final a grande ponta da flecha se alinhe com os vértices intermediários, enquanto a ponta do triângulo sólido se alinha com o vértice final. <defs> <marker id="mCircle" markerWidth="10" markerHeight="10" refX="5" refY="5">
<marker id="mArrow" markerWidth="6" markerHeight="10" refX="0" refY="4"> <path d="M 0 0 4 4 0 8" style="fill: none; stroke: black;"/> <marker id="mTriangle" markerWidth="5" markerHeight="10" refX="5" refY="5"> <path d="M 0 0 5 5 0 10 Z" style="fill: black;"/> <path d="M 10 20 100 20 A 20 30 0 0 1 120 50 L 120 110" style="marker-start: url(#mCircle); marker-mid: url(#mArrow); marker-end: url(#mTriangle); fill: none; stroke: black;"/>
Para obter o efeito que você quer, você deve definir explicitamente um atributo marcador "orient" para "auto". Isto o faz rodar automaticamente para coincidir com a direção do percurso (poderá igualmente especificar um número de graus, caso em que o marcador terá sempre que ser rodado por quantidade.) <defs> <marker id="mCircle" markerWidth="10" markerHeight="10" refX="5" refY="5">
<marker id="mArrow" markerWidth="6" markerHeight="10" refX="0" refY="4" orient="auto"> <path d="M 0 0 4 4 0 8" style="fill: none; stroke: black;"/> <marker id="mTriangle" markerWidth="5" markerHeight="10" refX="5" refY="5" orient="auto"> <path d="M 0 0 5 5 0 10 Z" style="fill: black;"/> <path d="M 10 20 100 20 A 20 30 0 0 1 120 50 L 120 110" style="marker-start: url(#mCircle); marker-mid: url(#mArrow); marker-end: url(#mTriangle); fill: none; stroke: black;"/>
Outro atributo útil é o atributo "markerUnits". Se definido como "strokeWidth", o marcador do sistema de coordenadas é definido para que uma unidade seja igual a largura do traçado. Isso faz com que o seu marcador cresça na proporção da largura do traço; é o comportamento padrão e é normalmente o que se quer. Se você definir o atributo para "SpaceOnUse", as coordenadas do marcador serão presumidas as mesmas do sistema de coordenadas do objeto que faz referência ao marcador. O marcador permanecerá o mesmo independentemente do tamanho da largura do traçado. 6.10 Miscelânea de marcadores Se quiser o mesmo marcador no início, meio e fim de um caminho, você não precisa especificar todas as propriedades para marcador de início, marcador de meio, e marcador de ponta. Basta usar a propriedade marcador e referenciar o marcador que você deseja. Assim, se quiséssemos que todos os vértices de um marcador sejam circulares, escreveríamos assim: <defs> <marker id="mCircle" markerWidth="10" markerHeight="10" refX="5" refY="5">
<path d="M 10 20 100 20 A 20 30 0 0 1 120 50 L 120 110" style="marker: url(#mCircle); fill: none; stroke: black;"/>
Também é possível definir o "viewBox" e atributos "preserveAspectRatio" num elemento <marker> para ganhar ainda mais controle sobre a sua exibição. Estes funcionam exatamente como descrito no Capítulo 2, na Seção 2.3 e na Seção 2.4.
Você pode fazer referência a um elemento<marker> em um elemento<polygon>, <polyline> ou
bem como em um <path>. O pensamento seguinte pode ter ocorrido a você: "Se um marcador pode ter um caminho nele, pode esse caminho têm um marcador ligado a ele também? "A resposta é sim, ele pode, mas o segundo marcador deve caber no retângulo estabelecido pelos atributos "markerWidth" e "markerHeight" do primeiro marcador . Por favor, lembre-se que só porque uma coisa pode ser feita não significa que deva ser feito. Se você precisa de um tal efeito, provavelmente é melhor desenhar o marcador secundário como parte do marcador primário, em vez de tentar aninhar os marcadores.
Capítulo 7. Padrões e gradientes Até este ponto, temos usado apenas cores sólidas para preencher e delinear objetos gráficos. Não há restrições em utilizar apenas cores sólidas; você também pode usar um padrão ou um gradiente para preencher ou traçar um gráfico. Isso é o que vamos examinar neste capítulo. 7.1 Padrões Para usar um padrão, você define um objeto gráfico que é replicado horizontalmente e/ou verticalmente para preencher outro objeto (ou borda). Este objeto gráfico é chamado de ladrilho (tile), porque o ato de preencher um objeto com um padrão (pattern) é muito parecido com cobrir uma área com ladrilhos (ou azulejos). Nesta seção, vamos usar a curva quadrática desenhada via SVG no exemplo abaixo como nosso ladrilho (tile). É desenhado em um quadro cinza para mostrar sua área (20 por 20 unidades do usuário) com clareza. <path d="M 0 0 Q 5 20 10 10 T 20 20" style="stroke: black; fill: none;"/> <path d="M 0 0 h20 v20 h-20 z" style="stroke: gray; fill: none;"/>
7.1.1 Unidades de Padrão (patternsUnits) Para criar um padrão (pattern) em ladrilho (tiles), você deve colocar os elementos <path> que descrevem seu ladrilho em um elemento <pattern> e, em seguida, tomar algumas decisões. A primeira decisão é como você deseja espaçar os ladrilhos, e isto reflete-se no atributo "patternUnits". Você quer que os ladrilhos sejam espaçados para preencher uma certa porcentagem de cada objeto eles são aplicados a, ou você os quer afastados com intervalos iguais, não importa qual o tamanho do objeto que está preenchendo? Se você quer dimensionar o ladrilho em uma base objeto a objeto, você deve especificar as coordenadas X e Y do canto superior esquerdo, sua largura e altura, como porcentagens ou decimais em uma faixa de zero a um, e definir as "patternUnits" atribuindo um "objectBoundingBox". A caixa delimitadora do objeto é o menor retângulo que inclui completamente um determinado objeto gráfico. <defs> <pattern id="tile" x="0" y="0" width="20%" height="20%" patternUnits="objectBoundingBox"> <path d="M 0 0 Q 5 20 10 10 T 20 20" style="stroke: black; fill: none;"/> <path d="M 0 0 h 20 v 20 h -20 z" style="stroke: gray; fill: none;"/>
Na Figura, o retângulo mais à esquerda, que é de 100 unidades do usuário de largura e e altura, oferece um ajuste exato para cinco peças que são, cada uma, 20 unidades do usuário de largura e altura. No retângulo do meio, a largura e altura não são grandes o suficiente para mostrar, em qualquer peça, o padrão completamente, então eles são truncados. No retângulo mais à direita, o espaço extra é adicionado desde a largura do retângulo e altura superior a cinco vezes o espaço necessário para um único ladrilho. Em todos os casos, uma vez definida as coordenadas X e Y, o canto superior esquerdo do bloco coincide com o canto superior esquerdo da retângulo.
Se você está acostumado à maioria dos programas gráficos, este comportamento é um pouco chocante. Programas de edição de gráficos típicos colocam ladrilhos diretamente um ao lado do outro para preencher a área, não importa o seu tamanho. Se este é o comportamento que você quer, você deve definir as "patternUnits" com o atributo "SpaceOnUse", e especificar as coordenadas X e Y, e a largura e altura do azulejo em unidades do usuário. <defs> <pattern id="tile" x="0" y="0" width="20" height="20" patternUnits="SpaceOnUse"> <path d="M 0 0 Q 5 20 10 10 T 20 20" style="stroke: black; fill: none;"/> <path d="M 0 0 h 20 v 20 h -20 z" style="stroke: gray; fill: none;"/>
Na figura abaixo, as telhas têm tamanho constante em todos os três retângulos. Seu alinhamento é, no entanto, dependente do sistema de coordenadas subjacente. O retângulo médio, por exemplo, tem uma coordenada x, que não é um múltiplo de vinte, de modo que o canto superior esquerdo do retângulo não coincide com o canto superior esquerdo do ladrilho. (As extremidades superiores estão alinhadas, porque a coordenada superior Y de todos os três retângulos são cuidadosamente escolhidas para ser um múltiplo de vinte.)
Se você não especificar um valor para "patternUnits", o padrão é "objectBoundingBox". 7.1.2 Unidades padrão de conteúdo Você deve decidir, a seguir, quais as unidades devem ser usadas para expressar os dados do padrão propriamente ditos. Por padrão, os "patternContentUnits" são definidos com o atributo "SpaceOnUse". Se você definir o atributo para "objectBoundingBox", o caminho dos pontos de dados é expresso em termos do objeto a ser preenchido. Se você usar o "objectBoundingBox" para seus "patternContentUnits", você deve tirar quaisquer objetos a serem preenchidos com o canto superior esquerdo de suas caixas delimitadoras na origem (0, 0). Além disso, você terá que reduzir o derrame de largura dos dados do padrão para 0,01, uma vez que estas unidades são percentagens, e não unidades do usuário. <defs> <pattern id="tile" patternUnits="objectBoundingBox" patternContentUnits="objectBoundingBox" x="0" y="0" width=".2" height=".2"> <path d="M 0 0 Q .05 .20 .10 .10 T .20 .20" style="stroke: black; fill: none; stroke-width: 0.01;"/> <path d="M 0 0 h 0.2 v 0.2 h-0.2z" style="stroke: black; fill: none; stroke-width: 0.01;"/>
Se você quiser reduzir um objeto gráfico existente para uso como um ladrilho, é mais fácil usar o atributo "ViewBox" e escalá-lo. Especificando "ViewBox", irá substituir qualquer informação de "patternContentUnits". Outra opção possível é usar o atributo "preserveAspectRatio", conforme descrito no Capítulo 2, na Seção 2.4. <defs> <pattern id="tile" patternUnits="SpaceOnUse" x="0" y="0" width="20" height="20" viewBox="0 0 150 150"> <path d="M30 100 C 50 50, 70 20, 100 100, 110, 130, 45, 150, 65, 100" style="stroke: black; stroke-width: 5; fill: none;"/>
7.1.3 Padrões aninhados Novamente, isso pode ter ocorrido com você: "Se um objeto pode ser preenchido com um padrão, então um padrão pode ser preenchido com um padrão? "A resposta é sim. Ao contrário de marcadores aninhados, que raramente são necessários, existem alguns efeitos que você não pode alcançar facilmente sem padrões aninhados. O exemplo abaixo cria um retângulo preenchido com círculos, todos cheios de listras horizontais. Isso produz o efeito incomum, mas válido, de bolinhas, mostrado na figura. <defs> <pattern id="stripe" patternUnits="SpaceOnUse" x="0" y="0" width="6" height="6"> <path d="M 0 0 6 0" style="stroke: black; fill: none;"/> <pattern id="polkadot" patternUnits="SpaceOnUse" x="0" y="0" width="36" height="36">
7.2 Os gradientes Em vez de preencher um objeto com uma cor sólida, você pode preenchê-lo com um gradiente, uma transição suave de uma cor para outra. Gradientes podem ser: linear, onde a transição de cor ocorre ao longo de uma linha reta, ou radial, onde a transição ocorre ao longo de uma trajetória circular. <defs>
<stop offset="0%" style="stop-color: #ffcc00;"/> <stop offset="100%" style="stop-color: #0099cc;"/>
7.2.1.1 O elemento de paragem Vamos examinar o elemento <stop> mais de perto. Ele tem dois atributos necessários; o "offset" diz o ponto ao longo da linha na qual a cor deve ser igual ao "stop-color". O deslocamento é expresso como uma porcentagem de 0 a 100% ou como um decimal no valor de 0 a 1,0. <defs>
<stop offset="0%" style="stop-color: #ffcc00;"/> <stop offset="33.3%" style="stop-color: #cc6699"/> <stop offset="100%" style="stop-color: #66cc99;"/>
7.2.1.2 Estabelecer uma linha de transição para um gradiente linear O comportamento padrão de um gradiente linear é fazer a transição ao longo de uma linha horizontal a partir do lado esquerdo de um objeto para o lado direito. Se você quer a transição de cores para ocorrer através de uma linha vertical ou uma linha em um ângulo, você deve especificar o ponto inicial com os atributos X1 e Y1 e seus pontos terminais com os atributos X2 e Y2. Por padrão, estes são também expressos como porcentagens de 0% a 100% ou decimais de 0 a 1. No Exemplo abaixo, vamos usar os mesmos limites de cor em um gradiente horizontal, vertical e diagonal. Ao invés de duplicar os "stops" em cada elemento
, usaremos o atributo "xlink: href" para se referir ao gradiente inicial da esquerda para a direita. As paradas serão herdadas, mas as coordenadas X e Y serão anuladas por cada gradiente individual. <defs>
<stop offset="0%" style="stop-color: #ffcc00;"/> <stop offset="33.3%" style="stop-color: #cc6699"/> <stop offset="100%" style="stop-color: #66cc99;"/>
Se você deseja estabelecer a linha de transição usando as unidades de usuário, em vez de porcentagens, defina as "gradientUnits" para "SpaceOnUse" em vez do valor padrão, que é "objectBoundingBox". 7.2.1.3 O atributo "spreethod" A linha de transição não tem que ir de um canto a outro do objeto. O que acontece se for dito que a linha de transição vai de (20%, 30%) de (40%, 80%)? O que acontece com a parte do objeto de fora da linha? Você pode definir o "spreethod" e atribuir a um dos seguintes valores: "pad" - O início e término de "stop-color" será estendido para as bordas do objeto. "repeat" - O gradiente será repetido do início ao fim, até atingir as extremidades do objeto. "reflect" - O gradiente será refletido do fim para o início, do início para o fim até atingir as bordas do objeto. <defs>
<stop offset="0%" style="stop-color: #ffcc00;"/> <stop offset="33.3%" style="stop-color: #cc6699"/> <stop offset="100%" style="stop-color: #66cc99;"/>
<use xlink:href="#show-line" transform="translate (20,20)"/>
<use xlink:href="#show-line" transform="translate (130,20)"/>
<use xlink:href="#show-line" transform="translate (240,20)"/>
7.2.2 gradiente radial O outro tipo de gradiente que você pode usar é o gradiente radial, onde a transição de cor ocorre ao longo de um percurso circular. É configurado, em muito, da mesma maneira que um gradiente linear. <defs>
<stop offset="0%" style="stop-color: #f96;"/> <stop offset="50%" style="stop-color: #9c9;"/> <stop offset="100%" style="stop-color: #906;"/>
7.2.2.1 Estabelecendo limites de transição para um gradiente radial Em vez de usar uma linha para determinar onde os pontos de paragem de 0% e 100% devem ser, os limites de um gradiente radial são determinados por um círculo; o centro é o ponto de parada 0%, e a circunferência externa define o ponto de paragem 100%. Você define o círculo externo com os atributos cx (Centro x), cy (centro y) e r(raio). Todos estes são, em termos de porcentagens do "objectBoundingBox". Os valores padrão para todos esses atributos é de 50%. <defs>
<stop offset="0%" style="stop-color: #f96;"/> <stop offset="50%" style="stop-color: #9c9;"/> <stop offset="100%" style="stop-color: #906;"/>
O ponto de parada 0%, também chamado de ponto focal, é, por padrão, colocado no centro do círculo que define o ponto de paragem 100%. Se você deseja ter o ponto de parada 0% em algum ponto diferente do centro do círculo limite, você deve alterar os atributos "fx" e "fy". O ponto focal deve estar dentro do círculo estabelecido para o ponto de paragem 100%. Se não for, o programa visualizador SVG irá mover automaticamente o ponto focal para o exterior da circunferência do círculo final. <defs>
<stop offset="0%" style="stop-color: #f96;"/> <stop offset="50%" style="stop-color: #9c9;"/> <stop offset="100%" style="stop-color: #906;"/>
Os valores padrão para os atributos de definição de limite de um
são as seguintes: Atributo
Valor Padrão
cx
50% (centro horizontal da caixa delimitadora do objeto)
cy
50% (centro vertical da caixa delimitadora do objeto)
r
50% (metade da largura / altura da caixa delimitadora do objeto)
fx
O mesmo que cx
fy
O mesmo que cy
Se você deseja estabelecer os limites do círculo usando coordenadas de espaço do usuário, em vez de porcentagens, defina as "gradientUnits" para "SpaceOnUse" em vez do valor padrão, que é "objectBoundingBox".
7.2.2.2 O atributo spreethod para gradientes radiais No caso em que os limites que você descreveu não chegam às bordas do objeto, você pode definir o atributo "spreethod" a um dos valores "pad", "repeat", ou "reflect" como descrito anteriormente na Seção 7.2.1.3 para preencher o espaço restante como você deseja. <defs>
<stop offset="0%" style="stop-color: #f96;"/> <stop offset="50%" style="stop-color: #9c9;"/> <stop offset="100%" style="stop-color: #906;"/>
7.3 Transformando gradientes e Padrões Às vezes você pode querer inclinar, esticar, ou rodar um padrão ou gradiente. Você não transforma o objeto que está sendo preenchido; você transforma o padrão ou o espectro de cores utilizado para preencher o objeto. Os atributos "gradientTransform" e "patternTransform" permitem fazer isso. <defs>
<stop offset="0%" style="stop-color: #ffcc00;"/> <stop offset="33.3%" style="stop-color: #cc6699"/> <stop offset="100%" style="stop-color: #66cc99;"/>
<pattern id="tile" x="0" y="0" width="20%" height="20%" patternUnits="objectBoundingBox"> <path d="M 0 0 Q 5 20 10 10 T 20 20" style="stroke: black; fill: none;"/> <path d="M 0 0 h 20 v 20 h -20 z" style="stroke: gray; fill: none;"/> <pattern id="skewed-tile" patternTransform="skewY(15)" xlink:href="#tile"/>
Uma nota final sobre gradientes e padrões - embora tenham sido aplicados apenas em uma área de uma forma preenchida, você também pode aplicá-los em bordas (stroke). Isso permite que você produza um esboço colorido ou com múltiplas estampas para um objeto. Normalmente você vai definir a largura da borda com um número maior do que um, para que o efeito seja mais claramente visível.
Capítulo 8. Texto Embora possa ser verdade que cada imagem conta uma história, é melhor ainda usar as palavras para ajudar a contar a história. Assim, SVG tem vários elementos que permitem adicionar texto para seus gráficos. 8.1 Terminologia Antes de investigar o principal método de adicionar o texto, o elemento
, devemos definir alguns termos que você verá se ler a especificação SVG ou se trabalhar com texto em qualquer ambiente gráfico: Caractere Um caractere, em termos de XML, é um byte ou bytes com um valor numérico de acordo com o padrão Unicode. Por exemplo, o que chamamos de letra "g" é o caractere com o valor Unicode 103. Glyph Um glifo é a representação visível de um caractere ou caracteres. Um único caractere pode ter muitos glifos diferentes para representá-lo. A figura abaixo mostra a palavra "glyphs" escrito com dois conjuntos diferentes de glifos - uma especial atenção à inicial "g" - é o mesmo caractere, mas os glifos são marcadamente diferentes.
Vários caracteres podem reduzir-se a um único glifo; algumas fontes têm glifos separados para as combinações de letras "fl" e "ff" para fazer o seu espaçamento parecer melhor (estes são chamados ligaduras). Outras vezes, um único caractere pode ser composto por múltiplos glifos; um programa de impressão pode criar o caractere "E" (que tem valor Unicode 233), combinando o glifo "e" com uma marca de acento sem espaçamento "´". A linha tracejada, na parte superior da figura é utilizada para determinar a "cap-height", que é a altura de uma letra maiúscula acima da linha de base. A linha inferior pontilhada é usada para determinar a saída da altura, que, logicamente, é a distância entre a linha de base para o topo de uma letra minúscula "x".
8.2 Atributos simples e propriedades do elemento de texto A forma mais simples do elemento
requer apenas dois atributos, X e Y, que definem o ponto em que a linha de base do primeiro caractere do conteúdo do elemento é colocado. O estilo padrão para o texto, como acontece com todos os objetos, é ter uma cor de preenchimento de
preto e sem contorno. Isto, como se vê, é precisamente o que você quer para o texto. Se você definir o contorno, bem como o preenchimento, o texto parece desconfortável de espessura. Se você definir apenas o contorno, você pode obter um conjunto agradável de glifos descritos, especialmente se você diminuir a largura do traçado. <path d="M 20 10, 20 120 M 10 30 100 30 M 10 70 100 70 M 10 110 100 110" style="stroke: gray;"/>
Simplest Text
Outlined/filled
Outlined only
Muitas das outras propriedades que se aplicam ao texto são as mesmas em que eles estão no CSS padrão . A seguir está uma lista das propriedades CSS e valores que são implementados no Apache Batik visualizador versão 1.0: font-family - O valor é uma lista separada por espaços de nomes de famílias de fontes ou nomes de família genéricos. Os nomes de família genéricos são "serif", "sans-serif", e "monospace". Fontes Serif têm pequenos "ganchos" nas extremidades dos cursos; fontes sans-serif não. Na figura abaixo, a palavra à esquerda está em uma fonte serif e a palavra à direita está em uma fonte sans-serif. Ambas as fontes com serifa e sem serifa são proporcionais; a largura de um M maiúsculo não é a mesma largura de um I maiúsculo. Uma fonte de espaçamento fixo, que pode ou não pode ter serifas, é aquela em que todos os "glifos" têm a mesma largura, como as letras de uma máquina de escrever. font-size - O valor é a distância da linha de base-a-base dos glifos se tiver mais de uma linha de texto. Em SVG, você não pode ter conteúdo
multi-linha, de modo que o conceito é um pouco abstrato.) Se você usar unidades nesse atributo, como em style = "font-size: 18pt", o tamanho de dezoito pontos será convertido para unidade de usuário antes de serem renderizados, para que ele possa ser afetado por transformações. font-weight - Os dois valores mais comumente usados desta propriedade são "negrito"(bold) e "normal" (normal). Você precisa do valor "normal" apenas no caso de você querer colocar um texto "não negrito" em um grupo cujo estilo foi definido para = "font-weight: bold". font-style - Os dois valores mais comumente usados dessa propriedade são "itálico" (italic) e "normal" (Normal). text-decoration - Os valores possíveis dessa propriedade são "nenhum" (none), "sublinhado" (underline), "overline" e "line-through". word-spacing - O valor desta propriedade é uma extensão, quer em unidades explícitas, como "pt" ou
em unidades do usuário. Um número positivo aumenta o espaço entre as palavras, configurá-lo para "normal" mantém o espaço normal, e torná-lo negativo diminui o espaço entre palavras. O comprimento especificado é adicionado ao espaçamento normal. letter-spacing - O valor desta propriedade é uma extensão, quer em unidades explícitas, como "pt" ou em unidades do usuário. Um número positivo aumenta o espaço entre as letras individuais, configurá-lo para"normal" para manter o espaço normal, e torná-lo negativo diminui o espaço entre as letras. O comprimento especificado é adicionado ao espaçamento normal.
bold
italic
under
over
through
more word space
less word space
wide letter space
narrow letter space
8.3 Alinhamento de Texto O elemento
permite especificar o ponto de partida, mas você não sabe, a priori, o seu ponto final. Isso tornaria mais difícil o alinhamento do texto para o centro ou direita, se não fosse a propriedade "text-anchor". Você pode configurá-la para um valor de começo, meio ou fim. Para fontes que são desenhadas da esquerda para a direita, estes são equivalentes aos alinhamentos à esquerda, centro, e à direita. Para fontes que são desenhadas em outras direções (ver Seção 8.7) estes têm um efeito diferente.
<path d="M 100 10 100 100" style="stroke: gray; fill: none;"/>
Start
Middle
End
8.4 O elemento
Outra consequência de não saber comprimento do texto com antecedência, é que é difícil construir uma cadeia com diferentes atributos de texto, como esta frase, que alterna entre texto em itálico, normal, e em negrito. Se você tivesse apenas o elemento
, você precisa experimentar para descobrir onde cada segmento de estilo diferente do texto terminou, a fim de espaçá-los adequadamente. Para resolver este problema, o SVG fornece a
ou elemento "span-texto". Análogo ao XHTML elemento <span>,
é uma tábula rasa que pode ser embutida no conteúdo de texto, e sobre a qual você pode impor mudanças de estilo. O
memoriza a posição de texto, para que você não precise memorizá-la.
Switch among
italic
, normal, and
bold
text.
Além de alterar as propriedades de apresentação como tamanho de fonte, cor, peso, etc., você também pode usar atributos com
para alterar o posicionamento das letras ou conjuntos individuais de letras. Se, por exemplo, você quer sobrescritos ou subscritos, você pode usar o atributo "dy" para compensar caracteres dentro de um intervalo. O valor que você atribui a este atributo é adicionado para a posição vertical dos caracteres, e continua a afetar texto mesmo fora do vão. Os valores negativos são permitidos. Um atributo semelhante, "dx", compensa caracteres na horizontal.
F
a
l
l
Se você deseja expressar os deslocamentos em termos absolutos, em vez de termos relativos, use os atributos x e y. Isso é útil para fazer corridas com várias linhas de texto. Na verdade, você deve fazê-lo desta forma, uma vez que, como você verá na Seção 8.9, o SVG não exibe caracteres de nova linha em texto. (A falta de uma nova linha será remediado em SVG 1.1.). Se o seu visualizador de SVG permite seleção de texto, colocando várias linhas em um único elemento
, permitirá a seleção para incluir todas as linhas. Você deve sempre usar
dentro de um elemento
para relacionar linhas de um mesmo grupo, não só para permitir que elas sejam selecionadas como uma unidade, mas também porque acrescentam estrutura para o seu documento.
They dined on mince, and slices of quince,
Which they ate with a runcible spoon;
And hand in hand, on the edge of the sand,
They danced by the light of the moon.
Você também pode girar uma letra ou série de letras dentro de um <span> usando o atributo "rotação", cujo valor é um ângulo em graus. Se você tem que modificar as posições de vários caracteres, você pode fazê-lo facilmente especificando uma série de números para qualquer um dos x, y, dx, dy, e rodar os atributos. Os números que você especificou serão aplicados, um após o outro, com os caracteres dentro do
.
Shaken
Embora a figura não mostre, os efeitos de dx e dy persistem após o
terminar. Se mais texto fosse colocado após o fechamento do , seria nos mesmos deslocamentos que a letra "n". Ele não iria voltar à linha de base estabelecida pela primeira letra: "S".
Se você tiver elementos
aninhados, os x, y, dx, dy, e valores de atributos girados não são herdadas pelos elementos internos. Embora você possa usar o atributo dy para produzir sobrescrito e subscrito, é mais fácil usar o estilo "baseline-shift", como fizemos no próximo exemplo. Esta propriedade do estilo tem valores de "super" e "sub". Você também pode especificar um comprimento, como 0.5em, ou uma porcentagem, a qual é calculada em relação ao tamanho da fonte. Efeitos de deslocamento de linha de base restringem-se ao período em que ocorrem.
C
12
H
22
O
11
(acúcar)
6.02 x 10
23
(Número de Avogrado)
8.5 Definir textLength Embora disséssemos que não há uma maneira priori para determinar o ponto final de um segmento de texto, você pode especificar explicitamente o comprimento do texto como o valor do atributo "textLength". O SVG, então, ajusta o texto para o espaço dado. Ele ajustará o espaço entre glifos, deixando os glifos intocados, ou ele pode ajustar tanto o espaçamento como o tamanho glifo. Se você quer ajustar um único espaço, defina o valor do "lengthAdjust" para "spacing" (este é o padrão). Se você
quiser que o SVG ajuste as palavras para caber em um determinado comprimento, ajustando tanto o tamanho do espaçamento quanto do glifo, defina "lengthAdjust" para "spacingAndGlyphs".
<path d="M 20 10 20 70 M 220 10 220 70" style="stroke: gray;"/>
Two words
Two words
Two words
(normal length)
<path d="M 20 100 20 170 M 100 100 100 170" style="stroke: gray;"/>
Two words
Two words
8.6 Texto Vertical Quando você usa SVG para criar gráficos ou tabelas, muitas vezes você vai querer rótulos escritos em eixos verticais. Uma maneira de conseguir texto orientado verticalmente é a utilização de uma transformação para rodar o texto 90 graus. Outra forma de conseguir o mesmo efeito é alterando o valor da propriedade de estilo "writing-mode" para o valor "tb" (ou seja, "top/bottom", de cima para baixo). Às vezes, porém, você quer que as letras apareçam em uma coluna vertical sem rotação. O exemplo abaixo faz isso definindo a propriedade "glyph-orientation-vertical" com um valor de zero. (Seu valor padrão é 90, que é o que gira o texto 90 graus de cima para baixo.). Esta definição tende a exibir o espaçamento entre letras como anormalmente grande. A definição de um pequeno valor negativo para "letter-spacing" resolve este problema.
Rotated 90
Writing Mode tb
Vertical zero
8.7 Internacionalização e texto 8.7.1 Unicode e Bidirecionalidade XML é baseado no padrão Unicode (devidamente documentados no website do Consórcio Unicode, http://www.unicode.org). Isso permite exibição de texto em qualquer idioma que o software de visualização subjacente possa exibir. Alguns idiomas como árabe e hebraico são escritos da direita para a esquerda, de modo que quando o texto nestas línguas são misturados com texto escrito da esquerda para a direita, como o Inglês, o texto é bidirecional, ou bidi. O software do sistema sabe quais caracteres vão em qual direção e trabalha as suas posições em conformidade. O exemplo abaixo substitui a implícita direcionalidade de um segmento de texto, definindo sua propriedade de estilo "direction" como "RTL", que significa (right to left) da direita para a esquerda. Se você deseja mudar a direção do hebraico ou texto em árabe, defina a "direction" como LTR, que é (left to right)da esquerda para a direita. Você também deve substituir explicitamente o algoritmo de bidireccionalidade, definindo o estilo de propriedade "unicode-bidi" para "bidi-override".
Greek:
αβγδε
Russian:
абвгд
Hebrew:
אבגדה (written right to left)
Arabic:
ابةت (written right to left)
This is
right-toleft
text.
8.7.2 O Elemento interruptor A capacidade de exibir vários idiomas em um único documento é útil para coisas como um folheto para um evento que recebe visitantes internacionais. Às vezes, porém, você gostaria de criar um documento com conteúdo em dois idiomas, digamos, espanhol e Russo. As pessoas que vissem o documento com software no sistema espanhol veriam o texto em espanhol, e os russos veriam o texto em russo. O SVG oferece esse recurso com o elemento <switch>. Este elemento procura através de todos os seus filhos até encontrar uma cujo atributo "systemLanguage" tem um valor que corresponda ao idioma que o usuário tenha escolhido nas preferências do software de visualização. O valor de "systemLanguage" é um valor único ou uma lista separada por vírgulas de nomes de idiomas. Um nome de idioma é ou um código de duas letras do idioma, como "ru" para Russo, ou uma linguagem de código seguido de um código de país, que especifica uma sublinguagem. Por exemplo, frCA denota franco-canadense, enquanto fr-CH denota franco-suíço.
Uma vez que um elemento filho correspondente for encontrado, todos os seus filhos serão exibidos. Todos os outros filhos do <switch> serão ignorados. O próximo exemplo mostra o texto em inglês britânico, inglês americano, espanhol e russo. Uma vez que um jogo de código de linguagem por si só é considerado um jogo, e códigos de países, são usados apenas para "quebrar um empate", o texto para o inglês britânico deve vir primeiro.
<switch>
A circle
without colour.
A circle
without color.
Un círculo
sin color.
Круг
без света.
8.7.3 Usando uma fonte personalizada Às vezes você precisa de símbolos especiais que não são representados no Unicode, ou você quer um subconjunto de caracteres Unicode sem ter que instalar uma fonte inteira. Um exemplo é a figura abaixo, que precisa apenas de algumas das mais de 2.000 sílabas coreanas. Você pode criar uma fonte personalizada, conforme descrito no Apêndice E e dar a sua partida
marcando uma identificação única. Aqui está a parte relevante de um arquivo que contém seis das sílabas coreanas exportadas da fonte TrueType Batang. O arquivo é chamado kfont.svg:
<missing-glyph horiz-adv-x="500" />
Uma vez feito isto, você pode fazer referência a uma fonte em um arquivo externo. Por uma questão de coerência, o valor do "font-family" que você usar neste arquivo SVG deve corresponder ao valor no arquivo externo. <defs>
서울 대한민국
8.8 texto em um caminho O texto não tem que ir em uma linha horizontal ou vertical em linha reta. Pode seguir qualquer caminho arbitrário; simplesmente coloque o texto em um elemento
que usa um atributo "xlink: href" para se referir a um elemento <path> anteriormente definido. Os caracteres serão girados para ficarem "Perpendicular" a curva (isto é, a linha de base das letras será tangente à curva). Texto ao longo de um caminho suavemente curvo e contínuo é mais fácil de ler do que o texto que segue um caminho acentuadamente inclinado ou descontínuo. O caminho referenciado no elemento
não será exibido. É por isso que os caminhos são desenhados com o elemento <use>. <defs> <path id="curvepath" d="M30 40 C 50 10, 70 10, 120 40 S 150 0, 200 40" style="stroke: gray; fill: none;"/> <path id="round-corner" d="M250 30 L 300 30 A 30 30 0 0 1 330 60 L 330 110" style="stroke: gray; fill: none;"/> <path id="sharp-corner" d="M 30 110 100 110 100 160" style="stroke: gray; fill: none;"/> <path id="discontinuous" d="M 150 110 A 40 30 0 1 0 230 110 M 250 110 270 140" style="stroke: gray; fill: none;"/> <use xlink:href="#curvepath"/>
Following a cubic Bézier curve.
<use xlink:href="#round-corner"/>
Going 'round the bend
<use xlink:href="#sharp-corner"/>
Making a quick turn
<use xlink:href="#discontinuous"/>
Text along a broken path
Você pode ajustar o ponto de início do texto ao longo de seu caminho, definindo para o atributo "startOffset" uma porcentagem ou um comprimento. Por exemplo, startOffset = "25%" irá iniciar o texto a um quarto da distância do caminho, e startOffset = "30" vai começar o texto a uma distância de trinta unidades de utilizador a partir do início do caminho. Se você deseja centralizar o texto em um caminho, defina o "text-anchor" como "middle" no elemento
e "startOffset" como "50%" no elemento
. O texto que cai para além das extremidades do caminho não será exibido. <defs> <path id="short-corner" transform="translate(40,40)" d="M0 0 L 30 0 A 30 30 0 0 1 60 30 L 60 60" style="stroke: gray; fill: none;"/> <path id="long-corner" transform="translate(140,40)" d="M0 0 L 50 0 A 30 30 0 0 1 80 30 L 80 80" style="stroke: gray; fill: none;"/> <use xlink:href="#short-corner"/>
This text is too long for the path.
<use xlink:href="#long-corner"/>
centered
8.9 Espaços em branco e texto Você pode mudar a maneira que o SVG lida com espaços em branco (espaços em branco, tabulações, e de nova linha, são caracteres) dentro do texto, alterando o valor do atributo "xml: space". Se você especificar um valor "default" (que, coincidentemente, é o valor padrão), o SVG irá lidar com os espaços em branco como se segue: • Remove todos os caracteres de nova linha • Altera todas as guias para espaços em branco • Remove todos os espaços em branco à esquerda e à direita • Altera qualquer execução de espaços em branco intermediários a um único espaço em branco. Assim, esta cadeia, onde "\t" representa uma guia e "\n" representa uma nova linha, e um sublinhado representa um "blank", este texto: \n\n___abc_\t\t_def_\n\n__ghi
Será renderizado como: abc_def_ghi
A outra configuração de "xml: space" é "preserve". Com esta definição, o SVG vai simplesmente converter todos as novas linhas e caracteres de tabulação para espaços em branco, e, em seguida, exibir o resultado, incluindo o líder e espaços em branco. O mesmo texto: \n\n___abc_\t\t_def_\n\n__ghi
Será renderizado como:
_____abc____def_____ghi
A manipulação SVG de espaços em branco não é como o de HTML. O tratamento padrão SVG elimina todas as novas linhas; O HTML muda novas linhas internas para espaço. O método "preserve" do SVG converte novas linhas em espaços em branco; No elemento HTML <pre> não há nenhuma nova linha em SVG 1,0; isso incomoda as pessoas até que elas percebam que o texto SVG é orientado para a exibição gráfica, e não para o conteúdo textual (como no XHTML). 8.10 Estudo de Caso - Adicionando texto a um gráfico A figura abaixo acrescenta texto coreano e inglês para o símbolo nacional da Coréia. O texto é centrado ao longo de uma trajetória elíptica. A SVG adicional é mostrada em negrito. <defs>
<path id="upper-curve" d="M -8 154 A 162 130 0 1 1 316 154" /> <path id="lower-curve" d="M -21 154 A 175 140 0 1 0 329 154" /> <ellipse cx="154" cy="154" rx="150" ry="120" style="fill: #999999;"/> <ellipse cx="152" cy="152" rx="150" ry="120" style="fill: #cceeff;"/> <path d="M 302 152 A 150 120, 0, 1, 0, 2 152 A 75 60, 0, 1, 0, 152 152" style="fill: #ffcccc;"/> <path d="M 152 152 A 75 60, 0, 1, 1, 302 152" style="fill: #cceeff;"/>
서울 대한민국
Seoul - Republic of Korea