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)
}
-/* 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 */
'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));
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 = '?';
}
for(i=0;i<im->gdes_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");
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
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;
}
case GF_LINE:
case GF_AREA:
case GF_TICK:
- case GF_STACK:
case GF_HRULE:
case GF_VRULE:
graphelement = 1;
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;
int i;
double scaledstep;
char graph_label[100];
+ int nlabels=0;
double X0=im->xorigin;
double X1=im->xorigin+im->xsize;
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);
}
}
}
+ nlabels++;
gfx_new_text ( im->canvas,
X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
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],
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) ) {
** |v+--+-------------------------------+--------+
** | |..............legends......................|
** +-+-------------------------------------------+
+ ** | watermark |
+ ** +---------------------------------------------+
*/
int Xvertical=0,
Ytitle =0,
#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;
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 */
*/
if(leg_place(im)==-1)
return -1;
-
+
+ if (im->watermark[0] != '\0') {
+ im->yimg += Ywatermark;
+ }
#if 0
if (Xlegend > im->ximg) {
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 */
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;ii<im->xsize;ii++){
if (isinf(im->gdes[i].p_data[ii])){
********************************************************* */
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;ii<im->xsize;ii++){
}
break;
#endif
+ case GF_STACK:
+ rrd_set_error("STACK should already be turned into LINE or AREA here");
+ return -1;
+ break;
} /* switch */
}
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;
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;
#endif
#ifdef HAVE_SETLOCALE
setlocale(LC_TIME,"");
+#ifdef HAVE_MBSTOWCS
+ setlocale(LC_CTYPE,"");
+#endif
#endif
im->yorigin=0;
im->xorigin=0;
im->step = 0;
im->ylegend[0] = '\0';
im->title[0] = '\0';
+ im->watermark[0] = '\0';
im->minval = DNAN;
im->maxval = DNAN;
im->unitsexponent= 9999;
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;i<DIM(text_prop);i++){
parsetime("end-24h", &start_tv);
parsetime("now", &end_tv);
+ /* defines for long options without a short equivalent. should be bytes,
+ and may not collide with (the ASCII value of) short options */
+ #define LONGOPT_UNITS_SI 255
+
while (1){
static struct option long_options[] =
{
{"no-gridfit", no_argument, 0, 'N'},
{"units-exponent",required_argument, 0, 'X'},
{"units-length",required_argument, 0, 'L'},
+ {"units", required_argument, 0, LONGOPT_UNITS_SI },
{"step", required_argument, 0, 'S'},
{"tabwidth", required_argument, 0, 'T'},
{"font-render-mode", required_argument, 0, 'R'},
{"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 */
{0,0,0,0}};
int option_index = 0;
int col_start,col_end;
opt = getopt_long(argc, argv,
- "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:",
+ "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
long_options, &option_index);
if (opt == EOF)
case 'F':
im->extra_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;
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);