Το HotXLS μπορεί να βάλει γράφημα κατευθείαν σε φύλλο εργασίας, αγκυρωμένο σε εύρος κελιών, αντί να το βάλει σε αφιερωμένο chart sheet. Σε όρους BIFF8 αυτό σημαίνει εγγραφή σχήματος σχεδίασης με OBJ record τύπου 5 και στάθμευση της υποροής του γραφήματος στο τέλος της ροής records του φύλλου, που είναι ακριβώς η διάταξη που παράγει το Excel και ακριβώς εκεί όπου περιμένει ο reader να τη βρει
Η διάκριση μετράει για όποιον παράγει λειτουργικές αναφορές. Ένα chart sheet είναι καλή στέγη για ένα μοναδικό headline οπτικό. Μια μηνιαία περιφερειακή ανάλυση θέλει το γράφημα δίπλα στους αριθμούς που συνοψίζει, στο ίδιο φύλλο, διαστασιολογημένο στο block κελιών που ανήκει, ώστε ο αναγνώστης να κυλήσει μία φορά αντί να αλλάζει tabs και να χάνει το πλαίσιο
Η ανάγνωση υπήρχε ήδη, η εγγραφή όχι
Η ασυμμετρία αξίζει να ονομαστεί γιατί διαμορφώνει τη δουλειά. Το HotXLS μπορούσε ήδη να διαβάζει ενσωματωμένα γραφήματα: όταν η ροή records του φύλλου περιέχει BOF σημασμένο ως υποροή γραφήματος, ο parser αλλάζει πλαίσιο, συλλέγει τα chart records, και στο κλείσιμο του EOF τα παραδίδει πίσω στο σχήμα σχεδίασης που εισήγαγε το OBJ record. Εκείνο το μονοπάτι το είχε ασκήσει κάθε βιβλίο εργασίας γραμμένο από Excel που άνοιξε ποτέ η βιβλιοθήκη
Έλειπε η πλευρά συγγραφής, και η χρήσιμη συνέπεια είναι ότι ο νέος writer είχε ακριβή προδιαγραφή να πετύχει: παράγε τη διάταξη bytes που ο υπάρχων reader επανασυνδέει ήδη. Δεν υπάρχει καλύτερο κριτήριο αποδοχής για χαρακτηριστικό δυαδικής μορφής από έναν ανεξάρτητα γραμμένο reader που δεν είχες το δικαίωμα να αλλάξεις
Από τι αποτελείται ένα ενσωματωμένο γράφημα
Τρία κομμάτια πρέπει να συμφωνούν. Το στρώμα σχεδίασης συνεισφέρει σχήμα host-control, το στρώμα αντικειμένων συνεισφέρει OBJ record του οποίου τα common object data δηλώνουν object type 5, και η ροή records συνεισφέρει την ίδια την υποροή γραφήματος. Τα option flags του OBJ record είναι όσα γράφει το Excel για πλαίσιο γραφήματος: positioned, locked, automatic line και automatic fill, που είναι όσα κάνουν το ενσωματωμένο γράφημα να συμπεριφέρεται ως εγγενές όταν το κάνει κλικ ένας χρήστης
Η άγκυρα αξίζει σημείωση γιατί είναι κοινή πηγή off-by-one bugs. Το API του HotXLS παίρνει αριθμούς γραμμών και στηλών με βάση το ένα, σε ευθυγράμμιση με την υπόλοιπη βιβλιοθήκη, και η client anchor που γράφεται στο αρχείο είναι με βάση το μηδέν. Η μετατροπή γίνεται μέσα στην AddChartObject, ώστε οι callers μένουν στο σύστημα συντεταγμένων που χρησιμοποιούν παντού αλλού, αλλά όποιος συγκρίνει hex dump με τη δική του κλήση πρέπει να θυμάται από ποια πλευρά εκείνου του ορίου διαβάζει
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;
// Αγκυρωμένο στο E2:M20 πάνω σε αυτό το φύλλο, με βάση το ένα
Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
'Month', 'Amount', Series, 2, 5, 20, 13);
Book.SaveToFile('regional-sales-charted.xls');
finally
Book.Free;
end;
end;
Το FillChar στον πίνακα series δεν είναι διακόσμηση. Η TXLSChartSeriesInfo κουβαλά αρκετά προαιρετικά sub-records, data labels, στυλ ανά series, trendlines και error bars, το καθένα με πύλη boolean, και ένα μερικώς αρχικοποιημένο record στη στοίβα θα παραδώσει στον emitter flags που δεν έθεσε κανείς. Μηδενίστε τον πίνακα, μετά ορίστε τα πεδία που εννοείτε
Ποιες αναφορές series δέχεται το ενσωματωμένο μονοπάτι;
Σκέτα εύρη σε στυλ A1 μέσα στο ίδιο βιβλίο εργασίας, και εκείνος ο περιορισμός είναι σκόπιμος και όχι παράλειψη. Κάθε αναφορά επιλύεται απέναντι στη λίστα φύλλων του βιβλίου και γίνεται ο δείκτης εξωτερικής αναφοράς που θέλουν τα chart records. Ένα named range ή μια αναφορά εξωτερικού βιβλίου πέφτει σε placeholder με parsed παράσταση μηδενικού μήκους, οπότε το γράφημα γράφεται καθαρά αλλά εκείνη η συγκεκριμένη series δεν έχει πηγή δεδομένων μέχρι να τη στρέψετε σε εύρος
Ο λόγος είναι ευθύς μηχανικός διακανονισμός. Η πλήρης διαδρομή μεταγλώττισης αναφορών υπάρχει στη διαδρομή chart sheet, τυλιγμένη μέσα στο στρώμα συλλογής worksheets, και η καθαρή εξαγωγή της θα σήμαινε αντιγραφή εκατό γραμμών λογικής επίλυσης για μια περίπτωση ασυνήθιστη στην πράξη. Ένα ενσωματωμένο γράφημα σχεδόν πάντα σχεδιάζει κελιά στο δικό του φύλλο ή σε αδερφό φύλλο δεδομένων. Named και εξωτερικές αναφορές καλύπτονται στη διαδρομή chart sheet μέσω AddChartSheet, οπότε τίποτα δεν είναι απρόσιτο, απλώς φτάνει από διαφορετικό σημείο εισόδου
Όλα τα άλλα στο μοντέλο series δουλεύουν πανομοιότυπα και στις δύο διαδρομές. Δέσιμο δευτερεύοντος άξονα, γραμμή, fill και στυλ markers ανά series, trendlines, error bars και data labels είναι όλα μέρος της TXLSChartSeriesInfo και όλα εκπέμπονται με τον ίδιο τρόπο, ώστε ένας ορισμός γραφήματος να μετακινείται ανάμεσα σε ενσωματωμένο αντικείμενο και chart sheet με αλλαγή μόνο της κλήσης. Η μηχανική των axis groups πίσω από τη σημαία δευτερεύοντος άξονα καλύπτεται στα secondary axis groups σε εγγραφή BIFF
Γιατί ο τίτλος του γραφήματος διαβάστηκε ως δύο χαρακτήρες;
Επειδή πλήθος χαρακτήρων πέρασε εκεί όπου αναμενόταν πλήθος bytes, και οι συμβολοσειρές BIFF Unicode κάνουν αυτό το λάθος εύκολο να γραφτεί και δύσκολο να φανεί. Μια σύντομη συμβολοσειρά BIFF Unicode αρχίζει με πλήθος χαρακτήρων και byte σημαιών, και το byte σημαιών κουβαλά το bit high-byte που λέει αν το payload είναι ένα byte ανά χαρακτήρα ή δύο. Διαβάστε payload 16-bit με το πλήθος χαρακτήρων σαν να ήταν μήκος bytes και παίρνετε ακριβώς τη μισή συμβολοσειρά: μια series ονόματι Sales γυρίζει ως Sa, και τίτλος γραφήματος περικόπτεται με τον ίδιο τρόπο επειδή τίτλοι και ετικέτες series μοιράζονται το μονοπάτι αποκωδικοποίησης
Όσο κάνει το ελάττωμα αξιοπρόσεκτο είναι ότι επανεμφανίστηκε τρεις φορές στην ίδια οικογένεια records, μία στα ονόματα trendlines, μία στα ονόματα pivot charts, και μία σε τίτλους γραφημάτων. Κάθε εμφάνιση έμοιαζε με φρέσκο bug σε νέο χαρακτηριστικό. Και τα τρία ήταν ο ίδιος λείπων πολλαπλασιασμός. Ο κανόνας που τελικά το έκλεισε είναι μηχανικός και πρέπει να εφαρμόζεται χωρίς κρίση: όποτε διαβάζετε μία από αυτές τις συμβολοσειρές, συμβουλευτείτε πρώτα τη σημαία high-byte και πολλαπλασιάστε το πλήθος χαρακτήρων με το πλάτος payload προτού ακουμπήσετε το buffer. Οι λεπτομέρειες επιπέδου record είναι στο αποκωδικοποίηση πλήθους χαρακτήρων XLUnicodeString και της σημαίας high-byte
// Το ενσωματωμένο γράφημα μοιράζεται το στρώμα σχεδίασης με εικόνες
// και σχήματα, ώστε υπάρχον σχέδιο πάνω στο φύλλο διατηρείται. Η
// AddChartObject γυρνά τον δείκτη του δημιουργημένου αντικειμένου
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;
Που χωράνε τα ενσωματωμένα γραφήματα απέναντι στις εναλλακτικές
Υπάρχουν τρεις διαδρομές και απαντούν διαφορετικές ερωτήσεις. Ένα ενσωματωμένο αντικείμενο γραφήματος ανήκει δίπλα στα δεδομένα του πάνω σε φύλλο εργασίας και είναι όσο θέλουν οι περισσότερες αναφορές. Ένα chart sheet ταιριάζει σε ένα μοναδικό οπτικό παρουσίασης και σας δίνει την πλήρη διαδρομή μεταγλώττισης αναφορών. Η διατήρηση υπάρχοντος γραφήματος από φορτωμένο αρχείο, ανέγγιχτο, είναι η σωστή απάντηση όταν το βιβλίο ήρθε από Excel με μορφοποίηση που κανείς δεν θέλει να επερμηνεύσει η βιβλιοθήκη· εκείνη η συμπεριφορά pass-through περιγράφεται στα διατηρημένα ChartML και combination charts
Επειδή το ενσωματωμένο γράφημα ιππεύει το στρώμα σχεδίασης, συνυπάρχει με εικόνες και σχήματα στο ίδιο φύλλο αντί να τα αντικαθιστά, και το γενικό μοντέλο για εκείνο το στρώμα καλύπτεται στα γραφήματα, εικόνες και σχέδια στο HotXLS. Και οι τρεις διαδρομές παραδίδονται στο HotXLS Delphi spreadsheet component, οπότε η επιλογή αφορά το πώς πρέπει να μοιάζει η αναφορά και όχι τι μπορεί να εκφράσει η βιβλιοθήκη
Η μεθοδολογική ιδέα είναι όσο αξίζει να κρατηθεί. Όταν ένα χαρακτηριστικό δυαδικής μορφής έχει υπάρχοντα reader, χτίστε τον writer απέναντι στον reader και όχι απέναντι στην ανάγνωσή σας της προδιαγραφής. Ο reader κωδικοποιεί χρόνια επαφής με αρχεία που παρήγαν πραγματικά εφαρμογές, συμπεριλαμβανομένων των μερών που η προδιαγραφή δηλώνει χαλαρά, και ένας writer που τον ικανοποιεί είναι πολύ πιο πιθανό να ικανοποιήσει και το Excel