Version 2.7.8: die Vorschau haengt an derselben Kante wie die Datei
This commit is contained in:
1 parent
2db7e03154
commit
713ff12db2
5 files changed
+122
-17
No files matched your search
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "tesm"
|
||||
version = "2.7.7"
|
||||
version = "2.7.8"
|
||||
description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "tesm-core"
|
||||
version = "2.7.7"
|
||||
version = "2.7.8"
|
||||
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -148,7 +148,11 @@ def create_base_app(
|
||||
#: Wortmarke, ohne Zeile darunter; die Marke selbst zeigen beide
|
||||
#: Anwendungen.
|
||||
auth_tagline: str = "",
|
||||
app_version: str = "2.7.7",
|
||||
#: Beide Anwendungen geben ihre eigene Paketversion mit -- und die laeuft
|
||||
#: absichtlich auseinander: was sich nicht geaendert hat, bekommt keine
|
||||
#: neue Nummer. Eine feste Zahl an dieser Stelle wuerde irgendwann eine
|
||||
#: falsche Version in die Fussnote schreiben.
|
||||
app_version: str = "unbekannt",
|
||||
built_in_trusted_keys: tuple[str, ...] = (),
|
||||
enable_license: bool = True,
|
||||
template_folder: str | None = None,
|
||||
|
||||
@@ -1456,17 +1456,23 @@
|
||||
Block, Groesse mit dem Griff unten rechts, entfernen mit dem Kreuz.
|
||||
"touch-action: none" ist auf dem iPad die Bedingung dafuer, dass ein Finger
|
||||
zieht statt die Seite zu scrollen. */
|
||||
/* Die Marke ist genau die Zeichnung: ihre Unterkante liegt auf dem
|
||||
Ankerpunkt -- dieselbe Kante, an der pdf-lib das Bild setzt. Der Text
|
||||
haengt darunter und darf die Hoehe nicht mitbestimmen. */
|
||||
.viewer__unterschrift {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
border: 1px dashed transparent;
|
||||
/* "outline" statt "border": ein Rahmen haette die Marke um zwei Pixel
|
||||
groesser gemacht und die Bildkante vom Ankerpunkt weggeschoben. */
|
||||
outline: 1px dashed transparent;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.viewer__unterschrift:hover,
|
||||
.viewer__unterschrift.is-fassend {
|
||||
border-color: var(--accent);
|
||||
outline-color: var(--accent);
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
@@ -1482,6 +1488,12 @@
|
||||
wie im PDF. Waere er so breit wie der Block, zeigte die Vorschau etwas
|
||||
anderes als die Datei. */
|
||||
.viewer__unterschrifttext {
|
||||
/* Unter der Zeichnung, nicht in ihr: "top: 100%" setzt die Oberkante des
|
||||
Strichs auf die Bildkante -- genau dort zieht ihn auch pdf-lib. Abstand,
|
||||
Strichstaerke und Innenabstand rechnet das Skript in Punkten. */
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
/* Helvetica: dieselbe Schrift, die das PDF benutzt (StandardFonts.Helvetica).
|
||||
Mit der Hausschrift sah die Vorschau anders aus als das Ergebnis. Die
|
||||
Groesse setzt das Skript je Unterschrift -- hier steht nur ein Rueckfall. */
|
||||
@@ -1493,7 +1505,6 @@
|
||||
line-height: 1.15;
|
||||
color: #111;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.85);
|
||||
padding-top: 1px;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
width: max-content;
|
||||
|
||||
@@ -297,9 +297,9 @@ async function nachbearbeiten(
|
||||
const textbreite = Math.max(
|
||||
...zeilen.map((zeile) => schrift.widthOfTextAtSize(zeile, groesse))
|
||||
);
|
||||
let unten = eintrag.y - 2;
|
||||
let unten = eintrag.y - UNTERSCHRIFT.textY;
|
||||
for (const zeile of zeilen) {
|
||||
unten -= groesse * 1.15;
|
||||
unten -= groesse * UNTERSCHRIFT.zeile;
|
||||
seite.drawText(zeile, {
|
||||
x: eintrag.x,
|
||||
y: unten,
|
||||
@@ -312,9 +312,9 @@ async function nachbearbeiten(
|
||||
// erkennbar zu bleiben: ein halber Punkt in hellem Grau ging zwischen
|
||||
// den Tabellenlinien schlicht unter.
|
||||
seite.drawLine({
|
||||
start: { x: eintrag.x, y: eintrag.y - 1.5 },
|
||||
end: { x: eintrag.x + textbreite, y: eintrag.y - 1.5 },
|
||||
thickness: 0.9,
|
||||
start: { x: eintrag.x, y: eintrag.y - UNTERSCHRIFT.strichY },
|
||||
end: { x: eintrag.x + textbreite, y: eintrag.y - UNTERSCHRIFT.strichY },
|
||||
thickness: UNTERSCHRIFT.strich,
|
||||
color: PDFLib.rgb(0.15, 0.15, 0.15),
|
||||
});
|
||||
}
|
||||
@@ -342,6 +342,71 @@ async function nachbearbeiten(
|
||||
return dokument.save();
|
||||
}
|
||||
|
||||
/** Masse des Textblocks unter einer Unterschrift -- in PDF-Punkten.
|
||||
*
|
||||
* Die Vorschau rechnet dieselben Zahlen in Pixel um. Standen sie zweimal im
|
||||
* Code, liefen sie auseinander: die Marke haengt mit ihrer **Unterkante** am
|
||||
* Ankerpunkt, das PDF setzt dort die **Unterkante des Bildes** und schreibt
|
||||
* den Text darunter. Beim Setzen sass der Block deshalb um die Texthoehe
|
||||
* hoeher als in der gespeicherten Datei.
|
||||
*/
|
||||
const UNTERSCHRIFT = {
|
||||
//: Mitte des Strichs unter der Bildkante.
|
||||
strichY: 1.5,
|
||||
//: Staerke des Strichs.
|
||||
strich: 0.9,
|
||||
//: Bildkante bis zur ersten Grundlinie, vor dem Zeilenabstand.
|
||||
textY: 2,
|
||||
//: Zeilenabstand als Vielfaches der Schriftgroesse.
|
||||
zeile: 1.15,
|
||||
//: Oberkante der Zeilenbox bis zur Grundlinie, in "em" -- nur ein
|
||||
//: Rueckfall: gewoehnlich misst "grundlinie()" das am echten Text nach.
|
||||
//: (Helvetica/Arial: Ascender 0,905 plus halber Durchschuss.)
|
||||
grundlinie: 0.9215,
|
||||
};
|
||||
|
||||
//: Gemessene Grundlinien, je dargestellter Schriftgroesse in Pixeln.
|
||||
const grundlinien = new Map();
|
||||
|
||||
/** Abstand von der Oberkante der Zeilenbox zur Grundlinie, in "em".
|
||||
*
|
||||
* Gemessen statt geraten, und bei genau der Pixelgroesse, die auch auf dem
|
||||
* Schirm steht. Zwei Gruende: welche Datei hinter "Helvetica" steckt,
|
||||
* entscheidet das Geraet -- auf einem iPad eine andere als auf einem
|
||||
* Windows-Rechner, mit anderen Oberlaengen. Und der Browser rundet die
|
||||
* Schriftmasse auf ganze Pixel: bei acht Punkt Schrift verschiebt das die
|
||||
* Zeile um einen halben Pixel gegenueber der Rechnung. pdf-lib rundet nicht.
|
||||
*
|
||||
* Eine leere Inline-Box sitzt auf der Grundlinie -- ihre Lage verraet also,
|
||||
* wo der Text steht.
|
||||
*/
|
||||
function grundlinie(px) {
|
||||
const schluessel = px.toFixed(1);
|
||||
const gemerkt = grundlinien.get(schluessel);
|
||||
if (gemerkt !== undefined) return gemerkt;
|
||||
let anteil = UNTERSCHRIFT.grundlinie;
|
||||
try {
|
||||
const probe = document.createElement("div");
|
||||
probe.className = "viewer__unterschrifttext";
|
||||
probe.style.cssText =
|
||||
"position:absolute;left:-9999px;top:0;visibility:hidden;border:0;padding:0;";
|
||||
probe.style.fontSize = `${px}px`;
|
||||
probe.style.lineHeight = String(UNTERSCHRIFT.zeile);
|
||||
const lot = document.createElement("span");
|
||||
lot.style.cssText = "display:inline-block;width:0;height:0;";
|
||||
probe.append(document.createTextNode("Hg"), lot);
|
||||
document.body.append(probe);
|
||||
const oben = probe.getBoundingClientRect().top;
|
||||
const auf = lot.getBoundingClientRect().top;
|
||||
probe.remove();
|
||||
if (auf > oben) anteil = (auf - oben) / px;
|
||||
} catch (fehler) {
|
||||
console.warn("Grundlinie nicht messbar -- Rueckfall auf Helvetica", fehler);
|
||||
}
|
||||
grundlinien.set(schluessel, anteil);
|
||||
return anteil;
|
||||
}
|
||||
|
||||
/** Schriftgroesse des Namenszugs unter einer Unterschrift dieser Breite.
|
||||
*
|
||||
* Ein Achtzehntel: bei den 150 Punkt der vollen Breite sind das gut acht
|
||||
@@ -716,17 +781,42 @@ async function pdfBetrachter(behaelter, seiten, url, basis, { formulare = true }
|
||||
seitenEl.append(marke);
|
||||
|
||||
const zeichnen = () => {
|
||||
// Die Marke ist genau die Zeichnung: ihre Unterkante liegt auf dem
|
||||
// Ankerpunkt, so wie im PDF. Der Text haengt darunter (siehe
|
||||
// Gestaltung: absolut, "top: 100%") und zaehlt nicht zur Hoehe --
|
||||
// sonst saesse der Block in der Vorschau um die Texthoehe zu hoch.
|
||||
marke.style.left = `${(eintrag.x / blick.width) * 100}%`;
|
||||
marke.style.bottom = `${(eintrag.y / blick.height) * 100}%`;
|
||||
marke.style.width = `${(eintrag.breite / blick.width) * 100}%`;
|
||||
// Die Schriftgroesse wird gerechnet, nicht vom Stylesheet abgeleitet:
|
||||
// Alles Weitere wird gerechnet, nicht vom Stylesheet abgeleitet:
|
||||
// Punkte mal Pixel-je-Punkt der gerade dargestellten Seite. Ueber
|
||||
// Container-Einheiten ("cqw") ging das auch -- aber nur dort, wo der
|
||||
// Browser sie kennt; wo nicht, erbte der Block die Schriftgroesse der
|
||||
// Seite, und der Text war um die Haelfte zu breit. Genau das war der
|
||||
// Unterschied zwischen Vorschau und Datei.
|
||||
// Seite, und der Text war um die Haelfte zu breit.
|
||||
const proPunkt = seitenEl.getBoundingClientRect().width / blick.width;
|
||||
text.style.fontSize = `${schriftgroesse(eintrag.breite) * proPunkt}px`;
|
||||
const groesse = schriftgroesse(eintrag.breite);
|
||||
const inPixeln = groesse * proPunkt;
|
||||
const oben = UNTERSCHRIFT.strichY - UNTERSCHRIFT.strich / 2;
|
||||
text.style.fontSize = `${inPixeln}px`;
|
||||
text.style.lineHeight = String(UNTERSCHRIFT.zeile);
|
||||
text.style.marginTop = `${oben * proPunkt}px`;
|
||||
text.style.borderTopWidth = `${UNTERSCHRIFT.strich * proPunkt}px`;
|
||||
// Rahmenbreiten rundet der Browser auf ganze Geraetepixel: aus 1,21
|
||||
// wird 1. Mit dem gerechneten Wert sass die erste Zeile deshalb einen
|
||||
// Fuenftel Punkt zu hoch -- also mit dem tatsaechlich benutzten rechnen.
|
||||
const strich =
|
||||
(parseFloat(getComputedStyle(text).borderTopWidth) ||
|
||||
UNTERSCHRIFT.strich * proPunkt) / proPunkt;
|
||||
// Oberkante des Strichs, die Strichstaerke, dann so viel Luft, dass die
|
||||
// erste Grundlinie dort sitzt, wo pdf-lib sie setzt: textY plus einen
|
||||
// Zeilenabstand unter der Bildkante.
|
||||
const innen =
|
||||
UNTERSCHRIFT.textY +
|
||||
UNTERSCHRIFT.zeile * groesse -
|
||||
oben -
|
||||
strich -
|
||||
grundlinie(inPixeln) * groesse;
|
||||
text.style.paddingTop = `${Math.max(0, innen) * proPunkt}px`;
|
||||
};
|
||||
// Beim Zoomen aendert sich Pixel-je-Punkt -- dann neu rechnen.
|
||||
neuzeichnen.add(zeichnen);
|
||||
@@ -764,8 +854,8 @@ async function pdfBetrachter(behaelter, seiten, url, basis, { formulare = true }
|
||||
} else {
|
||||
eintrag.x = Math.max(2, start.x + (zug.clientX - startX) / proPunkt);
|
||||
eintrag.y = Math.max(
|
||||
// Platz fuer die Textzeilen unter der Zeichnung.
|
||||
schriftgroesse(eintrag.breite) * 2.5,
|
||||
// Platz fuer die beiden Textzeilen unter der Zeichnung.
|
||||
UNTERSCHRIFT.textY + 2 * UNTERSCHRIFT.zeile * schriftgroesse(eintrag.breite),
|
||||
start.y - (zug.clientY - startY) / proPunkt
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user