สู่แผนภูมิ D3.js ที่อัปเดตได้

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

บทนำ

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

รูปแบบแผนภูมิที่อัปเดตได้ช่วยให้สร้างแผนภูมิ D3.js ได้ง่าย
ทวีต

มาเริ่มกันด้วยตัวอย่างง่ายๆ สมมติว่าคุณกำลังฝึกซ้อมสำหรับการแข่งขันระยะทาง 5 กม. และคุณต้องการสร้างแผนภูมิแท่งแนวนอนของจำนวนไมล์ที่คุณวิ่งในแต่ละวันของสัปดาห์ที่แล้ว:

 var milesRun = [2, 5, 4, 1, 2, 6, 5]; d3.select('body').append('svg') .attr('height', 300) .attr('width', 800) .selectAll('rect') .data(milesRun) .enter() .append('rect') .attr('y', function (d, i) { return i * 40 }) .attr('height', 35) .attr('x', 0) .attr('width', function (d) { return d*100}) .style('fill', 'steelblue');

หากต้องการดูการใช้งานจริง โปรดดูที่ bl.ocks.org

หากรหัสนี้ดูคุ้นเคยก็เยี่ยมมาก ถ้าไม่ ฉันพบว่าบทช่วยสอนของ Scott Murray เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับการเริ่มต้นใช้งาน D3.js

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

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

ความก้าวหน้าของรูปแบบแผนภูมิ D3.js

ขั้นตอนที่ 1: ตัวแปรการกำหนดค่า

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

 var highTemperatures = [77, 71, 82, 87, 84, 78, 80, 84, 86, 72, 71, 68]; var height = 300; var width = 800; var barPadding = 1; var barSpacing = height / highTemperatures.length; var barHeight = barSpacing - barPadding; var maxValue = d3.max(highTemperatures); var widthScale = width / maxValue; d3.select('body').append('svg') .attr('height', height) .attr('width', width) .selectAll('rect') .data(highTemperatures) .enter() .append('rect') .attr('y', function (d, i) { return i * barSpacing }) .attr('height', barHeight) .attr('x', 0) .attr('width', function (d) { return d*widthScale}) .style('fill', 'steelblue');

หากต้องการดูการใช้งานจริง โปรดดูที่ bl.ocks.org

สังเกตว่าความสูงและความกว้างของแท่งถูกปรับขนาดตามทั้งขนาดและค่าของข้อมูล ตัวแปรหนึ่งมีการเปลี่ยนแปลง และส่วนที่เหลือจะได้รับการดูแล

ขั้นตอนที่ 2: ทำซ้ำง่าย ๆ ผ่านฟังก์ชั่น

การเข้ารหัสไม่ควรเป็นแบบฝึกหัดในการคัดลอกและวาง

การเข้ารหัสไม่ควรเป็นแบบฝึกหัดในการคัดลอกและวาง
ทวีต

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

 var milesRun = [2, 5, 4, 1, 2, 6, 5]; var highTemperatures = [77, 71, 82, 87, 84, 78, 80, 84, 86, 72, 71, 68, 75, 73, 80, 85, 86, 80]; function drawChart(dom, data, options) { var width = options.width || 800; var height = options.height || 200; var barPadding = options.barPadding || 1; var fillColor = options.fillColor || 'steelblue'; var barSpacing = height / data.length; var barHeight = barSpacing - barPadding; var maxValue = d3.max(data); var widthScale = width / maxValue; d3.select(dom).append('svg') .attr('height', height) .attr('width', width) .selectAll('rect') .data(data) .enter() .append('rect') .attr('y', function (d, i) { return i * barSpacing }) .attr('height', barHeight) .attr('x', 0) .attr('width', function (d) { return d*widthScale}) .style('fill', fillColor); } var weatherOptions = {fillColor: 'coral'}; drawChart('#weatherHistory', highTemperatures, weatherOptions); var runningOptions = {barPadding: 2}; drawChart('#runningHistory', milesRun, runningOptions);

