Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содержание] [Дальше]

Создание Web-приложений: Практическое руководство

© Александр Фролов, Григорий Фролов
М.: Русская Редакция, 2001, 1040 стр.

16. Векторная графика на базе VML

16. Векторная графика на базе VML.. 1

Способы размещения графики в документах HTML. 1

Рисование простейших фигур. 2

Прямоугольник. 3

Изменение внешнего вида прямоугольника. 4

Исходный прямоугольник. 5

Градиентная закраска. 5

Эффект тени. 6

Экструзия. 6

Линия. 6

Прямая линия. 6

Ломаная линия. 8

Дуга и овал. 9

Кубическая кривая линия Безье. 10

Построение графиков.. 11

Столбчатая диаграмма. 11

График функции синуса. 13

График котировок акций на узле Web компании NetTtrader.ru. 16

Документ DHTML с графиками котировок и объема торгов. 16

Объект xchart 19

Метод initApp. 21

Метод addPrimaryChart 22

Функция drawLine. 23

Функция drawLabel 23

Функция xChartManager_drawLineChart 24

Функция xChartManager_drawShape. 24

Перспективы ли VML. 25

 

В этой главе мы рассмотрим относительно новое средство создания векторных графических иллюстраций на страницах узла Web — языке векторной разметки Vector Markup Language (VML). Это средство доступно при работе с браузером Microsoft Internet Explorer версии 5.0 и более новых версий. Оно очень удобно для отображения такой информации, как графики и диаграммы, причем исходные данные, необходимые для построения этих графиков и диаграмм, могут динамически извлекаться из базы данных или файлов.

Способы размещения графики в документах HTML

Ранее мы уже говорили о том, как можно разместить на страницах HTML графические иллюстрации с применением тега <IMG>, аплетов Java, клиентских элементов управления ActiveX, а также с использованием технологии Flash. К сожалению, всем этим способам присущи определенные недостатки.

Графические изображения, вставленные при помощи тега <IMG>, обычно статические. Хотя расширения сервера Web, такие как программы CGI и ISAPI, могут создавать растровые изображения формата GIF и JPG динамически, однако это не всегда просто. Кроме того, такие изображения располагаются в файлах относительно большого размера и поэтому долго загружаются в браузер по медленным каналам Интернета.

Аплеты Java свободны от перечисленных выше недостатков. Они могут динамически рисовать изображение в своем окне. Кроме того, файлы с исполнимым кодом аплетов имеют небольшие размеры. Однако для их работы в браузере посетителя должна быть установлена виртуальная машина Java. Из соображений безопасности многие посетители отключают эту виртуальную машину, отказываясь от запуска аплетов Java.

Хотя это может прозвучать странно, с аплетами Java связана и еще одна проблема — проблема совместимости. Несмотря на то, что язык Java разработан для создания приложений, работа которых не зависит от компьютерной платформы, на практике это не так. Приложения Java работают под управлением виртуальной машины Java, реализации которой могут отличаться на разных платформах. Хотя имеется принципиальная возможность загрузки исполнимого модуля виртуальной машины Java с узла Web разработчика (компании Sun Microsystems), такая процедура неудобна и редко применяется на практике обычными пользователями.

Клиентские элементы управления ActiveX работают как обычные программы в адресном пространстве компьютера пользователя и потому представляют собой большую потенциальную опасность. По этому причине многие пользователи отключают возможность запуска клиентских элементов управления ActiveX в своих браузерах. Кроме того, загрузка этих элементов управления через Интернет может занимать много времени.

Анимация и графика, созданная с применением технологии Flash, свободна от многих перечисленных выше недостатков, однако для ее просмотре в браузере посетителя должен быть установлен соответствующий модуль. И хотя при его отсутствии для просмотра графики Flash браузер предлагает выполнить загрузку соответствующего модуля через Интернет, эта процедура может отнять немало времени (особенно при использовании модемного соединения с Интернетом).

Что же касается языка VML, то он позволяет динамически рисовать векторные графические изображения в окне браузера без использования аплетов Java, клиентских элементов управления ActiveX или технологии Flash. Конструкции этого языка располагаются непосредственно в исходном тексте документа HTML, поэтому они занимают мало места. Изображения, созданные с использованием VML, тесно интегрируются с содержащими их документами, они могут создаваться динамически клиентскими или серверными сценариями JavaScript или VB Script. Заметим, однако, что текущая реализация VML не содержит никаких средств для работы с анимацией.

Язык VML построен на базе языка расширяемой разметки гипертекста XML (Extensible Markup Language), который, в свою очередь, является подмножеством другого языка — стандартного языка обобщенной разметки документов SGML (Standard Generalized Markup Language).  Кроме того, технология VML предполагает использование каскадных таблиц стилей CSS, о которых мы рассказывали в начале этой книги.

Используя VML, Вы можете описывать графические и текстовые объекты, свойства которых поддаются динамическому изменению посредством клиентских сценариев JavaScript и VB Script. Эти объекты называются фигурами (shapes). Фигуры могут объединяться в группы (groups).

У языка VML есть один заметный недостаток — пока этот язык понимают только современные версии браузера Microsoft Internet Explorer. Впрочем, этот браузер поставляется вместе с операционной системой Microsoft Windows и получает все большее распространение, поэтому во многих случаях этот недостаток не имеет существенного значения. Например, он никак не скажется при разработке систем на базе интрасетей, где системный администратор может полностью контролировать состав программного обеспечения, установленного на рабочих станциях.

В нашей книге мы рассмотрим только наиболее интересные, на наш взгляд, возможности VML. Полное описание этой спецификации Вы найдете в Интернете по адресу http://www.w3.org/TR/NOTE-VML. Мы также расскажем об использовании VML на узел Web компании NetTrader.ru, предоставляющей услуги дисконтного брокера через Интернет. Кроме того, самая необходимая справочная информация о VML и примеры использования этой технологии имеются в MSDN.

Рисование простейших фигур

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

Как мы уже говорили, конструкции языка VML встраиваются непосредственно в текст документа HTML. При этом в атрибутах тега <HTML> необходимо определить так называемое пространство имен VML, при помощи которого браузер будет распознавать конструкции VML.

Определение пространства имен VML выполняется следующим образом:

<html xmlns:v="urn:schemas-microsoft-com:vml">

