@space900

Yandex Maps. Карта с кастомным балуном центрируется только при втором клике, если текст в балуне ограничен по ширине. Почему?

62863f2d66b86081184480.png
При клике на кнопку "На карте", всегда открывается кастомный балун и карта центрируется на нём, в стилях кастомному балуну ymaps[class$="-balloon__content"] задал max-width 250, балун должен быть именно такой ширины. При этом дочерний элемент ymaps id="@#!%RT" получает ширину в зависимости от текста, и если длина текста больше, он выходит за балун, а не переносится.

Если к тексту или к любым его родительским классам ymaps добавлять width/max-width и т.д, или же как предлагается документацией yaMap https://yandex.ru/dev/maps/jsapi/doc/2.1/ref/refer..., ограничивать размер балуна через minWidth MaxWidth и т.п., это работает и текст корректно переносится.

Но здесь появляется баг, при первом клике по кнопке "На карте", всё ок, если нажать на любую другую, балун открывается, но карта на нём не центрируется, а остаётся в предыдущем положении, при повторном клике или дабл-клике, всё открывается корректно. Как сделать без костылей так, чтобы текст переносился нормально, и можно было переключаться по разным адресам с первого клика?
function yaMapInit() {
  const yaMapContainer = document.getElementById('yaMapStorages');
  // Инициализируем Яндекс карты
  const myMap = new ymaps.Map('yaMapStorages', {
    center: [34.76, 37.64],
    zoom: 10,
    // Опции скролла при взаимодействии с картой: двигаем карту, зум +/- по дабл-клику мышкой, масштабирование мультисенсорным касанием
    behaviors: [
      "drag",
      "dblClickZoom",
      "multiTouch"
    ],
    // Элементы управления: зум, геолокация
    controls: [
      'zoomControl',
      'geolocationControl'
    ],
  }, {
    // Отрубаем все не нужное на карте
    suppressMapOpenBlock: true,
    // Отключаем дефолтное позиционирование кнопки геолокации на экране
    geolocationControlFloat: 'none',
    // Отключаем все метки карты, кроме собственных
    yandexMapDisablePoiInteractivity: true,
    // Задаём позиционирование геолокации
    position: {
      top: '10px',
      right: '10px',
    },
    // Задаём позиционирование Скролл-зума карты
    zoomControlPosition: {
      right: '20px',
      bottom: '40px'
    }
  });
  // ObjectManager - Инструмент для добавления большого числа объектов на карту
  const objectManager = new ymaps.ObjectManager(
    // Опции
    {
      // Чтобы метки начали кластеризоваться (объединяться), выставляем опцию.
      clusterize: true,
      // При каком зуме объединять метки в группу
      maxZoom: 18,
      // Отступы от края карты
      zoomMargin: 100,
    }
  );
  // Отключаем scrollZoom
  myMap.behaviors.disable(['scrollZoom']);

  // Дополняем опции objectManager
  const markIconMap = {
    iconLayout: 'default#image',
    // Своё изображение иконки метки.
    iconImageHref: '',
    // Размеры метки.
    iconImageSize: [24, 33],
    //iconImageOffset: [-20, -53],
  };
  objectManager.objects.options.set(markIconMap);
  myMap.geoObjects.add(objectManager);
  myMap.geoObjects.add(placemark);
  
  // Объект меток, с координатами, кастомными балунами
  const pointsObjMsk = JSON.parse(document.getElementById('pointsObj').textContent);
  if (pointsObjMsk.features.length >= 1) {
    // Добавляем данные с метками в коллекцию objectManager
    objectManager.add(pointsObjMsk);
    if (pointsObjMsk.features.length === 1) {
      // Если на карте всего 1 метка, устанавливаем корректный зум для этой метки
      myMap.setCenter(pointsObjMsk.features[0].geometry.coordinates, 12);
    } else {
      // Центрируем карту по всем меткам, устанавливаем в опциях минимальные отступы для точек от границ карты.
      myMap.setBounds(myMap.geoObjects.getBounds(), {
        // Отступы от края карты
        zoomMargin: 100,
        checkZoomRange: true,
      });
    }
    // Контейнер с хранилищами и картой
    const mapAndStorages = yaMapContainer.closest('.map-and-storages');
    if (mapAndStorages) {
      // Скрываем карту на экранах < 768px
      if (window.innerWidth < 768) {
        const tabMapTarget = mapAndStorages.querySelector('#tab-map-target');
        if (tabMapTarget)
          tabMapTarget.classList.remove('active', 'show');
      }
      // Ищем объект на карте по клику на контейнер
      const buttons = mapAndStorages.querySelectorAll('.show-container-in-map');
      // Кнопка, которая открывает таб с картой
      if (buttons && buttons.length > 0) {
        const buttonTabMap = mapAndStorages.querySelector('button[data-bs-target="#tab-map-target"]');
        buttons.forEach(el => {
          el.addEventListener('click', () => {
            if (window.innerWidth < 768) buttonTabMap.click();
            const cardContainer = el.closest('.card-container');
            if (cardContainer) {
              const idContainer = cardContainer.getAttribute('data-id-container'),
                coords = {
                  x: cardContainer.getAttribute('data-x'),
                  y: cardContainer.getAttribute('data-y')
                },
                balloonInfo = pointsObjMsk.features[idContainer].properties;
              // показываем точку, меняем зум при необходимости
              myMap.setCenter([coords.x, coords.y], 13);
              const markIconMapContainer = {
                contentHeader: balloonInfo.balloonContentHeader,
                contentBody: balloonInfo.balloonContentBody,
                contentFooter: balloonInfo.balloonContentFooter,
                clusterCaption: balloonInfo.clusterCaption,
                hintContent: balloonInfo.hintContent,
              }
              // Показываем конкретный объект на карте
              Object.assign(markIconMapContainer, markIconMap);
              // При экране < 768px врубаем задержку для качественного рендеринга
              if (window.innerWidth < 768) {
                setTimeout(() => {
                  myMap.balloon.open(
                    myMap.getCenter(),
                    markIconMapContainer
                  );
                }, 100);
              } else {
                myMap.balloon.open(
                  myMap.getCenter(),
                  markIconMapContainer, {
                    /* minWidth: '250px',
                     minHeight: '1px',*/
                  }

                );
              }
            }
          });
        });
      }
    }

    // Скрываем лоадер
    const yaMapLoader = yaMapContainer.querySelector('img.map-loader');
    if (yaMapLoader) {
      yaMapLoader.remove();
    }
  }
}

