Cirkeldiagram med PHP og GD-Lib

Tags:    php
Skrevet af Bruger #285 @ 08.12.2003

Indledende kommentarer


I denne artikel vil jeg beskrive, hvordan med ved hjælp af PHP og GD-Lib kan lave ”dynamiske” cirkeldiagrammer. Denne artikel kræver lidt kendskab til PHP, GD-Lib og matematik i forvejen, men hvis man gider læse dokumentationen på de links, jeg har givet, kan man sagtens lave dette uden foregående kendskab. Det kræver også, at man har lidt forstand på cirkler, trigonometri, men det ridser jeg lige op, så vi har alle med.

Man skal være opmærksom på, at der i denne artikel ikke er gjort noget i emnet inputvalidering, så man skal give scriptet den rigtige type oplysninger for det virker.

Teori om cirkler


Når man skal lave et cirkeldiagram, skal man, som navnet siger, lavet en illustrativt opdelt cirkel ved hjælp af farver. For at gøre det, laver man nogle streger fra centrum af cirklen og ud til cirkelperiferien (”selve cirklen” så at sige). Derefter farver man disse områder. Det, der rent praktisk er lettest at gøre, er at først ”tegne” et stykke ved hjælp af streger og herefter fylde det med farve, og derefter næste osv.

Hvis man kigger på illustrationen nedenfor kan man se nogle betegnelser. Hvis man bruger nogle simple trigonometriske regler, kan man finde punktet (x,y) som er det punkt i cirkelperiferien, som den linie fra centrum skal gå ud til ud fra den angivne antal grader. Jeg forklarer ikke trigonometrien, da det godt kan være svært at forstå, hvis man endnu ikke har lært det.

Model:


Vinkler:


Punkter:


Indledende udregninger


