webalizer/webalizer-2.23-08/graphs.c
2021-05-15 15:52:00 +02:00

904 lines
30 KiB
C

/*
graphs.c - produces graphs used by the Webalizer
Copyright (C) 1997-2013 Bradford L. Barrett
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version, and provided that the above
copyright and permission notice is included with all distributed
copies of this or derived software.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <gd.h>
#include <gdfontt.h>
#include <gdfonts.h>
#include <gdfontmb.h>
/* need socket header? */
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include "webalizer.h"
#include "preserve.h"
#include "lang.h"
#include "graphs.h"
/* Some systems don't define this */
#ifndef PI
#define PI 3.14159265358979323846
#endif
#define HITCOLOR hit_or_green /* graph color - hits */
#define FILECOLOR file_or_blue /* files */
#define SITECOLOR site_or_orange /* sites */
#define KBYTECOLOR kbyte_or_red /* KBytes */
#define PAGECOLOR page_or_cyan /* Files */
#define VISITCOLOR visit_or_yellow /* Visits */
/* shortcuts to convert ASCII hex color for gdImageColorAllocate() */
#define getred(s) (ashex2int((s[0] == '#')?s+1:s))
/* returns the red base-10 integer value from a html color */
#define getgreen(s) (ashex2int((s[0] == '#')?s+3:s+2))
/* returns the green base-10 integer value from a html color */
#define getblue(s) (ashex2int((s[0] == '#')?s+5:s+4))
/* returns the blue base-10 integer value from a html color */
#define CX 156 /* center x (for pie) */
#define CY 150 /* center y (chart) */
#define XRAD 240 /* X-axis radius */
#define YRAD 200 /* Y-axis radius */
/* forward reference internal routines */
void init_graph(char *, int, int);
struct pie_data *calc_arc(float, float);
int ashex2int(char *);
/* common public declarations */
char *numchar[] = { " 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10",
"11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","25","26","27","28","29","30","31"};
gdImagePtr im; /* image buffer */
FILE *out; /* output file for PNG */
struct stat out_stat; /* stat struct for PNG */
char maxvaltxt[32]; /* graph values */
float percent; /* percent storage */
u_int64_t julday; /* julday value */
struct pie_data { int x; int y; /* line x,y */
int mx; int my; }; /* midpoint x,y */
/* colors */
int black, white, grey, dkgrey, kbyte_or_red,
file_or_blue, site_or_orange, hit_or_green,
page_or_cyan, visit_or_yellow, blue;
/*****************************************************************/
/* */
/* YEAR_GRAPH6x - Year graph from array of hist_rec structs */
/* */
/*****************************************************************/
int year_graph6x(char *fname, char *title, struct hist_rec data[HISTSIZE])
{
/* local variables */
int i,j,x1,y1,x2;
int s_mth,s_year=0;
float cw,cs,co,ci;
u_int64_t maxval=1;
double fmaxval=0.0;
/* initalize the graph */
init_graph(title,512,256); /* init as 512 x 256 */
gdImageLine(im, 305,25,305,233,black); /* draw section lines */
gdImageLine(im, 304,25,304,233,white);
gdImageLine(im, 305,130,490,130,black);
gdImageLine(im, 305,129,490,129,white);
/* index lines? */
if (graph_lines)
{
y1=210/(graph_lines+1);
for (i=0;i<graph_lines;i++)
gdImageLine(im,21,((i+1)*y1)+25,303,((i+1)*y1)+25,dkgrey);
y1=105/(graph_lines+1);
for (i=0;i<graph_lines;i++)
gdImageLine(im,306,((i+1)*y1)+25,489,((i+1)*y1)+25,dkgrey);
for (i=0;i<graph_lines;i++)
gdImageLine(im,306,((i+1)*y1)+130,489,((i+1)*y1)+130,dkgrey);
}
/* color coded legends? */
if (graph_legend)
{
/* Kbytes Legend */
i = (strlen(msg_h_xfer)*6);
gdImageString(im,gdFontSmall,491-i,237,
(unsigned char *)msg_h_xfer,dkgrey);
gdImageString(im,gdFontSmall,490-i,236,
(unsigned char *)msg_h_xfer,KBYTECOLOR);
/* Sites/Visits Legend */
i = (strlen(msg_h_visits)*6);
j = (strlen(msg_h_sites)*6);
gdImageString(im,gdFontSmall,491-i-j-12,11,
(unsigned char *)msg_h_visits,dkgrey);
gdImageString(im,gdFontSmall,490-i-j-12,10,
(unsigned char *)msg_h_visits,VISITCOLOR);
gdImageString(im,gdFontSmall,491-j-9,11,(unsigned char *)"/",dkgrey);
gdImageString(im,gdFontSmall,490-j-9,10,(unsigned char *)"/",black);
gdImageString(im,gdFontSmall,491-j,11,
(unsigned char *)msg_h_sites,dkgrey);
gdImageString(im,gdFontSmall,490-j,10,
(unsigned char *)msg_h_sites,SITECOLOR);
/* Hits/Files/Pages Legend */
i = (strlen(msg_h_pages)*6);
j = (strlen(msg_h_files)*6);
gdImageStringUp(im,gdFontSmall,6,231,
(unsigned char *)msg_h_pages,dkgrey);
gdImageStringUp(im,gdFontSmall,5,230,
(unsigned char *)msg_h_pages,PAGECOLOR);
gdImageStringUp(im,gdFontSmall,6,231-i-3,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,5,230-i-3,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,6,231-i-12,
(unsigned char *)msg_h_files,dkgrey);
gdImageStringUp(im,gdFontSmall,5,230-i-12,
(unsigned char *)msg_h_files,FILECOLOR);
gdImageStringUp(im,gdFontSmall,6,231-i-j-15,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,5,230-i-j-15,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,6,231-i-j-24,
(unsigned char *)msg_h_hits,dkgrey);
gdImageStringUp(im,gdFontSmall,5,230-i-j-24,
(unsigned char *)msg_h_hits,HITCOLOR);
}
/* Now draw data areas */
s_mth = HISTSIZE-graph_mths;
cs = 280.0/graph_mths; cw = cs/2;
co = (48/graph_mths<1)?1:48/graph_mths;
ci = 22+((cw-co)/2);
/* x-axis legend */
for (i=s_mth;i<HISTSIZE;i++)
{
if (graph_mths<16)
{
gdImageString(im,gdFontSmall,ci+((i-s_mth)*cs)+(((cw+co+co)-18)/2)+1,
236,(unsigned char *)s_month[data[i].month-1],black);
}
else if (graph_mths<36)
{
gdImageChar(im,gdFontSmall,ci+((i-s_mth)*cs)+(((cw+co+co)-6)/2)+1,
236,s_month[data[i].month-1][0],
(data[i].month==1)?blue:black);
}
else
{
if (s_year!=data[i].year) /* year change only */
{
if (data[i].month==1 && (i-s_mth)!=0)
gdImageChar(im,gdFontSmall, ci+((i-s_mth)*cs)-3,236,'|',blue);
j=(12-data[i].month+1)*cs;
if ((HISTSIZE-i)*cs < j) j=(HISTSIZE-i)*cs;
if (j>28)
{
/* format the year string */
sprintf(maxvaltxt, "%04d", data[i].year);
gdImageString(im,gdFontSmall,ci+((i-s_mth)*cs)+(j/2)-12,
236, (unsigned char *)maxvaltxt, black);
}
s_year=data[i].year;
}
}
if (data[i].hit > maxval) maxval = data[i].hit;
if (data[i].files > maxval) maxval = data[i].files;
if (data[i].page > maxval) maxval = data[i].page;
}
if (maxval <= 0) maxval = 1;
sprintf(maxvaltxt, "%llu", maxval);
gdImageStringUp(im,gdFontSmall,6,26+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt,black);
/* hits */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].hit / (float)maxval);
if (percent <= 0.0) continue;
x1 = ci + ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, HITCOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* files */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].files / (float)maxval);
if (percent <= 0.0) continue;
x1 = ci + co + ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, FILECOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* pages */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].page / (float)maxval);
if (percent <= 0.0) continue;
x1 = ci + co + co + ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, PAGECOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 232, black);
}
maxval=0;
for (i=s_mth; i<HISTSIZE; i++)
{
if (data[i].site > maxval) maxval = data[i].site;
if (data[i].visit > maxval) maxval = data[i].visit;
}
if (maxval <= 0) maxval = 1;
sprintf(maxvaltxt, "%llu", maxval);
gdImageStringUp(im, gdFontSmall,493,26+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt, black);
cs = 180.0/graph_mths; cw = cs/2;
co = (48/graph_mths<1)?1:48/graph_mths;
ci = 308+((cw-co)/2);
/* visits */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].visit / (float)maxval);
if (percent <= 0.0) continue;
x1 = ci + ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 127 - (percent * 98);
gdImageFilledRectangle(im, x1, y1, x2, 127, VISITCOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 127, black);
}
/* sites */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].site / (float)maxval);
if (percent <= 0.0) continue;
x1 = ci + co + ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 127 - (percent * 98);
gdImageFilledRectangle(im, x1, y1, x2, 127, SITECOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 127, black);
}
fmaxval=0.0;
for (i=s_mth; i<HISTSIZE; i++)
if (data[i].xfer > fmaxval) fmaxval = data[i].xfer;
if (fmaxval <= 0.0) fmaxval = 1.0;
sprintf(maxvaltxt, "%.0f", fmaxval);
gdImageStringUp(im, gdFontSmall,493,130+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt,black);
cs = 180.0/graph_mths; cw = (cs/2)+(co/2);
ci = 308+((cw-co)/2);
/* xfer */
for (i=s_mth; i<HISTSIZE; i++)
{
percent = ((float)data[i].xfer / (float)fmaxval);
if (percent <= 0.0) continue;
x1 = ci+ ((i-s_mth)*cs);
x2 = x1 + cw;
y1 = 232 - (percent * 98);
gdImageFilledRectangle(im, x1, y1, x2, 232, KBYTECOLOR);
if (cw>2) gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* stat the file */
if ( !(lstat(fname, &out_stat)) )
{
/* check if the file a symlink */
if ( S_ISLNK(out_stat.st_mode) )
{
if (verbose)
fprintf(stderr,"%s %s (symlink)\n",msg_no_open,fname);
return(EBADF);
}
}
/* save PNG image */
if ((out = fopen(fname, "wb")) != NULL)
{
gdImagePng(im, out);
fclose(out);
}
/* deallocate memory */
gdImageDestroy(im);
return (0);
}
/*****************************************************************/
/* */
/* MONTH_GRAPH6 - Month graph with six data sets */
/* */
/*****************************************************************/
#define YSIZE 400
int month_graph6( char *fname, /* filename */
char *title, /* graph title */
int month, /* graph month */
int year, /* graph year */
u_int64_t data1[31], /* data1 (hits) */
u_int64_t data2[31], /* data2 (files) */
u_int64_t data3[31], /* data3 (sites) */
double data4[31], /* data4 (kbytes) */
u_int64_t data5[31], /* data5 (views) */
u_int64_t data6[31]) /* data6 (visits) */
{
/* local variables */
int i,j,s,x1,y1,x2;
u_int64_t maxval=0;
double fmaxval=0.0;
/* calc julian date for month */
julday = (jdate(1, month,year) % 7);
/* initalize the graph */
init_graph(title,512,400);
gdImageLine(im, 21, 180, 490, 180, black); /* draw section lines */
gdImageLine(im, 21, 179, 490, 179, white);
gdImageLine(im, 21, 280, 490, 280, black);
gdImageLine(im, 21, 279, 490, 279, white);
/* index lines? */
if (graph_lines)
{
y1=154/(graph_lines+1);
for (i=0;i<graph_lines;i++)
gdImageLine(im,21,((i+1)*y1)+25,489,((i+1)*y1)+25,dkgrey);
y1=100/(graph_lines+1);
for (i=0;i<graph_lines;i++)
gdImageLine(im,21,((i+1)*y1)+180,489,((i+1)*y1)+180,dkgrey);
for (i=0;i<graph_lines;i++)
gdImageLine(im,21,((i+1)*y1)+280,489,((i+1)*y1)+280,dkgrey);
}
/* x-axis legend */
for (i=0;i<31;i++)
{
if ((julday % 7 == 6) || (julday % 7 == 0))
gdImageString(im,gdFontSmall,25+(i*15),382,
(unsigned char *)numchar[i+1],HITCOLOR);
else
gdImageString(im,gdFontSmall,25+(i*15),382,
(unsigned char *)numchar[i+1],black);
julday++;
}
/* y-axis legend */
for (i=0; i<31; i++)
{
if (data1[i] > maxval) maxval = data1[i]; /* get max val */
if (data2[i] > maxval) maxval = data2[i];
if (data5[i] > maxval) maxval = data5[i];
}
if (maxval <= 0) maxval = 1;
sprintf(maxvaltxt, "%llu", maxval);
gdImageStringUp(im, gdFontSmall,8,26+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt,black);
if (graph_legend) /* Print color coded legends? */
{
/* Kbytes Legend */
gdImageStringUp(im,gdFontSmall,494,376,
(unsigned char *)msg_h_xfer,dkgrey);
gdImageStringUp(im,gdFontSmall,493,375,
(unsigned char *)msg_h_xfer,KBYTECOLOR);
/* Sites/Visits Legend */
i = (strlen(msg_h_sites)*6);
gdImageStringUp(im,gdFontSmall,494,276,
(unsigned char *)msg_h_sites,dkgrey);
gdImageStringUp(im,gdFontSmall,493,275,
(unsigned char *)msg_h_sites,SITECOLOR);
gdImageStringUp(im,gdFontSmall,494,276-i-3,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,493,275-i-3,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,494,276-i-12,
(unsigned char *)msg_h_visits,dkgrey);
gdImageStringUp(im,gdFontSmall,493,275-i-12,
(unsigned char *)msg_h_visits,VISITCOLOR);
/* Pages/Files/Hits Legend */
s = ( i=(strlen(msg_h_pages)*6) )+
( j=(strlen(msg_h_files)*6) )+
( strlen(msg_h_hits)*6 )+ 52;
gdImageStringUp(im,gdFontSmall,494,s,
(unsigned char *)msg_h_pages,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-1,
(unsigned char *)msg_h_pages,PAGECOLOR);
gdImageStringUp(im,gdFontSmall,494,s-i-3,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-4,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,494,s-i-12,
(unsigned char *)msg_h_files,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-13,
(unsigned char *)msg_h_files,FILECOLOR);
gdImageStringUp(im,gdFontSmall,494,s-i-j-15,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-j-16,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,494,s-i-j-24,
(unsigned char *)msg_h_hits,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-j-25,
(unsigned char *)msg_h_hits,HITCOLOR);
}
/* data1 */
for (i=0; i<31; i++)
{
percent = ((float)data1[i] / (float)maxval);
if (percent <= 0.0) continue;
x1 = 25 + (i*15);
x2 = x1 + 7;
y1 = 176 - (percent * 147);
gdImageFilledRectangle(im, x1, y1, x2, 176, HITCOLOR);
gdImageRectangle(im, x1, y1, x2, 176, black);
}
/* data2 */
for (i=0; i<31; i++)
{
percent = ((float)data2[i] / (float)maxval);
if (percent <= 0.0) continue;
x1 = 27 + (i*15);
x2 = x1 + 7;
y1 = 176 - (percent * 147);
gdImageFilledRectangle(im, x1, y1, x2, 176, FILECOLOR);
gdImageRectangle(im, x1, y1, x2, 176, black);
}
/* data5 */
for (i=0; i<31; i++)
{
if (data5[i]==0) continue;
percent = ((float)data5[i] / (float)maxval);
if (percent <= 0.0) continue;
x1 = 29 + (i*15);
x2 = x1 + 7;
y1 = 176 - (percent * 147);
gdImageFilledRectangle(im, x1, y1, x2, 176, PAGECOLOR);
gdImageRectangle(im, x1, y1, x2, 176, black);
}
/* sites / visits */
maxval=0;
for (i=0; i<31; i++)
{
if (data3[i]>maxval) maxval = data3[i];
if (data6[i]>maxval) maxval = data6[i];
}
if (maxval <= 0) maxval = 1;
sprintf(maxvaltxt, "%llu", maxval);
gdImageStringUp(im, gdFontSmall,8,180+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt, black);
/* data 6 */
for (i=0; i<31; i++)
{
percent = ((float)data6[i] / (float)maxval);
if (percent <= 0.0) continue;
x1 = 25 + (i*15);
x2 = x1 + 8;
y1 = 276 - (percent * 92);
gdImageFilledRectangle(im, x1, y1, x2, 276, VISITCOLOR);
gdImageRectangle(im, x1, y1, x2, 276, black);
}
/* data 3 */
for (i=0; i<31; i++)
{
percent = ((float)data3[i] / (float)maxval);
if (percent <= 0.0) continue;
x1 = 29 + (i*15);
x2 = x1 + 7;
y1 = 276 - (percent * 92);
gdImageFilledRectangle(im, x1, y1, x2, 276, SITECOLOR);
gdImageRectangle(im, x1, y1, x2, 276, black);
}
/* data4 */
fmaxval=0.0;
for (i=0; i<31; i++)
if (data4[i]>fmaxval) fmaxval = data4[i];
if (fmaxval <= 0.0) fmaxval = 1.0;
sprintf(maxvaltxt, "%.0f", fmaxval/1024);
gdImageStringUp(im, gdFontSmall,8,280+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt, black);
for (i=0; i<31; i++)
{
percent = data4[i] / fmaxval;
if (percent <= 0.0) continue;
x1 = 26 + (i*15);
x2 = x1 + 10;
y1 = 375 - ( percent * 91 );
gdImageFilledRectangle(im, x1, y1, x2, 375, KBYTECOLOR);
gdImageRectangle(im, x1, y1, x2, 375, black);
}
/* stat the file */
if ( !(lstat(fname, &out_stat)) )
{
/* check if the file a symlink */
if ( S_ISLNK(out_stat.st_mode) )
{
if (verbose)
fprintf(stderr,"%s %s (symlink)\n",msg_no_open,fname);
return(EBADF);
}
}
/* save PNG image */
if ((out = fopen(fname, "wb")) != NULL)
{
gdImagePng(im, out);
fclose(out);
}
/* deallocate memory */
gdImageDestroy(im);
return (0);
}
/*****************************************************************/
/* */
/* DAY_GRAPH3 - Day graph with three data sets */
/* */
/*****************************************************************/
int day_graph3( char *fname,
char *title,
u_int64_t data1[24],
u_int64_t data2[24],
u_int64_t data3[24])
{
/* local variables */
int i,j,s,x1,y1,x2;
u_int64_t maxval=0;
/* initalize the graph */
init_graph(title,512,256);
/* index lines? */
if (graph_lines)
{
y1=210/(graph_lines+1);
for (i=0;i<graph_lines;i++)
gdImageLine(im,21,((i+1)*y1)+25,489,((i+1)*y1)+25,dkgrey);
}
/* x-axis legend */
for (i=0;i<24;i++)
{
gdImageString(im,gdFontSmall,33+(i*19),238,
(unsigned char *)numchar[i],black);
if (data1[i] > maxval) maxval = data1[i]; /* get max val */
if (data2[i] > maxval) maxval = data2[i];
if (data3[i] > maxval) maxval = data3[i];
}
if (maxval <= 0) maxval = 1;
sprintf(maxvaltxt, "%llu", maxval);
gdImageStringUp(im, gdFontSmall, 8, 26+(strlen(maxvaltxt)*6),
(unsigned char *)maxvaltxt, black);
if (graph_legend) /* print color coded legends? */
{
/* Pages/Files/Hits Legend */
s = ( i=(strlen(msg_h_pages)*6) )+
( j=(strlen(msg_h_files)*6) )+
( strlen(msg_h_hits)*6 )+ 52;
gdImageStringUp(im,gdFontSmall,494,s,
(unsigned char *)msg_h_pages,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-1,
(unsigned char *)msg_h_pages,PAGECOLOR);
gdImageStringUp(im,gdFontSmall,494,s-i-3,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-4,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,494,s-i-12,
(unsigned char *)msg_h_files,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-13,
(unsigned char *)msg_h_files,FILECOLOR);
gdImageStringUp(im,gdFontSmall,494,s-i-j-15,(unsigned char *)"/",dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-j-16,(unsigned char *)"/",black);
gdImageStringUp(im,gdFontSmall,494,s-i-j-24,
(unsigned char *)msg_h_hits,dkgrey);
gdImageStringUp(im,gdFontSmall,493,s-i-j-25,
(unsigned char *)msg_h_hits,HITCOLOR);
}
/* data1 */
for (i=0; i<24; i++)
{
percent = ((float)data1[i] / (float)maxval); /* percent of 100% */
if (percent <= 0.0) continue;
x1 = 29 + (i*19);
x2 = x1 + 10;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, HITCOLOR);
gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* data2 */
for (i=0; i<24; i++)
{
percent = ((float)data2[i] / (float)maxval); /* percent of 100% */
if (percent <= 0.0) continue;
x1 = 32 + (i*19);
x2 = x1 + 10;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, FILECOLOR);
gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* data3 */
for (i=0; i<24; i++)
{
percent = ((float)data3[i] / (float)maxval); /* percent of 100% */
if (percent <= 0.0) continue;
x1 = 35 + (i*19);
x2 = x1 + 10;
y1 = 232 - (percent * 203);
gdImageFilledRectangle(im, x1, y1, x2, 232, PAGECOLOR);
gdImageRectangle(im, x1, y1, x2, 232, black);
}
/* stat the file */
if ( !(lstat(fname, &out_stat)) )
{
/* check if the file a symlink */
if ( S_ISLNK(out_stat.st_mode) )
{
if (verbose)
fprintf(stderr,"%s %s (symlink)\n",msg_no_open,fname);
return(EBADF);
}
}
/* save PNG image */
if ((out = fopen(fname, "wb")) != NULL)
{
gdImagePng(im, out);
fclose(out);
}
/* deallocate memory */
gdImageDestroy(im);
return (0);
}
/*****************************************************************/
/* */
/* PIE_CHART - draw a pie chart (10 data items max) */
/* */
/*****************************************************************/
int pie_chart(char *fname, char *title, u_int64_t t_val,
u_int64_t data1[], char *legend[])
{
int i,x,percent,y=47;
double s_arc=0.0;
int purple_or_pie1, ltgreen_or_pie2, ltpurple_or_pie3, brown_or_pie4;
int r, g, b;
char buffer[128];
struct pie_data gdata;
/* init graph and colors */
init_graph(title,512,300);
r=getred(pie_color1); g=getgreen(pie_color1); b=getblue(pie_color1);
purple_or_pie1 = gdImageColorAllocate(im, r, g, b);
r=getred(pie_color2); g=getgreen(pie_color2); b=getblue(pie_color2);
ltgreen_or_pie2 = gdImageColorAllocate(im, r, g, b);
r=getred(pie_color3); g=getgreen(pie_color3); b=getblue(pie_color3);
ltpurple_or_pie3= gdImageColorAllocate(im, r, g, b);
r=getred(pie_color4); g=getgreen(pie_color4); b=getblue(pie_color4);
brown_or_pie4 = gdImageColorAllocate(im, r, g, b);
/* do the circle... */
gdImageArc(im, CX, CY, XRAD, YRAD, 0, 360, black);
gdImageArc(im, CX, CY+10, XRAD-2, YRAD-2, 2, 178, black);
gdImageFillToBorder(im, CX, CY+(YRAD/2)+1, black, black);
/* slice the pie */
gdata=*calc_arc(0.0,0.0);
gdImageLine(im,CX,CY,gdata.x,gdata.y,black); /* inital line */
for (i=0;i<10;i++) /* run through data array */
{
if ((data1[i]!=0)&&(s_arc<1.0)) /* make sure valid slice */
{
percent=(((double)data1[i]/t_val)+0.005)*100.0;
if (percent<1) break;
if (s_arc+((double)percent/100.0)>=1.0)
{
gdata=*calc_arc(s_arc,1.0);
s_arc=1.0;
}
else
{
gdata=*calc_arc(s_arc,s_arc+((double)percent/100.0));
s_arc+=(double)percent/100.0;
}
gdImageLine(im, CX, CY, gdata.x, gdata.y, black);
gdImageFill(im, gdata.mx, gdata.my, i+5);
snprintf(buffer,sizeof(buffer),"%s (%d%%)",legend[i], percent);
x=480-(strlen(buffer)*7);
gdImageString(im,gdFontMediumBold, x+1, y+1,
(unsigned char *)buffer, black);
gdImageString(im,gdFontMediumBold, x, y,
(unsigned char *)buffer, i+5);
y+=20;
}
}
if (s_arc < 1.0) /* anything left over? */
{
gdata=*calc_arc(s_arc,1.0);
gdImageFill(im, gdata.mx, gdata.my, white);
snprintf(buffer,sizeof(buffer),"%s (%d%%)",
msg_h_other,100-(int)(s_arc*100));
x=480-(strlen(buffer)*7);
gdImageString(im,gdFontMediumBold, x+1, y+1,
(unsigned char *)buffer, black);
gdImageString(im,gdFontMediumBold, x, y,
(unsigned char *)buffer, white);
}
/* stat the file */
if ( !(lstat(fname, &out_stat)) )
{
/* check if the file a symlink */
if ( S_ISLNK(out_stat.st_mode) )
{
if (verbose)
fprintf(stderr,"%s %s (symlink)\n",msg_no_open,fname);
return(EBADF);
}
}
/* save PNG image */
if ((out = fopen(fname, "wb")) != NULL)
{
gdImagePng(im, out);
fclose(out);
}
/* deallocate memory */
gdImageDestroy(im);
return (0);
}
/*****************************************************************/
/* */
/* CALC_ARC - generate x,y coordinates for pie chart */
/* */
/*****************************************************************/
struct pie_data *calc_arc(float min, float max)
{
static struct pie_data data;
double d;
/* Calculate max line */
d=max;
data.x=cos(d*(2*PI))*((XRAD-2)/2)+CX;
data.y=sin(d*(2*PI))*((YRAD-2)/2)+CY;
/* Now get mid-point */
d=((min+max)/2);
data.mx=cos(d*(2*PI))*(XRAD/3)+CX;
data.my=sin(d*(2*PI))*(YRAD/3)+CY;
return &data;
}
/*****************************************************************/
/* */
/* INIT_GRAPH - initalize graph and draw borders */
/* */
/*****************************************************************/
void init_graph(char *title, int xsize, int ysize)
{
int i, r, g, b;
im = gdImageCreate(xsize,ysize);
/* allocate color maps, background color first (grey) */
grey = gdImageColorAllocate(im, 192, 192, 192);
dkgrey = gdImageColorAllocate(im, 128, 128, 128);
black = gdImageColorAllocate(im, 0, 0, 0);
white = gdImageColorAllocate(im, 255, 255, 255);
blue = gdImageColorAllocate(im, 0, 0, 255);
r=getred(hit_color); g=getgreen(hit_color); b=getblue(hit_color);
hit_or_green = gdImageColorAllocate(im, r, g, b);
r=getred(site_color); g=getgreen(site_color); b=getblue(site_color);
site_or_orange = gdImageColorAllocate(im, r, g, b);
r=getred(file_color); g=getgreen(file_color); b=getblue(file_color);
file_or_blue = gdImageColorAllocate(im, r, g, b);
r=getred(kbyte_color); g=getgreen(kbyte_color); b=getblue(kbyte_color);
kbyte_or_red = gdImageColorAllocate(im, r, g, b);
r=getred(page_color); g=getgreen(page_color); b=getblue(page_color);
page_or_cyan = gdImageColorAllocate(im, r, g, b);
r=getred(visit_color); g=getgreen(visit_color); b=getblue(visit_color);
visit_or_yellow = gdImageColorAllocate(im, r, g, b);
/* black outside border */
gdImageRectangle(im, 0, 0, xsize-1, ysize-1, black);
/* do shadow effect (bevel) border */
for (i=1; i<5 ;i++)
{
gdImageLine(im, i, i, xsize-i-2, i, white);
gdImageLine(im, i, i, i, ysize-i-2, white);
gdImageLine(im, i+1, ysize-i-1, xsize-i-1, ysize-i-1, dkgrey);
gdImageLine(im, xsize-i-1, i+1, xsize-i-1, ysize-i-1, dkgrey);
}
/* generic inside shadow box */
gdImageRectangle(im, 20, 25, xsize-21, ysize-21, black);
gdImageRectangle(im, 19, 24, xsize-22, ysize-22, white);
/* display the graph title */
gdImageString(im, gdFontMediumBold, 20, 8,
(unsigned char *)title, blue);
return;
}
/****************************************************************/
/* */
/* ASHEX2INT - ASCII HEX TO INT CONVERTER */
/* */
/****************************************************************/
int ashex2int(char *str)
{
/* returns base-10 integer value from a 2 ASCII hex number */
return from_hex(str[1])+(from_hex(str[0])*16);
}