Samouczek dotyczący tekstu SVG: adnotacje tekstowe w Internecie
Opublikowany: 2022-03-11Dzięki HTML5 i CSS3 przeglądarki internetowe zyskały wiele niesamowitych technologii: grafikę 3D, gniazda, wątki i inne. Dzięki nim aplikacje internetowe mogą korzystać z najbardziej wyrafinowanych możliwości komputerów i systemów operacyjnych, na których są używane. Przeglądarka internetowa oferuje solidny, wszechstronny ekosystem do tworzenia aplikacji, co widać po niedawnym pojawieniu się wielu potężnych aplikacji internetowych, bez których nie możemy żyć. Jednak wciąż brakuje piękna adnotacji i dekoracji tekstu HTML. Co to jest dekoracja tekstu? Faliste podkreślenia, surowe podświetlenia i faliste przekreślenia to tylko niektóre z rzeczy, których przeglądarki internetowe nie zapewniają natywnej obsługi. To może wydawać się bardziej skomplikowane niż użyteczne, ale zdolność programistów JavaScript do tworzenia tych stylów może okazać się przydatna w takich aspektach, jak zasoby e-learningowe i internetowe czytniki e-booków. Co więcej, może to przyczynić się do poprawy doświadczenia użytkownika w aplikacjach internetowych, które opierają się na naturalnych zasadach projektowania. Przynajmniej budowanie takiego narzędzia jest zabawne i zapewnia wgląd w wiele dziwactw przeglądarki internetowej.
Deweloperzy znaleźli wiele obejść ograniczenia przeglądarki internetowej. Wiele z tych obejść wymaga użycia CSS w mniej intuicyjny sposób, ponieważ niektóre używają obrazów w pseudoelementach „::after”. To działa, ale utrzymanie wielu obrazów dla każdej pary styl-kolor często okazuje się trudne. W tym artykule przyjrzymy się anatomii biblioteki JavaScript, która stara się elegancko rozwiązać ten problem.
Biblioteka jest open source i jest dostępna na GitHub: Text Annotator
Przegląd
Przy tworzeniu tej biblioteki szczególną uwagę zwrócono na zapewnienie kompatybilności z najpopularniejszymi przeglądarkami internetowymi (w tym IE 9+). Jednak w przeciwieństwie do tego, jak większość rozwiązuje ten problem, biblioteka nie opiera się na specjalnie niejasnych sztuczkach CSS; lub gorzej, specjalne symbole Unicode. Zamiast tego używa SVG, aby uzyskać znacznie lepsze, czystsze dekoracje tekstu.
Zasadniczo biblioteka implementuje „klasę” Annotatora, która może być używana do automatycznego tworzenia elementów DIV, umieszczania ich pod tekstami, które mają być opisywane, i wypełniania ich tła obrazami SVG. Wiele elementów DIV można łączyć, aby jeszcze bardziej dostosować dekoracje. Podejście to jest kompatybilne z różnymi przeglądarkami, zapewnia elastyczność w pozycjonowaniu elementów dekoracyjnych i umożliwia łatwiejsze rozszerzenie za pomocą niestandardowych szablonów.
Biblioteka została opracowana przy użyciu Google Closure Tools, ponieważ jest modułowa i obsługuje wiele przeglądarek, co pomaga w tworzeniu zwartego i szybkiego kodu JavaScript bez żadnych dodatkowych zależności.
Architektura
Biblioteka została zaprojektowana jako zbiór „klas” JavaScript i udostępnia użytkownikowi wszystkie niezbędne funkcjonalności za pośrednictwem Annotatora „klasy”:
Oto krótki zarys dostępnych funkcjonalności:
annotateDocument - adnotuje elementy, które są oznaczone atrybutem „data-annotate”.
podkreślenie - podkreśla element
wyróżnienie - podkreśla element
strajk - uderza element
underlineSelected - podkreśla zaznaczony tekst
highlightSelected - podświetla zaznaczony tekst
strikeSelected - uderza w wybrany tekst
unannotateElement - usuwa adnotację z elementu
getTemplates - zwraca słownik szablonów adnotacji
setUnderlineOptions — ustawia ustawienia dla adnotatora podkreślenia
setHighlightOptions — ustawia ustawienia adnotatora podświetlenia
setStrikeOptions - ustawia ustawienia dla adnotatora ostrzeżeń
Klasa adnotator zawiera trzy wystąpienia klasy AnnotatorImpl dla każdej funkcji adnotacji: podkreślenie, wyróżnienie i przekreślenie.
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); };
Instancje AnnotatorImpl są tworzone z różnymi identyfikatorami i obiektami pomocniczymi pozycjonera. Przekazane identyfikatory są później używane w nazwach klas CSS i nazwach pól wewnętrznych, co wymaga, aby identyfikatory były unikatowe. Przekazuje się również odniesienie do listy znanych szablonów (można je później zmienić).
Każdy obiekt pozycjonera jest implementacją interfejsu IPOSitioner, który posiada tylko metodę „getPosition” i wygląda następująco:
/** * 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) }; } });
Dzięki temu każdy szablon może być używany z adnotacjami podkreślenia, wyróżnienia lub przekreślenia. Kiedy adnotacja jest stosowana do elementu, ramka ograniczająca dla elementu jest uzyskiwana przez wywołanie „getElementRects”, jak pokazano poniżej:
var rects = elemOrEv.getClientRects();
Ta metoda zwraca kolekcję prostokątów, które wskazują prostokąty ograniczające dla każdego pola w kliencie. Po przejściu każdego prostownika do pozycjonera betonu otrzymamy granice celu.
Szablony adnotacji tekstowych SVG
Jak wspomniano wcześniej, istnieje tylko jeden zestaw szablonów, które są używane do wszelkiego rodzaju adnotacji tekstowych SVG. Każdy szablon składa się z części szablonu. Część szablonu to jednostka, która reprezentuje zawartość części, szerokość szablonu i tryb rysowania.
Zawartość
Treść to zestaw elementów SVG reprezentowanych jako ciąg. Ponieważ ta treść nie ma głównego węzła SVG, w którym ustawiono szerokość i wysokość widocznego obszaru (w pikselach), konstruktor części szablonu akceptuje je jako parametry. Na przykład, możesz określić rozmiar rzutni jako 100px x 100px i narysować linię do (50, 50) i (25, 25). Po zastosowaniu adnotacji wszystkie elementy SVG zostaną odpowiednio dopasowane do żądanego rozmiaru. Wartość treści może zawierać ciąg „{0}”, który zostanie zastąpiony kolorem wybranym przez użytkownika.
Poniższy plik SVG renderuje linię ukośną. Będziemy używać tego jako jednej z części w przykładowym stylu adnotacji poniżej:
<line x1="0" y1="0" x2="5" y2="5" stroke-width="2" stroke="red" />
Szerokość
Szerokość szablonu to ciąg, którym może być „*”, „wysokość” lub cokolwiek innego:
„*” ustawia szerokość wszystkich elementów z gwiazdką równą sobie
„wysokość” ustawia szerokość równą wysokości elementu adnotacji
Wszystko inne ustawione tutaj będzie bezpośrednio ustawione na właściwości CSS width i min-width.
Tryb rysowania
Tryb rysowania to ciąg, który może być „powtórz” lub „rozciągnij”. Jak wskazują wartości, ustawienie go na „powtarzać” spowoduje powtórzenie treści, a ustawienie na „rozciąganie” rozciągnie zawartość.
Oto przykład tego, co możemy osiągnąć, konfigurując te trzy parametry:
Adnotacja tekstowa w powyższym przykładzie składa się z 4 części. Pierwsza część to linia ukośna, z szerokością szablonu ustawioną na „wysokość” i trybem rysowania ustawionym na „powtórz”. Druga część ma szerokość szablonu ustawioną na „*” i tryb rysowania ustawiony na „powtórz”. Trzecia część ma szerokość „15px” i jest rysowana w trybie „powtarzania”. Wreszcie szerokość ostatniej części jest ustawiona na „*”, a jej tryb rysowania jest ustawiony na „rozciąganie”.
Kiedy te szerokości są oceniane, pierwsza część zajmuje 5 pikseli (równe wysokości elementu adnotacji), trzecia część zajmuje 15 pikseli (zgodnie z ustawieniem), a pozostała przestrzeń jest równo dzielona między drugą i czwartą część.
Gdy ten sam fragment tekstu jest podświetlony przy użyciu tego samego szablonu, otrzymujemy:
Jak widać, wysokość elementu adnotacji jest większa, podobnie jak szerokość pierwszej części (ponieważ szerokość szablonu dla tej części jest ustawiona na „wysokość”). Oczywiście szerokość trzeciej części pozostała niezmieniona w stosunku do poprzedniego przykładu.
Zastosowanie efektu przekreślenia do tego samego tekstu z tym samym szablonem daje wynik bardzo podobny do pierwszego. Jedyną różnicą jest lokalizacja, w której znajdują się elementy adnotacji:
Chociaż te adnotacje tekstowe wydają się skomplikowane (sposób, w jaki wyglądają, składają się z czterech odrębnych części), wszystkie wykorzystują bardzo proste elementy SVG. Jako dodatkowy przykład, wykonanie falistej linii wymaga pojedynczej części z następującą, prostą zawartością SVG:
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' ))
Gdy te szablony są oceniane, rozmiar zawartości jest zmieniany, a „{0}” jest automatycznie zastępowane określonym kolorem. Co więcej, dodawanie nowych szablonów jest tak proste, jak dodawanie ich do obiektu JavaScript:
tvs.AnnotatorDictionary.svgTemplates['brush'] = new tvs.Template(new tvs.SvgTemplatePart( svgContent, 50, 50, '*', 'stretch' ));
Wyniki
Każda adnotacja jest stosowana przez dodanie do strony elementu div z pozycjonowaniem bezwzględnym:
<div class="tvs-annotate-element"> <div class="tvs-wrap-div"> <table> <tr> <td></td> <td></td> <td></td> </tr> </table> </div> </div>
Element div jest wypełniany tabelą, w której każda dodana komórka odpowiada jednej z części w szablonie. Zawartość każdej części szablonu jest dodawana jako URI danych zakodowanych w Base64, z zastosowanym wybranym kolorem:
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; };
Osadzanie
Dla lepszego doświadczenia użytkownika, zwłaszcza podczas próby użycia tej biblioteki JavaScript z edytowalnymi obszarami zawartości, ważne jest, aby adnotator tekstu znał granice tekstu aktualnie wybranego przez użytkownika. Rangy, zgrabna biblioteka JavaScript zajmująca się zakresem i selekcją, została wykorzystana do osiągnięcia tego w sposób umożliwiający korzystanie z różnych przeglądarek. Rangy zapewnia prosty, oparty na standardach interfejs API do wykonywania typowych zadań zakresu DOM i wyboru we wszystkich głównych przeglądarkach, oddzielając szalenie różne implementacje tej funkcji między Internet Explorerem a przeglądarkami zgodnymi z DOM. To jedyna zależność projektu.
Po osadzeniu adnotatora tekstu korzystanie z niego jest bardzo proste:
var annotator = new tvs.Annotator(); annotator.underlineSelected();
Każdy element adnotacji jest oznaczony klasą „tvs-annotated-text”, a każdy element adnotacji ma klasę „tvs-annotate-element”. Usuwanie adnotacji jest jeszcze prostsze, jednowierszowe:
annotator.unannotateElement(annotatedElement);
Dziwactwa
Po zmianie rozmiaru okna elementy mogą się przemieszczać, co wymaga „odświeżenia” elementów z adnotacjami. Jest to obsługiwane przez bibliotekę. Jednakże; aby zmniejszyć wpływ na wydajność, wezwanie do odświeżenia adnotacji jest ograniczane:
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); };
Po odświeżeniu elementy adnotacji można dodawać, zmieniać ich rozmiar lub usuwać ze strony zgodnie z wymaganiami.
Wygoda
Aby ułatwić dodawanie adnotacji do tekstu statycznego na stronie, wystarczy prosty atrybut danych w elemencie kontenera:
data-annotate='underline squiggly green'
Spowoduje to adnotację zawartości elementu za pomocą falistego, zielonego podkreślenia.
Wniosek
Co więcej mogę powiedzieć o tym samouczku tekstowym SVG? Łatwo zaimplementowano zabawne, ale potężne narzędzie. Nie sądzę, abyśmy odnieśli wiele korzyści, zapewniając obsługę Internet Explorera 8, ponieważ zamiast tego możemy skomplikować całą implementację. Jednak dzięki pewnym ulepszeniom i odrobinie pracy nad rdzeniem możemy rozszerzyć bibliotekę, aby móc tworzyć ozdobne obramowania dla elementów nietekstowych. Co więcej, ciekawym zadaniem może być zaimplementowanie mechanizmu zapisywania i późniejszego przywracania stanu edytowalnej treści adnotacji.
Na razie możliwości ogranicza tylko Twoja wyobraźnia (i możliwości przeglądarki). Być może potrzebujesz linii mikrodruku, gradientów, a nawet animacji. Z Adnotatorem tekstu możesz.