Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Leaflet expand map to fill page on print

I have in interesting CSS/JavaScript problem. I am building a user-friendly web map that will include volunteered geographic information and needs to have the ability to print at multiple paper sizes, up to poster size. For the interface, I am working with Leaflet.js, Mapbox.js, and jQuery. The way I've approached printing is to set up a preview window that shows overlays only (no tileLayer) on a completely new L.Map with a white background, with the markers scaled proportionally to the paper size selected by the user. The idea is that the map will fill the page and the markers will always print at the same size (8 mm across for circle markers, 10 mm for icons). Here's a screenshot of the preview window in Firefox:

print preview window

There is a fair bit of complex code. Suffice it to say that whenever the user changes the window size or paper orientation, the preview box and icons resize accordingly. Whenever the user changes the paper size, the icons resize but the preview box does not, so as to represent the correct size ratios. Here are the functions I'm using to do it:

function adjustPreviewBox(){
    //set preview box dimensions based on print window size and paper orientation
    if ($("#paperOrientation option[value=portrait]").prop("selected")){
        var height = $("#printBox").height() - 61;
        var width = height / Math.sqrt(2);
        $("#printPreview").height(height);
        $("#printPreview").width(width);
    } else {
        //first set by horizontal dimension
        var width = $("#printBox").width() - 300;
        var height = width / Math.sqrt(2);
        //check for vertical overflow
        if (height > $("#printBox").height() - 61){
            height = $("#printBox").height() - 61;
            width = height * Math.sqrt(2);
        };
        $("#printPreview").height(height);
        $("#printPreview").width(width);
    }
};

function adjustScale(){
    //change symbol sizes and ratio scale according to paper size
    var prevWidth = $("#printPreview").width();
    var prevHeight = $("#printPreview").height();
    var size = $("#paperSize select option:selected").val();
    var series = size[0];
    var pScale = Number(size[1]);
    var longside, mmppPaper;
    if (series == "A"){ //equations for long side lengths in mm, minus 10mm print margins
        longside = Math.floor(1000/(Math.pow(2,(2*pScale-1)/4)) + 0.2) - 20;
    } else if (series == "B"){
        longside = Math.floor(1000/(Math.pow(2,(pScale-1)/2)) + 0.2) - 20;
    };   
    //find the mm per pixel ratio
    mmppPaper = prevWidth > prevHeight ? longside / prevWidth : longside / prevHeight;
    var mapZoom = printPreviewMap.getZoom();
    var scaleText = $("#printBox .leaflet-control-scale-line").html().split(" ");
    var multiplier = scaleText[1] == "km" ? 1000000 : 1000;
    var scalemm = Number(scaleText[0]) * multiplier;
    var scalepx = Number($("#printBox .leaflet-control-scale-line").width());
    var mmppMap = scalemm / scalepx;
    var denominator = Math.round(mmppMap / mmppPaper);
    $("#ratioScale span").text(denominator);
    return [mmppMap, mmppPaper];
}

function resizeMarkers(markerType, init){
    //scale preview marker size based on paper size and orientation
    markerType == "circle" ? changeRadius(init) : changeIconSize(init);
};

function getRadius(){
    //adjust ratio scale and return scale ratios
    var scales = adjustScale();
    var mmppPaper = scales[1];
    return 4 / mmppPaper;
};

function changeRadius(init){
    //each circle marker will print at 8 mm diameter regardless of map scale and page size
    var radius = getRadius();
    printPreviewMap.eachLayer(function(layer){
        if (typeof layer._radius !== 'undefined'){
            if (init == true){
                layer.setStyle({
                    opacity: 1,
                    fillOpacity: 1
                });
                layer.unbindPopup();
            };
            layer.setRadius(radius);
        }
    });
};

function changeIconSize(init){
    //each icon will print at 10 mm per side regardless of map scale and page size
    var side = 2.5 * getRadius();

    //need to change dimensions and offset
    $("#printPreview .leaflet-marker-icon").css({
        width: side + "px",
        height: side + "px",
        "margin-left": -(side / 2),
        "margin-top": -(side / 2)
    })
};

I have @media print CSS styles that seem to work well for printing the preview window:

@media print {
    @page {
        size: auto;
        margin: 10mm;
    }

    #printBox, #printPreview {
        position: absolute;
        max-height: 100%;
        bottom: 0;
        left: 0;
        top: 0;
        right: 0;
    }

    #printPreview {
        position: absolute !important;
        width: 100% !important;
        height: 100% !important;
        border: none;
    }

    #scalegrip {
        visibility: hidden;
    }

    #container {
        visibility: hidden;
    }
}

I've tested this by printing to a PDF using Adobe's driver. Here's the result:

PDF print of map

It seems to work fine--except that the markers only fill the upper-left part of the page, whereas I would like them to expand outward to fill the entire page so that the final product is the same 'view' as the preview box. This is where I'm stumped and would welcome any advice or ideas from anyone who has tried something similar or knows their way around printing websites.

like image 763
northlandiguana Avatar asked Nov 01 '22 07:11

northlandiguana


1 Answers

In a similar project, I had to force the map to refresh after any CSS size changes through the invalidateSize method. For example using jQuery to change map height and weight div:

$("map").css('width', '267mm');
$("map").css('height', '210mm');
map.invalidateSize();

According to leaflet help:

invalidateSize: Checks if the map container size changed and updates the map if so — call it after you've changed the map size dynamically, also animating pan by default.

like image 180
David Avatar answered Nov 08 '22 04:11

David