Разработка серверной части

LoadingObjectManager производит все операции с объектами на стороне клиента. К таким операциям относятся: создание оверлеев, их отрисовка, кластеризация объектов и т. д. Однако информация об объектах хранится на сервере, и менеджер будет обращаться к нему для получения нужных данных.

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

  1. Организовать хранение данных на сервере.

  2. Настроить обработку запросов, поступающих от клиентской части.

  3. Настроить ответ сервера в нужном формате.

Размещение данных на сервере

Для хранения информации о географических объектах целесообразно использовать пространственные базы данных. Для многих СУБД существуют расширения, позволяющие организовывать доступ к пространственным объектам. Например, для MySQL — это SPATIAL, для PostgreSQLPostGIS. Также пространственные индексы поддерживают и другие стандартные базы данных, например, Oracle, MongoDB.

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

Обработка запросов менеджера

В зависимости от того, каким способом менеджер будет запрашивать данные (для всей видимой области сразу или по тайлам, по географическим координатам или по номерам тайлов), на сервер будут отправляться GET-запросы с разными параметрами. Ниже рассмотрены форматы запросов, которые менеджер будет отправлять на сервер при разных способах загрузки данных:

1. Данные запрашиваются сразу для всей видимой области по ее географическим координатам

Пример запроса, который отправит менеджер:

GET https://my-server.ru/?bbox=55.3589,36.2109,56.1519,39.0234&callback=myCallback_55_3589_36_2109_56_1519_39_0234

где:

  • bbox – координаты левого нижнего и правого верхнего углов области;
  • callback – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе Формат ответа сервера.

Чтобы менеджер запрашивал данные таким способом, необходимо при создании менеджера:

  • в параметре urlTemplate использовать подстановку %b.

Например:

// Создадим менеджер и передадим ему шаблон URL данных.
// В шаблоне будем использовать подстановку %b, которая
// заменяется на массив географических координат области (подробнее о подстановках).
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?bbox=%b', {
        // Шаблон названия callback-функции, в которую сервер должен обернуть ответ.
        paddingTepmlate: "myCallback_%b"
    });

Рекомендации по размещению данных на сервере

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

2. Данные запрашиваются сразу для всей видимой области по номерам угловых тайлов

Пример запроса, который отправит менеджер за данными:

GET https://server.ru/?tileBounds=615,319,622,322&z=10&callback=myCallback_615_319_622_322_10 

где:

  • tileBounds – номера левого верхнего и правого нижнего тайлов;
  • z — коэффициент масштабирования;
  • callback – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе Формат ответа сервера.

Чтобы менеджер запрашивал данные таким способом, необходимо:

Например:

// Создадим менеджер и передадим шаблон URL с подстановками %t и %z (подробнее о подстановках).
// %t – заменяется на последовательность номеров угловых тайлов области. Номера перечисляются через запятую.
// %z – заменяется на уровень масштабирования.
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?tileBounds=%t&z=%z', {
        // Шаблон названия callback-функции, в которую сервер должен обернуть ответ.
        paddingTemplate: 'myCallback_%t_%z'
    });

Рекомендации по размещению данных на сервере

При таком формате запроса можно настроить в базе составной индекс с ключами x, y и z, где x – номер тайла по X, y – номер тайла по Y и z – коэффициент масштабирования (подробнее о составных индексах). Тогда можно получить выборку из базы, опираясь на сформированный ключ, аналогично работе с географическими координатами.

Рекомендации по кэшированию ответа

В зависимости от действий пользователя на карте размеры запрашиваемых областей будут разными. По этой причине оптимальнее кэшировать выборку из базы потайлово. Поскольку серверу передается параметр tileBounds, содержащий номера первого и последнего тайлов области, нетрудно определить номера остальных тайлов, входящих в эту область. Тогда при запросе данных для некоторой тайловой области нужно «склеить» ответ из данных по каждому тайлу в составе области и отправить ответ на клиент.

Существует множество инструментов, позволяющих реализовать кэширование данных на сервере (например memcached или redis). В качестве ключа кэширования можно использовать параметры x, y, z.

3. Данные запрашиваются по тайлам по географическим координатам

Примеры запросов, которые менеджер будет отправлять на сервер:

GET https://server.ru/?bbox=55.5587,36.2109,55.7574,36.5625&callback=myCallback_55_5587_36_2109_55_7574_36_5625
GET https://server.ru/?bbox=55.7574,36.2109,55.9552,36.5625&callback=myCallback_55_7574_36_2109_55_9552_36_5625
GET https://server.ru/?bbox=55.3589,36.2109,55.5587,36.5625&callback=myCallback_55_3589_36_2109_55_5587_36_5625 
...

где:

  • bbox – координаты левого нижнего и правого верхнего углов тайла;
  • callback – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе Формат ответа сервера.

Чтобы менеджер запрашивал данные таким способом, необходимо:

Например:

// Создадим менеджер, который будет запрашивать данные отдельно по тайлам.
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?bbox=%b', {
        splitRequests: true,
        paddingTemplate: myCallback_%b
    });

Рекомендации по размещению данных на сервере

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

Рекомендации по кэшированию

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

4. Данные запрашиваются по тайлам по номерам этих тайлов

Пример запросов, которые будет формировать менеджер:

GET https://server.ru/?x=622&y=319&z=10&callback=myCallback_x_622_y_319_z_10 
GET https://server.ru/?x=622&y=321&z=10&callback=myCallback_x_622_y_321_z_10  
GET https://server.ru/?x=622&y=322&z=10&callback=myCallback_x_622_y_322_z_10
... 
  • x – номера тайла по оси X;
  • y – номер тайла по оси Y;
  • z – коэффициент масштабирования;
  • callback – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе Формат ответа сервера.

