Technical Article

Crtanje grafikona u PDF-u s HotPDF primitivima

HotPDF nema objekt grafikona. Ne postoji TPDFChart, niti AddBarSeries, ništa što prima niz brojeva i vraća iscrtani grafikon. Umjesto toga, nudi vam platno stranice s istim jednostavnim vokabularom koji koristi svaki PDF model crtanja: pravokutnike, linije, krugove, ispune, obrube i tekst postavljen na točne koordinate. Grafikon u HotPDF dokumentu je stoga nešto što sami gradite, a ne nešto što samo zatražite. To zvuči kao više posla nego što zapravo jest. Jednom kada napišete koordinatnu matematiku, stupčasti grafikon je samo petlja po pravokutnicima, linijski grafikon je izlomljena linija, a kružni grafikon je lepeza lukova, pri čemu kontrolirate svaki piksel rezultata.

To je važno jer alternativa kojoj ljudi prvo teže – pretvaranje grafikona sa zaslona u bitmapu i lijepljenje slike na stranicu – daje grafikon zaključan na razlučivost zaslona koji se ispisuje mutno i povećava veličinu datoteke. Crtanje grafikona pomoću HotPDF-ovih vektorskih primitiva održava izlaz oštrim pri svakom zumiranju i bilo kojem DPI-ju ispisa, jer su stupci i osi stvarni PDF operatori staza, a ne pikseli. Cijena je to što sami upravljate rasporedom. Mehanika se svodi na nekoliko poteza: okretanje koordinata koje svakoga zbunjuje, izradu stupčastog grafikona, trik s izlomljenom linijom za linijske grafikone i matematiku lukova za kriške kružnog grafikona.

Jedini težak dio je koordinatni sustav

Grafika zaslona postavlja ishodište u gornji lijevi kut s Y koji raste prema dolje. PDF radi suprotno. Ishodište se nalazi u donjem lijevom kutu stranice i Y raste prema gore, mjeri se u točkama (1/72 inča). Svaki poziv za crtanje u HotPDF-u, TextOut, Rectangle, MoveTo, LineTo, Circle, koristi tu konvenciju donjeg lijevog kuta i rasta prema gore. Ako prenesete instinkte s grafike zaslona, vaš će se prvi grafikon nacrtati naopako i izaći izvan donjeg ruba stranice.

Dakle, pravi posao u svakom grafikonu je jedno mapiranje: pretvoriti vrijednost podataka u Y koordinatu koja poštuje rast prema gore. Odlučite se za pravokutnik iscrtavanja, četiri broja za područje u kojem grafikon živi, a zatim mapirajte najmanju vrijednost u vašim podacima na donji rub, a najveću na gornji. Za stupac vrijednosti V na ljestvici koja se kreće od 0 do MaxValue, gornji rub stupca je PlotBottom + (V / MaxValue) * PlotHeight, a stupac raste prema gore od PlotBottom. Postavite taj jedan izraz ispravno i sve ostalo je samo vođenje evidencije. Pomoćna funkcija u nastavku drži geometriju iscrtavanja i vrši pretvorbu, tako da kod za crtanje nikada ne dira sirovu aritmetiku dvaput:

Jedna subjektivna odluka skriva se u MaxValue. Ako je postavite na točno najveću podatkovnu točku, najviši stupac će dodirivati gornji rub grafikona i izgledati odsječeno. Zaokružite je na čist broj iznad maksimuma, recimo sljedeći višekratnik od 10 ili 100, tako da grafikon ima slobodnog prostora na vrhu, a oznake mreže izgledaju kao zaokružene brojke, a ne onakve kakve su se zatekle u vrhuncu podataka.

Stupčasti grafikon je petlja po pravokutnicima

Kada je mapiranje riješeno, stupčasti grafikon se piše sam od sebe. Podijelite širinu grafikona na po jedno mjesto za svaku kategoriju, ostavite razmak između stupaca kako se ne bi dodirivali i nacrtajte svaki stupac kao ispunjeni pravokutnik čija visina dolazi iz ValueToY. HotPDF-ov Rectangle prima donji lijevi kut te širinu i visinu, što se točno podudara sa stupcem koji raste prema gore od osnovne linije. Najprije postavite boju ispune, položite stazu, a zatim pozovite Fill da je obojite. Oznaka kategorije ide ispod osnovne linije, a vrijednost iznad stupca:

Dva detalja zaslužuju svoje mjesto. Gap (razmak) je dio širine mjesta, a ne fiksni broj točaka, pa stupci ostaju proporcionalno raspoređeni bez obzira iscrtavate li četiri kategorije ili četrdeset. Oznaka vrijednosti je pozicionirana pomoću iste visine izvedene iz ValueToY koju koristi i stupac, tako da uvijek stoji točno iznad svog stupca umjesto da lebdi na procijenjenom pomaku. Ako želite vodoravne linije mreže iza stupaca, nacrtajte ih prije petlje: odaberite tri ili četiri zaokružene vrijednosti, pokrenite ValueToY za svaku i iscrtajte tanku liniju preko grafikona na tom Y. Crtanje tih linija najprije stavlja ih iza stupaca prema slikarskom modelu slaganja slojeva koji PDF koristi.

