SVG-Text-Tutorial: Textanmerkung im Web
Veröffentlicht: 2022-03-11Mit HTML5 und CSS3 haben Webbrowser eine Reihe erstaunlicher Technologien erworben: 3D-Grafiken, Sockets, Threads und mehr. Mit diesen können Webanwendungen einige der anspruchsvollsten Fähigkeiten der Computer und Betriebssysteme nutzen, auf denen sie verwendet werden. Der Webbrowser bietet ein robustes, vielseitiges Ökosystem für die Anwendungsentwicklung, was durch den jüngsten Aufstieg zahlreicher leistungsstarker Webanwendungen deutlich wird, ohne die wir nicht leben können. Was jedoch noch fehlt, ist die Schönheit der HTML-Textanmerkung und -dekoration. Was ist Textdekoration? Verschnörkelte Unterstreichungen, schroffe Hervorhebungen und wellenförmige Durchstreichungen sind einige der Dinge, die Webbrowser nicht nativ unterstützen. Das mag komplizierter als nützlich klingen, aber die Möglichkeit für JavaScript-Entwickler, diese Stile zu erstellen, kann sich in Aspekten wie E-Learning-Ressourcen und webbasierten E-Book-Readern als nützlich erweisen. Darüber hinaus kann dies zur Verbesserung der Benutzererfahrung in Webanwendungen beitragen, die sich um natürliche Designprinzipien drehen. Zumindest macht das Bauen eines solchen Tools Spaß und gibt Einblick in die vielen Macken eines Webbrowsers.
Entwickler haben viele Problemumgehungen für die Einschränkung des Webbrowsers gefunden. Viele dieser Problemumgehungen beinhalten die Verwendung von CSS auf weniger intuitive Weise, da einige Bilder in den „::after“-Pseudoelementen verwenden. Das funktioniert, aber es erweist sich oft als schwierig, viele Bilder für jedes Stil-Farb-Paar zu verwalten. Dieser Artikel wirft einen Blick auf die Anatomie einer JavaScript-Bibliothek, die versucht, dieses Problem elegant zu lösen.
Die Bibliothek ist Open Source und auf GitHub verfügbar: Text Annotator
Überblick
Bei der Entwicklung dieser Bibliothek wurde besonderes Augenmerk auf die Gewährleistung der Kompatibilität mit den gängigsten Webbrowsern (einschließlich IE 9+) gelegt. Im Gegensatz zu den meisten Lösungen für dieses Problem verlässt sich die Bibliothek jedoch nicht auf speziell obskure CSS-Tricks. oder noch schlimmer, spezielle Unicode-Symbole. Stattdessen verwendet es SVG, um viel bessere, sauberere Textdekorationen zu erzielen.
Grundsätzlich implementiert die Bibliothek eine Annotator-„Klasse“, die verwendet werden kann, um automatisch DIV-Elemente zu erstellen, sie unter zu kommentierenden Texten zu positionieren und ihre Hintergründe mit SVG-Bildern zu füllen. Mehrere DIVs können kombiniert werden, um die Dekorationen weiter anzupassen. Der Ansatz ist browserübergreifend kompatibel, bietet Flexibilität bei der Positionierung dekorativer Elemente und ermöglicht eine einfachere Erweiterung mit benutzerdefinierten Vorlagen.
Die Bibliothek wurde mit Google Closure Tools entwickelt, da sie modular und browserübergreifend ist, was dazu beiträgt, kompakten und schnellen JavaScript-Code ohne zusätzliche Abhängigkeiten zu erstellen.
Die Architektur
Die Bibliothek wurde als Sammlung von JavaScript-„Klassen“ entworfen und stellt dem Benutzer alle notwendigen Funktionalitäten über den „Klassen“-Annotator zur Verfügung:
Hier ein kurzer Überblick über die verfügbaren Funktionalitäten:
annotateDocument - kommentiert Elemente, die mit einem „data-annotate“-Attribut gekennzeichnet sind.
underline - unterstreicht das Element
Highlight - Hebt das Element hervor
Strike - Strikes-Element
underlineSelected - Unterstreicht ausgewählten Text
HighlightSelected - hebt ausgewählten Text hervor
StrikeSelected - streicht ausgewählten Text
unannotateElement - entfernt die Anmerkung vom Element
getTemplates - gibt das Wörterbuch der Anmerkungsvorlagen zurück
setUnderlineOptions - legt die Einstellungen für den Unterstreichungs-Annotator fest
setHighlightOptions - legt die Einstellungen für den Highlight-Annotator fest
setStrikeOptions - legt die Einstellungen für den Strike-Annotator fest
Die Annotator-Klasse enthält drei Instanzen der AnnotatorImpl-Klasse für jede Anmerkungsfunktion: Unterstreichen, Hervorheben und Streichen.
tvs.Annotator = function() { this.underliner_ = new tvs.AnnotatorImpl( 'underliner', tvs.Annotator.getTemplates(), tvs.AnnotatorCore.underlinePositioner); this.highlighter_ = new tvs.AnnotatorImpl( 'highlighter', tvs.Annotator.getTemplates(), tvs.AnnotatorCore.highlightPositioner, {opacity: 0.45}); this.striker_ = new tvs.AnnotatorImpl( 'striker', tvs.Annotator.getTemplates(), tvs.AnnotatorCore.strikePositioner); };
AnnotatorImpl-Instanzen werden mit unterschiedlichen IDs und Positionierungshilfsobjekten erstellt. Übergebene IDs werden später in CSS-Klassennamen und internen Feldnamen verwendet, sodass IDs eindeutig sein müssen. Außerdem wird ein Verweis auf eine Liste bekannter Vorlagen übergeben (kann später geändert werden).
Jedes Positioner-Objekt ist eine Implementierung der IPositioner-Schnittstelle, die nur die Methode „getPosition“ hat und wie folgt aussieht:
/** * Underline positioner * @implements {tvs.IPositioner} */ tvs.AnnotatorCore.underlinePositioner = /** @type {!tvs.IPositioner} */ ({ /** * @param {Object} elementRect * @param {number} annotationHeight * @return {{left: number, top: number, width: number, height: number}} */ getPosition: function(elementRect, annotationHeight) { return { width: elementRect.width, height: annotationHeight, left: elementRect.left, top: elementRect.bottom - (elementRect.height * 0.1) }; } });
Dadurch kann jede Vorlage mit Textanmerkungen unterstrichen, hervorgehoben oder durchgestrichen verwendet werden. Wenn eine Anmerkung auf ein Element angewendet wird, wird der Begrenzungsrahmen für das Element durch Aufrufen von „getElementRects“ wie unten gezeigt abgerufen:
var rects = elemOrEv.getClientRects();
Diese Methode gibt eine Sammlung von Rechtecken zurück, die die Begrenzungsrechtecke für jede Box in einem Client angeben. Nachdem wir jedes Rechteck an den konkreten Positioner übergeben haben, erhalten wir Zielgrenzen.
SVG-Vorlagen für Textanmerkungen
Wie bereits erwähnt, gibt es nur einen Satz von Vorlagen, die für alle Arten von SVG-Textanmerkungen verwendet werden. Jede Vorlage besteht aus Vorlagenteilen. Ein Vorlagenteil ist eine Entität, die den Inhalt, die Vorlagenbreite und den Zeichenmodus des Teils darstellt.
Inhalt
Inhalt ist eine Reihe von SVG-Elementen, die als Zeichenfolge dargestellt werden. Da dieser Inhalt keinen Root-SVG-Knoten hat, in dem die Breite und Höhe des Ansichtsfensters (in Pixel) festgelegt werden, akzeptiert der Teilkonstruktor der Vorlage sie als Parameter. Sie können beispielsweise die Größe eines Darstellungsbereichs als 100 x 100 Pixel angeben und eine Linie zu (50, 50) und (25, 25) ziehen. Nachdem die Anmerkung angewendet wurde, werden alle SVG-Elemente ordnungsgemäß auf die gewünschte Größe gebracht. Der Inhaltswert kann die Zeichenfolge „{0}“ verwenden, die durch die vom Benutzer ausgewählte Farbe ersetzt wird.
Das folgende SVG rendert eine diagonale Linie. Wir werden dies als einen der Teile in einem Beispiel-Anmerkungsstil verwenden, der in Kürze folgt:
<line x1="0" y1="0" x2="5" y2="5" stroke-width="2" stroke="red" />
Breite
Die Vorlagenbreite ist eine Zeichenfolge, die „*“, „Höhe“ oder irgendetwas anderes sein kann:
„*“ setzt die Breite aller Elemente mit einem Stern gleich
„height“ setzt die Breite gleich der Höhe des Anmerkungselements
Alles andere, was hier eingestellt wird, wird direkt auf die Eigenschaften CSS width und min-width gesetzt.
Zeichnen-Modus
Der Zeichenmodus ist eine Zeichenfolge, die entweder „Wiederholen“ oder „Stretch“ sein kann. Wie die Werte zeigen, wird der Inhalt durch die Einstellung „Wiederholen“ wiederholt, während durch die Einstellung „Stretch“ der Inhalt gedehnt wird.
Hier ist ein Beispiel dafür, was wir durch die Konfiguration dieser drei Parameter erreichen können:
Die Textanmerkung im obigen Beispiel enthält 4 Teile. Der erste Teil ist die diagonale Linie, wobei die Vorlagenbreite auf „Höhe“ und der Zeichenmodus auf „Wiederholen“ eingestellt ist. Beim zweiten Teil ist die Vorlagenbreite auf „*“ und der Zeichenmodus auf „Wiederholen“ eingestellt. Der dritte Teil ist auf „15px“ breit eingestellt und wird im „Repeat“-Modus gezeichnet. Schließlich wird die Breite des letzten Teils auf „*“ und sein Zeichenmodus auf „strecken“ eingestellt.
Wenn diese Breiten ausgewertet werden, nimmt der erste Teil 5 Pixel ein (gleich der Höhe des Anmerkungselements), der dritte Teil 15 Pixel (wie eingestellt) und der verbleibende Platz wird gleichmäßig auf den zweiten und den vierten Teil aufgeteilt.
Wenn derselbe Textabschnitt mit derselben Vorlage hervorgehoben wird, erhalten wir Folgendes:
Wie Sie sehen können, ist die Höhe des Anmerkungselements größer, ebenso wie die Breite des ersten Teils (da die Vorlagenbreite für diesen Teil auf „Höhe“ eingestellt ist). Natürlich blieb die Breite des dritten Teils gegenüber dem vorherigen Beispiel unverändert.
Das Anwenden eines Durchstreicheffekts auf denselben Text mit derselben Vorlage führt zu einem Ergebnis, das dem ersten sehr ähnlich ist. Der einzige Unterschied besteht in der Position, an der die Anmerkungselemente positioniert sind:
Obwohl diese Textanmerkungen komplex erscheinen (wie sie aussehen, da sie aus vier verschiedenen Teilen bestehen), verwenden sie alle sehr einfache SVG-Elemente. Als zusätzliches Beispiel erfordert das Erstellen einer verschnörkelten Linie ein einzelnes Teil mit dem folgenden einfachen SVG-Inhalt:
var t = new tvs.Template(new tvs.SvgTemplatePart( '<line y2="16.00" x2="20" y1="4.00" ' + 'x1="10" stroke-linecap="round" ' + 'stroke-width="5" stroke="{0}" fill="none"/>' + '<line y2="4.00" x2="10" y1="16.00" ' + 'x1="0" stroke-linecap="round" ' + 'stroke-width="5" stroke="{0}" fill="none"/>', 20, 20, 'repeat' ))
Wenn diese Vorlagen ausgewertet werden, wird die Größe des Inhalts angepasst und „{0}“ wird automatisch durch die angegebene Farbe ersetzt. Darüber hinaus ist das Hinzufügen neuer Vorlagen so einfach wie das Hinzufügen zu einem JavaScript-Objekt:
tvs.AnnotatorDictionary.svgTemplates['brush'] = new tvs.Template(new tvs.SvgTemplatePart( svgContent, 50, 50, '*', 'stretch' ));
Ergebnisse
Jede Anmerkung wird angewendet, indem ein div-Element mit absoluter Positionierung an die Seite angehängt wird:
<div class="tvs-annotate-element"> <div class="tvs-wrap-div"> <table> <tr> <td></td> <td></td> <td></td> </tr> </table> </div> </div>
Das div-Element wird mit einer Tabelle gefüllt, in der jede hinzugefügte Zelle einem der Teile in der Vorlage entspricht. Der Inhalt jedes Vorlagenteils wird als Base64-codierter Daten-URI hinzugefügt, wobei die ausgewählte Farbe angewendet wird:
tvs.SvgTemplatePart.prototype.getBackground = function(color) { var image = tvs.AnnotatorCore.formatString(this.content, [color]); var encodedSVG = goog.crypt.base64.encodeString(image); return 'data:image/svg+xml;base64,' + encodedSVG; };
Einbettung
Für eine bessere Benutzererfahrung, insbesondere wenn Sie versuchen, diese JavaScript-Bibliothek mit bearbeitbaren Inhaltsbereichen zu verwenden, ist es wichtig, dass der Textannotator die Grenzen des aktuell vom Benutzer ausgewählten Texts kennt. Rangy, eine hübsche JavaScript-Bibliothek, die sich mit Bereich und Auswahl befasst, wurde verwendet, um dies browserübergreifend zu erreichen. Rangy bietet eine einfache, auf Standards basierende API zur Durchführung gängiger DOM-Bereichs- und -Auswahlaufgaben in allen gängigen Browsern und abstrahiert die stark unterschiedlichen Implementierungen dieser Funktionalität zwischen Internet Explorer und DOM-kompatiblen Browsern. Es ist die einzige Abhängigkeit des Projekts.
Sobald Text Annotator eingebettet ist, ist die Verwendung sehr einfach:
var annotator = new tvs.Annotator(); annotator.underlineSelected();
Jedes kommentierte Element ist mit der Klasse „tvs-annotated-text“ gekennzeichnet und jedes Anmerkungselement hat die Klasse „tvs-annotate-element“. Das Entfernen von Anmerkungen ist noch einfacher, ein Einzeiler:
annotator.unannotateElement(annotatedElement);
Macken
Wenn die Größe des Fensters geändert wird, können sich Elemente verschieben, sodass kommentierte Elemente „aktualisiert“ werden müssen. Dies übernimmt die Bibliothek. Aber; Um die Auswirkungen auf die Leistung zu reduzieren, wird der Aufruf zum Aktualisieren von Anmerkungen gedrosselt:
tvs.AnnotatorImpl = function(id, templates, positioner, options) { // ... this.throttle = new goog.Throttle(goog.bind(this.refreshAllAnnotations, this), 50); tvs.AnnotatorCore.registerForWindowResize( this.id,goog.bind(this.throttle.fire, this.throttle)); }; tvs.AnnotatorImpl.prototype.refreshAllAnnotations = function() { var elems = goog.dom.getElementsByClass(this.getCssClassForAnnotated()); var refFunc = goog.bind(this.refreshAnnotation, this); goog.array.forEach(elems, refFunc); };
Beim Aktualisieren können Anmerkungselemente nach Bedarf hinzugefügt, in der Größe geändert oder von der Seite entfernt werden.
Bequemlichkeit
Um das Kommentieren von statischem Text auf einer Seite zu vereinfachen, genügt ein einfaches Datenattribut für das Containerelement:
data-annotate='underline squiggly green'
Dadurch wird der Inhalt des Elements mit einer verschnörkelten grünen Unterstreichung versehen.
Fazit
Was kann ich noch zu diesem SVG-Text-Tutorial sagen? Ein unterhaltsames und dennoch leistungsstarkes Tool wurde einfach implementiert. Ich glaube nicht, dass wir viel davon profitieren würden, wenn wir die Unterstützung für Internet Explorer 8 sicherstellen würden, da wir stattdessen die gesamte Implementierung verkomplizieren könnten. Mit einigen Verbesserungen und ein wenig Arbeit am Kern können wir die Bibliothek jedoch erweitern, um dekorative Rahmen für Nicht-Text-Elemente erstellen zu können. Darüber hinaus kann es eine interessante Aufgabe sein, einen Mechanismus zu implementieren, um den Zustand des bearbeitbaren Inhalts einer Anmerkung zu speichern und später wiederherzustellen.
Im Moment sind die Möglichkeiten nur durch Ihre Vorstellungskraft (und Browserfähigkeiten) begrenzt. Vielleicht möchten Sie Mikrodrucklinien oder Farbverläufe oder sogar Animationen. Mit Text Annotator ist das möglich.