מאמר טכני

ספארקליינים של Excel ב-Delphi: התוכנה HotXLS והרחבת x14

רכיב HotXLS מייצר ספארקליינים (Sparklines) של Excel — תרשימים זעירים ש-Excel מציירת בתוך תא בודד — מתוך Delphi ו-C++Builder בקריאה אחת: המתודה TXLSXWorksheet.AddSparklineGroup בונה קבוצת ספארקליינים על פני טווח נתונים, ושמירת חוברת העבודה כותבת אותה כבלוק הרחבה x14 בתוך ה-extLst של גיליון העבודה, שמרנדרים ב-Excel 2010 ומעלה וקוראים ישנים יותר מדלגים עליו ללא תלונות. ללא אובייקטים של תרשימים, ללא חלקי ציור וללא עוגנים גיאומטריים

התרחיש שהופך ספארקליינים למועילים הוא תמיד זהה. חוברת עבודה של לוח בקרה (dashboard) נושאת כמה מאות שורות, אחת לכל מוצר, אזור או חשבון, שנים עשר נתונים חודשיים כל אחת, ומישהו רוצה סימן מגמה בסוף כל שורה. מפו זאת באמצעות תרשימים אמיתיים ותיצרו מאות חלקי תרשימי DrawingML, כל אחד עם קובץ XML משלו, קשר וגיאומטריית עוגן, שלא לדבר על מה שזה עושה לגודל הקובץ ולזמן הפתיחה. קבוצת ספארקליינים היא בלוק XML אחד האומר "צייר קו זעיר מ-B2:M2 לתוך N2, ומ-B3:M3 לתוך N3", שמשוכפל בזול עבור מספר שורות רב ככל שיש לכם

מדוע ספארקליינים הם הרחבת x14 ולא תרשים?

ספארקליינים הגיעו עם Excel 2010, שלוש שנים לאחר שסכימת הבסיס ECMA-376 הוקפאה, כך שהם לא יכלו לחיות בתוך סימון גיליון העבודה עצמו מבלי לשבור כל קורא קיים. התשובה של מיקרוסופט היא מנגנון רשימת ההרחבות: גיליון עבודה עשוי להסתיים באלמנט <extLst> המחזיק בלוקי <ext>, כל אחד מתויג עם URI המזהה את התכונה ([MS-XLSX] §2.3.6). ספארקליינים משתמשים ב-URI‏ {05C60535-1F16-4fd2-B633-F4F36F0B64E0} ובמרחב השמות x14. קורא שמזהה את ה-GUID מנתח את הבלוק; קורא שאינו מזהה נדרש לדלג עליו. זהו כל סיפור התאימות קדימה, והיא הסיבה ש-Excel 2007 פותחת חוברת עבודה של ספארקליינים בצורה נקייה — היא פשוט מציגה את מספרי המקור ללא הגרפיקה

פרט אחד במנגנון ראוי לציון מכיוון שהוא סותר הנחה נפוצה: אין צורך בהצהרת mc:Ignorable בשורש גיליון העבודה. שער ה-ext GUID מספיק בפני עצמו, והכותב של Excel עצמו מצהיר על מרחב השמות x14 באופן מקומי באלמנט <ext> במקום לגעת בשורש. HotXLS עוקבת אחר אותה תבנית, מה שמשאיר את שאר ה-XML של גיליון העבודה ללא שינוי. זהו גם ההבדל המבני מתרשימים אמיתיים: תרשים הוא חלק DrawingML נפרד עם צינור רינדור משלו, המכוסה במאמר הנלווה על תרשימים, תמונות ושרטוטים, בעוד שספארקליין הוא מטא-נתונים של גיליון עבודה שרשת הגיליון האלקטרוני עצמה מציירת

כיצד מוסיפים ספארקליינים לקובץ XLSX תוכניתית?

