Слои активных областей

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

При использовании класса YMaps.Hotspots.Overlay все активные области должны находиться на карте одновременно, поэтому при начальной загрузке карты в браузер приходится подгружать значительный объем JavaScript-кода. Создание слоя активных областей позволяет реализовать более экономную потайловую загрузку объектов и подгружать сведения об активных областях, необходимые только для текущего набора видимых тайлов.

Слой активных областей работает по принципу, схожему с обычным слоем карты. Обычный слой - это экземпляр класса YMaps.Layer, который отображает тайлы, поставляемые источником данных YMaps.TileDataSource. Тайлы представляют собой экземпляры класса YMaps.ImageTile. Этот класс реализует интерфейс YMaps.ITile, что дает возможность создавать пользовательские тайлы.

Слой активных областей - это экземпляр класса YMaps.Hotspots.Layer Он содержит в себе объекты YMaps.Hotspots.Object, поставляемые источником данных YMaps.Hotspots.ObjectSource, см. Источники данных.

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

Примечание. Все приведенные выше классы реализуют интерфейс YMaps.Hotspots.IShape.

Рассмотрим алгоритм загрузки тайлов для слоя активных областей.

Слой активных областей обрабатывает события сдвига карты и запрашивает объекты для новых тайлов в источнике объектов активных областей. Источник объектов с помощью специального загрузчика (это может быть, например, стандартный загрузчик YMaps.Hotspots.Loader) загружает новые данные с сервера. После разбора данные передаются методу createObject() источника объектов, где на выходе получается массив объектов, готовых для добавления на слой активных областей.

Для хранения данных об объектах слоев активных областей используются те же самые тайловые технологии, что и для обычных, "картиночных" слоев карты: данные раскладываются по квадратам 256х256 пикселов, нарезанным для всех уровней масштабирования.

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

  1. для "картиночных" тайлов с изображениями объектов;
  2. для тайлов с данными, содержащих описание объектов, изображенных на соответствующих картиночных тайлах.

Тайлы первого типа накладываются на карту с помощью обычных слоев - экземпляров класса YMaps.Layer; тайлы второго типа накладываются на карту с помощью слоев активных областей - экземпляров класса YMaps.Hotspots.Layer.

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

Источники данных

При создании слоя активных областей необходимо указать источник данных слоя, который отвечает за взаимодействие с веб-сервисом, поставляющим данные об активных областях. API Яндекс.Карт предоставляет интерфейс источника данных YMaps.Hotspots.IObjectSource и стандартную реализацию этого интерфейса, которая работает с определенным форматом ответа веб-сервиса.

Интерфейс содержит единственный метод:

requestObjects (callback, layer, tileNumber, zoom)

При вызове этого метода источник данных должен обратиться к веб-сервису и получить описание активных областей для слоя layer, находящихся в тайле с номером tileNumber при коэффициенте масштабирования zoom. На основе этого описания источник должен построить массив объектов YMaps.Hotspots.Object и передать его функции callback.

При этом отправку запроса к веб-сервису, обмен данными и построение массива объектов разработчику потребуется реализовать самостоятельно.

Стандартный источник данных YMaps.Hotspots.ObjectSource

API Яндекс.Карт предлагает собственный стандарт обмена данными с веб-сервисом и класс YMaps.Hotspots.ObjectSource, предназначенный для работы с веб-сервисами, поддерживающими этот формат.

Как только слой активных областей запрашивает новую порцию данных, источник данных формирует URL (см. ниже), по которому следует обратиться за списком областей:

http://my.server.ru/tiles?x=10&y=20&z=10

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

l=mylayer&x=10&y=20&z=10

При создании объекта YMaps.Hotspots.ObjectSource необходимо указать шаблон построения URL тайла и ключа запроса. Например, такие:

var objectSource = new YMaps.Hotspots.ObjectSource('http://my.server.ru/tiles?%c', 'l=mylayer&%c');

При формировании URL тайла и ключа сочетание символов %c автоматически заменяется на x=<номер тайла по горизонтали>&y=<номер тайла по вертикали>&z=<коэффициент масштабирования>. Также поддерживаются конструкции %d и %g, о которых подробнее можно узнать из описания класса YMaps.TileDataSource.

Кроме того, можно переопределить функции getTileUrl и getKey, чтобы задать собственные правила формирования URL тайла и ключа запроса, например:

var objectSource = new YMaps.Hotspots.ObjectSource('http://my.server.ru/tiles/', 'mylayer#');

objectSource.getTileUrl = function (tileNumber, zoom) {
    // Пусть URL тайла имеют вид 'http://my.server.ru/tiles/tile-x-y-z.png'
    return this.getTileUrlTemplate() + 'tile-' + tileNumber.getX() + '-' + tileNumber.getY() + '-' + zoom + '.png';
}

objectSource.getKey = function (tileNumber, zoom) {
    // Пусть ключ запроса имеет вид 'mylayer#x-y-z'
    return this.getKeyTemplate() + tileNumber.getX() + '-' + tileNumber.getY() + '-' + zoom;
}

В ответ на запрос по указанному URL веб-сервис должен вернуть описание активных областей в следующем формате:

