นำ React, D3 และระบบนิเวศของพวกเขามารวมกัน

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างย่อ ↬ React และ D3.js เป็นเครื่องมือที่ยอดเยี่ยมที่จะช่วยเราจัดการกับ DOM และความท้าทายของมัน พวกเขาสามารถทำงานร่วมกันได้อย่างแน่นอน และเรามีอำนาจในการเลือกว่าจะลากเส้นแบ่งระหว่างพวกเขาที่ไหน

นับตั้งแต่ก่อตั้งในปี 2011 D3.js ได้กลายเป็นมาตรฐาน โดยพฤตินัย สำหรับการสร้างการแสดงข้อมูลเป็นภาพที่ซับซ้อนบนเว็บ React ยังเติบโตอย่างรวดเร็วในฐานะไลบรารี่ทางเลือกสำหรับการสร้างส่วนต่อประสานผู้ใช้แบบอิงส่วนประกอบ

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

ในโพสต์นี้ เราจะมาดูกันว่าเราจะสร้างโครงการ React ที่ต้องการการสร้างแผนภูมิอันทรงพลังของ D3 ได้อย่างไร เราจะค้นพบเทคนิคต่างๆ และวิธีการเลือกห้องสมุดที่ดีที่สุดสำหรับความต้องการของคุณในงานหลักและโครงการรองของคุณ

D3 และ DOM

D3 ใน D3.js ย่อมาจากเอกสารที่ขับเคลื่อนด้วยข้อมูล D3.js เป็น ไลบรารีระดับต่ำ ที่มีองค์ประกอบพื้นฐานที่จำเป็นในการสร้างการแสดงข้อมูลเชิงโต้ตอบ ใช้มาตรฐานเว็บเช่น SVG, HTML, canvas และ CSS เพื่อประกอบกล่องเครื่องมือส่วนหน้าด้วย API ที่กว้างใหญ่ และควบคุมรูปลักษณ์และพฤติกรรมของการแสดงภาพได้แทบไร้ขีดจำกัด นอกจากนี้ยังมีฟังก์ชันทางคณิตศาสตร์หลายอย่างที่ช่วยผู้ใช้ในการคำนวณเส้นทาง SVG ที่ซับซ้อน

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

มันทำงานอย่างไร?

โดยสรุป D3.js โหลดข้อมูลและเชื่อมต่อกับ DOM จากนั้นจะผูกข้อมูลนั้นกับองค์ประกอบ DOM และแปลงองค์ประกอบเหล่านั้น โดยเปลี่ยนระหว่างสถานะต่างๆ หากจำเป็น

การเลือก D3.js นั้นคล้ายกับออบเจกต์ jQuery เพราะช่วยให้เราจัดการกับความซับซ้อนของ SVG วิธีการนี้เทียบได้กับวิธีที่ jQuery จัดการกับองค์ประกอบ HTML DOM ไลบรารีทั้งสองยังใช้ API แบบลูกโซ่ที่คล้ายคลึงกันและการใช้ DOM เป็นที่จัดเก็บข้อมูล

การรวมข้อมูล

การรวมข้อมูล ดังที่อธิบายไว้ในบทความ "Thinking with Joins" ของ Mike Bostocks เป็นกระบวนการที่ D3 เชื่อมโยงข้อมูลกับองค์ประกอบ DOM ผ่านการใช้การเลือก

การรวมข้อมูลช่วยให้เราจับคู่ข้อมูลที่เราจัดเตรียมไว้กับองค์ประกอบที่สร้างไว้แล้ว เพิ่มรายการที่ขาดหายไป และลบองค์ประกอบที่ไม่ต้องการอีกต่อไป พวกเขาใช้การเลือก D3.js ซึ่งเมื่อรวมกับข้อมูลแล้ว จะแบ่งองค์ประกอบที่เลือกออกเป็นสามกลุ่มที่แตกต่างกัน: องค์ประกอบที่ต้องสร้าง (กลุ่มเข้าสู่) องค์ประกอบที่ต้องอัปเดต (กลุ่มอัปเดต) และองค์ประกอบที่ต้องการ จะถูกลบออก (กลุ่มทางออก)

องค์ประกอบข้อมูล แผนภาพเวนน์

ในทางปฏิบัติ วัตถุ JavaScript ที่มีสองอาร์เรย์แสดงถึงการรวมข้อมูล เราสามารถทริกเกอร์การดำเนินการในกลุ่มเข้าและออกจากกลุ่มได้โดยการเรียกวิธีการเข้าและออกจากการเลือก ในขณะที่เราสามารถดำเนินการโดยตรงกับกลุ่มการอัปเดตใน D3.js เวอร์ชันล่าสุด

