Особенности разработки приложений для обмена медиаданными в широкополосной интегрированной среде
А.А. Марков,
д.т.н., профессор, зав. кафедрой информационных систем МГУП имени Ивана
Федорова
М.Е. Смирнова,
ст. преподаватель кафедры информационных систем МГУП имени Ивана Федорова.
Часть 1. Обмен данными между устройствами с использованием сервера
В статье рассматриваются вопросы использования мобильных устройств в задачах обмена данными. Мобильные устройства являются не только потребителями, но и активными поставщиками медиаданных. Для мобильных устройств важной особенностью является привязка генерируемого контента к геоинформационным сервисам. В силу объемности статья разделена на две части. Первая часть посвящена организации обмена данными между мобильными устройствами с использованием сервера.
1. Введение
Обмен данными между интеллектуальными мобильными устройствами (ИМУ), такими как смартфоны и планшетные компьютеры, является важной характерной чертой для многих приложений1. В упрощенном случае данные, с которыми работают приложения, интегрирующие информацию, можно разбить на две группы: общие дан-
1 Геоинформационные приложения, приложения для корпоративных клиентов, другие приложения, использующие мультимедийные возможности современных ИМУ, работают с большими объемам данных
ные (ОД), доступные всем пользователям приложения, и пользовательские данные (ПД), эти данные находятся на многих ИМУ, но могут быть предоставлены их владельцами для общего доступа. Программное обеспечение рассматривает ОД и ПД как единую интегрированную среду, с которой взаимодействуют как приложения ИМУ, так и серверные приложения, обеспечивающие хранение, обработку и обновление ОД. Деление данных на две группы дает возможность сформулировать несколько общих задач, рассмотрение которых удобно провести на примере.
Рассмотрим, приложение ИМУ, предназначенное для сбора, просмотра и интерактивной демонстрации медиаданных о расположенных на туристическом маршруте объектах. Подобного рода приложение интенсивно использует обмен медиаданными с сервером и другими мобильными устройствами. ИМУ собирает фотографии, видео, текстовые и голосовые заметки, привязывает эту информацию к географическому положению объекта. Собранная на ИМУ информация, может быть передана на сервер или сохранена в локальной базе данных ИМУ. Для разработки приложения можно использовать API Яндекс карты или Google Maps2.
2. Подключение геоинформационных сервисов к приложению
Демонстрацию основной последовательности действий, связанных с получением геоинформационных медиаданных и пересылкой накопленной информации на сервер приложений, удобно привести на примере WEB приложения.
Код HTML3 страницы показан ниже (Листинг 1).
1 <html xmlns="http://www.w3.org/1999/xhtml">
2 <head>
3 <script src="http://maps.google.com/maps?file=api&v=2&key=ZZZ" type="text/javascript">
4 </script>
5 <script src="map_data.php" type="text/javascript"></script>
6 <script src="map_functions.js" type="text/javascript"></script>
7 </head>
8 <body>
2 Для ИМУ используется Google Maps для мобильных устройств.
3 Основные коды для решения задач, рассматриваемые в статье, разрабатывались и отлаживались в соответствии с рекомендациями и шаблонами, приведенными в [1].
9 <div id="map" style="width: 480px; height: 320px"></div>
10 </body>
11 </html>
Листинг 1. — HTML код приложения
Для получения доступа к картам Google приложение должно использовать специальный ключ4 (строка 3, Листинг 1). Ключ нужно подставить в строке 2 вместо «ZZZ». Данные о имеющейся разметке карты можно указать (строка 5) в файле map_data.php. Обрабатывающий события, связанные с картой, JavaScript код записывается в файле «map_functions.js». В строке 9 Листинга 1 показан блок div, используемый для размещения карты. Размеры блока соответствуют предполагаемому экрану ИМУ.
Простейшие действия, связанные с картой, активируются с помощью кликов мышкой (стационарные компьютеры/ноутбуки) или касаний (ИМУ с сенсорными экранами).
JavaScript код, демонстрирующий всплывающее в точке клика окно с увеличенным (в заданном масштабе) фрагментом карты, показан на листинге 2.
1 var map;
2 var centerLatitude = 55.836385613416;
3 var centerLongitude = 37.538394927979;
4 var startZoom = 12;
5 function init() {
6 if (GBrowserIsCompatible()) {
7 map = new GMap2(document.getElementById("map"));
8 map.addControl(new GSmallMapControl());
9 map.addControl(new GMapTypeControl());
10 map.setCenter(new GLatLng(centerLatitude, centerLongitude), startZoom);
11 GEvent.addListener(map, "click",
12 function(overlay, latlng) {
13 map.showMapBlowup(new GLatLng(latlng.lat(), latlng.lng()), 3)
14 }
15 );
4 Получить ключ можно, зарегистрировавшись на сайте Google
16 }
17 }
18 window.onload = init;
19 window.onunload = GUnload;
Листинг 2. — Исходный JavaScript код
Первые 4 строки кода служат для объявления переменных, установки широты и долготы точки центра карты, а также для установки начального масштаба отображения. Строки 18-19 выполняют два важных действия. Они устанавливают: название функции для вызова после загрузки страницы (строка 18); название функции, вызываемой перед выходом (строка 19) по ссылке со страницы5. События, обрабатываемые приложением, использующим Google maps, обрабатываются с помощью объекта GEvent. Обработчик кликов по карте (строки 11-15) принимает в качестве 3-го параметра функцию обратного вызова (строки 12-14). Действием этой функции (строка 13) является размещение над картой всплывающего окна (метод showMapBlowup) с фрагментом карты и указателем на точку, соответствующую координатам клика (показаны параметром GLatLng(latlng.lat(), latlng.lng()) ), с масштабом отображения задаваемым 2-м параметром. Начальный код init() создает карту (строка 7), добавляет к карте элементы управления (строки 8-9), отображает карту, центрируя ее в заданной точке (строка 10).
На рис. 1-2 показаны два способа отображения всплывающего окна с увеличенным масштабом фрагмента карты.
Рис. 1. Развязка в районе платформы Рис. 2. Развязка в районе платформы Ленинградская (карта) Ленинградская (спутник)
5 Функция GUnload освобождает память от размещенных в ней объектов, используемых приложением.
3. Разметка карты маркерами
Маркеры — это интерактивные элементы приложения, позволяющие пользователю с помощью кликов или касаний экрана получить информацию об объекте, размещенном в некоторой точке карты. Для изображения маркеров можно применять различные пиктограммы, по умолчанию в Google Maps используются пиктограммы, изображающие перевернутую каплю. В Листинге 1 строчка 5 задает ссылку на PHP сценарий, направляющий приложению JavaScript код, определяющий некоторые объекты программы. Для примера рассмотрим определение этим сценарием маркеров с простым текстовым описанием определяемых объектов. Пусть сценарий map_data.php генерирует следующий код:
1 var markers = [
2 { 'latitude': 37.547148, 'longitude': 55.834516, 'name': 'Памятник Прянишникову'},
3 { 'latitude': 37.549385, 'longitude': 55.833486, 'name': 'Памятник Вильямсу'},
4 { 'latitude': 37.550757, 'longitude': 55.833166, 'name': 'Памятник Тимирязеву'},
5 { 'latitude': 37.549745, 'longitude': 55.83366, 'name': '27 трамвай, остановка ТСХА'}
6 ]
Листинг 3. — Определение маркеров
В строках 1-5 Листинга 3 определяется JavaScript массив markers, элементами которого являются 4 объекта (строки 2-5). Каждый объект определяет отдельный маркер, у каждого маркера задаются свойства: широта — 'latitude', долгота — 'longitude' и краткое описание -'name'. Эти свойства используются для позиционирования маркера и отображения относящейся к маркеру информации по клику6. На рис. 3-4, показано отображение массива маркеров на карте.
Покажем привязку маркеров к карте. В Листинге 2 (строки 5-12) необходимо изменить функцию init(). Новая функция показана на Листинге 4, она отличается от рассмотренной ранее, добавленными строками 7-9.
6 Поскольку в момент клика объект-маркер доступен программе-обработчику, то возможным становится не только отображение текстовой, но и другой медиаинформации.
EByf^ I Карта I Спутник | Гибрид ] | Карта | Спутник | Гибрид ]
шш mm
щ ш
Рис. 3. Массив маркеров (Листинг 3), Рис. 4. Отображение текстовой отображенный на карте информации об объекте
1 function init() {
2-6
7 for(i in markers) {
8 addMarker(markers[i].latitude, markers[i].longitude, markers[i].name);
9 }
10-11 ... завершение init()
Листинг 4 — Модифицированная функция инициализации приложения
Строки 2-6 (Листинг 4) точно такие же, как строки 6-10 Листинга 2, строки 10-11 завершают init(). Основные действия с массивом markers заданы в строках 7-9. Цикл for просматривает все маркеры, для каждого маркера вызывается функция addMarker(...). Функция предназначена для привязки маркера к событиям (клик или касание). Первые два параметра addMarker () задают широту и долготу точки привязки маркера, третий параметр определяет описание объекта маркера. Покажем код для выполнения требуемых в addMarker() действий.
1 function addMarker(longitude, latitude, description) {
2 var marker = new GMarker(new GLatLng(latitude, longitude));
3 GEvent.addListener(marker, 'click',
4 functionO {
5 marker.openlnfoWindowHtml(description);
6 }
7 );
8 map.addOverlay(marker);
9 }
Листинг 5. — Добавление маркера к карте
В строке 2 Листинга 5 создается объект класса GMarker (локальная переменная marker). Этот объект привязывается к карте (глобальная переменная map) в строке 8. События в картах Google обрабатываются классом GEvent. В строках 3-7 событие «click» привязывается к размещаемому на карте маркеру. Анонимная функция-обработчик (строки 4-6) выполняет простое действие: выводит в информационное окно (строка 5) сообщение description7.
4. Создание новых маркеров
В рассматриваемых приложениях существующие маркеры, размечающие карту, должны после загрузки приложения считываться с сервера. Если необходимо, то новые маркеры добавляются пользователем к карте и сохраняются на сервере. Иллюстрирующая процессы обмена схема показана на рис. 5.
Рис. 5. Добавление и считывание маркеров
7 Параметр description может быть представлен HTML кодом.
Как показано на схеме, добавление маркера инициируется пользователем. Действие пользователя вызывает появление всплывающего окна с формой для данных. Заполненная форма может быть удалена с экрана (в этом случае маркер к карте не добавляется) или сохранена на сервере (кнопка «save»). Нажатие «save» приводит к вызову JavaScript функции storeMarker(). Эта функция (1) собирает требуемые данные, а затем вызывает (3) серверный сценарий storeMarker.php. Исполняемые этим сценарием действия добавляют описание маркера к данным, уже имеющимся в файле data.xml. Таким способом обеспечивается добавление маркеров при разметке карты.
Запуск приложения на ИМУ начинается с подключения к картографическому сервису Google Maps. После отображения карты приложение считывает информацию о маркерах с сервера. Для выполнения этих действий приложение вызывает функцию retrieveMarkers(). Функция отправляет запрос к серверу, который выполняет сценарий retrieveMarker.php, после чего возвращает приложению информацию о маркерах в виде XML объекта. Далее полученная приложением информация отображается на карте.
Рассмотрим добавление маркеров подробнее. Для этой задачи функция init() достаточно сложная, поэтому приведем ее полностью (Листинг 6).
1 function init() {
2
... retrieveMarkers();
8
9 GEvent.addListener(map, "click",
10 function(overlay, latlng) {
11
12 var inputForm = document.createElement("form");
13 inputForm.setAttribute("action","");
14 //Установить действие по submit
15 inputForm.onsubmit = function() {storeMarker(); return false;};
16
17 var Ing = latlng.lngO;
18 var lat = latlng.lat();
19 inputForm.innerHTML = '<fieldset style="width:150px;">'
20 + '<Iegend>HoBbM MapKep</Iegend>'
21 + '<label for="found">T/m</IabeI>'
22 + '<input type="text" ¡d="found" style="width:100%;"/>'
23 + '<label for="left">Название</label>'
24 + '<input type="text" id="left" styIe="width:100%;"/>'
25 + '<input type="submit" value="Save"/>'
26 + '<input type="hidden" id="longitude" value="' + Ing + '"/>'
27 + '<input type="hidden" id="latitude" value="' + lat + '"/>'
28 + '</fieIdset>';
29 map.openlnfoWindow (IatIng,inputForm);
30 });//Завершается обработчик клика
31 }//if
32 }//init()
Листинг 6. — Инициализация приложения
Строки 2-7 функции повторяют ранее разобранный код. В строках 8-30 показано добавление функции обработки кликов по карте. Особенностью является необходимость — в ответ на клик по новой точке вывести пользователю форму, запрашивающую информацию о маркере. Такая форма, как элемент HTML, создается в строке 12. В строке 15, устанавливается реакция формы на нажатие кнопки «submit», определяемой в строке 25. Поля формы создаются строками 19-28. Далее id, установленные для созданных полей, будут использованы для подготовки информации, пересылаемой на сервер.
В строке 29 функции init() открывается информационное окно, содержащее созданную форму. Рис. 6, демонстрирующий форму, выведенную в точке клика, приведен ниже.
Данный карты исгЕапьдовапи
Рис. 6. Форма для ввода данных
5. Сохранение маркеров на сервере
После заполнения формы и нажатия кнопки «save» вызывается функция storeMarker(). Ее задача - собрать данные, требуемые для пересылки на сервер, сформировать, выполнить и обработать XmlHttp запрос для пересылки данных. Эта часть использует технологии AJAX и может быть выполнена различными способами (например, с помощью стандартного XmlHTTP запроса [2] или с помощью jQuery [3]). Google предлагает использовать свою версию AJAX запросов.
Приведем (Листинг 7) код функции storeMarker().
1 function storeMarker(){
2 var Ing = document.getElementById("longitude"). value;
get3lem entById("Iatitude").vaIue;
4 var getVars = "?type=" + document.getEIementById("found").vaIue
5 + "&name=" + document.getEIementById("Ieft").vaIue
6 + "&lng=" + Ing
7 + "&lat=" + lat
8 + "&icon=" +'default';
9 var request = GXmIHttp.create();
10
11 request.onreadystatechange = function() {
12 if (request.readyState == 4) {
//запрос завершен
13
14 var responseNode = xmlDoc.documentEIement;
15 var type = responseNode.getAttribute("type");
16 var content = responseNode.firstChild.nodeValue;
//Проверка ошибки
17
18
19 } else {
//Создать маркер и добавить его к карте
20 var latlng = new GLatLng(parseFIoat(Iat),parseFIoat(Ing));
21 var marker = createMarker(IatIng, content);
22 map.addOverlay(marker);
//Закрыть форму
23 map.closeInfoWindow();
24 }
25 }
26 }//onreadystatechange
//Отправить запрос
27 request.send(null);
28 return false;
29 }// storeMarker
Листинг 7. — Подготовка данных, создание, вызов и обработка запроса
Для взаимодействия с сервером используется стандартный запрос GET. Данные для запроса подготавливаются в строках 2-8 Листинга 7. В строках 9-10 создается и открывается для пересылки на сервер запрос. Функция-обработчик смены состояния запроса приводится в строках 11-26. Запрос завершается успешно, если статус состояния (строка 12) равен 4. В этом случае формируется XML объект и проверяется успешность ответа со стороны сервера (строки 13-18). Если ответ успешен (строки 19-24), то по аналогии с функцией addMarker() создается маркер (строка 21), который добавляется к карте, после чего окно с формой закрывается. Созданный запрос отправляется к серверу (строка 27).
Для справки приведем код сценария storeMarker.php (Листинг 8).
1 <?php
2 header('Content-Type: text/xml');
3 $lat = (float)$_GET['lat'];
4 $lng = (float)$_GET['lng'];
5 $found = $_GET['type'];
6 $left = $_GET['name'];
7 $icon = $_GET['icon'];
//Создать XML узел
8 $marker = '<marker lat="'.$lat.'" lng="'.$lng.'" type="'.$found.'" name="'.$left.'" icon="'.$icon.'"/>';
//открыть файл data.xml file для добавления
9 $f=fopen('data.xml', 'a+');
10 if(!$f) die('<?xml version="1.0"?>
11 <response type="error"><![CDATA[Could not open data.xml file]]></response>');
//добавить узел
12 $w=fwrite($f, $marker);
13 if(!$w) die('<?xml version="1.0"?> <response type="error"><![CDATA[Could not write to data.xml file]]></response>');
14 fclose($f);
15 $newMarkerContent = "<div><b>T/m: </b>$found</div><div><b>Название: </b>$left</div>";
16 echo '<?xml version="1.0"?><response type="success"><![CDATA[ '.$newMarkerContent.']]></response>';
17 ?>
Листинг 8. — Серверный сценарий
В первых (3-7) строках Листинга 8 сценарий выбирает переданные ему через запрос GET параметры. В строке 9 сценарий открывает файл data.xml для добавления. Если файл открыть не удалось, то формируется и пересылается клиентскому приложению XML документ, отмечающий (строка 11) появление ошибки.
В случае успешного открытия файла, в конец файла data.xml дописывается новый узел (строки 12-14), после чего клиентскому приложению возвращается XML с описанием вновь добавленного маркера. Приложение самостоятельно решает, что с этим описанием делать. Три интерактивно добавленных маркера с окном описания показаны на рис. 7.
Goqgle
Рис. 7. Вариант разметки
Содержимое файла data.xml с тремя маркерами будет следующим (Листинг 9):
1 <marker lat="55.836482011121" lng="37.538394927979" type="Перекресток" name="Б.Академическая/Прянишникова" icon="default"/>
2 <marker lat="55.836674805814" lng="37.575645446777" type^'Cranm,^ метро" ^^^^Петровско-Разумовская" icon="default"/>
3 <marker lat="55.847084299785" lng="37.590236663818" type^'Crabm^ метро" name="Владыкино" icon="default"/>
Листинг 9. — Содержимое файла data.xml
6. Выборка маркеров с сервера
На Листинге 6 в функции начальной инициализации программы показан вызов функции retrieveMarkers(). Эта функция считывает и размещает на карте маркеры, определенные в файле data.xml. Запрос к серверному сценарию retrieveMarkers.php подготавливается также, как и в функции saveMarker(). Серверный сценарий считывает файл data.xml, добавляет к нему заголовок и корневой узел, после чего пересылает клиентскому приложению. Эти действия нетрудно записать по аналогии с рассмотренными ранее.
7. Выводы
В части 1 статьи на примере геоинформационного приложения рассмотрены методы обмена данными через файловую систему сервера. Использование общего файла data.xml позволяет клиентским приложениям добавлять (для дальнейшего совместного использования) данные, поставляемые клиентскими приложениями. В статье приводится пример текстовых данных, но показанные технологии хранения применимы и к медиаданным. В статье рассмотрено подключение web-при-ложений к геоинформационным сервисам, приведены типовые задачи (нанесение, обработка, добавление маркеров, размечающих карту). Показано взаимодействие клиентского приложения с серверными сценариями. Подобное поведение позволяет мобильным приложениям обмениваться информацией через сервер. В части 2 статьи будут показаны механизмы непосредственного обмена медиаданными между мобильными устройствами на примере рассмотренного картографического приложения.
Библиографический список
1. PurvisM,SambelSsJ, TurnerC. Beginning Google Maps Applications with PHP and Ajax From Novice to Professional. 2008, Apress — 358 pp.
2. МарковА.А. Разработка WEB-приложений для iPhone/iPod Touch. Часть I. Работа с данными : учеб. пособие / А.А. Марков. — М. : МГУП, 2009. — 106 с.
3. Бер Бибо. jQuery. Подробное руководство по продвинутому JavaScript / Бер Бибо, Иегуда Кац. — 2011, Символ-Плюс — 384 с.