PDF izveštaju je često potreban grafikon, a ako pregledate HotPDF paletu u potrazi za komponentom grafikona, nećete je naći. U biblioteci ne postoji objekat grafikona. Da biste postavili stubičasti, linijski ili kružni grafikon na stranicu, crtate ga sami koristeći vektorske primitive: Rectangle, LineTo i Circle. Iako to zvuči kao više posla nego postavljanje gotove komponente, pruža vam potpunu kontrolu nad veličinom fajla i renderovanjem. Eksterni motori za grafikone često izvoze tako što grafikon pretvore u rastersku sliku, što naduvava PDF i pikselizuje se pri štampanju. Crtanje pomoću primitiva proizvodi čistu vektorsku akustiku koja se skalira beskonačno i zauzima samo nekoliko kilobajta. Trud se ne ulaže u same pozive za crtanje, već u koordinatnu matematiku koja mapira vaše tačke podataka na stranicu.
Ovaj članak pokriva to koordinatno mapiranje i pruža kod za crtanje tri najčešća tipa grafikona.
Matematika mreže: mapiranje podataka u tačke
Pre nego što nacrtate ijednu liniju, morate definisati uokvirujući kvadrat (bounding box) na stranici gde će grafikon živeti, i izračunati faktore skaliranja za mapiranje vrednosti vaših podataka u tačke. Koordinatni sistem, kao što je objašnjeno u vodiču za crtanje po kanvasu, postavlja (0,0) u donji levi ugao stranice.
Za oblast grafikona definisanu sa Left, Bottom, Width i Height, prostor podataka se mapira na sledeći način:
- X se mapira iz indeksa podataka (0 do N-1) u tačke:
X_point = Left + (Index * (Width / (N - 1))) - Y se mapira iz vrednosti podataka (MinVal do MaxVal) u tačke:
Y_point = Bottom + ((Val - MinVal) * (Height / (MaxVal - MinVal)))
Korišćenje namenske pomoćne funkcije za ovo mapiranje održava vaše petlje za crtanje čitljivim.
1. Crtanje stubičastog grafikona
Stubičasti grafikon predstavlja vrednosti podataka kao vertikalne stubce. Matematika mora izračunati širinu svakog stubca i razmak između njih (gap) tako da se tačno uklapaju u širinu grafikona.
procedure DrawBarChart(Pdf: THotPDF; const Data: array of Double;
const Left, Bottom, Width, Height: Double);
var
I: Integer;
BarWidth, Gap, MaxVal, ValHeight: Double;
begin
MaxVal := 100.0; // scale against a known maximum
Gap := 10.0; // spacing between bars
BarWidth := (Width - (Gap * (Length(Data) + 1))) / Length(Data);
Pdf.CurrentPage.FillColor := RGB(70, 130, 180); // steel blue
Pdf.CurrentPage.StrokeColor := clBlack;
Pdf.CurrentPage.LineWidth := 1;
for I := 0 to High(Data) do
begin
ValHeight := (Data[I] / MaxVal) * Height;
// X = Left + Gap + spacing for previous bars
Pdf.CurrentPage.Rectangle(
Left + Gap + (I * (BarWidth + Gap)),
Bottom,
BarWidth,
ValHeight
);
Pdf.CurrentPage.FillAndStroke;
end;
end;
Primetite kako se visina svakog stubca računa u odnosu na maksimalnu vrednost u skupu podataka, a pravougaonik se crta koristeći stanje popunjavanja i konture (fill-and-stroke) tako da ima crnu ivicu i plavu unutrašnjost.
2. Crtanje linijskog grafikona
Linijski grafikon povezuje tačke podataka pravim linijama. Koristan je za prikazivanje trendova tokom vremena. Matematika je slična kao kod stubičastog grafikona, ali umesto crtanja pravougaonika, pomerate se na prvu tačku i crtate linije do svake sledeće tačke.
procedure DrawLineChart(Pdf: THotPDF; const Data: array of Double;
const Left, Bottom, Width, Height: Double);
var
I: Integer;
X, Y, Step, MaxVal: Double;
begin
MaxVal := 100.0;
Step := Width / High(Data);
Pdf.CurrentPage.StrokeColor := RGB(220, 20, 60); // crimson red
Pdf.CurrentPage.LineWidth := 2;
// Move to the first data point
Y := Bottom + ((Data[0] / MaxVal) * Height);
Pdf.CurrentPage.MoveTo(Left, Y);
// Draw lines to subsequent points
for I := 1 to High(Data) do
begin
X := Left + (I * Step);
Y := Bottom + ((Data[I] / MaxVal) * Height);
Pdf.CurrentPage.LineTo(X, Y);
end;
Pdf.CurrentPage.Stroke;
// Optional: Draw markers at each point
Pdf.CurrentPage.FillColor := clBlack;
for I := 0 to High(Data) do
begin
X := Left + (I * Step);
Y := Bottom + ((Data[I] / MaxVal) * Height);
Pdf.CurrentPage.Circle(X, Y, 3);
Pdf.CurrentPage.Fill;
end;
end;
LineWidth je podešen na 2 tačke kako bi se linija istakla, a mali krugovi se crtaju na svakoj tački podataka da označe vrednosti. Putanja se iscrtava u jednom neprekidnom pozivu Stroke.
3. Crtanje kružnog grafikona
Kružni grafikon (pita) prikazuje udele u celini. Umesto mapiranja koordinata na mrežu, procente podataka mapirate u uglove (od 0 do 360 stepeni). HotPDF crta lukove i isečke kruga koristeći metode za segmente kruga (Circle).
procedure DrawPieChart(Pdf: THotPDF; const Proportions: array of Double;
const CX, CY, Radius: Double);
var
I: Integer;
Total, CurrentAngle, SliceAngle: Double;
Colors: array[0..3] of TColor;
begin
Colors[0] := RGB(70, 130, 180);
Colors[1] := RGB(220, 20, 60);
Colors[2] := RGB(46, 139, 87);
Colors[3] := RGB(218, 165, 32);
Total := 0.0;
for I := 0 to High(Proportions) do
Total := Total + Proportions[I];
CurrentAngle := 0.0;
Pdf.CurrentPage.StrokeColor := clBlack;
Pdf.CurrentPage.LineWidth := 1;
for I := 0 to High(Proportions) do
begin
SliceAngle := (Proportions[I] / Total) * 360.0;
Pdf.CurrentPage.FillColor := Colors[I mod 4];
// CX, CY, Radius, StartAngle, EndAngle
Pdf.CurrentPage.DrawPieSlice(
CX, CY, Radius,
CurrentAngle,
CurrentAngle + SliceAngle
);
CurrentAngle := CurrentAngle + SliceAngle;
end;
end;
Isečci pite se crtaju pomoću metode DrawPieSlice. Uglovi se mere u stepenima, počevši sa desne strane (pozicija 3 sata) i krećući se u smeru suprotnom od kretanja kazaljke na satu. Morate pratiti StartAngle i dodavati ugao svakog isečka kako biste izračunali sledeći početni ugao.
Metode za vektorske primitive, boje i fontove prikazane ovde deo su standardnog HotPDF Component API-ja za Delphi i C++Builder.