[rrd-developers] patch for legends position
Tobias Oetiker
tobi at oetiker.ch
Fri Mar 6 06:47:27 CET 2009
Hi Melchior,
cool ... looking at your sample graphs it seems that the watermark
at the bottom of the graph is runing into the labeling ...
http://mrab.de/wp-content/uploads/go_all_w___.png
Also your patch lacks a patch for doc/rrdgrah.pod
I will be glad to integrate an updated version.
cheers
tobi
Feb 9 Melchior Rabe wrote:
> 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 ----------------------------------------
>
>
> _______________________________________________
> rrd-developers mailing list
> rrd-developers at lists.oetiker.ch
> https://lists.oetiker.ch/cgi-bin/listinfo/rrd-developers
>
>
--
Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
http://it.oetiker.ch tobi at oetiker.ch ++41 62 775 9902 / sb: -9900
More information about the rrd-developers
mailing list