display measurements in selected units
[openemr.git] / interface / forms / vitals / growthchart / chart.php
blobb01797dba005e9535d77c3433d2970c41bc9015c
1 <?php
3 // be careful with the relative paths here...
5 include_once ("../../../../interface/globals.php");
6 include_once ($GLOBALS['fileroot']."/library/patient.inc");
7 $chartpath = $GLOBALS['fileroot']."/interface/forms/vitals/growthchart/";
9 $name = "";
10 $pid = $_GET['pid'];
12 if ($pid == "") {
13 // no pid? no graph for you.
14 echo "<p>Missing PID. Please close this window.</p>";
15 exit;
18 $patient_data = "";
19 if (isset($pid) && is_numeric($pid)) {
20 $patient_data = getPatientData($pid, "fname, lname, sex, DATE_FORMAT(DOB,'%Y%m%d') as DOB");
21 $nowAge = getPatientAge($patient_data['DOB']);
22 $dob = $patient_data['DOB'];
23 $name = $patient_data['fname'] ." ".$patient_data['lname'];
26 // The first data point in the DATA set is significant. It tells date
27 // of the currently viewed vitals by the user. We will use this
28 // date to define which chart is displayed on the screen
29 $charttype = "2-20"; // default the chart-type to ages 2-20
30 $datapoints = explode('~', $_GET['data']);
31 if (isset($datapoints) && $datapoints != "") {
32 list($date, $height, $weight, $head_circ) = explode('-', $datapoints[0]);
33 if ($date != "") { $charttype_date = $date; }
34 $tmpAge = getPatientAgeInDays($patient_data['DOB'], $date);
35 // use the birth-36 chart if the age-on-date-of-vitals is 25months or younger
36 if ($tmpAge < (365*2)+31 ) { $charttype = "birth"; }
39 // determine the patient's age
40 // return - a floating point age in months or years
41 // - a string in the formay '#y #m #d'
42 function get_age($dob, $date=null) {
43 global $charttype;
45 if ($date == null) {
46 $daynow = date("d");
47 $monthnow = date("m");
48 $yearnow = date("Y");
50 else {
51 $datenow=preg_replace("/-/", "", $date);
52 $yearnow=substr($datenow,0,4);
53 $monthnow=substr($datenow,4,2);
54 $daynow=substr($datenow,6,2);
55 $datenow=$yearnow.$monthnow.$daynow;
58 $dob=preg_replace("/-/", "", $dob);
59 $dobyear=substr($dob,0,4);
60 $dobmonth=substr($dob,4,2);
61 $dobday=substr($dob,6,2);
62 $dob=$dobyear.$dobmonth.$dobday;
64 //to compensate for 30, 31, 28, 29 days/month
65 $mo=$monthnow; //to avoid confusion with later calculation
67 if ($mo==05 or $mo==07 or $mo==10 or $mo==12) { //determined by monthnow-1
68 $nd=30; //nd = number of days in a month, if monthnow is 5, 7, 9, 12 then
69 } // look at April, June, September, November for calculation. These months only have 30 days.
70 elseif ($mo==03) { // for march, look to the month of February for calculation, check for leap year
71 $check_leap_Y=$yearnow/4; // To check if this is a leap year.
72 if (is_int($check_leap_Y)) {$nd=29;} //If it true then this is the leap year
73 else {$nd=28;} //otherwise, it is not a leap year.
75 else {$nd=31;} // other months have 31 days
77 $bdthisyear=$yearnow.$dobmonth.$dobday; //Date current year's birthday falls on
78 if ($datenow < $bdthisyear) // if patient hasn't had birthday yet this year
80 $age_year = $yearnow - $dobyear - 1;
81 if ($daynow < $dobday) {
82 $months_since_birthday=12 - $dobmonth + $monthnow - 1;
83 $days_since_dobday=$nd - $dobday + $daynow; //did not take into account for month with 31 days
85 else {
86 $months_since_birthday=12 - $dobmonth + $monthnow;
87 $days_since_dobday=$daynow - $dobday;
90 else // if patient has had birthday this calandar year
92 $age_year = $yearnow - $dobyear;
93 if ($daynow < $dobday) {
94 $months_since_birthday=$monthnow - $dobmonth -1;
95 $days_since_dobday=$nd - $dobday + $daynow;
97 else {
98 $months_since_birthday=$monthnow - $dobmonth;
99 $days_since_dobday=$daynow - $dobday;
103 $day_as_month_decimal = $days_since_dobday / 30;
104 $months_since_birthday_float = $months_since_birthday + $day_as_month_decimal;
105 $month_as_year_decimal = $months_since_birthday_float / 12;
106 $age_float = $age_year + $month_as_year_decimal;
108 if ($charttype == 'birth') {
109 //if (($age_year < 2) or ($age_year == 2 and $months_since_birthday < 12)) {
110 $age_in_months = $age_year * 12 + $months_since_birthday_float;
111 $age = round($age_in_months,2); //round the months to xx.xx 2 floating points
113 else if ($charttype == '2-20') {
114 $age = round($age_float,2);
117 // round the years to 2 floating points
118 $ageinYMD = $age_year."y ".$months_since_birthday."m ".$days_since_dobday."d";
119 return compact('age','ageinYMD');
122 // convert to applicable weight units from the globals.php setting
123 function unitsWt($wt) {
124 if (($GLOBALS['units_of_measurement'] == 2) || ($GLOBALS['units_of_measurement'] == 4)) {
125 //convert to metric
126 return (number_format(($wt*0.45359237),2,'.',''));
128 else {
129 //keep US units
130 return $wt;
134 // convert to applicable weight units from the globals.php setting
135 function unitsDist($dist) {
136 if (($GLOBALS['units_of_measurement'] == 2) || ($GLOBALS['units_of_measurement'] == 4)) {
137 //convert to metric
138 return (number_format(($dist*2.54),2,'.',''));
140 else {
141 //keep US units
142 return $dist;
146 /******************************/
147 /******************************/
148 /******************************/
150 $name_x = 650;
151 $name_y = 60;
152 $name_x1 = 1650;
153 $name_y1 = 60;
155 $ageOffset = 0;
156 $heightOffset = 0;
157 $weightOffset = 0;
159 if ($charttype == 'birth') {
160 // Use birth to 36 months chart
162 $dot_x = 180; //months starts here (pixel)
163 $delta_x = 17.36; //pixels per month - length
164 $dot_y1 = 825; //height starts here - at 15 inches
165 $delta_y1 = 24.89; //pixels per inch - height
166 $dot_y2 = 1155; //weight starts here - at 4 lbs
167 $delta_y2 = 22.09; //pixels per pound - weight
169 $HC_dot_x = 1180; //months starts here for Head circumference chart
170 $HC_delta_x = 17.39; //pixels per month for Head circumference chart
171 $HC_dot_y = 764; //Head circumference starts here - at 11 inches
172 $HC_delta_y = 60.00; //calculated pixels per inch for head circumference
174 if (preg_match('/^male/i', $patient_data['sex'])) {
175 $chart = "birth-36mos_boys_HC.png";
177 elseif (preg_match('/^female/i', $patient_data['sex'])) {
178 $chart = "birth-36mos_girls_HC.png";
181 $ageOffset = 0;
182 $heightOffset = 15; // Substract 15 because the graph starts at 15 inches
183 $weightOffset = 4; // graph starts at 4 lbs
185 // pixel positions and offsets for data table
186 $datatable_x = 357;
187 $datatable_age_offset = 75;
188 $datatable_weight_offset = 160;
189 $datatable_height_offset = 240;
190 $datatable_hc_offset = 320;
191 $datatable_y = 1021;
192 $datatable_y_increment = 17;
194 // pixel positions and offsets for head-circ data table
195 $datatable2_x = 1375;
196 $datatable2_age_offset = 75;
197 $datatable2_weight_offset = 160;
198 $datatable2_height_offset = 225;
199 $datatable2_hc_offset = 310;
200 $datatable2_y = 1092;
201 $datatable2_y_increment = 18;
203 elseif ($charttype == "2-20") {
204 // current patient age between 2 and 20 years
206 $dot_x = 177;
207 $delta_x = 35.17;
208 $dot_y1 = 945;
209 $delta_y1 = 16.74;
210 $dot_y2 = 1176; //at 14 lbs, 1157 at 20 lbs
211 $delta_y2 = 3.01;
213 $bmi_dot_x = 1135;
214 $bmi_delta_x = 39.89;
215 $bmi_dot_y = 1130;
216 $bmi_delta_y = 37.15;
218 if (preg_match('/^male/i', $patient_data['sex'])) {
219 $chart = "2-20yo_boys_BMI.png";
221 elseif (preg_match('/^female/i', $patient_data['sex'])) {
222 $chart = "2-20yo_girls_BMI.png";
225 $ageOffset = 2;
226 $heightOffset = 30;
227 $weightOffset = 14;
229 // pixel positions and offsets data table
230 $datatable_x = 96;
231 $datatable_age_offset = 84;
232 $datatable_weight_offset = 200;
233 $datatable_height_offset = 290;
234 $datatable_bmi_offset = 360;
235 $datatable_y = 188;
236 $datatable_y_increment = 18;
238 // pixel positions and offsets for BMI data table
239 $datatable2_x = 1071;
240 $datatable2_age_offset = 73;
241 $datatable2_weight_offset = 165;
242 $datatable2_height_offset = 230;
243 $datatable2_bmi_offset = 310;
244 $datatable2_y = 152;
245 $datatable2_y_increment = 17;
248 else {
249 // bad age data? no graph for you.
250 echo "<p>Age data is out of range. </p>";
251 exit;
254 // create the graph
255 $im = imagecreatefrompng($chartpath.$chart);
256 $color1 = imagecolorallocate($im, 0, 0, 255); //blue - color scheme imagecolorallocate($im, Red, Green, Blue)
257 $color = imagecolorallocate($im, 255, 51, 51); //red
259 // draw the patient's name
260 imagestring($im, 12, $name_x, $name_y, $name, $color);
261 imagestring($im, 12, $name_x1, $name_y1, $name, $color);
263 // counter to limit the number of data points plotted
264 $count = 0;
266 // sort and plot the data points
267 rsort($datapoints);
268 foreach ($datapoints as $data) {
269 list($date, $height, $weight, $head_circ) = explode('-', $data);
270 if ($date == "") { continue; }
272 // only plot if we have both weight and heights. Skip if either is 0.
273 // Rational is only well visit will need both, sick visit only needs weight
274 // for some clinic.
275 if ($weight == 0 || $height == 0 ) { continue; }
277 // get age of patient at this data-point
278 // to get data from function get_age including $age, $ageinYMD
279 extract(get_age($dob, $date));
281 // exclude data points that do not belong on this chart
282 // for example, a data point for a 18 month old can be excluded
283 // from that patient's 2-20 yr chart
284 $daysold = getPatientAgeInDays($dob, $date);
285 if ($daysold > (365*3) && $charttype == "birth") { continue; }
286 if ($daysold < (365*2) && $charttype == "2-20") { continue; }
288 // calculate the x-axis (Age) value
289 $x = $dot_x + $delta_x * ($age - $ageOffset);
291 // Draw Height dot
292 $y1 = $dot_y1 - $delta_y1 * ($height - $heightOffset);
293 imagefilledellipse($im, $x, $y1, 10, 10, $color);
295 // Draw Weight bullseye
296 $y2 = $dot_y2 - $delta_y2 * ($weight - $weightOffset);
297 imageellipse($im, $x, $y2, 12, 12, $color); // outter ring
298 imagefilledellipse($im, $x, $y2, 5, 5, $color); //center dot
300 if ($charttype == "birth") {
301 // Draw Head circumference
302 $HC_x = $HC_dot_x + $HC_delta_x * $age;
303 $HC_y = $HC_dot_y - $HC_delta_y * ($head_circ - 11);
304 imagefilledellipse($im, $HC_x, $HC_y, 10, 10, $color1);
306 else if ($charttype == "2-20") {
307 // Draw BMI
308 $bmi = $weight/$height/$height*703;
309 $bmi_x = $bmi_dot_x + $bmi_delta_x * ($age - 2);
310 $bmi_y = $bmi_dot_y - $bmi_delta_y * ($bmi - 10);
311 imagefilledellipse($im, $bmi_x, $bmi_y, 10, 10, $color1);
314 // fill in data tables
316 $datestr = substr($date,0,4)."/".substr($date,4,2)."/".substr($date,6,2);
318 //birth to 36 mos chart has 9 rows to fill.
319 if ($count < 9 && $charttype == "birth") {
320 imagestring($im, 2, $datatable_x, $datatable_y, $datestr, $color);
321 imagestring($im, 2, ($datatable_x+$datatable_age_offset), $datatable_y, $ageinYMD, $color);
322 imagestring($im, 2, ($datatable_x+$datatable_weight_offset), $datatable_y, unitsWt($weight), $color);
323 imagestring($im, 2, ($datatable_x+$datatable_height_offset), $datatable_y, unitsDist($height), $color);
324 imagestring($im, 2, ($datatable_x+$datatable_hc_offset), $datatable_y, unitsDist($head_circ), $color);
325 $datatable_y = $datatable_y + $datatable_y_increment; // increment the datatable "row pointer"
328 // 2 to 20 year-old chart has 7 rows to fill.
329 if ($count < 7 && $charttype == "2-20") {
330 imagestring($im, 2, $datatable_x, $datatable_y, $datestr, $color);
331 imagestring($im, 2, ($datatable_x+$datatable_age_offset), $datatable_y, $ageinYMD, $color);
332 imagestring($im, 2, ($datatable_x+$datatable_weight_offset), $datatable_y, unitsWt($weight), $color);
333 imagestring($im, 2, ($datatable_x+$datatable_height_offset), $datatable_y, unitsDist($height), $color);
334 imagestring($im, 2, ($datatable_x+$datatable_bmi_offset), $datatable_y, substr($bmi,0,5), $color);
335 $datatable_y = $datatable_y + $datatable_y_increment; // increment the datatable "row pointer"
338 // Head Circumference chart has 5 rows to fill in
339 if ($count < 5 && $charttype == "birth") {
340 imagestring($im, 2, $datatable2_x, $datatable2_y, $datestr, $color);
341 imagestring($im, 2, ($datatable2_x+$datatable2_age_offset), $datatable2_y, $ageinYMD, $color);
342 imagestring($im, 2, ($datatable2_x+$datatable2_weight_offset), $datatable2_y, unitsWt($weight), $color);
343 imagestring($im, 2, ($datatable2_x+$datatable2_height_offset), $datatable2_y, unitsDist($height), $color);
344 imagestring($im, 2, ($datatable2_x+$datatable2_hc_offset), $datatable2_y, unitsDist($head_circ), $color);
345 $datatable2_y = $datatable2_y + $datatable2_y_increment; // increment the datatable2 "row pointer"
348 // BMI chart has 14 rows to fill in.
349 if ($count < 14 && $charttype == "2-20") {
350 imagestring($im, 2, $datatable2_x, $datatable2_y, $datestr, $color);
351 imagestring($im, 2, ($datatable2_x+$datatable2_age_offset), $datatable2_y, $ageinYMD, $color);
352 imagestring($im, 2, ($datatable2_x+$datatable2_weight_offset), $datatable2_y, unitsWt($weight), $color);
353 imagestring($im, 2, ($datatable2_x+$datatable2_height_offset), $datatable2_y, unitsDist($height), $color);
354 imagestring($im, 2, ($datatable2_x+$datatable2_bmi_offset), $datatable2_y, substr($bmi,0,5), $color);
355 $datatable2_y = $datatable2_y + $datatable2_y_increment; // increment the datatable2 "row pointer"
358 $count++;
361 if ($_GET['pdf'] == 1) {
362 require_once ($GLOBALS['fileroot'] . "/library/classes/class.ezpdf.php");
363 $pdf =& new Cezpdf("LETTER");
364 $pdf->ezSetMargins(0,0,0,0);
366 // we start with one large image, break it into two pages
367 $page1 = imagecreate((imagesx($im)/2),imagesy($im));
368 $page2 = imagecreate((imagesx($im)/2),imagesy($im));
369 imagecopy($page1, $im, 0,0, 0,0,(imagesx($im)/2),imagesy($im));
370 imagecopy($page2, $im, 0,0, (imagesx($im)/2),0,imagesx($im),imagesy($im));
371 imagedestroy($im);
373 // each page is built
374 $tmpfilename = tempnam("/tmp", "oemr");
375 imagepng($page1,$tmpfilename);
376 imagedestroy($page1);
377 $pdf->ezImage($tmpfilename);
378 $pdf->ezNewPage();
379 imagepng($page2,$tmpfilename);
380 imagedestroy($page2);
381 $pdf->ezImage($tmpfilename);
383 // temporary file is removed
384 unlink($tmpfilename);
386 // output the PDF
387 $pdf->ezStream();
389 else {
390 // older style chart that is simply a PNG image
391 header("Content-type: image/png");
392 imagepng($im);
393 imagedestroy($im);