Клуб API Карт

Некорректный autopan для собственного макета балуна

Пост в архиве.
spb.pavlov
13 июля 2012, 16:22

я сделал свой макет балуна для примера http://api.yandex.ru/maps/doc/jsapi/2.x/examples/mapeventsballoon.html

балун открывается вниз вправо, соответсвенно если щелкнуть на левом верхнем углу карты - есть место для его открытия внутрь карты, тем не менее срабатывает autopan и центр зачем то сдвигается. Почему так происходит и что сделать чтобы autopan срабатывал только тогда когда это дейтвительно нужно?    


 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <title>Примеры. События карты.</title>

 

  <STYLE type="text/css">

div.test1 {

 

 position: relative;

width: 150px;

padding: 10px;

margin-left: -10px;

border: 1px solid #848877;

background: #f8ffe0;

 

}

  </STYLE>

 

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

 

    <!--

        Подключаем API карт 2.x

        Параметры:

          - load=package.full - полная сборка;

     - lang=ru-RU - язык русский.

    -->

    <script src="http://api-maps.yandex.ru/2.0/?load=package.full&lang=ru-RU"

            type="text/javascript"></script>

 

    <script type="text/javascript">

        // Как только будет загружен API и готов DOM, выполняем инициализацию

        ymaps.ready(init);

 

        function init () {

            var myMap = new ymaps.Map("map", {

                    center: [57.513314, 41.23869], // Красное-на-Волге

                    zoom: 11

                }, {

                    balloonMaxWidth: 200

                });

 

var myBalloonContentBodyLayout = ymaps.templateLayoutFactory.createClass(

                '<div class="test1"><h3>$[contentHeader]</h3>' +

                '<p>$[contentBody]</p>' +

                '<p>$[contentFooter]</p></div>'

            );

 

ymaps.layout.storage.add('my#balloonContentBodyLayout', myBalloonContentBodyLayout);

 

            // Обработка события, возникающего при щелчке

            // левой кнопкой мыши в любой точке карты.

            // При возникновении такого события откроем балун.

            myMap.events.add('click', function (e) {

                if (!myMap.balloon.isOpen()) {

                    var coords = e.get('coordPosition');

                    myMap.balloon.open(coords, {

                        contentHeader: 'Событие!',

                        contentBody: '<p>Кто-то щелкнул по карте.</p>' +

                            '<p>Координаты щелчка: ' + [

                                coords[0].toPrecision(6),

                                coords[1].toPrecision(6)

                            ].join(', ') + '</p>',

                        contentFooter: '<sup>Щелкните еще раз</sup>'

                    }, {

layout: "my#balloonContentBodyLayout",

shadow: false

});

                } else {

                    myMap.balloon.close();

                }

            });

 

            // Обработка события, возникающего при щелчке

            // правой кнопки мыши в любой точке карты.

            // При возникновении такого события покажем всплывающую подсказку.

            myMap.events.add('contextmenu', function (e) {

                myMap.hint.show(e.get('coordPosition'), 'Кто-то щелкнул правой кнопкой');

            });

        }

    </script>

</head>

 

<body>

<h2>События карты</h2>

 

<p>При щелчке левой кнопкой мыши в любой точке карты открывается балун (в соответствующей позиции).

    При щелчке правой кнопкой мыши появляется всплывающая подсказка.</p>

 

<div id="map" style="width: 800px; height: 400px"></div>

</body>

 

</html>

 

3 комментария

уберите код под врезку, пожалуйста

Та же проблема для балуна кластера. Пытаюсь самостоятельно посчитать куда надо сдвинуть карту.

Логика следующая, если очень надо. На открытие балуна ...balloon.events.add('open', ...) мы вешаем колбек с расчетом новых координат, куда надо сдвинуть карту (т.к. евент посылается после того, как балун уже создан и размещен на карте - это не проблема). Для того, чтобы понять, куда надо сдвинуть карту (какие координаты надо отправить в panTo), нам надо взять глобальные координаты карты в пикселях, взять координаты балуна (тоже в пикселях), посчитать разницу, перевести её в lat/lng и наложить на текущие геокоординаты (map.getPosition() карты). Чтобы это сделать еще потребуется map.getZoom(), и небольшое знание JS, конечно.

Есть небольшие моменты, которые слегка пугают. У cluster.Balloon нет метода getBalloon(), а не хочется завязываться на внутреннюю переменную _balloon. Но с кластером, как я понял, вообще отдельная история. Его лучше под себя перегружать своим объектом. Я для себя добавил event createcluster, который отправляется в clusterer, и думаю это еще не конец.

Текущие projection можно получить так: map.options.get('projection'). Еще можно просто запомнить где-то снаружи, какой нам нужен projection, и работать с ним. По умолчанию используется меркатор, как можно понять из доков.

При всем вышеизложенном сдвинуть карту руками - дело техники, желаю удачи)

P.s. Может есть какой-то багтрекер для непосвященных? Я тут наловил немного ошибок. Например, у geoObjects в доках есть метод removeAll, но в функционале нет, и другие похожие несостыковки и, вроде, логичные хотелки.

Еще один вариант - это при создании балуна (метод build в вашем лайоуте) проставлять размеры вашего балуна в родительские элемент. Но autoPan в этом случае прыгает очень странно: если отвести метку (в моем случае кластер) в левый верхний угол, то при открытии балуна метка оказывается за пределами карты в правом нижнем углу. Т.е. оно едет, но едет слишком много. Уж не знаю почему. Примерно так:

 

clusterBalloonLayout: ymaps.templateLayoutFactory.createClass(Geo.makers.html('balloonLayout'), {

  build: function () {

    var self = this, parent = this.getParentElement(), el = $('div:first', parent);

    el.find('.close').unbind('click').bind('click', function(e){

      self.events.fire('userclose'); // кнопка закрытия? хак, помойму.

    });

    el.css({marginTop: -2*el.outerHeight()/3}); //.css({bottom: 15, left: -22}); // сдвиг под стрелочку балуна    $(parent).css({width: el.outerWidth(), height: el.outerHeight()/3, marginLeft: -22, marginTop: -el.outerHeight()/3}); // хаки, хаки...

  }

...

В общем, я делю высоту на отступ на 2/3 у внутреннего элемента, и треть реальная высота родителя в яндекс.апи - тогда стрелочка втыкается куда надо. -22 это отступ слева до стрелочки, в моем макете это 22пкс.

Это все хаки, но как один из простых вариантов работает.

Может быть я что-то не так делаю, но у меня стойкое ощущение, что autoPad криво считает сдвиг. Т.е. код, на мой взгляд, должен быть таким, если забыть о codestyle etc.:

 

    $(parent).css({width: el.outerWidth(), height: el.outerHeight(), marginLeft: -22 /* сдвиг влево до стрелочки*/, marginTop: -el.outerHeight() /*и вверх до стрелочки*/ });Но увы в таком случае оно работает криво.В примере используется jquery ;-)