หากต้องการดูการใช้งานจริง โปรดดูที่ bl.ocks.org

สิ่งสำคัญคือต้องจดบันทึกเกี่ยวกับการเลือก D3.js ในบริบทนี้ ควรหลีกเลี่ยงการเลือกทั่วไป เช่น d3.selectAll('rect') เสมอ หากมี rect อยู่ที่อื่นบนหน้า แก้ไขทั้งหมดบนหน้าจะกลายเป็นส่วนหนึ่งของการเลือก แทนที่จะใช้การอ้างอิง DOM ที่ส่งผ่าน ให้สร้างวัตถุ svg หนึ่งรายการที่คุณสามารถอ้างอิงได้เมื่อผนวกและอัปเดตองค์ประกอบ เทคนิคนี้ยังสามารถปรับปรุงรันไทม์ของการสร้างแผนภูมิได้อีกด้วย เนื่องจากการใช้ข้อมูลอ้างอิง เช่น แถบช่วยป้องกันไม่ให้ต้องเลือก D3.js อีกครั้ง

ขั้นตอนที่ 3: การผูกมัดและการเลือกวิธีการ

แม้ว่าโครงร่างก่อนหน้าที่ใช้ออบเจ็กต์การกำหนดค่าจะพบได้ทั่วไปในไลบรารี JavaScript Mike Bostock ผู้สร้าง D3.js ขอแนะนำรูปแบบอื่นสำหรับการสร้างแผนภูมิที่ใช้ซ้ำได้ กล่าวโดยย่อ Mike Bostock แนะนำให้ใช้แผนภูมิเป็นการปิดด้วยวิธี getter-setter ในขณะที่เพิ่มความซับซ้อนให้กับการใช้งานแผนภูมิ การตั้งค่าตัวเลือกการกำหนดค่าจะตรงไปตรงมามากสำหรับผู้เรียกโดยใช้วิธีการผูกมัด:

 // Using Mike Bostock's Towards Reusable Charts Pattern function barChart() { // All options that should be accessible to caller var width = 900; var height = 200; var barPadding = 1; var fillColor = 'steelblue'; function chart(selection){ selection.each(function (data) { var barSpacing = height / data.length; var barHeight = barSpacing - barPadding; var maxValue = d3.max(data); var widthScale = width / maxValue; d3.select(this).append('svg') .attr('height', height) .attr('width', width) .selectAll('rect') .data(data) .enter() .append('rect') .attr('y', function (d, i) { return i * barSpacing }) .attr('height', barHeight) .attr('x', 0) .attr('width', function (d) { return d*widthScale}) .style('fill', fillColor); }); } chart.width = function(value) { if (!arguments.length) return margin; width = value; return chart; }; chart.height = function(value) { if (!arguments.length) return height; height = value; return chart; }; chart.barPadding = function(value) { if (!arguments.length) return barPadding; barPadding = value; return chart; }; chart.fillColor = function(value) { if (!arguments.length) return fillColor; fillColor = value; return chart; }; return chart; } var milesRun = [2, 5, 4, 1, 2, 6, 5]; var highTemperatures = [77, 71, 82, 87, 84, 78, 80, 84, 86, 72, 71, 68, 75, 73, 80, 85, 86, 80]; var runningChart = barChart().barPadding(2); d3.select('#runningHistory') .datum(milesRun) .call(runningChart); var weatherChart = barChart().fillColor('coral'); d3.select('#weatherHistory') .datum(highTemperatures) .call(weatherChart);

หากต้องการดูการใช้งานจริง โปรดดูที่ bl.ocks.org

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

ขั้นตอนที่ 4: รูปแบบใหม่สำหรับแผนภูมิที่อัปเดตได้

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

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

