Zum Hauptinhalt springen

Text Auto-Resize

Der Auto-Resize Mechanismus passt die Schriftgröße automatisch an, damit Text in den Container passt, ohne Wörter zu umbrechen.

Problemstellung

Wenn ein Benutzer Text wie "DEIN FERNSTUDIUM ENTDECKEN" in einen 170px breiten Container eingibt:

  • Das Wort "FERNSTUDIUM" ist bei 33px Schriftgröße breiter als der Container
  • Ohne Auto-Resize würde das Wort mitten im Wort umbrechen → unschön

Lösung: Zwei-Phasen-Algorithmus

Phase 1: Word-Fit Check

Prüft, ob jedes einzelne Wort in den Container passt:

Input: "DEIN FERNSTUDIUM ENTDECKEN" @ 33px, Container: 170px

Wort-Breiten:
- "DEIN" = 52px ✅
- "FERNSTUDIUM" = 185px ❌ (> 170px)
- "ENTDECKEN" = 128px ✅

Ergebnis: Word-Fit FAILED → Schriftgröße muss reduziert werden

Phase 2: Binary Search für optimale Größe

Findet die größte Schriftgröße, bei der alle Wörter passen:

Binary Search: low=8, high=33

Iteration 1: mid=20 → "FERNSTUDIUM"=112px ✅ → low=20
Iteration 2: mid=26 → "FERNSTUDIUM"=145px ✅ → low=26
Iteration 3: mid=29 → "FERNSTUDIUM"=160px ✅ → low=29
Iteration 4: mid=31 → "FERNSTUDIUM"=172px ❌ → high=31
Iteration 5: mid=30 → "FERNSTUDIUM"=166px ✅ → low=30

Ergebnis: 30px (größte Größe bei der alles passt)

Max-Lines Constraint

Wenn maxLines gesetzt ist, wird zusätzlich geprüft, ob der Text in X Zeilen passt:

Text: "BILDUNG, DIE DICH BEGLEITET"
Container: 170px
maxLines: 2

Bei 33px: 3 Zeilen → zu viele
Bei 25px: 2 Zeilen → passt ✅

Wichtig: Word-Fit wird IMMER zuerst geprüft, auch wenn maxLines gesetzt ist!

Implementierung

Ort: packages/render-engine/ (von Studio und beiden Export-Renderern genutzt)

Text-Messung im Browser über die Canvas API (context.measureText()). Dieselbe Fit-Logik gilt für Live-Vorschau und Export — es gibt keinen separaten Export-Messpfad mehr.

Flowchart

┌─────────────────────────────────────┐
│ Auto-Resize Start │
│ (initial_font_size = 33px) │
└──────────────┬──────────────────────┘


┌─────────────────────────────────────┐
│ Phase 1: Check Word-Fit │
│ Passt jedes Wort in Container? │
└──────────────┬──────────────────────┘

┌─────┴─────┐
│ │
YES NO
│ │
▼ ▼
┌─────────────┐ ┌─────────────────────────┐
│ Keep Size │ │ Binary Search: │
│ │ │ Find largest size where │
│ │ │ all words fit │
└──────┬──────┘ └───────────┬─────────────┘
│ │
└──────────┬──────────┘


┌─────────────────────────────────────┐
│ Phase 2: Check Max-Lines │
│ (nur wenn maxLines gesetzt) │
└──────────────┬──────────────────────┘

┌─────┴─────┐
│ │
lines ≤ max lines > max
│ │
▼ ▼
┌─────────────┐ ┌─────────────────────────┐
│ Done │ │ Binary Search: │
│ │ │ Find largest size where │
│ │ │ lines ≤ maxLines │
└─────────────┘ └─────────────────────────┘

Edge Cases

1. Leerer Text

if not text or not text.strip():
return initial_font_size # Keine Änderung

2. Einzelnes sehr langes Wort

Wenn ein Wort selbst bei minimaler Schriftgröße (8px) nicht passt, wird es trotzdem angezeigt (overflow).

3. BBCode Formatierung

BBCode-Tags ([b], [/b]) werden vor der Messung entfernt:

plain_text = re.sub(r'\[[biu]\]|\[\/[biu]\]', '', text)

4. Windows-Zeilenenden

\r\n und \r werden zu \n normalisiert:

text = text.replace('\r\n', '\n').replace('\r', '\n')

Debugging

Bei Problemen mit Auto-Resize:

  1. Prüfe Container-Breite: Ist sie korrekt gesetzt?
  2. Prüfe Font-Loading: Wird die richtige Schriftart geladen?
  3. Vergleiche Browser vs Renderer: Unterschiedliche Schriftgrößen?
  4. Aktiviere Logging:
    print(f"Word '{word}' width: {word_width}px, max: {max_width}px")

Siehe auch