ตามที่อธิบายไว้โดย Bostock ด้วยการรวมข้อมูล "คุณสามารถเห็นภาพข้อมูลแบบเรียลไทม์ อนุญาตการสำรวจเชิงโต้ตอบ และการเปลี่ยนแปลงระหว่างชุดข้อมูลได้อย่างราบรื่น" พวกมันเป็นอัลกอริธึมที่แตกต่างกันอย่างมีประสิทธิภาพ คล้ายกับวิธีที่ React จัดการการเรนเดอร์องค์ประกอบย่อย ดังที่เราจะเห็นในหัวข้อต่อไปนี้

ห้องสมุด D3

ชุมชน D3 ไม่พบวิธีมาตรฐานในการสร้างส่วนประกอบจากโค้ด D3 ซึ่งเป็นความต้องการบ่อยครั้งเนื่องจาก D3.js อยู่ในระดับต่ำอย่างน่าทึ่ง เราสามารถพูดได้ว่ามีรูปแบบการห่อหุ้มเกือบมากพอๆ กับไลบรารีบน D3 แม้ว่าฉันจะจำแนกรูปแบบเหล่านี้ — ผ่าน API — ออกเป็นสี่กลุ่ม: เชิงวัตถุ, เชิงประกาศ, เชิงฟังก์ชัน และแบบลูกโซ่ (หรือเหมือน D3)

ฉันได้ค้นคว้าเกี่ยวกับระบบนิเวศ D3.js และเลือกชุดย่อยขนาดเล็กคุณภาพสูง เป็นไลบรารี่ล่าสุดที่มี D3.js เวอร์ชัน 4 และครอบคลุมการทดสอบที่ดี พวกเขาต่างกันในประเภทของ API และความละเอียดของสิ่งที่เป็นนามธรรม

พล็อตตาราง

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

พล็อตตาราง
(ที่มาของภาพ: Plottable)

ป้ายโฆษณา

Billboard คือส่วนแยกของไลบรารี C3.js ที่มีชื่อเสียง ซึ่งอัปเดตด้วยความเข้ากันได้กับ D3.js เวอร์ชัน 4 และมีเป้าหมายเพื่อให้ไลบรารีคลาสสิกนี้มีความต่อเนื่อง มันเขียนโดยใช้ ECMAScript 6 และเครื่องมือที่ทันสมัยเช่น Webpack API นั้นอิงตามออบเจ็กต์การกำหนดค่าที่ส่งไปยังแผนภูมิ ดังนั้นเราจึงสามารถพูดได้ว่าเป็น API ที่เปิดเผย

ป้ายโฆษณา
(ที่มาของภาพ: บิลบอร์ด)

เวก้า

Vega ใช้เส้นทางการประกาศเพิ่มเติมอีกเล็กน้อย โดยพัฒนาการกำหนดค่าจากออบเจกต์ JavaScript เป็นไฟล์ JSON แท้ มีจุดมุ่งหมายเพื่อใช้ไวยากรณ์การสร้างภาพข้อมูลที่ได้รับแรงบันดาลใจจาก The Grammar of Graphics ซึ่งเป็นหนังสือของ Leland Wilkinson ที่สร้างรูปแบบการสร้างภาพข้อมูลให้เป็นแบบแผนและเป็นแรงบันดาลใจสำหรับ D3.js เช่นกัน คุณสามารถใช้ตัวแก้ไขได้โดยเลือกตัวอย่างหนึ่งตัวอย่างเป็นจุดเริ่มต้น

เวก้า
(ที่มาของภาพ: เวก้า)

D3FC

D3FC ใช้ประโยชน์จาก D3.js และบล็อคการสร้างแบบกำหนดเองเพื่อช่วยคุณสร้างแผนภูมิเชิงโต้ตอบที่ทรงพลังทั้งใน SVG และผ้าใบ มันมีอินเทอร์เฟซที่ใช้งานได้และมีความละเอียดต่ำและโค้ด D3.js จำนวนมาก ดังนั้นถึงแม้จะทรงพลัง แต่ก็อาจต้องใช้เวลาเรียนรู้บ้าง ลองดูตัวอย่าง

D3FC
(ที่มาของภาพ: D3FC)

บริทเคะชาต

Britecharts — ห้องสมุดที่สร้างโดย Eventbrite ซึ่งฉันเป็นผู้สนับสนุนหลัก — ใช้ประโยชน์จาก Reusable Chart API ซึ่งเป็นรูปแบบการห่อหุ้มที่ Mike Bostock นิยมในโพสต์ของเขา “Towards Reusable Charts” และใช้ในห้องสมุดอื่นๆ เช่น NVD3 Britecharts สร้างสิ่งที่เป็นนามธรรมระดับสูง ทำให้ง่ายต่อการสร้างแผนภูมิ ในขณะที่ยังคงความซับซ้อนต่ำไว้ภายใน ทำให้นักพัฒนา D3 ปรับแต่ง Britecharts สำหรับการใช้งานของพวกเขา เราใช้เวลามากมายในการสร้าง UI ที่สวยงามและการสาธิตที่เข้าถึงได้มากมาย

