index 74884bb9aec1ddd625f6ed23e99673d9b7aee6f0..ee44c77e3481cbb47aca15ba50f79194489f8e30 100644 (file)
--- a/program/src/rrd_graph.c
+++ b/program/src/rrd_graph.c
/****************************************************************************
- * RRDtool 1.2.25 Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.2.30 Copyright by Tobi Oetiker, 1997-2009
****************************************************************************
* rrd__graph.c produce graphs from data in rrdfiles
****************************************************************************/
{10, 0, TMT_MINUTE,5, TMT_MINUTE,20, TMT_MINUTE,20, 0,"%H:%M"},
{30, 0, TMT_MINUTE,10, TMT_HOUR,1, TMT_HOUR,1, 0,"%H:%M"},
{60, 0, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,2, 0,"%H:%M"},
- {60, 24*3600, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,4, 0,"%a %H:%M"},
+ {60, 24*3600, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,6, 0,"%a %H:%M"},
{180, 0, TMT_HOUR,1, TMT_HOUR,6, TMT_HOUR,6, 0,"%H:%M"},
{180, 24*3600, TMT_HOUR,1, TMT_HOUR,6, TMT_HOUR,12, 0,"%a %H:%M"},
/*{300, 0, TMT_HOUR,3, TMT_HOUR,12, TMT_HOUR,12, 12*3600,"%a %p"}, this looks silly*/
im->minval = sensiblevalues[i]*(im->magfact);
if (-sensiblevalues[i-1]<=scaled_min &&
- -sensiblevalues[i]>=scaled_min)
+ -sensiblevalues[i]>=scaled_min)
im->minval = -sensiblevalues[i-1]*(im->magfact);
if (sensiblevalues[i-1] >= scaled_max &&
double new_range = factor * (im->maxval - im->minval);
double gridstep = im->ygrid_scale.gridstep;
double minor_y, minor_y_px, minor_y_px_frac;
+
+
if (im->maxval > 0.0)
im->maxval = im->minval + new_range;
else
im->minval = im->maxval - new_range;
ytr(im,DNAN); /* reset precalc */
+
/* make sure first minor gridline is on integer pixel y coord */
minor_y = gridstep * floor(im->minval / gridstep);
while (minor_y < im->minval)
return 0;
}
+static int AlmostEqual2sComplement (float A, float B, int maxUlps)
+{
+
+ int aInt = *(int*)&A;
+ int bInt = *(int*)&B;
+ int intDiff;
+ /* Make sure maxUlps is non-negative and small enough that the
+ default NAN won't compare as equal to anything. */
+
+ /* assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); */
+
+ /* Make aInt lexicographically ordered as a twos-complement int */
+
+ if (aInt < 0)
+ aInt = 0x80000000l - aInt;
+
+ /* Make bInt lexicographically ordered as a twos-complement int */
+
+ if (bInt < 0)
+ bInt = 0x80000000l - bInt;
+
+ intDiff = abs(aInt - bInt);
+
+ if (intDiff <= maxUlps)
+ return 1;
+
+ return 0;
+}
+
/* massage data so, that we get one value for each x coordinate in the graph */
int
data_proc( image_desc_t *im ){
im->maxval = maxval;
}
/* make sure min is smaller than max */
- if (im->minval > im->maxval) {
+ if (im->minval > im->maxval ) {
+ if (im->maxval > 0)
im->minval = 0.99 * im->maxval;
+ else
+ im->minval = 1.01 * im->maxval;
}
/* make sure min and max are not equal */
- if (im->minval == im->maxval) {
- im->maxval *= 1.01;
+ if ( AlmostEqual2sComplement(im->minval,im->maxval,4)) {
+ if (im->maxval > 0)
+ im->maxval *= 1.01;
+ else
+ im->maxval *= 0.99;
+
if (! im->logarithmic) {
- im->minval *= 0.99;
+ if (im->minval > 0)
+ im->minval *= 0.99;
+ else
+ im->minval *= 1.01;
}
/* make sure min and max are not both zero */
- if (im->maxval == 0.0) {
+ if (AlmostEqual2sComplement(im->maxval,0,4)) {
im->maxval = 1.0;
}
}
int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1);
int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1);
double MaxY;
+ double second_axis_magfact = 0;
+ char *second_axis_symb = "";
scaledstep = im->ygrid_scale.gridstep/(double)im->magfact*(double)im->viewfactor;
MaxY = scaledstep*(double)egrid;
for (i = sgrid; i <= egrid; i++){
}
}
nlabels++;
+ if (im->second_axis_scale != 0){
+ char graph_label_right[100];
+ double sval = im->ygrid_scale.gridstep*(double)i*im->second_axis_scale+im->second_axis_shift;
+ if (im->second_axis_format[0] == '\0'){
+ if (!second_axis_magfact){
+ double dummy = im->ygrid_scale.gridstep*(double)(sgrid+egrid)/2.0*im->second_axis_scale+im->second_axis_shift;
+ auto_scale(im,&dummy,&second_axis_symb,&second_axis_magfact);
+ }
+ sval /= second_axis_magfact;
+
+ if(MaxY < 10) {
+ sprintf(graph_label_right,"%5.1f %s",sval,second_axis_symb);
+ } else {
+ sprintf(graph_label_right,"%5.0f %s",sval,second_axis_symb);
+ }
+ }
+ else {
+ sprintf(graph_label_right,im->second_axis_format,sval);
+ }
+ gfx_new_text ( im->canvas,
+ X1+7, Y0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER,
+ graph_label_right );
+ }
gfx_new_text ( im->canvas,
X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
return mnt;
}
-static int AlmostEqual2sComplement (float A, float B, int maxUlps)
-{
-
- int aInt = *(int*)&A;
- int bInt = *(int*)&B;
- int intDiff;
- /* Make sure maxUlps is non-negative and small enough that the
- default NAN won't compare as equal to anything. */
-
- /* assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); */
-
- /* Make aInt lexicographically ordered as a twos-complement int */
-
- if (aInt < 0)
- aInt = 0x80000000l - aInt;
-
- /* Make bInt lexicographically ordered as a twos-complement int */
-
- if (bInt < 0)
- bInt = 0x80000000l - bInt;
-
- intDiff = abs(aInt - bInt);
-
- if (intDiff <= maxUlps)
- return 1;
-
- return 0;
-}
-
/* logaritmic horizontal grid */
int
horizontal_log_grid(image_desc_t *im)
else
symbol = '?';
- sprintf(graph_label,"%3.0f %c", pvalue, symbol);
- } else
+ sprintf(graph_label,"%3.0f %c", pvalue, symbol);
+ } else {
sprintf(graph_label,"%3.0e", value);
+ }
+ if (im->second_axis_scale != 0){
+ char graph_label_right[100];
+ double sval = value*im->second_axis_scale+im->second_axis_shift;
+ if (im->second_axis_format[0] == '\0'){
+ if (im->extra_flags & FORCE_UNITS_SI) {
+ double mfac = 1;
+ char *symb = "";
+ auto_scale(im,&sval,&symb,&mfac);
+ sprintf(graph_label_right,"%4.0f %s", sval,symb);
+ }
+ else {
+ sprintf(graph_label_right,"%3.0e", sval);
+ }
+ }
+ else {
+ sprintf(graph_label_right,im->second_axis_format,sval);
+ }
+
+ gfx_new_text ( im->canvas,
+ X1+7, Y0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER,
+ graph_label_right );
+ }
+
gfx_new_text ( im->canvas,
- X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
- im->graph_col[GRC_FONT],
- im->text_prop[TEXT_PROP_AXIS].font,
- im->text_prop[TEXT_PROP_AXIS].size,
- im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER,
- graph_label );
+ X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER,
+ graph_label );
/* minor grid */
if(mid < 4 && exfrac == 1) {
im->xorigin+0.5, im->yorigin-im->ysize-7, /* LINEOFFSET */
im->graph_col[GRC_ARROW]);
+ if (im->second_axis_scale != 0){
+ gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin+4,
+ im->xorigin+im->xsize,im->yorigin-im->ysize-4,
+ MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+ gfx_new_area ( im->canvas,
+ im->xorigin+im->xsize-2, im->yorigin-im->ysize-2,
+ im->xorigin+im->xsize+3, im->yorigin-im->ysize-2,
+ im->xorigin+im->xsize+0.5, im->yorigin-im->ysize-7, /* LINEOFFSET */
+ im->graph_col[GRC_ARROW]);
+ }
}
void
}
/* yaxis unit description */
- gfx_new_text( im->canvas,
+ if (im->ylegend[0] != '\0'){
+ gfx_new_text( im->canvas,
10, (im->yorigin - im->ysize/2),
im->graph_col[GRC_FONT],
im->text_prop[TEXT_PROP_UNIT].font,
RRDGRAPH_YLEGEND_ANGLE,
GFX_H_LEFT, GFX_V_CENTER,
im->ylegend);
-
+ }
+ if (im->second_axis_legend[0] != '\0'){
+ double Xylabel=gfx_get_text_width(im->canvas, 0,
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,
+ "0", 0) * im->unitslength
+ + im->text_prop[TEXT_PROP_UNIT].size *2;
+ gfx_new_text( im->canvas,
+ im->xorigin+im->xsize+Xylabel+4, (im->yorigin - im->ysize/2),
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_UNIT].font,
+ im->text_prop[TEXT_PROP_UNIT].size, im->tabwidth,
+ RRDGRAPH_YLEGEND_ANGLE,
+ GFX_H_LEFT, GFX_V_CENTER,
+ im->second_axis_legend);
+ }
/* graph title */
gfx_new_text( im->canvas,
im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.3+4,
GFX_H_CENTER, GFX_V_CENTER,
im->title);
/* rrdtool 'logo' */
- gfx_new_text( im->canvas,
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ gfx_new_text( im->canvas,
im->ximg-7, 7,
( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044,
im->text_prop[TEXT_PROP_AXIS].font,
5.5, im->tabwidth, 270,
GFX_H_RIGHT, GFX_V_TOP,
"RRDTOOL / TOBI OETIKER");
-
+ }
/* graph watermark */
if(im->watermark[0] != '\0') {
gfx_new_text( im->canvas,
*/
im->ximg = Xylabel + Xmain + 2 * Xspacing;
+ if (im->second_axis_scale != 0){
+ im->ximg += Xylabel + Xspacing;
+ }
+ if (im->extra_flags & NO_RRDTOOL_TAG){
+ im->ximg -= Xspacing;
+ }
+
#ifdef WITH_PIECHART
im->ximg += Xpie;
#endif
im->ximg += Xvertical;
im->xorigin += Xvertical;
}
+ if (im->second_axis_legend[0] != '\0' ) {
+ im->ximg += Xvertical;
+ }
+
xtr(im,0);
/* The vertical size is interesting... we need to compare
im -> gdes[i].col );
} else if ( im -> gdes[i].yrule < 0 ) {
gfx_new_line(im->canvas,
- im -> xorigin + ii, im->yorigin - im -> ysize,
- im -> xorigin + ii, im->yorigin - ( 1 - im -> gdes[i].yrule ) * im -> ysize,
+ im -> xorigin + ii, im->yorigin - im->ysize,
+ im -> xorigin + ii, im->yorigin - im->ysize - im->gdes[i].yrule * im->ysize,
1.0,
im -> gdes[i].col );
@@ -3071,6 +3180,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *s
*ymax=im.maxval;
if (im.imginfo) {
char *filename;
+ char *path;
if (!(*prdata)) {
/* maybe prdata is not allocated yet ... lets do it now */
if ((*prdata = calloc(2,sizeof(char *)))==NULL) {
@@ -3083,13 +3193,10 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *s
rrd_set_error("malloc imginfo");
return -1;
}
- filename=im.graphfile+strlen(im.graphfile);
- while(filename > im.graphfile) {
- if (*(filename-1)=='/' || *(filename-1)=='\\' ) break;
- filename--;
- }
-
+ path = strdup(im.graphfile);
+ filename = basename(path);
sprintf((*prdata)[0],im.imginfo,filename,(long)(im.canvas->zoom*im.ximg),(long)(im.canvas->zoom*im.yimg));
+ free(path);
}
im_free(&im);
return 0;
im->ysize = 100;
im->step = 0;
im->ylegend[0] = '\0';
+ im->second_axis_scale = 0; /* 0 disables it */
+ im->second_axis_shift = 0; /* no shift by default */
+ im->second_axis_legend[0] = '\0';
+ im->second_axis_format[0] = '\0';
im->title[0] = '\0';
im->watermark[0] = '\0';
im->minval = DNAN;
{"font-smoothing-threshold", required_argument, 0, 'B'},
{"watermark", required_argument, 0, 'W'},
{"alt-y-mrtg", no_argument, 0, 1000}, /* this has no effect it is just here to save old apps from crashing when they use it */
+ {"disable-rrdtool-tag", no_argument, 0, 1001},
+ {"right-axis", required_argument, 0, 1002},
+ {"right-axis-label", required_argument, 0, 1003},
+ {"right-axis-format", required_argument, 0, 1004},
{0,0,0,0}};
int option_index = 0;
int opt;
case 'F':
im->extra_flags |= FORCE_RULES_LEGEND;
break;
+ case 1001:
+ im->extra_flags |= NO_RRDTOOL_TAG;
+ break;
case LONGOPT_UNITS_SI:
if(im->extra_flags & FORCE_UNITS) {
rrd_set_error("--units can only be used once!");
return;
}
break;
+ case 1002: /* right y axis */
+
+ if(sscanf(optarg,
+ "%lf:%lf",
+ &im->second_axis_scale,
+ &im->second_axis_shift) == 2) {
+ if(im->second_axis_scale==0){
+ rrd_set_error("the second_axis_scale must not be 0");
+ return;
+ }
+ } else {
+ rrd_set_error("invalid right-axis format expected scale:shift");
+ return;
+ }
+ break;
+ case 1003:
+ strncpy(im->second_axis_legend,optarg,150);
+ im->second_axis_legend[150]='\0';
+ break;
+ case 1004:
+ if (bad_format(optarg)){
+ rrd_set_error("use either %le or %lf formats");
+ return;
+ }
+ strncpy(im->second_axis_format,optarg,150);
+ im->second_axis_format[150]='\0';
+ break;
case 'v':
strncpy(im->ylegend,optarg,150);
im->ylegend[150]='\0';
case 'n':{
char prop[15];
double size = 1;
- char font[1024] = "";
-
+ int end;
if(sscanf(optarg,
- "%10[A-Z]:%lf:%1000s",
- prop,&size,font) >= 2){
+ "%10[A-Z]:%lf%n",
+ prop,&size,&end) >= 2){
int sindex,propidx;
if((sindex=text_prop_conv(prop)) != -1){
for (propidx=sindex;propidx<TEXT_PROP_LAST;propidx++){
if (size > 0){
im->text_prop[propidx].size=size;
+ }
+ if ((int)strlen(optarg) > end+2){
+ if (optarg[end] == ':'){
+ strncpy(im->text_prop[propidx].font,optarg+end+1,255);
+ im->text_prop[propidx].font[255] = '\0';
+ } else {
+ rrd_set_error("expected : after font size in '%s'",optarg);
+ return;
+ }
}
- if (strlen(font) > 0){
- strcpy(im->text_prop[propidx].font,font);
- }
+ /* only run the for loop for DEFAULT (0) for
+ all others, we break here. woodo programming */
if (propidx==sindex && sindex != 0) break;
}
} else {
src = &im->gdes[dst->vidx];
data = src->data + src->ds;
steps = (src->end - src->start) / src->step;
-
#if 0
printf("DEBUG: start == %lu, end == %lu, %lu steps\n"
,src->start