D3: פרק ראשון ובו יסופר על עץ

זהו פוסט ראשון בסדרה על ספרית הויזואליזציה d3.js

הפוסט מניח היכרות סבירה עם פיתוח ווב ועם SVG ו DOM.

D3, קיצור של Data Driven Document, היא ספריית javascript המאפשרת, בעזרת ממשקיה הרבים, קבלת מידע, שינויו וקישורו ל DOM.

אפשר להוריד את הספריה ישירות מהאתר: https://d3js.org או בעזרת מנהל הספריות npm ב https://www.npmjs.com/package/d3. לאחר ההורדה יש להכליל את הספריה בדף ה HTML.

לצומת ליבכם, הקוראים:

בפוסט מעורבבות מילים בעברית ומילים שאינן, ככה זה!

מטרת הפוסט הזה ואלה שיבואו אחריו היא להנגיש את D3 לקוראים. לצורך זה פישטנו חלק מההסברים.

מתחילים…


בואו נדבר על עץ…

אבל לפני כן בואו נדבר על צורות בסיסיות יותר… קטע הקוד הבא יוצר עיגול:

var svg = d3.select("#tree-container").append("svg")
        .attr("width", 400)
        .attr("height", 50);

svg.append("circle")
        .attr("cx", 30)
        .attr("cy", 30)
        .attr("r", 10);

השיטה append

השיטה append מאפשרת לנו לצרף אלמנט חדש כצאצא אחרון עבור כל אלמנט בבחירה הנוכחית שלנו. מיד נסביר מהי “בחירה” אבל לרגע בואו נניח שיש לנו אוסף אלמנטים מה DOM, הפקודה append תצרף לכל אחד מהם אלמנט חדש ששמו הוא הארגומנט היחיד של השיטה.

בדוגמא שלנו, השורה svg.append(“circle”) מצרפת למשתנה svg, אלמנט circle חדש.

בחירת אלמנטים ב DOM

select ו selectAll הן שתי שיטות המאפשרות בחירת אלמנטים ב DOM ע”פ קריטריון (הארגומנט של השיטה). הערך המוחזר מהשיטות יהיה תמיד מערך של קבוצות אלמנטים: עבור השיטה select הבחירה תהיה אלמנט תואם יחיד ועבור selectAll, כל האלמנטים התואמים.

הערך המוחזר בקריאות ל d3.select ו d3.selectAll יהיה תמיד מערך בגודל אחד. כאשר משרשרים קריאות לשיטות אלה, מתווספות קבוצות לבחירה.

דוגמא: הקריאה d3.select(“#tree-container”) תחזיר מערך בגודל 1 המכיל קבוצה בגודל אחד ובתוכה האלמנט הראשון ב DOM שה ID שלו הוא “tree-container”.


מה עם העץ? עוד מעט…

מה אם נרצה לצייר כמה עיגולים? לולאת for יכולה לעזור? כן, אבל אנו רוצים לרתום את מלוא הכח של d3 שנכתבה בגישה דקלרטיבית, ולכן נכתוב זאת אחרת:

var startX = 30, startY = 30, radius = 10;

var svg = d3.select("#tree-container").append("svg")
        .attr("width", 400)
        .attr("height", 50);

//איכלוס מערך נתוני עיגולים
var i, data = [];
for (i = 0; i < 10; i++)
    data.push({v: i, x: startX + i * radius * 3, y: startY});

svg.selectAll("circle")
        .data(data, function (d){return d.v;})
        .enter().append("circle")
        .attr("cx", function (d) {return d.x;})
        .attr("cy", function (d) {return d.y;})
        .attr("r", radius)
        .attr("fill", "blue");

זו הדרך לומר ל d3 מה אנו רוצים (דקלרטיבי) ולא כיצד לבצע זאת (אימפרטיבי): אנו רוצים 10 עיגולים שמיקומם תואם לנתוני המערך שאיכלסנו.

רגע, אז למה להשתמש ב selectAll כאשר אנו יודעים שאין שום אלמנטים מסוג circle ב DOM שלנו? כך d3 יכול לבצע data-join, שעוזר לנו כאשר הנתונים שלנו דינמיים ועושה זאת באופן אלגנטי. data-join משלב את הנתונים של הבחירה ומחלק אותם ל 3:

  • update: המשותף בין הנתונים הקיימים והחדשים
  • enter: נתונים חדשים שאינם קיימים
  • exit: נתונים קיימים שאינם מופיעים בנתונים החדשים

d3-data-joinמתוך המדריך של מייק בוסטוק, היוצר של d3

בדוגמא הבאה, לחיצה על הכפתור תייצר 10 עיגולים (כמו מקודם), תוסיף עוד חמישה עיגולים ותסמן כל קבוצה מבין ה 3 שתיארנו בצבע אחר:

var startX = 30, startY = 30, radius = 10;

var svg = d3.select("#tree-container").append("svg")
        .attr("width", 700)
        .attr("height", 150);

var i, data = [];
for (i = 0; i < 10; i++)
    data.push({
                 v: i, 
                 x: startX + (i % 5) * radius * 3, 
                 y: startY + parseInt(i / 5) * (radius * 3)
             });

svg.selectAll("circle")
        .data(data, function (d){return d.v;})
        .enter().append("circle")
        .attr("cx", function (d) {return d.x;})
        .attr("cy", function (d) {return d.y;})
        .attr("r", radius)
        .attr("fill", "blue");

var newData = [];
for (i = 5; i < 15; i++)
    newData.push({
                    v: i, 
                    x: startX + (i % 5) * radius * 3, 
                    y: startY + parseInt(i / 5) * (radius * 3)
                });

var selection = svg.selectAll("circle")
        .data(newData, function (d){return d.v;});

selection.exit()
        .transition()
        .duration(2000)
        .attr("fill", "green");

selection
        .enter().append("circle")
        .transition()
        .duration(2000)
        .attr("cx", function (d) {return d.x;})
        .attr("cy", function (d) {return d.y;})
        .attr("r", radius)
        .attr("fill", "red");

קריאה נוספת:

https://bost.ocks.org/mike/selection

ומה עם העץ? בפוסט הבא...

Leave a Reply

Your email address will not be published. Required fields are marked *