Векторная графика SVG в Swing

Масштабируемая векторная графика SVG (Scalable Vector Graphics) представляет собой описание графического объекта в XML формате. SVG поддерживает как статическую, так и анимированную интерактивную графику. Но SVG не поддерживает описание трёхмерных объектов, к которой не относится имитация трёхмерности путём светотени.

До 2001 года (даты создания SVG) были доступны несколько форматов векторной графики - это Postscript и его родственник PDF, широко используемые во многих приложениях. Множество форматов, специфичных для конкретных приложений, включает Postscript-based Adobe Illustrator (.ai), CorelDRAW (.cdr), Computer Grapher Metafile (.cgm), Windows Metafile (.wmf), Autocad (.dxf), Hewlett-Packard Graphics Language (.hpgl), WordPerfect (.wpg), и множество других. Общепринятым средством векторного изображения, распространяемого через интернет, является Macromedia's SWF/Flash.

Основное отличие SVG от всех этих форматов связано с тем, что SVG явялется частным случаем XML. Это означает что SVG намного универсальнее, чем остальные графические форматы как с точки зрения описания, так и с точки зрения программного управления графикой. В частности, можно управлять SVG при помощи интернет-браузеров (или других приложений), используя ECMAScript и Document Object Model (DOM). Кроме этого важно, что можно преобразовывать и создавать SVG с помощью привычных XML-технологий или с помощью библиотек, поддерживающих работу с XML. Можно комбинировать SVG с другими форматами XML, используя пространства имен. Более того, можно также стилизовать SVG с помощью Cascading Style Sheets (CSS).

Поскольку SVG является XML форматом, то он относится к открытым стандартам и свободен от действия любых патентов и ограничений охраны авторского права. Спецификация SVG полностью документирована.

Примечание :
1. Описание достоинств и недостатков, а также сложности использования векторной графики SVG не являются предметом данного сайта. Об этом достаточно информации можно найти на просторах Internet'a.
2. На данной странице сайта будет приведено краткое описание SVG формата и рассмотрен пример просмотра графических векторных изображений в Swing-приложении, интерфейс которого представлен на следующем скриншоте.

Структура SVG графика

Ниже представлен код общего описания векторной графики SVG. Первая строка — это стандартный XML-заголовок, включающий версию XML (version, обычно «1.0») и кодировку символов (encoding). Во второй и третьей строках располагается заголовок DOCTYPE, определяющий тип документа DTD (Document Type Definitions). К сожалению, некоторые браузеры со встроенным просмотрщиком SVG могут воспринимать содержание тега DOCTYPE как ошибку. Имеются рекомендации не использовать декларацию DOCTYPE в SVG версий 1.0. Вместо этого рекомендовано включать атрибут baseProfile в корневой теге <svg> со значением "full".

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="80%" height="80%">
    . . .
</svg>

Тег <svg> с атрибутами определяет векторную графику SVG. Наибольший интерес представляют следующие атрибуты :

  • width и height, определяющие размеры графического изображения в пикселях (px; может не использоваться) или процентах (%);
  • viewBox задаёт координаты и размеры «окна видения»; используется для позиционирования изображения в области рендеринга (может игнорироваться некоторыми программами просмотра).

Описание векторного графика SVG располагается между тегами <svg> ... </svg>.

Описание тегов SVG

В следующей таблице представлены «жизненно» важные и наиболее часто используемые теги определения SVG графика.

<svg>заголовок векторного SVG
<defs>определения; секция хранит описания градиентов и объектов, которые не нужно выводить непосредственно
<g>группа; контейнер для изображаемых элементов (на него можно сослаться при необходимости)
<path>векторная фигура; набор правил для отображения рисунка ("перейти в заданную точку", "нарисовать отрезок из текущей позиции в заданную точку"). Поддерживаются прямые отрезки, кривые Безье 2-го и 3-го порядка, а также дуги окружности
<text>однострочный текст; SVG нет имеет полноценной поддержки многострочных текстов
<linearGradient>линейный градиент
<radialGradient>радиальный градиент
<clipPath>область отсечения; определение фигуры, которая может использоваться для отсечения при выводе
<pattern>узор для заливки замкнутых областей
<mask>маска; объект, alpha-значения пикселей которого можно использовать при выводе произвольного изображения
<filter>фильтр; один из предопределённых способов пост-обработки графического элемента (например, его размытие)
<use>использование графических объектов, определенных в секции <defs>
<image>растровая картинка
<animate>секция описания анимационного изображения

