Рендеринг компонента React в GoogleMaps InfoBox — остановить клики

У меня проблема с картами Google InfoBox в приложении React. Моя цель — открыть пустой InfoBox в экземпляре Google Maps, а затем использовать ReactDOM.render, чтобы поместить в него мой компонент. Компонент состоит из набора вкладок, при этом каждая панель вкладок выполняет вызов API через избыточность и преобразователь при ее открытии.

Все работает, показывает красиво. Проблема возникает из-за фактического нажатия на InfoBox. Я могу заставить его работать одним из двух способов, изменив enableEventPropagation на true или false:

  1. enableEventPropagation = true: компонент работает, все вкладки и кнопки, но любые маркеры под моим информационным полем будут открыты, если я случайно нажму на правую часть информационного окна, что полностью нарушит состояние и поток моего приложения.

  2. enableEventPropagation = false: клики не передаются на карту, но тогда ни одно из событий кликов в реагирующем компоненте не работает. Ни вкладок, ни кнопок: ничего. Выглядит отлично, но совсем не работает.

Вот мой код для создания моего InfoBox и рендеринга в него с помощью ReactDOM:

renderInfoBox() {
    let {map, google, infoBox} = this.props;
    let markerElement = MarkerElementService.getMarkerElement(infoBox.ui.markerId);

    this.infoBox = new this.infoBoxClass({
        content: this.refs.infoBoxHolder,
        enableEventPropagation: false,
        pixelOffset: new google.maps.Size(10, -275),
        maxWidth: 350,
        zIndex: 99999999,
        infoBoxClearance: new google.maps.Size(75, 75)
    });

    ReactDOM.render(
        <Provider store={AppStore}>
            <ThemeProvider theme={Theme}>
                <InfoBoxComponent google={google} onClose={this.closeButtonClicked.bind(this)} />
            </ThemeProvider>
        </Provider>,
        this.refs.infoBoxHolder,
        () => {
            this.infoBox.open(map, markerElement);
        }
    );
}

render() {
    return (
        <div ref="infoBoxHolder" />
    );
}

Я пробовал следующие решения:

  • Переключение на GoogleMaps OverLay. Точно такая же проблема, на самом деле глядя на надстройку InfoBox, кажется, что InfoBox является оболочкой для OverLay, которая помогает устранить некоторые из этих проблем, но все еще предполагает, что она будет неинтерактивной.

  • Отключение распространения событий в различных точках внутри моих компонентов, но эффект заключается в том, что он отключает распространение событий вниз по дереву DOM, а не вверх, что означает, что дочерние компоненты не работают! Безумный!

Кажется, мой единственный оставшийся вариант — каким-то образом вычислить границы широты/долготы информационного окна после его рендеринга, а затем последовательно отключить все маркеры, которые находятся в этой области, но я хочу избежать этого хакерского вздора!

А может у меня совсем неправильный подход?


person Tom    schedule 05.05.2017    source источник
comment
Вы собираетесь поставить скрипт JS? Я сам создал собственное наложение информационного окна, используя наложения googlemaps, что звучит похоже на это. Я не понимаю ни одной из проблем, которые вы описываете. Трудно сказать, в чем причина проблемы, не видя больше. Я бродил, если есть решение, использующее css-указатели-события?   -  person Paul Thomas    schedule 08.05.2017
comment
Аналогично этому и/или этот?   -  person Saravanabalagi Ramachandran    schedule 09.05.2017


Ответы (1)


Есть несколько вещей, которые вы могли бы попробовать.

Во-первых, если у вас не так много маркеров, вы определенно можете попробовать установить свои маркеры оптимизированный флаг на false. Он будет отображать их как отдельные элементы DOM, снижая производительность, но вы не получите странного поведения, как вы испытываете.

Я не смог воспроизвести вашу проблему с обычными маркерами, но смог с POI, которые добавляются по умолчанию. Чтобы предотвратить открытие любого маркера за вашим InfoBox, вы можете создать прослушиватель на enter и leave вашего InfoBox, который установит логическое значение и переопределит метод set InfoWindow, чтобы отменить поведение по умолчанию, пока вы зависаете. Вы все еще можете видеть изменение курсора мыши, но это можно удалить с помощью некоторых базовых CSS.

Вот пример, попробуйте нажать на маркер Sechelt Aquatic Center после нажатия на маркер, чтобы открыть InfoxBox, у вас не должно получиться это сделать.

function initialize () {

  let enableMarkers = true
  
  const set = google.maps.InfoWindow.prototype.set;
  google.maps.InfoWindow.prototype.set = function (key, val) {
    if (key === 'map') {
      if (!enableMarkers) {
        return
      }
    }
    set.apply(this, arguments)
  }

  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 15,
    center: new google.maps.LatLng(49.47216, -123.76307),
    mapTypeId: google.maps.MapTypeId.ROADMAP,
  })

  const marker = new google.maps.Marker({
    map,
    draggable: true,
    position: new google.maps.LatLng(49.47216, -123.76307),
    visible: true
  })

  const box = document.createElement('div')
  box.innerHTML = 'Hello <br> Hello <br> Hello'

  google.maps.event.addListener(marker, 'click', function (e) {
    if (!enableMarkers) { return }
    ib.open(map, this)
  })

  const ib = new InfoBox({
    content: box,
    zIndex: 10,
    pixelOffset: new google.maps.Size(-100, 0),
    boxStyle: { 
      background: 'white',
      padding: '5px',
      opacity: 0.75,
      width: '200px',
    },
    closeBoxMargin: '2px',
    closeBoxURL: 'https://www.google.com/intl/en_us/mapfiles/close.gif',
    isHidden: false,
    enableEventPropagation: true,
  })
  
  box.addEventListener('mouseenter', () => {
    enableMarkers = false
  })
  
  box.addEventListener('mouseleave', () => {
    enableMarkers = true
  })
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&amp;sensor=false"></script>
<script src="https://rawgit.com/googlemaps/v3-utility-library/master/infobox/src/infobox.js"></script>

<body onload="initialize()">
  <div id="map" style="width: 100%; height: 200px"></div>
</body>

Я также видел в нескольких местах, где у людей была такая же проблема, и им приходилось ждать, пока событие InfoBox domready не начнет связывать их клики. На самом деле не думаю, что это актуально, поскольку я действительно не знаю, как вы могли бы сделать это с помощью React, но все же стоит отметить.

person Balthazar    schedule 09.05.2017
comment
Черт, спасибо за ответ! Ваш подход в целом был просто одним из тех, которые я не рассматривал. Все операции mouseenter и mouseleave великолепны, в итоге я решил свою проблему, прослушав эти события в своем информационном окне, а затем установив значение в моем хранилище избыточности, которое проверяется при нажатии маркера, косвенно отключая все другие маркеры всякий раз, когда я навожу курсор мыши на ИнфоБокс. Спасибо! - person Tom; 10.05.2017
comment
Только что обнаружил, что этот подход не работает на мобильных устройствах! - person Tom; 24.07.2018