summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: f4abf7d)
raw | patch | inline | side by side (parent: f4abf7d)
author | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Wed, 18 Mar 2009 17:12:09 +0000 (17:12 +0000) | ||
committer | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Wed, 18 Mar 2009 17:12:09 +0000 (17:12 +0000) |
CONTRIBUTORS | patch | blob | history | |
NEWS | patch | blob | history | |
doc/rrdgraph.pod | patch | blob | history | |
src/rrd_graph.c | patch | blob | history | |
src/rrd_graph.h | patch | blob | history |
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ed5aca4fcbc3084402c43c4ed842ae1eacf48b7b..29bbcae6d95fad221e84a8c32075407c5d83f9ef 100644 (file)
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
Larry Leszczynski <larryl with furph.com>
Mark Plaksin <happy@usg.edu> rrd_graph_v
Matt Chambers <matthew.chambers with vanderbilt.edu> --full-size-mode for rrdgraph
+Melchior Rabe <rrdtool at mrab.de> -- legend position patch
McCreary mccreary with xoanon.colorado.edu
Mike Mitchell <mcm with unx.sas.com>
Mike Slifcak <slif with bellsouth.net> many rrdtool-1.1.x fixes
index 7d0c920499ec453888a27d7ab3f51d6538b9c04e..1f3b38bca3474fe01b111ff34068bc50469e7c54 100644 (file)
--- a/NEWS
+++ b/NEWS
RRDgraph
--------
* VDEF PERCENTNAN (PRECENT that ignores NAN)
+* new --legend-direction and --legend-positon placement option
RRDflush
--------
diff --git a/doc/rrdgraph.pod b/doc/rrdgraph.pod
index 0ac2fbf786798118dcc1ae0299b6b36b51ae5218..b798ff92dafda29603b435ff20bae51d19459432 100644 (file)
--- a/doc/rrdgraph.pod
+++ b/doc/rrdgraph.pod
=back
+=head2 Legend
+
+[B<-g>|B<--no-legend>]
+
+Suppress generation of the legend; only render the graph.
+
+[B<-F>|B<--force-rules-legend>]
+
+Force the generation of HRULE and VRULE legends even if those HRULE or
+VRULE will not be drawn because out of graph boundaries (mimics
+behaviour of pre 1.0.42 versions).
+
+[B<--legend-position>=(north|south|west|east)]
+
+Place the legend at the given side of the graph. The default is south.
+In west or east position it is necessary to add line breaks manually.
+
+[B<--legend-direction>=(topdown|bottomup)]
+
+Place the legend items in the given vertical order. The default is topdown.
+Using bottomup the legend items appear in the same vertical order as a
+stack of lines or areas.
+
=head2 Miscellaneous
[B<-z>|B<--lazy>]
If images are interlaced they become visible on browsers more quickly.
-[B<-g>|B<--no-legend>]
-
-Suppress generation of the legend; only render the graph.
-
-[B<-F>|B<--force-rules-legend>]
-
-Force the generation of HRULE and VRULE legends even if those HRULE or
-VRULE will not be drawn because out of graph boundaries (mimics
-behaviour of pre 1.0.42 versions).
-
[B<-T>|B<--tabwidth> I<value>]
By default the tab-width is 40 pixels, use this option to change it.
diff --git a/src/rrd_graph.c b/src/rrd_graph.c
index 19e3c4033f87fec325a458ef74976d5ed16f7bd8..eb909522e50635ba19c2ff535afeb2d19a15b553 100644 (file)
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
}
+
/* place legends with color spots */
int leg_place(
image_desc_t *im,
- int *gY)
+ int 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) {
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) {
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] == '\\') {
}
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:
}
}
/* is it time to place the legends ? */
- if (fill > im->ximg - 2 * border) {
+ if (fill > legendwidth) {
if (leg_c > 1) {
/* go back one */
i--;
}
}
-
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->
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);
}
/* 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,
/* 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].
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].
}
/* graph watermark */
if (im->watermark[0] != '\0') {
+ water_color = im->graph_col[GRC_FONT];
+ water_color.alpha = 0.3;
gfx_text(im,
im->ximg / 2, im->yimg - 6,
water_color,
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->
/* 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.........|
** | +---+-------------------------------+
** +---------------------------------------+
*/
+ 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;
+ }
+
+ if(im->watermark[0] != '\0') {
+ Ywatermark = im->text_prop[TEXT_PROP_WATERMARK].size * 2;
+ }
+
+ // 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
/* 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, 1) == -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->second_axis_legend[0] != '\0' ) {
- Xmain -= im->text_prop[TEXT_PROP_UNIT].size * 1.5;
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ Xmain -= Xspacing;
}
- im->xsize = Xmain;
+ Xmain -= Xvertical + Xvertical2;
- 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;
+ /* limit the remaining space to 0 */
+ if(Xmain < 1){
+ Xmain = 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;
+ im->xsize = Xmain;
+
+ /* 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, 0) == -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 */
** and other things outside the graph area.
*/
- if (im->ylegend[0] != '\0') {
- Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
- }
-
-
- 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;
- }
-
if (elements) {
- Xmain = im->xsize;
+ Xmain = im->xsize; // + Xspacing;
Ymain = im->ysize;
}
- /* 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. */
- /* 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;
-
- if (im->second_axis_scale != 0){
- im->ximg += Xylabel + Xspacing;
+ im->ximg = Xmain + Xylabel;
+ if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+ im->ximg += Xspacing;
}
- if (im->extra_flags & NO_RRDTOOL_TAG){
- im->ximg -= Xspacing;
+
+ if( (im->legendposition == WEST || im->legendposition == EAST) && !(im->extra_flags & NOLEGEND) ){
+ im->ximg += im->legendwidth;// + Xspacing;
}
-
- 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_scale != 0){
+ im->ximg += Xylabel;
}
- if (im->second_axis_legend[0] != '\0' ) {
- im->ximg += Xvertical;
+
+ im->ximg += Xvertical + Xvertical2;
+
+ if (!(im->extra_flags & NOLEGEND)) {
+ if(im->legendposition == NORTH || im->legendposition == SOUTH){
+ im->legendwidth = im->ximg;
+ if (leg_place(im, 0) == -1){
+ return -1;
+ }
+ }
}
- 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;
+ if( (im->legendposition == NORTH || im->legendposition == SOUTH) && !(im->extra_flags & NOLEGEND) ){
+ im->yimg += im->legendheight;
+ }
+
/* 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, 0) == -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 / 2) + Yxlabel;
+
+ 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 / 2) + Yxlabel;
+
+ 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 / 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 / 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 / 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 / 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 / 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 / 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;
}
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;
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;
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;
{ "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'},
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;
diff --git a/src/rrd_graph.h b/src/rrd_graph.h
index cc36c256eb4a3526096ae9c541b52a6dbed56d28..f029fd1f3e14157f1d064b1963c6ada00f777ece 100644 (file)
--- a/src/rrd_graph.h
+++ b/src/rrd_graph.h
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 };
reasonable probablility that the
existing one is out of date */
int slopemode; /* connect the dots of the curve directly, not using a stair */
+ enum legend_pos legendposition; /* the position of the legend: north, west, south or east */
+ enum 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 */
/* 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 */
image_desc_t *);
int leg_place(
image_desc_t *,
- int *);
+ int);
int calc_horizontal_grid(
image_desc_t *);
int draw_horizontal_grid(