Определение стилей CSS в SVG

Чтобы модифицировать вид графиков SVG следует использовать стили CSS, которые можно определить по ссылке на внешнюю таблицу стилей или внутри документа.

Ссылка на внешний файл стилей test.css

Перед основным тегом определения векторного SVG графика можно определить ссылку (href) на файл со стилями, как это представлено в следующем коде (файл стилей test.css). Внешний файл стилей следует использовать в тех случаях, если в интерфейсе приложения (на сайте) в разных местах используются различные векторные SVG графики.

<?xml-stylesheet type="text/css" href="tests/resources/style/test.css" ?>
<svg>
    ... 
</svg>

Определение стилей внутри SVG документа

Стиль CSS векторного графика SVG можно определить в секции описания SVG графика.

<svg>
   <style type="text/css" >
      <![CDATA[
         title {
            font-family: Arial, Helvetica; 
            font-size: 16;
            text-anchor: middle;
         }
         legend {
            font-family: Arial, Helvetica; 
            font-size: 10;
            text-anchor: middle;
         }
      ]]>
    </style>
    ... 
</svg>

Простым изменением атрибутов стилей, можно изменять общий вид SVG диаграммы, чтобы сделать ее более привлекательной в различных ситуациях.

Определение векторных SVG фигур

Для определения векторных фигур в SVG используются теги <path>, <polygon>, <circle> и <rect>. В следующем примере в секции defs приводится описание параметров звезды - цвет заполнения (fill), цвет обрамления (stroke) и полигон в виде набора точек.

<svg xmlns="http://www.w3.org/2000/svg" 
     xmlns:xlink="http://www.w3.org/1999/xlink"
     width="500" height="300">
    <defs>
        <g id="star" fill="cyan" stroke="black">
            <polygon points="47.773,241.534 123.868,8.466 200.427,\
                              241.534 7.784,98.208 242.216,98.208" />
        </g>
    </defs>

    <use x="0" y="0" xlink:href="#star" fill-rule="nonzero" />
    <use x="250" y="0" xlink:href="#star" fill-rule="evenodd" />
</svg>

В тегах use определяются координаты местоположения звёзд, приводится ссылка на объект (xlink:href="#star") и устанавливается порядок закраски объекта. Формат SVG поддерживает два различных метода определения замкнутой внутренней области для закрашивания :

  • fill-rule="nonzero"; — из точки внутри области выпускается луч и отдельно считается количество его пересечений с линиями идущими по часовой стрелке и против часовой стрелки; область закрашивается, если полученные числа не совпадают;
  • fill-rule="evenodd" — из точки внутри области выпускается луч и считается количество пересечений с линиями, задающими границу; область закрашивается, если количество пересечений нечётно.

SVG изображение двух звезд представлено на следующем скриншоте.

SVG анимация с использованием ECMAScript скриптов