ขออภัย มีปัญหาหลายประการในการแก้ปัญหานี้

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

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

 width = newWidth; widthScale = width / maxValue; bars.attr('width', function(d) { return d*widthScale}); svg.attr('width', width);

แต่มันจะดียิ่งขึ้นไปอีก เนื่องจากตอนนี้เรามีประวัติของแผนภูมิแล้ว เราจึงสามารถใช้ทรานซิชันในตัวของ D3 เพื่ออัปเดตแผนภูมิของเราและทำให้เคลื่อนไหวได้อย่างง่ายดาย ต่อจากตัวอย่างด้านบน การเพิ่มทรานสิชั่นบน width นั้นง่ายเหมือนการเปลี่ยน

 bars.attr('width', function(d) { return d*widthScale});

ถึง

 bars.transition().duration(1000).attr('width', function(d) { return d*widthScale});

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

 d3.select('#weatherHistory') .datum(highTemperatures) .call(weatherChart);

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

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

 weatherChart.width(420);

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

ไม่มีการคำนวณที่ไม่จำเป็น + การเปลี่ยนแปลงที่ทันสมัย ​​= ลูกค้ามีความสุข

ไม่มีการคำนวณที่ไม่จำเป็น + การเปลี่ยนแปลงที่ทันสมัย ​​= ลูกค้ามีความสุข
ทวีต

ฟังก์ชันพิเศษนี้มาพร้อมกับความพยายามของนักพัฒนาที่เพิ่มขึ้นเล็กน้อย อย่างไรก็ตาม ความพยายามที่ฉันพบว่าคุ้มค่ากับเวลาในอดีต นี่คือโครงร่างของแผนภูมิที่สามารถอัปเดตได้:

 function barChart() { // All options that should be accessible to caller var data = []; var width = 800; //... the rest var updateData; var updateWidth; //... the rest function chart(selection){ selection.each(function () { // //draw the chart here using data, width // updateWidth = function() { // use width to make any changes }; updateData = function() { // use D3 update pattern with data } }); } chart.data = function(value) { if (!arguments.length) return data; data = value; if (typeof updateData === 'function') updateData(); return chart; }; chart.width = function(value) { if (!arguments.length) return width; width = value; if (typeof updateWidth === 'function') updateWidth(); return chart; }; //... the rest return chart; }

หากต้องการดูการใช้งานทั้งหมด โปรดดูที่ bl.ocks.org

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

 chart.width = function(value) { if (!arguments.length) return width; width = value; if (typeof updateWidth === 'function') updateWidth(); return chart; };

โปรดทราบว่าจะไม่กำหนด updateWidth จนกว่าจะมีการเริ่มต้นแผนภูมิ หาก undefined ตัวแปรการกำหนดค่าจะถูกตั้งค่าและใช้ในการปิดแผนภูมิทั่วโลก หากมีการเรียกฟังก์ชันแผนภูมิ การเปลี่ยนภาพทั้งหมดจะถูกส่งไปยังฟังก์ชัน updateWidth ซึ่งใช้ตัวแปร width ที่เปลี่ยนแปลงเพื่อทำการเปลี่ยนแปลงที่จำเป็น บางอย่างเช่นนี้:

 updateWidth = function() { widthScale = width / maxValue; bars.transition().duration(1000).attr('width', function(d) { return d*widthScale}); svg.transition().duration(1000).attr('width', width); };

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

 var weatherChart = barChart(); d3.select('#weatherHistory') .datum(highTemperatures) .call(weatherChart);

ซึ่งจะกลายเป็น:

 var weatherChart = barChart().data(highTemperatures); d3.select('#weatherHistory') .call(weatherChart);

ดังนั้นเราจึงได้ทำการเปลี่ยนแปลงและเพิ่มความพยายามของนักพัฒนา มาดูประโยชน์กันดีกว่า

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

 weatherChart.data(lowTemperatures).fillColor('blue');

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

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

การเปลี่ยนแปลงในปรัชญา

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