Articolo tecnico

Sparkline di Excel in Delphi: HotXLS e l'estensione x14

HotXLS crea le Sparkline di Excel — i mini grafici che Excel traccia all'interno di una singola cella — da Delphi e C++Builder con un'unica chiamata: TXLSXWorksheet.AddSparklineGroup compila un gruppo di sparkline su un intervallo di dati, e il salvataggio della cartella di lavoro lo scrive come blocco di estensione x14 all'interno di extLst nel foglio di lavoro, che Excel 2010 e versioni successive visualizzano mentre i lettori meno recenti ignorano senza problemi. Nessun oggetto grafico, nessuna parte di disegno, nessun ancoraggio

Lo scenario che rende vantaggioso l'uso delle sparkline è sempre lo stesso. Una cartella di lavoro dashboard contiene alcune centinaia di righe, una per ogni prodotto, area o account, con dodici dati mensili ciascuna, e si desidera un indicatore di tendenza alla fine di ogni riga. Se provassi a realizzare questo comportamento con grafici reali, dovresti creare centinaia di parti di grafici DrawingML, ciascuna con la propria sezione XML, relazione e geometria di ancoraggio, per non parlare dell'impatto sulle dimensioni del file e sui tempi di apertura. Un gruppo di sparkline è invece un unico blocco XML che indica semplicemente "disegna una linea minuscola da B2:M2 in N2, e da B3:M3 in N3", ripetuto in modo efficiente per tutte le righe necessarie

Perché le sparkline sono un'estensione x14 invece di un grafico?

Le sparkline sono state introdotte con Excel 2010, tre anni dopo il congelamento dello schema di base ECMA-376, per cui non potevano risiedere direttamente nel markup del foglio di lavoro senza compromettere la compatibilità con i lettori esistenti. La soluzione di Microsoft è il meccanismo dell'elenco di estensioni: un foglio di lavoro può terminare con un elemento <extLst> contenente blocchi <ext>, ciascuno contrassegnato da un URI che identifica la funzionalità ([MS-XLSX] §2.3.6). Le sparkline utilizzano l'URI {05C60535-1F16-4fd2-B633-F4F36F0B64E0} e il namespace x14. Un lettore che riconosce il GUID analizza il blocco; un lettore che non lo riconosce deve ignorarlo. Questa è l'intera strategia di compatibilità futura, ed è il motivo per cui Excel 2007 apre correttamente una cartella di lavoro contenente sparkline — semplicemente mostrando i numeri sorgente senza i grafici

Un dettaglio di questo meccanismo merita di essere evidenziato poiché smentisce un presupposto comune: no è richiesta alcuna dichiarazione mc:Ignorable sulla radice del foglio di lavoro. La verifica del GUID di estensione è sufficiente di per sé, e l'esportatore di Excel dichiara il namespace x14 localmente sull'elemento <ext> anziché agire sulla radice. HotXLS segue lo stesso schema, preservando intatto il resto dell'XML del foglio di lavoro. Questa è anche la differenza strutturale rispetto ai grafici reali: un grafico è una parte DrawingML separata con una propria pipeline di rendering, trattata nell'articolo correlato su grafici, immagini e disegni, mentre una sparkline è un metadato del foglio di lavoro disegnato direttamente dalla griglia del foglio di calcolo

Come si aggiungono le sparkline a un file XLSX a livello di programmazione?

Il metodo TXLSXWorksheet.AddSparklineGroup(AType, ASourceRange, ALocation) rappresenta il percorso ad attivazione singola: crea un gruppo del tipo specificato, lo imposta con il colore predefinito della serie di Excel e aggiunge la prima sparkline che mappa un intervallo sorgente qualificato dal foglio su una cella ospite. L'oggetto TXLSXSparklineGroup restituito accetta quindi ulteriori sparkline tramite il suo metodo Add, una coppia F/Sqref per riga, che condividono tutte il tipo e la formattazione del gruppo. Per il caso di una dashboard, questa è esattamente la struttura ideale: un gruppo, un set di opzioni visive e centinaia di membri

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;

I tre tipi di sparkline supportati da Excel sono coperti dall'enumeratore TXLSXSparklineType: xlsxSparklineLine per linee di tendenza, xlsxSparklineColumn per piccoli grafici a barre, e xlsxSparklineStacked per andamenti positivi/negativi in cui ogni valore è rappresentato da un blocco verso l'alto o verso il basso. Ogni sparkline membro è costituita solo da due stringhe — F, l'intervallo sorgente qualificato dal foglio, e Sqref, la cella in cui viene disegnato il grafico — per cui non vi sono altre configurazioni per riga. I gruppi possono anche essere creati interamente a mano tramite la raccolta Worksheet.SparklineGroups quando si desidera iniziare da un gruppo vuoto anziché utilizzare i valori predefiniti

Marcatori, slot di colore e scala degli assi nel modello tipizzato

L'oggetto TXLSXSparklineGroup espone l'intero set di opzioni della barra degli strumenti Sparkline di Excel sotto forma di proprietà semplici. Sei interruttori booleani consentono di evidenziare i punti dati: Markers per ogni punto su una sparkline a linea, oltre a HighPoint, LowPoint, NegativePoints, FirstPoint, e LastPoint. A questi si associano otto slot di colore ARGB — ColorSeries, ColorNegative, ColorAxis, ColorMarkers, ColorFirst, ColorLast, ColorHigh, ColorLow — con la convenzione che uno slot lasciato a 0 viene omesso dal file e Excel applica il proprio valore predefinito. La stessa rappresentazione ARGB completamente opaca è utilizzata in tutta la libreria, per cui $FFD00000 qui indica lo stesso rosso utilizzato negli stili di formattazione condizionale

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;

