Страницы

Поиск по вопросам

среда, 25 декабря 2019 г.

Callback загрузки карты yandex map

#javascript #yandex_maps_api


Имеется пустая страница с картой для печати. С помощью window.print() вызывается
на печать. Проблема заключается в том, что карта не успевает отрисоваться. Никак не
могу нагуглить и нарыть в их замечательной документации какой-то вариант события или
callback'a именно на готовность карты.  

Есть предложения, коллеги?

ymaps.ready(function() {
  ymaps.ready(init);
  var map,
    object;

  function init() {
    var center = settings.map.center,
      zoom = parseInt(settings.map.zoom),
      coords_point = settings.map.coords_point;

    center = center.split(',').map(parseFloat);
    coords_point = coords_point.split(',').map(parseFloat);

    map = new ymaps.Map('yamap', {
      center: center,
      zoom: zoom,
      controls: [],
    });

    object = new ymaps.GeoObject({
      geometry: {
        type: "Point",
        coordinates: coords_point
      },
    }, {
      preset: 'custom#point_green',
    });

    map.geoObjects.add(object);
  }

  ymaps.option.presetStorage.add('custom#point_green', {
    iconLayout: 'default#image',
    iconImageHref: settings.themePath + '/img/yamap_point_g.png',
    iconImageSize: [48, 41],
    iconImageOffset: [-15, -41],
    hideIconOnBalloonOpen: false,
  });
});


Обновление

Пример вызова window.print():

Пример на JsFiddle



ymaps.ready(function() {
  ymaps.ready(init);
  var map,
    object;

  function init() {
    var center = "56.83676954481658,60.61677207117298",
      zoom = 15,
      coords_point = "56.836098132297586,60.61771118192043";

    center = center.split(',').map(parseFloat);
    coords_point = coords_point.split(',').map(parseFloat);

    map = new ymaps.Map('yamap', {
      center: center,
      zoom: zoom,
      controls: [],
    });

    object = new ymaps.GeoObject({
      geometry: {
        type: "Point",
        coordinates: coords_point
      },
    });

    map.geoObjects.add(object);
  }
});

window.print();
#yamap {
  width: 300px;
  height: 200px;
}


Ответы

Ответ 1



Поместите хотя бы window.print() внутрь ymaps.ready() и вместо ymaps.ready(init) вызывайте просто init(). Дополнено Событий, однозначно показывающих полное окончание всех процедур составления карты пока нет. Однако, как показывает практика, загрузка карты заканчивается загрузкой всех тайлов. И в документации есть описание как можно добавлять новые слои с тайлами. Это делается при помощи классов layer.tileContainer.CanvasContainer и layer.tileContainer.DomContainer. У этих-то классов есть событие ready, которое вызывается когда все тайлы слоя загружены. И они даже используются при отображении карт, но до их экземпляра не так просто добраться. Если вы ничего не делаете со слоями, то на карте есть один единственный слой (если слоев все-таки несколько, придется обрабатывать все слои в циклах), к которому можно достучаться вот так var layer = map.layers.get(0).get(0); /* Сначала мы получаем первый экземпляр коллекции слоев, потом первый слой коллекции */ Так мы получаем экземпляр Layer, но в его описании нету ничего про tileContainer, однако это поле там есть, только оно как бы приватное и при минимизации становится неудобоваримым (в debug версии это поле _tileContainer). Чтобы его найти можно воспользоваться вот такой функцией: function getTileContainer(layer) { for (var k in layer) { if (layer.hasOwnProperty(k)) { if ( layer[k] instanceof ymaps.layer.tileContainer.CanvasContainer || layer[k] instanceof ymaps.layer.tileContainer.DomContainer ) { return layer[k]; } } } return null; } Теперь можно сделать так: var tc = getTileContainer(layer); tc.events.once("ready", function() { // Вызываем, например, печать документа window.print(); }); Одно плохо. Мы не узнаем о загрузке всех тайлов если выяснится, что мы не успели начать слушать событие до окончания загрузки тайлов. Неплохо было бы знать вообще чего-то ждем или нет. Для этого перед "подслушиванием" события нужно узнать есть-ли "неготовые" тайлы. Это можно проверить если перебрать все тайлы в контейнере и вызвать методы isReady() для layer.tile.CanvasTile или layer.tile.DomTile, после этого, если неготовые тайлы есть подключать событие. Будет удобно сделать такую функцию, которая будет возвращать промис. function waitForTilesLoad(layer) { return new ymaps.vow.Promise(function (resolve, reject) { var tc = getTileContainer(layer), readyAll = true; tc.tiles.each(function (tile, number) { if (!tile.isReady()) { readyAll = false; } }); if (readyAll) { resolve(); } else { tc.events.once("ready", function() { resolve(); }); } }); } В вашем случае этой функцией можно воспользоваться так: waitForTilesLoad(layer).then(function() { window.print(); });

Ответ 2



Привожу код, написанный @tutankhamun. // Здесь ваша загрузка карты. Ниже допишем строки. /* Поймаем событие завершения загрузки карты. */ // Сначала мы получаем первый экземпляр коллекции слоев, потом первый слой коллекции. var layer = myMap.layers.get(0).get(0); // Отслеживаем событие окончания отрисовки тайлов. waitForTilesLoad(layer).then(function() { // Вызываем, например, печать документа window.print(); alert('Карта загружена'); }); } // Получить слой, содержащий тайлы. function getTileContainer(layer) { for (var k in layer) { if (layer.hasOwnProperty(k)) { if ( layer[k] instanceof ymaps.layer.tileContainer.CanvasContainer || layer[k] instanceof ymaps.layer.tileContainer.DomContainer ) { return layer[k]; } } } return null; } // Определить, все ли тайлы загружены. Возвращает Promise. function waitForTilesLoad(layer) { return new ymaps.vow.Promise(function (resolve, reject) { var tc = getTileContainer(layer), readyAll = true; tc.tiles.each(function (tile, number) { if (!tile.isReady()) { readyAll = false; } }); if (readyAll) { resolve(); } else { tc.events.once("ready", function() { resolve(); }); } }); }

Комментариев нет:

Отправить комментарий