مقاله فنی

اسپارک‌لاین‌های اکسل در دلفی: HotXLS و پسوند x14

کامپوننت HotXLS اسپارک‌لاین‌های اکسل (Sparklines) — نمودارهای کوچکی که اکسل در داخل یک سلول می‌کشد — را از دلفی و C++Builder با یک فراخوانی ایجاد می‌کند: متد TXLSXWorksheet.AddSparklineGroup یک گروه اسپارک‌لاین را روی یک محدوده داده می‌سازد و ذخیره کارپوشه، آن را به عنوان یک بلوک پسوند x14 در داخل extLst کاربرگ می‌نویسد که اکسل ۲۰۱۰ و نسخه‌های جدیدتر آن را رندر می‌کنند و خواننده‌های قدیمی‌تر بدون شکایت از آن عبور می‌کنند. بدون هیچ شیء نمودار، بخش‌های ترسیم یا لنگر

سناریویی که داشتن اسپارک‌لاین‌ها را ارزشمند می‌کند همیشه یکسان است. یک کارپوشه داشبورد شامل چند صد ردیف است، یکی برای هر محصول یا منطقه یا حساب، که هر کدام دوازده رقم ماهانه دارند و کسی می‌خواهد یک نمودار روند در انتهای هر ردیف داشته باشد. اگر این کار را با نمودارهای واقعی شبیه‌سازی کنید، صدها بخش نمودار DrawingML ایجاد خواهید کرد که هر کدام دارای بخش XML، رابطه و هندسه لنگر خود هستند، ناگفته نماند که این کار چه تأثیری بر حجم فایل و زمان باز شدن آن می‌گذارد. یک گروه اسپارک‌لاین، یک بلوک XML است که می‌گوید "یک خط کوچک از B2:M2 در داخل N2، و از B3:M3 در داخل N3 بکشید"، که با هزینه بسیار کم برای هر تعداد ردیف که دارید تکرار می‌شود

چرا اسپارک‌لاین‌ها به جای نمودار، یک پسوند x14 هستند؟

اسپارک‌لاین‌ها با اکسل ۲۰۱۰ ارائه شدند، یعنی سه سال پس از انجماد طرحواره پایه ECMA-376، بنابراین نمی‌توانستند در نشانه‌گذاری اصلی کاربرگ بدون خراب کردن خواننده‌های موجود قرار بگیرند. پاسخ مایکروسافت مکانیزم لیست پسوند است: یک کاربرگ ممکن است با عنصر <extLst> پایان یابد که بلوک‌های <ext> را نگه می‌دارد، که هر کدام با یک URI که ویژگی را شناسایی می‌کند ([MS-XLSX] §2.3.6) علامت‌گذاری شده‌اند. اسپارک‌لاین‌ها از URI معادل {05C60535-1F16-4fd2-B633-F4F36F0B64E0} و فضای نام x14 استفاده می‌کنند. خواننده‌ای که این شناسه GUID را تشخیص دهد، بلوک را تجزیه می‌کند؛ خواننده‌ای که تشخیص ندهد موظف است از آن عبور کند. این کل داستان سازگاری رو به جلو است و به همین دلیل است که اکسل ۲۰۰۷ یک کارپوشه حاوی اسپارک‌لاین را به طور تمیز باز می‌کند — این نرم‌افزار به سادگی اعداد منبع را بدون نمودارها نشان می‌دهد

یکی از جزئیات این مکانیزم شایسته توجه است زیرا با یک فرض رایج تناقض دارد: هیچ بیانیه mc:Ignorable روی ریشه کاربرگ نیاز نیست. گیت GUID افزونه به خودی خود کافی است و نویسنده خود اکسل فضای نام x14 را به طور محلی روی عنصر <ext> اعلام می‌کند به جای اینکه به ریشه دست بزند. HotXLS نیز از همین الگو پیروی می‌کند که بقیه XML کاربرگ را دست‌نخورده نگه می‌دارد. این همچنین تفاوت ساختاری با نمودارهای واقعی است: یک نمودار یک بخش مجزای DrawingML با خط لوله رندر خود است که در مقاله همراه در مورد نمودارها، تصاویر و ترسیم‌ها پوشش داده شده است، در حالی که یک اسپارک‌لاین متادیتای کاربرگ است که خود شبکه صفحه گسترده آن را رسم می‌کند

چگونه اسپارک‌لاین‌ها را به صورت برنامه‌نویسی به یک فایل XLSX اضافه کنیم؟

