Autor Beitrag
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Mo 19.08.13 17:42 
Hallo,

wir entwickeln eine Webseite, mit der Nutzer eine DIN-A5-Seite gestalten können, vor allem mit formatiertem Text, Bildern und Tabellen. Diese A5-Seiten sollen anschließend auf den verschiedensten Geräten angezeigt werden.

Der offensichtliche Ansatz ist ein WYSIWYG-Editor, der auf eine konstante Größe beschränkt und einfach HTML-Code ausspuckt. Das funktioniert soweit auch schon wunderbar.

Diesen erzeugten HTML-Code möchten wir dynamisch verkleinern oder vergrößern, um die Seite auf das entsprechende Zielgerät (großer Bildschirm, kleiner Bildschirm, Smartphone etc.) anzupassen. Dafür geben wir alle Größen in em an, und modifzieren dann einfach die Schriftgröße des Wurzelelements. Das funktioniert auch.

Das Problem ist nur, dass der Text nicht perfekt proportional mit der Zoomstufe wächst/schrumpft, sondern in unterschiedlich großen Schritten. Das summiert sich auf die Breite einer Zeile zu einigen Pixeln auf, sodass mal ein Wort mehr, mal eines weniger in eine Zeile passt. Am Ende der Seite springen schließlich einige Wörter hin- und her, wenn man die Zoomstufe langsam verändert.

zur Illustration:

small-zoom large-zoom

Das letzte "mehr" passt bei der großen Zoomstufe nicht mehr in die dritte Zeile und wird umgebrochen.

Dieses Phänomen tritt übrigens auch auf, wenn man einfach die Zoomfunktion des Browsers (Firefox oder Chrome) verwendet, und nicht nur bei unserer Seite, sondern auch bei vielen anderen Webseiten. Es ist für uns allerdings besonders relevant, weil dem Beitrag nur ein bestimmter Platz zur Verfügung steht und der Autor diesen optimal ausfüllen will. Wenn der Beitrag bei der Anzeige dann anders umbricht, ist eventuell das gesamte Layout zerstört.

Der offensichtliche Fehler ist, HTML für ein statisches Seitenlayout zu verwenden. Besser geeignet wären dafür natürlich PDF oder SVG. Allerdings möchten wir die WYSIWYG-Funktionen der Browser verwenden, und das geht nunmal nur mit HTML.

Wir müssen also entweder die Browser dazu bringen, die Rundungsfehler beim Zoomen zu vermeiden, oder Zeilenumbrüche irgendwie fixieren.

Den zweiten Ansatz, Zeilenumbrüche fixieren, habe ich schon testweise umgesetzt: HTML -> PDF -> HTML konvertieren. Geht mit wkhtmltopdf und pdf2htmlEX. Beides sind sehr gute, aktuelle Bibliotheken, und das Ergebnis sieht auch gut aus, aber es entfernt jegliche HTML-Semantik wie z.B. Absätze oder Listen (es wandelt Aufzählungszeichen in Bitmaps um)

Habt ihr weitere Ideen? Seid ihr schonmal über dieses Problem gestolpert? Google kennt es anscheinend überhaupt nicht.

Vielen Dank fürs durchlesen ;)

Grüße,
Yogu
Einloggen, um Attachments anzusehen!
IhopeonlyReader
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 19.08.13 21:11 
ganz billig, kann man ein "bild" davon machen und das vergrößern/verkleinern.
Nachteil: Jeglicher Text geht verloren, da es nurnoch bildpixel sind. kopieren etc ist somit nicht mehr möglich..

ansonten könntest du testen ob die wörter verschoben wurden und wenn ja die zoom-stufe zurücksetzten..

also z.B. bei zoomstufe 1,2,3,5,6 tritt der "mehr" fehler nicht auf, bei 4 schon dann "überspringst" du die zoomstufe 4..
Wie das möglich ist weiß ich nicht, aber ich versuche mal dir meine Ansätze zu überbringen

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Yogu Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Di 20.08.13 01:42 
Hallo,