הקריאה TXLSXWorksheet.AddSparklineGroup(AType, ASourceRange, ALocation) היא הנתיב בקריאה אחת: היא יוצרת קבוצה מהסוג הנתון, מאתחלת אותה עם צבע ברירת המחדל של סדרת Excel ומוסיפה את מיפוי הספארקליין הראשון הממפה טווח מקור מוגדר-גיליון לתא מארח. ה-TXLSXSparklineGroup המוחזר מקבל לאחר מכן ספארקליינים נוספים באמצעות מתודת ה-Add שלו, זוג F/Sqref אחד לכל שורה, כולם משתפים את הסוג והעיצוב של הקבוצה. עבור מקרה לוח הבקרה זה בדיוק המבנה שאתם רוצים: קבוצה אחת, סט אחד של אפשרויות ויזואליות, מאות חברים

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Grp: TXLSXSparklineGroup;
  Row: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('dashboard.xlsx');
    Sheet := Book.Sheets[0];

    // One group: every product row shares type and formatting
    Grp := Sheet.AddSparklineGroup(xlsxSparklineLine,
      'Sheet1!B2:M2', 'N2');
    for Row := 3 to 201 do
      Grp.Add(Format('Sheet1!B%d:M%d', [Row, Row]),
        Format('N%d', [Row]));

    Book.SaveAs('dashboard-trends.xlsx');
  finally
    Book.Free;
  end;
end;

הטיפוס TXLSXSparklineType מכסה את שלושת הסוגים ש-Excel מציעה: xlsxSparklineLine לקווי מגמה, xlsxSparklineColumn לתרשימי עמודות זעירים ו-xlsxSparklineStacked לרצועות זכייה/הפסד שבהן כל ערך מרונדר כבלוק למעלה או למטה. כל ספארקליין חבר הוא רק שתי מחרוזות — F, טווח המקור המוגדר-גיליון, ו-Sqref, התא שבו מצויר הגליף — כך שאין דבר אחר להגדיר לכל שורה. ניתן לבנות קבוצות גם באופן ידני לחלוטין דרך אוסף Worksheet.SparklineGroups כאשר אתם רוצים להתחיל מקבוצה ריקה ולא מברירת המחדל המאותחלת

סמנים, חריצי צבע ושינוי קנה מידה של צירים במודל מוגדר-סוג

הקבוצה TXLSXSparklineGroup חושפת את ערכת האפשרויות המלאה מסרגל הכלים Sparkline Tools של Excel כמאפיינים פשוטים. שישה מתגים בוליאניים מדגישים נקודות נתונים: Markers עבור כל נקודה בספארקליין קו, בתוספת HighPoint,‏ LowPoint,‏ NegativePoints,‏ FirstPoint ו-LastPoint. שמונה חריצי צבע ARGB מזדווגים איתם — ColorSeries,‏ ColorNegative,‏ ColorAxis,‏ ColorMarkers,‏ ColorFirst,‏ ColorLast,‏ ColorHigh,‏ ColorLow — עם המוסכמה שחריץ שנשאר ב-0 מושמט מהקובץ ו-Excel מחילה את ברירת המחדל שלה. אותה צורת ARGB אטומה לחלוטין מופיעה בכל הספרייה, כך ש-$FFD00000 כאן פירושו אותו אדום כמו בסגנונות עיצוב מותנים

Grp := Sheet.AddSparklineGroup(xlsxSparklineStacked,
  'Sheet1!B2:M2', 'N2');
Grp.NegativePoints := True;          // losing months stand out
Grp.ColorNegative := $FFD00000;
Grp.HighPoint := True;
Grp.ColorHigh := $FF00B050;
Grp.MinAxisType := xlsxSparklineAxisGroup;   // one scale for all rows
Grp.MaxAxisType := xlsxSparklineAxisGroup;
Grp.DisplayEmptyCellsAs := xlsxSparklineEmptyGap;

מאפייני הציר ראויים למחשבה לפני שאתם מקבלים את ערכי ברירת המחדל. MinAxisType ו-MaxAxisType מקבלים כל אחד קנה מידה בודד, קבוצתי או מותאם אישית: קנה מידה בודד מותח כל ספארקליין למינימום ולמקסימום שלו, מה שגורם לשורה שמתנדנדת בין 99 ל-101 להיראות דרמטית כמו שורה שגדלה פי שלושה. קנה מידה קבוצתי מציב את כל החברים על קנה מידה אנכי משותף אחד, כך שגובה הגליף מייצג את אותו כמות בכל שורה — בדרך כלל מה שלוח בקרה השוואתי דורש. המאפיין DisplayEmptyCellsAs קובע מה תא מקור ריק עושה לקו: משאיר מרווח, נחשב כאפס או מחבר את השכנים שלו מעל החור

מה HotXLS כותבת לתוך extLst של גיליון העבודה בעת השמירה

