Google Maps InfoBubble pixelOffset (переход от позиции по умолчанию над маркером)

Я пытаюсь реализовать пользовательский infoBubble, который имеет окно, открывающееся в сторону маркера, а не позицию по умолчанию сверху. Это оказалось сложнее, чем ожидалось.

Используя обычный инфо-окно, вы можете использовать pixelOffset. См. Здесь documentation

Использование infoBubble, похоже, не так. Есть ли способ использования pixelOffset в infoBubble или что-то, что будет делать то же самое?

Я нашел это очень трудным для поиска, поскольку использование поиска Google, такого как это, не возвращает никаких релевантных результатов Google Search

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

  • Пример infoBubble здесь.

  • Мой JavaScript для настройки карты и infoBubble здесь.

И теперь мой javascript здесь просто в случае, если ссылка jsfiddle нарушена.

<script type="text/javascript">

    $(document).ready(function () {
        init();
    });

    function init() {

        //Setup the map
        var googleMapOptions = {
            center: new google.maps.LatLng(53.5167, -1.1333),
            zoom: 13,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        //Start the map
        var map = new google.maps.Map(document.getElementById("map_canvas"),
        googleMapOptions);

        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(53.5267, -1.1333),
            title: "Just a test"
        });

        marker.setMap(map);

        infoBubble = new InfoBubble({
            map: map,
            content: '<div class="phoneytext">Some label</div>',
            //position: new google.maps.LatLng(-35, 151),
            shadowStyle: 1,
            padding: '10px',
            //backgroundColor: 'rgb(57,57,57)',
            borderRadius: 5,
            minWidth: 200,
            arrowSize: 10,
            borderWidth: 1,
            borderColor: '#2c2c2c',
            disableAutoPan: true,
            hideCloseButton: false,
            arrowPosition: 7,
            backgroundClassName: 'phoney',
            pixelOffset: new google.maps.Size(130, 120),
            arrowStyle: 2
        });
        infoBubble.open(map, marker);

    }
</script>

Обновление

Чтобы ответить на этот вопрос, я собрал тестовый пример здесь. Важными линиями являются строки 38 и 39, которые должны указывать, где разместить метку.

Обновление 2

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

Обновление 3

Я удалил тестовый файл из обновления 1, потому что он размещен на моих старых серверах компании.

Ответы

Ответ 1

Кажется, что сама библиотека infoBubble по умолчанию ставит пузырь над маркером, к которому она привязана. Посмотрите пример файла, который они включили в библиотеку: http://code.google.com/p/google-maps-utility-library-v3/source/browse/trunk/infobubble/examples/example.html. В частности, обратите внимание на строку 99 на строку 122 и на использование двух информационных блоков. Первый связан с маркером, однако второй из них является автономным, и, таким образом, если вы видите строку 106, вы можете определить позицию для нее. Теперь, основываясь на этом понимании, я создал для вас пример в этой скрипте http://jsfiddle.net/pDFc3/. Информационная панель расположена справа от маркера.