danke für deine Antwort, IhopeonlyReader. Den ganzen Beitrag in ein Bild umzuwandeln wäre keine schöne Sache.

"Schlechte" Zoomstufen zu überspringen ist prinzipiell eine gute Idee. Allerdings sind diese ganzen Rundungsfehler (man nennt es wohl kerning)* sehr schwer zu berechnen und variieren anscheinend auch zwischen Browsern.

Mein aktueller Ansatz ist es, im Editor <br>s nach jedem (automatischen) Zeilenwechsel einzufügen und den Beitrag dann mit white-space: pre; anzuzeigen. Beim nächsten Bearbeiten werden diese automatisch generierten <br>s dann wieder entfernt. Somit sollten die Zeilenumbrüche unabhängig von Browser und Zoomstufe überall gleich sein. Nur, wenn man einen Beitrag in Browser A erstellt und Browser B editiert, könnte das Problem wieder auftreten. Dann hat man jedoch die Gelegenheit, den Beitrag entsprechend anzupassen.

Ich melde mich wieder, wenn ich Fortschritte gemacht habe.

Nach bessren Alternativen suche ich weiterhin, denn das ist eher ein Workaround als eine saubere Lösung.

Grüße,
Yogu

* Kerning ist doch etwas anderes.


Zuletzt bearbeitet von Yogu am Mo 26.08.13 22:03, insgesamt 2-mal bearbeitet
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6386
Erhaltene Danke: 146

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 20.08.13 11:58 
Ich habe gerade ein ähnliches Problem, allerdings mit TRichEdit-Feldern in Delphi. Das Grundproblem ist aber exakt das selbe. Alle Ansätze die ich bisher angefangen habe, scheitern in der Regel an den Rundungsproblemen. Also genau, wie bei dir.

Jetzt habe ich das ein paar Tage ruhen lassen und hatte spontan eine neue Idee, die mir vielversprechend erscheint und auch bei dir zur Lösung führen kann. (Denke ich zumindest)

Vor dem Zoom merke ich mir die Anzahl der Zeilen und für jede Zeile die Anzahl der Zeichen pro Zeile.
Dann sehe ich die Zeilen durch und verändere je nach Veränderung die Breite des Text-Bereiches pixelweise, bis es für die betroffene Zeile passt. Danach muss ich natürlich wieder von vorne anfangen.

Wie gesagt, ist das bisher nur eine Idee, aber ich wollte da heute Nachmittag ein paar Tests machen, ob das funktioniert. Vielleicht muss ich mit Toleranzen arbeiten, damit ich da nicht in einer Endlos-Schleife lande.

Vielleicht hilft dir die Idee ja auch weiter. Kenne mich mit Web-Programmierung eher nur rudimentär aus. :wink:

Für diesen Beitrag haben gedankt: Yogu
Tilo
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1098
Erhaltene Danke: 13

Win7 geg. WInXP oder sogar Win98
Rad2007
BeitragVerfasst: Di 20.08.13 12:29 
Hallo Yogu,

Zur Vermeidung von ungewollten Umbrüchen könntest Du es mal mit geschützten Leerzeichen versuchen.

Eine weitere Möglichkeit wäre beim Editieren einen "virtuellen" Rahmen um den Text zu erstellen und etwas früher einen Umbruch zu erwzingen. Damit wäre bei einer Darstellungskombination die den Text etwas breiter darstellt noch genügend Platz vorhanden um einen ungewollten Umbruch zu vermeiden.

MFG,
Tilo
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6386
Erhaltene Danke: 146

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 20.08.13 13:47 
Nur zur Info:
Meine Idee hat funktioniert. Es gibt aber trotzdem vereinzelt Grenzfälle, die nicht 100%ig passen.
Yogu Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Mo 26.08.13 21:58 
user profile iconjasocul hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe gerade ein ähnliches Problem, allerdings mit TRichEdit-Feldern in Delphi. Das Grundproblem ist aber exakt das selbe. Alle Ansätze die ich bisher angefangen habe, scheitern in der Regel an den Rundungsproblemen. Also genau, wie bei dir.