Den måde, man finder ud af, hvor store ”cirkelstykkerne” skal være er, at man tager summen af inputtallene. Dette gøres med php-funktionen array_sum (URL: http://php.net/array_sum ). Da vi ved, at der er 360° i en cirkel bruges denne oplysning til at finde forholdet mellem antallet af grader samt summen af input. Det forhold kalder vi ”degreesPrUnit”, og er givet ved:
Fold kodeboks ind/udKode 
Dette tal skal vi senere bruge, når vi skal finde de tilhørende x- og y-værdier. Vi skal også indledende sætte nogle indstillinger for scriptet – så som fx en margin, hvor mange pixels en forklaringslinie skal fylde (en farveboks samt en forklaringstekst (kommer senere)). Jeg har kaldt dem følgende, og har givet dem følgende værdier, og sat sammen med overstående giver det følgende:
Fold kodeboks ind/udKode 
Først sættes pointeren til starten i array’erne med funktionen reset (URL: http://php.net/reset ). Derefter sætter jeg, at der skal 15 px til hver række forklaring. Jeg sætter ydermere margin til 5 px. Nu har jeg nok oplysninger til at regne bredden og højden ud. Bredden er margin i venstre side + cirklens bredde (2*r) + margin i højre side. Højden på billedet skal være det samme som bredden plus størrelsen på hver forklaring ganget med antallet af forklaringer (antal numre, der er i input). De sidste to variabelinitialiseringer er blot for at sætte dem, så vi ved, at de senere bliver brugt.

Nu oprettes billedet med de størrelser, vi har regnet ud, med funktionen imagecreatetruecolor (URL: http://php.net/imagecreatetruecolor ). Jeg initialiserer også nogle farver (en til baggrund, en til at tegne cirklen samt andre småting og til sidst 10 til forskellige cirkelstykker – hvis man skal have flere tal ind i cirkeldiagrammet, initialiserer man blot flere på samme måde) med funktionen imagecolorallocate (URL: http://php.net/imagecolorallocate ). Derefter tegner jeg en hvid baggrund med funktionen imagefilledrectangle (URL: http://php.net/imagefilledrectangle ). Til sidst tegner jeg selve cirklen med funktionen imageellipse (URL: http://php.net/imageellipse ).
Fold kodeboks ind/udKode 
Herefter løber jeg alle inputtallene igennem og ganger med det forhold vi før fandt ud af, degreesPrUnit, og lagrer i et array, numbersDegrees. Samtidig regner jeg ud, hvor mange procent tallet (der bruger jeg funktionen number_format til at gøre tallet pænere – URL: http://php.net/number-format ) er i forhold til summen og laver fylder i et array, numbersTmp, der bliver brugt, sådan, at hvis der ikke er angivet noget navn til et nummer, så bliver inputtallet skrevet som en form for ”erstatning”.
Fold kodeboks ind/udKode 


Nu begynder jeg at tegne cirkelafsnittene og farve dem. Til at tegne linier med, bliver funktionen imageline brugt (URL: http://php.net/imageline ). Jeg laver gradeantallet om til radianer med funktionen deg2rad da funktionerne sin og cos tager antal radianer som argument (URL’s: http://php.net/deg2rad , http://php.net/cos og http://php.net/sin ). Jeg fylder afsnittene med funktionen imagefilltoborder (URL: http://php.net/imagefilltoborder ). Jeg skriver det tilhørende navn (eller blot tallet, hvis der ikke er noget navn) samt procent i parentes bagefter med funktionen imagestring (URL: http://php.net/imagestring ).
Fold kodeboks ind/udKode 


Optimering af koden


Man kan sagtens optimere og arbejde med koden, men meget af det kræver, at man laver nogle skarpere regler for input – det optimale ville være at lave en funktion til at validere input, og så optimere funktionerne endnu mere. Dette vil jeg ikke beskrive i denne artikel, da denne blot er for at give en idé om, hvordan det kunne laves.

Samlet kode


Fold kodeboks ind/udKode 


Hvad kan jeg bruge det til?


Noget, dette ville være smart at bruge til er fx en afstemningsstatistik. Fx pga., at der er indbygget procentregning i, så tallene blot skal læses ud fra databasen og sættes ind i et array, scriptet så kan "fodres" med.

Det var alt!


Det var alt for denne gang. Skriv meget gerne ris/ros. Jeg har været lidt i tvivl om, hvor meget der skulle med, men dette var, hvad det endte med :)

Når du laver scriptet, så husk på, at der ingen inputvalidering er (betyder bl.a. at specialtegn som fx æ, ø og å ikke kan vises med imagestring - det betyder også, at hvis man vil skrive kommatal skal det gøres med engelsk komma - punktum - fx 45.6)

Et diagram lavet med overstående script

Dette er lavet med URL'en (blot for eksemplets skyld):
fil.php?r=50&s=50,45,87,54&n=Dansk,Svensk,Norsk,Finsk

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (21)

User
Bruger #846 @ 08.12.03 20:19
Flot og lærerig artikel :-)
User
Bruger #3530 @ 08.12.03 22:32
alt for svært....men selvfølgelig også en erfaren skribent/udvikler der er forfatter !
User
Bruger #285 @ 08.12.03 23:26
KasperTech: Derfor behøver den jo ikke være dårlig :s (har en mistanke om, at det er dig, der har ratet lavt (2 så vidt jeg kan regne ud)?) Hvis du bruger lidt tid på at sætte dig ind i det, er jeg sikker på, at du nok skal forstå det :) Ellers spørg endelig :)
User
Bruger #1445 @ 09.12.03 02:12
Det ser helt sjovt ud. Det må jeg prøv tak for artiklen....

Mvh
Janus

P.s Jeg skal lave noget til en evaluering af et fag og tror denne metode kan anvendes...
User
Bruger #714 @ 09.12.03 13:23
Uuuuha, det her ligner guffeluf :-), den må læses ordenligt igennem. Første lille ting jeg bed mærke i som jeg ikke brød mig om var måden du lavede $colorsCircle, hvorfor skrive $colorsCircle[0], [1] osv. når man bare kan bruge []? Ellers ligner det guf, jeg vil kigge lidt nærmere på den og rate den bagefter :-)
User
Bruger #714 @ 09.12.03 13:32
Huha, der er vist lidt mere matematik til stede end jeg har lært, nå, what ever, det skal da ikke stå i vejen for at det er en god artikel!

Udover det jeg allerede har skrevet, så laver du dine foreach med f.eks. foreach($numbers as $value) så vidt jeg kan huske står der på www.phpnet.dk/foreach at man bør lave dem som foreach($numbers as $number), men igen mindre detajler, men når jeg nu ikke kan smide andet end det efter dig må jeg jo gøre det.

Igen rigtig rigtig god artikel! (den fik selvfølgelig 5 herfra ;-))
User
Bruger #285 @ 09.12.03 14:23
Tak skal du have :)