Странно, потому что библиотека infoBubble js имеет функцию setPosition (http://code.google.com/p/google-maps-utility-library-v3/source/browse/trunk/infobubble/src/infobubble.js?r=206), см. строку 1027. Но по какой-то причине после я дождитесь загрузки DOM и попробуйте изменить позицию, перейдя в infoBubble.setPosition(newLatLng); Я не работаю. Напротив, объявление infoBubble.getPosition(); после загрузки DOM дает мне текущую позицию маркера, к которой привязан infoBubble. Поэтому setPosition() может иметь ошибку в js-библиотеке, потому что я считаю, что она все еще работает (я могу ошибаться, может быть, это просто глючит).


Я исправил свой jsFiddle, чтобы решить вашу проблему при масштабировании и выключении, и соответственно позиционируя infoBubble (http://jsfiddle.net/pDFc3/). Позвольте мне сначала объяснить логику. Во-первых, максимальный уровень масштабирования на Картах Google для типа дорожной карты равен 21 - это значение не соответствует спутниковым снимкам, но максимальный масштаб, на который может перейти пользователь, равен 21. Начиная с 21, каждый раз, когда вы уменьшаете масштаб, разница между двумя точками может быть последовательно "на экране" на основе следующей логики:

consitent_screen_dist = initial_dist * (2 ^ (21 - zoomlevel))

В нашем случае разумное значение для начального расстояния составляло 0,00003 градуса (между маркером и infoBubble). Итак, основываясь на этой логике, я добавил следующую часть, чтобы найти начальное продольное расстояние между маркером и infoBubble:

var newlong = marker.getPosition().lng() + (0.00003 * Math.pow(2, (21 - map.getZoom())));

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

    google.maps.event.addListener(map, "zoom_changed", function() {
        newlong = marker.getPosition().lng() + (0.00003 * Math.pow(2, (21 - map.getZoom())));
        infoBubble.setPosition(new google.maps.LatLng(marker.getPosition().lat(), newlong));                
    });

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

Ответ 2

Это мое решение.

В InfoBubble библиотеке

заменить

весь InfoBubble.prototype.draw метод

с

/*
 * Sets InfoBubble Position
 * */
InfoBubble.prototype.setBubbleOffset = function(xOffset, yOffset) {
  this.bubbleOffsetX = parseInt(xOffset);
  this.bubbleOffsetY = parseInt(yOffset);
}


/*
 * Gets InfoBubble Position
 * */
InfoBubble.prototype.getBubbleOffset = function() {
  return {
    x: this.bubbleOffsetX || 0,
    y: this.bubbleOffsetY || 0
  }
}

/**
 * Draw the InfoBubble
 * Implementing the OverlayView interface
 */
InfoBubble.prototype.draw = function() {
  var projection = this.getProjection();

  if (!projection) {
    // The map projection is not ready yet so do nothing
    return;
  }

  var latLng = /** @type {google.maps.LatLng} */ (this.get('position'));

  if (!latLng) {
    this.close();
    return;
  }

  var tabHeight = 0;

  if (this.activeTab_) {
    tabHeight = this.activeTab_.offsetHeight;
  }

  var anchorHeight = this.getAnchorHeight_();
  var arrowSize = this.getArrowSize_();
  var arrowPosition = this.getArrowPosition_();

  arrowPosition = arrowPosition / 100;

  var pos = projection.fromLatLngToDivPixel(latLng);
  var width = this.contentContainer_.offsetWidth;
  var height = this.bubble_.offsetHeight;

  if (!width) {
    return;
  }

  // Adjust for the height of the info bubble
  var top = pos.y - (height + arrowSize) + this.getBubbleOffset().y;

  if (anchorHeight) {
    // If there is an anchor then include the height
    top -= anchorHeight;
  }

  var left = pos.x - (width * arrowPosition) + this.getBubbleOffset().x;

  this.bubble_.style['top'] = this.px(top);
  this.bubble_.style['left'] = this.px(left);

  var shadowStyle = parseInt(this.get('shadowStyle'), 10);

  switch (shadowStyle) {
    case 1:
      // Shadow is behind
      this.bubbleShadow_.style['top'] = this.px(top + tabHeight - 1);
      this.bubbleShadow_.style['left'] = this.px(left);
      this.bubbleShadow_.style['width'] = this.px(width);
      this.bubbleShadow_.style['height'] =
        this.px(this.contentContainer_.offsetHeight - arrowSize);
      break;
    case 2:
      // Shadow is below
      width = width * 0.8;
      if (anchorHeight) {
        this.bubbleShadow_.style['top'] = this.px(pos.y);
      } else {
        this.bubbleShadow_.style['top'] = this.px(pos.y + arrowSize);
      }
      this.bubbleShadow_.style['left'] = this.px(pos.x - width * arrowPosition);

      this.bubbleShadow_.style['width'] = this.px(width);
      this.bubbleShadow_.style['height'] = this.px(2);
      break;
  }
};

а затем вы можете использовать его

var infoBubble = new InfoBubble({
  map: map,
  content: "My Content",
  position: new google.maps.LatLng(1, 1),
  shadowStyle: 1,
  padding: 0,
  backgroundColor: 'transparent',
  borderRadius: 7,
  arrowSize: 10,
  borderWidth: 1,
  borderColor: '#2c2c2c',
  disableAutoPan: true,
  hideCloseButton: true,
  arrowPosition: 50,
  backgroundClassName: 'infoBubbleBackground',
  arrowStyle: 2

});

Затем, наконец, мы должны использовать этот метод setBubbleOffset(x,y); для установки положения InfoBubble

infoBubble.setBubbleOffset(0,-32);

Ответ 3

К сожалению, такой опции, как pixelOffset в InfoBubble, отсутствует. Но если вы просто хотите переместиться вверх по Bubble над маркером в своем примере, вы не должны устанавливать параметр map при инициализации пузырьков. Рассмотрим следующую скрипту (я исправил ее для вас):

http://jsfiddle.net/ssrP9/5/


P.S. Ваша скрипка не работает, потому что вы не добавили ресурсы должным образом http://doc.jsfiddle.net/basic/introduction.html#add-resources

Ответ 4

Я только что столкнулся с одной и той же проблемой, но не смог найти ответ нигде. Сквозь небольшой проб и ошибок я справился.

Вы будете использовать JS файл Google для "infoBubble". Зайдите в этот файл и выполните поиск...

InfoBubble.prototype.buildDom_ = function() {

Для меня это в строке 203 (но это может быть результатом предыдущих перетасовки и редактирования).

Внутри этой функции вы увидите позицию "абсолютное" объявление. В новой строке вы можете добавить marginTop, marginRight, marginBottom и marginLeft. Это подтолкнет пузырь от положения по умолчанию (которое также зависит от объявления позиции стрелки в вашей конфигурации)...

Это моя настройка кода в JSP файле пузыря, который позиционирует пузырь поверх метки (из-за функции дизайна)...

var bubble = this.bubble_ = document.createElement('DIV');
bubble.style['position'] = 'absolute';
bubble.style['marginTop'] = this.px(21);
bubble.style['marginLeft'] = this.px(1);
bubble.style['zIndex'] = this.baseZIndex_;

Надеюсь, что это поможет.

Ответ 5

Вы также можете использовать определенную высоту привязки;

var anchorHeight = YOURNUMBER;

строка 874 infobubble.js

Ответ 6

В функции CreateDom InfoBubble добавьте:

bubble.className = 'bubble-container';

Теперь у вас есть класс CSS для каждого InfoBubble, вы можете перенести его с помощью поля CSS.