[rrd-developers] patch for legends position
Melchior Rabe
rrdtool at mrab.de
Mon Feb 9 17:47:35 CET 2009
Hello together,
at the moment the legend section is placed below the graph. This is in
the most cases fine as the time axis gets a much space as possible. But
I want to graph data that is a set of stacked values (up to 25) and also
want to print some informational numbers into the legend. In that case I
find it more convinient placing the legend on the side of the graph
(Possibly that might be also nice for the pie chart function...). I
created a patch that is introducing two new options:
--legend-position north|south|west|east (default: south)
--legend-direction topdown|bottomup (default: topdown)
The first option decides where the legend is placed and the second can
be used to reverse the vertical order of the legend items. In a stack
the first item (AREA, LINEx) is the bottommost and the following is
stacked on top of it. The legend is placed in the same sequence. That
means that the first item and the next one is placed (after a line
break) below the preceeding ones. So the graph is stacked bottomup while
the legend is "stacked" topdown. The --legend-direction is reversing the
vertical order of the legend items.
Some not so nice (but IMHO acceptable) side effects:
- Placing the legend on the side will result in a very wide graph with
all items in one line (as long as there is no manual line break
inserted). So the user has to take care for the line breaks. I think
that is acceptable, as any other solution I thought of (giving the width
of the legend or defining some ratio between legend and graph) was
leading to more parameters.
- Placing the legend items bottomup might lead to an incomplete first
line, because only the vertical alignment is inverted, but not the
sequence of the items e.g. like that:
topdown legend:
first second third
forth fifth sixth
seventh
will lead to bottomup:
seventh
forth fifth sixth
first second third
The patch is tested on WinXP32, but as there is only some painting
affected I do not expect any problems on other systems. I wrote a short
description with some example images (http://mrab.de/?p=64) and placed
the patch below also in a zip at
http://mrab.de/wp-content/uploads/rrdtool_patch_legend-position.zip
Any comments, hints and tips are appreciated!
Cheers,
Melchior
Patch for rrd_graph.h
----------------------- BEGIN ----------------------------------------
Index: rrd_graph.h
===================================================================
--- rrd_graph.h (revision 1746)
+++ rrd_graph.h (working copy)
@@ -81,6 +81,8 @@
TEXT_PROP_LAST
};
+enum legend_pos{ NORTH = 0, WEST, SOUTH, EAST };
+enum legend_direction { TOP_DOWN = 0, BOTTOM_UP };
enum gfx_if_en { IF_PNG = 0, IF_SVG, IF_EPS, IF_PDF };
enum gfx_en { GFX_LINE = 0, GFX_AREA, GFX_TEXT };
@@ -231,6 +233,8 @@
reasonable probablility that the
existing one is out of date */
int slopemode; /* connect the dots of the curve directly, not using a stair */
+ legend_pos legendposition; /* the position of the legend: north, west, south or east */
+ legend_direction legenddirection; /* The direction of the legend topdown or bottomup */
int logarithmic; /* scale the yaxis logarithmic */
double force_scale_min; /* Force a scale--min */
double force_scale_max; /* Force a scale--max */
@@ -238,7 +242,12 @@
/* status information */
int with_markup;
long xorigin, yorigin; /* where is (0,0) of the graph */
+ long xOriginTitle, yOriginTitle; /* where is the origin of the title */
+ long xOriginLegendY, yOriginLegendY; /* where is the origin of the y legend */
+ long xOriginLegendY2, yOriginLegendY2; /* where is the origin of the second y legend */
+ long xOriginLegend, yOriginLegend; /* where is the origin of the legend */
long ximg, yimg; /* total size of the image */
+ long legendwidth, legendheight; /* the calculated height and width of the legend */
size_t rendered_image_size;
double zoom;
double magfact; /* numerical magnitude */
----------------------- END ----------------------------------------
Patch for rrd_graph.c
----------------------- BEGIN ----------------------------------------
Index: rrd_graph.c
===================================================================
--- rrd_graph.c (revision 1746)
+++ rrd_graph.c (working copy)
@@ -1613,26 +1613,37 @@
}
+
/* place legends with color spots */
int leg_place(
image_desc_t *im,
- int *gY)
+ bool calc_width)
{
/* graph labels */
int interleg = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
int border = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
int fill = 0, fill_last;
+ double legendwidth; // = im->ximg - 2 * border;
int leg_c = 0;
double leg_x = border;
- int leg_y = im->yimg;
- int leg_y_prev = im->yimg;
+ int leg_y = 0; //im->yimg;
+ int leg_y_prev = 0; // im->yimg;
int leg_cc;
double glue = 0;
int i, ii, mark = 0;
char default_txtalign = TXA_JUSTIFIED; /*default line orientation */
int *legspace;
char *tab;
+ char saved_legend[FMT_LEG_LEN + 5];
+ if(calc_width){
+ legendwidth = 0;
+ }
+ else{
+ legendwidth = im->legendwidth - 2 * border;
+ }
+
+
if (!(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH)) {
if ((legspace = (int*)(malloc(im->gdes_c * sizeof(int)))) == NULL) {
rrd_set_error("malloc for legspace");
@@ -1641,6 +1652,10 @@
for (i = 0; i < im->gdes_c; i++) {
char prt_fctn; /*special printfunctions */
+ if(calc_width){
+ strcpy(saved_legend, im->gdes[i].legend);
+ }
+
fill_last = fill;
/* hide legends for rules which are not displayed */
if (im->gdes[i].gf == GF_TEXTALIGN) {
@@ -1663,6 +1678,7 @@
memmove(tab, tab + 1, strlen(tab));
tab[0] = (char) 9;
}
+
leg_cc = strlen(im->gdes[i].legend);
/* is there a controle code at the end of the legend string ? */
if (leg_cc >= 2 && im->gdes[i].legend[leg_cc - 2] == '\\') {
@@ -1721,7 +1737,10 @@
}
if (prt_fctn == '\0') {
- if (i == im->gdes_c - 1 || fill > im->ximg - 2 * border) {
+ if(calc_width && (fill > legendwidth)){
+ legendwidth = fill;
+ }
+ if (i == im->gdes_c - 1 || fill > legendwidth) {
/* just one legend item is left right or center */
switch (default_txtalign) {
case TXA_RIGHT:
@@ -1739,7 +1758,7 @@
}
}
/* is it time to place the legends ? */
- if (fill > im->ximg - 2 * border) {
+ if (fill > legendwidth) {
if (leg_c > 1) {
/* go back one */
i--;
@@ -1752,23 +1771,22 @@
}
}
-
if (prt_fctn != '\0') {
leg_x = border;
if (leg_c >= 2 && prt_fctn == 'j') {
- glue = (double)(im->ximg - fill - 2 * border) / (double)(leg_c - 1);
+ glue = (double)(legendwidth - fill) / (double)(leg_c - 1);
} else {
glue = 0;
}
if (prt_fctn == 'c')
- leg_x = (double)(im->ximg - fill) / 2.0;
+ leg_x = (double)(legendwidth - fill) / 2.0;
if (prt_fctn == 'r')
- leg_x = im->ximg - fill - border;
+ leg_x = legendwidth - fill - border;
for (ii = mark; ii <= i; ii++) {
if (im->gdes[ii].legend[0] == '\0')
continue; /* skip empty legends */
im->gdes[ii].leg_x = leg_x;
- im->gdes[ii].leg_y = leg_y;
+ im->gdes[ii].leg_y = leg_y + border;
leg_x +=
(double)gfx_get_text_width(im, leg_x,
im->
@@ -1784,27 +1802,26 @@
leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
if (prt_fctn == 's')
leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+
+ if(calc_width && (fill > legendwidth)){
+ legendwidth = fill;
+ }
fill = 0;
leg_c = 0;
mark = ii;
}
- }
- if (im->extra_flags & FULL_SIZE_MODE) {
- /* now for some backpaddeling. We have to shift up all the
- legend items into the graph and tell the caller about the
- space we used up. */
- long shift_up = leg_y - im->yimg - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 + border * 0.7;
- for (i = 0; i < im->gdes_c; i++) {
- im->gdes[i].leg_y -= shift_up;
+ if(calc_width){
+ strcpy(im->gdes[i].legend, saved_legend);
}
- im->yorigin = im->yorigin - leg_y + im->yimg - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 - border;
- *gY = im->yorigin;
- } else {
- im->yimg =
- leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 +
- border * 0.6;
}
+
+ if(calc_width){
+ im->legendwidth = legendwidth + 2 * border;
+ }
+ else{
+ im->legendheight = leg_y + border * 0.6;
+ }
free(legspace);
}
return 0;
@@ -2590,24 +2607,20 @@
/* yaxis unit description */
if (im->ylegend[0] != '\0'){
gfx_text(im,
- 10,
- (im->yorigin -
- im->ysize / 2),
+ im->xOriginLegendY+10,
+ im->yOriginLegendY,
im->graph_col[GRC_FONT],
im->
text_prop[TEXT_PROP_UNIT].
font_desc,
im->tabwidth,
RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend);
+
}
if (im->second_axis_legend[0] != '\0'){
- double Xylabel=gfx_get_text_width(im, 0,
- im->text_prop[TEXT_PROP_AXIS].font_desc,
- im->tabwidth,
- "0") * im->unitslength
- + im->text_prop[TEXT_PROP_UNIT].size *2;
gfx_text( im,
- im->xorigin+im->xsize+Xylabel+8, (im->yorigin - im->ysize/2),
+ im->xOriginLegendY2+10,
+ im->yOriginLegendY2,
im->graph_col[GRC_FONT],
im->text_prop[TEXT_PROP_UNIT].font_desc,
im->tabwidth,
@@ -2618,7 +2631,7 @@
/* graph title */
gfx_text(im,
- im->ximg / 2, 6,
+ im->xOriginTitle, im->yOriginTitle+6,
im->graph_col[GRC_FONT],
im->
text_prop[TEXT_PROP_TITLE].
@@ -2628,7 +2641,8 @@
if (!(im->extra_flags & NO_RRDTOOL_TAG)){
water_color = im->graph_col[GRC_FONT];
water_color.alpha = 0.3;
- gfx_text(im, im->ximg - 4, 5,
+ double xpos = im->legendposition == EAST ? im->xOriginLegendY : im->ximg - 4;
+ gfx_text(im, xpos, 5,
water_color,
im->
text_prop[TEXT_PROP_WATERMARK].
@@ -2652,8 +2666,8 @@
if (im->gdes[i].legend[0] == '\0')
continue;
/* im->gdes[i].leg_y is the bottom of the legend */
- X0 = im->gdes[i].leg_x;
- Y0 = im->gdes[i].leg_y;
+ X0 = im->xOriginLegend + im->gdes[i].leg_x;
+ Y0 = im->legenddirection == TOP_DOWN ? im->yOriginLegend + im->gdes[i].leg_y : im->yOriginLegend + im->legendheight - im->gdes[i].leg_y;
gfx_text(im, X0, Y0,
im->graph_col[GRC_FONT],
im->
@@ -2770,22 +2784,12 @@
/* The actual size of the image to draw is determined from
** several sources. The size given on the command line is
** the graph area but we need more as we have to draw labels
- ** and other things outside the graph area
+ ** and other things outside the graph area. If the option
+ ** --full-size-mode is selected the size defines the total
+ ** image size and the size available for the graph is
+ ** calculated.
*/
- int Xvertical = 0, Ytitle =
- 0, Xylabel = 0, Xmain = 0, Ymain =
- 0, Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4;
-
- if (im->extra_flags & ONLY_GRAPH) {
- im->xorigin = 0;
- im->ximg = im->xsize;
- im->yimg = im->ysize;
- im->yorigin = im->ysize;
- ytr(im, DNAN);
- return 0;
- }
-
/** +---+-----------------------------------+
** | y |...............graph title.........|
** | +---+-------------------------------+
@@ -2806,10 +2810,33 @@
** +---------------------------------------+
*/
+ int Xvertical = 0, Xvertical2 = 0, Ytitle =
+ 0, Xylabel = 0, Xmain = 0, Ymain =
+ 0, Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4;
+
+ // no legends and no the shall be plotted it's easy
+ if (im->extra_flags & ONLY_GRAPH) {
+ im->xorigin = 0;
+ im->ximg = im->xsize;
+ im->yimg = im->ysize;
+ im->yorigin = im->ysize;
+ ytr(im, DNAN);
+ return 0;
+ }
+
+ // calculate the width of the left vertical legend
if (im->ylegend[0] != '\0') {
Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
}
+ // calculate the width of the right vertical legend
+ if (im->second_axis_legend[0] != '\0') {
+ Xvertical2 = im->text_prop[TEXT_PROP_UNIT].size * 2;
+ }
+ else{
+ Xvertical2 = Xspacing;
+ }
+
if (im->title[0] != '\0') {
/* The title is placed "inbetween" two text lines so it
** automatically has some vertical spacing. The horizontal
@@ -2818,92 +2845,112 @@
/* if necessary, reduce the font size of the title until it fits the image width */
Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
}
+ else{
+ // we have no title; get a little clearing from the top
+ Ytitle = 1.5 * Yspacing;
+ }
if (elements) {
if (im->draw_x_grid) {
+ // calculate the height of the horizontal labelling
Yxlabel = im->text_prop[TEXT_PROP_AXIS].size * 2.5;
}
if (im->draw_y_grid || im->forceleftspace) {
+ // calculate the width of the vertical labelling
Xylabel =
gfx_get_text_width(im, 0,
- im->
- text_prop
- [TEXT_PROP_AXIS].
- font_desc,
+ im->text_prop[TEXT_PROP_AXIS].font_desc,
im->tabwidth, "0") * im->unitslength;
}
}
+ // add some space to the labelling
+ Xylabel += Xspacing;
+
+ /* If the legend is printed besides the graph the width has to be
+ ** calculated first. Placing the legend north or south of the
+ ** graph requires the width calculation first, so the legend is
+ ** skipped for the moment.
+ */
+ im->legendheight = 0;
+ im->legendwidth = 0;
+ if (!(im->extra_flags & NOLEGEND)) {
+ if(im->legendposition == WEST || im->legendposition == EAST){
+ if (leg_place(im, true) == -1){
+ return -1;
+ }
+ }
+ }
+
if (im->extra_flags & FULL_SIZE_MODE) {
+
/* The actual size of the image to draw has been determined by the user.
** The graph area is the space remaining after accounting for the legend,
** the watermark, the axis labels, and the title.
*/
- im->xorigin = 0;
im->ximg = im->xsize;
im->yimg = im->ysize;
- im->yorigin = im->ysize;
Xmain = im->ximg;
Ymain = im->yimg;
+
/* Now calculate the total size. Insert some spacing where
desired. im->xorigin and im->yorigin need to correspond
with the lower left corner of the main graph area or, if
this one is not set, the imaginary box surrounding the
pie chart area. */
/* Initial size calculation for the main graph area */
- Xmain = im->ximg - Xylabel - 3 * Xspacing;
- im->xorigin = Xspacing + Xylabel;
-
- if (Xvertical) { /* unit description */
- Xmain -= Xvertical;
- im->xorigin += Xvertical;
+ Xmain -= Xylabel;// + Xspacing;
+ if((im->legendposition == WEST || im->legendposition == EAST) && !(im->extra_flags & NOLEGEND) ){
+ Xmain -= im->legendwidth;// + Xspacing;
}
-
- /* adjust space for second axis */
if (im->second_axis_scale != 0){
- Xmain -= Xylabel + Xspacing;
+ Xmain -= Xylabel;
}
- if (im->extra_flags & NO_RRDTOOL_TAG){
- Xmain += Xspacing;
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ Xmain -= Xspacing;
}
- if (im->second_axis_legend[0] != '\0' ) {
- Xmain -= im->text_prop[TEXT_PROP_UNIT].size * 1.5;
+
+ Xmain -= Xvertical + Xvertical2;
+
+ /* limit the remaining space to 0 */
+ if(Xmain < 1){
+ Xmain = 1;
}
-
im->xsize = Xmain;
- xtr(im, 0);
- /* The vertical size of the image is known in advance. The main graph area
- ** (Ymain) and im->yorigin must be set according to the space requirements
- ** of the legend and the axis labels.
- */
- if (im->extra_flags & NOLEGEND) {
- im->yorigin = im->yimg -
- im->text_prop[TEXT_PROP_AXIS].size * 2.5 - Yspacing;
- Ymain = im->yorigin;
+ /* Putting the legend north or south, the height can now be calculated */
+ if (!(im->extra_flags & NOLEGEND)) {
+ if(im->legendposition == NORTH || im->legendposition == SOUTH){
+ im->legendwidth = im->ximg;
+ if (leg_place(im, false) == -1){
+ return -1;
+ }
+ }
}
- else {
- /* Determine where to place the legends onto the image.
- ** Set Ymain and adjust im->yorigin to match the space requirements.
- */
- if (leg_place(im, &Ymain) == -1)
- return -1;
+
+ if( (im->legendposition == NORTH || im->legendposition == SOUTH) && !(im->extra_flags & NOLEGEND) ){
+ Ymain -= Yxlabel + im->legendheight;
}
+ else{
+ Ymain -= Yxlabel;
+ }
+
+ /* reserve space for the title *or* some padding above the graph */
+ Ymain -= Ytitle;
-
- /* remove title space *or* some padding above the graph from the main graph area */
- if (Ytitle) {
- Ymain -= Ytitle;
- } else {
- Ymain -= 1.5 * Yspacing;
+ /* reserve space for padding below the graph */
+ if (im->extra_flags & NOLEGEND) {
+ Ymain -= Yspacing;
}
- /* watermark doesn't seem to effect the vertical size of the main graph area, oh well! */
if (im->watermark[0] != '\0') {
Ymain -= Ywatermark;
}
-
+ /* limit the remaining height to 0 */
+ if(Ymain < 1){
+ Ymain = 1;
+ }
im->ysize = Ymain;
} else { /* dimension options -width and -height refer to the dimensions of the main graph area */
@@ -2913,94 +2960,171 @@
** and other things outside the graph area.
*/
- if (im->ylegend[0] != '\0') {
- Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
+ if (elements) {
+ Xmain = im->xsize; // + Xspacing;
+ Ymain = im->ysize;
}
-
- if (im->title[0] != '\0') {
- /* The title is placed "inbetween" two text lines so it
- ** automatically has some vertical spacing. The horizontal
- ** spacing is added here, on each side.
- */
- /* don't care for the with of the title
- Xtitle = gfx_get_text_width(im->canvas, 0,
- im->text_prop[TEXT_PROP_TITLE].font_desc,
- im->tabwidth,
- im->title, 0) + 2*Xspacing; */
- Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
+ im->ximg = Xmain + Xylabel;
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ im->ximg += Xspacing;
}
- if (elements) {
- Xmain = im->xsize;
- Ymain = im->ysize;
+ if( (im->legendposition == WEST || im->legendposition == EAST) && !(im->extra_flags & NOLEGEND) ){
+ im->ximg += im->legendwidth;// + Xspacing;
}
- /* Now calculate the total size. Insert some spacing where
- desired. im->xorigin and im->yorigin need to correspond
- with the lower left corner of the main graph area or, if
- this one is not set, the imaginary box surrounding the
- pie chart area. */
+ if (im->second_axis_scale != 0){
+ im->ximg += Xylabel;
+ }
- /* The legend width cannot yet be determined, as a result we
- ** have problems adjusting the image to it. For now, we just
- ** forget about it at all; the legend will have to fit in the
- ** size already allocated.
- */
- im->ximg = Xylabel + Xmain + 2 * Xspacing;
+ im->ximg += Xvertical + Xvertical2;
- if (im->second_axis_scale != 0){
- im->ximg += Xylabel + Xspacing;
+ if (!(im->extra_flags & NOLEGEND)) {
+ if(im->legendposition == NORTH || im->legendposition == SOUTH){
+ im->legendwidth = im->ximg;
+ if (leg_place(im, false) == -1){
+ return -1;
+ }
+ }
}
- if (im->extra_flags & NO_RRDTOOL_TAG){
- im->ximg -= Xspacing;
+
+ im->yimg = Ymain + Yxlabel;
+ if( (im->legendposition == NORTH || im->legendposition == SOUTH) && !(im->extra_flags & NOLEGEND) ){
+ im->yimg += im->legendheight;
}
- if (Xmain)
- im->ximg += Xspacing;
- im->xorigin = Xspacing + Xylabel;
- /* 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->xorigin += Xvertical;
- }
- if (im->second_axis_legend[0] != '\0' ) {
- im->ximg += Xvertical;
- }
-
- xtr(im, 0);
- /* The vertical size is interesting... we need to compare
- ** 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,
- ** adding space for a watermark if one exists;
- */
- /* reserve space for main and/or pie */
- im->yimg = Ymain + Yxlabel;
- im->yorigin = im->yimg - Yxlabel;
/* reserve space for the title *or* some padding above the graph */
if (Ytitle) {
im->yimg += Ytitle;
- im->yorigin += Ytitle;
} else {
im->yimg += 1.5 * Yspacing;
- im->yorigin += 1.5 * Yspacing;
}
/* reserve space for padding below the graph */
- im->yimg += Yspacing;
- /* Determine where to place the legends onto the image.
- ** Adjust im->yimg to match the space requirements.
- */
- if (leg_place(im, 0) == -1)
- return -1;
+ if (im->extra_flags & NOLEGEND) {
+ im->yimg += Yspacing;
+ }
+
if (im->watermark[0] != '\0') {
im->yimg += Ywatermark;
}
}
+
+ /* In case of putting the legend in west or east position the first
+ ** legend calculation might lead to wrong positions if some items
+ ** are not aligned on the left hand side (e.g. centered) as the
+ ** legendwidth wight have been increased after the item was placed.
+ ** In this case the positions have to be recalculated.
+ */
+ if (!(im->extra_flags & NOLEGEND)) {
+ if(im->legendposition == WEST || im->legendposition == EAST){
+ if (leg_place(im, false) == -1){
+ return -1;
+ }
+ }
+ }
+
+ /* After calculating all dimensions
+ ** it is now possible to calculate
+ ** all offsets.
+ */
+ switch(im->legendposition){
+ case NORTH:
+ im->xOriginTitle = Xvertical + Xylabel + (im->xsize / 2);
+ im->yOriginTitle = 0;
+
+ im->xOriginLegend = 0;
+ im->yOriginLegend = Ytitle;
+
+ im->xOriginLegendY = 0;
+ im->yOriginLegendY = Ytitle + im->legendheight + (Ymain + Yxlabel) / 2;
+
+ im->xorigin = Xvertical + Xylabel;
+ im->yorigin = Ytitle + im->legendheight + Ymain;
+
+ im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+ if (im->second_axis_scale != 0){
+ im->xOriginLegendY2 += Xylabel;
+ }
+ im->yOriginLegendY2 = Ytitle + im->legendheight + (Ymain + Yxlabel) / 2;
+
+ break;
+
+ case WEST:
+ im->xOriginTitle = im->legendwidth + Xvertical + Xylabel + im->xsize / 2;
+ im->yOriginTitle = 0;
+
+ im->xOriginLegend = 0;
+ im->yOriginLegend = Ytitle;
+
+ im->xOriginLegendY = im->legendwidth;
+ im->yOriginLegendY = (Ytitle + Ymain + Yxlabel) / 2;
+
+ im->xorigin = im->legendwidth + Xvertical + Xylabel;
+ im->yorigin = Ytitle + Ymain;
+
+ im->xOriginLegendY2 = im->legendwidth + Xvertical + Xylabel + Xmain;
+ if (im->second_axis_scale != 0){
+ im->xOriginLegendY2 += Xylabel;
+ }
+ im->yOriginLegendY2 = (Ytitle + Ymain + Yxlabel) / 2;
+
+ break;
+
+ case SOUTH:
+ im->xOriginTitle = Xvertical + Xylabel + im->xsize / 2;
+ im->yOriginTitle = 0;
+
+ im->xOriginLegend = 0;
+ im->yOriginLegend = Ytitle + Ymain + Yxlabel;
+
+ im->xOriginLegendY = 0;
+ im->yOriginLegendY = (Ytitle + Ymain + Yxlabel) / 2;
+
+ im->xorigin = Xvertical + Xylabel;
+ im->yorigin = Ytitle + Ymain;
+
+ im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+ if (im->second_axis_scale != 0){
+ im->xOriginLegendY2 += Xylabel;
+ }
+ im->yOriginLegendY2 = (Ytitle + Ymain + Yxlabel) / 2;
+
+ break;
+
+ case EAST:
+ im->xOriginTitle = Xvertical + Xylabel + im->xsize / 2;
+ im->yOriginTitle = 0;
+
+ im->xOriginLegend = Xvertical + Xylabel + Xmain + Xvertical2;
+ if (im->second_axis_scale != 0){
+ im->xOriginLegend += Xylabel;
+ }
+ im->yOriginLegend = Ytitle;
+
+ im->xOriginLegendY = 0;
+ im->yOriginLegendY = (Ytitle + Ymain + Yxlabel) / 2;
+
+ im->xorigin = Xvertical + Xylabel;
+ im->yorigin = Ytitle + Ymain;
+
+ im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+ if (im->second_axis_scale != 0){
+ im->xOriginLegendY2 += Xylabel;
+ }
+ im->yOriginLegendY2 = (Ytitle + Ymain + Yxlabel) / 2;
+
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ im->xOriginTitle += Xspacing;
+ im->xOriginLegend += Xspacing;
+ im->xOriginLegendY += Xspacing;
+ im->xorigin += Xspacing;
+ im->xOriginLegendY2 += Xspacing;
+ }
+ break;
+ }
+
+ xtr(im, 0);
ytr(im, DNAN);
return 0;
}
@@ -3827,6 +3951,10 @@
im->imgformat = IF_PNG;
im->imginfo = NULL;
im->lazy = 0;
+ im->legenddirection = TOP_DOWN;
+ im->legendheight = 0;
+ im->legendposition = SOUTH;
+ im->legendwidth = 0;
im->logarithmic = 0;
im->maxval = DNAN;
im->minval = 0;
@@ -3848,6 +3976,10 @@
im->ximg = 0;
im->xlab_user.minsec = -1;
im->xorigin = 0;
+ im->xOriginLegend = 0;
+ im->xOriginLegendY = 0;
+ im->xOriginLegendY2 = 0;
+ im->xOriginTitle = 0;
im->xsize = 400;
im->ygridstep = DNAN;
im->yimg = 0;
@@ -3857,6 +3989,10 @@
im->second_axis_legend[0] = '\0';
im->second_axis_format[0] = '\0';
im->yorigin = 0;
+ im->yOriginLegend = 0;
+ im->yOriginLegendY = 0;
+ im->yOriginLegendY2 = 0;
+ im->yOriginTitle = 0;
im->ysize = 100;
im->zoom = 1;
@@ -3941,6 +4077,8 @@
{ "lazy", no_argument, 0, 'z'},
{ "zoom", required_argument, 0, 'm'},
{ "no-legend", no_argument, 0, 'g'},
+ { "legend-position", required_argument, 0, 1005},
+ { "legend-direction", required_argument, 0, 1006},
{ "force-rules-legend", no_argument, 0, 'F'},
{ "only-graph", no_argument, 0, 'j'},
{ "alt-y-grid", no_argument, 0, 'Y'},
@@ -4005,6 +4143,30 @@
case 'g':
im->extra_flags |= NOLEGEND;
break;
+ case 1005:
+ if (strcmp(optarg, "north") == 0) {
+ im->legendposition = NORTH;
+ } else if (strcmp(optarg, "west") == 0) {
+ im->legendposition = WEST;
+ } else if (strcmp(optarg, "south") == 0) {
+ im->legendposition = SOUTH;
+ } else if (strcmp(optarg, "east") == 0) {
+ im->legendposition = EAST;
+ } else {
+ rrd_set_error("unknown legend-position '%s'", optarg);
+ return;
+ }
+ break;
+ case 1006:
+ if (strcmp(optarg, "topdown") == 0) {
+ im->legenddirection = TOP_DOWN;
+ } else if (strcmp(optarg, "bottomup") == 0) {
+ im->legenddirection = BOTTOM_UP;
+ } else {
+ rrd_set_error("unknown legend-position '%s'", optarg);
+ return;
+ }
+ break;
case 'F':
im->extra_flags |= FORCE_RULES_LEGEND;
break;
----------------------- END ----------------------------------------
More information about the rrd-developers
mailing list