]> git.cworth.org Git - acre/commitdiff
Add support for a new TIMELINE style for drawing a data-set.
authorCarl Worth <cworth@cworth.org>
Thu, 7 Nov 2013 21:24:30 +0000 (13:24 -0800)
committerCarl Worth <cworth@cworth.org>
Thu, 7 Nov 2013 21:24:30 +0000 (13:24 -0800)
For the TIMELINE style, each (X,Y) pair represents (start,stop) time
in the X dimension for a timeline bar to be drawn. The recently added
"_named" variant of add_data is also useful for supplying a name to be
drawn on the bar.

With multiple timelines within a chart, each one is positioned at a
different integer position along the Y axis, (and the Y axis range
computation is changed to preserve this).

There's only minimal cleverness to avoid collision of timeline label,
(the vertical position is cycled unconditionally).

More clever approaches would not change the vertical position if there
is no possibility of conflict, and would also reset to the top
position as soon as possible.

Other potential improvements to the TIMELINE style include:

  * Ensuring that a timeline label is visible whenever any portion of
    a timeline bar is visible.

  * Eliminating the rendering of numbers and ticks on the Y axis.

acre.c
acre.h

diff --git a/acre.c b/acre.c
index 8e7f1b17b6c20134201b547037660927a573e3ec..4e00beeee9557e9111d8a21467e1827e93ebc6e7 100644 (file)
--- a/acre.c
+++ b/acre.c
@@ -328,6 +328,20 @@ acre_add_data (acre_t *acre, acre_data_t *data)
 
     acre->data[acre->num_data] = data;
 
+    /* For timeline datasets, the X and Y ranges need to be
+     * adjusted. The desired X range is the min/max of the X and Y
+     * ranges, and the desired Y range has a size of 1.0 (centered
+     * around the dataset's index) */
+    if (data->style == ACRE_STYLE_TIMELINE) {
+       if (data->min.y < data->min.x)
+           data->min.x = data->min.y;
+       if (data->max.y > data->max.x)
+           data->max.x = data->max.y;
+
+       data->min.y = acre->num_data -0.5;
+       data->max.y = acre->num_data + 0.5;
+    }
+
     if (acre->num_data == 0) {
        acre->x_axis.data_min = data->min.x;
        acre->y_axis.data_min = data->min.y;
@@ -669,6 +683,11 @@ _find_y_range_given_x_range (acre_t *acre,
 
     for (d = 0; d < acre->num_data; d++) {
        data = acre->data[d];
+
+       /* Never mess with the Y range for timeline data. */
+       if (data->style == ACRE_STYLE_TIMELINE)
+           continue;
+
        for (i = 0; i < data->num_points; i++) {
            if (data->points[i].x >= x_min &&
                data->points[i].x <= x_max)
@@ -827,6 +846,71 @@ _draw_data_line (acre_t *acre, acre_data_t *data)
     cairo_restore (cr);
 }
 
+#define TIMELINE_BAR_HEIGHT 0.6
+
+/* Draw the given dataset as a timeline. Each (X,Y) point (potentially
+ * with a name) specifies the (start,stop) of a single timeline bar.
+ *
+ * Each independent timeline dataset in the chart is given its own
+ * vertical position, as specified by 'y_position'.
+ */
+static void
+_draw_data_timeline (acre_t *acre, acre_data_t *data, int y_position)
+{
+    unsigned i;
+    cairo_t *cr = acre->cr;
+    PangoLayout *timeline_label_layout;
+    double ignored, label_offset;
+    int labels_within_bar;
+
+    cairo_save (cr);
+
+    timeline_label_layout = _create_layout (acre, "Timeline");
+    pango_layout_set_font_description (timeline_label_layout, acre->font);
+
+    ignored = 0.0;
+    label_offset = ACRE_FONT_SIZE;
+    cairo_device_to_user_distance (cr, &ignored, &label_offset);
+
+    labels_within_bar = TIMELINE_BAR_HEIGHT / fabs (label_offset);
+
+    for (i = 0; i < data->num_points; i++) {
+       cairo_rectangle (cr,
+                        data->points[i].x,
+                        y_position - TIMELINE_BAR_HEIGHT / 2.0,
+                        data->points[i].y - data->points[i].x,
+                        TIMELINE_BAR_HEIGHT);
+
+       cairo_save (cr);
+       cairo_identity_matrix (cr);
+       cairo_set_line_width (cr, 1.0);
+       cairo_stroke_preserve (cr);
+       cairo_restore (cr);
+
+       cairo_new_path (cr);
+
+       if (i <= data->num_names && data->names[i]) {
+           cairo_save (cr);
+
+           cairo_move_to (cr, data->points[i].x,
+                          y_position + TIMELINE_BAR_HEIGHT / 2.0 +
+                          (i % labels_within_bar) * label_offset);
+           pango_layout_set_text (timeline_label_layout, data->names[i], -1);
+           cairo_identity_matrix (cr);
+           pango_cairo_show_layout (cr, timeline_label_layout);
+
+           cairo_restore (cr);
+       } else {
+           cairo_new_path (cr);
+       }
+
+    }
+
+    _destroy_layout (timeline_label_layout);
+
+    cairo_restore (cr);
+}
+
 /* Draw all the datasets of the chart. */
 static void
 _draw_data (acre_t *acre)
@@ -858,6 +942,10 @@ _draw_data (acre_t *acre)
        case ACRE_STYLE_LINE:
            _draw_data_line (acre, data);
            break;
+       case ACRE_STYLE_TIMELINE:
+           /* Position the timeline bars top-down */
+           _draw_data_timeline (acre, data, acre->num_data - 1 - i);
+           break;
        }
     }
 
@@ -1113,6 +1201,12 @@ acre_data_destroy (acre_data_t *data)
     free (data);
 }
 
+void
+acre_data_set_style (acre_data_t *data, acre_style_t style)
+{
+    data->style = style;
+}
+
 /* Set the label for this dataset (to appear in the plot's key). */
 void
 acre_data_set_name (acre_data_t *data, const char *name)
diff --git a/acre.h b/acre.h
index 6bad89aa88555127137ef45a8494484f527972be..9611da3d8d15a8b7c4cf00d4bfd07f564b5e574a 100644 (file)
--- a/acre.h
+++ b/acre.h
@@ -115,7 +115,18 @@ acre_data_destroy (acre_data_t *data);
 /* The style to be used for rendering data sets. */
 typedef enum
 {
-       ACRE_STYLE_LINE
+       /* A simple line graph connection each (X,Y) pair in order. */
+       ACRE_STYLE_LINE,
+
+       /* A timeline.
+        *
+        * Each (X,Y) pair specifies the (start,stop) time of a
+        * timeline bar.
+        *
+        * The acre_data_add_point_2d_named function is particularly
+        * useful to provide a name for each timeline bar.
+        */
+       ACRE_STYLE_TIMELINE
 } acre_style_t;
 
 /* Set the rendering style for this dataset. */