Osi, oznake i natpisi su samo dodatne linije i tekst

Grafikon nije gotov dok čitatelj ne može shvatiti što stupci znače, a to je isključivo posao oko osi. Okomita os je jedna povučena linija uz lijevi rub grafikona s nekoliko oznaka (ticks) i njihovih vrijednosti. Ponovno upotrijebite ValueToY kako bi oznake sletjele na istu ljestvicu koju koriste i stupci, inače se stupac i njegova linija mreže neće podudarati, a grafikon će tiho prikazivati pogrešne informacije:

Natpisi su mjesto gdje grafikoni najčešće pucaju u produkciji, a neuspjeh je uvijek isti: tekst koji je stao na zaslon prelazi svoj prostor u PDF-u. Dugi nazivi kategorija sudaraju se sa susjednima, a lokalizirani nazivi mjeseci poput "septembre" ili "Dezember" širi su od engleskog "Sep" s kojim ste testirali. Ovdje nema automatske veličine koja bi vas spasila, pa ostavite stvarnu marginu ispod osnovne linije, smanjite font za točku ili dvije za guste skupove kategorija, a ako su nazivi uistinu dugi, rotirajte ih. TextOut prima kut kao treći argument, pa prosljeđivanje 90 postavlja natpis uspravno i kupuje vam prostor bez preklapanja. Testirajte raspored sa svojim najširim očekivanim natpisom, a ne najkraćim, prije nego što izvoz krene.

Linijski grafikoni: jedna izlomljena linija kroz mapirane točke

Linijski grafikon ponovno koristi cijelo mapiranje vrijednosti i mijenja samo način na koji se točke povezuju. Umjesto pravokutnika po kategoriji, prolazite kroz podatke jednom, pretvarate svaku vrijednost u njezin (X, Y) pomoću ValueToY i spajate točke pomoću jednog poziva MoveTo praćenog pozivima LineTo, koji se obrubljuju na kraju. Prva točka otvara stazu, a svaka sljedeća točka je produžuje:

Obratite pažnju na razliku u razmaku. Stupčasti grafikon dijeli širinu s brojem stupaca jer svaki stupac posjeduje svoj prostor. Linijski grafikon dijeli s brojem intervala, Count - 1, jer prva i zadnja točka leže na rubovima grafikona, a linija premošćuje praznine između njih. Miješanje ta dva pristupa uobičajeni je razlog zašto linijski grafikon odstupa za pola mjesta od stupčastog grafikona koji bi trebao prekriti. Ako želite marker na svakoj podatkovnoj točki, postavite mali Circle i primijenite Fill na svakom (X, Y) nakon što je izlomljena linija iscrtana pomoću Stroke.

Kružni grafikoni: lukovi, ili isječci ako želite jednostavnost

Isječci kružnog grafikona su jedini oblik koji zahtijeva trigonometriju, jer je isječak omeđen dvama polumjerima i lukom. Ispravna verzija iscrtava luk prolaskom kroz male segmente linije duž opsega, što aproksimira krivulju dovoljno precizno da čitatelj ne može uočiti razliku. Kut zakreta svakog isječka je njegov udio u ukupnom iznosu, (Value / Total) * 2π, a vi akumulirate tekući kut dok idete u krug:

Staza od središta prema van – najprije vrh, zatim luk, pa natrag do vrha – daje zatvoreni isječak koji Fill ispunjava bojom. Broj segmenata mijenja glatkoću za veličinu staze: otprilike dva stupnja po koraku izgledaju okruglo na bilo kojem razumnom polumjeru bez stvaranja ogromnog toka sadržaja. Ako vam ne treba pravi krug, možete u potpunosti preskočiti trigonometriju i prikazati iste podatke kao jedan vodoravni naslagani stupac, pri čemu je širina svakog segmenta proporcionalna njegovom udjelu. To je ionako često čitljivije od kružnog grafikona, a to je zapravo samo kod za stupce s pravokutnicima položenim jedan do drugoga. Posegnite za verzijom s lukom samo kada dizajn zahtijeva stvarni krug.

Ništa od ovoga ne ovisi o instaliranim knjižnicama za grafikone, što je tiha prednost izravnog crtanja primitiva. Isti pozivi za crtanje na platnu koji postavljaju logotip ili okvir za potpis grade i ove grafikone, a isti TextOut koji označava polje obrasca označava i os. Stavite geometriju grafikona u zapis (record), mapirajte vrijednosti na Y jednom, i stupčasti, linijski ili kružni grafikon bit će kratka rutina nad metodama Rectangle, LineTo i Circle koju možete ubaciti u bilo koji izvještaj. Pozivi Rectangle, MoveTo, LineTo, Circle, Fill, Stroke i TextOut koji se ovdje koriste dio su HotPDF komponente za Delphi i C++Builder.