متد TXLSXWorksheet.AddSparklineGroup(AType, ASourceRange, ALocation) مسیر تک فراخوانی است: این متد یک گروه از نوع داده شده را ایجاد می‌کند، آن را با رنگ پیش‌فرض اکسل مقداردهی اولیه می‌کند و اولین اسپارک‌لاین را که یک محدوده منبع مشخص در برگ را به یک سلول میزبان نگاشت می‌کند، اضافه می‌کند. سپس کلاس برگشتی TXLSXSparklineGroup اسپارک‌لاین‌های بیشتری را از طریق متد Add خود می‌پذیرد، یک جفت F/Sqref برای هر ردیف، که همگی نوع و قالب‌بندی گروه را به اشتراک می‌گذارند. برای حالت داشبورد، این دقیقاً همان شکلی است که می‌خواهید: یک گروه، یک مجموعه از گزینه‌های بصری، صدها عضو

شمارش TXLSXSparklineType سه نوع ارائه شده توسط اکسل را پوشش می‌دهد: xlsxSparklineLine برای خطوط روند، xlsxSparklineColumn برای نمودارهای میله‌ای کوچک، و xlsxSparklineStacked برای نوار برد/باخت که در آن هر مقدار به عنوان یک بلوک بالا یا پایین رندر می‌شود. هر عضو اسپارک‌لاین فقط دو رشته است — F، محدوده منبع مشخص در برگ، و Sqref، سلولی که نمودار در آن رسم می‌شود — بنابراین چیز دیگری برای پیکربندی در هر ردیف وجود ندارد. گروه‌ها همچنین می‌توانند کاملاً به صورت دستی از طریق مجموعه Worksheet.SparklineGroups ساخته شوند، زمانی که می‌خواهید از یک گروه خالی شروع کنید به جای اینکه از پیش‌فرض مقداردهی‌شده استفاده کنید

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;

نشانگرها، اسلات‌های رنگ و مقیاس‌گذاری محور در مدل تایپ‌شده

کلاس TXLSXSparklineGroup کل مجموعه گزینه‌های تب ابزارهای اسپارک‌لاین اکسل را به عنوان ویژگی‌های ساده در دسترس قرار می‌دهد. شش دکمه بولین نقاط داده را برجسته می‌کنند: Markers برای هر نقطه روی یک خط اسپارک‌لاین، به علاوه HighPoint، LowPoint، NegativePoints، FirstPoint و LastPoint. هشت اسلات رنگ ARGB با آنها جفت می‌شوند — ColorSeries، ColorNegative، ColorAxis، ColorMarkers، ColorFirst، ColorLast، ColorHigh، ColorLow — با این قرارداد که اگر اسلاتی روی ۰ رها شود، از فایل حذف شده و اکسل پیش‌فرض خود را اعمال می‌کند. همان شکل ARGB کاملاً کدر در سراسر کتابخانه ظاهر می‌شود، بنابراین $FFD00000 در اینجا به همان رنگ قرمزی است که در سبک‌های قالب‌بندی شرطی معنی دارد

ویژگی‌های محور قبل از پذیرش مقادیر پیش‌فرض شایسته کمی تفکر هستند. MinAxisType و MaxAxisType هر کدام مقاسی‌گذاری فردی، گروهی یا سفارشی را می‌پذیرند: مقیاس‌گذاری فردی هر اسپارک‌لاین را به حداقل و حداکثر خود می‌کشاند، که باعث می‌شود ردیفی که بین ۹۹ و ۱۰۱ نوسان دارد به اندازه ردیفی که سه برابر می‌شود چشمگیر به نظر برسد. مقیاس‌گذاری گروهی همه اعضا را در یک مقیاس عمودی مشترک قرار می‌دهد، بنابراین ارتفاع نمودار به معنای همان مقدار در هر ردیف است — که معمولاً همان چیزی است که یک داشبورد مقایسه‌ای می‌خواهد. DisplayEmptyCellsAs تصمیم می‌گیرد که یک سلول منبع خالی با خط چه کند: ایجاد فاصله، محاسبه به عنوان صفر، یا پر کردن حفره با اتصال همسایگانش

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;

آنچه HotXLS هنگام ذخیره در extLst کاربرگ می‌نویسد

هنگام ذخیره، HotXLS هر گروه را به عنوان یک عنصر x14:sparklineGroup حاوی ویژگی‌های نوع و دکمه‌های کنترلی، اسلات‌های رنگ به عنوان عناصر فرزند، و یک لیست x14:sparklines که اعضای آن یک فرمول محدوده xm:f را با یک سلول میزبان xm:sqref جفت می‌کنند، سریال‌سازی می‌کند. کل این ساختار در داخل <extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"> در انتهای بخش کاربرگ قرار می‌گیرد، در حالی که فضای نام x14 مستقیماً روی بلوک اعلام شده است، دقیقاً همانطور که اکسل آن را می‌نویسد. یک کاربرگ بدون هیچ گروه اسپارک‌لاین اصلاً هیچ عنصر extLst صادر نمی‌کند، بنابراین فایل‌هایی که هرگز از این ویژگی استفاده نکرده‌اند، بایت به بایت شبیه به آنچه نسخه‌های قبلی HotXLS تولید می‌کردند خارج می‌شوند — همان انضباط نویسنده محافظه‌کار که در مقاله زیرساخت رفت و برگشت بدون اتلاف توضیح داده شده است

