HotXLS sekundarne skupine osi grafikona BIFF8 zapiše tako, da odda drugi blok AxisParent, ne tako, da za osi doda drugo skupino grafikona. V podtoku grafikona Classic XLS vsaka skupina grafikona — ChartFormat, zapis vrste grafikona in CrtLink — živi znotraj lastnega bloka skupine osi, vsaka serija pa se na eno veže prek SerToCrt. Obrnite to ugnezdenost in za serijo ni druge skupine grafikona, na katero bi se lahko vezala, ne glede na to, koliko zapisov osi oddate
Zakaj druga skupina grafikona za osema ne veže ničesar?
Slovnica je celoten odgovor in je ena vrstica ABNF-ja. Pravilo CHARTFOMATS v [MS-XLS] 2.1.7.20.1 pravi AxesUsed 1*2AXISPARENT, nato pa zapiše AXISPARENT = AxisParent Begin Pos [AXES] 1*4CRT End. Preberite ti produkciji skupaj in oblika postane jasna: skupine grafikonov so otroci skupine osi, ne njeni sorodniki. Podtok grafikona z dvema paroma osi in eno končno skupino grafikona ni grafikon z dvojno osjo in posebnostjo postavitve, temveč grafikon z eno skupino grafikona in množico osirotelih zapisov osi. To je pomembno, ker SerToCrt ($1045), ki sedi znotraj bloka SERIESFORMAT, vsebuje ničelni indeks skupine grafikona, ne indeksa osi. Če zapišete crt = 1, ko obstaja samo en blok CRT, serijo usmerite na skupino grafikona, ki ni bila nikoli oddana. Intuicija, ki ljudi ujame, je ime zapisa: AXESUSED ($1046) zveni, kot da šteje osi, zato je naravni naslednji korak oddati več osi. V resnici šteje skupine osi in vsaka skupina osi s seboj prinese celotno območje izrisa ter skupino grafikona
Označevanje serije za sekundarno skupino osi
Na strani HotXLS se to skrči na eno logično vrednost. TXLSChartSeriesInfo vsebuje polje SecondaryAxis, njegova nastavitev na kateri koli seriji v polju, ki ga posredujete TXLSWorksheets.AddChartSheet, pa celoten graditelj preklopi v način dveh skupin. Ločen klic »omogoči sekundarno os« in parameter za število osi ne obstajata, ker je število mogoče izpeljati: če katera koli serija želi sekundarno skupino, grafikon potrebuje dve
var
Wb: TXLSWorkbook;
Series: array [0..1] of TXLSChartSeriesInfo;
begin
Wb := TXLSWorkbook.Create;
try
Wb.Sheets.Add.Name := 'Data';
// ... zapolni A1:C12 s kategorijami, prihodkom in maržo ...
Series[0] := Default(TXLSChartSeriesInfo); // tega zapisa nikoli ne FillChar
Series[0].Name := 'Revenue';
Series[0].Categories := 'Data!$A$1:$A$12';
Series[0].Values := 'Data!$B$1:$B$12';
Series[1] := Default(TXLSChartSeriesInfo);
Series[1].Name := 'Margin';
Series[1].Categories := 'Data!$A$1:$A$12';
Series[1].Values := 'Data!$C$1:$C$12';
Series[1].SecondaryAxis := True; // AXESUSED postane 2
Wb.Sheets.AddChartSheet('Dual Axis', xlsChartTypeLine,
'Revenue vs Margin', '', '', Series);
Wb.SaveAs('dual-axis.xls', xlExcel97);
finally
Wb.Free;
end;
end;
Vrstica Default(TXLSChartSeriesInfo) ni okras. TXLSChartSeriesInfo združuje upravljana polja (imena WideString, dinamična polja trendnih črt in stolpcev napak) z navadnimi člani Boolean, Delphi pa jamči le, da bo upravljana polja počistil namesto vas. Če SecondaryAxis pustite neinicializirano, je njegova vrednost odvisna od sklada, kar v praksi pomeni, da ista binarna datoteka ustvari grafikon z eno osjo, ko jo zaženete iz konzolnega gostitelja, in grafikon z dvema osema pod testnim izvajalnikom. Razpona kategorij in vrednosti se medtem razrešita prek tabele EXTERNSHEET delovnega zvezka, še preden ju graditelj vidi — isti mehanizem indeksov, ki je obravnavan v članku kako HotXLS razvršča zunanje povezave SupBook in XTI BIFF — zato se razpon z neznanim listom poslabša v prazen nadomestni BRAI, namesto da bi gradnja odpovedala
Kaj odda HotXLS, ko je serija sekundarna
Oddajnik spremeni obliko, ne samo vrednosti. Brez sekundarne serije ima AXESUSED vrednost 1 (oziroma 0 pri tortnem in 3D-tortnem grafikonu, ki sploh nimata skupin osi), nato pa sledi en blok AxisParent. Z eno sekundarno serijo ima AXESUSED vrednost 2 in graditelj blok izvede dvakrat, pri čemer je iax — prva beseda 18-bajtnega tovora AxisParent ($1041) — najprej 0 in nato 1. Vsak prehod odda Pos, os kategorij in os vrednosti (Axis, $101D), oznako PlotArea ($1035), privzeti Frame, nato ChartFormat ($1014), zapis vrste grafikona, CrtLink ($1022) in dve oznaki End, ki zapreta skupino grafikona in skupino osi. Sekundarna serija se nato veže z SerToCrt crt = 1, primarna pa ohrani crt = 0. En zapis se namerno ne podvoji: legenda se odda samo v prvi skupini, ker Excel grafikonu dodeli eno legendo, ne glede na število skupin osi. Še dve lastnosti je vredno povedati jasno. Prestrukturiranje oddajnika, ki je skupino grafikona postavilo znotraj bloka AxisParent, ni spremenilo izhoda običajnih grafikonov — brez sekundarne serije je podtok bajtno enak prejšnji različici, saj je parametriziranje AddAxisParent z iax = 0 natanko stara pot kode. Graditelj še vedno odda celoten par osi na skupino, zato sekundarna skupina vedno prispe z lastno osjo kategorij, tudi ko vas zanima samo njena lestvica vrednosti
Kako pregled grafikona obnovi povezavo s skupino osi?
Branje poteka v dveh prehodih čez seznam zapisov in tako mora biti, ker AXESUSED prispe pred bloki, ki jih opisuje. Prvi prehod išče samo $1046 in njegovo prvo besedo prebere kot število skupin osi. Vrednost se začne pri 1 in se samo poveča, nikoli zmanjša: HotXLS vzame največjo vrednost trenutnega števila in prijavljene, tako da napačen ali podvojen AXESUSED ne more pokvariti grafikona, za katerega je bilo že ugotovljeno, da prijavlja dve skupini. Drugi prehod sledi trenutni skupini osi, jo posodobi pri vsakem AxisParent in ta indeks odtisne na vsak zapis Axis, na katerega naleti, vse do naslednjega AxisParent
var
Model: TXLSChartModel;
i: Integer;
begin
// Sheets[1] je podatkovni delovni list, Sheets[2] list grafikona
Model := Wb.Sheets[2]._Chart.GetChartModel;
try
if Model.AxisGroupCount = 2 then
Writeln('AXESUSED declares a secondary axis group');
for i := 0 to Model.AxisCount - 1 do
Writeln('axis ', i, ' group ', Model.GetAxis(i).AxisGroup);
for i := 0 to Model.SeriesCount - 1 do
Writeln('series ', i, ' chart group ', Model.GetSeries(i).ChartGroup);
finally
Model.Free;
end;
end;
Vredno je poimenovati dve omejitvi. TXLSChartModel.AxisGroupCount poroča, kaj datoteka prijavlja, ne koliko blokov AxisParent je bilo dejansko najdenih; datoteka, ki pravi 2 in pošlje en blok, bo poročala 2, mesto, kjer to opazite, pa je AxisCount. Poleg tega je TXLSChartAxis.AxisGroup položajni odtis: zabeleži, znotraj katerega bloka je bila os prebrana, kar je edino, kar vam format pove. Na strani serij je dekodiranje SerToCrt omejeno na čas znotraj bloka Series, ker se isti ID zapisa pojavlja v kontekstih, kjer ni vezava serije, neomejeni dekodirnik pa bi z veseljem prepisal napačno serijo
Preverjanje sekundarnih osi brez prave datoteke Excel
Preverjanje tukaj ni potrebovalo datoteke Excel s sekundarno osjo in prav to je uporabni del zgodbe. Strukturno dekodiranje je lastnost zaporedja zapisov, zato jo sintetizirano zaporedje dokaže enako dobro kot zajeto. Regresija zgradi AXESUSED s tovorom 2, nato dva bloka AxisParent, ki vsak ovijeta os kategorij in os vrednosti, ter preveri, da se model vrne z AxisGroupCount = 2, štirimi osmi z odtisi 0, 0, 1, 1 in pričakovanimi vrstami osi na drugem paru
// Strukturno preverjanje brez kakršne koli datoteke Excel
Chart := TXLSCustomChart.Create(nil, $0600);
try
AddWordRecord($1046, [2]); // AXESUSED: dve skupini osi
AddAxisParentGroup(0); // AxisParent iax=0 + Begin + 2 Axis + End
AddAxisParentGroup(1); // AxisParent iax=1 + Begin + 2 Axis + End
Model := Chart.GetChartModel;
Assert.AreEqual(2, Model.AxisGroupCount);
Assert.AreEqual(4, Model.AxisCount);
Assert.AreEqual(0, Model.GetAxis(1).AxisGroup);
Assert.AreEqual(1, Model.GetAxis(2).AxisGroup);
finally
Model.Free;
Chart.Free;
end;
Če zapise sintetizirate sami, sta pomembni dve praktični opombi. TXLSCustomChart.AddData(RecID, Len, nil) pri neničelni vrednosti Len dereferencira tovor, zato je treba oznaki Begin ($1033) in End ($1034) dodati z dolžino 0, ne z ničelnim blobom in zastarelo dolžino. Sintetično zaporedje poleg tega dokaže dekodirnik, nikoli pa Excelovega sprejema vašega izhoda — zapisovalna stran je bila strukturirana iz ABNF-ja in nato preverjena s povratnim branjem prek GetChartModel, s preverjanjem odtisov osi 0/0/1/1 in skupin grafikonov serij 0/1, pri čemer je bajtno enaka pot brez sekundarne osi varnostna mreža. To je isto konservativno stališče, na katerem temelji preostala podpora HotXLS za grafikone, slike in risbe v Delphiju: dekodirajte, kar pravijo zapisi, in ne ugibajte binarne postavitve, ki je niste prebrali v specifikaciji. Celotna zbirka Delphi je po vključitvi zapisovalne strani na Win32 in Win64 izvedla 1650 od 1650 testov
Parametri prizora Chart3d in past fAuto
Dve sosednji podrobnosti ugrizneta tiste, ki gredo dlje od privzetega grafikona. Prva je Chart3d ($103A, [MS-XLS] 2.4.46), ploski 14-bajtni tovor, oddan znotraj skupine grafikona pri 3D-različicah: anRot (zasuk, 0 do 360), anElev (višina, predznačena, -90 do 90), pcDist (perspektivna razdalja, 0 do 100, prezrta, razen če je nastavljen fPerspective), pcHeight in pcDepth (odstotek širine grafikona, 5 do 500), pcGap (0 do 500) ter grbit, katerega biti so fPerspective $0001, fCluster $0002, fAutoscale $0004, f3DScaling $0010 in f2DWalls $0020. Specifikacija dodaja omejitve, ki jih postavitev zapisa sama ne bo uveljavila: pri prečnem stolpčnem grafikonu anRot in anElev ne smeta preseči 44, pri tortnem grafikonu pa anElev ne sme biti negativen
Druga je bit fAuto, ki ustvari prijavo napake »moje barve so bile prezrte«. LineFormat ($1007), AreaFormat ($100A) in MarkerFormat ($1009) vsi nosijo fAuto v bitu 0 svojega grbit, in ko je ta bit nastavljen, Excel uporabi samodejni slog ter izrecne vrednosti RGB, slog črte, obliko oznake in velikost oznake obravnava kot okras. Vsak oddajnik, ki zapisuje slog serije po meri, mora bit 0 počistiti; privzeti oddajniki ga ohranjajo nastavljenega prav zato, da Excel izbere paleto. Če urejate obstoječi delovni zvezek namesto gradnje novega, se pravila ohranjanja znova razlikujejo in so opisana v članku urejanje grafikonov Excel brez izgube ohranjenega ChartML
Sekundarne skupine osi, vezava SerToCrt in tipizirani model grafikona, prikazan tukaj, so del komponente HotXLS Delphi spreadsheet za Delphi in C++Builder, ki bere in zapisuje grafikone BIFF8 brez nameščenega Excela; stran izdelka vsebuje popoln pregled zapisov grafikona in seznam preobremenitev AddChartSheet