remove all traces of GIF and make PNG the default
[rrdtool.git] / src / rrd_graph.c
index 0f6f588..2e9e009 100644 (file)
@@ -174,13 +174,13 @@ enum gf_en gf_conv(char *string){
     conv_if(DEF,GF_DEF)
     conv_if(CDEF,GF_CDEF)
     conv_if(VDEF,GF_VDEF)
+    conv_if(PART,GF_PART)
     
     return (-1);
 }
 
 enum if_en if_conv(char *string){
     
-    conv_if(GIF,IF_GIF)
     conv_if(PNG,IF_PNG)
 
     return (-1);
@@ -803,7 +803,7 @@ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
                             * further save step size and data source
                             * count of this rra
                             */ 
-                           im->gdes[gdi].rpnp[rpi].data = im->gdes[ptr].data; 
+                            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;
 
@@ -815,6 +815,17 @@ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
                    } /* if OP_VARIABLE */
                } /* loop through all rpi */
 
+                /* 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){
+                        long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+                        if(im->gdes[gdi].start > im->gdes[ptr].start) {
+                            im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt;
+                        }
+                     }
+                }
+        
+
                if(steparray == NULL){
                    rrd_set_error("rpn expressions without DEF"
                                " or CDEF variables are not supported");
@@ -937,6 +948,7 @@ data_proc( image_desc_t *im ){
            case GF_DEF:               
            case GF_CDEF:
            case GF_VDEF:
+           case GF_PART:
                break;
            }
        }
@@ -1209,6 +1221,7 @@ print_calc(image_desc_t *im, char ***prdata)
        case GF_LINE:
        case GF_AREA:
        case GF_TICK:
+       case GF_PART:
        case GF_STACK:
        case GF_HRULE:
        case GF_VRULE:
@@ -1710,17 +1723,22 @@ grid_paint(
     
 
     /* draw 3d border */
-    node = gfx_new_area (canvas, 0,im->ygif, 0,0, im->xgif, 0,im->graph_col[GRC_SHADEA]);
+    node = gfx_new_area (canvas, 0,im->ygif,
+                                 2,im->ygif-2,
+                                 2,2,im->graph_col[GRC_SHADEA]);
     gfx_add_point( node , im->xgif - 2, 2 );
-    gfx_add_point( node , 2,2 );
-    gfx_add_point( node , 2,im->ygif-2 );
-    gfx_add_point( node , 0,im->ygif );
+    gfx_add_point( node , im->xgif, 0 );
+    gfx_add_point( node , 0,0 );
+/*    gfx_add_point( node , 0,im->ygif ); */
    
-    node =  gfx_new_area (canvas, 0,im->ygif, im->xgif,im->ygif, im->xgif,0,im->graph_col[GRC_SHADEB]);
-    gfx_add_point( node , im->xgif - 2, 2 );
-    gfx_add_point( node , im->xgif-2,im->ygif-2 );
-    gfx_add_point( node , 2,im->ygif-2 );
-    gfx_add_point( node , 0,im->ygif );
+    node =  gfx_new_area (canvas, 2,im->ygif-2,
+                                  im->xgif-2,im->ygif-2,
+                                  im->xgif - 2, 2,
+                                 im->graph_col[GRC_SHADEB]);
+    gfx_add_point( node ,   im->xgif,0);
+    gfx_add_point( node ,   im->xgif,im->ygif);
+    gfx_add_point( node ,   0,im->ygif);
+/*    gfx_add_point( node , 0,im->ygif ); */
    
    
     if (im->draw_x_grid == 1 )
