Сейчас на рынке много предложений по продаже мобильных устройств, предназначенных для контроля движущихся объектов или трекеров. В большинстве из них есть функция передачи информации по GPRS на любой заданный веб-адрес через определенный интервал времени. Чаще всего формат передачи данных разный. Поэтому мы не будем рассматривать вопрос загрузки данных с трекера в базу. Предположим данные есть и мы хотим приступить к созданию сервиса мониторинга транспорта. Основу такой системы образуют возможности: // Создаем слои-карты VirtualEarth var vectorImage = new OpenLayers.Layer.Vector("Картинки", } }
-выбор карты и ее отображение
-отображение точки или картинки и подписи к ней
-отображение полигона и его редактирование
-отображение линии и ее редактирование
-отображение информации связной с полигонами, линиями, точками (всплывающие подсказки)
-немного математики (подсчет пройденного пути, площадь полигона, принадлежность точки полигону)
Все эти функции легко реализовать с помощью OpenLayers, библиотеки на JavaScript.
Выбор карты и ее отображение
Для этого на вашей страничке нужно создать элемент div c нужными размерами. В нем и будет отображаться карта. Пример:
div id="map" style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
Подключить OpenLayers:
script type="text/javascript" src="Scripts/OpenLayers.js"
Создать глобальную переменную map, в которой будет храниться объект карты. Создать вызов функции на событие загрузки страницы, в которой будет код непосредственного создания карты. Пример:
body onload="LoadMap()"
Описать функцию LoadMap:
//Границы задаются для проекции EPSG:900913.
var maxExtent = new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508);
var restrictedExtent = maxExtent.clone();
var maxResolution = 156543.0339;
//Отображаться карта будет в проекции EPSG:4326.
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
numZoomLevels: 18,
maxResolution: maxResolution,
maxExtent: maxExtent,
restrictedExtent: restrictedExtent
};
//Создаем карту
map = new OpenLayers.Map('map', options);
var veroad = new OpenLayers.Layer.VirtualEarth("Virtual Earth Roads", { 'type': VEMapStyle.Road, sphericalMercator: true });
var veaer = new OpenLayers.Layer.VirtualEarth("Virtual Earth Aerial", { 'type': VEMapStyle.Aerial, hericalMercator: true });
var vehyb = new OpenLayers.Layer.VirtualEarth("Virtual Earth Hybrid", { 'type': VEMapStyle.Hybrid, sphericalMercator: true });
// Создаем слои-карты OpenStreet
var mapnik = new OpenLayers.Layer.OSM();
//Добавляем подсказку масштаба карты и позици курсора
map.addControl(new OpenLayers.Control.ScaleLine());
map.addControl(new OpenLayers.Control.MousePosition());
//Складываем созданные слои в объект OpenLayers.Map
map.addLayers([ mapnik, veroad, veaer, vehyb]);
//Добавляем панель управления слоями
map.addControl(new OpenLayers.Control.LayerSwitcher());
//Создаем точку на которую будет центрироваться карта при старте
var point0 = new OpenLayers.Geometry.Point(37.600328, 55.574624);
//Помним что карта отображается в одной проекции, а с данными работает в другой проекции.
point0.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
//Выполняем центрирование карты на точку с масштабом 9. По умолчанию их 15.
map.setCenter(new OpenLayers.LonLat(point0.x, point0.y), 9);
}
На сайте проекта openlayers можно найти много примеров, около двухсот. Пример визуализации карты из заданного сервиса, можно увидеть здесь. Большинство решаемых задач в статье эти примеры покрывают. В представленном коде отсутствует присоединение карт google и yandex, для работы этих карт нужны ключи. Вы должны зарегистрироваться, получить ключ доступа к сервису и только после этого можно подсоединяться к этим сервисам. Результат кода выше:
Отображение точки или картинки и подписи к ней
Создаем слои, которые будет хранить наши объекты(точки и картинки).
//Создаем объект стиля отображения картинок. Указываем параметры ширены, высоты, сдвига по вертикале относительно точки, подпись(${} - это объявление параметра, можно выводить константу для всех точек), url к графику, размер шрифта.
var styleImage = new OpenLayers.Style(
{
graphicWidth: 21,
graphicHeight: 25,
graphicYOffset: -28,
label: "${label}",
externalGraphic: "http://www.openlayers.org/dev/img/marker.png",
fontSize: 12
});
//labelYOffset - сдвиг текста по вертикале относительно точки
var stylePoint = new OpenLayers.Style(
{
pointRadius: 5,
strokeColor: "red",
strokeWidth: 2,
fillColor: "lime",
labelYOffset: -16,
label: "${label}",
fontSize: 16
});
//Создаем слой для точек. В свойстве styleMap указываем как отображать в обычном случае. Свойство select будет применено после выбора элемента.
var vectorPoint = new OpenLayers.Layer.Vector("Точки",
{
styleMap: new OpenLayers.StyleMap(
{ "default": stylePoint,
"select": { pointRadius: 20}
})
});
//В отличие от слоя с точками, где выделение объекта взывает увеличение радиуса точки, на слое с картинками будет их поворот на 45 градусов
{
styleMap: new OpenLayers.StyleMap(
{ "default": styleImage,
"select": { rotation: 45}
})
});
//Складываем слои на карту
map.addLayer(vectorImage );
map.addLayer(vectorPoint );
Слои созданы, создаем функции которые будут работать со слоями.
//Функция добавляет изображение с подписью. Аргументы: долгота, широта, подпись, уникальный идентификатор, слой. В случае, если объект уже есть функция сдвигает его в новое положение.
function addImg(lon,lat,title,ident, layr){
var ttt = new OpenLayers.LonLat(parseFloat(lon), parseFloat(lat));
ttt.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
// features-массив объектов на карте. Объект может быть например: точкой, полигоном, кривой, изображением
for (var k = 0; k < layr.features.length; k++)
{
// У объектов features есть атрибуты, как предопределенные так и добавленные пользователем
if(layr.features[k].attributes.ImgId==ident) {
// move - функция перемещения объекта в данную точку
layr.features[k].move(ttt);
layr.features[k].attributes.label=title;
return false;
}
var point0 = new OpenLayers.Geometry.Point(parseFloat(lon), parseFloat(lat));
point0.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
//Для создание объекта Feature использовался класс OpenLayers.Feature.Vector
layr.addFeatures(new OpenLayers.Feature.Vector(point0, { label: title, name: title, ImgId: ident }));
}
function addPoint(lon,lat,title,ident){
var ttt = new OpenLayers.LonLat(parseFloat(lon), parseFloat(lat));
ttt.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
for (var k = 0; k < map.layers[5].features.length; k++)
{
if(map.layers[5].features[k].attributes.PointId==ident) {
map.layers[5].features[k].move(ttt);
map.layers[5].features[k].attributes.label=title;
return false;
}
var point0 = new OpenLayers.Geometry.Point(parseFloat(lon), parseFloat(lat));
point0.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
map.layers[5].addFeatures(new OpenLayers.Feature.Vector(point0, { label: title, name: title, PointId: ident }));
}
Теперь осталось выполнить добавление точек и изображений:
addPoint(37,55.5,'Точка 1','1',map.layers[4]);
addPoint(37,55.1,'Точка 2','2',map.layers[4]);
addImg(37,55.6,'Изображение 1','2',map.layers[5]);
addImg(37,55.9,'Изображение 2','2',map.layers[5]);
Результат:
Добавилось только одно изображение потому, что вызов функции был с одинаковыми идентификаторами изображений. Объект сместился, название было изменено на новое.
Отображение полигона и его редактирование
Функция создания полигона:
//Предполагаемый форма данных: координаты разделены точкой с запятой, долгота с широтой разделены пробелом
function addPoly(data,title,ident,layr){
var featuress = Array();
var coords = data.split(';');
for (var i = 0; i < coords.length; i++) {
var d = coords[i].split(' ');
var ttt = new OpenLayers.LonLat(parseFloat(d[0]), parseFloat(d[1]));
var point0 = new OpenLayers.Geometry.Point(ttt.lon, ttt.lat);
point0.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
featuress.push(point0);
}
//Массив точек порождает линию, из нее создается полигон
var linearRing2 = new OpenLayers.Geometry.LinearRing(featuress);
var polygonFeature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([linearRing2]), { label: title, PolyID: ident });
layr.addFeatures(polygonFeature2);
}
Пример вызова функции прорисовки полигона:
addPoly('37 55.9;37.5 55.4;37 55','Полигон','1',map.layers[5]);
Редактирование в OpenLayrs осуществляется с помощью OpenLayers.Control.ModifyFeature. Нужно создать экземпляр этого класса указав слой объекты которого нужно модифицировать:
var modef = new OpenLayers.Control.ModifyFeature(map.layers[5])
modef.clickout = false;
modef.toggle = false;
modef.standalone = true;
map.addControls([ modef]);
modef.activate();
//Выбираем созданный полигон
modef.selectFeature(map.layers[5].features[2]);
//Получаем центр полигона
var centr = map.layers[5].features[2].geometry.getCentroid()
//Карту центрируем по полученной точке
map.setCenter(new OpenLayers.LonLat(centr.x, centr.y));
Каждая вершина полигона в момент редактирования обозначается точкой и в силу того, что полигон мы разместили на слое для точек, к ним был применен стиль этого слоя. Результат: подписи «undefined» у вершин полигона. Это приме того, что для каждого типа объектов лучше создавать отдельные слои. Пример отображения режима редактирования:
Выход из режима редактирования:
modef.deactivate();
Отображение линии и ее редактирование
Как было уже сказано, полигон создается из линии, таким образом в функции AddPoly нужно изменить одну строку:
layr.addFeatures(polygonFeature2);
на
layr.addFeatures(linearRing2 );
Процесс редактирование ничем не отличается.
Всплывающие подсказки
Для реализации всплывающей подсказки нужно добавить на карту обработчик событий, который представляет собой экземпляр класса: OpenLayers.Control.SelectFeature.
var selectControl = new OpenLayers.Control.SelectFeature([map.layers[5]]);
map.addControls([selectControl],
{
clickout: true, toggle: false,
multiple: false, hover: true,
toggleKey: "ctrlKey",
multipleKey: "shiftKey"
});
selectControl.activate();
После этого будет происходить обработка нажатий на объекты слоев. Точки будут увеличиваться в размере, картинки поворачиваться на 45 градусов. Создаем обработчик события выделения точки:
//Событие on - это событие выделения
map.layers[5].events.on( {
"featureselected": function (e) {
var HTMLcontent;
var point
//Здесь можно генерировать любой контент
HTMLcontent = 'table style="width: 100%;" tr td Информация об объекте td tr table ';
//getCentroid() - получить центр фигуры, в данном случае лишнее, но это унифицированный способ получения места всплытия подсказки
point = new OpenLayers.LonLat(e.feature.geometry.getCentroid().x, e.feature.geometry.getCentroid().y);
//OpenLayers.Popup.AnchoredBubble - всплывающий прямоугольник, есть другие варианты в OpenLayers.Popup
var popup = new OpenLayers.Popup.AnchoredBubble("SDVegetationInfo",
point,
new OpenLayers.Size(100, 100),
HTMLcontent,
null,
false);
popup.opacity = 0.9;
popup.autoSize = true;
popup.setBackgroundColor("#bcd2bb");
//добавление на карту
map.addPopup(popup, true);
}
// когда выделение убрано, через секунду окно погаснет
, "featureunselected": function (e) {
setTimeout('if(map.popups.length - 1>-1){map.removePopup(map.popups[map.popups.length - 1]);}', 1000);
}
});
Подсчет пройденного пути, площадь полигона, принадлежность точки полигону
Подсчет пройденного пути
map.layers[4].features[2].feature.geometry.getLength()
площадь полигона
map.layers[4].features[2].feature.geometry.getArea()
принадлежность точки полигону
map.layers[4].features[2].containsPoint(map.layers[4].features[0])
Результат всех предыдущих действий можно увидеть на странице: ссылка
В заключение отмечу, что многое компании уже сделали свои трекеры на OpenLayers это дешево и просто. Документацию по OpenLayers можно найти тут.
Автор: RedQuark, OpenLayers или делаем сервис мониторинга транспорта