Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как правильно скопировать google карту в модальное окно и добавить в неё указатели? (https://javascript.ru/forum/misc/85871-kak-pravilno-skopirovat-google-kartu-v-modalnoe-okno-i-dobavit-v-nejo-ukazateli.html)

giwuf 26.04.2024 12:22

Как правильно скопировать google карту в модальное окно и добавить в неё указатели?
 
Есть карта google map. Теперь я хочу скопировать и отобразить текущую карту в модальном окне bootstarp и по условию производить с ней действия (добавлять маркеры).

Но, сталкиваюсь с двумя проблемами:

Копирую с помощью функции map.getDiv() и получаю HTMLElement MapDiv карты, который помещаю внутрь компонента модального окна
modalmaped.append(map.getDiv());

Однако, исходная карта почему-то не копируется, а вырезается из исходного места (мне нужно добиться копирования)
При задании новых границ в карте, которая теперь в модальном окне
modalmaped.fitBounds(bounds);


я получаю ошибку:
Uncaught TypeError: modalmaped.fitBounds is not a function

Как это исправить?

Код
var map = "null";
var lat = 54.6786609;
var lng = 25.3077807;

function myMap() {
  var mapCanvas = document.getElementById("map");
  var mapOptions = {
    center: new google.maps.LatLng(51.508742, -0.120850),
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    styles: [{
      stylers: [{
        saturation: -100
      }]
    }],
    zoom: 30
  };
  map = new google.maps.Map(mapCanvas, mapOptions);
}

document.getElementById('showMap').addEventListener('shown.bs.modal', function(event) {
  modalmaped = document.getElementById('new-map');
  modalmaped.append(map.getDiv());
  var bounds = new google.maps.LatLngBounds();
  bounds.extend(new google.maps.LatLng(lat, lng));

  if ((modalmaped !== undefined) && (modalmaped !== null)) {
    modalmaped.fitBounds(bounds);
    modalmaped.setZoom(30);

  }
});

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<div id="map"></div>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#mapModal">
  Launch demo modal
</button>
<div id="mapModal" class="modal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <div id="new-map"></div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

roland 26.04.2024 15:03

giwuf, не подскажу с Google Maps API, это уже на Ваше время чтения документации, но укажу на проблему:

Метод Element.append вставляет узлы (Nodes), а не копирует их. Перед вставкой их нужно клонировать. Для клонирования есть метод Node.cloneNode. Но это не решит вашей проблемы, потому что API будет работать лишь с одним элементом одновременно.

Вам необходимо создать новый экземпляр карты для модального окна и при инициализации или его показе выставлять координаты, взятые из существующей карты.

Что касается ошибки, то "modalmaped" это экземпляр HTMLDivElement (элемент "div"), у которого нет метода "fitBounds". А Вы с ним пытаетесь работать, как с экземплятором Map (из Google Maps API).

giwuf 26.04.2024 22:51

roland, за направление мыслей спасибо!
Т.е. при любых раскладах придётся создавать 2 отдельных экземпляра карты и дважды проходить по всем координатам и нет более изящного решения?
Я просто изначально так и делал, создавал два независимых экземпляра. Но, посчитал, что такой подход избыточен и потенциально может приводить к лагам во время открытия окна особенно в мобильной версии, поэтому и стал искать пути клонирования или буферизации карты с установленными маркерами.

Вот этот момент можете пояснить не очень его понял
Цитата:

API будет работать лишь с одним элементом одновременно
Мне единовременно и нужна работа с одной картой стартовой или переключаться на модальную, а при закрытии окна возвращаться обратно. Или вы как раз говорите о невозможности переключения при клонировании?

roland 27.04.2024 14:09

giwuf, трудно посоветовать что-то конкретное, не видя дизайна и не зная логики интерфейса. Если предполагается работа только с одной картой одновременно, то почему недопустимо перемещение карты в контейнер модального окна? Вопрос в заглушке на месте основной карты? Слишком много нюансов:

Насколько сильно модальное окно перекрывает основную карту? Можно ли по дизайну сделать заглушку растровым изображением (неактуальной карты)? Насколько глубокое клонирование узла карты ресурсозатратно? Поддерживает ли Google Maps API отображение карты или конвертацию в растровое изображение (HTML5 Canvas)? Допустимо ли использовать на сайте html2canvas для создания заглушки? Были ли изучены примеры с аналогичным использованием карт на других сайтах?

Ответить на эти вопросы и принять решение может только сам разработчик интерфейсов, работая с дизайнером (если это разные люди) и открытой вкладкой Performance в DevTools, зная целевые устройства, на которых это будет использоваться.

Nexus 27.04.2024 17:17

Признаться, я не читал всего, что вы тут понаписали, но почему не сделать как-то так?
var map = "null";
var lat = 54.6786609;
var lng = 25.3077807;

function launchGMap(container, center, options) {
    if (typeof container === 'string') {
        container = document.querySelector(container);
    }

    if (Array.isArray(center)) {
        center = new google.maps.LatLng(center[0], center[1]);
    }

    return new google.maps.Map(container, Object.assign({}, {
        center: center,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        styles: [{
            stylers: [{
                saturation: -100,
            }],
        }],
        zoom: 30,
    }, options || {}));
}

function myMap() {
    return map = launchGMap('#map', [51.508742, -0.120850]);
}

document.getElementById('showMap').addEventListener('shown.bs.modal', function() {
    modalmaped = launchGMap('#new-map', [lat, lng]);

    var bounds = new google.maps.LatLngBounds();
    bounds.extend(new google.maps.LatLng(lat, lng));

    if (modalmaped != null) {
        modalmaped.fitBounds(bounds);
        modalmaped.setZoom(30);
    }
});


Часовой пояс GMT +3, время: 12:19.