- idxI=-1;
- drawem = 0;
- }
- if (drawem != 0){
- drawem = 0;
- idxI=-1;
- }
- if (ii == im->xsize) break;
-
- /* keep things simple for now, just draw these bars
- do not try to build a big and complex area */
-
-
- if ( im->slopemode == 0 && ii==0){
- continue;
- }
- if ( isnan(im->gdes[i].p_data[ii]) ) {
- drawem = 1;
- continue;
- }
- ytop = ytr(im,im->gdes[i].p_data[ii]);
- if ( lastgdes && im->gdes[i].stack ) {
- ybase = ytr(im,lastgdes->p_data[ii]);
- } else {
- ybase = ytr(im,areazero);
- }
- if ( ybase == ytop ){
- drawem = 1;
- continue;
- }
- /* 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 ){
- backY[++idxI] = ybase-0.2;
- backX[idxI] = ii+im->xorigin-1;
- foreY[idxI] = ytop+0.2;
- foreX[idxI] = ii+im->xorigin-1;
- }
- backY[++idxI] = ybase-0.2;
- backX[idxI] = ii+im->xorigin;
- foreY[idxI] = ytop+0.2;
- foreX[idxI] = ii+im->xorigin;
- }
- /* close up any remaining area */
- free(foreY);
- free(foreX);
- free(backY);
- free(backX);
- } /* else GF_LINE */
- } /* if color != 0x0 */
- /* make sure we do not run into trouble when stacking on NaN */
- for(ii=0;ii<im->xsize;ii++){
- if (isnan(im->gdes[i].p_data[ii])) {
- if (lastgdes && (im->gdes[i].stack)) {
- im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
- } else {
- im->gdes[i].p_data[ii] = areazero;
- }
- }
- }
- lastgdes = &(im->gdes[i]);
- break;
-#ifdef WITH_PIECHART
- 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(im,im->gdes[i].col,
- im->pie_x,im->pie_y,im->piesize*0.4,
- M_PI*2.0*PieStart/100.0,
- M_PI*2.0*(PieStart+im->gdes[i].yrule)/100.0);
- PieStart += im->gdes[i].yrule;
- }
- break;
-#endif
- case GF_STACK:
- rrd_set_error("STACK should already be turned into LINE or AREA here");
- return -1;
- break;
-
- } /* switch */
- }
-#ifdef WITH_PIECHART
- if (piechart==2) {
- im->draw_x_grid=0;
- im->draw_y_grid=0;
- }
-#endif
+ } /* for */
+
+ /* *******************************************************
+ a ___. (a,t)
+ | | ___
+ ____| | | |
+ | |___|
+ -------|--t-1--t--------------------------------
+
+ if we know the value at time t was a then
+ we draw a square from t-1 to t with the value a.
+
+ ********************************************************* */
+ if (im->gdes[i].col.alpha != 0.0) {
+ /* GF_LINE and friend */
+ if (im->gdes[i].gf == GF_LINE) {
+ double last_y = 0.0;
+ int draw_on = 0;
+
+ cairo_save(im->cr);
+ cairo_new_path(im->cr);
+ cairo_set_line_width(im->cr, im->gdes[i].linewidth);
+ if (im->gdes[i].dash) {
+ cairo_set_dash(im->cr,
+ im->gdes[i].p_dashes,
+ im->gdes[i].ndash, im->gdes[i].offset);
+ }
+
+ 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]))) {
+ draw_on = 0;
+ continue;
+ }
+ if (draw_on == 0) {
+ last_y = ytr(im, im->gdes[i].p_data[ii]);
+ if (im->slopemode == 0) {
+ double x = ii - 1 + im->xorigin;
+ double y = last_y;
+
+ gfx_line_fit(im, &x, &y);
+ cairo_move_to(im->cr, x, y);
+ x = ii + im->xorigin;
+ y = last_y;
+ gfx_line_fit(im, &x, &y);
+ cairo_line_to(im->cr, x, y);
+ } else {
+ double x = ii - 1 + im->xorigin;
+ double y =
+ ytr(im, im->gdes[i].p_data[ii - 1]);
+ gfx_line_fit(im, &x, &y);
+ cairo_move_to(im->cr, x, y);
+ x = ii + im->xorigin;
+ y = last_y;
+ gfx_line_fit(im, &x, &y);
+ cairo_line_to(im->cr, x, y);
+ }
+ draw_on = 1;
+ } else {
+ double x1 = ii + im->xorigin;
+ double y1 = ytr(im, im->gdes[i].p_data[ii]);
+
+ if (im->slopemode == 0
+ && !AlmostEqual2sComplement(y1, last_y, 4)) {
+ double x = ii - 1 + im->xorigin;
+ double y = y1;
+
+ gfx_line_fit(im, &x, &y);
+ cairo_line_to(im->cr, x, y);
+ };
+ last_y = y1;
+ gfx_line_fit(im, &x1, &y1);
+ cairo_line_to(im->cr, x1, y1);
+ };
+ }
+ cairo_set_source_rgba(im->cr,
+ im->gdes[i].
+ col.red,
+ im->gdes[i].
+ col.green,
+ im->gdes[i].
+ col.blue, im->gdes[i].col.alpha);
+ cairo_set_line_cap(im->cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join(im->cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_stroke(im->cr);
+ cairo_restore(im->cr);
+ } else {
+ double lastx=0;
+ double lasty=0;
+ int idxI = -1;
+ double *foreY =
+ (double *) malloc(sizeof(double) * im->xsize * 2);
+ double *foreX =
+ (double *) malloc(sizeof(double) * im->xsize * 2);
+ double *backY =
+ (double *) malloc(sizeof(double) * im->xsize * 2);
+ double *backX =
+ (double *) malloc(sizeof(double) * im->xsize * 2);
+ int drawem = 0;
+
+ for (ii = 0; ii <= im->xsize; ii++) {
+ double ybase, ytop;
+
+ if (idxI > 0 && (drawem != 0 || ii == im->xsize)) {
+ int cntI = 1;
+ int lastI = 0;
+
+ while (cntI < idxI
+ &&
+ AlmostEqual2sComplement(foreY
+ [lastI],
+ foreY[cntI], 4)
+ &&
+ AlmostEqual2sComplement(foreY
+ [lastI],
+ foreY
+ [cntI + 1], 4)) {
+ cntI++;
+ }
+ if (im->gdes[i].gf != GF_GRAD) {
+ gfx_new_area(im,
+ backX[0], backY[0],
+ foreX[0], foreY[0],
+ foreX[cntI],
+ foreY[cntI], im->gdes[i].col);
+ } else {
+ lastx = foreX[cntI];
+ lasty = foreY[cntI];
+ }
+ while (cntI < idxI) {
+ lastI = cntI;
+ cntI++;
+ while (cntI < idxI
+ &&
+ AlmostEqual2sComplement(foreY
+ [lastI],
+ foreY[cntI], 4)
+ &&
+ AlmostEqual2sComplement(foreY
+ [lastI],
+ foreY
+ [cntI
+ + 1], 4)) {
+ cntI++;
+ }
+ if (im->gdes[i].gf != GF_GRAD) {
+ gfx_add_point(im, foreX[cntI], foreY[cntI]);
+ } else {
+ gfx_add_rect_fadey(im,
+ lastx, foreY[0],
+ foreX[cntI], foreY[cntI], lasty,
+ im->gdes[i].col,
+ im->gdes[i].col2,
+ im->gdes[i].gradheight
+ );
+ lastx = foreX[cntI];
+ lasty = foreY[cntI];
+ }
+ }
+ if (im->gdes[i].gf != GF_GRAD) {
+ gfx_add_point(im, backX[idxI], backY[idxI]);
+ } else {
+ gfx_add_rect_fadey(im,
+ lastx, foreY[0],
+ backX[idxI], backY[idxI], lasty,
+ im->gdes[i].col,
+ im->gdes[i].col2,
+ im->gdes[i].gradheight);
+ lastx = backX[idxI];
+ lasty = backY[idxI];
+ }
+ while (idxI > 1) {
+ lastI = idxI;
+ idxI--;
+ while (idxI > 1
+ &&
+ AlmostEqual2sComplement(backY
+ [lastI],
+ backY[idxI], 4)
+ &&
+ AlmostEqual2sComplement(backY
+ [lastI],
+ backY
+ [idxI
+ - 1], 4)) {
+ idxI--;
+ }
+ if (im->gdes[i].gf != GF_GRAD) {
+ gfx_add_point(im, backX[idxI], backY[idxI]);
+ } else {
+ gfx_add_rect_fadey(im,
+ lastx, foreY[0],
+ backX[idxI], backY[idxI], lasty,
+ im->gdes[i].col,
+ im->gdes[i].col2,
+ im->gdes[i].gradheight);
+ lastx = backX[idxI];
+ lasty = backY[idxI];
+ }
+ }
+ idxI = -1;
+ drawem = 0;
+ if (im->gdes[i].gf != GF_GRAD)
+ gfx_close_path(im);
+ }
+ if (drawem != 0) {
+ drawem = 0;
+ idxI = -1;
+ }
+ if (ii == im->xsize)
+ break;
+ if (im->slopemode == 0 && ii == 0) {
+ continue;
+ }
+ if (isnan(im->gdes[i].p_data[ii])) {
+ drawem = 1;
+ continue;
+ }
+ ytop = ytr(im, im->gdes[i].p_data[ii]);
+ if (lastgdes && im->gdes[i].stack) {
+ ybase = ytr(im, lastgdes->p_data[ii]);
+ } else {
+ ybase = ytr(im, areazero);
+ }
+ if (ybase == ytop) {
+ drawem = 1;
+ continue;
+ }
+
+ if (ybase > ytop) {
+ double extra = ytop;
+
+ ytop = ybase;
+ ybase = extra;
+ }
+ if (im->slopemode == 0) {
+ backY[++idxI] = ybase - 0.2;
+ backX[idxI] = ii + im->xorigin - 1;
+ foreY[idxI] = ytop + 0.2;
+ foreX[idxI] = ii + im->xorigin - 1;
+ }
+ backY[++idxI] = ybase - 0.2;
+ backX[idxI] = ii + im->xorigin;
+ foreY[idxI] = ytop + 0.2;
+ foreX[idxI] = ii + im->xorigin;
+ }
+ /* close up any remaining area */
+ free(foreY);
+ free(foreX);
+ free(backY);
+ free(backX);
+ } /* else GF_LINE */
+ }
+ /* if color != 0x0 */
+ /* make sure we do not run into trouble when stacking on NaN */
+ for (ii = 0; ii < im->xsize; ii++) {
+ if (isnan(im->gdes[i].p_data[ii])) {
+ if (lastgdes && (im->gdes[i].stack)) {
+ im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
+ } else {
+ im->gdes[i].p_data[ii] = areazero;
+ }
+ }
+ }
+ lastgdes = &(im->gdes[i]);
+ break;
+ } /* GF_AREA, GF_LINE, GF_GRAD */
+ case GF_STACK:
+ rrd_set_error
+ ("STACK should already be turned into LINE or AREA here");
+ return -1;
+ break;
+ } /* switch */
+ }
+ cairo_reset_clip(im->cr);
+
+ /* grid_paint also does the text */
+ if (!(im->extra_flags & ONLY_GRAPH))
+ grid_paint(im);
+ if (!(im->extra_flags & ONLY_GRAPH))
+ axis_paint(im);
+ /* the RULES are the last thing to paint ... */
+ for (i = 0; i < im->gdes_c; i++) {
+
+ switch (im->gdes[i].gf) {
+ case GF_HRULE:
+ if (im->gdes[i].yrule >= im->minval
+ && im->gdes[i].yrule <= im->maxval) {
+ cairo_save(im->cr);
+ if (im->gdes[i].dash) {
+ cairo_set_dash(im->cr,
+ im->gdes[i].p_dashes,
+ im->gdes[i].ndash, im->gdes[i].offset);
+ }
+ gfx_line(im, im->xorigin,
+ ytr(im, im->gdes[i].yrule),
+ im->xorigin + im->xsize,
+ ytr(im, im->gdes[i].yrule), 1.0, im->gdes[i].col);
+ cairo_stroke(im->cr);
+ cairo_restore(im->cr);
+ }
+ break;
+ case GF_VRULE:
+ if (im->gdes[i].xrule >= im->start
+ && im->gdes[i].xrule <= im->end) {
+ cairo_save(im->cr);
+ if (im->gdes[i].dash) {
+ cairo_set_dash(im->cr,
+ im->gdes[i].p_dashes,
+ im->gdes[i].ndash, im->gdes[i].offset);
+ }
+ gfx_line(im,
+ xtr(im, im->gdes[i].xrule),
+ im->yorigin, xtr(im,
+ im->
+ gdes[i].
+ xrule),
+ im->yorigin - im->ysize, 1.0, im->gdes[i].col);
+ cairo_stroke(im->cr);
+ cairo_restore(im->cr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ /* close the graph via cairo*/
+ return graph_cairo_finish(im);
+}
+
+int graph_cairo_setup (image_desc_t *im)
+{
+ /* the actual graph is created by going through the individual
+ graph elements and then drawing them */
+ cairo_surface_destroy(im->surface);
+ switch (im->imgformat) {
+ case IF_PNG:
+ im->surface =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ im->ximg * im->zoom,
+ im->yimg * im->zoom);
+ break;
+ case IF_PDF:
+ im->gridfit = 0;
+ im->surface = strlen(im->graphfile)
+ ? cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom,
+ im->yimg * im->zoom)
+ : cairo_pdf_surface_create_for_stream
+ (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+ break;
+ case IF_EPS:
+ im->gridfit = 0;
+ im->surface = strlen(im->graphfile)
+ ?
+ cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom,
+ im->yimg * im->zoom)
+ : cairo_ps_surface_create_for_stream
+ (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+ break;
+ case IF_SVG:
+ im->gridfit = 0;
+ im->surface = strlen(im->graphfile)
+ ?
+ cairo_svg_surface_create(im->
+ graphfile,
+ im->ximg * im->zoom, im->yimg * im->zoom)
+ : cairo_svg_surface_create_for_stream
+ (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+ cairo_svg_surface_restrict_to_version
+ (im->surface, CAIRO_SVG_VERSION_1_1);
+ break;
+ case IF_XML:
+ case IF_XMLENUM:
+ case IF_CSV:
+ case IF_TSV:
+ case IF_SSV:
+ case IF_JSON:
+ case IF_JSONTIME:
+ break;
+ };
+ cairo_destroy(im->cr);
+ im->cr = cairo_create(im->surface);
+ cairo_set_antialias(im->cr, im->graph_antialias);
+ cairo_scale(im->cr, im->zoom, im->zoom);
+// pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
+ gfx_new_area(im, 0, 0, 0, im->yimg,
+ im->ximg, im->yimg, im->graph_col[GRC_BACK]);
+ gfx_add_point(im, im->ximg, 0);
+ gfx_close_path(im);
+ gfx_new_area(im, im->xorigin,
+ im->yorigin,
+ im->xorigin +
+ im->xsize, im->yorigin,
+ im->xorigin +
+ im->xsize,
+ im->yorigin - im->ysize, im->graph_col[GRC_CANVAS]);
+ gfx_add_point(im, im->xorigin, im->yorigin - im->ysize);
+ gfx_close_path(im);
+ cairo_rectangle(im->cr, im->xorigin, im->yorigin - im->ysize - 1.0,
+ im->xsize, im->ysize + 2.0);
+ cairo_clip(im->cr);
+ return 0;
+}
+
+int graph_cairo_finish (image_desc_t *im)
+{