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": "Importieren",
|
||||||
"import-hint": "GPX, FIT, KML oder TCX Dateien auswählen oder hierher ziehen...",
|
"import-hint": "GPX, FIT, KML oder TCX Dateien auswählen oder hierher ziehen...",
|
||||||
"include-description": "Beschreibung übernehmen",
|
"include-description": "Beschreibung übernehmen",
|
||||||
|
"include-waypoints": "Wegpunkte einbeziehen",
|
||||||
"integration-description-komoot": "Synchronisiert Deine komoot Touren regelmäßig mit wanderer.",
|
"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-description-strava": "Synchronisiert Deine strava Routen und Aktivitäten regelmäßig mit wanderer.",
|
||||||
"integration-disabled": "Integration deaktiviert",
|
"integration-disabled": "Integration deaktiviert",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Import",
|
"import": "Import",
|
||||||
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
||||||
"include-description": "Include description",
|
"include-description": "Include description",
|
||||||
|
"include-waypoints": "Include waypoints",
|
||||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
"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-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||||
"integration-disabled": "integration disabled",
|
"integration-disabled": "integration disabled",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importar",
|
"import": "Importar",
|
||||||
"import-hint": "Selecciona o arrastra aquí archivos GPX, FIT, KML o TCX...",
|
"import-hint": "Selecciona o arrastra aquí archivos GPX, FIT, KML o TCX...",
|
||||||
"include-description": "Incluir descripción",
|
"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-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-description-strava": "Sincroniza tus recorridos de Strava con Wanderer en intervalos regulares.",
|
||||||
"integration-disabled": "integración deshabilitada",
|
"integration-disabled": "integración deshabilitada",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importer",
|
"import": "Importer",
|
||||||
"import-hint": "Sélectionnez ou glissez des fichiers GPX, FIT, KML ou TCX ici...",
|
"import-hint": "Sélectionnez ou glissez des fichiers GPX, FIT, KML ou TCX ici...",
|
||||||
"include-description": "Inclure la description",
|
"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-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-description-strava": "Synchronisez vos itinéraires et vos activités Strava avec wanderer à intervalles réguliers.",
|
||||||
"integration-disabled": "Intégration désactivée",
|
"integration-disabled": "Intégration désactivée",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Import",
|
"import": "Import",
|
||||||
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
"import-hint": "Select or drag GPX, FIT, KML or TCX files here...",
|
||||||
"include-description": "Include description",
|
"include-description": "Include description",
|
||||||
|
"include-waypoints": "Útpontok hozzáadása",
|
||||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
"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-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||||
"integration-disabled": "integration disabled",
|
"integration-disabled": "integration disabled",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importa",
|
"import": "Importa",
|
||||||
"import-hint": "Seleziona o trascina qui i file GPX, FIT, KML o TCX...",
|
"import-hint": "Seleziona o trascina qui i file GPX, FIT, KML o TCX...",
|
||||||
"include-description": "Adotta descrizione",
|
"include-description": "Adotta descrizione",
|
||||||
|
"include-waypoints": "Includi waypoint",
|
||||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
"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-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||||
"integration-disabled": "integration disabled",
|
"integration-disabled": "integration disabled",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importeer",
|
"import": "Importeer",
|
||||||
"import-hint": "Selecteer of sleep GPX-, FIT-, KML- of TCX-bestanden hierheen...",
|
"import-hint": "Selecteer of sleep GPX-, FIT-, KML- of TCX-bestanden hierheen...",
|
||||||
"include-description": "Inclusief beschrijving",
|
"include-description": "Inclusief beschrijving",
|
||||||
|
"include-waypoints": "Waypoints toevoegen",
|
||||||
"integration-description-komoot": "Synchroniseert je Komoot-tochten met Wanderer op regelmatige tijdstippen.",
|
"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-description-strava": "Synchroniseert je Strava-routes en -activiteiten met Wanderer op regelmatige tijdstippen.",
|
||||||
"integration-disabled": "Integratie uitgeschakeld",
|
"integration-disabled": "Integratie uitgeschakeld",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importuj",
|
"import": "Importuj",
|
||||||
"import-hint": "Wybierz lub przeciągnij tutaj plik GPX, FIT, KML lub TCX...",
|
"import-hint": "Wybierz lub przeciągnij tutaj plik GPX, FIT, KML lub TCX...",
|
||||||
"include-description": "Dołącz opis",
|
"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-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-description-strava": "Synchronizuje trasy i aktywność z wanderer w równych odstępach.",
|
||||||
"integration-disabled": "integracja wyłączona",
|
"integration-disabled": "integracja wyłączona",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "Importar",
|
"import": "Importar",
|
||||||
"import-hint": "Selecionar ou arrastar ficheiros GPX, FIT, KML ou TCX para aqui...",
|
"import-hint": "Selecionar ou arrastar ficheiros GPX, FIT, KML ou TCX para aqui...",
|
||||||
"include-description": "Incluir descrição",
|
"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-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
||||||
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
"integration-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||||
"integration-disabled": "integration disabled",
|
"integration-disabled": "integration disabled",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
"import": "导入",
|
"import": "导入",
|
||||||
"import-hint": "在此选择或拖拽GPX、FIT、KML或TCX文件...",
|
"import-hint": "在此选择或拖拽GPX、FIT、KML或TCX文件...",
|
||||||
"include-description": "包含描述",
|
"include-description": "包含描述",
|
||||||
|
"include-waypoints": "包括航点",
|
||||||
"integration-description-komoot": "Syncs your komoot tours with wanderer in regular intervals.",
|
"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-description-strava": "Syncs your strava routes & activities with wanderer in regular intervals.",
|
||||||
"integration-disabled": "integration disabled",
|
"integration-disabled": "integration disabled",
|
||||||
|
|||||||
@@ -81,6 +81,7 @@
|
|||||||
let printLoading: boolean = $state(false);
|
let printLoading: boolean = $state(false);
|
||||||
|
|
||||||
let includeDescription: boolean = $state(false);
|
let includeDescription: boolean = $state(false);
|
||||||
|
let includeWaypoints: boolean = $state(false);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
let qrcode = new QrCodeWithLogo({
|
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() {
|
async function print() {
|
||||||
if (!map) {
|
if (!map) {
|
||||||
return;
|
return;
|
||||||
@@ -328,25 +353,17 @@
|
|||||||
doc.setFont("IBMPlexSans-Regular", "normal");
|
doc.setFont("IBMPlexSans-Regular", "normal");
|
||||||
doc.text($trail.location || "-", 12, currentHeight);
|
doc.text($trail.location || "-", 12, currentHeight);
|
||||||
|
|
||||||
|
// End of page
|
||||||
|
currentHeight = height;
|
||||||
|
|
||||||
// Logo
|
// Logo
|
||||||
const logo = new Image();
|
const logo = new Image();
|
||||||
logo.src = "/imgs/logo_text_dark.png";
|
logo.src = "/imgs/logo_text_dark.png";
|
||||||
const logoRatio = 64 / 212;
|
const logoRatio = 64 / 212;
|
||||||
const logoWidth = 32;
|
const logoWidth = 32;
|
||||||
const logoHeight = logoWidth * logoRatio;
|
const logoHeight = logoWidth * logoRatio;
|
||||||
doc.addImage(
|
|
||||||
logo,
|
|
||||||
width - 8 - logoWidth,
|
|
||||||
height - 4 - logoHeight,
|
|
||||||
logoWidth,
|
|
||||||
logoHeight,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (includeDescription && $trail.description) {
|
function addLogo() {
|
||||||
doc.addPage();
|
|
||||||
doc.text(formatHTMLAsText($trail.description), 16, 16, {
|
|
||||||
maxWidth: width - 32,
|
|
||||||
});
|
|
||||||
doc.addImage(
|
doc.addImage(
|
||||||
logo,
|
logo,
|
||||||
width - 8 - logoWidth,
|
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");
|
doc.save($trail.name + ".pdf");
|
||||||
printLoading = false;
|
printLoading = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -504,6 +583,17 @@
|
|||||||
>{$_("include-description")}</label
|
>{$_("include-description")}</label
|
||||||
>
|
>
|
||||||
</div>
|
</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
|
<Button
|
||||||
loading={printLoading}
|
loading={printLoading}
|
||||||
|
|||||||
Reference in New Issue
Block a user