HotXLS kan plassere et diagram direkte på et regneark, forankret til et celleområde, i stedet for å legge det på et eget diagramark. I BIFF8-termer betyr det å skrive en tegningsshape med en OBJ-post av type 5 og parkere diagramsubstreamen på slutten av poststrømmen til arket, noe som er nøyaktig oppsettet Excel produserer og nøyaktig der leseren forventer å finne det
Skillet betyr noe for alle som genererer driftsrapporter. Et diagramark er et fint hjem for ett enkelt hovedvisual. En månedlig regional oppdeling vil ha diagrammet ved siden av tallene det oppsummerer, på samme ark, dimensjonert til celleblokken det hører til, så en leser ruller én gang i stedet for å bytte fane og miste konteksten
Lesingen var allerede der, skrivingen var ikke det
Asymmetrien er verdt å navngi fordi den former arbeidet. HotXLS kunne allerede lese innebygde diagrammer: når poststrømmen til regnearket inneholder en BOF merket som en diagramsubstream, bytter parseren kontekst, samler diagrampostene, og ved den avsluttende EOF gir den dem tilbake til tegningsshapen som OBJ-posten introduserte. Den veien var blitt brukt av hver Excel-genererte arbeidsbok biblioteket noen gang åpnet
Det som manglet, var forfattersiden, og den nyttige konsekvensen er at den nye skriveren hadde en presis spesifikasjon å treffe: produser byte-oppsettet den eksisterende leseren allerede fester på igjen. Det finnes ikke noe bedre akseptansekriterium for en binærformatfunksjon enn en uavhengig skrevet leser du ikke fikk lov til å endre
Hva et innebygd diagram består av
Tre brikker må være enige. Tegnelaget bidrar med en vertskontroll-shape, objektlaget bidrar med en OBJ-post hvis vanlige objektdata deklarerer objekttype 5, og poststrømmen bidrar med diagramsubstreamen selv. Valgflaggene på OBJ-posten er de Excel skriver for en diagramramme: posisjonert, låst, automatisk linje og automatisk fyll, noe som er det som gjør at det innebygde diagrammet oppfører seg som et innfødt når en bruker klikker på det
Forankringen fortjener en merknad fordi den er en vanlig kilde til off-by-one-feil. HotXLS API tar rad- og kolonnenumre fra én, i tråd med resten av biblioteket, og klientforankringen som skrives inn i filen, er nullbasert. Konverteringen skjer inne i AddChartObject, så kallere forblir i koordinatsystemet de bruker alle andre steder, men alle som sammenligner en hex-dump mot sitt eget kall, må huske hvilken side av den grensen de leser
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;
// Forankret til E2:M20 på dette arket, én-basert
Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
'Month', 'Amount', Series, 2, 5, 20, 13);
Book.SaveToFile('regional-sales-charted.xls');
finally
Book.Free;
end;
end;
FillChar på serie-arrayen er ikke dekorasjon. TXLSChartSeriesInfo bærer flere valgfrie underposter, datamerkelapper, stil per serie, trendlinjer og feilindikatorer, hver portet av en boolsk verdi, og en delvis initialisert post på stabelen vil gi emitteren flagg ingen satte. Nullstill arrayen, og sett så feltene du mener
Hvilke seriereferanser godtar den innebygde veien?
Rene A1-stil-områder inne i samme arbeidsbok, og den begrensningen er bevisst snarere enn et tilsyn. Hver referanse løses mot arbeidsbokens arkeliste og gjøres om til den eksterne referanseindeksen diagrampostene trenger. Et navngitt område eller en ekstern arbeidsbokreferanse faller tilbake til en plassholder med et uttrykk av null lengde, så diagrammet skrives rent, men den serien har ingen datakilde før du peker den mot et område
Grunnen er en rett fram ingeniøravveining. Den fullstendige referanseskompileringsveien finnes på diagramark-ruten, innhyllet i arksamling-laget, og å løfte den ren ut ville bety å duplisere hundre linjer med oppløsningslogikk for et tilfelle som er uvanlig i praksis. Et innebygd diagram plotter nesten alltid celler på sitt eget ark eller et søskendataark. Navngitte og eksterne referanser er dekket på diagramark-veien via AddChartSheet, så ingenting er utilgjengelig, bare nådd fra et annet inngangspunkt
Alt annet i seriemodellen fungerer identisk på begge ruter. Sekundær akse-binding, linje, fyll og markørstiler per serie, trendlinjer, feilindikatorer og datamerkelapper er alle del av TXLSChartSeriesInfo og emitteres alle på samme måte, så en diagramdefinisjon kan flytte mellom et innebygd objekt og et diagramark med bare kallet endret. Aksegruppe-mekanikken bak sekundær akse-flagget er dekket i sekundære aksegrupper ved BIFF-skriving
Hvorfor ble diagramtittelen lest som to tegn?
Fordi et tegnantall ble sendt der et byteantall ble forventet, og BIFF Unicode-strenger gjør den feilen lett å skrive og vanskelig å se. En kort BIFF Unicode-streng begynner med et tegnantall og en flaggbyte, og flaggbyten bærer high-byte-biten som sier om nyttelasten er én byte per tegn eller to. Les en 16-bits nyttelast med tegnantallet som om det var en bytelengde, og du får nøyaktig halve strengen: en serie kalt Sales kommer tilbake som Sa, og en diagramtittel avkortes på samme måte fordi titler og seriemerkelapper deler dekodeveien
Det som gjør denne defekten bemerkelsesverdig, er at den gjentok seg tre ganger i samme postfamilie, én gang i trendlinjenavn, én gang i pivotdiagramnavn, og én gang i diagramtitler. Hvert tilfelle så ut som en fersk feil i en ny funksjon. Alle tre var det samme manglende multiplikasjonen. Regelen som til slutt lukket den, er mekanisk og bør anvendes uten skjønn: når du leser en av disse strengene, sjekk high-byte-flagget først og multipliser tegnantallet med nyttelastbredden før du rører bufferen. Postnivådetaljene er i dekoding av XLUnicodeString-tegnantall og high-byte-flagget
// Det innebygde diagrammet deler tegnelaget med bilder og shaper,
// så en eksisterende tegning på arket bevares. AddChartObject
// returnerer indeksen til det opprettede objektet
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;
Hvor innebygde diagrammer passer i forhold til alternativene
Tre ruter finnes, og de svarer på ulike spørsmål. Et innebygd diagramobjekt hører hjemme ved dataene sine på et regneark og er det de fleste rapporter vil ha. Et diagramark passer for ett presentasjonsvisual og gir deg den fullstendige referanseskompileringsveien. Å bevare et eksisterende diagram fra en innlastet fil, urørt, er det riktige svaret når arbeidsboken kom fra Excel med formatering ingen vil ha et bibliotek til å re-tolke; den gjennomgangsatferden er beskrevet i bevart ChartML og kombinasjonsdiagrammer
Fordi det innebygde diagrammet rir tegnelaget, eksisterer det side om side med bilder og shaper på samme ark i stedet for å erstatte dem, og den generelle modellen for det laget er dekket i diagrammer, bilder og tegninger i HotXLS. Alle tre ruter følger med i HotXLS Delphi regnearkkomponent, så valget handler om hvordan rapporten skal se ut snarere enn om hva biblioteket kan uttrykke
Det metodiske poenget er det verdt å ta vare på. Når en binærformatfunksjon har en eksisterende leser, bygg skriveren mot leseren i stedet for mot din lesning av spesifikasjonen. Leseren koder år med kontakt med filer ekte applikasjoner faktisk produserte, inkludert delene spesifikasjonen sier noe løst om, og en skriver som tilfredsstiller den, er langt mer sannsynlig å også tilfredsstille Excel