/****************************************************************************
- * RRDtool 1.2.0 Copyright by Tobi Oetiker, 1997-2005
+ * RRDtool 1.2.9 Copyright by Tobi Oetiker, 1997-2005
****************************************************************************
* rrd__graph.c produce graphs from data in rrdfiles
****************************************************************************/
#include "rrd_tool.h"
-#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
#include <io.h>
#include <fcntl.h>
#endif
#ifndef RRD_DEFAULT_FONT
/* there is special code later to pick Cour.ttf when running on windows */
-#define RRD_DEFAULT_FONT "VeraMono.ttf"
+#define RRD_DEFAULT_FONT "DejaVuSansMono-Roman.ttf"
#endif
text_prop_t text_prop[] = {
0xE0505080, /* major grid */
0x000000FF, /* font */
0x802020FF, /* arrow */
- 0x202020FF /* axis */
-};
+ 0x202020FF, /* axis */
+ 0x000000FF /* frame */
+};
/* #define DEBUG */
if (! im->rigid) {
/* keep yval as-is */
} else if (yval > im->yorigin) {
- yval = im->yorigin+2;
+ yval = im->yorigin +0.00001;
} else if (yval < im->yorigin - im->ysize){
- yval = im->yorigin - im->ysize - 2;
+ yval = im->yorigin - im->ysize - 0.00001;
}
return yval;
}
conv_if(FONT,GRC_FONT)
conv_if(ARROW,GRC_ARROW)
conv_if(AXIS,GRC_AXIS)
+ conv_if(FRAME,GRC_FRAME)
return -1;
}
* and the resulting number is the step size for the
* resulting data source.
*/
- for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
- if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
- im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
- long ptr = im->gdes[gdi].rpnp[rpi].ptr;
- if (im->gdes[ptr].ds_cnt == 0) {
+ for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
+ if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
+ im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
+ long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+ if (im->gdes[ptr].ds_cnt == 0) { /* this is a VDEF data source */
#if 0
- printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
- im->gdes[gdi].vname,
- im->gdes[ptr].vname);
- printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
+ printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
+ im->gdes[gdi].vname,
+ im->gdes[ptr].vname);
+ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
#endif
im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val;
im->gdes[gdi].rpnp[rpi].op = OP_NUMBER;
- } else {
- if ((steparray =
+ } else { /* normal variables and PREF(variables) */
+
+ /* add one entry to the array that keeps track of the step sizes of the
+ * data sources going into the CDEF. */
+ if ((steparray =
rrd_realloc(steparray,
(++stepcnt+1)*sizeof(*steparray)))==NULL){
- rrd_set_error("realloc steparray");
- rpnstack_free(&rpnstack);
- return -1;
+ rrd_set_error("realloc steparray");
+ rpnstack_free(&rpnstack);
+ return -1;
};
steparray[stepcnt-1] = im->gdes[ptr].step;
* to the earliest endpoint of any of the
* rras involved (ptr)
*/
+
if(im->gdes[gdi].start < im->gdes[ptr].start)
im->gdes[gdi].start = im->gdes[ptr].start;
* further save step size and data source
* count of this rra
*/
- im->gdes[gdi].rpnp[rpi].data = im->gdes[ptr].data + im->gdes[ptr].ds;
- im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step;
+ im->gdes[gdi].rpnp[rpi].data = im->gdes[ptr].data + im->gdes[ptr].ds;
+ im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step;
im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt;
/* backoff the *.data ptr; this is done so
/* move the data pointers to the correct period */
for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
- if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
- im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
- long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+ if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
+ im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
+ long ptr = im->gdes[gdi].rpnp[rpi].ptr;
long diff = im->gdes[gdi].start - im->gdes[ptr].start;
if(diff > 0)
else {
for(i=0;ylab[i].grid > 0;i++){
pixel = im->ysize / (scaledrange / ylab[i].grid);
- if (pixel > 5) {
+ if (pixel > 7) {
gridind = i;
break;
}
}
for(i=0; i<4;i++) {
- if (pixel * ylab[gridind].lfac[i] >= 2 * im->text_prop[TEXT_PROP_AXIS].size) {
+ if (pixel * ylab[gridind].lfac[i] >= 2.5 * im->text_prop[TEXT_PROP_AXIS].size) {
im->ygrid_scale.labfact = ylab[gridind].lfac[i];
break;
}
int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1);
int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1);
+ double MaxY;
scaledstep = im->ygrid_scale.gridstep/im->magfact;
+ MaxY = scaledstep*(double)im->viewfactor*(double)egrid;
for (i = sgrid; i <= egrid; i++){
double Y0=ytr(im,im->ygrid_scale.gridstep*i);
if ( Y0 >= im->yorigin-im->ysize
&& Y0 <= im->yorigin){
if(i % im->ygrid_scale.labfact == 0){
if (i==0 || im->symbol == ' ') {
- if(scaledstep < 1){
+ if(MaxY < 10) {
if(im->extra_flags & ALTYGRID) {
sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*im->viewfactor*i);
}
sprintf(graph_label,"%4.0f",scaledstep*im->viewfactor*i);
}
}else {
- if(scaledstep < 1){
+ if(MaxY < 10){
sprintf(graph_label,"%4.1f %c",scaledstep*im->viewfactor*i, im->symbol);
} else {
sprintf(graph_label,"%4.0f %c",scaledstep*im->viewfactor*i, im->symbol);
} else {
res = draw_horizontal_grid(im);
}
-
+
/* dont draw horizontal grid if there is no min and max val */
if (! res ) {
char *nodata = "No Data found";
/* yaxis unit description */
gfx_new_text( im->canvas,
- 7, (im->yorigin - im->ysize/2),
+ 10, (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,
/* graph title */
gfx_new_text( im->canvas,
- im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.2,
+ im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.3+4,
im->graph_col[GRC_FONT],
im->text_prop[TEXT_PROP_TITLE].font,
im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
GFX_H_CENTER, GFX_V_CENTER,
im->title);
+ /* rrdtool 'logo' */
+ 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 labels */
if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) {
boxH = gfx_get_text_width(im->canvas, 0,
im->text_prop[TEXT_PROP_LEGEND].font,
im->text_prop[TEXT_PROP_LEGEND].size,
- im->tabwidth,"M", 0)*1.2;
- boxV = boxH;
+ im->tabwidth,"o", 0) * 1.2;
+ boxV = boxH*1.1;
- /* make sure transparent colors show up all the same */
- node = gfx_new_area(im->canvas,
+ /* make sure transparent colors show up the same way as in the graph */
+ node = gfx_new_area(im->canvas,
X0,Y0-boxV,
X0,Y0,
X0+boxH,Y0,
- im->graph_col[GRC_CANVAS]);
+ im->graph_col[GRC_BACK]);
gfx_add_point ( node, X0+boxH, Y0-boxV );
node = gfx_new_area(im->canvas,
im->gdes[i].col);
gfx_add_point ( node, X0+boxH, Y0-boxV );
node = gfx_new_line(im->canvas,
- X0,Y0-boxV, X0,Y0,
- 1,im->graph_col[GRC_FONT]);
+ X0,Y0-boxV,
+ X0,Y0,
+ 1.0,im->graph_col[GRC_FRAME]);
gfx_add_point(node,X0+boxH,Y0);
gfx_add_point(node,X0+boxH,Y0-boxV);
gfx_close_path(node);
** | |..............legends......................|
** +-+-------------------------------------------+
*/
- int Xvertical=0, Yvertical=0,
- Xtitle =0, Ytitle =0,
+ int Xvertical=0,
+ Ytitle =0,
Xylabel =0,
Xmain =0, Ymain =0,
#ifdef WITH_PIECHART
if (im->ylegend[0] != '\0' ) {
Xvertical = im->text_prop[TEXT_PROP_UNIT].size *2;
- Yvertical = gfx_get_text_width(im->canvas, 0,
- im->text_prop[TEXT_PROP_UNIT].font,
- im->text_prop[TEXT_PROP_UNIT].size,
- im->tabwidth,im->ylegend, 0);
}
** automatically has some vertical spacing. The horizontal
** spacing is added here, on each side.
*/
- Xtitle = gfx_get_text_width(im->canvas, 0,
+ /* don't care for the with of the title
+ Xtitle = gfx_get_text_width(im->canvas, 0,
im->text_prop[TEXT_PROP_TITLE].font,
im->text_prop[TEXT_PROP_TITLE].size,
im->tabwidth,
- im->title, 0) + 2*Xspacing;
- Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.5;
+ im->title, 0) + 2*Xspacing; */
+ Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.6+10;
}
if (elements) {
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_AXIS].size * 2;
+ "0", 0) * im->unitslength;
}
}
im->xorigin = Xspacing + Xylabel;
- if (Xtitle > im->ximg) im->ximg = Xtitle;
+ /* the length of the title should not influence with width of the graph
+ if (Xtitle > im->ximg) im->ximg = Xtitle; */
if (Xvertical) { /* unit description */
im->ximg += Xvertical;
im->yimg += Ytitle;
im->yorigin += Ytitle;
} else {
- im->yimg += Yspacing;
- im->yorigin += Yspacing;
+ im->yimg += 1.5*Yspacing;
+ im->yorigin += 1.5*Yspacing;
}
/* reserve space for padding below the graph */
im->yimg += Yspacing;
if(leg_place(im)==-1)
return -1;
- /* last of three steps: check total height of image */
- if (im->yimg < Yvertical) im->yimg = Yvertical;
#if 0
if (Xlegend > im->ximg) {
node=gfx_new_area ( im->canvas,
0, 0,
- im->ximg, 0,
- im->ximg, im->yimg,
+ 0, im->yimg,
+ im->ximg, im->yimg,
im->graph_col[GRC_BACK]);
- gfx_add_point(node,0, im->yimg);
+ gfx_add_point(node,im->ximg, 0);
#ifdef WITH_PIECHART
if (piechart != 2) {
} /* for */
/* *******************************************************
- ___
- | | ___
+ a ___. (a,t)
+ | | ___
____| | | |
| |___|
- -------|---------------------------------------
+ -------|--t-1--t--------------------------------
- if we know the value of y at time t was a then
+ if we know the value at time t was a then
we draw a square from t-1 to t with the value a.
********************************************************* */
/* GF_LINE and friend */
if(stack_gf == GF_LINE ){
node = NULL;
- for(ii=1;ii<im->xsize;ii++){
- if (isnan(im->gdes[i].p_data[ii])){
+ for(ii=1;ii<im->xsize;ii++){
+ if (isnan(im->gdes[i].p_data[ii]) || (im->slopemode==1 && isnan(im->gdes[i].p_data[ii-1]))){
node = NULL;
continue;
}
if ( node == NULL ) {
- node = gfx_new_line(im->canvas,
+ if ( im->slopemode == 0 ){
+ node = gfx_new_line(im->canvas,
ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
im->gdes[i].linewidth,
im->gdes[i].col);
+ } else {
+ node = gfx_new_line(im->canvas,
+ ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
+ ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+ im->gdes[i].linewidth,
+ im->gdes[i].col);
+ }
} else {
- gfx_add_point(node,ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+ if ( im->slopemode==0 ){
+ gfx_add_point(node,ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+ };
gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
};
}
} else {
- for(ii=1;ii<im->xsize;ii++){
+ double ybase0 = DNAN,ytop0=DNAN;
+ for(ii=0;ii<im->xsize;ii++){
/* keep things simple for now, just draw these bars
do not try to build a big and complex area */
- float ybase,ytop;
+ double ybase,ytop;
+ if ( im->slopemode == 0 && ii==0){
+ continue;
+ }
if ( isnan(im->gdes[i].p_data[ii]) ) {
+ ybase0 = DNAN;
continue;
}
ytop = ytr(im,im->gdes[i].p_data[ii]);
- if ( im->gdes[i].stack ) {
+ if ( lastgdes && im->gdes[i].stack ) {
ybase = ytr(im,lastgdes->p_data[ii]);
} else {
ybase = ytr(im,areazero);
}
if ( ybase == ytop ){
- continue;
+ ybase0 = DNAN;
+ continue;
}
- node = gfx_new_area(im->canvas,
- ii-1+im->xorigin,ybase,
- ii-1+im->xorigin,ytop,
- ii+im->xorigin,ytop,
+ /* every area has to be wound clock-wise,
+ so we have to make sur base remains base */
+ if (ybase > ytop){
+ double extra = ytop;
+ ytop = ybase;
+ ybase = extra;
+ }
+ if ( im->slopemode == 0){
+ ybase0 = ybase;
+ ytop0 = ytop;
+ }
+ if ( !isnan(ybase0) ){
+ node = gfx_new_area(im->canvas,
+ (double)ii-1.2+(double)im->xorigin,ybase0-0.2,
+ (double)ii-1.2+(double)im->xorigin,ytop0+0.2,
+ (double)ii+0.2+(double)im->xorigin,ytop+0.2,
im->gdes[i].col
);
- gfx_add_point(node,ii+im->xorigin,ybase);
+ gfx_add_point(node,
+ (double)ii+0.02+im->xorigin,ybase-0.2
+ );
+ }
+ ybase0=ybase;
+ ytop0=ytop;
}
} /* else GF_LINE */
} /* if color != 0x0 */
if (strcmp(im->graphfile,"-")==0) {
fo = im->graphhandle ? im->graphhandle : stdout;
-#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
/* Change translation mode for stdout to BINARY */
_setmode( _fileno( fo ), O_BINARY );
#endif
return (-1);
}
}
- gfx_render (im->canvas,im->ximg,im->yimg,0x0,fo);
+ gfx_render (im->canvas,im->ximg,im->yimg,0x00000000,fo);
if (strcmp(im->graphfile,"-") != 0)
fclose(fo);
return 0;
rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *stream, double *ymin, double *ymax)
{
image_desc_t im;
-
rrd_graph_init(&im);
im.graphhandle = stream;
im->gridfit = 1;
im->imginfo = NULL;
im->lazy = 0;
+ im->slopemode = 0;
im->logarithmic = 0;
im->ygridstep = DNAN;
im->draw_x_grid = 1;
for(i=0;i<DIM(graph_col);i++)
im->graph_col[i]=graph_col[i];
-#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
{
char *windir;
char rrd_win_default_font[1000];
if (windir != NULL) {
strncpy(rrd_win_default_font,windir,999);
rrd_win_default_font[999] = '\0';
- strcat(rrd_win_default_font,"\\fonts\\cour.ttf");
+ strcat(rrd_win_default_font,"\\fonts\\");
+ strcat(rrd_win_default_font,RRD_DEFAULT_FONT);
for(i=0;i<DIM(text_prop);i++){
strncpy(text_prop[i].font,rrd_win_default_font,sizeof(text_prop[i].font)-1);
text_prop[i].font[sizeof(text_prop[i].font)-1] = '\0';
long long_tmp;
struct rrd_time_value start_tv, end_tv;
gfx_color_t color;
+ optind = 0; opterr = 0; /* initialize getopt */
parsetime("end-24h", &start_tv);
parsetime("now", &end_tv);
{"only-graph", no_argument, 0, 'j'},
{"alt-y-grid", no_argument, 0, 'Y'},
{"no-minor", no_argument, 0, 'I'},
+ {"slope-mode", no_argument, 0, 'E'},
{"alt-autoscale", no_argument, 0, 'A'},
{"alt-autoscale-max", no_argument, 0, 'M'},
{"no-gridfit", no_argument, 0, 'N'},
{"units-length",required_argument, 0, 'L'},
{"step", required_argument, 0, 'S'},
{"tabwidth", required_argument, 0, 'T'},
+ {"font-render-mode", required_argument, 0, 'R'},
+ {"font-smoothing-threshold", required_argument, 0, 'B'},
+ {"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 opt;
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:zgjFYAMX:L:S:T:N",
+ "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:",
long_options, &option_index);
if (opt == EOF)
case 'z':
im->lazy = 1;
break;
+ case 'E':
+ im->slopemode = 1;
+ break;
+
case 'o':
im->logarithmic = 1;
if (isnan(im->minval))
int ci;
int col_len = col_end - col_start;
switch (col_len){
+ case 3:
+ color = (
+ ((color & 0xF00) * 0x110000) |
+ ((color & 0x0F0) * 0x011000) |
+ ((color & 0x00F) * 0x001100) |
+ 0x000000FF
+ );
+ break;
+ case 4:
+ color = (
+ ((color & 0xF000) * 0x11000) |
+ ((color & 0x0F00) * 0x01100) |
+ ((color & 0x00F0) * 0x00110) |
+ ((color & 0x000F) * 0x00011)
+ );
+ break;
case 6:
color = (color << 8) + 0xff /* shift left by 8 */;
break;
if(sscanf(optarg,
"%10[A-Z]:%lf:%1000s",
prop,&size,font) == 3){
- int sindex;
+ int sindex,propidx;
if((sindex=text_prop_conv(prop)) != -1){
- im->text_prop[sindex].size=size;
- strcpy(im->text_prop[sindex].font,font);
- if (sindex==0) { /* the default */
- im->text_prop[TEXT_PROP_TITLE].size=size;
- strcpy(im->text_prop[TEXT_PROP_TITLE].font,font);
- im->text_prop[TEXT_PROP_AXIS].size=size;
- strcpy(im->text_prop[TEXT_PROP_AXIS].font,font);
- im->text_prop[TEXT_PROP_UNIT].size=size;
- strcpy(im->text_prop[TEXT_PROP_UNIT].font,font);
- im->text_prop[TEXT_PROP_LEGEND].size=size;
- strcpy(im->text_prop[TEXT_PROP_LEGEND].font,font);
- }
+ for (propidx=sindex;propidx<TEXT_PROP_LAST;propidx++){
+ if (size > 0){
+ im->text_prop[propidx].size=size;
+ }
+ if (strlen(font) > 0){
+ strcpy(im->text_prop[propidx].font,font);
+ }
+ if (propidx==sindex && sindex != 0) break;
+ }
} else {
rrd_set_error("invalid fonttag '%s'",prop);
return;
im->title[150]='\0';
break;
+ case 'R':
+ if ( strcmp( optarg, "normal" ) == 0 )
+ im->canvas->aa_type = AA_NORMAL;
+ else if ( strcmp( optarg, "light" ) == 0 )
+ im->canvas->aa_type = AA_LIGHT;
+ else if ( strcmp( optarg, "mono" ) == 0 )
+ im->canvas->aa_type = AA_NONE;
+ else
+ {
+ rrd_set_error("unknown font-render-mode '%s'", optarg );
+ return;
+ }
+ break;
+
+ case 'B':
+ im->canvas->font_aa_threshold = atof(optarg);
+ break;
+
case '?':
if (optopt != 0)
rrd_set_error("unknown option '%c'", optopt);