Формат SVG позволяет использовать скрипты (ECMAScript). Следующий анимационный SVG рисунок использует ECMAScript скрипт для постепенного увеличения надписи. Сначала небольшой блеклый красный текст надписи появляется в левом нижнем углу. За несколько секунд текст увеличивается до максимально возможных значений (допускаемых разрешением экрана) с изменением яркости и перемещением в центр экрана.

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="0 0 400 200"
    onload="StartAnimation(evt)" version="1.1">
    <script type="text/ecmascript">
    <![CDATA[
        var txt, step=0;
        function StartAnimation(evt) {
            txt = evt.target.ownerDocument.getElementById("Text");
            ShowAndGrowElement();
        }
        function ShowAndGrowElement() {
          step = step+1;
          if (step > 200) return;
          // Scale text string gradually until it is 20 times larger
          txt.setAttribute("transform", "scale("+ step/10 +")" );
          // Make the string more opaque
          txt.setAttribute("opacity", step/200);
          // Call ShowAndGrowElement again 50 milliseconds later.
          setTimeout("ShowAndGrowElement()", 50)
        }
        window.ShowAndGrowElement = ShowAndGrowElement
     ]]>
  </script>
  <g transform="translate(50,150)" fill="red" font-size="7">
      <text id="Text">SVG</text>
  </g>
</svg>

Возможность использования ECMAScript скриптов позволяет SVG документу взаимодействовать с пользовательским интерфейсом (действиями пользователя). Простое взаимодействие связано с нажатием кнопки мыши. Следующий пример тривиальный, но он позволяет обеспечить отклик SVG графика в виде красного круга. При нажатии кнопкой мыши на красный круг он сначала увеличивает размер, а при следующем нажатии - восстанавливает размер.

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    height = "440px"  width = "440px">
    <title>ECMAScript function for an onclick event</title>
    <script type="text/ecmascript">
        <![CDATA[
            function circle_click(evt) {
                var circle = evt.target;
                var currentRadius = circle.getAttribute("r");
                if (currentRadius == 100)
                    circle.setAttribute("r", currentRadius*2);
                else
                    circle.setAttribute("r", currentRadius*0.5);
            }
        ]]>
    </script>
    <!-- Act on click event -->
    <circle onclick="circle_click(evt)"
                     cx="215" cy="210" r="100" fill="red"/>
</svg>

Примеры SVG графики

Ниже представлены примеры двух статических SVG изображений и одного анимационного.

Прямоугольник с разноцветными кругами

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version = "1.1"
    baseProfile="full"
    xmlns = "http://www.w3.org/2000/svg" 
    xmlns:xlink = "http://www.w3.org/1999/xlink"
    xmlns:ev = "http://www.w3.org/2001/xml-events"
    height = "410px" width = "410px">
    <rect x="5" y="5" width="400" height="400" 
          fill="none" stroke="black" stroke-width="5px" stroke-opacity="0.5"/>
    <g fill-opacity="0.6" stroke="black" stroke-width="0.5px">
        <circle cx="200px" cy="200px" r="104px" fill="red"   transform="translate(  0,-52)" />
        <circle cx="200px" cy="200px" r="104px" fill="blue"  transform="translate( 60, 52)" />
        <circle cx="200px" cy="200px" r="104px" fill="green" transform="translate(-60, 52)" />
    </g>
</svg>

Графическое изображение векторного SVG прямоугольника с кругами.

Прямоугольник с закругленными углами

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1"
     baseProfile="full"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     xmlns:ev="http://www.w3.org/2001/xml-events"
     width="80%" height="80%">
   <rect x="5" y="5" rx="20" ry="20" width="80%" height="80%"
         style="fill:red;stroke:black;stroke-width:5;opacity:0.5" />
</svg>

Графическое изображение векторного SVG прямоугольника с закругленными углами.

Анимационный SVG график из 3-х прямоугольников

<svg width="130" height="300">
    <rect x="5" y="5" width="130" height="300" 
        fill="none" stroke="black" 
        stroke-width="5px" stroke-opacity="0.5"/>
    <rect x="20" y="20" width="90" height="60">
        <animate id="a1" 
                 attributeName="fill"
                 from="red" to="blue"
                 dur="3s" fill="freeze" />
    </rect>
    <rect x="20" y="120" width="90" height="60">
        <animate id="a2"
                 attributeName="fill"
                 from="blue" to="yellow" 
                 begin="a1.end" 
                 dur="3s" fill="freeze" />
    </rect>
    <rect x="20" y="220" width="90" height="60">
        <animate id="a3"
                 attributeName="fill"
                 from="yellow" to="green"
                 begin="a2.end"
                 dur="3s" fill="freeze" />
    </rect>
    Sorry, your browser does not support inline SVG.  