В качестве идентификатора пространства имен мы указали здесь символ v. Его можно заменить другим символом или строкой, например, vml:

<html xmlns:vml="urn:schemas-microsoft-com:vml">

Идентификатор пространства имен используется для отметки тегов VML. О том, как делать такую отметку, мы расскажем чуть позже.

Далее в заголовке документа необходимо определить так называемое поведение VML, используя выбранный идентификатор пространства имен. Если выбран идентификатор v, то поведение определяется следующим образом:

<style>
v\:* { behavior: url(#default#VML); }
</style>

Для идентификатора vml нужно использовать другой стиль:

<style>
vml\:* { behavior: url(#default#VML); }
</style>

Смысл такого определения заключается в том, чтобы передавать все теги, отмеченные как принадлежащие пространству имен VML, системе отображения графических объектов браузера.

Более подробную информацию о пространствах имен и поведении Вы можете узнать из описания языка XML, которому посвящено немало книг. Тем не менее, для изучения наших примеров Вам не потребуются глубокие знания XML.

Прямоугольник

В первом примере мы нарисуем прямоугольник, показанный на рис. 16-1. Исходный текст соответствующего документа HTML представлен в листинге 16-1.

Рис. 16-1. Рисование прямоугольника

Листинг 16-1. Вы найдете в файле chap16\rectangle.html на прилагаемом к книге компакт-диске

<html xmlns:v="urn:schemas-microsoft-com:vml">
 
<head>
<title>Прямоугольник</title>
<style>
v\:* { behavior: url(#default#VML); }
</style>
</head>
 
<body>
<h2>Прямоугольник</h2>
<v:rect style="HEIGHT: 70px; WIDTH: 100px" fillcolor = "green" />
</body>
</html>

В первой строке исходного текста мы определяем пространство имен VML с идентификатором v:

<html xmlns:v="urn:schemas-microsoft-com:vml">

В заголовке документа, выделенном тегами <head> и </head>, мы задаем поведение VML, используя для этого идентификатор пространства имен v:

<style>
v\:* { behavior: url(#default#VML); }
</style>

Рисование прямоугольника выполняется следующим образом:

<v:rect style="HEIGHT: 70px; WIDTH: 100px" fillcolor = "green" />

Как видите, здесь используется тег <v:rect> с атрибутами style и fillcolor. Имя тега rect отмечено идентификатором v, поэтому при интерпретации документа HTML браузер «поймет», что этот тег относится к пространству имен VML. Если Вы ошибетесь в определении пространства имен или в определении поведения VML, данная конструкция не будет работать — браузер проигнорирует неизвестный ему тег.

Обращаем Ваше внимание на то, как завершается определение тега — здесь использована последовательность символов «/>». Эта конструкция XML позволяет избежать применения закрывающих тегов, если между открывающим и закрывающим тегами ничего нет. Таким образом, приведенную выше строку можно записать и так:

<v:rect style="HEIGHT: 70px; WIDTH: 100px" fillcolor="green">
</v:rect>

Здесь мы явно указали закрывающий тег </v:rect>.

Атрибут style позволяет определить размеры прямоугольника. При помощи атрибута fillcolor мы задаем цвет, которым раскрашивается внутренняя область прямоугольника.

Заметим, что допустимо указывать параметры локальной координатной системы, связанной с отображаемой фигурой. При этом атрибут coordorigin задает смещение начала системы координат, а атрибут coordsize определяет размеры блока, содержащего фигуру. Локальная координатная система удобная при использовании атрибутов позиционирования, определенных в каскадных стилях CSS. Это такие атрибуты, как left, top, width, height и т.д. Подробнее об этом читайте в спецификации VML, расположенной в Интернете по адресу http://www.w3.org/TR/NOTE-VML.

Изменение внешнего вида прямоугольника

Задавая дополнительные теги внутри тега <v:rect>, можно изменять внешний вид прямоугольника, добавляя, например, градиентную закраску или тень. Можно даже превратить прямоугольник в параллелепипед (рис. 16-2).

Рис. 16-2. Изменение внешнего вида прямоугольника

В листинге 16-2 мы привели исходный текст документа HTML, формирующего изображение, показанное на рис. 16-2.

Листинг 16-2. Вы найдете в файле chap16\rectangle1.html на прилагаемом к книге компакт-диске

Вот как в этом документе определены прямоугольники:

<v:rect style="height: 70px; width: 100px" fillcolor = "green" />
<v:rect style="height:70px;width:100px">
<v:fill Type="GradientCenter" Color2="Red" Focusposition="0.3, 0.4"  Focussize="0.3, 0.4" />
</v:rect>
<p>
<v:rect style="height:70px;width:100px">
<v:fill Type="Solid"  Color="RGB(0,128,0)"  />
<v:shadow  on="t" Offset="4pt, 5pt"  />
</v:rect>
<v:rect fillcolor="red" style="width:100;height:70">
<v:extrusion on=True/>
</v:rect>

Рассмотрим эти прямоугольники по отдельности.

Исходный прямоугольник

Первый прямоугольник, отображаемый в верхнем левом углу, такой же, как и показанный на рис. 16-1:

<v:rect style="height: 70px; width: 100px" fillcolor = "green" />

Здесь для нас нет ничего нового. Мы определили размеры прямоугольника и задали зеленый цвет для его закраски.

Градиентная закраска

В следующем прямоугольнике мы указали внутри тега <v:rect> тег <v:fill>, задающий градиентную закраску внутренней поверхности прямоугольника:

<v:rect style="height:70px;width:100px">
<v:fill Type="GradientCenter" Color2="Red" Focusposition="0.3, 0.4"  Focussize="0.3, 0.4" />
</v:rect>

Атрибут type определяет тип закраски. Для обычной, равномерной закраски нужно указать значение этого атрибута как Solid.

Атрибут Color задает первичный цвет закраски (по умолчанию — белый), а Color2 — вторичный цвет закраски. Таким образом, в нашем примере цвет заливки будет плавно изменяться от белого (по краям) до красного (в центре).

С помощью атрибутов Focusposition и Focussize задается, соответственно, координаты центра радиального градиента и размер фокуса радиальной раскраски.

В спецификации VML (http://www.w3.org/TR/NOTE-VML) Вы найдете описание множества других атрибутов тега <v:fill>.

Эффект тени

При помощи тега <v:shadow> можно создать эффект тени. На рис. 16-2 в левом нижнем углу мы нарисовали прямоугольник с тенью. Вот соответствующий фрагмент исходного текста документа HTML:

<v:rect style="height:70px;width:100px">
<v:fill Type="Solid" Color="RGB(0,128,0)" />
<v:shadow on="t" Offset="4pt, 5pt" />
</v:rect>

Здесь внутри тега <v:rect> мы разместили теги <v:fill> и <v:shadow>. Первый из них выполняет равномерную закраску зеленым цветом, а второй — создает тень.

Атрибут on со значением t включает тень. Что же касается атрибута Offset, то он задает смещение тени относительно изображения прямоугольника. По умолчанию тень смещается на расстояние 2pt.

Экструзия

С помощью тега <v:extrusion> можно добиться эффекта «выдавливания», или экструзии. В простейшем случае с помощью этого эффекта прямоугольник легко превращается в параллелепипед:

<v:rect fillcolor="red" style="width:100;height:70">
<v:extrusion on=True/>
</v:rect>

Этот параллелепипед изображен в правом нижнем углу рис. 16-2.

Здесь мы применили тег <v:extrusion> с единственным атрибутом on, включающим эффект экструзии. Вы можете использовать более двух десятков других атрибутов тега <v:extrusion>, создавая и настраивая подсветку, определяя глубину и ориентацию выдавливания, яркость, цветовой режим и т.д. Подробности Вы найдете в описании VML.

Линия

Средствами VML можно рисовать прямые и ломаные линии, окружности, а также кривые Безье. Эти линии удобны для построения различного рода графиков.

Рассмотрим несколько несложных примеров.

Прямая линия

На рис. 16-3 мы показали тонкую прямую линию, нарисованную с помощью VML в окне браузера.

Рис. 16-3. Прямая линия

Исходный текст соответствующего документа HTML приведен в листинге 16-3.

Листинг 16-3. Вы найдете в файле chap16\line.html на прилагаемом к книге компакт-диске

Вот как в этом документе выполняется рисование линии:

<v:line from="0,0" to="140px,60px">
</v:line>

Как видите, для этого мы использовали тег <v:line> с атрибутами from и to. Первый из этих атрибутов задает координаты начала линии, а второй — конца линии.

На рис. 16-4 мы показали некоторые возможности VML по рисованию прямых линий различного стиля.

Рис. 16-4. Линии различных стилей

Как видите, можно рисовать обычные, пунктирные и штрих-пунктирные линии, можно снабжать линии стрелками различного вида, а также изменять цвет линии.

Исходный текст документа HTML, показанного на рис. 16-4, приведен в листинге 16-4.

Листинг 16-4. Вы найдете в файле chap16\line1.html на прилагаемом к книге компакт-диске

Рассмотрим отдельные фрагменты этого исходного текста.

Самая верхняя линия нарисована с использованием только что описанного тега <v:line>:

<v:line from="0,0" to="260px,0px">
</v:line>

Добавив тег <v:stroke> с атрибутом DashStyle, можно нарисовать пунктирные или штрих-пунктирные линии:

<v:line from="0,10px" to="260px,10px">
<v:stroke DashStyle="Dot"/>
</v:line>
<v:line from="0,20px" to="260px,20px">
<v:stroke DashStyle="DashDot" />
</v:line>
<v:line from="0,30px" to="260px,30px">
<v:stroke DashStyle="Dash" />
</v:line>
<v:line from="0,40px" to="260px,40px">
<v:stroke DashStyle="LongDash" />
</v:line>
<v:line from="0,50px" to="260px,50px">
<v:stroke DashStyle="LongDashDot" />
</v:line>
<v:line from="0,60px" to="260px,60px">
<v:stroke DashStyle="LongDashDotDot" />
</v:line>

С помощью атрибута DashStyle можно выбрать один из видов пунктирной или штрих-пунктирной линии.

Атрибуты StartArrow и EndArrow позволяют выбрать вид стрелки, которая должна быть нарисована, соответственно, в начале или конце линии:

<v:line from="0,70px" to="260px,70px">
<v:stroke EndArrow="Classic" />
</v:line>
<v:line from="0,80px" to="260px,80px">
<v:stroke  EndArrow="Diamond"  />
</v:line>

Здесь мы нарисовали на концах двух линий классическую стрелку и стрелку в виде ромбика.

При помощи атрибута Weight тега <v:stroke> можно определить толщину линии:

<v:line from="0,100px" to="260px,100px">
<v:stroke Weight="6pt" />
</v:line>

И, наконец, атрибут Color позволяет изменить цвет линии:

<v:line from="0,120px" to="260px,120px">
<v:stroke Weight="6pt" DashStyle="Dash" Color="Red" />
</v:line>

Ломаная линия

Для рисования графиков и разного рода многоугольников удобен тег <v:polyline>. На рис. 16-5 мы показали фигуру, нарисованную в документе HTML с его помощью.

Рис. 16-5. Ломаная линия

Исходный текст соответствующего документа HTML Вы найдете в листинге 16-5.

Листинг 16-5. Вы найдете в файле chap16\line2.html на прилагаемом к книге компакт-диске

Для тега <v:polyline> необходимо указать атрибут points, определяющий координаты точек излома линии:

<v:polyline points="0px,0px 200px,200px 0px,200px 0px,0px 200px,0px 200px,200px 200px,0px 0px,200px">
</v:polyline>

Координаты задаются в виде пар чисел, первое из которых определяет координату по горизонтальной оси, а второе — по вертикальной.

Дуга и овал

Для рисования дуги Вы можете использовать тег <v:arc>. Чтобы нарисовать овал,  а также окружность, являющуюся частным случаем овала, применяют тег <v:oval>.

На рис. 16-6 мы показали страницу HTML, в которой нарисована дуга и овал.

Рис. 16-6. Дуга и овал

Исходный текст этой страницы Вы найдете в листинге 16-6.

Листинг 16-6. Вы найдете в файле chap16\arc.html на прилагаемом к книге компакт-диске

Тегам <v:arc> и <v:oval> необходимо передать атрибуты width и height, определяющие размеры соответствующих фигур:

<v:arc style="height:160px; width: 160px" startangle = "-90"
endangle = "190" />
<v:oval style="height:160px; width:100px" />

Для тега <v:arc> дополнительно нужно задать атрибуты startangle и endangle. Первый из них определяет угол, соответствующий началу дуги, а второй — концу дуги.

При необходимости Вы можете изменять стили дуги и овала таким же образом, что и стили прямых линий. Для этого нужно воспользоваться тегом <v:stroke>. В том случае, если Вам нужно закрасить внутреннюю область овала, используйте атрибут fillcolor тега <v:oval> (аналогично тому, как мы это делали для закрашивания прямоугольников).

Кубическая кривая линия Безье

Чтобы нарисовать кубическую кривую линию Безье, Вы можете использовать тег <v:curve>. Пример применения этого тега показан на рис. 16-7.

Рис. 16-7. Кривая линия Безье

Исходный текст документа HTML представлен в листинге 16-7.

Листинг 16-7. Вы найдете в файле chap16\curve.html на прилагаемом к книге компакт-диске.

Для тега <v:curve> нужно определить как минимум четыре атрибута:

<v:curve from="0px,0px" to="180px,50px" control1="30px,150px" control2="40px,30px">
</v:curve>

Атрибуты from и to задают координаты начала и конца линии. Что же касается атрибутов control1 и control2, то они задают координаты, соответственно, первой и второй управляющей точки кубической кривой Безье.

Построение графиков

Язык VML очень удобен для построения различного рода графиков и диаграмм в документах HTML. С этой целью Вы можете использовать теги VML, предназначенные для рисования прямых и ломаных линий, прямоугольников и других простейших фигур.

Столбчатая диаграмма

В этом разделе мы нарисуем средствами VML внутри документа HTML координатную сетку, а также график функции синуса в виде столбчатой диаграммы (рис. 16-8).

Рис. 16-8. График в виде столбчатой диаграммы

Исходный текст документа HTML, в котором формируется диаграмма, приведен в листинге 16-8.

 

Листинг 16-8. Вы найдете в файле chap16\sinus.html на прилагаемом к книге компакт-диске.

Рассмотрим этот исходный текст.

Прежде всего, в заголовке документа мы определили две функции с именами table и bar.

Функция table рисует координатную сетку при помощи тегов <v:rect> и <v:line>, вставляя их динамически в текст документа HTML вызовом метода document.write:

function table()
{
  document.write('<v:rect fillcolor="yellow" style="position:absolute;top=20pt;left=20pt;width:400pt; height:300pt;"><v:stroke weight="2pt" color="green"/></v:rect>');
  var i;
  for(i=0;i<20;i++)
  {
     document.write('<v:line from="0,'+i*15+'pt" to="400pt,'+i*15+'pt" style="position:absolute;top=20pt;left=20pt"><v:stroke dashstyle="dot"/></v:line>');
  }
  for(i=0;i<20;i++)
  {
     document.write('<v:line from="'+i*20+'pt,0" to="'+i*20+'pt,300pt" style="position:absolute;top=20pt;left=20pt"><v:stroke dashstyle="dot"/></v:line>');
  }
  document.write('<v:line from="0,150pt" to="400pt,150pt" style="position:absolute;top=20pt;left=20pt"><v:stroke weight="2pt" /></v:line>');
}

Обратите внимание, что эта функция вначале рисует толстую рамку вокруг координатной сетки при помощи тега <v:rect>. Внутренняя область рамки закрашивается желтым цветом, а для рисования самой рамки применен зеленый цвет. Чтобы рамка выглядела толстой, ширина линии задается равной 2 pt.

Далее в работу включаются два цикла, предназначенные для рисования горизонтальных и вертикальных линий координатной сетки. Чтобы линии были пунктирными, мы в теге <v:stroke> указываем значение атрибута dashstyle как «dot».

И, наконец, перед тем как завершить свою работу, функция table рисует жирную горизонтальную линию координатной оси X.

Функция bar рисует столбец диаграммы, расположенной в заданном месте координатной оси X (определяется параметром x). Высота столбца определяется параметром y. Вот исходный текст функции bar:

function bar(x,y)
{
  if(y>0)
  {
     document.write('<v:rect fillcolor="red" style="position:absolute;top='+(20+150-y)+'pt;left='+(20+x)+'pt;width:5pt;height:'+y+'pt"><v:stroke color="red" weight="0pt" /></v:rect>');
  }
  else
  {
     y = -y;
     document.write('<v:rect fillcolor="red" style="position:absolute;top='+(20+150)+'pt;left='+(20+x)+'pt;width:5pt;height:'+y+'pt"><v:stroke color="red" weight="0pt" /></v:rect>');
  }
}

Как видите, столбец рисуется при помощи тега <v:rect>, предназначенного для изображения прямоугольников. Чтобы правильно определить расположение углов прямоугольника, функция bar учитывает знак параметра y. Если он отрицательный, значение параметра инвертируется, а координаты углов прямоугольника рассчитываются по-другому.

Что же касается тела документа HTML, то расположенный в нем клиентский сценарий JavaScript вначале рисует координатную сетку, вызывая для этого функцию table, а затем столбчатую диаграмму, вызывая в цикле функцию bar:

<body>
<SCRIPT LANGUAGE="JavaScript">
<!--
 table();
 for(var a=0;a<400; a+=15)
 {
   var rad=(a/360)*6.28;
   bar(a,Math.sin(rad)*150);
 }
// -->
</SCRIPT>
</body>

Обратите внимание, что мы передаем функции bar в качестве первого параметра значение угла в радианах, а в качестве второго — значение синуса этого угла, умноженное на число 150. В результате внутри нарисованной ранее координатной сетки помещается изображение чуть больше, чем одного периода функции синуса.

График функции синуса

Если Вам нужно построить на странице HTML обычный график функции в виде кривой линии, то это можно сделать, по крайней мере, двумя способами. Во-первых, можно аппроксимировать кривую линию графика при помощи прямых линий, а во-вторых — использовать многоугольник.

На рис. 16-9 мы показали график функции синуса, нарисованный с помощью прямых линий.

Рис. 16-9. График функции синуса

Исходный текст соответствующего документа HTML Вы найдете в листинге 16-9.

 

Листинг 16-9. Вы найдете в файле chap16\sinus1.html на прилагаемом к книге компакт-диске.

Для рисования графика мы определили функцию lineto, которая рисует отрезок, заданный координатами начала (x1,y2) и конца (x2,y2) линии:

function lineto(x1,y1,x2,y2)
{
  y1 = 150-y1;
  y2 = 150-y2;
  document.write('<v:line from="'+x1+'pt,'+y1+'pt" to="'+x2+'pt,'+y2+'pt" style="position:absolute;top=20pt;left=20pt"><v:stroke weight="2pt" color="blue" /></v:line>');
}

В теле документа мы организовали цикл, внутри которого вычисляются значения функции синуса:

<body>
<SCRIPT LANGUAGE="JavaScript">
<!--
 table();
 var x_old=0;
 var y_old=0;
 for(var a=0;a<410; a+=10)
 {
   var rad=(a/360)*6.28;
   lineto(x_old,y_old,a,Math.sin(rad)*150);
   x_old=a;
   y_old=Math.sin(rad)*150;
 }
// -->
</SCRIPT>
</body>

На каждой итерации цикла мы сохраняем в переменных x_old и y_old предыдущее значение функции, и, соответственно, координаты начала отрезка, аппроксимирующего соответствующий участок функции.

Ту же самую функцию можно нарисовать и при помощи многоугольника (рис. 16-10).

Рис. 16-10. График функции синуса, вариант с использованием многоугольника

Как видно из рис. 16-10, увеличивая количество сторон многоугольника, можно добиться неплохой аппроксимации функции синуса.

Исходный текст документа HTML, в котором мы рисуем график функции синуса при помощи многоугольника, представлен в листинге 16-10.

Листинг 16-10. Вы найдете в файле chap16\sinus2.html на прилагаемом к книге компакт-диске.

Определенная в этом документе функция draw_graph рисует многоугольник, координаты вершин которого передаются ей через параметр points:

function draw_graph(points)
{
  document.write('<v:polyline fillcolor="white" points="'+points+'" style="position:absolute;top=20pt;left=20pt"><v:stroke weight="1pt" color="red"/></v:polyline');
}

Эти координаты готовятся сценарием JavaScript, размещенным в теле документа:

<body>
<SCRIPT LANGUAGE="JavaScript">
<!--
 table();
 var points="0pt,150pt ";
 var new_point="";
 var x_new=0;
 var y_new=0;
 for(var a=0;a<410; a+=10)
 {
   var rad=(a/360)*6.28;
   var x_new=a;
   var y_new=150 - Math.sin(rad)*150;
   
   points += " " + x_new + "pt," + y_new + "pt ";
 }
 points += "400pt, 150pt 0pt,150pt";
 draw_graph(points);
// -->
</SCRIPT>
</body>

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

График котировок акций на узле Web компании NetTtrader.ru

Компания NetTtrader.ru, предоставляющая услуги дисконтного брокера через Интернет. Клиенты NetTtrader.ru могут в реальном времени покупать и продавать через Интернет акции и другие ценные бумаги (инструменты). Узел Web этой компании с адресом http://www.nettrader.ru является примером широкого применения самых современных технологий Интернета от Microsoft.

В этом разделе мы расскажем о том, как компания NetTtrader.ru использует VML для отображения графиков котировок ценных бумаг (рис. 16-11).

Рис. 16-11. График котировок акций на узле Web компании NetTtrader.ru

Документ DHTML с графиками котировок и объема торгов

Для рисования графика котировок на узле Web компании NetTrader.ru были использованы средства динамического HTML (DHTML), а также объектно-ориентированное программирование на языке сценариев JavaScript. Сотрудник компании NetTrader.ru Сергей Лебедев любезно предоставил для публикации в нашей книге листинги документов DHTML, предназначенных для отображения котировок ценных бумаг и объемов торгов.

Исходный текст документа HTML chart.html, в котором отображается график котировок,  Вы найдете в листинге 16-11. Не пытайтесь загружать этот документ в окно своего браузера, так как в отрыве от контекста сервера NetTrader.ru он не будет работать. Мы публикуем данный листинг только в качестве примера применения технологии VML в реально действующей торговой системе компании NetTrader.ru.

Листинг 16-11. Вы найдете в файле chap16\NetTrader\chart.html на прилагаемом к книге компакт-диске.

Прежде всего, в заголовке документа подключается файл каскадных стилей CSS с именем style.css, а также определяется пространство имен для VML:

<head>
<
LINK REL="StyleSheet" HREF="../include/style.css" type="text/css">
<
xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>
<style>
v\:* { behavior:url(#default#VML);}
.xchart { behavior:url(xchart.htc);}
.label { font-size:9px }
</style>
</head>

Обратите внимание на следующую строку заголовка:

<style>
   . . .
.xchart { behavior:url(xchart.htc);}
   . . .
</style>

Здесь мы определили класс xchart и указали, что его поведение описано в файле с именем xchart.htc. Объект xchart представляет собой активный компонент, созданный средствами JavaScript. Его интерфейс (то есть набор методов для доступа к объекту) предназначен для рисования графиков котировок средствами VML и выполнения других действий, определен в файле xchart.htc. Мы расскажем о файле xchart.htc в конце этой главы.

Рассмотрим теперь тело документа HTML, исходный текст которого приведен в листинге 16-11.

В начале тела документа определены функции JavaScript, предназначенные для работы с объектом класса xchart, то есть с нашим графиком котировок:

<script>
var curPeriod;
var curTime;

function loadGraph(ric, period, time, type)
{
   chID4.addPrimaryChart( ric, period, time, type );
   chID4.style.visibility = "visible";
}

function loadCorrGraph(ric)
{
   chID4.addSecondaryChart( ric );
}

function addMAChart( period )
{
   chID4.addMAChart( period );
}
</script>

Как видите, все эти функции обращаются к объекту xchart с использованием идентификатора chID4. Вот как определен этот объект с применением тега <DIV>:

<div id="chID4" style="position:relative;top:0;left:0;width:550;height:400;
visibility:hidden"
class="xchart"
graphBottom = "130" graphLeft = "70" graphWidth = "460"
graphHeight = "230" volumeHeight = "80" volumeBottom = "20"
labelWidth = "65" labelHeight = "10" labelClass = "label"
yGridRange = "11" xGridRange = "7" mainGraphColor = "blue"
mainGraphWeight = "1px">
</div>

Атрибут STYLE тега <DIV> определяет размеры и расположение объекта, а также его видимость. По умолчанию объект скрыт, так как параметр visibility имеет значение hidden. Остальные параметры определяют внешний вид графика.

Для того чтобы отобразить график, функция loadGraph вначале вызывает метод addPrimaryChart объекта xchart, добавляющий график котировок (верхний график на рис. 16-11) а затем устанавливает значение параметра visibility равным visible:

function loadGraph(ric, period, time, type)
{
   chID4.addPrimaryChart( ric, period, time, type );
   chID4.style.visibility = "visible";
}

Для того чтобы клиент мог просмотреть графики котировок по выбранному инструменту и за определенный период времени, а также графики сравнения котировок различных инструментов, в документе HTML предусмотрена форма с несколькими списками:

<form id="x">
<input class="sm3" name="ric" type="text" size="10" value="EESR.RTS"></input>

<select class="sm3" name="time" >
     <option value="1M">1
месяц</option>
     <option value="2M">2
месяца</option>
     <option value="3M">3
месяца</option>
     <option value="6M" SELECTED>6
месяцев</option>
     <option value="YTD">
с начала года</option>
     <option value="1Y">1
год</option>
     <option value="2Y">2
года</option>
     <option value="3Y">3
года</option>
     <option value="5Y">5
лет</option>
</select>

<select class="sm3" name="period" >
     <option value="D" SELECTED>
день</option>
     <option value="W">
неделя</option>
     <option value="M">
месяц</option>
</select>

<select class="sm3" name="type" >
     <option value="HIGH">High</option>
     <option value="LOW">Low</option>
     <option value="OPEN">Open</option>
     <option value="CLOSE" SELECTED>Close</option>
     <option value="HLOC">Hi-Lo-Open-Close</option>
     <option value="CAN">Candlesticks</option>
</select>

<input class="sm3" type="button" value="Get Chart"
onclick="loadGraph(document.forms.x.ric.value, document.forms.x.period.value, document.forms.x.time.value, document.forms.x.type.value );"></input>

<br>
<input class="sm3" name="corric" type="text" size="10" value="LKOH.RTS"></input>
<input class="sm3" type="button" value="Compare to Stock"
onclick="loadCorrGraph(document.forms.x.corric.value );">
</input>

<input class="sm3" name="ma" type="text" size="10" value="20"></input>
<input class="sm3" type="button" value="Add MA"
onclick="addMAChart(document.forms.x.ma.value );">
</input>

<input class="sm3" type="button" value="Export"
onclick="chID4.exportCSV();"></input>

<br>
<select class="sm3" name="idx" >
     <option value=".IRTS">
Индекс РТС</option>
     <option value=".RMM">
Индекс ММВБ</option>
     <option value=".IXIC">NASDAQ Composite</option>
     <option value=".SPO">S&P 100</option>
     <option value=".RUT">RUSSELL 2000</option>
     <option value=".WIL5">WILSHIRE 5000</option>
     <option value=".FTEU1">FTSE 100</option>
     <option value=".FCHI">CAC 40</option>
     <option value=".DAX">DAX</option>
     <option value=".BVSP">BOVESPA</option>
     <option value=".N225">NIKKEY 225</option>
     <option value=".HSI">HANG SENG</option>
     <option value=".KS11">KOSPIO</option>
</select>

<input class="sm3" type="button" value="Compare to Index"
onclick="loadCorrGraph(document.forms.x.idx.value );">
</input>
</form>

Когда клиент щелкает ту или иную кнопку в форме, вызывается функция JavaScript, вызывающая соответствующий метод объекта xchart. В результате в окне браузера появляется нужный график.

Объект xchart

Теперь пора перейти к описанию активного компонента xchart и его интерфейса. Исходный текст файла xchart.htc, содержащего определения этого объекта, Вы найдете в листинге 16-12. Полное описание этого весьма объемного листинга выходит за рамки нашей книги, поэтому мы рассмотрим только некоторые его фрагменты.

Листинг 16-12. Вы найдете в файле chap16\NetTrader\xchart.htc на прилагаемом к книге компакт-диске.

Прежде всего, мы рассмотрим общую структуру файла xchart.htc:

<PUBLIC:COMPONENT>
<PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="initApp()" FOR="element"/>
<PUBLIC:METHOD NAME="addPrimaryChart"/>
<PUBLIC:METHOD NAME="addSecondaryChart"/>
<PUBLIC:METHOD NAME="addMAChart"/>
<PUBLIC:METHOD NAME="exportCSV"/>

<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>
<style>
v\:* { behavior:url(#default#VML);}
</style>


<SCRIPT LANGUAGE="JScript">
 
var chartData;
var mainArea;
var detailsLine;
var graphHeader;

////////////////////////////////////////////////////////////////////////
Методы, объявленный как PUBLIC

function addPrimaryChart( code, periodicity, time, type )
{ . . .}

function addMAChart( period )
{ . . .}

function findChart( code, type )
{ . . .}

function exportCSV()
{ . . .}


function initApp()
{ . . .}

. . .
/////////////////////////////////////////////////////////////////////
/// Другие методы
. . .

</SCRIPT>
<PUBLIC:COMPONENT>

Тег <PUBLIC:COMPONENT>, расположенный в начале и в конце файла xchart.htc, указывает, что данный файл является определением активного компонента, то есть фактически определением его интерфейса.

Тег <PUBLIC:ATTACH> задает обработчик события ondocumentready, который вызывается при завершении загрузки документа в окно браузера:

<PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="initApp()" FOR="element"/>

В роли такого обработчика выступает функция initApp, определенная в файле xchart.htc.

Далее при помощи тега <PUBLIC:METHOD> перечислены общедоступные методы объекта xchart, образующие его интерфейс:

<PUBLIC:METHOD NAME="addPrimaryChart"/>
<PUBLIC:METHOD NAME="addSecondaryChart"/>
<PUBLIC:METHOD NAME="addMAChart"/>
<PUBLIC:METHOD NAME="exportCSV"/>

Как видите, это те самые методы, которые вызывает сценарий JavaScript документа HTML, представленного в листинге 16-11. Первые три метода добавляют графики различных типов, а четвертый — экспортирует данные графика в формате «данные, разделенные запятой» (Comma Separated Values, CSV) для последующей загрузки, например, в Microsoft Excel.

Вслед за определением интерфейса объекта xchart располагается определение пространства имен VML:

<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>
<style>
v\:* { behavior:url(#default#VML);}
</style>

И, наконец, завершает файл  xchart.htc определение методов, образующих внешний интерфейс объекта, а также служебных методов, доступных только внутри самого файла xchart.htc.

Рассмотрим вкратце некоторые методы объекта xchart.

Метод initApp

Этот метод получает управление сразу после завершения загрузки документа HTML с графиком в окно браузера:

function initApp()
{
   mainArea = drawMainFrame();

   var mainChart = drawChartFrame(element.graphLeft, element.graphBottom, element.graphWidth, element.graphHeight);

   element.onclick = debugInfo;
   mainChart.onmousemove = showDetails;

   var volChart = drawChartFrame(element.graphLeft, element.volumeBottom, element.graphWidth, element.volumeHeight);
  . . .
}

Прежде всего, метод рисует главную рамку, ограничивающую область рисования графиков, вызывая для этого функцию drawMainFrame.

Функция drawMainFrame пользуется объектной моделью документа DHTML (Document Object Model, DOM), динамически формируя теги VML:

function drawMainFrame()
{
  var g = document.createElement("v:group");
  g.coordsize = (element.clientWidth-element.clientLeft*2)+","+(element.clientHeight-element.clientTop*2);
  g.coordorigin = "0,0";
  g.style.position = "relative";
  g.style.top = 0;
  g.style.left = 0;
  g.style.width = element.clientWidth-element.clientLeft*2;
  g.style.height = element.clientHeight-element.clientTop*2;
  g.style.flip = "y";

  var mainGroup = element.insertBefore(g);

  var or = document.createElement("v:rect");
  or.style.position = "absolute";
  or.style.top = 0;
  or.style.left = 0;
  or.style.width = element.clientWidth-element.clientLeft*2;
  or.style.height = element.clientHeight-element.clientTop*2;
  or.fillcolor = "#E7EACD";

  mainGroup.insertBefore(or);

  var details = document.createElement("div");
  details.style.fontSize = "9px";
  details.align = "left";
  details.style.position = "absolute";
  details.style.left = element.graphLeft;
  details.style.top = 25;
  details.style.width = element.graphWidth;
  details.style.height = element.labelHeight; 

  detailsLine = mainGroup.insertBefore( details );

  var header = document.createElement("div");
  header.style.fontSize = "12px";
  header.align = "left";
  header.style.position = "absolute";
  header.style.left = element.graphLeft;
  header.style.top = 10;
  header.style.width = element.graphWidth;
  header.style.height = element.labelHeight;
  header.style.fontWeight = "bold";

  graphHeader = mainGroup.insertBefore( header );

  return( mainGroup );
}

Формирование тегов выполняется функцией createElement объекта document, а вставка тегов — функцией insertBefore.

В самом начале формируется тег <v:group>, объединяющий все объекты сетки графика в одну группу. Идентификатор этого тега возвращается функцией drawMainFrame после завершения ее работы. Функция initApp сохраняет этот идентификатор в глобальной переменной mainArea.

Вслед за функцией drawMainFrame метод initApp дважды вызывает функцию drawChartFrame для изображения рамки графика котировок (верхняя часть рисунка 16-11) и графика объема торгов (нижняя часть рисунка 16-11):

function drawChartFrame( left, bottom, width, height)
{
  var r = document.createElement("v:rect");

  r.style.position = "absolute";
  r.style.top = bottom;
  r.style.left = left;
  r.style.width = width;
  r.style.height = height;
  r.style.cursor = "crosshair";
  r.fillcolor = "#E7F2F4";
 
  var graphArea = mainArea.insertBefore(r);
  return( graphArea );
}

Эта функция вставляет в документ тег <v:rect>, предназначенный для изображения прямоугольника. Создав тег функцией createElement, функция  drawChartFrame определяет его атрибуты. Затем тег  вставляется в только что сформированную главную область mainArea функцией insertBefore.

Метод addPrimaryChart

Метод addPrimaryChart вызывается из клиентского сценария JavaScript, расположенного в документе HTML с графиками (листинг 16-11). 

Вот его исходный текст:

function addPrimaryChart( code, periodicity, time, type )
{
  if(chartData)
  {
     if((chartData.code != code) || (chartData.queryPeriodicity != periodicity) || (chartData.queryTime != time))
     {
       chartData = null;
       chartData = new xChartManager(code, periodicity, time, type);
       chartData.addChart(code);
     }
     else
     {
       if(chartData.setChartType(type)) chartData.redrawCharts();
     }
  }
  else
  {
     chartData = new xChartManager( code, periodicity, time, type );
     chartData.addChart(code);
  }
  return ( true );
}

Метод addPrimaryChart создает новый объект класса xChartManager, обеспечивающий рисование графиков. Метод setChartType класса xChartManager определяет тип графика, а метод redrawCharts рисует график.

Функция drawLine

Служебная функция drawLine рисует прямую линию, координаты начала и конца которой определяются первыми четырьмя параметрами функции:

function drawLine(startx, starty, endx, endy, color, dashStyle)
{
  var l = document.createElement("v:line");
  l.style.position = "absolute";
  l.style.zindex = "2";
  l.strokecolor = color;

  l.from = startx+","+starty;
  l.to = endx+","+endy;
  l.style.cursor = "crosshair";
  l.name = "gridline";
  l.onmousemove=showDetails;

  var d = document.createElement("v:stroke");
  d.dashstyle = dashStyle;

  l.insertBefore(d);
  mainArea.appendChild(l);
}

Параметры color и dashStyle задают цвет и стиль линии (сплошная, пунктирная, штрих-пунктирная и т.д.), соответственно.

Для рисования линии функция drawLine вначале динамически создает тег <v:line> вызовом функции createElement, а затем определяет атрибуты этого тега. Далее аналогичным образом создается тег <v:stroke>, задающий стиль линии. Теги вставляются в документ HTML функцией insertBefore, а затем добавляются в главную область, выделенную для построения графиков, функцией appendChild.

Функция drawLabel

Функция drawLabel предназначена для рисования подписей к элементам графиков:

function drawLabel( text, x, y, width, align, className )
{
 
var div = document.createElement("div");
 
div.style.fontSize = "9px";
 
div.align = align;
 
div.innerText = text;
 
div.style.position = "absolute";
 
div.style.left = Math.round(x);
 
div.style.top = (mainArea.clientHeight - (Number(element.labelHeight)/2) - y);
 
div.style.width = width;
 
div.className = className;
 
div.name = "label";

 
mainArea.appendChild( div );
}

Получив управление, функция drawLabel создает тег <div>, вызывая для этого функцию createElement. Далее наша функция определяет различные атрибуты тега, в том числе текст подписи, высоту шрифта и выравнивание текста. Для добавления подписи в область, выделенную для рисования графика, используется функция  appendChild.

Функция xChartManager_drawLineChart

Ниже мы привели исходный текст функции xChartManager_drawLineChart, предназначенной для рисования графика котировок (столбчатую диаграмму объемов торгов рисует функция xChartManager_drawBarChart, исходный текст которой мы оставляем Вам на самостоятельное изучение):

function xChartManager_drawLineChart( code, data, id, isActive )
{
  var vpath, x, y, cur;
  for( var i = 0; i < this.dateIndex.length; i++ )
  {
     cur = data[id].data[this.dateIndex[i]];
     if( cur != null )
     {
       y = Math.round( (cur - this.min + this.offsetY)*this.scaleY );
       x = Math.round( this.scaleX*i + this.barOffset );
       if( !vpath )
          vpath = "nf m "+ x +"," + y + " l";
       else
          vpath+=x+","+y+" ";
     }
  }
  if(this.dateIndex.length == 1)
  {
     vpath+=x+","+y+"e";
     vpath+="m"+(x-1)+","+(y+1)+" l"+             (x+1)+","+(y+1)+","+(x+1)+","+(y-1)+","+(x-1)+","+(y-1)+"x"

  }
  vpath+="e";
  this.drawShape(code, vpath, id, code+" ("+data[id].label+")", data[id], 1, isActive);
}

Как видно из исходного текста функции xChartManager_drawBarChart, непосредственное формирование тегов VML для рисования выполняет функция drawShape. Через параметр vpath ей передается набор координат графика, подготовленный функцией xChartManager_drawBarChart на основании данных, переданный ей через параметр data.

Функция drawShape будет рисовать график при помощи тега <v:shape>, подробное описание которого выходит за рамки нашей книги. Заметим только, что атрибут path этого тега содержит последовательность команд, определяющих форму рисуемой фигуры. При помощи команд можно определять прямые и кривые линии, окружности и т.д.

В начале строки vpath, подготовленной функцией xChartManager_drawLineChart, находится команда nf (notfill). Она указывает, что форму, описанную данной строкой, не нужно закрашивать. Далее следует команда m (moveto), которая означает перемещение координаты текущей точки в позицию, заданную следующими двумя числами. Следом идет команда l (lineto), выполняющая рисование линии из текущей точки в точку, заданную парой следующих двух чисел. Если после команды l следует несколько пар чисел, будет нарисована ломаная линия. Команда e  завершает текущую последовательность команд.

Более подробно о командах и различных атрибутах тега <v:shape> читайте в спецификации VML (http://www.w3.org/TR/NOTE-VML).

Функция xChartManager_drawShape

Функция xChartManager_drawShape использует тег <v:shape> для рисования графиков. Атрибуты этого тега, определяющие форму графика, передаются функции через параметр vpath, другие параметры задают внешний вид графика:

function xChartManager_drawShape(code, vpath, chartType, label, data, area, isActive )
{
  var bottom = (area)?this.clientBottom:(this.volumeClientBottom);
  var height = (area)?this.clientHeight:(this.volumeClientHeight);
      
  var gr = document.createElement("v:shape");
  gr.style.position = "absolute";
  gr.style.left = this.clientLeft;
  gr.style.top = bottom;
  gr.style.width = this.clientWidth;
  gr.style.height = height;
  gr.strokeweight = 1;     
  gr.style.zIndex = ( code == this.code )?"5":"4";
  gr.coordsize = this.clientWidth+","+height;
  gr.coordorigin = "0 0";
  gr.fillcolor = this.data[code].color;
  gr.path = vpath;
  gr.title = label;
  gr.style.cursor = (isActive)?"hand":"crosshair";
      
  if( isActive )
  {
     gr.onmouseover = hilightChart;
     gr.onmouseout = restoreChart;
     gr.onclick = removeChart;
  }
      
  gr.onmousemove = showDetails;
  gr.id = code;
  gr.chartType = chartType;
  gr.name = "chart"

  var color = (data != null && data.lineColor)?(data.lineColor):(this.data[code].color);
  var stroke = (data != null && data.lineStyle)?(data.lineStyle):("solid");

  gr.originalColor = color;
      
  var d = document.createElement("v:stroke");
  d.dashstyle = stroke;
  d.color = color
  gr.insertBefore(d);
  mainArea.insertBefore(gr);
}

Создание тегов <v:shape> и <v:stroke> выполняется функцией createElement, а их вставка — функцией insertBefore. Обратите внимание, что в зависимости от параметров функции xChartManager_drawShape выбирается форма курсора мыши, стиль линии графика и ее цвет.

Перспективы ли VML

Как видите, технология VML позволяет относительно простыми средствами создавать в документах HTML достаточно сложные графические изображения. При этом объем информации, передаваемой с сервера Web в браузер посетителя весьма невелик, поэтому загрузка изображений VML выполняется довольно быстро.

Написав всего несколько десятков строк кода, Вы сможете построить график функции или столбчатую диаграмму. Без VML решить такую задачу было бы довольно сложно. Создавая динамически страницы HTML, серверные сценарии ASP, программы CGI или ISAPI могут встраивать в них сложные графические изображения без привлечения дополнительных программных модулей, что упрощает программирование.

Учитывая все это, а также и то, что популярность браузера Microsoft Internet Explorer новых версий неуклонно возрастает, мы можем сделать вывод о том, что технология VML является перспективной. Когда эта технология будет дополнена средствами анимации, она может составить успешную конкуренцию Flash-технологии.

[Назад] [Содержание] [Дальше]