Select to view content in your preferred language

Custom Print maintaining scale 1 inch = 100 ft

175
0
08-05-2024 07:50 AM
QDSGIS
by
Emerging Contributor

Hello, 

My client needs a custom print functionality (the javascript sdk is too slow and doesn't maintain scale) that when a user prints the map at 1 inch = 100 ft, the printed image maintains that scale when they put a ruler to it. I have been trying quite a few ways, but my best seems to be 1 inch = 90 ft. Here is my code for the print: 

document
.getElementById("Print-selector")
.addEventListener("click", function () {
captureMap();
});

function captureMap() {
const printDPI = 300; // Standard print DPI
const pageWidthInInches = 8.5; // Width of the paper in inches
const pageHeightInInches = 11; // Height of the paper in inches
const mapWidthInInches = 8; // Slightly reduced width of the map on paper in inches
const mapHeightInInches = 7; // Slightly reduced height of the map on paper in inches
const mapWidthInPixels = mapWidthInInches * printDPI;
const mapHeightInPixels = mapHeightInInches * printDPI;

view
.takeScreenshot({
width: mapWidthInPixels,
height: mapHeightInPixels,
})
.then(function (screenshot) {
const title = "Map Title"; // Set your dynamic title here
const printWindow = window.open("", "_blank");
const scaleBar1 = document.getElementById("scale-value");
const scaleBarHTML = scaleBar1.innerHTML;
const currentDate = new Date().toLocaleString();

printWindow.document.write(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Print Map</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
}
.print-title {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 24px;
margin: 20px 0;
}
.print-scale {
display: flex;
align-items: center;
justify-content: space-around;
text-align: center;
font-size: 14px;
width: 100%;
margin-left: 20px;
margin-right: 20px;
}
.print-title img {
margin-right: 20px;
}
.scale-bar-container {
transform: scale(1.5);
margin-right: 50px;
}
.print-scale-bar {
width: 300px;
height: 30px;
}
.info-writing-container {
display: flex;
justify-content: center;
align-items: flex-start;
width: 80%;
margin: 20px auto;
}
.info-text {
width: 20%;
text-align: left;
margin-right: 20px;
}
.writing-lines {
width: 80%;
text-align: center;
}
.writing-lines div {
border-bottom: 1px solid black;
margin: 10px 0;
height: 20px;
}
@media print {
body * {
visibility: visible;
}
}
</style>
</head>
<body>
<div class="print-title" id="print-title">
<img id="town-logo" src="${configVars.welcomeImage}" alt="Town Logo">
<h1 id="title-text">${configVars.title}</h1>
</div>
<div class="print-map">
<img id="print-map-image" src="${screenshot.dataUrl}" alt="Map Image" style="width: ${mapWidthInInches}in; height: auto; border: 3px solid #A9A9A9; margin: 0 0.75in;">
</div>
<div class="print-scale">
<div class="print-date" style="font-size: 12px;">Date Printed: ${currentDate}</div>
<div id="to-scale" class="scale-bar-container"></div>
<div id="print-scale-bar" class="scale-bar-container">${scaleBarHTML}</div>
</div>
<div style="text-align: center; font-size: 12px; padding-left: 30px; padding-right: 30px;">
<p>Disclaimer: This map is intended for reference and general informational purposes
only and is not a legally recorded map or survey. While reasonable effort has been
made to ensure the accuracy, correctness, and timeliness of materials presented,
the map vendor and the municipality disclaim any and all liability and responsibility for
any errors, omissions, or inaccuracies in the data provided, including without limitation
any liability for direct, indirect, incidental, consequential, special, exemplary,
punitive, or any other type of damages. Users are hereby notified that the primary
information source should be consulted for verification of the data contained herein.
Continued use of this map acknowledges acceptance of these terms.</p>
</div>
<script>
window.onload = function() {
window.print();
};
</script>
</body>
</html>
`);
printWindow.document.close();
});
}

Here is also my code for the user to dynamically set the map scale with a dropdown: 
<!-- Default dropup button -->
<div id='scale-dropdown' class="btn-group dropup ">
<button type="button" style="color: white;" id="scale-value" class="btn bg-info btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
Select Scale
</button>

<div class="dropdown-menu dropdown-menu-sm dropp-2">
<button value="240" class="dropdown-item btn-sm scale-select" type="button">1 inch = 20 feet</button>
<button value="600" class="dropdown-item btn-sm scale-select" type="button">1 inch = 50 feet</button>
<button value="1200" class="dropdown-item btn-sm scale-select" type="button">1 inch = 100 feet</button>
<button value="2400" class="dropdown-item btn-sm scale-select" type="button">1 inch = 200 feet</button>
<button value="6000" class="dropdown-item btn-sm scale-select" type="button">1 inch = 500 feet</button>
<button value="9600" class="dropdown-item btn-sm scale-select" type="button">1 inch = 800 feet</button>
<button value="18000" class="dropdown-item btn-sm scale-select" type="button">1 inch = 1500 feet</button>
<button value="36000" class="dropdown-item btn-sm scale-select" type="button">1 inch = 3000 feet</button>
<button value="72000" class="dropdown-item btn-sm scale-select" type="button">1 inch = 6000 feet</button>
<button value="144000" class="dropdown-item btn-sm scale-select" type="button">1 inch = 12000 feet</button>
</div>
</div>
// Scale mapping
var scaleMapping = {
240: "1 inch = 20 feet",
600: "1 inch = 50 feet",
1200: "1 inch = 100 feet",
2400: "1 inch = 200 feet",
6000: "1 inch = 500 feet",
9600: "1 inch = 800 feet",
18000: "1 inch = 1500 feet",
36000: "1 inch = 3000 feet",
72000: "1 inch = 6000 feet",
144000: "1 inch = 12000 feet",
};

// Add event listener for scale selection
var scaleDropdown = document.getElementById("scale-dropdown");

document.querySelectorAll(".scale-select").forEach(function (button) {
button.addEventListener("click", function (event) {
var selectedScale = parseInt(event.target.value);
var selectedText = event.target.innerHTML;
console.log(selectedScale);
if (selectedScale) {
view.scale = selectedScale;
}

$("#scale-value").val(selectedScale).html(selectedText);
});
});

view.ui.add(scaleDropdown);

// Watch for changes in the view's scale and update the dropdown
const handle = reactiveUtils.watch(
() => [view.stationary, view.scale],
([stationary, scale]) => {
// Only print the new scale value when the view is stationary
if (stationary) {
// console.log(`Change in scale level: ${scale}`);
updateScaleDropdown(scale);
}
}
);

function updateScaleDropdown(scale) {
var roundedScale = Math.round(scale);
var scaleText = getScaleText(roundedScale);

if (scaleText) {
$("#scale-value").val(roundedScale).html(scaleText);
}
}

function getScaleText(scale) {
// Find the closest scale in the mapping
var closestScale = Object.keys(scaleMapping).reduce(function (
prev,
curr
) {
return Math.abs(curr - scale) < Math.abs(prev - scale) ? curr : prev;
});

return scaleMapping[closestScale];
}


0 Kudos
0 Replies