#yaMapStorages {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  @include max_768 {
    position: relative;
    height: 600px;
  }
  img.map-loader {
    position: absolute;
    right: 0;
    left: 0;
    top: 0;
    bottom: 0;
    max-width: 150px;
    margin: auto;
  }
  >ymaps {
    //width: 100% !important;
  }
  ymaps[class$="-balloon-content__header"] {
    margin: 0;
  }
  ymaps[class$="-balloon-content__footer"] {
    margin: 0;
  }
  ymaps[class$="-balloon__content"] {
    ymaps {}
    width: 100%;
    max-width: 250px;
    padding: 0;
    margin-right: 0;
    .baloon__link {
      text-decoration: underline;
      &:hover {
        text-decoration: none;
        color: black;
      }
    }
    .baloon__image {
      width: 250px;
      height: 140px;
      object-fit: cover;
      object-position: center;
    }
    strong {
      @include rg-font-style('bold');
    }
    p {
      @include px-to-rem(16);
      //width: 250px;
    }
    h3 {
      background-color: #f3f3f3;
      @include px-to-rem(20);
      text-align: left;
      padding: 10px;
      +p {
        margin-bottom: 0;
        padding: 10px;
      }
    }
  }
  ymaps[class$="-balloon__close"] {
    background-color: white;
    width: 20px;
    height: 20px;
    border-radius: 25px;
    border: 1px solid black;
    top: 5px;
    right: 5px;
    >ymaps {
      width: 20px;
      height: 20px;
      background-size: 10px;
    }
  }
}
  • Вопрос задан
  • 62 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы