X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_graph.c;h=67d7f0558bb57106085334af6fc6a66539745265;hb=a9e69acbc184063dcc0eda6a250ee1b7ae1cbb47;hp=a4f250c9b6ddffb773d5149c0a8c628d42552cae;hpb=3895c7d3d1089bcf68d89390189d96497392df23;p=rrdtool.git diff --git a/src/rrd_graph.c b/src/rrd_graph.c index a4f250c..67d7f05 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -1,5 +1,5 @@ /**************************************************************************** - * RRDtool 1.2.11 Copyright by Tobi Oetiker, 1997-2005 + * RRDtool 1.2.13 Copyright by Tobi Oetiker, 1997-2006 **************************************************************************** * rrd__graph.c produce graphs from data in rrdfiles ****************************************************************************/ @@ -179,7 +179,7 @@ enum gf_en gf_conv(char *string){ conv_if(VRULE,GF_VRULE) conv_if(LINE,GF_LINE) conv_if(AREA,GF_AREA) - conv_if(STACK,GF_STACK) + conv_if(STACK,GF_STACK) conv_if(TICK,GF_TICK) conv_if(DEF,GF_DEF) conv_if(CDEF,GF_CDEF) @@ -312,14 +312,8 @@ auto_scale( } -/* find SI magnitude symbol for the numbers on the y-axis*/ -void -si_unit( - image_desc_t *im /* image description */ -) -{ - - char symbol[] = {'a', /* 10e-18 Atto */ +static char si_symbol[] = { + 'a', /* 10e-18 Atto */ 'f', /* 10e-15 Femto */ 'p', /* 10e-12 Pico */ 'n', /* 10e-9 Nano */ @@ -331,9 +325,17 @@ si_unit( 'G', /* 10e9 Giga */ 'T', /* 10e12 Tera */ 'P', /* 10e15 Peta */ - 'E'};/* 10e18 Exa */ + 'E', /* 10e18 Exa */ +}; +const static int si_symbcenter = 6; + +/* find SI magnitude symbol for the numbers on the y-axis*/ +void +si_unit( + image_desc_t *im /* image description */ +) +{ - int symbcenter = 6; double digits,viewdigits=0; digits = floor( log( max( fabs(im->minval),fabs(im->maxval)))/log((double)im->base)); @@ -353,9 +355,9 @@ si_unit( im->viewfactor = im->magfact / pow((double)im->base , viewdigits); - if ( ((viewdigits+symbcenter) < sizeof(symbol)) && - ((viewdigits+symbcenter) >= 0) ) - im->symbol = symbol[(int)viewdigits+symbcenter]; + if ( ((viewdigits+si_symbcenter) < sizeof(si_symbol)) && + ((viewdigits+si_symbcenter) >= 0) ) + im->symbol = si_symbol[(int)viewdigits+si_symbcenter]; else im->symbol = '?'; } @@ -1020,8 +1022,7 @@ data_proc( image_desc_t *im ){ for(i=0;igdes_c;i++) { if((im->gdes[i].gf==GF_LINE) || (im->gdes[i].gf==GF_AREA) || - (im->gdes[i].gf==GF_TICK) || - (im->gdes[i].gf==GF_STACK)) { + (im->gdes[i].gf==GF_TICK)) { if((im->gdes[i].p_data = malloc((im->xsize +1) * sizeof(rrd_value_t)))==NULL){ rrd_set_error("malloc data_proc"); @@ -1043,7 +1044,6 @@ data_proc( image_desc_t *im ){ case GF_TICK: if (!im->gdes[ii].stack) paintval = 0.0; - case GF_STACK: value = im->gdes[ii].yrule; if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) { /* The time of the data doesn't necessarily match @@ -1082,6 +1082,10 @@ data_proc( image_desc_t *im ){ im->gdes[ii].p_data[i] = DNAN; } break; + case GF_STACK: + rrd_set_error("STACK should already be turned into LINE or AREA here"); + return -1; + break; default: break; } @@ -1361,7 +1365,6 @@ print_calc(image_desc_t *im, char ***prdata) case GF_LINE: case GF_AREA: case GF_TICK: - case GF_STACK: case GF_HRULE: case GF_VRULE: graphelement = 1; @@ -1376,6 +1379,10 @@ print_calc(image_desc_t *im, char ***prdata) case GF_SHIFT: case GF_XPORT: break; + case GF_STACK: + rrd_set_error("STACK should already be turned into LINE or AREA here"); + return -1; + break; } } return graphelement; @@ -1527,11 +1534,10 @@ calc_horizontal_grid(image_desc_t *im) double range; double scaledrange; int pixel,i; - int gridind; + int gridind=0; int decimals, fractionals; im->ygrid_scale.labfact=2; - gridind=-1; range = im->maxval - im->minval; scaledrange = range / im->magfact; @@ -1582,17 +1588,16 @@ calc_horizontal_grid(image_desc_t *im) else { for(i=0;ylab[i].grid > 0;i++){ pixel = im->ysize / (scaledrange / ylab[i].grid); - if (pixel > 7) { - gridind = i; - break; - } + gridind = i; + if (pixel > 7) + break; } for(i=0; i<4;i++) { if (pixel * ylab[gridind].lfac[i] >= 2.5 * im->text_prop[TEXT_PROP_AXIS].size) { - im->ygrid_scale.labfact = ylab[gridind].lfac[i]; + im->ygrid_scale.labfact = ylab[gridind].lfac[i]; break; - } + } } im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact; @@ -1609,6 +1614,7 @@ int draw_horizontal_grid(image_desc_t *im) int i; double scaledstep; char graph_label[100]; + int nlabels=0; double X0=im->xorigin; double X1=im->xorigin+im->xsize; @@ -1619,9 +1625,13 @@ int draw_horizontal_grid(image_desc_t *im) MaxY = scaledstep*(double)egrid; for (i = sgrid; i <= egrid; i++){ double Y0=ytr(im,im->ygrid_scale.gridstep*i); + double YN=ytr(im,im->ygrid_scale.gridstep*(i+1)); if ( Y0 >= im->yorigin-im->ysize && Y0 <= im->yorigin){ - if(i % im->ygrid_scale.labfact == 0){ + /* Make sure at least 2 grid labels are shown, even if it doesn't agree + with the chosen settings. Add a label if required by settings, or if + there is only one label so far and the next grid line is out of bounds. */ + if(i % im->ygrid_scale.labfact == 0 || ( nlabels==1 && (YN < im->yorigin-im->ysize || YN > im->yorigin) )){ if (im->symbol == ' ') { if(im->extra_flags & ALTYGRID) { sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*(double)i); @@ -1644,6 +1654,7 @@ int draw_horizontal_grid(image_desc_t *im) } } } + nlabels++; gfx_new_text ( im->canvas, X0-im->text_prop[TEXT_PROP_AXIS].size, Y0, @@ -1737,8 +1748,24 @@ horizontal_log_grid(image_desc_t *im) X1+2,Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID], im->grid_dash_on, im->grid_dash_off); - - sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]); + + if (im->extra_flags & FORCE_UNITS_SI) { + double pvalue = value * yloglab[majoridx][i]; + double scale = floor( log10( fabs(pvalue)) / 3); + char symbol; + + pvalue /= pow(10, 3*scale); + + if ( ((scale+si_symbcenter) < sizeof(si_symbol)) && + ((scale+si_symbcenter) >= 0) ) + symbol = si_symbol[(int)scale+si_symbcenter]; + else + symbol = '?'; + + sprintf(graph_label,"%3.0f %c", pvalue, symbol); + } else + sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]); + gfx_new_text ( im->canvas, X0-im->text_prop[TEXT_PROP_AXIS].size, Y0, im->graph_col[GRC_FONT], @@ -1974,6 +2001,17 @@ grid_paint(image_desc_t *im) 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/2, im->yimg-6, + ( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044, + im->text_prop[TEXT_PROP_AXIS].font, + 5.5, im->tabwidth, 0, + GFX_H_CENTER, GFX_V_BOTTOM, + im->watermark); + } /* graph labels */ if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) { @@ -2137,6 +2175,8 @@ graph_size_location(image_desc_t *im, int elements ** |v+--+-------------------------------+--------+ ** | |..............legends......................| ** +-+-------------------------------------------+ + ** | watermark | + ** +---------------------------------------------+ */ int Xvertical=0, Ytitle =0, @@ -2149,7 +2189,9 @@ graph_size_location(image_desc_t *im, int elements #if 0 Xlegend =0, Ylegend =0, #endif - Xspacing =15, Yspacing =15; + Xspacing =15, Yspacing =15, + + Ywatermark =4; if (im->extra_flags & ONLY_GRAPH) { im->xorigin =0; @@ -2236,12 +2278,13 @@ graph_size_location(image_desc_t *im, int elements xtr(im,0); /* The vertical size is interesting... we need to compare - ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend} with Yvertical - ** however we need to know {Ytitle+Ymain+Yxlabel} in order to - ** start even thinking about Ylegend. + ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with + ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel} + ** in order to start even thinking about Ylegend or Ywatermark. ** ** Do it in three portions: First calculate the inner part, - ** then do the legend, then adjust the total height of the img. + ** then do the legend, then adjust the total height of the img, + ** adding space for a watermark if one exists; */ /* reserve space for main and/or pie */ @@ -2270,7 +2313,10 @@ graph_size_location(image_desc_t *im, int elements */ if(leg_place(im)==-1) return -1; - + + if (im->watermark[0] != '\0') { + im->yimg += Ywatermark; + } #if 0 if (Xlegend > im->ximg) { @@ -2344,7 +2390,6 @@ graph_paint(image_desc_t *im, char ***calcpr) gfx_node_t *node; double areazero = 0.0; - enum gf_en stack_gf = GF_PRINT; graph_desc_t *lastgdes = NULL; /* if we are lazy and there is nothing to PRINT ... quit now */ @@ -2468,22 +2513,27 @@ graph_paint(image_desc_t *im, char ***calcpr) for (ii = 0; ii < im->xsize; ii++) { if (!isnan(im->gdes[i].p_data[ii]) && - im->gdes[i].p_data[ii] > 0.0) - { - /* generate a tick */ - gfx_new_line(im->canvas, im -> xorigin + ii, - im -> yorigin - (im -> gdes[i].yrule * im -> ysize), - im -> xorigin + ii, - im -> yorigin, - 1.0, - im -> gdes[i].col ); - } + im->gdes[i].p_data[ii] != 0.0) + { + if (im -> gdes[i].yrule > 0 ) { + gfx_new_line(im->canvas, + im -> xorigin + ii, im->yorigin, + im -> xorigin + ii, im->yorigin - im -> gdes[i].yrule * im -> ysize, + 1.0, + 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, + 1.0, + im -> gdes[i].col ); + + } + } } break; case GF_LINE: case GF_AREA: - stack_gf = im->gdes[i].gf; - case GF_STACK: /* fix data points at oo and -oo */ for(ii=0;iixsize;ii++){ if (isinf(im->gdes[i].p_data[ii])){ @@ -2509,7 +2559,7 @@ graph_paint(image_desc_t *im, char ***calcpr) ********************************************************* */ if (im->gdes[i].col != 0x0){ /* GF_LINE and friend */ - if(stack_gf == GF_LINE ){ + if(im->gdes[i].gf == GF_LINE ){ double last_y=0.0; node = NULL; for(ii=1;iixsize;ii++){ @@ -2653,6 +2703,10 @@ graph_paint(image_desc_t *im, char ***calcpr) } break; #endif + case GF_STACK: + rrd_set_error("STACK should already be turned into LINE or AREA here"); + return -1; + break; } /* switch */ } @@ -2742,9 +2796,12 @@ gdes_alloc(image_desc_t *im){ im->gdes[im->gdes_c-1].step=im->step; im->gdes[im->gdes_c-1].step_orig=im->step; im->gdes[im->gdes_c-1].stack=0; + im->gdes[im->gdes_c-1].linewidth=0; im->gdes[im->gdes_c-1].debug=0; im->gdes[im->gdes_c-1].start=im->start; + im->gdes[im->gdes_c-1].start_orig=im->start; im->gdes[im->gdes_c-1].end=im->end; + im->gdes[im->gdes_c-1].end_orig=im->end; im->gdes[im->gdes_c-1].vname[0]='\0'; im->gdes[im->gdes_c-1].data=NULL; im->gdes[im->gdes_c-1].ds_namv=NULL; @@ -2757,6 +2814,8 @@ gdes_alloc(image_desc_t *im){ im->gdes[im->gdes_c-1].format[0]='\0'; im->gdes[im->gdes_c-1].rrd[0]='\0'; im->gdes[im->gdes_c-1].ds=-1; + im->gdes[im->gdes_c-1].cf_reduce=CF_AVERAGE; + im->gdes[im->gdes_c-1].cf=CF_AVERAGE; im->gdes[im->gdes_c-1].p_data=NULL; im->gdes[im->gdes_c-1].yrule=DNAN; im->gdes[im->gdes_c-1].xrule=0; @@ -2766,7 +2825,7 @@ gdes_alloc(image_desc_t *im){ /* copies input untill the first unescaped colon is found or until input ends. backslashes have to be escaped as well */ int -scan_for_col(char *input, int len, char *output) +scan_for_col(const char *const input, int len, char *const output) { int inp,outp=0; for (inp=0; @@ -2872,6 +2931,9 @@ rrd_graph_init(image_desc_t *im) #endif #ifdef HAVE_SETLOCALE setlocale(LC_TIME,""); +#ifdef HAVE_MBSTOWCS + setlocale(LC_CTYPE,""); +#endif #endif im->yorigin=0; im->xorigin=0; @@ -2884,6 +2946,7 @@ rrd_graph_init(image_desc_t *im) im->step = 0; im->ylegend[0] = '\0'; im->title[0] = '\0'; + im->watermark[0] = '\0'; im->minval = DNAN; im->maxval = DNAN; im->unitsexponent= 9999; @@ -2919,8 +2982,8 @@ rrd_graph_init(image_desc_t *im) windir = getenv("windir"); /* %windir% is something like D:\windows or C:\winnt */ if (windir != NULL) { - strncpy(rrd_win_default_font,windir,999); - rrd_win_default_font[999] = '\0'; + strncpy(rrd_win_default_font,windir,500); + rrd_win_default_font[500] = '\0'; strcat(rrd_win_default_font,"\\fonts\\"); strcat(rrd_win_default_font,RRD_DEFAULT_FONT); for(i=0;iextra_flags |= FORCE_RULES_LEGEND; break; + case LONGOPT_UNITS_SI: + if(im->extra_flags & FORCE_UNITS) { + rrd_set_error("--units can only be used once!"); + return; + } + if(strcmp(optarg,"si")==0) + im->extra_flags |= FORCE_UNITS_SI; + else { + rrd_set_error("invalid argument for --units: %s", optarg ); + return; + } + break; case 'X': im->unitsexponent = atoi(optarg); break; @@ -3281,6 +3362,11 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) im->canvas->font_aa_threshold = atof(optarg); break; + case 'W': + strncpy(im->watermark,optarg,100); + im->watermark[99]='\0'; + break; + case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); @@ -3386,12 +3472,17 @@ int bad_format(char *fmt) { /* '%s', '%S' and '%%' are allowed */ if (*ptr == 's' || *ptr == 'S' || *ptr == '%') ptr++; + /* %c is allowed (but use only with vdef!) */ + else if (*ptr == 'c') { + ptr++; + n=1; + } + /* or else '% 6.2lf' and such are allowed */ else { - /* optional padding character */ if (*ptr == ' ' || *ptr == '+' || *ptr == '-') ptr++; - + /* This should take care of 'm.n' with all three optional */ while (*ptr >= '0' && *ptr <= '9') ptr++; if (*ptr == '.') ptr++; @@ -3412,7 +3503,7 @@ int bad_format(char *fmt) { int vdef_parse(gdes,str) struct graph_desc_t *gdes; -char *str; +const char *const str; { /* A VDEF currently is either "func" or "param,func" * so the parsing is rather simple. Change if needed.