@@ -1772,15 +1790,15 @@ grid_paint(
         if(im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT){
            x0 = im->gdes[i].leg_x;
            y0 = im->gdes[i].leg_y+1.0;
-           x1 = x0+boxH;
+           x1 = x0;
            x2 = x0+boxH;
-           x3 = x0;
-           y1 = y0;
+           x3 = x0+boxH;
+           y1 = y0+boxV;
            y2 = y0+boxV;
-           y3 = y0+boxV;
+           y3 = y0;
            node = gfx_new_area(canvas, x0,y0,x1,y1,x2,y2 ,im->gdes[i].col);
            gfx_add_point ( node, x3, y3 );
-           gfx_add_point ( node, x0, y0 );
+/*         gfx_add_point ( node, x0, y0 ); */
            node = gfx_new_line(canvas, x0,y0,x1,y1 ,GRIDWIDTH, im->graph_col[GRC_FRAME]);
            gfx_add_point ( node, x2, y2 );
            gfx_add_point ( node, x3, y3 );
@@ -1830,9 +1848,6 @@ int lazy_check(image_desc_t *im){
     if ((fd = fopen(im->graphfile,"rb")) == NULL) 
       return 0; /* the file does not exist */
     switch (im->imgformat) {
-    case IF_GIF:
-          size = GifSize(fd,&(im->xgif),&(im->ygif));
-          break;
     case IF_PNG:
           size = PngSize(fd,&(im->xgif),&(im->ygif));
           break;
@@ -1841,6 +1856,51 @@ int lazy_check(image_desc_t *im){
     return size;
 }
 
+void
+pie_part(gfx_canvas_t *canvas, gfx_color_t color,
+           double PieCenterX, double PieCenterY, double Radius,
+           double startangle, double endangle)
+{
+    gfx_node_t *node;
+    double angle;
+    double step=M_PI/50; /* Number of iterations for the circle;
+                        ** 10 is definitely too low, more than
+                        ** 50 seems to be overkill
+                        */
+
+    /* Strange but true: we have to work clockwise or else
+    ** anti aliasing nor transparency don't work.
+    **
+    ** This test is here to make sure we do it right, also
+    ** this makes the for...next loop more easy to implement.
+    ** The return will occur if the user enters a negative number
+    ** (which shouldn't be done according to the specs) or if the
+    ** programmers do something wrong (which, as we all know, never
+    ** happens anyway :)
+    */
+    if (endangle<startangle) return;
+
+    /* Hidden feature: Radius decreases each full circle */
+    angle=startangle;
+    while (angle>=2*M_PI) {
+       angle  -= 2*M_PI;
+       Radius *= 0.8;
+    }
+
+    node=gfx_new_area(canvas,
+               PieCenterX+sin(startangle)*Radius,
+               PieCenterY-cos(startangle)*Radius,
+               PieCenterX,
+               PieCenterY,
+               PieCenterX+sin(endangle)*Radius,
+               PieCenterY-cos(endangle)*Radius,
+               color);
+    for (angle=endangle;angle-startangle>=step;angle-=step) {
+       gfx_add_point(node,
+               PieCenterX+sin(angle)*Radius,
+               PieCenterY-cos(angle)*Radius );
+    }
+}
 
 /* draw that picture thing ... */
 int
@@ -1848,6 +1908,8 @@ graph_paint(image_desc_t *im, char ***calcpr)
 {
   int i,ii;
   int lazy =     lazy_check(im);
+  int piechart = 0;
+  double PieStart=0.0, PieSize=0.0, PieCenterX=0.0, PieCenterY=0.0;
   FILE  *fo;
   gfx_canvas_t *canvas;
   gfx_node_t *node;
@@ -1904,9 +1966,31 @@ graph_paint(image_desc_t *im, char ***calcpr)
   if(im->title[0] != '\0')
     im->yorigin += im->text_prop[TEXT_PROP_TITLE].size*3+4;
   
-  im->xgif=20+im->xsize + im->xorigin;
+  im->xgif= 20 +im->xsize + im->xorigin;
   im->ygif= im->yorigin+2* im->text_prop[TEXT_PROP_LEGEND].size;
-  
+
+  /* check if we need to draw a piechart */
+  for(i=0;i<im->gdes_c;i++){
+    if (im->gdes[i].gf == GF_PART) {
+      piechart=1;
+      break;
+    }
+  }
+
+  if (piechart) {
+       /* allocate enough space for the piechart itself (PieSize), 20%
+       ** more for the background and an additional 50 pixels spacing.
+       */
+    if (im->xsize < im->ysize)
+       PieSize = im->xsize;
+    else
+       PieSize = im->ysize;
+    im->xgif += PieSize*1.2 + 50;
+
+    PieCenterX = im->xorigin + im->xsize + 50 + PieSize*0.6;
+    PieCenterY = im->yorigin - PieSize*0.5;
+  }
+
   /* determine where to place the legends onto the graphics.
      and set im->ygif to match space requirements for text */
   if(leg_place(im)==-1)
@@ -1914,6 +1998,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
 
   canvas=gfx_new_canvas();
 
+
   /* the actual graph is created by going through the individual
      graph elements and then drawing them */
   
@@ -1933,7 +2018,66 @@ graph_paint(image_desc_t *im, char ***calcpr)
   
   gfx_add_point(node,im->xorigin, im->yorigin - im->ysize);
 
-  
+#if 0
+/******************************************************************
+ ** Just to play around.  If you see this, I forgot to remove it **
+ ******************************************************************/
+  im->ygif+=100;
+  node=gfx_new_area(canvas,
+                       0,              im->ygif-100,
+                       im->xgif,       im->ygif-100,
+                       im->xgif,       im->ygif,
+                       im->graph_col[GRC_CANVAS]);
+  gfx_add_point(node,0,im->ygif);
+
+  /* Four areas:
+  ** top left:     current way, solid color
+  ** top right:    proper way,  solid color
+  ** bottom left:  current way, alpha=0x80, partially overlapping
+  ** bottom right: proper way,  alpha=0x80, partially overlapping
+  */
+  {
+    double x,y,x1,y1,x2,y2,x3,y3,x4,y4;
+
+    x=(im->xgif-40)/6;
+    y=     (100-40)/6;
+    x1=    20;   y1=im->ygif-100+20;
+    x2=3*x+20;   y2=im->ygif-100+20;
+    x3=  x+20;   y3=im->ygif-100+20+2*y;
+    x4=4*x+20;   y4=im->ygif-100+20+2*y;
+
+    node=gfx_new_area(canvas,
+                       x1,y1,
+                       x1+3*x,y1,
+                       x1+3*x,y1+3*y,
+                       0xFF0000FF);
+    gfx_add_point(node,x1,y1+3*y);
+    node=gfx_new_area(canvas,
+                       x2,y2,
+                       x2,y2+3*y,
+                       x2+3*x,y2+3*y,
+                       0xFFFF00FF);
+    gfx_add_point(node,x2+3*x,y2);
+    node=gfx_new_area(canvas,
+                       x3,y3,
+                       x3+2*x,y3,
+                       x3+2*x,y3+3*y,
+                       0x00FF007F);
+    gfx_add_point(node,x3,y3+3*y);
+    node=gfx_new_area(canvas,
+                       x4,y4,
+                       x4,y4+3*y,
+                       x4+2*x,y4+3*y,
+                       0x0000FF7F);
+    gfx_add_point(node,x4+2*x,y4);
+  }
+                       
+#endif
+
+  if (piechart) {
+    pie_part(canvas,im->graph_col[GRC_CANVAS],PieCenterX,PieCenterY,PieSize*0.6,0,2*M_PI);
+  }
+
   if (im->minval > 0.0)
     areazero = im->minval;
   if (im->maxval < 0.0)
@@ -1942,7 +2086,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
   axis_paint(im,canvas);
 
 
-  for(i=0;i<im->gdes_c;i++){    
+  for(i=0;i<im->gdes_c;i++){
     switch(im->gdes[i].gf){
     case GF_CDEF:
     case GF_VDEF:
@@ -2061,6 +2205,18 @@ graph_paint(image_desc_t *im, char ***calcpr)
       } 
       lastgdes = &(im->gdes[i]);                         
       break;
+    case GF_PART:
+      if(isnan(im->gdes[i].yrule)) /* fetch variable */
+       im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
+     
+      if (finite(im->gdes[i].yrule)) { /* even the fetched var can be NaN */
+       pie_part(canvas,im->gdes[i].col,
+               PieCenterX,PieCenterY,PieSize/2,
+               M_PI*2.0*PieStart/100.0,
+               M_PI*2.0*(PieStart+im->gdes[i].yrule)/100.0);
+       PieStart += im->gdes[i].yrule;
+      }
+      break;
     } /* switch */
   }
   grid_paint(im,canvas);
@@ -2070,7 +2226,6 @@ graph_paint(image_desc_t *im, char ***calcpr)
     
     switch(im->gdes[i].gf){
     case GF_HRULE:
-      printf("DEBUG: HRULE at %f\n",im->gdes[i].yrule);
       if(isnan(im->gdes[i].yrule)) { /* fetch variable */
         im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
       };
@@ -2112,8 +2267,6 @@ graph_paint(image_desc_t *im, char ***calcpr)
     }
   }
   switch (im->imgformat) {
-  case IF_GIF:
-    break;
   case IF_PNG:
     gfx_render_png (canvas,im->xgif,im->ygif,im->zoom,0x0,fo);
     break;
@@ -2285,7 +2438,7 @@ rrd_graph_init(image_desc_t *im)
     im->gdes_c = 0;
     im->gdes = NULL;
     im->zoom = 1.0;
-    im->imgformat = IF_GIF; /* we default to GIF output */
+    im->imgformat = IF_PNG; /* we default to PNG output */
 
     for(i=0;i<DIM(graph_col);i++)
         im->graph_col[i]=graph_col[i];
@@ -2511,27 +2664,46 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
             }
             break;        
         case 'n':{
-          char *prop = "";
-          double size = 1;
-          char *font = "dummy";
-
-          if(sscanf(optarg,
-                    "%10[A-Z]:%lf:%s",
-                    prop,&size,font) == 3){
-            int sindex;
-            if((sindex=text_prop_conv(prop)) != -1){
-              im->text_prop[sindex].size=size;              
-              im->text_prop[sindex].font=font;
-              
-            }  else {
-              rrd_set_error("invalid color name '%s'",col_nam);
-            }
-          } else {
-            rrd_set_error("invalid text property format");
-            return;
-          }
-          break;          
-        }
+                       /* originally this used char *prop = "" and
+                       ** char *font = "dummy" however this results
+                       ** in a SEG fault, at least on RH7.1
+                       **
+                       ** The current implementation isn't proper
+                       ** either, font is never freed and prop uses
+                       ** a fixed width string
+                       */
+           char prop[100];
+           double size = 1;
+           char *font;
+
+           font=malloc(255);
+           if(sscanf(optarg,
+                               "%10[A-Z]:%lf:%s",
+                               prop,&size,font) == 3){
+               int sindex;
+               if((sindex=text_prop_conv(prop)) != -1){
+                   im->text_prop[sindex].size=size;              
+                   im->text_prop[sindex].font=font;
+                   if (sindex==0) { /* the default */
+                       im->text_prop[TEXT_PROP_TITLE].size=size;
+                       im->text_prop[TEXT_PROP_TITLE].font=font;
+                       im->text_prop[TEXT_PROP_AXIS].size=size;
+                       im->text_prop[TEXT_PROP_AXIS].font=font;
+                       im->text_prop[TEXT_PROP_UNIT].size=size;
+                       im->text_prop[TEXT_PROP_UNIT].font=font;
+                       im->text_prop[TEXT_PROP_LEGEND].size=size;
+                       im->text_prop[TEXT_PROP_LEGEND].font=font;
+                   }
+               } else {
+                   rrd_set_error("invalid fonttag '%s'",prop);
+                   return;
+               }
+           } else {
+               rrd_set_error("invalid text property format");
+               return;
+           }
+           break;          
+       }
         case 'm':
            im->zoom= atof(optarg);
            if (im->zoom <= 0.0) {
@@ -2612,7 +2784,7 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im)
        /* function:newvname=string[:ds-name:CF]        for xDEF
        ** function:vname[#color[:string]]              for LINEx,AREA,STACK
        ** function:vname#color[:num[:string]]          for TICK
-       ** function:vname-or-num#color[:string]         for xRULE
+       ** function:vname-or-num#color[:string]         for xRULE,PART
        ** function:vname:CF:string                     for xPRINT
        ** function:string                              for COMMENT
        */
@@ -2641,6 +2813,7 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im)
                if (rrd_graph_legend(gdp,&line[argstart])==0)
                    rrd_set_error("Cannot parse comment in line: %s",line);
                break;
+           case GF_PART:
            case GF_VRULE:
            case GF_HRULE:
                j=k=l=m=0;