HotXLS može smjestiti grafikon izravno na radni list, sidren na raspon ćelija, umjesto da ga da na zasebni list grafikona. U BIFF8 terminima to znači zapisati drawing oblik s OBJ recordom tipa 5 i parkirati chart substream na kraj sheet record streama, što je točno raspored koji Excel proizvodi i točno mjesto gdje čitač očekuje da ga nađe
Razlika je bitna svakomu tko generira operativne izvještaje. List grafikona je sasvim dobar dom za jedan naslovni vizual. Mjesečni regionalni pregled želi grafikon pokraj brojeva koje sažima, na istom listu, dimenzioniran na blok ćelija kojem pripada, pa čitatelj skrola jednom umjesto da mijenja tabove i gubi kontekst
Čitanje je već postojalo, pisanje nije
Asimetriju vrijedi imenovati jer oblikuje posao. HotXLS je već umio čitati ugrađene grafikone: kad sheet record stream sadrži BOF označen kao chart substream, parser mijenja kontekst, prikuplja chart recorde i na zatvarajućem EOF ih vraća drawing obliku koji je OBJ record uveo. Tim je putem prošla svaka radna knjiga nastala u Excelu koju je biblioteka ikad otvorila
Nedostajala je autorska strana, i korisna posljedica je da je novi writer imao preciznu specifikaciju koju treba pogoditi: proizvesti byte raspored koji postojeći čitač već ponovno spaja. Ne postoji bolji acceptance kriterij za feature binarnog formata od neovisno napisanog čitača koji niste smjeli mijenjati
Od čega se sastoji ugrađeni grafikon
Tri komada se moraju slagati. Drawing sloj doprinosi host-control oblik, objektni sloj doprinosi OBJ record čiji common object data deklarira tip objekta 5, a record stream doprinosi sam chart substream. Option zastavice na OBJ recordu su one koje Excel piše za chart frame: positioned, locked, automatic line i automatic fill, i to je ono što ugrađeni grafikon čini da se ponaša kao nativan kad ga korisnik klikne
Sidro zaslužuje napomenu jer je čest izvor off-by-one bugova. HotXLS API uzima brojeve redaka i stupaca od jedan, u suglasju s ostatkom biblioteke, a client anchor zapisan u datoteku je zero-based. Konverzija se odvija unutar AddChartObject, pa pozivatelji ostaju u koordinatnom sustavu koji koriste posvuda drugdje, ali tko god uspoređuje hex dump sa svojim pozivom treba pamtiti 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;
// Sidro na E2:M20 na ovom listu, one-based
Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
'Month', 'Amount', Series, 2, 5, 20, 13);
Book.SaveToFile('regional-sales-charted.xls');
finally
Book.Free;
end;
end;
FillChar na series arrayu nije dekoracija. TXLSChartSeriesInfo nosi nekoliko neobaveznih sub-recorda, data labele, stil po seriji, trend linije i error barove, svaki iza boolean zastavice, i djelomično inicijaliziran record na stogu će emitteru predati zastavice koje nitko nije postavio. Zeroirajte array, pa postavite polja koja mislite
Koje reference serija ugrađeni put prihvaća?
Obične A1-stilom pisane raspone unutar iste radne knjige, i to ograničenje je namjerno a ne promašaj. Svaka se referenca razriješi protiv popisa listova radne knjige i pretvori u external reference indeks koji chart recordi trebaju. Imenovani raspon ili referenca na vanjsku radnu knjigu pada natrag na placeholder s parsed izrazom duljine nula, pa grafikon se piše čisto, ali ta serija nema izvor podataka dok je ne usmjerite na raspon
Razlog je direktan inženjerski trade. Pun put kompilacije referenci postoji na ruti list grafikona, umotan unutar worksheet-collection sloja, i izvaditi ga čisto značilo bi duplicirati sto linija resolution logike za slučaj koji je u praksi redak. Ugrađeni grafikon gotovo uvijek crta ćelije sa svog lista ili sestrinskog data lista. Imenovane i vanjske reference pokriva put list grafikona preko AddChartSheet, pa ništa nije nedostupno, samo se dolazi iz drugog entry pointa
Sve ostalo u modelu serija radi identično na obje rute. Vezivanje sekundarne osi, stil linije, ispune i markera po seriji, trend linije, error bars i data labele svi su dio TXLSChartSeriesInfo i svi se emitiraju isto, pa definicija grafikona može preseliti između ugrađenog objekta i list grafikona uz promjenu samo poziva. Mehaniku axis-groupa iza zastavice sekundarne osi pokriva sekundarne axis grupe pri BIFF zapisu
Zašto se naslov grafikona pročitao kao dva znaka?
Jer je broj znakova proslijeđen tamo gdje se očekivao broj bajtova, a BIFF Unicode stringovi tu grešku čine lako napisanom i teško vidljivom. Kratki BIFF Unicode string počinje brojem znakova i flags bajtom, a flags bajt nosi high-byte bit koji kaže je li payload jedan bajt po znaku ili dva. Pročitajte 16-bit payload s brojem znakova kao da je byte duljina i dobijete točno pola stringa: serija imenovana Sales vraća se kao Sa, i naslov grafikona se skraćuje isto jer naslovi i labele serija dijele decoding put
Ono što ovaj defekt čini zanimljivim je da se triput vratio u istoj familiji recorda, jednom u imenima trend linija, jednom u imenima pivot grafikona i jednom u naslovima grafikona. Svaka pojava izgledala je kao svjež bug u novoj mogućnosti. Sve tri bile su isto umnožavanje koje je nedostajalo. Pravilo koje ga je napokon zatvorilo je mehaničko i treba ga primijeniti bez suđenja: kad god čitate jedan od ovih stringova, prvo pogledajte high-byte zastavicu i pomnožite broj znakova širinom payloada prije nego dotaknete buffer. Detalji na razini recorda su u dekodiranju brojača znakova XLUnicodeStringa i high-byte zastavice
// Ugrađeni grafikon dijeli drawing sloj sa slikama i oblicima, pa
// postojeći drawing na listu ostaje sačuvan. AddChartObject vraća
// indeks stvorenog 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;
Gdje se ugrađeni grafikoni uklopaju u odnosu na alternative
Postoje tri rute i odgovaraju na različita pitanja. Ugrađeni chart objekt pripada pokraj svojih podataka na radnom listu i to je što većina izvještaja želi. List grafikona odgovara jednom prezentacijskom vizualu i daje pun put kompilacije referenci. Sačuvati postojeći grafikon iz učitane datoteke, netaknut, je pravi odgovor kad je radna knjiga došla iz Excela s formatiranjem koje nitko ne želi da biblioteka reinterpretira; to pass-through ponašanje opisano je u sačuvanom ChartML-u i combination grafikonima
Budući da ugrađeni grafikon jaše drawing sloj, koegzistira sa slikama i oblicima na istom listu umjesto da ih zamijeni, a opći model tog sloja pokriva grafikoni, slike i crteži u HotXLS-u. Sve tri rute isporučuje HotXLS Delphi spreadsheet komponenta, pa je izbor pitanje kako izvještaj treba izgledati, a ne što biblioteka može izraziti
Metodološka poanta je ona koju vrijedi zadržati. Kad feature binarnog formata ima postojeći čitač, gradite writer protiv čitača a ne protiv svog čitanja specifikacije. Čitač kodira godine kontakta s datotekama koje su stvarne aplikacije stvarno proizvele, uključujući dijelove koje specifikacija izriče labavo, i writer koji njega zadovolji daleko je veće vjerojatnosti da zadovolji i Excel