Add waypoints to printed PDF (#307)
* Print waypoints * add waypoint titles and format nicely with description and first page * add translations * handle creation of second page a bit better * adds padding between waypoint name and description --------- Co-authored-by: Christian Beutel <>
This commit is contained in:
@@ -164,6 +164,7 @@
|
||||
"import": "Importieren",
|
||||
"import-hint": "GPX, FIT, KML oder TCX Dateien auswählen oder hierher ziehen...",
|
||||
"include-description": "Beschreibung übernehmen",
|
||||
"include-waypoints": "Wegpunkte einbeziehen",
|
||||
"integration-description-komoot": "Synchronisiert Deine komoot Touren regelmäßig mit wanderer.",
|
||||
"integration-description-strava": "Synchronisiert Deine strava Routen und Aktivitäten regelmäßig mit wanderer.",
|
||||
"integration-disabled": "Integration deaktiviert",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Import",
|
||||
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
||||
"include-description": "Include description",
|
||||
"include-waypoints": "Include waypoints",
|
||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||
"integration-disabled": "integration disabled",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importar",
|
||||
"import-hint": "Selecciona o arrastra aquí archivos GPX, FIT, KML o TCX...",
|
||||
"include-description": "Incluir descripción",
|
||||
"include-waypoints": "Incluir puntos de interés",
|
||||
"integration-description-komoot": "Sincroniza tus recorridos de Komoot con Wanderer en intervalos regulares.",
|
||||
"integration-description-strava": "Sincroniza tus recorridos de Strava con Wanderer en intervalos regulares.",
|
||||
"integration-disabled": "integración deshabilitada",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importer",
|
||||
"import-hint": "Sélectionnez ou glissez des fichiers GPX, FIT, KML ou TCX ici...",
|
||||
"include-description": "Inclure la description",
|
||||
"include-waypoints": "Inclure les points de passage",
|
||||
"integration-description-komoot": "Synchronisez vos Tours Komoot avec wanderer à intervalles réguliers.",
|
||||
"integration-description-strava": "Synchronisez vos itinéraires et vos activités Strava avec wanderer à intervalles réguliers.",
|
||||
"integration-disabled": "Intégration désactivée",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Import",
|
||||
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
||||
"include-description": "Include description",
|
||||
"include-waypoints": "Útpontok hozzáadása",
|
||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||
"integration-disabled": "integration disabled",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importa",
|
||||
"import-hint": "Seleziona o trascina qui i file GPX, FIT, KML o TCX...",
|
||||
"include-description": "Adotta descrizione",
|
||||
"include-waypoints": "Includi waypoint",
|
||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||
"integration-disabled": "integration disabled",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importeer",
|
||||
"import-hint": "Selecteer of sleep GPX-, FIT-, KML- of TCX-bestanden hierheen...",
|
||||
"include-description": "Inclusief beschrijving",
|
||||
"include-waypoints": "Waypoints toevoegen",
|
||||
"integration-description-komoot": "Synchroniseert je Komoot-tochten met Wanderer op regelmatige tijdstippen.",
|
||||
"integration-description-strava": "Synchroniseert je Strava-routes en -activiteiten met Wanderer op regelmatige tijdstippen.",
|
||||
"integration-disabled": "Integratie uitgeschakeld",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importuj",
|
||||
"import-hint": "Wybierz lub przeciągnij tutaj plik GPX, FIT, KML lub TCX...",
|
||||
"include-description": "Dołącz opis",
|
||||
"include-waypoints": "Uwzględnij punkty trasy",
|
||||
"integration-description-komoot": "Synchronizuje trasy kamoot z wanderer w równych odstępach.",
|
||||
"integration-description-strava": "Synchronizuje trasy i aktywność z wanderer w równych odstępach.",
|
||||
"integration-disabled": "integracja wyłączona",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "Importar",
|
||||
"import-hint": "Selecionar ou arrastar ficheiros GPX, FIT, KML ou TCX para aqui...",
|
||||
"include-description": "Incluir descrição",
|
||||
"include-waypoints": "Incluir pontos de passagem",
|
||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||
"integration-disabled": "integration disabled",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"import": "导入",
|
||||
"import-hint": "在此选择或拖拽GPX、FIT、KML或TCX文件...",
|
||||
"include-description": "包含描述",
|
||||
"include-waypoints": "包括航点",
|
||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||
"integration-disabled": "integration disabled",
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
let printLoading: boolean = $state(false);
|
||||
|
||||
let includeDescription: boolean = $state(false);
|
||||
let includeWaypoints: boolean = $state(false);
|
||||
|
||||
onMount(() => {
|
||||
let qrcode = new QrCodeWithLogo({
|
||||
@@ -92,6 +93,30 @@
|
||||
});
|
||||
});
|
||||
|
||||
function faUnicode(name: string) {
|
||||
var testI = document.createElement('i');
|
||||
var char;
|
||||
|
||||
testI.className = 'fa fa-' + name;
|
||||
document.body.appendChild(testI);
|
||||
|
||||
char = window.getComputedStyle( testI, ':before' )
|
||||
.content.replace(/'|"/g, '');
|
||||
|
||||
testI.remove();
|
||||
|
||||
return char.charCodeAt(0);
|
||||
}
|
||||
|
||||
function getTextHeight(text: string, doc: jsPDF, width: number) {
|
||||
let numLines = doc.splitTextToSize(text, width).length;
|
||||
|
||||
return (numLines * doc.getFontSize() * doc.getLineHeightFactor() -
|
||||
doc.getFontSize() * (doc.getLineHeightFactor() - 1)) /
|
||||
doc.internal.scaleFactor;
|
||||
|
||||
}
|
||||
|
||||
async function print() {
|
||||
if (!map) {
|
||||
return;
|
||||
@@ -328,25 +353,17 @@
|
||||
doc.setFont("IBMPlexSans-Regular", "normal");
|
||||
doc.text($trail.location || "-", 12, currentHeight);
|
||||
|
||||
// End of page
|
||||
currentHeight = height;
|
||||
|
||||
// Logo
|
||||
const logo = new Image();
|
||||
logo.src = "/imgs/logo_text_dark.png";
|
||||
const logoRatio = 64 / 212;
|
||||
const logoWidth = 32;
|
||||
const logoHeight = logoWidth * logoRatio;
|
||||
doc.addImage(
|
||||
logo,
|
||||
width - 8 - logoWidth,
|
||||
height - 4 - logoHeight,
|
||||
logoWidth,
|
||||
logoHeight,
|
||||
);
|
||||
|
||||
if (includeDescription && $trail.description) {
|
||||
doc.addPage();
|
||||
doc.text(formatHTMLAsText($trail.description), 16, 16, {
|
||||
maxWidth: width - 32,
|
||||
});
|
||||
function addLogo() {
|
||||
doc.addImage(
|
||||
logo,
|
||||
width - 8 - logoWidth,
|
||||
@@ -356,6 +373,68 @@
|
||||
);
|
||||
}
|
||||
|
||||
function newPage() {
|
||||
addLogo();
|
||||
doc.addPage();
|
||||
currentHeight = 16;
|
||||
}
|
||||
|
||||
if (includeDescription && $trail.description) {
|
||||
let textHeight = getTextHeight($trail.description, doc, width - 32)
|
||||
if (currentHeight + textHeight + 8 > height) {
|
||||
newPage();
|
||||
}
|
||||
doc.text(formatHTMLAsText($trail.description), 16, currentHeight, {
|
||||
maxWidth: width - 32,
|
||||
});
|
||||
currentHeight += getTextHeight($trail.description, doc, width - 32) + 8;
|
||||
}
|
||||
|
||||
if (includeWaypoints && $trail.expand?.waypoints) {
|
||||
const header = $_("waypoints", { values: { n: 2 } })
|
||||
let textHeight = getTextHeight(header, doc, width - 32)
|
||||
if (currentHeight + textHeight + 8 > height) {
|
||||
newPage();
|
||||
}
|
||||
doc.setFont("IBMPlexSans-SemiBold", "bold");
|
||||
doc.text(header, 16, currentHeight);
|
||||
currentHeight += textHeight + 8;
|
||||
doc.setFont("IBMPlexSans-Regular", "normal");
|
||||
|
||||
($trail.expand.waypoints || []).forEach(waypoint => {
|
||||
let description = waypoint.description || "";
|
||||
let name = waypoint.name || "";
|
||||
|
||||
let content = description;
|
||||
if (name) {
|
||||
content = `${name}\n${description}`;
|
||||
}
|
||||
|
||||
let textHeight = getTextHeight(content, doc, width - 32)
|
||||
if (currentHeight + textHeight + 16 > height) {
|
||||
newPage();
|
||||
}
|
||||
|
||||
doc.setFont("fa-solid-900", "normal");
|
||||
doc.text(String.fromCharCode(faUnicode(waypoint.icon || "circle")), 16, currentHeight);
|
||||
doc.setFont("IBMPlexSans-Regular", "normal");
|
||||
|
||||
if (name) {
|
||||
doc.setFont("IBMPlexSans-SemiBold", "bold");
|
||||
doc.text(name, 24, currentHeight);
|
||||
currentHeight += getTextHeight(name, doc, width - 32) + 2;
|
||||
doc.setFont("IBMPlexSans-Regular", "normal");
|
||||
}
|
||||
|
||||
doc.text(description, 24, currentHeight, {
|
||||
maxWidth: width - 32 - 8
|
||||
});
|
||||
currentHeight += textHeight + 8;
|
||||
});
|
||||
}
|
||||
|
||||
addLogo();
|
||||
|
||||
doc.save($trail.name + ".pdf");
|
||||
printLoading = false;
|
||||
} catch (e) {
|
||||
@@ -504,6 +583,17 @@
|
||||
>{$_("include-description")}</label
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
id="waypoints-checkbox"
|
||||
type="checkbox"
|
||||
bind:checked={includeWaypoints}
|
||||
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
|
||||
/>
|
||||
<label for="waypoints-checkbox" class="ms-2 text-sm"
|
||||
>{$_("include-waypoints")}</label
|
||||
>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
loading={printLoading}
|
||||
|
||||
Reference in New Issue
Block a user