Клуб API Карт

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

Пост в архиве.

я сделал свой макет балуна для примера 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 комментария

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

Алексей Yarrr!
28 января 2016, 04:10

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

Логика следующая, если очень надо. На открытие балуна ...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, но в функционале нет, и другие похожие несостыковки и, вроде, логичные хотелки.

Алексей Yarrr!
28 января 2016, 04:10

Еще один вариант - это при создании балуна (метод 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 ;-)