Le proprietà degli assi meritano una riflessione prima di accettare i valori predefiniti. MinAxisType e MaxAxisType supportano ciascuno una scala individuale, di gruppo o personalizzata: la scala individuale adatta ogni sparkline ai propri valori minimi e massimi, il che rende una riga che oscilla tra 99 e 101 visivamente drammatica tanto quanto una che triplica. La scala di gruppo posiziona ogni membro su un'unica scala verticale condivisa, in modo che l'altezza del grafico indichi la stessa quantità in ogni riga — solitamente la scelta preferibile per una dashboard comparativa. DisplayEmptyCellsAs stabilisce come una cella sorgente vuota influenzi una linea: lasciare uno spazio vuoto, considerare il valore come zero, o unire i punti adiacenti per colmare il vuoto

Cosa scrive HotXLS in extLst del foglio di lavoro al momento del salvataggio

Al momento del salvataggio, HotXLS serializza ciascun gruppo come elemento x14:sparklineGroup contenente gli attributi di tipo e di interruttori, gli slot di colore come elementi figli e un elenco x14:sparklines i cui membri accoppiano una formula di intervallo xm:f con una cella ospite xm:sqref. L'intera struttura risiede all'interno di <extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"> alla fine della sezione del foglio di lavoro, con il namespace x14 dichiarato direttamente sul blocco, esattamente come fa Excel. Un foglio di lavoro senza gruppi di sparkline non produce alcun elemento extLst, per cui i file che non utilizzano questa funzionalità risultano identici byte per byte a quelli prodotti dalle versioni precedenti di HotXLS — seguendo lo stesso rigore di scrittura conservativa descritto nell'articolo sull'infrastruttura di round-trip senza perdita di dati

Un dettaglio delle specifiche è importante se si confronta l'output con quello di Excel o si esamina manualmente l'XML: il valore predefinito dello schema per lineWeight è 0.75 punti, e non 1.25 come citano alcune fonti secondarie — lo standard [MS-XLSX] definisce CT_SparklineGroup@lineWeight con un valore di default di 0.75, corrispondente allo spessore che l'interfaccia utente di Excel applica effettivamente. HotXLS rispetta questo comportamento predefinito per omissione: impostando LineWeight su un valore diverso da 0.75 l'attributo viene scritto, lasciandolo a 0.75 l'attributo viene omesso. Un errore in tal senso produce file che vengono renderizzati in modo leggermente più marcato o più leggero rispetto alla stessa cartella di lavoro salvata da Excel

Round-trip, copie di fogli ed estensioni non modellate da HotXLS

L'apertura è l'immagine speculare del salvataggio. Quando HotXLS apre una cartella di lavoro contenente sparkline — sia essa generata da HotXLS o da Excel — il parser verifica il GUID di estensione della sparkline e ricostruisce ogni gruppo, membro, colore e opzione dell'asse nel modello tipizzato, in modo che un ciclo di apertura→modifica→salvataggio li preservi completamente. La copia di un foglio di lavoro in un'altra cartella di lavoro clona i suoi gruppi di sparkline insieme al resto del foglio, semplificando la generazione di report basata su modelli: è sufficiente mantenere un foglio modello formattato, copiarlo per ciascun report e aggiornare gli intervalli

L'elemento extLst può contenere anche blocchi di estensione per i quali HotXLS non dispone di un modello tipizzato — Excel scrive nello stesso elenco blocchi x14 per funzionalità come i filtri dati (slicer) e la formattazione condizionale estesa. A partire dalla versione v2.131.0, questi blocchi esterni vengono preservati testualmente durante un round-trip anziché essere eliminati: il parser li acquisisce, li espone in modalità sola lettura tramite Worksheet.RawWorksheetExts e li scrive nuovamente al salvataggio; inoltre, essi seguono il foglio quando questo viene copiato in un'altra cartella di lavoro. L'XML preservato viene ricostruito a partire dagli eventi del parser, per cui è semanticamente equivalente all'originale ma non identico byte per byte; tuttavia, Excel lo accetta e le funzionalità vengono mantenute. La conseguenza pratica è quella rilevante in produzione: l'apertura di una cartella di lavoro di un cliente e il successivo salvataggio non rimuovono più le estensioni che non è stato richiesto a HotXLS di interpretare

Limite oggettivo: le sparkline vengono visualizzate in Excel 2010 e versioni successive, e in qualsiasi altro lettore che implementi l'estensione x14; Excel 2007 mostra i dati senza i grafici, che rappresenta la degradazione per cui il formato è stato concepito. I tre tipi di sparkline, gli otto slot di colore, gli interruttori dei punti e le tre modalità degli assi coprono l'intero spettro di opzioni offerto dalla finestra di dialogo di Excel. Il supporto alle sparkline, insieme al resto del motore XLSX mostrato qui, è fornito nel Componente HotXLS Delphi Excel per Delphi e C++Builder