HotXLS BIFF8 diagramos antrinės ašies grupes rašo išvesdama antrą AxisParent bloką, o ne pridėdama antrą diagramų grupę po ašimis. Klasikinio XLS diagramos posrautyje kiekviena diagramų grupė – ChartFormat, diagramos tipo įrašas ir CrtLink – gyvena savo ašies grupės bloke, o kiekviena seka prie vienos jų prisijungia per SerToCrt. Supainiokite šį lizdavimą ir serijai nebeliks antros diagramų grupės, prie kurios ji galėtų prisijungti, nesvarbu, kiek ašių įrašų išvesite
Kodėl antra diagramų grupė po ašimis nieko nesusieja?
Visa atsakymo esmė yra gramatikoje, ir ji telpa į vieną ABNF eilutę. [MS-XLS] 2.1.7.20.1 taisyklė CHARTFOMATS sako AxesUsed 1*2AXISPARENT, o tada išdėsto AXISPARENT = AxisParent Begin Pos [AXES] 1*4CRT End. Perskaitę šias dvi produkcijas kartu matome formą: diagramų grupės yra ašies grupės vaikai, o ne jos seseriniai elementai. Diagramos posrautas su dviem ašių poromis ir viena gale esančia diagramų grupe nėra dviejų ašių diagrama su keistu maketu; tai diagrama su viena diagramų grupe ir našlaičių ašių įrašų rinkiniu. Tai svarbu, nes SerToCrt ($1045), esantis SERIESFORMAT bloke, turi nulinį diagramų grupės indeksą, o ne ašies indeksą. Įrašę crt = 1, kai egzistuoja tik vienas CRT blokas, nurodote grupei, kuri niekada nebuvo išvesta. Intuiciją klaidina įrašo pavadinimas: AXESUSED ($1046) skamba taip, lyg skaičiuotų ašis, todėl natūralu išvesti daugiau ašių. Jis skaičiuoja ašių grupes, o kiekviena ašių grupė atsineša visą braižymo sritį ir diagramų grupę
Serijos pažymėjimas antrinei ašies grupei
HotXLS pusėje tai susiveda į vieną Boolean. TXLSChartSeriesInfo turi SecondaryAxis lauką, o nustačius jį bet kuriai serijai masyve, kurį perduodate TXLSWorksheets.AddChartSheet, visas generatorius persijungia į dviejų grupių režimą. Atskiro iškvietimo „įjungti antrinę ašį“ ir ašių skaičiaus parametro nėra, nes skaičių galima išvesti: jei bent vienai serijai reikia antrinės grupės, diagramai reikia dviejų
var
Wb: TXLSWorkbook;
Series: array [0..1] of TXLSChartSeriesInfo;
begin
Wb := TXLSWorkbook.Create;
try
Wb.Sheets.Add.Name := 'Data';
// ... užpildome A1:C12 kategorijomis, pajamomis ir marža ...
Series[0] := Default(TXLSChartSeriesInfo); // niekada nenaudoti FillChar šiam įrašui
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 tampa 2
Wb.Sheets.AddChartSheet('Dual Axis', xlsChartTypeLine,
'Revenue vs Margin', '', '', Series);
Wb.SaveAs('dual-axis.xls', xlExcel97);
finally
Wb.Free;
end;
end;
Eilutė Default(TXLSChartSeriesInfo) nėra dekoracija. TXLSChartSeriesInfo jungia valdomus laukus (WideString vardus, dinaminius trendline ir error-bar masyvus) su paprastais Boolean nariais, o Delphi garantuoja, kad už jus išvalyti bus tik valdomi laukai. Palikus SecondaryAxis neinicializuotą, jo reikšmė priklauso nuo to, kas buvo steke, todėl praktiškai tas pats dvejetainis failas konsolės šeimininke sukuria vienos ašies diagramą, o testų vykdyklėje – dviejų. Tuo tarpu kategorijų ir reikšmių diapazonai išsprendžiami per darbaknygės EXTERNSHEET lentelę dar prieš generatoriui juos pamatant – tai ta pati indeksų mechanika, aprašyta kaip HotXLS klasifikuoja BIFF SupBook ir XTI išorines nuorodas – todėl diapazonas, nurodantis nežinomą lapą, tampa tuščiu BRAI vietos žymekliu, o ne sugadina buildą
Ką HotXLS išveda, kai serija yra antrinė?
Generatorius pakeičia formą, ne vien reikšmę. Kai antrinių serijų nėra, AXESUSED turi 1 (arba 0 pyrago ir 3D pyrago diagramoms, kurios apskritai neturi ašių grupių), o po jo eina vienas AxisParent blokas. Kai tokia serija yra, AXESUSED turi 2 ir generatorius bloką paleidžia du kartus, iax – pirmąjį 18 baitų AxisParent ($1041) naudingosios apkrovos žodį – nustatydamas iš pradžių į 0, tada į 1. Kiekvienas etapas išveda Pos, kategorijų ir reikšmių ašis (Axis, $101D), PlotArea žymeklį ($1035), numatytąjį Frame, tada ChartFormat ($1014), diagramos tipo įrašą, CrtLink ($1022) ir du End žymeklius diagramų bei ašių grupei uždaryti. Tada antrinė serija prisijungia su SerToCrt crt = 1, o pirminė išlaiko crt = 0. Vienas įrašas sąmoningai nedubliuojamas: legenda išvedama tik pirmoje grupėje, nes Excel diagramai suteikia vieną legendą, nesvarbu, kiek ašių grupių ji turi. Dar du dalykai verti aiškaus paminėjimo. Pertvarkius generatorių taip, kad diagramų grupė būtų AxisParent bloko viduje, įprastų diagramų išvestis nepasikeitė – kai antrinės serijos nėra, posrautas yra baitas po baito identiškas ankstesniam, nes AddAxisParent parametrizavimas su iax = 0 yra lygiai senasis kelias. Generatorius taip pat vis dar išveda pilną ašių porą kiekvienai grupei, todėl antrinė grupė visada atsineša savo kategorijų ašį, net jei rūpi tik jos reikšmių skalė
Kaip diagramų tikrinimas atkuria ašių grupės ryšį?
Skaitymas vyksta dviem etapais per įrašų sąrašą, ir kitaip negalima, nes AXESUSED ateina prieš aprašomus blokus. Pirmame etape žiūrima tik į $1046 ir jo pirmas žodis perskaitomas kaip ašių grupių skaičius. Ši reikšmė pradedama nuo 1 ir tik didinama, niekada nemažinama: HotXLS ima esamo skaičiaus ir deklaruoto skaičiaus maksimumą, todėl sugadintas ar pasikartojantis AXESUSED negali pabloginti diagramos, kuri jau buvo pamatyta deklaruojanti dvi grupes. Antrame etape sekama dabartinė ašių grupė, ji atnaujinama ties kiekvienu AxisParent, o šis indeksas įspaudžiamas į kiekvieną sutiktą Axis įrašą, kol pasirodo kitas AxisParent
var
Model: TXLSChartModel;
i: Integer;
begin
// Sheets[1] yra duomenų darbalapis, Sheets[2] – diagramų lapas
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;
Verta įvardyti du apribojimus. TXLSChartModel.AxisGroupCount praneša, ką failas deklaruoja, o ne kiek AxisParent blokų iš tikrųjų rasta; failas, sakantis 2 ir pateikiantis vieną bloką, praneš 2, o AxisCount yra vieta, kur tai pastebite. TXLSChartAxis.AxisGroup yra pozicinis antspaudas: jis įrašo, kuriame bloke ašis buvo perskaityta, o tai vienintelis dalykas, kurį formatas mums sako. Serijų pusėje SerToCrt dekodavimas įjungiamas tik esant Series blokui, nes tas pats įrašo ID pasitaiko kontekstuose, kuriuose jis nėra serijos ryšys, o dekoderis be šio vartų tikrinimo mielai perrašytų netinkamą seriją
Antrinių ašių tikrinimas be tikro Excel failo
Šiam tikrinimui nereikėjo Excel failo su antrine ašimi, ir būtent tai yra naudinga istorijos dalis. Struktūrinis dekodavimas yra įrašų sekos savybė, todėl sintetinė seka jį įrodo taip pat tiksliai kaip užfiksuota. Regresija sukuria AXESUSED su 2 reikšmės naudinga apkrova, tada du AxisParent blokus, kurių kiekvienas apgaubia kategorijų ir reikšmių ašį, ir tikrina, kad modelis grįžta su AxisGroupCount = 2, keturiomis ašimis, pažymėtomis 0, 0, 1, 1, ir tikėtinais ašių tipais antroje poroje
// Struktūrinis tikrinimas visiškai be Excel failo
Chart := TXLSCustomChart.Create(nil, $0600);
try
AddWordRecord($1046, [2]); // AXESUSED: dvi ašių grupės
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;
Jei sintetinius įrašus kuriate patys, verta žinoti dvi praktines pastabas. TXLSCustomChart.AddData(RecID, Len, nil) dereferencijuoja naudingąją apkrovą, kai Len nenulinis, todėl Begin ($1033) ir End ($1034) žymeklius reikia pridėti su nuliniu ilgiu, o ne su nil blobu ir pasenusiu ilgiu. Sintetinė seka įrodo dekoderį, bet ne Excel priima jūsų išvestį – rašymo pusė buvo sudėliota iš ABNF ir patikrinta per GetChartModel, tikrinant ašių antspaudus 0/0/1/1 ir serijų diagramų grupes 0/1, o baitas po baito identiškas kelias be antrinės grupės yra saugos tinklas. Tokia pat konservatyvi laikysena taikoma ir likusiam HotXLS diagramų, vaizdų ir piešinių palaikymui Delphi aplinkoje: dekoduoti tai, ką sako įrašai, ir atsisakyti spėti dvejetainį maketą, kurio neperskaitėte specifikacijoje. Visa Delphi rinkinio Win32 ir Win64 dalis po rašymo pusės įdiegimo išlaikė 1650 iš 1650 testų
Chart3d scenos parametrai ir fAuto spąstai
Dvi gretimos detalės įkanda tiems, kurie nueina toliau nei numatytoji diagrama. Pirmoji yra Chart3d ($103A, [MS-XLS] 2.4.46), plokščia 14 baitų naudingoji apkrova, išvedama diagramos grupėje 3D variantams: anRot (pasukimas, 0–360), anElev (aukštis, su ženklu, -90–90), pcDist (perspektyvos atstumas, 0–100, ignoruojamas, jei nenustatyta fPerspective), pcHeight ir pcDepth (diagramos pločio procentas, 5–500), pcGap (0–500) bei grbit, kurio bitai yra fPerspective $0001, fCluster $0002, fAutoscale $0004, f3DScaling $0010 ir f2DWalls $0020. Specifikacija prideda apribojimų, kurių įrašo maketas pats neužtikrina: transponuotoje juostinėje diagramoje anRot ir anElev neturi viršyti 44, o pyrago diagramoje anElev negali būti neigiamas
Antroji detalė yra fAuto bitas, ir jis sukelia pranešimą „mano spalvos buvo ignoruotos“. LineFormat ($1007), AreaFormat ($100A) ir MarkerFormat ($1009) visi turi fAuto savo grbit 0 bite, o nustačius šį bitą Excel taiko automatinį stilių ir šalia esančias aiškias RGB reikšmes, linijos stilių, žymeklio formą bei dydį traktuoja kaip dekoraciją. Bet kuris generatorius, rašantis pasirinktinį serijos stilių, turi išvalyti 0 bitą; numatytieji generatoriai palieka jį nustatytą būtent tam, kad Excel parinktų paletę. Jei redaguojate esamą darbaknygę, o ne ją kuriate, išsaugojimo taisyklės vėl kitokios ir aprašytos redaguojant Excel diagramas neprarandant išsaugoto ChartML
Antrinės ašių grupės, SerToCrt ryšys ir čia parodytas tipinis diagramos modelis pateikiami HotXLS Delphi skaičiuoklių komponente, skirtame Delphi ir C++Builder, kuris skaito ir rašo BIFF8 diagramas be įdiegto Excel; produkto puslapyje pateikta visa diagramos įrašų nuoroda ir AddChartSheet overload sąrašas