บทช่วยสอนข้อความ SVG: คำอธิบายประกอบข้อความบนเว็บ

เผยแพร่แล้ว: 2022-03-11

ด้วย HTML5 และ CSS3 เว็บเบราว์เซอร์ได้รับเทคโนโลยีที่น่าทึ่งมากมาย: กราฟิก 3 มิติ ซ็อกเก็ต เธรด และอื่นๆ ด้วยเหตุนี้ เว็บแอปพลิเคชันจึงสามารถใช้ประโยชน์จากความสามารถที่ซับซ้อนที่สุดของคอมพิวเตอร์และระบบปฏิบัติการที่ใช้งานได้ เว็บเบราว์เซอร์นำเสนอระบบนิเวศที่หลากหลายที่แข็งแกร่งสำหรับการพัฒนาแอปพลิเคชัน ซึ่งเห็นได้จากการเพิ่มขึ้นของเว็บแอปพลิเคชันที่ทรงพลังมากมายเมื่อเร็วๆ นี้ ซึ่งเราไม่สามารถอยู่ได้โดยปราศจาก อย่างไรก็ตาม สิ่งที่ยังขาดหายไปคือความสวยงามของคำอธิบายประกอบและการตกแต่งข้อความ HTML การตกแต่งข้อความคืออะไร? การขีดเส้นใต้ที่หยาบกร้าน ไฮไลต์ที่ขรุขระ และการขีดฆ่าที่เป็นคลื่นคือบางสิ่งที่เว็บเบราว์เซอร์ไม่ได้ให้การสนับสนุนดั้งเดิม นี่อาจฟังดูซับซ้อนกว่ามีประโยชน์ แต่ความสามารถสำหรับนักพัฒนา JavaScript ในการสร้างสไตล์เหล่านี้อาจพิสูจน์ได้ว่ามีประโยชน์ในด้านต่างๆ เช่น แหล่งข้อมูลอีเลิร์นนิงและโปรแกรมอ่าน ebook บนเว็บ นอกจากนี้ยังสามารถช่วยเพิ่มประสบการณ์ผู้ใช้ในเว็บแอปพลิเคชันที่เกี่ยวกับหลักการออกแบบที่เป็นธรรมชาติ อย่างน้อยที่สุด การสร้างเครื่องมือดังกล่าวเป็นเรื่องสนุกและให้ข้อมูลเชิงลึกเกี่ยวกับลักษณะเฉพาะต่างๆ ของเว็บเบราว์เซอร์

บทช่วยสอนข้อความ SVG - คำอธิบายประกอบข้อความ

นักพัฒนาซอฟต์แวร์พบวิธีแก้ไขปัญหาชั่วคราวมากมายสำหรับข้อจำกัดของเว็บเบราว์เซอร์ วิธีแก้ปัญหาชั่วคราวเหล่านี้เกี่ยวข้องกับการใช้ CSS ในรูปแบบที่ไม่ค่อยเป็นธรรมชาติ เนื่องจากบางส่วนใช้รูปภาพในองค์ประกอบเทียม "::after" วิธีนี้ใช้ได้ แต่การรักษาภาพหลายภาพสำหรับคู่สไตล์-สีแต่ละคู่มักจะพิสูจน์ได้ยาก บทความนี้กล่าวถึงกายวิภาคของไลบรารี JavaScript ที่พยายามแก้ปัญหานี้อย่างงดงาม

ไลบรารีเป็นโอเพ่นซอร์ส และพร้อมใช้งานบน GitHub: Text Annotator

ภาพรวม

ขณะพัฒนาไลบรารีนี้ เราให้ความสำคัญเป็นพิเศษกับการรับประกันความเข้ากันได้กับเว็บเบราว์เซอร์ยอดนิยม (รวมถึง IE 9+) อย่างไรก็ตาม ไลบรารีไม่ได้พึ่งพาเทคนิค CSS ที่ไม่ชัดเจน ซึ่งแตกต่างจากวิธีแก้ปัญหานี้ส่วนใหญ่ หรือแย่กว่านั้นคือสัญลักษณ์ Unicode พิเศษ แทนที่จะใช้ SVG เพื่อให้ได้การตกแต่งข้อความที่ดีขึ้นและสะอาดตายิ่งขึ้น

โดยพื้นฐานแล้ว ไลบรารีจะใช้ "คลาส" ของ Annotator ที่สามารถใช้เพื่อสร้างองค์ประกอบ DIV โดยอัตโนมัติ วางตำแหน่งไว้ใต้ข้อความที่จะใส่คำอธิบายประกอบ และเติมพื้นหลังด้วยภาพ SVG สามารถรวม DIV หลายตัวเพื่อปรับแต่งการตกแต่งเพิ่มเติมได้ วิธีการนี้เข้ากันได้กับเบราว์เซอร์ข้าม ให้ความยืดหยุ่นเหนือตำแหน่งขององค์ประกอบตกแต่ง และช่วยให้ขยายได้ง่ายขึ้นด้วยเทมเพลตที่กำหนดเอง

ไลบรารีได้รับการพัฒนาโดยใช้ Google Closure Tools เนื่องจากเป็นแบบโมดูลาร์และแบบข้ามเบราว์เซอร์ ซึ่งช่วยสร้างโค้ด JavaScript ที่กะทัดรัดและรวดเร็วโดยไม่ต้องพึ่งพาเพิ่มเติม

สถาปัตยกรรม

ไลบรารีได้รับการออกแบบให้เป็นคอลเล็กชันของ "คลาส" ของ JavaScript และแสดงฟังก์ชันที่จำเป็นทั้งหมดแก่ผู้ใช้ผ่าน "คลาส" Annotator:

ไลบรารีตัวบันทึกข้อความ