บริทเคะชาต
(ที่มาของภาพ: Britecharts)

การสรุปไลบรารีโดย API ของพวกเขา เราสามารถแสดงได้ดังนี้:

การเขียนโปรแกรมเชิงวัตถุ

ปฏิกิริยาและ DOM

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

มันทำงานอย่างไร?

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

องค์ประกอบลูกแบบไดนามิก

เมื่อแสดงส่วนประกอบที่มีรายการของไอเท็ม นักพัฒนาจำเป็นต้องใช้คุณสมบัติ "คีย์" เฉพาะที่แนบกับคอมโพเนนต์ย่อย ค่านี้ช่วยให้อัลกอริธึม diff ทราบว่ารายการจำเป็นต้องแสดงผลใหม่หรือไม่เมื่อมีการส่งข้อมูลใหม่ หรือสถานะตามที่เรียกในโลก React ไปยังส่วนประกอบ อัลกอริธึมการกระทบยอดจะตรวจสอบค่าของคีย์เพื่อดูว่าจำเป็นต้องเพิ่มหรือนำรายการออกหรือไม่ สิ่งนี้รู้สึกคุ้นเคยหลังจากเรียนรู้เกี่ยวกับการรวมข้อมูลของ D3.js หรือไม่

ตั้งแต่เวอร์ชัน 0.14 React ยังเก็บตัวแสดงภาพไว้ในโมดูลแยกต่างหาก ด้วยวิธีนี้ เราสามารถใช้ส่วนประกอบเดียวกันเพื่อแสดงผลในสื่อต่างๆ เช่น แอปพลิเคชันแบบเนทีฟ (React Native) ความเป็นจริงเสมือน (React VR) และ DOM (react-dom) ความยืดหยุ่นนี้คล้ายกับวิธีแสดงโค้ด D3.js ในบริบทต่างๆ เช่น SVG และ canvas

ตอบสนองและ D3.js

ทั้ง React และ D3 มีเป้าหมายร่วมกันในการช่วยให้เราจัดการกับ DOM และความซับซ้อนของมันด้วยวิธีที่เหมาะสมที่สุด พวกเขายังแบ่งปันการตั้งค่าสำหรับฟังก์ชั่นล้วนๆ — โค้ดที่ส่งคืนเอาต์พุตเดียวกันเสมอโดยไม่มีผลข้างเคียง — และส่วนประกอบไร้สัญชาติสำหรับอินพุตที่กำหนด

อย่างไรก็ตาม ความกังวลร่วมกันเกี่ยวกับ DOM ทำให้ไลบรารีที่มีความคิดเห็นทั้งสองนี้ขัดแย้งกันเมื่อพิจารณาว่ารายการใดจะแสดงผลและทำให้องค์ประกอบอินเทอร์เฟซผู้ใช้เคลื่อนไหว เราจะเห็นวิธีการต่างๆ ในการแก้ปัญหาข้อพิพาทนี้ และไม่มีคำตอบที่ง่าย อย่างไรก็ตาม เราสามารถสร้างกฎที่เข้มงวดได้: พวกเขาไม่ควรแบ่งปันการควบคุม DOM นั่นจะเป็นสูตรสำหรับภัยพิบัติ

แนวทาง

เมื่อรวม React กับ D3.js เราสามารถทำได้ในระดับต่างๆ โดยอาศัยฝั่ง D3.js หรือด้าน React มากขึ้น มาดูสี่ตัวเลือกหลักของเรากัน

D3.js ภายใน React

