2015-04-04 16 views
5

Tôi có vấn đề CSS/JavaScript thú vị. Tôi đang xây dựng một bản đồ web thân thiện với người dùng sẽ bao gồm thông tin địa lý tình nguyện và cần có khả năng in ở nhiều kích cỡ giấy, lên đến kích thước poster. Đối với giao diện, tôi đang làm việc với Leaflet.js, Mapbox.js và jQuery. Cách tôi tiếp cận in là thiết lập cửa sổ xem trước chỉ hiển thị lớp phủ (không có tileLayer) trên L.Map hoàn toàn mới với nền trắng, với các điểm đánh dấu được tỷ lệ tương ứng với kích thước giấy do người dùng chọn. Ý tưởng là bản đồ sẽ điền vào trang và các điểm đánh dấu sẽ luôn in ở cùng kích thước (8 mm cho điểm đánh dấu vòng tròn, 10 mm cho biểu tượng). Dưới đây là một ảnh chụp màn hình của cửa sổ xem trước trong Firefox:Tờ rơi mở rộng bản đồ để điền vào trang in

print preview window

Có một chút công bằng của mã phức tạp. Đủ để nói rằng bất cứ khi nào người dùng thay đổi kích thước cửa sổ hoặc hướng giấy, hộp xem trước và biểu tượng thay đổi kích thước cho phù hợp. Bất cứ khi nào người dùng thay đổi kích thước giấy, các biểu tượng thay đổi kích thước nhưng hộp xem trước không, để đại diện cho tỷ lệ kích thước chính xác. Dưới đây là các chức năng Tôi đang sử dụng để làm điều đó:

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) 
    }) 
}; 

Tôi có @media print phong cách CSS mà dường như làm việc tốt để in cửa sổ xem trước:

@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; 
    } 
} 

Tôi đã thử nghiệm điều này bằng cách in một tệp PDF bằng trình điều khiển của Adobe. Dưới đây là kết quả:

PDF print of map

Có vẻ như để làm việc tốt - ngoại trừ các dấu chỉ điền phần trên bên trái của trang, trong khi tôi muốn họ mở rộng ra nước ngoài để lấp đầy toàn bộ trang do đó sản phẩm cuối cùng là 'chế độ xem' giống như hộp xem trước. Đây là nơi tôi đang bối rối và sẽ chào đón bất kỳ lời khuyên hoặc ý tưởng từ bất cứ ai đã thử một cái gì đó tương tự hoặc biết cách của họ xung quanh các trang web in ấn.

Trả lời

1

Trong một dự án tương tự, tôi đã buộc bản đồ phải làm mới sau khi bất kỳ thay đổi kích thước CSS nào thông qua phương thức invalidateSize. Ví dụ sử dụng jQuery để thay đổi chiều cao bản đồ và cân div:

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

Theo leaflet help:

invalidateSize: Kiểm tra nếu kích thước container đồ thay đổi và cập nhật bản đồ nếu như vậy - gọi nó là sau khi bạn' đã thay đổi kích thước bản đồ động, cũng làm hoạt hình pan theo mặc định.

Các vấn đề liên quan