SVG 텍스트 튜토리얼: 웹에서의 텍스트 주석

게시 됨: 2022-03-11

HTML5 및 CSS3를 통해 웹 브라우저는 3D 그래픽, 소켓, 스레드 등 여러 놀라운 기술을 획득했습니다. 이를 통해 웹 응용 프로그램은 사용되는 컴퓨터 및 운영 체제의 가장 정교한 기능을 활용할 수 있습니다. 웹 브라우저는 애플리케이션 개발을 위한 강력한 다목적 생태계를 제공하며, 이는 우리가 없이는 살 수 없는 수많은 강력한 웹 애플리케이션의 최근 부상에서 분명합니다. 그러나 여전히 누락된 것은 HTML 텍스트 주석 및 장식의 아름다움입니다. 텍스트 장식이란 무엇입니까? 구불구불한 밑줄, 거친 강조 표시 및 물결 모양의 취소선은 웹 브라우저가 기본적으로 지원하지 않는 부분입니다. 이것은 유용하기보다 정교하게 들릴 수 있지만 JavaScript 개발자가 이러한 스타일을 생성할 수 있는 기능은 전자 학습 리소스 및 웹 기반 전자 책 리더와 같은 측면에서 유용할 수 있습니다. 또한, 이는 자연 디자인 원칙을 중심으로 하는 웹 애플리케이션의 사용자 경험 향상에 기여할 수 있습니다. 최소한 그러한 도구를 구축하는 것은 재미있고 웹 브라우저의 많은 단점에 대한 통찰력을 제공합니다.

SVG 텍스트 튜토리얼 - 텍스트 주석

개발자는 웹 브라우저 제한에 대한 많은 해결 방법을 찾았습니다. 이러한 해결 방법의 대부분은 "::after" 유사 요소의 이미지를 사용하기 때문에 덜 직관적인 방식으로 CSS를 사용하는 것과 관련이 있습니다. 이것은 효과가 있지만 각 스타일-색상 쌍에 대해 많은 이미지를 유지 관리하는 것은 종종 어려운 일입니다. 이 기사에서는 이 문제를 우아하게 해결하려는 JavaScript 라이브러리의 구조를 살펴봅니다.

라이브러리는 오픈 소스이며 GitHub: Text Annotator에서 사용할 수 있습니다.

개요

이 라이브러리를 개발하는 동안 가장 인기 있는 웹 브라우저(IE 9 이상 포함)와의 호환성을 보장하는 데 특별한 주의를 기울였습니다. 그러나 대부분이 이 문제를 해결하는 방법과 달리 라이브러리는 특히 모호한 CSS 트릭에 의존하지 않습니다. 또는 더 나쁜 것은 특수 유니코드 기호입니다. 대신 SVG를 사용하여 훨씬 더 좋고 깔끔한 텍스트 장식을 구현합니다.

기본적으로 라이브러리는 DIV 요소를 자동으로 생성하고 주석을 추가할 텍스트 아래에 배치하고 배경을 SVG 이미지로 채우는 데 사용할 수 있는 Annotator "클래스"를 구현합니다. 여러 DIV를 결합하여 장식을 추가로 사용자 지정할 수 있습니다. 이 접근 방식은 브라우저 간 호환이 가능하고 장식 요소의 위치 지정에 대한 유연성을 제공하며 사용자 지정 템플릿으로 쉽게 확장할 수 있습니다.

라이브러리는 모듈식 및 크로스 브라우저이기 때문에 Google Closure Tools를 사용하여 개발되었으며 추가 종속성 없이 간결하고 빠른 JavaScript 코드를 생성하는 데 도움이 됩니다.

건축물

라이브러리는 JavaScript "클래스" 모음으로 설계되었으며 "클래스" Annotator를 통해 사용자에게 필요한 모든 기능을 제공합니다.

텍스트 주석자 라이브러리

다음은 사용 가능한 기능에 대한 간략한 개요입니다.

  • annotateDocument - "data-annotate" 속성으로 표시된 요소에 주석을 답니다.

  • 밑줄 - 요소에 밑줄

  • 하이라이트 - 하이라이트 요소

  • 스트라이크 - 스트라이크 요소

  • underlineSelected - 선택한 텍스트에 밑줄을 긋습니다.

  • HighlightSelected - 선택한 텍스트 강조 표시

  • 스트라이크 선택 - 선택한 텍스트를 스트라이크

  • unannotateElement - 요소에서 주석을 제거합니다.

  • getTemplates - 주석 템플릿의 사전을 반환합니다.

  • setUnderlineOptions - 밑줄 주석에 대한 설정을 지정합니다.

  • setHighlightOptions - 강조 표시 주석에 대한 설정을 지정합니다.

  • setStrikeOptions - 스트라이크 주석에 대한 설정을 지정합니다.