اگر خروجی را با اکسل مقایسه می‌کنید یا XML را به صورت دستی بررسی می‌کنید، یک جزئیات مشخصات اهمیت دارد: پیش‌فرض طرحواره برای lineWeight برابر ۰.۷۵ امتیاز است و نه ۱.۲۵ که برخی منابع فرعی نقل می‌کنند — استاندارد [MS-XLSX] ویژگی CT_SparklineGroup@lineWeight را با پیش‌فرض ۰.۷۵ تعریف می‌کند که با وزنی که رابط کاربری اکسل واقعاً اعمال می‌کند مطابقت دارد. HotXLS با عدم نوشتن آن به پیش‌فرض احترام می‌گذارد: اگر LineWeight را روی مقداری غیر از ۰.۷۵ تنظیم کنید، ویژگی نوشته می‌شود، آن را روی ۰.۷۵ رها کنید و نوشته نخواهد شد. اشتباه گرفتن این مورد در هر جهت، فایل‌هایی تولید می‌کند که نسبت به همان کارپوشه ذخیره شده از اکسل، کمی ضخیم‌تر یا نازک‌تر به نظر می‌رسند

رفت و برگشت‌ها، کپی‌های برگ و پسوندهایی که HotXLS شبیه‌سازی نمی‌کند

باز کردن، تصویر آینه‌ای ذخیره کردن است. هنگامی که HotXLS کارپوشه‌ای را باز می‌کند که حاوی اسپارک‌لاین است — چه HotXLS آن را نوشته باشد چه اکسل — تجزیه‌کننده روی شناسه GUID پسوند اسپارک‌لاین متمرکز می‌شود و هر گروه، عضو، رنگ و گزینه محور را در مدل تایپ‌شده بازسازی می‌کند، بنابراین چرخه باز کردن←ویرایش←ذخیره آنها را کاملاً حفظ می‌کند. کپی کردن یک کاربرگ در کارپوشه دیگر، گروه‌های اسپارک‌لاین آن را همراه با بقیه برگ شبیه‌سازی می‌کند، که تولید گزارش مبتنی بر قالب را آسان می‌سازد: یک برگ قالب استایل‌دهی شده را نگه دارید، آن را برای هر گزارش کپی کنید و محدوده‌ها را دوباره تنظیم کنید

لیست extLst همچنین می‌تواند حاوی بلوک‌های پسوندی باشد که HotXLS هیچ مدل تایپ‌شده‌ای برای آنها ندارد — اکسل بلوک‌های x14 را برای ویژگی‌هایی مانند اسلایسرها (slicers) و قالب‌بندی شرطی پیشرفته در همان لیست می‌نویسد. از نسخه v2.131.0، آن بلوک‌های خارجی در طول رفت و برگشت به صورت کلمه به کلمه حفظ می‌شوند و حذف نمی‌گردند: تجزیه‌کننده آنها را ضبط می‌کند، آنها را به صورت فقط خواندنی از طریق Worksheet.RawWorksheetExts در دسترس قرار می‌دهد و هنگام ذخیره، آنها را بازنویسی می‌کند و این اطلاعات همراه با یک برگ هنگام کپی در کاربرگ دیگر منتقل می‌شوند. XML حفظ‌شده از رویدادهای تجزیه‌کننده بازسازی می‌شود، بنابراین از نظر معنایی معادل نسخه اصلی است و نه بایت به بایت یکسان، اما اکسل آن را می‌پذیرد و ویژگی‌ها زنده می‌مانند. نتیجه عملی همان چیزی است که در محیط واقعی اهمیت دارد: باز کردن کارپوشه مشتری و ذخیره مجدد آن، دیگر پسوندهایی را که از HotXLS نخواسته‌اید متوجه شود، حذف نمی‌کند

مرز صادقانه: اسپارک‌لاین‌ها در اکسل ۲۰۱۰ و نسخه‌های جدیدتر، و در هر خواننده دیگری که پسوند x14 را پیاده‌سازی می‌کند، رندر می‌شوند؛ اکسل ۲۰۰۷ داده‌ها را بدون نمودارها نشان می‌دهد، که این همان تنزل کارکردی است که فرمت برای آن طراحی شده است. سه نوع اسپارک‌لاین، هشت اسلات رنگ، دکمه‌های نقاط داده و سه حالت محور، کل ویژگی‌های دیالوگ خود اکسل را پوشش می‌دهند. پشتیبانی از اسپارک‌لاین، همراه با بقیه موتور XLSX نشان داده شده در اینجا، در HotXLS Delphi Excel Component برای دلفی و C++Builder ارائه می‌شود