#include "graph.h"
#include "flist.h"
#include "lib/prio_tree.h"
-#include "gettime.h"
-struct thread_data;
-#include "time.h"
/*
* Allowable difference to show tooltip
*/
-#define TOOLTIP_DELTA 1.02
+#define TOOLTIP_DELTA 0.08
struct xyvalue {
double x, y;
double xtick_zero;
double xtick_delta;
double xtick_zero_val;
+ double xtick_one_val;
double ytick_zero;
double ytick_delta;
double ytick_zero_val;
+ double ytick_one_val;
};
void graph_set_size(struct graph *g, unsigned int xdim, unsigned int ydim)
if (!i) {
g->xtick_zero = tx;
g->xtick_zero_val = tm[0].value;
- } else if (i == 1)
+ } else if (i == 1) {
g->xtick_delta = (tm[1].value - tm[0].value) / (tx - g->xtick_zero);
+ g->xtick_one_val = tm[1].value;
+ }
/* really tx < yx || tx > x2, but protect against rounding */
if (x1 - tx > 0.01 || tx - x2 > 0.01)
if (!i) {
g->ytick_zero = ty;
g->ytick_zero_val = tm[0].value;
- } else if (i == 1)
+ } else if (i == 1) {
g->ytick_delta = (tm[1].value - tm[0].value) / (ty - g->ytick_zero);
+ g->ytick_one_val = tm[1].value;
+ }
/* really ty < y1 || ty > y2, but protect against rounding */
if (y1 - ty > 0.01 || ty - y2 > 0.01)
skip_data:
cairo_restore(cr);
-
}
static void setstring(char **str, const char *value)
static void graph_label_add_value(struct graph_label *i, void *value,
const char *tooltip)
{
+ struct graph *g = i->parent;
struct graph_value *x;
x = malloc(sizeof(*x));
+ memset(x, 0, sizeof(*x));
x->value = value;
- if (tooltip)
- x->tooltip = strdup(tooltip);
- else
- x->tooltip = NULL;
x->next = NULL;
- if (!i->tail) {
+ if (!i->tail)
i->values = x;
- } else {
+ else
i->tail->next = x;
- }
i->tail = x;
i->value_count++;
- if (x->tooltip) {
- double yval = gety(x);
- double miny = yval / TOOLTIP_DELTA;
- double maxy = yval * TOOLTIP_DELTA;
-
- x->node.start = miny;
- x->node.last = maxy;
- if (x->node.last == x->node.start)
- x->node.last++;
+ if (tooltip) {
+ /*
+ * use msec to avoid dropping too much precision when
+ * storing as an integer.
+ */
+ double xval = getx(x);
+ double minx = xval - (g->xtick_one_val * TOOLTIP_DELTA);
+ double maxx = xval + (g->xtick_one_val * TOOLTIP_DELTA);
+ struct prio_tree_node *ret;
+
+ xval = xval * 1000.0;
+ minx = minx * 1000.0;
+ maxx = maxx * 1000.0;
+
+ INIT_PRIO_TREE_NODE(&x->node);
+ x->node.start = minx;
+ x->node.last = maxx;
+ if (x->node.last == x->node.start) {
+ x->node.last += fabs(g->xtick_delta);
+ if (x->node.last == x->node.start)
+ x->node.last++;
+ }
- prio_tree_insert(&i->prio_tree, &x->node);
- printf("insert (x=%u,y=%u) range %lu-%lu (%s)\n", (int)getx(x), (int)gety(x), x->node.start, x->node.last, x->tooltip);
- i->tooltip_count++;
+ /*
+ * If ret != &x->node, we have an alias. Since the values
+ * should be identical, we can drop it
+ */
+ ret = prio_tree_insert(&i->prio_tree, &x->node);
+ if (ret == &x->node) {
+ x->tooltip = strdup(tooltip);
+ i->tooltip_count++;
+ }
}
- if (i->parent->per_label_limit != -1 &&
- i->value_count > i->parent->per_label_limit) {
+ if (g->per_label_limit != -1 &&
+ i->value_count > g->per_label_limit) {
int to_drop = 1;
/*
* entries. This will make us (eventually) reach the
* specified limit.
*/
- if (i->value_count - i->parent->per_label_limit >= 2)
+ if (i->value_count - g->per_label_limit >= 2)
to_drop = 2;
while (to_drop--) {
return 0;
}
-static void graph_free_values(struct graph_value *values)
+static void graph_free_values(struct graph_label *l, struct graph_value *values)
{
struct graph_value *i, *next;
for (i = values; i; i = next) {
next = i->next;
free(i->value);
+ if (i->tooltip) {
+ free(i->tooltip);
+ prio_tree_remove(&l->prio_tree, &i->node);
+ l->tooltip_count--;
+ }
free(i);
}
}
for (i = labels; i; i = next) {
next = i->next;
- graph_free_values(i->values);
+ graph_free_values(i, i->values);
free(i);
}
}
struct graph_label *i;
struct graph_value *best = NULL;
double best_delta;
- double maxx, minx;
+ 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);
- maxx = x * TOOLTIP_DELTA;
- minx = x / TOOLTIP_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;
i = g->labels;
do {
- prio_tree_iter_init(&iter, &i->prio_tree, y, y);
+ INIT_PRIO_TREE_ITER(&iter);
+ prio_tree_iter_init(&iter, &i->prio_tree, x, x);
n = prio_tree_next(&iter);
if (!n)
do {
struct graph_value *v;
- double xval, xdiff;
+ double yval, ydiff;
v = container_of(n, struct graph_value, node);
- xval = getx(v);
-
- if (xval > x)
- xdiff = xval - x;
- else
- xdiff = x - xval;
+ yval = gety(v);
+ ydiff = fabs(yval - y);
/*
* zero delta, or within or match critera, break
*/
- if (xdiff < best_delta) {
- best_delta = xdiff;
+ if (ydiff < best_delta) {
+ best_delta = ydiff;
if (!best_delta ||
- (xval >= minx && xval <= maxx)) {
+ (yval >= miny && yval <= maxy)) {
best = v;
break;
}