นี่คือโครงร่างสั้น ๆ ของฟังก์ชันที่พร้อมใช้งาน:

  • annotateDocument - ใส่คำอธิบายประกอบองค์ประกอบซึ่งทำเครื่องหมายด้วยแอตทริบิวต์ "data-annotate"

  • ขีดเส้นใต้ - ขีดเส้นใต้องค์ประกอบ

  • ไฮไลท์ - ไฮไลท์องค์ประกอบ

  • การนัดหยุดงาน - องค์ประกอบการนัดหยุดงาน

  • underlineSelected - ขีดเส้นใต้ข้อความที่เลือก

  • highlightSelected - ไฮไลท์ข้อความที่เลือก

  • strikeSelected - นัดหยุดงานข้อความที่เลือก

  • 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 ไม่ซ้ำกัน นอกจากนี้ การอ้างอิงไปยังรายการเทมเพลตที่รู้จักจะถูกส่งต่อ (สามารถเปลี่ยนแปลงได้ในภายหลัง)

แต่ละอ็อบเจ็กต์ positioner เป็นการนำอินเทอร์เฟซ IPositioner ไปใช้ซึ่งมีเมธอด “getPosition” เท่านั้น และมีลักษณะดังนี้:

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

เมธอดนี้ส่งคืนคอลเลกชันของสี่เหลี่ยมที่ระบุสี่เหลี่ยมที่มีขอบเขตสำหรับแต่ละกล่องในไคลเอนต์ หลังจากผ่านแต่ละส่วนตรงไปยังตัวกำหนดตำแหน่งที่เป็นรูปธรรม เราจะได้รับขอบเขตปลายทาง

เทมเพลตคำอธิบายประกอบข้อความ 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" />

ความกว้าง

ความกว้างของเทมเพลตคือสตริงที่สามารถเป็น “*”, “ความสูง” หรืออะไรก็ได้:

  • “*” กำหนดความกว้างขององค์ประกอบทั้งหมดที่มีดาวเท่ากัน

  • “ความสูง” กำหนดความกว้างเท่ากับความสูงขององค์ประกอบคำอธิบายประกอบ

สิ่งอื่นๆ ที่ตั้งไว้ที่นี่จะถูกตั้งค่าโดยตรงเป็นคุณสมบัติความกว้างของ CSS และความกว้างต่ำสุด

คุณสมบัติ CSS

โหมดวาด

โหมดการวาดเป็นสตริงที่สามารถเป็น "ซ้ำ" หรือ "ยืด" ได้ ตามค่าที่ระบุ การตั้งค่าเป็น "ซ้ำ" จะทำให้เนื้อหาซ้ำ ในขณะที่การตั้งค่าเป็น "ยืด" จะยืดเนื้อหา

นี่คือตัวอย่างสิ่งที่เราสามารถทำได้โดยการกำหนดค่าพารามิเตอร์ทั้งสามนี้:

หมายเหตุข้อความ

คำอธิบายประกอบข้อความในตัวอย่างข้างต้นประกอบด้วย 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 ถูกเติมด้วยตารางที่ทุกเซลล์ที่เพิ่มเข้ามาจะสัมพันธ์กับส่วนใดส่วนหนึ่งในเทมเพลต เนื้อหาของแต่ละส่วนของเทมเพลตจะถูกเพิ่มเป็น URI ข้อมูลที่เข้ารหัส Base64 โดยใช้สีที่เลือก:

 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 เพื่อทราบขอบเขตของข้อความที่ผู้ใช้เลือกในปัจจุบัน Rangy ซึ่งเป็นไลบรารี JavaScript ที่เรียบร้อยซึ่งเกี่ยวข้องกับช่วงและการเลือก ถูกนำมาใช้เพื่อให้บรรลุเป้าหมายนี้ในลักษณะข้ามเบราว์เซอร์ Rangy จัดเตรียม API ตามมาตรฐานอย่างง่ายสำหรับการทำงาน DOM Range และ Selection ทั่วไปในเบราว์เซอร์หลักทั้งหมด ทำให้การใช้งานฟังก์ชันนี้แตกต่างกันอย่างมากระหว่าง 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 อย่างง่ายในองค์ประกอบคอนเทนเนอร์:

 data-annotate='underline squiggly green'

สิ่งนี้จะอธิบายเนื้อหาขององค์ประกอบด้วยการขีดเส้นใต้สีเขียวขยุกขยิก

บทสรุป

ฉันจะพูดอะไรได้อีกเกี่ยวกับบทช่วยสอนข้อความ SVG นี้ เครื่องมือที่สนุกแต่ทรงพลังได้รับการนำไปใช้อย่างง่ายดาย ฉันไม่คิดว่าเราจะได้รับประโยชน์มากนักจากการรับประกันการสนับสนุน Internet Explorer 8 เนื่องจากเราอาจทำให้การใช้งานทั้งหมดซับซ้อน อย่างไรก็ตาม ด้วยการปรับปรุงและการทำงานเพียงเล็กน้อยในแกนกลาง เราสามารถขยายไลบรารีเพื่อให้สามารถผลิตเส้นขอบตกแต่งสำหรับองค์ประกอบที่ไม่ใช่ข้อความได้ นอกจากนี้ อาจเป็นงานที่น่าสนใจที่จะใช้กลไกบางอย่างเพื่อบันทึกและกู้คืนสถานะของเนื้อหาที่แก้ไขได้ของคำอธิบายประกอบในภายหลัง

สำหรับตอนนี้ ความเป็นไปได้นั้นจำกัดด้วยจินตนาการของคุณเท่านั้น (และความสามารถของเบราว์เซอร์) บางทีคุณอาจต้องการเส้น microprint หรือการไล่ระดับสี หรือแม้แต่แอนิเมชั่น ด้วย Text Annotator คุณสามารถ