Всем известно, что напечать ядрекс-карту API 2.х с метками и кластерами просто так не получится. До сих пор карта строится не на канвасе, а на дивах с подложкой (background-image). Да и канвас любимому браузеру не поможет.
Была поставлена задача — быстро сделать версию для печати карты. Количество меток — более 600 + кластеры «из коробки».
Работающий вариант под катом
инициализируем карту как обычно — зум и центр берем из ссылки
ymaps.ready(function () {
var mapTypes = ['yandex#map', 'yandex#satellite', 'yandex#hybrid', 'yandex#publicMap', 'yandex#publicMapHybrid'],
map = new ymaps.Map($('#map')[0], {
center:[ parseFloat(<?= $request_lat?>),
parseFloat(<?= $request_lng?>)],
zoom:parseInt(<?= $request_zoom?>),
type: mapTypes[<?= $request_mtype ? $request_mtype : 0?>]
});
делаем принтер-френдли лейаут для метки
тут надо сказать, что принтер-френдли — это значит, что не используем background-image, а делаем кучу дивов с имиджами.
у меня иконка метки состоит из 2 частей — картинки и подложки. и то и другое — в спрайте. поэтому такой бешеный style. его я привожу inline для наглядности
ymaps.layout.storage.add('voina#icon', ymaps.templateLayoutFactory.createClass(
'<div style="position: absolute; width: 28px; height: 36px; overflow: hidden;z-index: 0; ">' +
'<div style="position:absolute;width:20px;height:20px;overflow:hidden;top:4px;left:4px">' +
'<img src="/img/new_buttons_21.png" style="position:absolute;left:$[properties.iconOffset]px;"></div>' +
'<img src="/img/buttons7.gif" style="position: absolute; left: -264px; top: -70px; "></div>'
));
то же самое — с иконкой кластера. заморачиваться с разными размерами иконок кластера под разное количество точек внутри я не стал — быстро надо было)
ymaps.layout.storage.add('voina#cluster', ymaps.templateLayoutFactory.createClass(
'<div style="position: absolute; margin: -26px 0 0 -26px; width: 58px; height: 58px; overflow: hidden;z-index: 0; ">' +
'<div style="z-index:800;position: absolute; width: 58px; height: 58px; text-align: center; font-size: 13px; line-height: 58px;">$[properties.geoObjects.length]</div>' +
'<img src="/img/cluster_big.png" style="position: absolute;"></div>'));
здесь получаем контейнер лейера самОй подложки карты
var $container = map.panes.get('layers').getElement(),
так как типы карты у статики другие, делаем соответствия и получаем центр карты
stMapTypes = {'yandex#map' : 'map', 'yandex#satellite' : 'sat', 'yandex#hybrid' : 'sat,ski', 'yandex#publicMap' : 'pmap'},
center = map.getCenter(),
size — это засада. статик отдает максимум 650 на 450. тоже заморачиваться не стал — пускай будет максимум
div с картой тоже надо делать не больше этих размеров.
по-хорошему, если делать див с картой большого размера, нужен другой подход — через layer.
size = [650, 450],
формируем линку для статики
mapUrl = 'http://static-maps.yandex.ru/1.x/?ll='+center[1]+','+center[0]+
'&z='+map.getZoom()+'&l='+stMapTypes[map.getType()]+
'&size='+size[0]+','+size[1];
тут начинается магия
делаем див с абсолютным позиционированием и располагаем его посередине, так как привязка pane будет к центру вьюпорта. на самом деле, надо было вызывать map.panes.get('layers').getViewport() и считать центр. но при загрузке pane лежит посередине, а карту мы двигать не дадим
$('<div></div>').css({
position: 'absolute',
left: -Math.round(size[0] / 2)+'px',
top: -Math.round(size[1] / 2)+'px',
zIndex: 800}).
вставляем внутрь img со статикой
wrapInner($('<img>').attr({'src':mapUrl, width: size[0], height: size[1], border: '0'})).
и вставляем в контейнер лейера над остальными элементами
prependTo($container);
хорошая функция — отключает все события карты. теперь ни сдвинуть, ни позумить
map.events.removeAll();
тут я добавляю на карту свои маркеры. они у меня лежат в переменной window.data
var len = window.data.length;
if (len)
{
for (var i = 0, markers = [ ], properties, latLng; i < len; i++) {
latLng = [parseFloat(window.data[i][1]), parseFloat(window.data[i][2])];
markers.push( new ymaps.Placemark(latLng,
{ iconOffset: -window.data[i][5] * 20 - 1 },
{
iconLayout:'voina#icon',
iconOffset: [1, 2],
openBalloonOnClick: false
}));
}
теперь кластерер. что такое margin — я не помню, но было на нормальной карте
var clusterer = new ymaps.Clusterer({margin: [20]});
для иконок кластеров устанавливаем макет
clusterer.options.set('clusterIconLayout', 'voina#cluster');
не хотелось писать эту функцию, но по-другому заставить кластеры не раскрываться не смог
clusterer.createCluster = function (center, geoObjects) {
var cluster = ymaps.Clusterer.prototype.createCluster.call(this, center, geoObjects);
// вот сюда я вписал все возможные отменялки поднятия события
cluster.events.add('click', function(e) {
e.stopImmediatePropagation();
e.preventDefault();
return false;
});
return cluster;
};
добавляем маркеры в кластерер
clusterer.add(markers);
на всякий случай кластерер тоже заглушим
clusterer.events.removeAll();
добавляем кластерер на карту
map.geoObjects.add(clusterer);
}
});
тада!!! все работает и печатается (если браузер выдержит такое количества dom-объектов)
один лишь баг — два копирайта. при удалении с карты или даже скрытия сыпятся ошибки. для и ладно.
посмотреть можно тут
Автор: Pamarkin