Чтобы менеджер запрашивал данные таким способом, необходимо:

Например:

// Создадим менеджер, который будет запрашивать данные отдельно по тайлам.
var loadingObjectManager = new ymaps.LoadingObjectManager('http://server.ru/?%c', {
        splitRequests: true,
        // Такой шаблон доступен только при splitRequests=true.
        paddingTemplate: myCallback_%c 
    });

Примечание

Обратите внимание, подстановка '%c' доступна только при splitRequests=true.

Рекомендации по размещению данных на сервере

При таком формате запроса можно настроить в базе составной индекс с ключами x, y и z (подробнее о составных индексах).

Рекомендации по кэшированию

Когда клиент запрашивает данные потайлово, он формирует конечное число запросов к серверу (карта состоит из конечного числа тайлов). Чтобы при поступлении нового запроса каждый раз не обращаться к базе данных, для каждого запроса можно кэшировать ответ. В качестве ключей кэширования можно установить параметры запроса: x, y, z. Для реализации серверного кэширования можно использовать memcached или, например, redis.

Формат ответа сервера

При получении запроса со стороны клиента на сервере необходимо:

  1. сформировать JSON-описание объектов для запрашиваемой области;
  2. обернуть JSON-описание в callback-функцию;
  3. отправить ответ клиенту.

Структура JSON-описания объектов

Описание объектов должно представлять собой GeoJSON-подобную структуру:

{
  "type": "FeatureCollection",
  "features": [
      ... 
  ]
}

Поле features – это массив объектов (меток, кругов, линий и пр.), которые входят в запрашиваемую область. Каждый объект описывается следующими полями:

Поле

Тип

Описание

type*

String

Поле должно всегда иметь значение "Feature".

id*

Number

Уникальный идентификатор объекта. Разработчик должен сформировать идентификаторы объектов самостоятельно.

"id": 0

geometry*

Object

Геометрия объекта. Содержит поля:

  • type – тип геометрии объекта. Доступные значения: «Point»(метка), «LineString»(линия), «Cicrle»(круг), «Polygon»(многоугольник).
  • coordinates – координаты объекта. Следует задавать в той последовательности, которая указана в параметре coordorder (если параметр не задан, используется последовательность «широта, долгота»).
  • radius (только для объекта с типом «Circle») – радиус круга в метрах.
Примеры задания геометрии

Для метки:

"geometry": {
    "type": "Point",
    "coordinates": [55.780898, 37.642889]
}

Для линии:

"geometry": {
    "type": "LineString",
    "coordinates": [
        [55.780898, 37.642889],
        [55.780898, 37.642889]
    ]
}

Для многоугольника:

"geometry": { 
    "type": "Polygon",
    "coordinates": [
        [55.801280971180454, 37.552642822265625],
        [55.81285742969946, 37.518310546875],
        [55.8367712028016, 37.540283203125],
        [55.801280971180454, 37.552642822265625]
    ]
}

Для круга:

"geometry": {
    "type": "Circle",
    "coordinates": [55.780898, 37.642889],
    "radius": 1000
}

Для кластера:

"geometry": {
    "type": "Point",
    "coordinates": [55.780898, 37.642889]
}

properties

Object

Свойства объекта (например, содержимое балуна или метки). Список доступных свойств описан в классе GeoObject. Кроме того, в свойствах могут быть указаны произвольные поля.

Пример:

"properties": {
    "balloonContent": "Текст балуна",
    "clusterCaption": "Метка 1",
    "hintContent": "Текст подсказки",
    "myDescription": "Произвольное описание"
}

options

Object

Опции объекта (например, стиль метки или цвет линии). Список доступных опций описан в классе GeoObject.

"options": {
    "preset": "islands#yellowIcon"
}

* Обязательное поле.

Пример JSON-описания объектов
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": 0,
      "geometry": {
        "type": "Point",
        "coordinates": [55.831903, 37.411961]
      },
      "properties": {
        "balloonContent": "Содержимое балуна",
        "clusterCaption": "Метка 1",
        "hintContent": "Текст подсказки"
      }
    },
    {
      "type": "Feature",
      "id": 1,
      "geometry": {
        "type": "Point",
        "coordinates": [55.763338, 37.565466]
      },
      "properties": {
        "balloonContent": "Содержимое балуна",
        "clusterCaption": "Метка 2",
        "hintContent": "Текст подсказки"
      }
    }
  ]
}

Внимание

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

Оборачивание JSON-описания в callback

Менеджер и сервер обмениваются данными в формате JSONP.
Это означает, что сервер должен возвращать менеджеру JSON-описание, обернутое в
callback-функцию:

callback_function({
  "type": "FeatureCollection",
  "features": [
    ... 
  ]
})

Имя функции, в которую сервер должен обернуть ответ, менеджер будет формировать
автоматически и передавать в запросе в GET-параметре callback:

/?callback=id_436554526&...

При создании менеджера можно задать шаблон, на основе которого менеджер будет формировать
имена callback-функций. Для этого предназначена опция paddingTemplate:

// Создание менеджера. 
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/tile/?%c', {
        // Укажем шаблон для именования callback-функций.
        paddingTemplate: 'myCallback_%c',
        splitRequests: true
    });

Тогда для тайла с номером [1,2] и z=5 менеджер отправит запрос по URL:

https://server.com/tile/?x=1&y=2&z=5&callback=myCallback_x_1_y_2_z_5

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

myCallback_x_1_y_2_z_5({
  "type": "FeatureCollection",
  "features": [
    ... 
  ]
})

Использование параметра paddingTemplate упростит реализацию серверной части, так как для каждого запроса серверу будут заранее известны названия callback-функции. Для каждого тайла JSON-описание можно формировать сразу обернутым в заданную callback-функцию и сохранять это описание в статическом файле.