בעת השמירה, HotXLS מסדרת כל קבוצה כאלמנט x14:sparklineGroup הנושא את סוג הפעילות ותכונות המתגים, חריצי הצבע כאלמנטים ילדים ורשימת x14:sparklines שחבריה מצמידים נוסחת טווח xm:f לתא מארח xm:sqref. המבנה כולו יושב בתוך <extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"> בסוף חלק גיליון העבודה, כאשר מרחב השמות x14 מוצהר ישירות על הבלוק, בדיוק כפי ש-Excel כותבת אותו. גיליון עבודה ללא קבוצות ספארקליינים אינו מפיק extLst כלל, כך שקבצים שלא השתמשו בתכונה יוצאים זהים ביט לביט למה שגרסאות קודמות של HotXLS הפיקו — אותה משמעת כתיבה שמרנית המתוארת במאמר על תשתית סבב ללא אובדן נתונים

פרט מפרט אחד חשוב אם תסרקו את ה-XML: ברירת המחדל של הסכימה עבור lineWeight היא 0.75 נקודות, ולא 1.25 שמקורות משניים מסוימים מצטטים — [MS-XLSX] מגדיר את CT_SparklineGroup@lineWeight עם ברירת מחדל של 0.75, התואמת למשקל שממשק המשתמש של Excel מחיל בפועל. HotXLS מכבדת את ברירת המחדל על ידי השמטה: הגדירו את LineWeight לכל ערך אחר מלבד 0.75 והתכונה תיכתב, השאירו אותה ב-0.75 והיא לא תיכתב. טעות בכך בכל כיוון מייצרת קבצים המרונדרים כבדים או קלים יותר מאותה חוברת עבודה שנשמרה מ-Excel

סבבים, העתקות גיליונות והרחבות ש-HotXLS אינה ממדלת

הפתיחה היא תמונת הראי של השמירה. כאשר HotXLS פותחת חוברת עבודה הנושאת ספארקליינים — בין אם HotXLS כתבה אותה או Excel — המנתח מזהה את ה-ext GUID של הספארקליין ובונה מחדש כל קבוצה, חבר, צבע ואפשרות ציר לתוך המודל המוגדר-סוג, כך שמחזור פתיחה←עריכה←שמירה משמר אותם לחלוטין. העתקת גיליון עבודה לחוברת עבודה אחרת משכפלת את קבוצות הספארקליינים שלו יחד עם שאר הגיליון, מה שהופך יצירת דוחות מונחית תבנית לקלה: שמרו על גיליון תבנית מעוצב, העתיקו אותו לכל דוח וכוונו מחדש את הטווחים

רשימת ה-extLst יכולה להכיל גם בלוקי הרחבה של-HotXLS אין מודל מוגדר-סוג עבורם — Excel כותבת בלוקי x14 עבור תכונות כמו מסננים (slicers) ועיצוב מותנה מורחב לתוך אותה רשימה. מאז גרסה v2.131.0 בלוקים זרים אלה נשמרים ללא שינוי לאורך סבב במקום להימחק: המנתח לוכד אותם, חושף אותם לקריאה בלבד דרך Worksheet.RawWorksheetExts וכותב אותם חזרה בעת השמירה, והם נוסעים עם גיליון כאשר הוא מועתק לחוברת עבודה אחרת. ה-XML המשומר נבנה מחדש מאירועי מנתח, כך שהוא שקול סמנטית למקור ולא זהה ביט לביט, אך Excel מקבלת אותו והתכונות שורדות. התוצאה המעשית היא החשובה בייצור: פתיחת חוברת העבודה של לקוח ושמירתה מחדש אינה מסירה יותר הרחבות שלא ביקשתם מ-HotXLS לפרש

הגבול הכנה: ספארקליינים מרונדרים ב-Excel 2010 ומעלה, ובכל קורא אחר המיישם את הרחבת x14; גרסת Excel 2007 מציגה את הנתונים ללא הגרפיקה, שהיא ההדרדרות שעיצוב הפורמט תוכנן לה. שלושת סוגי הספארקליינים, שמונת חריצי הצבע, מתגי הנקודות ושלושת מצבי הציר מכסים את כל פני השטח של אפשרויות שדיאלוג Excel עצמו מציע. תמיכת ספארקליינים, יחד עם שאר מנוע ה-XLSX המוצג כאן, מגיעה ב-רכיב HotXLS Delphi Excel עבור Delphi ו-C++Builder