YMaps.HotspotLoader.onLoad(
    // Ключ запроса
    "l=mylayer&x=<номер тайла по x>&y=<номер тайла по y>&z=<коэффициент масштабирования>",
    {
        // Массив объектов-активных областей на карте
        objects: [
            {
                // Данные, ассоциированные с объектом. Будут в неизменном виде переданы в созданные по описанию объекты
                data: {
                    // Здесь могут быть любые поля, например
                    // name: 'Объект',
                    // description: 'Описание объекта'
                    // ...
                },
                // Точка привязки. Задает географическую точку, от которой будет
                // строиться геометрия области. Используется только для удобства
                // вычислений и может не иметь никакого отношения к объекту.
                base: new YMaps.GeoPoint(0, 0),
                // Описание геометрии активной области.
                // Область описывается набором геометрических фигур на плоскости.
                geometry: [
                    // Все координаты задаются в пикселах на текущем масштабе,
                    // отсчитанных от точки привязки области.
                    {
                        // Форма фигуры. Допустимые значения:
                        // 'rect' - прямоугольник,
                        // 'cpoly' - выпуклый многоугольник,
                        // 'npoly' - невыпуклый многоугольник
                        shape: 'rect',
                        // Массив координат фигуры. Для прямоугольника -
                        // левый нижний и правый верхний углы
                        coords: [-10, 10, 10, -10]
                    },
                    // Такая форма записи - сокращенное описание прямоугольника
                    [-5, 20, 5, 15],
                    {
                        // Выпуклый многоугольник
                        shape: 'cpoly',
                        // Задается массивом координат вершин.
                        coords: [20, 0, 25, 10, 30, 0] // Треугольник с вершинами (20, 0), (25, 10) и (30, 0)
                    }
                    // ...
                ]
            }
            // ...
        ]
    }
);

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

Объекты слоя активных областей

Отдельные активные области в составе слоя представляются экземплярами класса YMaps.Hotspots.Object. Объект-активная область состоит из геометрического представления (аналогично YMaps.Hotspots.Overlay) и ассоциированных с объектом данных. И данные, и геометрия задаются при создании объекта параметрами конструктора и больше не изменяются.

Для работы с геометрией объекта предназачены следующие методы:

  • getNumShapes() - возвращает количество геометрических фигур, из которых составлен объект;
  • getShape(index) - возвращает конкретную фигуру по ее индексу.

Фигуры представляют собой объекты, реализующие интерфейс YMaps.Hotspots.IShape. В API предусмотрены три стандартных фигуры - прямоугольник, выпуклый многоугольник и невыпуклый многоугольник.

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

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

// Географические координаты -> пикселы на текущем масштабе
var pixelPoint = map.tileCoordinates.scale(map.coordSystem.fromCoordPoint(geoPoint), map.coordSystem.getMaxZoom(), map.getZoom());
// Пиксели на текущем масштабе -> географические координаты
var geoPoint = map.coordSystem.toCoordPoint(map.tileCoordinates.scale(pixelPoint, map.getZoom(), map.coordSystem.getMaxZoom()));

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

  • getData() - возвращает ассоциированные с объектом данные;
  • requestHintData(callback, event, shape) - формирует содержимое всплывающей подсказки в виде строки, HTML-элемента или объекта YMaps.ILayout и отдает его функции callback; здесь event - событие, инициировавшее появление всплывающей подсказки, а shape - фигура, над которой оно произошло;
  • requestBalloonData(callback, event, shape) - аналогичным образом формирует содержимое балуна.
Примечание. По умолчанию содержимым подсказки считается поле name ассоциированных с объектом данных (если такое есть), а содержимым балуна - HTML вида <h3>[$name]</h3><p>[$description]</p>. Для задания собственных правил формирования содержимого подсказки и/или балуна необходимо переопределить соответствующие методы.

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

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

Пользовательские формы геометрических фигур

Интерфейс YMaps.Hotspots.IShape описывает геометрические фигуры, которые могут отображаться на слое активных областей. Стандартные классы YMaps.Hotspots.RectShape, YMaps.Hotspots.CPolyShape и YMaps.Hotspots.NPolyShape (прямоугольник, выпуклый многоугольник и невыпуклый многоугольник) реализуют этот интерфейс. Кроме того, API предоставляет возможность создать свой собственный тип геометрической фигуры (например, эллипс или кривую). Для этого необходимо реализовать следующие методы интерфейса YMaps.Hotspots.IShape:

  • getMinX, getMinY, getMaxX, getMaxY - возвращают границы фигуры, т.е. максимальные и минимальные значения координат точек фигуры;
  • contains - проверяет принадлежность точки фигуре;
  • getOwner и setOwner - возвращает и задает активную область (YMaps.Hotspots.Object или YMaps.Hotspots.Overlay), которой принадлежит фигура.

Классы YMaps.Hotspots.CPolyShape и YMaps.Hotspots.NPolyShape дополнительно реализуют методы:

  • getNumPoints - возвращает число вершин многоугольника;
  • getPoint - возвращает координаты вершины по ее индексу.