+void graph_add_extra_space(struct graph *g, double left_percent,
+ double right_percent, double top_percent,
+ double bottom_percent)
+{
+ g->left_extra = left_percent;
+ g->right_extra = right_percent;
+ g->top_extra = top_percent;
+ g->bottom_extra = bottom_percent;
+}
+
+/*
+ * Normally values are logged in a base unit of 0, but for other purposes
+ * it makes more sense to log in higher unit. For instance for bandwidth
+ * purposes, you may want to log in KB/sec (or MB/sec) rather than bytes/sec.
+ */
+void graph_set_base_offset(struct graph *g, unsigned int base_offset)
+{
+ g->base_offset = base_offset;
+}
+
+int graph_has_tooltips(struct graph *g)
+{
+ struct flist_head *entry;
+ struct graph_label *i;
+
+ flist_for_each(entry, &g->label_list) {
+ i = flist_entry(entry, struct graph_label, list);
+
+ if (!prio_tree_empty(&i->prio_tree))
+ return 1;
+ }
+
+ return 0;
+}
+
+int graph_contains_xy(struct graph *g, int x, int y)
+{
+ int first_x = g->xoffset;
+ int last_x = g->xoffset + g->xdim;
+ int first_y = g->yoffset;
+ int last_y = g->yoffset + g->ydim;
+
+ return (x >= first_x && x <= last_x) && (y >= first_y && y <= last_y);
+}
+
+const char *graph_find_tooltip(struct graph *g, int ix, int iy)
+{
+ double x = ix, y = iy;
+ struct prio_tree_iter iter;
+ struct prio_tree_node *n;
+ struct graph_value *best = NULL;
+ struct flist_head *entry;
+ double best_delta;
+ double maxy, miny;
+
+ x -= g->xoffset;
+ y -= g->yoffset;
+
+ x = g->xtick_zero_val + ((x - g->xtick_zero) * g->xtick_delta);
+ y = g->ytick_zero_val + ((y - g->ytick_zero) * g->ytick_delta);
+
+ x = x * 1000.0;
+ maxy = y + (g->ytick_one_val * TOOLTIP_DELTA);
+ miny = y - (g->ytick_one_val * TOOLTIP_DELTA);
+ best_delta = UINT_MAX;
+ flist_for_each(entry, &g->label_list) {
+ struct graph_label *i;
+
+ i = flist_entry(entry, struct graph_label, list);
+ if (i->hide)
+ continue;
+
+ INIT_PRIO_TREE_ITER(&iter);
+ prio_tree_iter_init(&iter, &i->prio_tree, x, x);
+
+ n = prio_tree_next(&iter);
+ if (!n)
+ continue;
+
+ do {
+ struct graph_value *v, *rootv;
+ double yval, ydiff;
+
+ v = container_of(n, struct graph_value, node);
+ rootv = v;
+ do {
+ yval = gety(v);
+ ydiff = fabs(yval - y);
+
+ /*
+ * zero delta, or within or match critera, break
+ */
+ if (ydiff < best_delta) {
+ best_delta = ydiff;
+ if (!best_delta ||
+ (yval >= miny && yval <= maxy)) {
+ best = v;
+ break;
+ }
+ }
+ if (!flist_empty(&v->alias))
+ v = flist_entry(v->alias.next, struct graph_value, alias);
+ } while (v != rootv);
+ } while ((n = prio_tree_next(&iter)) != NULL);
+
+ /*
+ * If we got matches in one label, don't check others.
+ */
+ if (best)
+ break;
+ }
+
+ if (best)
+ return best->tooltip;
+
+ return NULL;
+}
+
+void graph_set_graph_all_zeroes(struct graph *g, unsigned int set)
+{
+ g->dont_graph_all_zeroes = !set;
+}