Annotator 클래스는 각 주석 기능에 대한 AnnotatorImpl 클래스의 세 가지 인스턴스(밑줄, 강조 표시 및 스트라이크)를 보유합니다.

 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 인스턴스는 다른 ID와 포지셔너 도우미 개체로 생성됩니다. 전달된 ID는 나중에 CSS 클래스 이름과 내부 필드 이름에서 사용되며 ID는 고유해야 합니다. 또한 알려진 템플릿 목록에 대한 참조가 전달됩니다(나중에 변경할 수 있음).

각 포지셔너 개체는 "getPosition" 메서드만 있고 다음과 같이 보이는 IPositioner 인터페이스의 구현입니다.

 /** * 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) }; } });

이렇게 하면 밑줄, 강조 표시 또는 스트라이크 텍스트 주석과 함께 모든 템플릿을 사용할 수 있습니다. 주석이 요소에 적용될 때 요소의 경계 상자는 아래와 같이 "getElementRects"를 호출하여 얻습니다.

 var rects = elemOrEv.getClientRects();

이 메서드는 클라이언트의 각 상자에 대한 경계 사각형을 나타내는 사각형 컬렉션을 반환합니다. 각 rect를 구체적인 포지셔너에 전달한 후 대상 경계를 얻습니다.

SVG 텍스트 주석 템플릿

앞서 언급했듯이 모든 종류의 SVG 텍스트 주석에 사용되는 템플릿 세트는 단 하나뿐입니다. 모든 템플릿은 템플릿 부분으로 구성됩니다. 템플릿 파트는 파트의 내용, 템플릿 너비 및 그리기 모드를 나타내는 엔터티입니다.

콘텐츠

콘텐츠는 문자열로 표현되는 SVG 요소의 집합입니다. 이 콘텐츠에는 뷰포트의 너비와 높이(픽셀 단위)가 설정된 루트 SVG 노드가 없기 때문에 템플릿의 부분 생성자는 이를 매개변수로 받아들입니다. 예를 들어, 뷰포트의 크기를 100px x 100px로 지정하고 (50, 50) 및 (25, 25)에 선을 그릴 수 있습니다. 주석이 적용된 후 모든 svg 요소의 크기가 원하는 크기로 적절하게 조정됩니다. 콘텐츠 값은 사용자가 선택한 색상으로 대체될 문자열 "{0}"을 사용할 수 있습니다.

다음 SVG는 대각선을 렌더링합니다. 우리는 이것을 곧 다음 주석 스타일 예제의 부분 중 하나로 사용할 것입니다.

 <line x1="0" y1="0" x2="5" y2="5" stroke-width="2" stroke="red" />

너비

템플릿 너비는 "*", "높이" 또는 기타가 될 수 있는 문자열입니다.

  • "*"는 별표가 있는 모든 요소의 너비를 서로 동일하게 설정합니다.

  • "height"는 주석 요소의 높이와 동일한 너비를 설정합니다.

여기에 설정된 다른 모든 것은 CSS 너비 및 최소 너비 속성으로 직접 설정됩니다.

CSS 속성

그리기 모드

그리기 모드는 "반복" 또는 "늘이기"가 될 수 있는 문자열입니다. 값에서 알 수 있듯이 "repeat"로 설정하면 콘텐츠가 반복되고 "stretch"로 설정하면 콘텐츠가 늘어납니다.

다음은 이 세 가지 매개변수를 구성하여 달성할 수 있는 작업의 예입니다.

텍스트 주석

위 예의 텍스트 주석에는 4개의 부분이 있습니다. 첫 번째 부분은 템플릿 너비가 "높이"로 설정되고 그리기 모드가 "반복"으로 설정된 대각선입니다. 두 번째 부분은 템플릿 너비가 "*"로 설정되어 있고 그리기 모드가 "반복"으로 설정되어 있습니다. 세 번째 부분은 "15px" 너비로 설정되고 "반복" 모드로 그려집니다. 마지막으로 마지막 부분의 너비는 "*"로 설정되고 그리기 모드는 "늘이기"로 설정됩니다.

이러한 너비가 평가될 때 첫 번째 부분은 5픽셀(주석 요소의 높이와 동일)을 사용하고 세 번째 부분은 15픽셀(설정된 대로)을 사용하며 나머지 공간은 두 번째 부분과 네 번째 부분으로 균등하게 분할됩니다.

동일한 템플릿을 사용하여 동일한 텍스트를 강조 표시하면 다음과 같습니다.

그리기 모드

알 수 있듯이 주석 요소의 높이는 더 크고 첫 번째 부분의 너비도 마찬가지입니다(해당 부분의 템플릿 너비가 "높이"로 설정되어 있기 때문에). 당연히 세 번째 부분의 너비는 이전 예와 변경되지 않았습니다.

동일한 템플릿을 사용하여 동일한 텍스트에 취소선 효과를 적용하면 첫 번째 것과 매우 유사한 결과가 생성됩니다. 유일한 차이점은 주석 요소가 배치되는 위치입니다.

텍스트 주석 그리기 모드

이러한 텍스트 주석은 복잡해 보이지만(모양, 네 부분으로 구분) 매우 단순한 SVG 요소를 사용합니다. 추가 예로서 구불구불한 선을 수행하려면 다음과 같은 간단한 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' ))

이러한 템플릿이 평가되면 내용의 크기가 조정되고 "{0}"이 지정된 색상으로 자동으로 대체됩니다. 더욱이 새 템플릿을 추가하는 것은 JavaScript 객체에 추가하는 것만큼 간단합니다.

 tvs.AnnotatorDictionary.svgTemplates['brush'] = new tvs.Template(new tvs.SvgTemplatePart( svgContent, 50, 50, '*', 'stretch' ));

결과

각 주석은 페이지에 절대 위치 지정이 있는 div 요소를 추가하여 적용됩니다.

 <div class="tvs-annotate-element"> <div class="tvs-wrap-div"> <table> <tr> <td></td> <td></td> <td></td> </tr> </table> </div> </div>

div 요소는 추가된 모든 셀이 템플릿의 부분 중 하나에 해당하는 테이블로 채워집니다. 각 템플릿 부분의 콘텐츠는 선택한 색상이 적용된 Base64 인코딩 데이터 URI로 추가됩니다.

 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; };

임베딩

더 나은 사용자 경험을 위해, 특히 편집 가능한 콘텐츠 영역과 함께 이 JavaScript 라이브러리를 사용하려고 할 때, Text Annotator는 사용자가 현재 선택한 텍스트의 경계를 아는 것이 중요합니다. 범위 및 선택을 처리하는 깔끔한 JavaScript 라이브러리인 Rangy는 브라우저 간 방식으로 이를 달성하는 데 사용되었습니다. Rangy는 모든 주요 브라우저에서 공통 DOM 범위 및 선택 작업을 수행하기 위한 간단한 표준 기반 API를 제공하여 Internet Explorer에서 DOM 호환 브라우저까지 이 기능의 엄청나게 다른 구현을 추상화합니다. 이것은 프로젝트의 유일한 종속성입니다.

Text Annotator가 포함되면 사용하는 것은 매우 간단합니다.

 var annotator = new tvs.Annotator(); annotator.underlineSelected();

주석이 달린 각 요소는 "tvs-annotated-text" 클래스로 표시되고 각 주석 요소에는 "tvs-annotate-element" 클래스가 있습니다. 주석 제거는 한 줄로 훨씬 간단합니다.

 annotator.unannotateElement(annotatedElement);

단점

창의 크기가 조정되면 요소가 이동할 수 있으므로 주석이 달린 요소를 "새로 고침"해야 합니다. 이것은 라이브러리에서 처리합니다. 하지만; 성능에 미치는 영향을 줄이기 위해 주석 새로 고침 호출이 제한됩니다.

 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); };

새로 고침 시 주석 요소를 추가, 크기 조정 또는 필요에 따라 페이지에서 제거할 수 있습니다.

편의

페이지의 정적 텍스트에 주석을 쉽게 추가하려면 컨테이너 요소의 간단한 데이터 속성만 있으면 됩니다.

 data-annotate='underline squiggly green'

그러면 구불구불한 녹색 밑줄이 있는 요소의 내용에 주석이 추가됩니다.

결론

이 SVG 텍스트 자습서에 대해 무엇을 더 말할 수 있습니까? 재미있지만 강력한 도구가 쉽게 구현되었습니다. Internet Explorer 8에 대한 지원을 보장함으로써 우리가 많은 이점을 얻을 것이라고 생각하지 않습니다. 대신 전체 구현을 복잡하게 만들 수 있기 때문입니다. 그러나 몇 가지 개선 사항과 코어에 대한 약간의 작업을 통해 라이브러리를 확장하여 텍스트가 아닌 요소에 대한 장식 테두리를 생성할 수 있습니다. 또한 주석의 편집 가능한 내용 상태를 저장하고 나중에 복원하는 일부 메커니즘을 구현하는 것은 흥미로운 작업일 수 있습니다.

현재로서는 가능성이 귀하의 상상력(및 브라우저 기능)에 의해서만 제한됩니다. 미세 인쇄 선, 그라디언트 또는 애니메이션을 원할 수도 있습니다. Text Annotator를 사용하면 할 수 있습니다.