</svg>

Изображение анимационного векторного SVG рисунка. Слева - при старте, справа - после останова анимации.

Примечание :
Не все из рассмотренных на странице SVG примеров удалось увидеть в браузере Google Chrome на странице html. В первую очередь это относится к анимационным графикам, а также к тигру. Следует отметить, что я не сильно усердствовал в этом вопросе, поскольку проверял только возможности браузера отображать SVG график.

Размещение SVG графика на сайте

Для вставки SVG изображения (файла с описанием SVG графика) на страницу сайта можно использовать теги

  • image :
    <img src="stars.svg" />
  • object :
    <object type="image/svg+xml" data="stars.svg" ></object>
  • iframe

Создание SVG диаграммы

Имеются различные редакторы создания векторных графиков. Но это очень слабо связано с рассматриваемыми на сайте вопросами программирования.

Библиотека JFreeChart включает утилиту, позволяющуюю выполнять экспорт динамически созданного графика JFreeChart в векторный SVG график. Ниже представлен пример, не требующий каких-либо пояснений.

import java.io.*;

import org.jfree.chart.*;
import org.jfree.chart.util.ExportUtils;
. . .
int width = 500;
int height = 270;

File file = new File("barChartDemo.html");
ExportUtils.writeAsSVG(jfreechart, width, height, file);

Пример просмотра SVG графики в Swing приложении

Создадим простое Swing приложение для просмотра векторного SVG изображения. Интерфейс приложения с загруженным векторным SVG тигром представлен в верхней части страницы. Для просмотра SVG графиков используем класс JSVGCanvas.

JSVGCanvas включает API, позволяющее видеть выполняемые объектом действия. Для этого необходимо подключить соответствующих слушателей Listener :

  • SVGDocumentLoaderAdapter - адаптер загрузки изображения;
  • GVTTreeBuilderAdapter - адаптер формирования тела документа (XML tree);
  • GVTTreeRendererAdapter - адаптер прорисовки изображения.

Ниже представлен листинг методов создания интерфейса и подключения слушателей к объекту JSVGCanvas.

private JLabel      label     = new JLabel();
private JSVGCanvas  svgCanvas = new JSVGCanvas();

private JLabel      label     = new JLabel();
private JSVGCanvas  svgCanvas = new JSVGCanvas();
private JPanel createGUI()
{
    final JPanel panel = new JPanel(new BorderLayout());
    JPanel top = new JPanel(new FlowLayout(FlowLayout.LEFT));
        
    JButton button = new JButton("Load...");
    label = new JLabel();
    top.add(button);
    top.add(label);
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
            JFileChooser fc = new JFileChooser(".");
            int choice = fc.showOpenDialog(panel);
            if (choice == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                svgCanvas.setURI(file.toURI().toString());
            }
        }
    });
    svgCanvas = new JSVGCanvas();
    addJSVGCanvasListeners();

    panel.add("Center", svgCanvas);
    panel.add("South", top);

    return panel;
}

private void addJSVGCanvasListeners()
{
    // Подключение слушателей JSVGCanvas
    svgCanvas.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {
        public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
            label.setText("Document loading ...");
        }
        public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
            label.setText("");
        }
    });

    svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
        public void gvtBuildStarted(GVTTreeBuilderEvent e) {
            label.setText("Build started ...");
        }
        public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
            label.setText("");
            frame.pack();
        }
    });

    svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
        public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
            label.setText("Rendering ...");
        }
        public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
            label.setText("");
        }
    });
}

Скачать примеры

Рассмотренные на странице исходные коды примера просмотра векторного SVG графика и примера экспорта графика JFreeChart в векторный SVG график в виде maven-проекта можно скачать здесь (67.6 Кб). Архив включает поддиректорию "svg" с примерами векторных графиков.

  Рейтинг@Mail.ru