วิธีแรกที่เราสามารถปฏิบัติตามได้คือการให้โค้ด D3 ของเราควบคุม DOM ได้มากที่สุด ใช้องค์ประกอบ React เพื่อแสดงองค์ประกอบ SVG ว่างที่ทำงานเป็นองค์ประกอบรากของการแสดงข้อมูลของเรา จากนั้นใช้เมธอดวงจรชีวิต componentDidUpdate เพื่อสร้างแผนภูมิโดยใช้รหัส D3.js ที่เราจะใช้ในสถานการณ์ JavaScript วานิลลาโดยใช้องค์ประกอบรูทนั้น นอกจากนี้เรายังสามารถบล็อกการอัปเดตส่วนประกอบเพิ่มเติมโดยทำให้วิธีการ shouldComponentUpdate ส่งคืน false เสมอ

 class Line extends React.Component { static propTypes = {...} componentDidMount() { // D3 Code to create the chart // using this._rootNode as container } shouldComponentUpdate() { // Prevents component re-rendering return false; } _setRef(componentNode) { this._rootNode = componentNode; } render() { <div className="line-container" ref={this._setRef.bind(this)} /> } }

การประเมินแนวทางนี้ เราตระหนักดีว่าแนวทางนี้มีประโยชน์และข้อเสียบางประการ ในบรรดาประโยชน์ที่ได้รับ นี่เป็นวิธีแก้ปัญหาง่ายๆ ที่ทำงานได้ดีเกือบตลอดเวลา นอกจากนี้ยังเป็นวิธีแก้ปัญหาที่เป็นธรรมชาติที่สุดเมื่อคุณพอร์ตโค้ดที่มีอยู่ไปยัง React หรือเมื่อคุณใช้แผนภูมิ D3.js ที่ทำงานอยู่ที่อื่นอยู่แล้ว

ด้านลบ การผสมทั้งโค้ด React และโค้ด D3.js ภายในคอมโพเนนต์ React อาจถูกมองว่าเป็นการดูแย่ ผสมผสานการพึ่งพามากเกินไป และทำให้ไฟล์นั้นยาวเกินไปที่จะถือว่าเป็นโค้ดที่มีคุณภาพ นอกจากนี้ การใช้งานนี้ไม่ได้รู้สึกว่า React-idiomatic เลย สุดท้ายนี้ เนื่องจากเซิร์ฟเวอร์แสดงผล React ไม่ได้เรียกใช้เมธอด componentDidUpdate เราจึงไม่สามารถจัดส่งเวอร์ชันที่แสดงผลของแผนภูมิใน HTML เริ่มต้นได้

ตอบโต้ Faux DOM

ดำเนินการโดย Oliver Caldwell React Faux DOM "เป็นวิธีใช้เครื่องมือ D3 ที่มีอยู่ แต่แสดงผลผ่าน React ใน React ethos" ใช้ DOM ปลอมเพื่อหลอก D3.js ให้คิดว่ากำลังจัดการกับ DOM จริง ด้วยวิธีนี้ เราคงรักษา React DOM tree ในขณะที่ใช้ D3.js อยู่ใน — เกือบ — ทุกศักยภาพของมัน

 import {withFauxDOM} from 'react-faux-dom' class Line extends React.Component { static propTypes = {...} componentDidMount() { const faux = this.props.connectFauxDOM('div', 'chart'); // D3 Code to create the chart // using faux as container d3.select(faux) .append('svg') {...} } render() { <div className="line-container"> {this.props.chart} </div> } } export default withFauxDOM(Line);

ข้อดีของวิธีนี้คือช่วยให้คุณใช้ API ของ D3.js ได้เกือบทั้งหมด ทำให้ง่ายต่อการผสานรวมกับโค้ด D3.js ที่สร้างไว้แล้ว นอกจากนี้ยังช่วยให้สามารถแสดงผลฝั่งเซิร์ฟเวอร์ได้ ข้อบกพร่องของกลยุทธ์นี้คือประสิทธิภาพน้อยกว่า เนื่องจากเรากำลังวางการใช้งาน DOM ปลอมอีกครั้งก่อน DOM เสมือนของ React ทำให้ DOM จำลองเสมือนสองครั้ง ปัญหานี้จำกัดการใช้งานในการแสดงภาพข้อมูลขนาดเล็กและขนาดกลาง

การห่อวิธีวงจรชีวิต

วิธีการนี้ ซึ่งระบุไว้ครั้งแรกโดย Nicolas Hery ใช้ประโยชน์จากวิธีวงจรชีวิตที่มีอยู่ในส่วนประกอบ React แบบคลาส มันห่อหุ้มการสร้าง อัปเดต และลบแผนภูมิ D3.js อย่างหรูหรา สร้างขอบเขตที่ชัดเจนระหว่างโค้ด React และ D3.js

 import D3Line from './D3Line' class Line extends React.Component { static propTypes = {...} componentDidMount() { // D3 Code to create the chart this._chart = D3Line.create( this._rootNode, this.props.data, this.props.config ); } componentDidUpdate() { // D3 Code to update the chart D3Line.update( this._rootNode, this.props.data, this.props.config, this._chart ); } componentWillUnmount() { D3Line.destroy(this._rootNode); } _setRef(componentNode) { this._rootNode = componentNode; } render() { <div className="line-container" ref={this._setRef.bind(this)} /> } }

D3Line มีลักษณะดังนี้:

 const D3Line = {}; D3Line.create = (el, data, configuration) => { // D3 Code to create the chart }; D3Line.update = (el, data, configuration, chart) => { // D3 Code to update the chart }; D3Line.destroy = () => { // Cleaning code here }; export default D3Line;

การเข้ารหัสด้วยวิธีนี้จะสร้างส่วนประกอบ React ที่มีน้ำหนักเบาซึ่งสื่อสารกับอินสแตนซ์แผนภูมิแบบ D3.js ผ่าน API แบบง่าย (สร้าง อัปเดต และลบ) ผลักวิธีการโทรกลับที่เราต้องการฟังลง

กลยุทธ์นี้ส่งเสริมการแยกข้อกังวลอย่างชัดเจน โดยใช้ซุ้มเพื่อซ่อนรายละเอียดการใช้งานของแผนภูมิ มันสามารถสรุปกราฟใดๆ และอินเทอร์เฟซที่สร้างขึ้นนั้นเรียบง่าย ข้อดีอีกประการหนึ่งคือง่ายต่อการรวมเข้ากับโค้ด D3.js ใดๆ ที่เขียนไว้แล้ว และช่วยให้เราใช้ทรานสิชันที่ยอดเยี่ยมของ D3.js ข้อเสียเปรียบหลักของวิธีนี้คือไม่สามารถแสดงผลฝั่งเซิร์ฟเวอร์ได้

ตอบสนองสำหรับ DOM, D3 สำหรับคณิตศาสตร์

ในกลยุทธ์นี้ เราจำกัดการใช้ D3.js ให้น้อยที่สุด นี่หมายถึงการคำนวณสำหรับเส้นทาง SVG มาตราส่วน เลย์เอาต์ และการแปลงใดๆ ที่นำข้อมูลผู้ใช้ไปแปลงเป็นสิ่งที่เราสามารถวาดด้วย React

การใช้ D3.js สำหรับคณิตศาสตร์เพียงอย่างเดียวเป็นไปได้ด้วยโมดูลย่อย D3.js จำนวนมากที่ไม่เกี่ยวข้องกับ DOM เส้นทางนี้เป็นมิตรกับ React มากที่สุด ทำให้ห้องสมุด Facebook มีอำนาจเหนือ DOM ซึ่งเป็นสิ่งที่ทำได้ดีอย่างน่าทึ่ง

มาดูตัวอย่างง่าย ๆ กัน:

 class Line extends React.Component { static propTypes = {...} drawLine() { let xScale = d3.scaleTime() .domain(d3.extent(this.props.data, ({date}) => date)); .rangeRound([0, this.props.width]); let yScale = d3.scaleLinear() .domain(d3.extent(this.props.data, ({value}) => value)) .rangeRound([this.props.height, 0]); let line = d3.line() .x((d) => xScale(d.date)) .y((d) => yScale(d.value)); return ( <path className="line" d={line(this.props.data)} /> ); } render() { <svg className="line-container" width={this.props.width} height={this.props.height} > {this.drawLine()} </svg> } }

เทคนิคนี้เป็นที่ชื่นชอบของนักพัฒนา React ที่ช่ำชอง เพราะมันสอดคล้องกับวิธี React นอกจากนี้ เมื่อติดตั้งแล้ว การสร้างแผนภูมิด้วยโค้ดก็ให้ความรู้สึกที่ดี ประโยชน์อีกประการหนึ่งคือการแสดงผลบนฝั่งเซิร์ฟเวอร์และอาจ React Native หรือ React VR

ในทางตรงกันข้าม นี่คือแนวทางที่ต้องใช้ความรู้เพิ่มเติมเกี่ยวกับวิธีการทำงานของ D3.js เนื่องจากเราจำเป็นต้องรวมเข้ากับโมดูลย่อยของมันในระดับต่ำ เราต้องนำฟังก์ชันบางอย่างของ D3.js กลับมาใช้ใหม่ — แกนและรูปร่างที่ใช้กันทั่วไป การแปรง การซูม และการลากอาจเป็นสิ่งที่ยากที่สุด — และนี่หมายถึงการทำงานล่วงหน้าจำนวนมาก

เราจะต้องปรับใช้แอนิเมชั่นทั้งหมดด้วย เรามีเครื่องมือที่ยอดเยี่ยมในระบบนิเวศของ React ที่ช่วยให้เราสามารถจัดการแอนิเมชั่น — ดู react-transition-group, react-motion และ react-move แม้ว่าจะไม่มีใครทำให้เราสร้างการประมาณค่าที่ซับซ้อนของเส้นทาง SVG ได้ คำถามหนึ่งที่รอดำเนินการคือวิธีการใช้ประโยชน์จากวิธีการนี้ในการแสดงผลแผนภูมิโดยใช้องค์ประกอบผ้าใบของ HTML5

ในไดอะแกรมต่อไปนี้ เราสามารถเห็นแนวทางที่อธิบายไว้ทั้งหมดตามระดับการผสานกับทั้ง React และ D3.js:

React และระดับการรวม D3.js

React-D3.js Libraries

ฉันได้ค้นคว้าเกี่ยวกับไลบรารี D3.js-React ซึ่งหวังว่าจะช่วยคุณได้เมื่อคุณต้องเผชิญกับการตัดสินใจเลือกห้องสมุดที่จะทำงานด้วย มีส่วนร่วม หรือแยกจากกัน มันมีตัวชี้วัดเชิงอัตวิสัยดังนั้นโปรดใช้เม็ดเกลือ

การวิจัยครั้งนี้เปิดเผยว่าถึงแม้จะมีห้องสมุดจำนวนมาก แต่ก็ยังมีเพียงไม่กี่แห่งที่ได้รับการบำรุงรักษา ในฐานะผู้ดูแล ฉันสามารถเข้าใจได้ว่ามันยากแค่ไหนที่จะตามให้ทันการเปลี่ยนแปลงในห้องสมุดหลักแห่งเดียว และการที่ต้องดูแลสองห้องสมุดนั้นจะเป็นงานที่น่ากลัว

นอกจากนี้ จำนวนไลบรารีที่พร้อมใช้งานจริง (ตั้งแต่เวอร์ชัน 1.0.0 ขึ้นไป) ยังค่อนข้างต่ำ อาจเกี่ยวข้องกับปริมาณงานที่จำเป็นในการจัดส่งไลบรารีประเภทนี้

มาดูของโปรดกันบ้างครับ

ชัยชนะ

โครงการโดยบริษัทที่ปรึกษา Formidable Labs Victory เป็นไลบรารีองค์ประกอบระดับต่ำขององค์ประกอบแผนภูมิ เนื่องจากคุณลักษณะระดับต่ำนั้น ส่วนประกอบ Victory สามารถรวมเข้ากับการกำหนดค่าต่างๆ เพื่อสร้างการแสดงข้อมูลที่ซับซ้อน ภายใต้ประทุน มันนำคุณลักษณะ D3.js มาใช้ใหม่ เช่น แปรงและการซูม แม้ว่าจะใช้ d3-interpolate สำหรับแอนิเมชันก็ตาม

ชัยชนะ
(ที่มาของภาพ: ชัยชนะ)

การใช้สำหรับแผนภูมิเส้นจะมีลักษณะดังนี้:

 class LineChart extends React.Component { render() { return ( <VictoryChart height={400} width={400} containerComponent={<VictoryVoronoiContainer/>} > <VictoryGroup labels={(d) => `y: ${dy}`} labelComponent={ <VictoryTooltip style={{ fontSize: 10 }} /> } data={data} > <VictoryLine/> <VictoryScatter size={(d, a) => {return a ? 8 : 3;}} /> </VictoryGroup> </VictoryChart> ); } }

ที่สร้างแผนภูมิเส้นดังนี้:

แผนภูมิเส้น

การเริ่มต้นใช้งาน Victory เป็นเรื่องง่าย และมีโบนัสที่ดี เช่น การซูมและคอนเทนเนอร์ Voronoi สำหรับคำแนะนำเครื่องมือ เป็นห้องสมุดที่ทันสมัยแม้ว่าจะยังอยู่ในสถานะก่อนเผยแพร่และมีข้อบกพร่องจำนวนมากที่รอดำเนินการ Victory เป็นห้องสมุดเดียวที่คุณสามารถใช้กับ React Native ได้ในขณะนี้

รีชาร์ต

ด้วยประสบการณ์การใช้งานที่สนุกสนาน ภาพเคลื่อนไหวที่ราบรื่น และคำแนะนำเครื่องมือที่ดูดี Recharts เป็นหนึ่งในไลบรารี React-D3.js ที่ฉันโปรดปราน Rechart ใช้เฉพาะขนาด d3, d3-interpolate และ d3-shape มันมีระดับความละเอียดที่สูงกว่า Victory ซึ่งจำกัดจำนวนการแสดงข้อมูลเป็นภาพที่เราสามารถทำได้

รีชาร์ต
(ที่มาของภาพ: Recharts)

การใช้ Recharts มีลักษณะดังนี้:

 class LineChart extends React.Component { render () { return ( <LineChart width={600} height={300} data={data} margin={{top: 5, right: 30, left: 20, bottom: 5}} > <XAxis dataKey="name"/> <YAxis/> <CartesianGrid strokeDasharray="3 3"/> <Tooltip/> <Legend /> <Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{r: 8}}/> <Line type="monotone" dataKey="uv" stroke="#82ca9d" /> </LineChart> ); } } 
รีชาร์ต

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

Nivo

Nivo เป็นไลบรารีสร้างแผนภูมิ React-D3.js ระดับสูง มีตัวเลือกมากมายสำหรับการเรนเดอร์: SVG, canvas, แม้แต่แผนภูมิเวอร์ชัน HTML ที่ใช้ API ซึ่งเหมาะสำหรับการเรนเดอร์ฝั่งเซิร์ฟเวอร์ ใช้ React Motion สำหรับแอนิเมชั่น

Nivo
(ที่มาของภาพ: Nivo)

API ของมันแตกต่างกันเล็กน้อย เพราะมันแสดงให้เห็นเพียงองค์ประกอบเดียวที่กำหนดค่าได้สำหรับแต่ละแผนภูมิ มาดูตัวอย่างกัน:

 class LineChart extends React.Component { render () { return ( <ResponsiveLine data={data} margin={{ "top": 50, "right": 110, "bottom": 50, "left": 60 }} minY="auto" stacked={true} axisBottom={{ "orient": "bottom", "tickSize": 5, "tickPadding": 5, "tickRotation": 0, "legend": "country code", "legendOffset": 36, "legendPosition": "center" }} axisLeft={{ "orient": "left", "tickSize": 5, "tickPadding": 5, "tickRotation": 0, "legend": "count", "legendOffset": -40, "legendPosition": "center" }} dotSize={10} dotColor="inherit:darker(0.3)" dotBorderWidth={2} dotBorderColor="#ffffff" enableDotLabel={true} dotLabel="y" dotLabelYOffset={-12} animate={true} motionStiffness={90} motionDamping={15} legends={[ { "anchor": "bottom-right", "direction": "column", "translateX": 100, "itemWidth": 80, "itemHeight": 20, "symbolSize": 12, "symbolShape": "circle" } ]} /> ); } } 
แผนภูมิ Nivo

Raphael Benitte ทำผลงานได้อย่างน่าประหลาดใจกับ Nivo เอกสารประกอบมีความน่ารักและสามารถกำหนดค่าการสาธิตได้ เนื่องจากไลบรารีนี้มีระดับนามธรรมที่สูงขึ้น มันจึงใช้งานง่ายมาก และเราสามารถพูดได้ว่ามีศักยภาพน้อยกว่าสำหรับการสร้างการแสดงภาพ คุณลักษณะที่ดีของ Nivo คือความเป็นไปได้ในการใช้รูปแบบ SVG และการไล่ระดับสีเพื่อเติมลงในแผนภูมิของคุณ

VX

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

VX
(ที่มาของภาพ: VX)

มาดูรหัสกัน:

 class VXLineChart extends React.Component { render () { let {width, height, margin} = this.props; // bounds const xMax = width - margin.left - margin.right; const yMax = height - margin.top - margin.bottom; // scales const xScale = scaleTime({ range: [0, xMax], domain: extent(data, x), }); const yScale = scaleLinear({ range: [yMax, 0], domain: [0, max(data, y)], nice: true, }); return ( <svg width={width} height={height} > <rect x={0} y={0} width={width} height={height} fill="white" rx={14} /> <Group top={margin.top}> <LinePath data={data} xScale={xScale} yScale={yScale} x={x} y={y} stroke='#32deaa' strokeWidth={2} /> </Group> </svg> ); } }; 
กราฟ

ด้วยความละเอียดระดับต่ำนี้ ฉันคิดว่า VX เป็น D3.js สำหรับโลก React มันไม่เชื่อเรื่องพระเจ้าเกี่ยวกับไลบรารีแอนิเมชั่นที่ผู้ใช้ต้องการใช้ ตอนนี้ยังอยู่ในช่วงเบต้าแม้ว่าจะถูกใช้ในการผลิตโดย Airbnb ข้อบกพร่องในขณะนี้คือการขาดการสนับสนุนสำหรับการโต้ตอบเช่นการแปรงและการซูม

ปฏิกริยาของบริเตรท

Britecharts React ยังอยู่ในช่วงเบต้า และเป็นเพียงหนึ่งในไลบรารี่เหล่านี้ที่ใช้วิธีการห่อวิธีการวงจรชีวิต มีจุดมุ่งหมายเพื่อให้สามารถใช้การสร้างภาพข้อมูลของ Britecharts ใน React โดยการสร้างตัวตัดโค้ดที่ใช้งานง่าย

ปฏิกริยาของบริเตรท
(ที่มาของภาพ: Britecharts React)

นี่คือรหัสอย่างง่ายสำหรับแผนภูมิเส้น:

 class LineChart extends React.Component { render () { const margin = { top: 60, right: 30, bottom: 60, left: 70, }; return ( <TooltipComponent data={lineData.oneSet()} topicLabel="topics" title="Tooltip Title" render={(props) => ( <LineComponent margin={margin} lineCurve="basis" {...props} /> )} /> ); } } 
แผนภูมิเส้น

ฉันไม่สามารถมีวัตถุประสงค์เกี่ยวกับเรื่องนี้ Britecharts React สามารถใช้เป็นโครงนั่งร้านเพื่อแสดงแผนภูมิ D3.js ของคุณเป็นส่วนประกอบ React ไม่รองรับการแสดงผลฝั่งเซิร์ฟเวอร์ แม้ว่าเราจะรวมสถานะการโหลดเพื่อแก้ปัญหานี้ด้วยวิธีการบางอย่าง

อย่าลังเลที่จะตรวจสอบการสาธิตออนไลน์และเล่นกับรหัส

การเลือกแนวทางหรือห้องสมุด

ฉันได้จัดกลุ่มข้อควรพิจารณาในการสร้างแอปพลิเคชันด้วยแผนภูมิเป็นสี่ประเภท ได้แก่ คุณภาพ เวลา ขอบเขต และต้นทุน พวกมันมากเกินไป เราจึงควรลดความซับซ้อน

สมมติว่าเราแก้ไข คุณภาพ เราสามารถตั้งเป้าที่จะมีฐานโค้ดที่ได้รับการทดสอบอย่างดี อัปเดตด้วย D3.js เวอร์ชัน 4 และเอกสารประกอบที่ครอบคลุม

หากเรานึกถึง เวลา คำถามที่มีประโยชน์สำหรับถามตัวเองคือ “นี่คือการลงทุนระยะยาวใช่หรือไม่” หากคำตอบคือ "ใช่" ฉันจะแนะนำให้คุณสร้างไลบรารีตาม D3.js และรวมไว้ด้วย React โดยใช้วิธีการวงจรชีวิต วิธีการนี้แยกรหัสของเราออกจากเทคโนโลยีและมีเวลามากขึ้น

ในทางตรงกันข้าม หากโครงการมีกำหนดเวลาที่คับแคบและทีมงานไม่ต้องบำรุงรักษาเป็นเวลานาน ผมขอแนะนำให้หยิบไลบรารี React-D3.js หรือ D3.js ที่ใกล้เคียงที่สุดกับข้อกำหนด แยกส่วนและใช้งาน พยายามที่จะมีส่วนร่วมไปพร้อมกัน

เมื่อเราจัดการกับ scope เราควรคิดว่าสิ่งที่เราต้องการคือแผนภูมิพื้นฐานจำนวนน้อย การแสดงภาพที่ซับซ้อนในครั้งเดียว หรือกราฟิกที่มีการปรับแต่งสูงหลายๆ แบบ ในกรณีแรก ฉันจะเลือกไลบรารีที่ใกล้เคียงที่สุดกับข้อกำหนดอีกครั้งและแยกมันออก สำหรับการสร้างภาพข้อมูลตามความต้องการซึ่งมีภาพเคลื่อนไหวหรือการโต้ตอบจำนวนมาก การสร้างด้วย D3.js ปกติคือตัวเลือกที่ดีที่สุด สุดท้ายนี้ หากคุณวางแผนที่จะใช้แผนภูมิที่แตกต่างกันโดยมีข้อกำหนดเฉพาะ — อาจได้รับการสนับสนุนจาก UX'ers ​​และนักออกแบบ — การสร้างไลบรารี D3 ของคุณตั้งแต่เริ่มต้นหรือแยกส่วนและปรับแต่งไลบรารีที่มีอยู่แล้วจะทำงานได้ดีที่สุด

สุดท้าย ด้าน ต้นทุน ของการตัดสินใจเกี่ยวข้องกับงบประมาณและการฝึกอบรมของทีม ทีมของคุณมีทักษะอะไรบ้าง? หากคุณมีนักพัฒนา D3.js พวกเขาต้องการแยกความแตกต่างระหว่าง D3.js และ React อย่างชัดเจน ดังนั้นแนวทางที่ใช้การห่อวิธีการวงจรชีวิตอาจใช้ได้ผลดี อย่างไรก็ตาม หากทีมของคุณส่วนใหญ่เป็นนักพัฒนา React พวกเขาจะสนุกกับการขยายไลบรารี React-D3.js ปัจจุบัน นอกจากนี้ การใช้วิธีวงจรชีวิตร่วมกับตัวอย่าง D3.js ก็สามารถทำงานได้เช่นกัน สิ่งที่ฉันไม่ค่อยแนะนำคือการเปิดไลบรารี React-D3.js ของคุณเอง ปริมาณงานที่จำเป็นล่วงหน้านั้นน่ากังวล และขั้นตอนในการอัปเดตของห้องสมุดทั้งสองทำให้ค่าใช้จ่ายในการบำรุงรักษาไม่สำคัญ

สรุป

React และ D3.js เป็นเครื่องมือที่ยอดเยี่ยมในการช่วยเราจัดการกับ DOM และความท้าทายต่างๆ พวกเขาสามารถทำงานร่วมกันได้อย่างแน่นอน และเรามีอำนาจในการเลือกว่าจะลากเส้นแบ่งระหว่างพวกเขาที่ไหน ระบบนิเวศที่ดีของห้องสมุดมีอยู่เพื่อช่วยให้เราใช้ D3.js มีตัวเลือกที่น่าตื่นเต้นมากมายสำหรับ React-D3.js เช่นกัน และไลบรารีทั้งสองมีวิวัฒนาการอย่างต่อเนื่อง ดังนั้นโปรเจ็กต์ที่รวมทั้งสองอย่างเข้าด้วยกันจะมีช่วงเวลาที่ยากลำบากในการติดตาม

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

ด้วยรากฐานนี้ ฉันแนะนำให้คุณอยากรู้อยากเห็น ตรวจสอบห้องสมุดที่กล่าวถึง และเพิ่มแผนภูมิที่ดีให้กับโครงการของคุณ

คุณเคยใช้โครงการเหล่านี้หรือไม่? ถ้าคุณมี ประสบการณ์ของคุณคืออะไร? แบ่งปันคำบางคำกับเราในความคิดเห็น