Создание пользовательской координатной системы
API предоставляет возможности для создания пользовательских координатных систем и осуществления навигации по картам, "склеенным" вдоль вертикальной и/или горизонтальной оси.
Для того чтобы создать пользовательскую координатную систему, необходимо:
- Задать объект-точку системы, см. Интерфейс YMaps.ICoordPoint.
- Задать объект-область системы, см. Интерфейс YMaps.ICoordBounds .
- Задать правила пересчета координат системы в пикселы на последнем масштабе карты, см. Интерфейс YMaps.ICoordSystem.
Ниже подробно описано создание галактической координатной системы, предназначенной для навигации по астрономической карте нашей Галактики.
Как задать объект-точку
Интерфейс YMaps.ICoordPoint позволяет задать объект-точку пользовательской координатной системы, когда нельзя воспользоваться стандартными классами YMaps.Point и YMaps.GeoPoint.
С помощью YMaps.ICoordPoint необходимо реализовать следующие методы:
Рассмотрим использование интерфейса на примере карты Млечного Пути:

На астрономической карте Галактики используются специальные координаты: галактическая долгота (изменяется от 360 градусов до 0) и галактическая широта (изменяется от -90 до 90 градусов), поэтому стандартные классы географических точек использовать нельзя.
Кроме того, карта "склеена" вдоль горизонтальной оси, поэтому точки на ней могут, как и в случае с картой Земли, быть ограниченными и неограниченными, см. Преобразование координат. Один градус в этой системе координат приблизительно равен 500 световым годам.
Ограниченные точки в галактических координатах имеют широту от 0 до 360 и долготу от -90 до 90 градусов. Неограниченные точки могут принимать произвольные координаты и, фактически, являются вектором, соединяющим начало системы координат с определенной точкой. Для различения ограниченных и неограниченных точек используется флаг unbounded.
Чтобы задать объект-точку выполните следующие шаги:
Как задать объект-область
Интерфейс YMaps.ICoordBounds позволяет задавать пользовательские объекты-области координатной системы, когда нельзя воспользоваться стандартными объектами YMaps.Bounds и YMaps.GeoBounds.
С помощью YMaps.ICoordBounds необходимо реализовать следующие методы:
- getRightTop, getRightBottom, getLeftBottom, getLeftTop, которые возвращают (в виде точки координатной системы) правый верхний, правый нижний, левый нижний и левый верхний углы области, соответственно;
- getMapZoom, возвращающий максимальное значение коэффициента масштабирования, при котором область видна на карте целиком;
- equals проверяющий, совпадают ли две области;
- contains проверяющий, содержит ли область переданную точку;
- copy возвращающий копию области.
Например, чтобы задать объект-область на карте Млечного пути, реализуйте класс MyBounds
(см. пример ниже). При этом следует учесть, что точки в галактической системе координат могут быть двух типов (ограниченные и неограниченные), соответственно и область также может принадлежать к одному из двух типов: заданная либо ограниченными, либо неограниченными точками.
// Класс "область на карте"
function MyBounds(leftBottom, rightTop) {
this.left = leftBottom.getX();
this.right = rightTop.getX();
this.bottom = leftBottom.getY();
this.top = rightTop.getY();
// Флаг unbounded указывает какими точками задана область: ограниченными или неограниченными
this.unbounded = leftBottom.unbounded && rightTop.unbounded;
}
MyBounds.prototype = {
// Границы области
getTop: function () {
return this.top;
},
getRight: function () {
return this.right;
},
getBottom: function () {
return this.bottom;
},
getLeft: function () {
return this.left;
},
// Углы области
getRightTop: function () {
return new MyPoint(this.right, this.top, this.unbounded);
},
getRightBottom: function () {
return new MyPoint(this.right, this.bottom, this.unbounded);
},
getLeftBottom: function () {
return new MyPoint(this.left, this.bottom, this.unbounded);
},
getLeftTop: function () {
return new MyPoint(this.left, this.top, this.unbounded);
},
// Центр области
getCenter: function () {
var x = (this.left + this.right) / 2,
y = (this.top + this.bottom) / 2;
// Если координата левой точки меньше координаты правой, то берется диаметрально противоположная точка
if (this.right > this.left && !this.unbounded) {
x += 180;
}
return new MyPoint(x, y, this.unbounded);
},
// Размеры области
getSpan: function () {
return new YMaps.Size(Math.abs(this.left - this.right), Math.abs(this.top - this.bottom));
},
// Вычисляет масштаб карты, при котором область видна целиком
getMapZoom: function (map) {
var pixelLeftBottom = map.coorSystem.toPixels(this.getLeftBottom()),
pixelRightTop = map.coorSystem.toPixels(this.getRightTop()),
// Вычисляет размеры области в пикселах на последнем масштабе
pixelSpan = pixelLeftBottom.diff(pixelRightTop).apply(Math.abs),
// Вычисляет размер HTML-элемента карты в пикселах
mapSize = map.getContainerSize(),
// Вычисляет отношение размеров области и карты
scale = Math.max(pixelSpan.getX() / mapSize.getX(), pixelSpan.getX() / mapSize.getX()),
// Вычисляет количество значений коэффициента масштабирования (не
// превышающих максимального), при которых область видна на карте целиком
offset = scale < 1 ? 0 : Math.ceil(Math.log(scale)/Math.LN2);
// Вычисляет уровень масштаба карты
return map.coordSystem.getMaxZoom() - offset;
},
// Сравнивает области
equals: function (myBounds) {
var precision = 1e-10; // Точность сравнения объектов
return (Math.abs(this.top - myBounds.getTop()) < precision &&
Math.abs(this.right - myBounds.getRight())