Ah! Ich dachte schon, ich wäre alleine mit diesem Problem. Habe die Frage auch auf StackOverflow gepostet, und dort praktisch nur zu hören bekommen, dass der Ansatz zum Scheitern verurteilt ist.

user profile iconjasocul hat folgendes geschrieben Zum zitierten Posting springen:
Vor dem Zoom merke ich mir die Anzahl der Zeilen und für jede Zeile die Anzahl der Zeichen pro Zeile.
Dann sehe ich die Zeilen durch und verändere je nach Veränderung die Breite des Text-Bereiches pixelweise, bis es für die betroffene Zeile passt. Danach muss ich natürlich wieder von vorne anfangen.

Das ist meine Lösungr sehr ähnlich. Wenn meine scheitert, probiere ich sie vielleicht mal aus.

Falls jemand an meinem Code interessiert ist:

ausblenden volle Höhe JavaScript-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
      function getTextNodesIn(node, includeWhitespaceNodes) {
          var textNodes = [], whitespace = /^\s*$/;

          function getTextNodes(node) {
              if (node.nodeType == 3) {
                  if (includeWhitespaceNodes || !whitespace.test(node.nodeValue)) {
                      textNodes.push(node);
                  }
              } else {
                  for (var i = 0, len = node.childNodes.length; i < len; ++i) {
                      getTextNodes(node.childNodes[i]);
                  }
              }
          }

          getTextNodes(node);
          return textNodes;
      }
      
      function addLinebreaks(root) {
        var elems = $('p, div, li, blockquote, td, th, h1, h2, h3', root);
        elems.each(function() {
          var elem = $(this);

          // Wrap words into <span>s
          var textNodes = getTextNodesIn(elem[0]);
          for (var i = 0; i < textNodes.length; i++) {
            var node = textNodes[i];
            var text = node.textContent;
            var letters = [];
            for (var j = 0; j < text.length; j++) {
              letters.push($('<span>').addClass('letter').text(text[j]));
            }
            $(node).replaceWith(letters);
            var html = '';
            var oldY = -1;
              for (var j = 0; j < letters.length; j++) {
                var letter = letters[j];
                var y = letter.offset().top;
                if (oldY >= 0 && y != oldY) {
                  html += '<br class="auto" />';
                }
                html += letter.html(); // escape
              oldY = letter.offset().top;
              }
              $(letters[0]).replaceWith(html);
              $(letters).each(function() { $(this).remove()});
          }
        });
        console.log('added linebreaks');
      }
      
      function removeLinebreaks(root) {
        $('br.auto', root).remove();
      }

Die root-Parameter sind jQuery-Objekte des HTML-Elements, dessen Zeilenumbrüche fixiert werden sollen.

Es funktioniert bei allen bisher getesteten Dokumenten perfekt; vor allem bei sehr vielen Bildern bin ich mir aber nicht sicher, ob es immer klappt.


user profile iconTilo hat folgendes geschrieben Zum zitierten Posting springen:
Zur Vermeidung von ungewollten Umbrüchen könntest Du es mal mit geschützten Leerzeichen versuchen.

Ist im Prinzip äquivalent zu <br>-Tags und white-space: nowrap;.

user profile iconTilo hat folgendes geschrieben Zum zitierten Posting springen:
Eine weitere Möglichkeit wäre beim Editieren einen "virtuellen" Rahmen um den Text zu erstellen und etwas früher einen Umbruch zu erwzingen. Damit wäre bei einer Darstellungskombination die den Text etwas breiter darstellt noch genügend Platz vorhanden um einen ungewollten Umbruch zu vermeiden.

Das Problem ist, dass dann möglicherweise zu wenig umgebrochen wird und das Layout doch wieder anders aussieht. Wir möchten, dass die Autoren ihren Beitrag in einem echten WYSIWYG-Editor gestalten können.

Danke für alle Meldungen!

Viele Grüße,
Yogu