HotXLS može da postavi grafikon direktno na radni list, sidren na opseg ćelija, umesto da ga stavi na poseban chart sheet. U BIFF8 terminima to znači upisati drawing oblik sa OBJ zapisom tipa 5 i parkirati chart substream na kraj toka zapisa lista, što je baš raspored koji Excel proizvodi i baš mesto gde čitač očekuje da ga nađe
Razlika je važna svakome ko generiše operativne izveštaje. Chart sheet je fina kuća za jedan naslovni vizuelni prikaz. Mesečni regionalni pregled želi grafikon pored brojeva koje sumira, na istom listu, dimenzionisan na blok ćelija kojem pripada, da čitalac skroluje jednom umesto da menja tabove i gubi kontekst
Čitanje je već postojalo, pisanje nije
Asimetriju vredi imenovati jer oblikuje posao. HotXLS je već umeo da čita ugrađene grafikone: kad tok zapisa radnog lista sadrži BOF označen kao chart substream, parser menja kontekst, sakuplja zapise grafikona, i pri zatvarajućem EOF vraća ih drawing obliku koji je OBJ zapis uveo. Tom putanjom je prošla svaka radna sveska autorstva Excel-a koju je biblioteka ikada otvorila
Nedostajala je autorska strana, i korisna posledica je da je novi pisac imao preciznu specifikaciju koju treba pogoditi: proizvedi bajt raspored koji postojeći čitač već ponovo kači. Ne postoji bolji kriterijum prihvatanja za mogućnost binarnog formata od nezavisno napisanog čitača koji niste smeli menjati
Od čega se sastoji ugrađeni grafikon
Tri dela moraju da se slažu. Drawing sloj doprinosi oblik domaćin kontrole, sloj objekata doprinosi OBJ zapis čiji common object data deklariše tip objekta 5, a tok zapisa doprinosi sam chart substream. Opcione zastavice na OBJ zapisu su one koje Excel piše za chart okvir: positioned, locked, automatic line i automatic fill, i to je ono što ugrađeni grafikon čini da se ponaša kao nativni kad ga korisnik klikne
Sidro zaslužuje napomenu jer je čest izvor off-by-one bagova. HotXLS API uzima brojeve redova i kolona sa bazom jedan, u skladu sa ostatkom biblioteke, a client anchor upisan u datoteku je sa bazom nula. Konverzija se dešava unutar AddChartObject, pa pozivaoci ostaju u koordinatnom sistemu koji koriste svuda drugde, ali svako ko poredi hex dump sa svojim pozivom treba da se seti koju stranu te granice čita
var
Book: TXLSWorkbook;
Sheet: TXLSWorksheet;
Series: array[0..1] of TXLSChartSeriesInfo;
begin
Book := TXLSWorkbook.Create(nil);
try
Book.LoadFromFile('regional-sales.xls');
Sheet := Book.Sheets[0];
FillChar(Series, SizeOf(Series), 0);
Series[0].Name := 'Actual';
Series[0].Categories := 'Data!$A$2:$A$13';
Series[0].Values := 'Data!$B$2:$B$13';
Series[0].DataLabels.ShowValue := True;
Series[0].HasDataLabels := True;
Series[1].Name := 'Target';
Series[1].Categories := 'Data!$A$2:$A$13';
Series[1].Values := 'Data!$C$2:$C$13';
Series[1].SecondaryAxis := True;
// Sidrirano na E2:M20 na ovom listu, sa bazom jedan
Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
'Month', 'Amount', Series, 2, 5, 20, 13);
Book.SaveToFile('regional-sales-charted.xls');
finally
Book.Free;
end;
end;
FillChar nad nizom serija nije dekoracija. TXLSChartSeriesInfo nosi nekoliko opcionih podzapisa — data labele, stil po seriji, trendline i error bars — svaki vođen boolean-om, i delimično inicijalizovan zapis na steku će emitteru uručiti zastavice koje niko nije postavio. Ispraznite niz, pa postavite polja koja mislite
Koje reference serija prihvata ugrađena putanja?
Obične A1-stilske opsege unutar iste radne sveske, i to ograničenje je namerno, a ne previd. Svaka referenca se razrešava naspram spiska listova sveske i pretvara u indeks eksterne reference koji zapisi grafikona traže. Imenovani opseg ili referenca na eksternu svesku pada nazad na placeholder sa parsiranim izrazom nulte dužine, pa se grafikon piše čisto, ali ta konkretna serija nema izvor podataka dok je ne usmerite na opseg
Razlog je direktan inženjerski kompromis. Puna putanja kompajliranja referenci postoji na chart-sheet ruti, umotana unutar sloja kolekcije radnih listova, i njeno čisto izvlačenje značilo bi udvostručavanje sto linija logike razrešavanja za slučaj koji je u praksi redak. Ugrađeni grafikon gotovo uvek plotuje ćelije na svom listu ili srodnom listu podataka. Imenovane i eksterne reference su pokrivene na chart-sheet putanji preko AddChartSheet, pa ništa nije nedostupno, samo se stiže iz drugog ulaza
Sve ostalo u modelu serija radi identično na obe rute. Vezivanje sekundarne ose, stilovi linije, ispune i markera po seriji, trendlines, error bars i data labele svi su deo TXLSChartSeriesInfo i svi se emituju isto, pa definicija grafikona može da se preseli između ugrađenog objekta i chart sheet-a uz promenu samo poziva. Mehanika axis grupa iza zastavice sekundarne ose pokrivena je u članku o sekundarnim osnim grupama pri BIFF upisu
Zašto se naslov grafikona pročitao kao dva znaka?
Zato što je broj znakova prosleđen tamo gde se očekivao broj bajtova, i BIFF Unicode stringovi tu grešku čine lakom za upis a teškom za viđenje. Kratak BIFF Unicode string počinje brojem znakova i bajtom zastavica, a bajt zastavica nosi high-byte bit koji kaže da li je payload po jedan bajt po znaku ili po dva. Pročitajte 16-bitni payload sa brojem znakova kao da je dužina u bajtovima i dobićete tačno pola stringa: serija imenovana Sales vraća se kao Sa, i naslov grafikona se seče isto, jer naslovi i labele serija dele putanju dekodovanja
Ono što ovaj defekt čini zapaženim je što se ponovio tri puta u istoj familiji zapisa: jednom u imenima trendline, jednom u imenima pivot grafikona, i jednom u naslovima grafikona. Svaka pojava delovala je kao svež bag u novoj mogućnosti. Sve tri bile su isto izostavljeno množenje. Pravilo koje ga je konačno zatvorilo je mehaničko i treba ga primenjivati bez procene: kad god čitate jedan od ovih stringova, prvo pogledajte high-byte zastavicu i pomnožite broj znakova širinom payload-a pre nego što dirate bafer. Detalji na nivou zapisa su u članku o dekodovanju broja znakova XLUnicodeString i high-byte zastavice
// Ugrađeni grafikon deli drawing sloj sa slikama i oblicima,
// pa postojeći crtež na listu ostaje sačuvan. AddChartObject
// vraća indeks kreiranog objekta
var
ObjIndex: Integer;
begin
ObjIndex := Sheet.AddChartObject(xlsChartTypeLine, 'Trend',
'Week', 'Units', Series, 2, 8, 18, 16);
if ObjIndex < 0 then
raise Exception.Create('chart object was not created');
end;
Gde se ugrađeni grafikoni uklopuju naspram alternativa
Postoje tri rute i one odgovaraju na različita pitanja. Ugrađeni objekat grafikona pripada pored svojih podataka na radnom listu i to je ono što većina izveštaja želi. Chart sheet odgovara jednom prezentacionom vizuelnom prikazu i daje vam punu putanju kompajliranja referenci. Čuvanje postojećeg grafikona iz učitane datoteke netaknutog je pravi odgovor kad je radna sveska došla iz Excel-a sa formatiranjem koje niko ne želi da biblioteka ponovo tumači; to ponašanje propuštanja opisano je u članku o sačuvanim ChartML i kombinovanim grafikonima
Pošto ugrađeni grafikon jaše na drawing sloju, koegzistira sa slikama i oblicima na istom listu umesto da ih zamenjuje, i opšti model tog sloja pokriven je u članku o grafikonima, slikama i crtežima u HotXLS-u. Sve tri rute stižu u HotXLS Delphi spreadsheet komponenti, pa je izbor o tome kako izveštaj treba da izgleda, a ne o tome šta biblioteka ume da izrazi
Metodološka tačka je ona vredna čuvanja. Kad mogućnost binarnog formata ima postojeći čitač, gradite pisca naspram čitača, a ne naspram svog čitanja specifikacije. Čitač kodira godine kontakta sa datotekama koje su stvarne aplikacije proizvele, uključujući delove koje specifikacija izlaže labavo, i pisac koji njega zadovolji daleko je verovatnije da zadovolji i Excel