Jeg må vist indrømme, at nogle ting kunne have været lavet smartere, men det er småting :p

Mht. den foreach - hvad er problemer, siger du?
User
Bruger #479 @ 09.12.03 15:49
Rigtig god artikel, lige til at bygge videre på :)

Kaare: Alle eksemplerne på dk.php.net/foreach bliver skrevet med $noget as $nogetAndet, og ikke med samme navn.
User
Bruger #714 @ 09.12.03 19:10
Sørmer ja, mener ellers at jeg har læst det et sted
User
Bruger #2330 @ 10.12.03 13:12
Jeg har kun en ting at sige... Kanon artikel... Fatter ikke så meget af matematiken, men pyt med det. Det virker da ihvertfald... Rigtig god artikel. Keep up the good work.
User
Bruger #3966 @ 11.12.03 19:28
Wauv... Det var jeg også en gang med at lave, men matematikken i det blev for meget...

Rigtig god artikel... Topkarakter fra mig
User
Bruger #1076 @ 13.12.03 17:48
Ved første øjekast ser der ud til at være meget godt i denne artikel. Og rart at du gider lave matematiken for mig ;). Rater den, når jeg har testet det
User
Bruger #2034 @ 16.12.03 17:15
Jaja... Sådan kan det skam også gøres.
Ellers en udemærket artikel. Det kunne dog laves lidt nemmere :)
User
Bruger #3765 @ 24.12.03 13:19
lol.. svært matematik? noo.. :D
Men scriptet er pænt og nydelig gennemgang!
User
Bruger #285 @ 26.12.03 14:11
Jesper -> Nej, men hvis man ikke har haft det, så er det svært :) Man lærer som regel ikke cirklens centrumsligning i folkeskolen, så sikkert derfor.

Simon -> Så skriv gerne en artikel om det, eller blot hurtigt beskrevet her, så man kan få gode idéer :)
User
Bruger #1151 @ 23.01.04 23:10
Tror godt jeg fatter artiklen (Matematikken er jeg indforstået med man går jo ikke på gym for ingenting) Men der er nok nogen der falder af da koden er så stor og det kan gøre at hvis de ikke li selv sidder og roder med noget ligende så er det svær at visualisere den i hovedet, men ellers er den fed!
User
Bruger #4479 @ 11.02.04 10:42
Rigtig god artikel, men matematiken er svær, da jeg kun går i folkeskolen.(femte klasse)
User
Bruger #5601 @ 20.05.04 00:20
AAAAH... Det jo alt det jeg har haft af mat iår der blir brugt der... LOL.. men fed artikel.. har set de der cirkel diagrammer flere steder og undret mig over hvordan man lavede dem...

Er rimelig ny indenfor php, men tror jeg fattede det meste bag scriptet.. tror jeg vil teste det engang.. genialt til at vise afstemninger osv med... :P

Gæt hvad.. Nemmerlig... Top karakter her fra mig :)
User
Bruger #4992 @ 21.07.04 13:29
Smart nok, men der mangler et lighedstegn på linie 76:

$y = (sin($rad) * ($radius - 1)) + $centerCircle;

:)
User
Bruger #14114 @ 25.08.08 15:46
Generelt en interessant artikel. Blot ærgerligt at funktionen opfører sig mærkeligt engang imellem.

Hvis man kører funktion med følgende input, så farvelægger den lidt forkert. 2 af kagestykkerne får samme farve, hvilket de ikke bør.
-------

//Radius
$r="50";

//Tal
$s="500,300,500,100";

//Navne
$n="Signe,Julie,Ulla,Bente";

// kunne kaldes på følgende måde:
$stats = explode(",", $s);
$navne = explode(",", $n);
header("Content-type: image/png");
cirkeldiagram($stats, $navne, $r);
User
Bruger #14114 @ 25.08.08 15:51
Sorry, det var de forkerte parametre jeg angav. Her er dem som fejler:
------------

$s="1,2,3,4,5";

//Navne
$n="Signe,Julie,Ulla,Bente,Jenni";

// kunne kaldes på følgende måde:
$stats = explode(",", $s);
$navne = explode(",", $n);
header("Content-type: image/png");
cirkeldiagram($stats, $navne, $r);
Du skal være logget ind for at skrive en kommentar.
t