Print Yandex.Maps under API 2.x with tags and clusters

Everyone knows that printing an API 2.x core map with labels and clusters just doesn’t work. Until now, the map is not built on canvas, but on divas with a backing (background-image). And canvas doesn’t help your favorite browser.
The task was set to quickly make a printable version of the map. The number of labels is more than 600 + clusters “out of the box”.
We’ll
initialize the working version under the cutter
as usual - we take the zoom and center from the link
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?>]
        });

make a printer-friendly layout for the label;
I must say that printer-friendly means that we do not use background-image, but do a bunch of divs with images.
my tag icon consists of 2 parts - a picture and a background. both in sprite. therefore such a frantic style. I bring it inline for clarity
        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>'
            ));


the same thing with the cluster icon. I did not bother with different sizes of cluster icons for a different number of points inside - I had to quickly)
        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>'));


here we get the container of the layer itself
        var $container = map.panes.get('layers').getElement(),

since the types of cards in statics are different, we make correspondence and get the center of the card
            stMapTypes = {'yandex#map' : 'map', 'yandex#satellite' : 'sat', 'yandex#hybrid' : 'sat,ski', 'yandex#publicMap' : 'pmap'},
            center = map.getCenter(),


size is an ambush. the static gives a maximum of 650 to 450. I also did not bother - let it be a maximum
div with a map, you also need to do no more than these sizes.
in a good way, if you make a div with a large map, you need a different approach - through layer.
          size = [650, 450],

form link for statics
            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];

here the magic begins,
we make a div with absolute positioning and place it in the middle, since the pane will be attached to the center of the viewport. in fact, you had to call map.panes.get ('layers'). getViewport () and read the center. but when loading, pane lies in the middle, and we won’t let the map move
        $('<div></div>').css({
                position: 'absolute',
                left: -Math.round(size[0] / 2)+'px',
                top: -Math.round(size[1] / 2)+'px',
                zIndex: 800}).

insert inside img with statics
            wrapInner($('<img>').attr({'src':mapUrl, width: size[0], height: size[1], border: '0'})).

and insert into the container of the layer over the remaining elements
            prependTo($container);

good feature - disables all map events. now neither move nor think
       map.events.removeAll();

here I add my markers to the map. I have them in the variable 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
                    }));
            }

now a cluster. what is margin - I do not remember, but it was on a normal map
       var clusterer = new ymaps.Clusterer({margin: [20]});

for cluster icons set the layout
          clusterer.options.set('clusterIconLayout', 'voina#cluster');

I didn’t want to write this function, but I couldn’t open the clusters differently
          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;
            };

add markers to the cluster
    clusterer.add(markers);

just in case, the cluster is also drowned out
            clusterer.events.removeAll();

add a cluster to the card
            map.geoObjects.add(clusterer);
        }
    });


TA-dah!!! everything works and prints (if the browser can withstand so many dom objects) there is
only one bug - two copyrights. when deleting from the card or even hiding errors are pouring in. for and okay.



You can see here