Several cursors methods added. Make rel_zoom_{x,y}_m{in,ax} readonly properties.

This commit is contained in:
Kolan Sh 2017-11-28 21:41:25 +03:00
parent 8a7ce14f5d
commit b465034bc3
4 changed files with 352 additions and 81 deletions

View File

@ -87,17 +87,21 @@ namespace Gtk.CairoChart {
} }
} }
double rel_zoom_x_min = 0.0; double _rel_zoom_x_min = 0.0;
double rel_zoom_x_max = 1.0; double _rel_zoom_x_max = 1.0;
double rel_zoom_y_min = 0.0; double _rel_zoom_y_min = 0.0;
double rel_zoom_y_max = 1.0; double _rel_zoom_y_max = 1.0;
public double rel_zoom_x_min { get { return _rel_zoom_x_min; } default = 0.0; }
public double rel_zoom_x_max { get { return _rel_zoom_x_max; } default = 1.0; }
public double rel_zoom_y_min { get { return _rel_zoom_y_min; } default = 0.0; }
public double rel_zoom_y_max { get { return _rel_zoom_y_max; } default = 1.0; }
int zoom_first_show = 0; int zoom_first_show = 0;
public virtual void zoom_in (double x0, double y0, double x1, double y1) { public virtual void zoom_in (double x0, double y0, double x1, double y1) {
for (var si = 0, max_i = series.length; si < max_i; ++si) { for (var si = 0, max_i = series.length; si < max_i; ++si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
var real_x0 = get_real_x (s, x0); var real_x0 = get_real_x (s, x0);
var real_x1 = get_real_x (s, x1); var real_x1 = get_real_x (s, x1);
var real_y0 = get_real_y (s, y0); var real_y0 = get_real_y (s, y0);
@ -105,7 +109,7 @@ namespace Gtk.CairoChart {
// if selected square does not intersect with the series's square // if selected square does not intersect with the series's square
if ( real_x1 <= s.axis_x.zoom_min || real_x0 >= s.axis_x.zoom_max if ( real_x1 <= s.axis_x.zoom_min || real_x0 >= s.axis_x.zoom_max
|| real_y0 <= s.axis_y.zoom_min || real_y1 >= s.axis_y.zoom_max) { || real_y0 <= s.axis_y.zoom_min || real_y1 >= s.axis_y.zoom_max) {
s.zoom_show = false; s.show = false;
continue; continue;
} }
if (real_x0 >= s.axis_x.zoom_min) { if (real_x0 >= s.axis_x.zoom_min) {
@ -136,24 +140,24 @@ namespace Gtk.CairoChart {
zoom_first_show = 0; zoom_first_show = 0;
for (var si = 0, max_i = series.length; si < max_i; ++si) for (var si = 0, max_i = series.length; si < max_i; ++si)
if (series[si].zoom_show) { if (series[si].show) {
zoom_first_show = si; zoom_first_show = si;
break; break;
} }
var new_rel_zoom_x_min = rel_zoom_x_min + (x0 - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) * (rel_zoom_x_max - rel_zoom_x_min); var new_rel_zoom_x_min = _rel_zoom_x_min + (x0 - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) * (_rel_zoom_x_max - _rel_zoom_x_min);
var new_rel_zoom_x_max = rel_zoom_x_min + (x1 - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) * (rel_zoom_x_max - rel_zoom_x_min); var new_rel_zoom_x_max = _rel_zoom_x_min + (x1 - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) * (_rel_zoom_x_max - _rel_zoom_x_min);
var new_rel_zoom_y_min = rel_zoom_y_min + (y0 - plot_area_y_min) / (plot_area_y_max - plot_area_y_min) * (rel_zoom_y_max - rel_zoom_y_min); var new_rel_zoom_y_min = _rel_zoom_y_min + (y0 - plot_area_y_min) / (plot_area_y_max - plot_area_y_min) * (_rel_zoom_y_max - _rel_zoom_y_min);
var new_rel_zoom_y_max = rel_zoom_y_min + (y1 - plot_area_y_min) / (plot_area_y_max - plot_area_y_min) * (rel_zoom_y_max - rel_zoom_y_min); var new_rel_zoom_y_max = _rel_zoom_y_min + (y1 - plot_area_y_min) / (plot_area_y_max - plot_area_y_min) * (_rel_zoom_y_max - _rel_zoom_y_min);
rel_zoom_x_min = new_rel_zoom_x_min; _rel_zoom_x_min = new_rel_zoom_x_min;
rel_zoom_x_max = new_rel_zoom_x_max; _rel_zoom_x_max = new_rel_zoom_x_max;
rel_zoom_y_min = new_rel_zoom_y_min; _rel_zoom_y_min = new_rel_zoom_y_min;
rel_zoom_y_max = new_rel_zoom_y_max; _rel_zoom_y_max = new_rel_zoom_y_max;
} }
public virtual void zoom_out () { public virtual void zoom_out () {
foreach (var s in series) { foreach (var s in series) {
s.zoom_show = true; s.show = true;
s.axis_x.zoom_min = s.axis_x.min; s.axis_x.zoom_min = s.axis_x.min;
s.axis_x.zoom_max = s.axis_x.max; s.axis_x.zoom_max = s.axis_x.max;
s.axis_y.zoom_min = s.axis_y.min; s.axis_y.zoom_min = s.axis_y.min;
@ -163,10 +167,10 @@ namespace Gtk.CairoChart {
s.place.zoom_y_low = s.place.y_low; s.place.zoom_y_low = s.place.y_low;
s.place.zoom_y_high = s.place.y_high; s.place.zoom_y_high = s.place.y_high;
} }
rel_zoom_x_min = 0; _rel_zoom_x_min = 0;
rel_zoom_x_max = 1; _rel_zoom_x_max = 1;
rel_zoom_y_min = 0; _rel_zoom_y_min = 0;
rel_zoom_y_max = 1; _rel_zoom_y_max = 1;
zoom_first_show = 0; zoom_first_show = 0;
} }
@ -174,7 +178,7 @@ namespace Gtk.CairoChart {
public virtual void move (double delta_x, double delta_y) { public virtual void move (double delta_x, double delta_y) {
delta_x /= plot_area_x_max - plot_area_x_min; delta_x *= - 1.0; delta_x /= plot_area_x_max - plot_area_x_min; delta_x *= - 1.0;
delta_y /= plot_area_y_max - plot_area_y_min; delta_y *= - 1.0; delta_y /= plot_area_y_max - plot_area_y_min; delta_y *= - 1.0;
var rzxmin = rel_zoom_x_min, rzxmax = rel_zoom_x_max, rzymin = rel_zoom_y_min, rzymax = rel_zoom_y_max; var rzxmin = _rel_zoom_x_min, rzxmax = _rel_zoom_x_max, rzymin = _rel_zoom_y_min, rzymax = _rel_zoom_y_max;
zoom_out(); zoom_out();
//draw(); // TODO: optimize here //draw(); // TODO: optimize here
delta_x *= plot_area_x_max - plot_area_x_min; delta_x *= plot_area_x_max - plot_area_x_min;
@ -355,7 +359,7 @@ namespace Gtk.CairoChart {
foreach (var s in series) { foreach (var s in series) {
if (!s.zoom_show) continue; if (!s.show) continue;
// carry // carry
switch (legend.position) { switch (legend.position) {
@ -554,7 +558,7 @@ namespace Gtk.CairoChart {
int nzoom_series_show = 0; int nzoom_series_show = 0;
for (var si = series.length - 1; si >=0; --si) { for (var si = series.length - 1; si >=0; --si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
++nzoom_series_show; ++nzoom_series_show;
if ( s.axis_x.position != series[0].axis_x.position if ( s.axis_x.position != series[0].axis_x.position
|| s.axis_x.zoom_min != series[0].axis_x.zoom_min || s.axis_x.zoom_min != series[0].axis_x.zoom_min
@ -575,7 +579,7 @@ namespace Gtk.CairoChart {
// Join and calc X-axes // Join and calc X-axes
for (var si = series.length - 1, nskip = 0; si >=0; --si) { for (var si = series.length - 1, nskip = 0; si >=0; --si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
if (nskip != 0) {--nskip; continue;} if (nskip != 0) {--nskip; continue;}
double max_rec_width = 0; double max_rec_height = 0; double max_rec_width = 0; double max_rec_height = 0;
calc_axis_rec_sizes (s.axis_x, out max_rec_width, out max_rec_height, true); calc_axis_rec_sizes (s.axis_x, out max_rec_width, out max_rec_height, true);
@ -585,11 +589,11 @@ namespace Gtk.CairoChart {
// join relative x-axes with non-intersect places // join relative x-axes with non-intersect places
for (int sj = si - 1; sj >= 0; --sj) { for (int sj = si - 1; sj >= 0; --sj) {
var s2 = series[sj]; var s2 = series[sj];
if (!s2.zoom_show) continue; if (!s2.show) continue;
bool has_intersection = false; bool has_intersection = false;
for (int sk = si; sk > sj; --sk) { for (int sk = si; sk > sj; --sk) {
var s3 = series[sk]; var s3 = series[sk];
if (!s3.zoom_show) continue; if (!s3.show) continue;
if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high) if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
|| s2.axis_x.position != s3.axis_x.position || s2.axis_x.position != s3.axis_x.position
|| s2.axis_x.type != s3.axis_x.type) { || s2.axis_x.type != s3.axis_x.type) {
@ -623,7 +627,7 @@ namespace Gtk.CairoChart {
// Join and calc Y-axes // Join and calc Y-axes
for (var si = series.length - 1, nskip = 0; si >=0; --si) { for (var si = series.length - 1, nskip = 0; si >=0; --si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
if (nskip != 0) {--nskip; continue;} if (nskip != 0) {--nskip; continue;}
double max_rec_width = 0; double max_rec_height = 0; double max_rec_width = 0; double max_rec_height = 0;
calc_axis_rec_sizes (s.axis_y, out max_rec_width, out max_rec_height, false); calc_axis_rec_sizes (s.axis_y, out max_rec_width, out max_rec_height, false);
@ -633,11 +637,11 @@ namespace Gtk.CairoChart {
// join relative x-axes with non-intersect places // join relative x-axes with non-intersect places
for (int sj = si - 1; sj >= 0; --sj) { for (int sj = si - 1; sj >= 0; --sj) {
var s2 = series[sj]; var s2 = series[sj];
if (!s2.zoom_show) continue; if (!s2.show) continue;
bool has_intersection = false; bool has_intersection = false;
for (int sk = si; sk > sj; --sk) { for (int sk = si; sk > sj; --sk) {
var s3 = series[sk]; var s3 = series[sk];
if (!s3.zoom_show) continue; if (!s3.show) continue;
if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high) if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
|| s2.axis_y.position != s3.axis_y.position || s2.axis_y.position != s3.axis_y.position
|| s2.axis_x.type != s3.axis_x.type) { || s2.axis_x.type != s3.axis_x.type) {
@ -678,7 +682,7 @@ namespace Gtk.CairoChart {
protected virtual void draw_horizontal_axis () { protected virtual void draw_horizontal_axis () {
for (var si = series.length - 1, nskip = 0; si >=0; --si) { for (var si = series.length - 1, nskip = 0; si >=0; --si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
if (common_x_axes && si != zoom_first_show) continue; if (common_x_axes && si != zoom_first_show) continue;
// 1. Detect max record width/height by axis_rec_npoints equally selected points using format. // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
double max_rec_width, max_rec_height; double max_rec_width, max_rec_height;
@ -829,11 +833,11 @@ namespace Gtk.CairoChart {
// join relative x-axes with non-intersect places // join relative x-axes with non-intersect places
for (int sj = si - 1; sj >= 0; --sj) { for (int sj = si - 1; sj >= 0; --sj) {
var s2 = series[sj]; var s2 = series[sj];
if (!s2.zoom_show) continue; if (!s2.show) continue;
bool has_intersection = false; bool has_intersection = false;
for (int sk = si; sk > sj; --sk) { for (int sk = si; sk > sj; --sk) {
var s3 = series[sk]; var s3 = series[sk];
if (!s3.zoom_show) continue; if (!s3.show) continue;
if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high) if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
|| s2.axis_x.position != s3.axis_x.position || s2.axis_x.position != s3.axis_x.position
|| s2.axis_x.type != s3.axis_x.type) { || s2.axis_x.type != s3.axis_x.type) {
@ -869,7 +873,7 @@ namespace Gtk.CairoChart {
protected virtual void draw_vertical_axis () { protected virtual void draw_vertical_axis () {
for (var si = series.length - 1, nskip = 0; si >=0; --si) { for (var si = series.length - 1, nskip = 0; si >=0; --si) {
var s = series[si]; var s = series[si];
if (!s.zoom_show) continue; if (!s.show) continue;
if (common_y_axes && si != zoom_first_show) continue; if (common_y_axes && si != zoom_first_show) continue;
// 1. Detect max record width/height by axis_rec_npoints equally selected points using format. // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
double max_rec_width, max_rec_height; double max_rec_width, max_rec_height;
@ -972,11 +976,11 @@ namespace Gtk.CairoChart {
// join relative x-axes with non-intersect places // join relative x-axes with non-intersect places
for (int sj = si - 1; sj >= 0; --sj) { for (int sj = si - 1; sj >= 0; --sj) {
var s2 = series[sj]; var s2 = series[sj];
if (!s2.zoom_show) continue; if (!s2.show) continue;
bool has_intersection = false; bool has_intersection = false;
for (int sk = si; sk > sj; --sk) { for (int sk = si; sk > sj; --sk) {
var s3 = series[sk]; var s3 = series[sk];
if (!s3.zoom_show) continue; if (!s3.show) continue;
if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high) if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
|| s2.axis_y.position != s3.axis_y.position) { || s2.axis_y.position != s3.axis_y.position) {
has_intersection = true; has_intersection = true;
@ -1027,16 +1031,21 @@ namespace Gtk.CairoChart {
return plot_area_y_max - (plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_low + (y - s.axis_y.zoom_min) return plot_area_y_max - (plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_low + (y - s.axis_y.zoom_min)
/ (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_high - s.place.zoom_y_low)); / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_high - s.place.zoom_y_low));
} }
protected virtual Point get_scr_point (Series s, Point p) {
return Point (get_scr_x(s, p.x), get_scr_y(s, p.y));
}
protected virtual Float128 get_real_x (Series s, double scr_x) { protected virtual Float128 get_real_x (Series s, double scr_x) {
return s.axis_x.zoom_min + ((scr_x - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) - s.place.zoom_x_low) return s.axis_x.zoom_min + ((scr_x - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) - s.place.zoom_x_low)
* (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_high - s.place.zoom_x_low); * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_high - s.place.zoom_x_low);
} }
protected virtual Float128 get_real_y (Series s, double scr_y) { protected virtual Float128 get_real_y (Series s, double scr_y) {
return s.axis_y.zoom_min + ((plot_area_y_max - scr_y) / (plot_area_y_max - plot_area_y_min) - s.place.zoom_y_low) return s.axis_y.zoom_min + ((plot_area_y_max - scr_y) / (plot_area_y_max - plot_area_y_min) - s.place.zoom_y_low)
* (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_high - s.place.zoom_y_low); * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_high - s.place.zoom_y_low);
} }
protected virtual Point get_real_point (Series s, Point p) {
return Point (get_real_x(s, p.x), get_real_y(s, p.y));
}
protected virtual bool point_in_rect (Point p, double x0, double x1, double y0, double y1) { protected virtual bool point_in_rect (Point p, double x0, double x1, double y0, double y1) {
if ( (x0 <= p.x <= x1 || x1 <= p.x <= x0) if ( (x0 <= p.x <= x1 || x1 <= p.x <= x0)
@ -1072,7 +1081,7 @@ namespace Gtk.CairoChart {
} }
delegate int PointComparator(Point a, Point b); delegate int PointComparator(Point a, Point b);
void sort_points(Point[] points, PointComparator compare) { void sort_points_delegate(Point[] points, PointComparator compare) {
for(var i = 0; i < points.length; ++i) { for(var i = 0; i < points.length; ++i) {
for(var j = i + 1; j < points.length; ++j) { for(var j = i + 1; j < points.length; ++j) {
if(compare(points[i], points[j]) > 0) { if(compare(points[i], points[j]) > 0) {
@ -1121,28 +1130,33 @@ namespace Gtk.CairoChart {
return false; return false;
} }
protected virtual void draw_series () { protected virtual Point[] sort_points (Series s) {
for (var si = 0; si < series.length; ++si) {
var s = series[si];
if (!s.zoom_show) continue;
if (s.points.length == 0) continue;
var points = s.points.copy(); var points = s.points.copy();
switch(s.sort) { switch(s.sort) {
case Series.Sort.BY_X: case Series.Sort.BY_X:
sort_points(points, (a, b) => { sort_points_delegate(points, (a, b) => {
if (a.x < b.x) return -1; if (a.x < b.x) return -1;
if (a.x > b.x) return 1; if (a.x > b.x) return 1;
return 0; return 0;
}); });
break; break;
case Series.Sort.BY_Y: case Series.Sort.BY_Y:
sort_points(points, (a, b) => { sort_points_delegate(points, (a, b) => {
if (a.y < b.y) return -1; if (a.y < b.y) return -1;
if (a.y > b.y) return 1; if (a.y > b.y) return 1;
return 0; return 0;
}); });
break; break;
} }
return points;
}
protected virtual void draw_series () {
for (var si = 0; si < series.length; ++si) {
var s = series[si];
if (!s.show) continue;
if (s.points.length == 0) continue;
var points = sort_points(s);
set_line_style(s.line_style); set_line_style(s.line_style);
// draw series line // draw series line
for (int i = 1; i < points.length; ++i) { for (int i = 1; i < points.length; ++i) {
@ -1164,8 +1178,193 @@ namespace Gtk.CairoChart {
} }
} }
protected List<Point?> cursors = new List<Point?> ();
protected Point active_cursor = Point ();
protected bool is_cursor_active = false;
public virtual void set_active_cursor (double x, double y, bool remove = false) {
active_cursor = Point (scr2rel_x(x), scr2rel_y(y));
is_cursor_active = true;
}
public virtual void add_active_cursor () {
cursors.append (active_cursor);
is_cursor_active = false;
}
public enum CursorOrientation {
VERTICAL = 0, // default
HORIZONTAL
}
public CursorOrientation cursors_orientation = CursorOrientation.VERTICAL;
public double cursor_max_distance = 32;
public virtual void remove_active_cursor () {
if (cursors.length() == 0) return;
var distance = width * width;
uint rm_indx = 0;
uint i = 0;
foreach (var c in cursors) {
double d = distance;
switch (cursors_orientation) {
case CursorOrientation.VERTICAL:
d = (c.x - active_cursor.x).abs();
break;
case CursorOrientation.HORIZONTAL:
d = (c.y - active_cursor.y).abs();
break;
default:
break;
}
if (distance > d) {
distance = d;
rm_indx = i;
}
++i;
}
if (distance < cursor_max_distance)
cursors.delete_link(cursors.nth(rm_indx));
}
// TODO:
protected virtual bool get_cursor_limits (Series s, Point cursor, out Point low, out Point high) {
var points = sort_points (s);
bool ret = false;
low.x = plot_area_x_min;
low.y = plot_area_y_min;
high.x = plot_area_x_max;
high.y = plot_area_y_max;
for (var i = 0; i + 1 < points.length; ++i) {
switch (cursors_orientation) {
case CursorOrientation.VERTICAL:
Float128 y = 0.0;
if (vcross(get_scr_point(s, s.points[i]), get_scr_point(s, s.points[i+1]), cursor.x, plot_area_y_min, plot_area_y_max, out y)) {
if (y < low.y) low.y = y;
if (y > high.y) high.y = y;
ret = true;
}
break;
case CursorOrientation.HORIZONTAL:
Float128 x = 0.0;
if (hcross(get_scr_point(s, s.points[i]), get_scr_point(s, s.points[i+1]), cursor.y, plot_area_x_min, plot_area_x_max, out x)) {
if (x < low.x) low.x = x;
if (x > high.x) high.x = x;
ret = true;
}
break;
}
}
if (common_x_axes) {
switch (s.axis_x.position) {
case Axis.Position.LOW: low.y = plot_area_y_max + s.axis_x.font_indent; break;
case Axis.Position.HIGH: high.y = plot_area_y_min - s.axis_x.font_indent; break;
case Axis.Position.BOTH:
low.y = plot_area_y_max + s.axis_x.font_indent;
high.y = plot_area_y_min - s.axis_x.font_indent;
break;
}
}
if (common_y_axes) {
switch (s.axis_y.position) {
case Axis.Position.LOW: low.x = plot_area_x_min - s.axis_y.font_indent; break;
case Axis.Position.HIGH: high.x = plot_area_x_max + s.axis_y.font_indent; break;
case Axis.Position.BOTH:
low.x = plot_area_x_min - s.axis_y.font_indent;
high.x = plot_area_x_max + s.axis_y.font_indent;
break;
}
}
return false;
}
protected virtual Float128 scr2rel_x (Float128 x) {
return (x - plot_area_x_min) / (plot_area_x_max - plot_area_x_min);
}
protected virtual Float128 scr2rel_y (Float128 y) {
return (y - plot_area_y_min) / (plot_area_y_max - plot_area_y_min);
}
protected virtual Point scr2rel_point (Point p) {
return Point (scr2rel_x(p.x), scr2rel_y(p.y));
}
protected virtual Float128 rel2scr_x(Float128 x) {
return plot_area_x_min + (plot_area_x_max - plot_area_x_min) * x;
}
protected virtual Float128 rel2scr_y(Float128 y) {
return plot_area_y_max - (plot_area_y_max - plot_area_y_min) * y;
}
protected virtual Point rel2scr_point (Point p) {
return Point (rel2scr_x(p.x), rel2scr_y(p.y));
}
public LineStyle cursor_line_style = LineStyle();
// TODO: // TODO:
protected virtual void draw_cursors () { protected virtual void draw_cursors () {
if (series.length == 0) return;
var all_cursors = cursors.copy();
all_cursors.append(active_cursor);
foreach (var c in all_cursors) {
switch (cursors_orientation) {
case CursorOrientation.VERTICAL:
if (c.x <= rel_zoom_x_min || c.x >= rel_zoom_x_max) continue; break;
case CursorOrientation.HORIZONTAL:
if (c.y <= rel_zoom_y_min || c.y >= rel_zoom_y_max) continue; break;
}
var low = Point(plot_area_x_max, plot_area_y_min); // low and high
var high = Point(plot_area_x_min, plot_area_y_max); // points of the cursor
foreach (var s in series) {
var l = Point(), h = Point();
if (get_cursor_limits (s, c, out l, out h)) {
if (l.x < low.x) low.x = l.x;
if (l.y < low.y) low.y = l.y;
if (h.x > high.x) high.x = h.x;
if (h.y > high.y) high.y = h.y;
}
}
switch (cursors_orientation) {
case CursorOrientation.VERTICAL:
// TODO: draw cursor line
set_line_style(cursor_line_style);
context.move_to (rel2scr_x(c.x), low.y);
context.line_to (rel2scr_x(c.x), high.y);
context.stroke();
// TODO: show values
if (common_x_axes)
// TODO: show only Y value
;
else
// TODO: show [X;Y]
;
break;
case CursorOrientation.HORIZONTAL:
// TODO: draw cursor line
set_line_style(cursor_line_style);
context.move_to (low.x, rel2scr_y(c.y));
context.line_to (high.x, rel2scr_y(c.y));
context.stroke();
// TODO: show values
if (common_y_axes)
// TODO: show only X value
;
else
// TODO: show [X;Y]
;
break;
}
}
} }
public Chart copy () { public Chart copy () {
@ -1193,10 +1392,10 @@ namespace Gtk.CairoChart {
chart.plot_area_x_min = this.plot_area_x_min; chart.plot_area_x_min = this.plot_area_x_min;
chart.plot_area_y_max = this.plot_area_y_max; chart.plot_area_y_max = this.plot_area_y_max;
chart.plot_area_y_min = this.plot_area_y_min; chart.plot_area_y_min = this.plot_area_y_min;
chart.rel_zoom_x_min = this.rel_zoom_x_min; chart._rel_zoom_x_min = this._rel_zoom_x_min;
chart.rel_zoom_x_max = this.rel_zoom_x_max; chart._rel_zoom_x_max = this._rel_zoom_x_max;
chart.rel_zoom_y_min = this.rel_zoom_y_min; chart._rel_zoom_y_min = this._rel_zoom_y_min;
chart.rel_zoom_y_max = this.rel_zoom_y_max; chart._rel_zoom_y_max = this._rel_zoom_y_max;
chart.selection_style = this.selection_style; chart.selection_style = this.selection_style;
chart.show_legend = this.show_legend; chart.show_legend = this.show_legend;
chart.title = this.title.copy().copy(); chart.title = this.title.copy().copy();

View File

@ -3,7 +3,7 @@ namespace Gtk.CairoChart {
Float128 x; Float128 x;
Float128 y; Float128 y;
public Point (Float128 x, Float128 y) { public Point (Float128 x = 0.0, Float128 y = 0.0) {
this.x = x; this.y = y; this.x = x; this.y = y;
} }
} }

View File

@ -49,7 +49,7 @@ namespace Gtk.CairoChart {
default = Color (0.0, 0.0, 0.0, 1.0); default = Color (0.0, 0.0, 0.0, 1.0);
} }
public bool zoom_show = true; public bool show = true;
public Series copy () { public Series copy () {
var series = new Series (); var series = new Series ();
@ -63,7 +63,7 @@ namespace Gtk.CairoChart {
series.points = this.points.copy(); series.points = this.points.copy();
series.sort = this.sort; series.sort = this.sort;
series.title = this.title.copy(); series.title = this.title.copy();
series.zoom_show = this.zoom_show; series.show = this.show;
return series; return series;
} }

View File

@ -203,6 +203,13 @@ bool point_in_chart (Chart chart, double x, double y) {
return true; return true;
} }
enum MouseState {
FREE = 0, // default
DRAW_SELECTION,
MOVING_CHART,
CURSOR_SELECTION
}
int main (string[] args) { int main (string[] args) {
init (ref args); init (ref args);
@ -346,9 +353,40 @@ int main (string[] args) {
} }
}); });
bool draw_selection = false;
/* var radio_button5 = new RadioButton.with_label (null, "Labels");
var radio_button6 = new RadioButton.with_label_from_widget (radio_button5, "Cursors");
radio_button5.toggled.connect ((button) => {
// TODO: set labels
if (button.get_active()) {
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
}
});
radio_button6.toggled.connect ((button) => {
// TODO: set cursors
if (button.get_active()) {
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
}
});*/
var radio_button7 = new RadioButton.with_label (null, "Vertical Cursors");
var radio_button8 = new RadioButton.with_label_from_widget (radio_button7, "Horizontal Cursors");
radio_button7.toggled.connect ((button) => {
if (button.get_active()) {
chart.cursors_orientation = Chart.CursorOrientation.VERTICAL;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
}
});
radio_button8.toggled.connect ((button) => {
if (button.get_active()) {
chart.cursors_orientation = Chart.CursorOrientation.HORIZONTAL;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
}
});
MouseState mouse_state = MouseState.FREE;
double sel_x0 = 0, sel_x1 = 0, sel_y0 = 0, sel_y1 = 0; double sel_x0 = 0, sel_x1 = 0, sel_y0 = 0, sel_y1 = 0;
bool moving_chart = false;
double mov_x0 = 0, mov_y0 = 0; double mov_x0 = 0, mov_y0 = 0;
da.draw.connect((context) => { da.draw.connect((context) => {
@ -363,7 +401,7 @@ int main (string[] args) {
/*var ret = */chart.draw(); /*var ret = */chart.draw();
// user's post draw operations here... // user's post draw operations here...
if (draw_selection) { if (mouse_state == MouseState.DRAW_SELECTION) {
context.set_source_rgba (0.5, 0.5, 0.5, 0.7); context.set_source_rgba (0.5, 0.5, 0.5, 0.7);
context.set_line_join(Cairo.LineJoin.MITER); context.set_line_join(Cairo.LineJoin.MITER);
context.set_line_cap(Cairo.LineCap.ROUND); context.set_line_cap(Cairo.LineCap.ROUND);
@ -381,18 +419,30 @@ int main (string[] args) {
da.button_press_event.connect((event) => { da.button_press_event.connect((event) => {
if (!point_in_chart(chart, event.x, event.y)) return true; if (!point_in_chart(chart, event.x, event.y)) return true;
if (event.button == 2) { switch (event.button) {
draw_selection = true; case 1: // start cursor position selection
if ((event.state & Gdk.ModifierType.SHIFT_MASK) != 0) { // remove cursor
chart.set_active_cursor (event.x, event.y, true);
} else { // add cursor
chart.set_active_cursor (event.x, event.y);
}
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
mouse_state = MouseState.CURSOR_SELECTION;
break;
case 2: // start zoom area selection
sel_x0 = sel_x1 = event.x; sel_x0 = sel_x1 = event.x;
sel_y0 = sel_y1 = event.y; sel_y0 = sel_y1 = event.y;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
} mouse_state = MouseState.DRAW_SELECTION;
break;
if (event.button == 3) { case 3: // start moving
moving_chart = true;
mov_x0 = event.x; mov_x0 = event.x;
mov_y0 = event.y; mov_y0 = event.y;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
mouse_state = MouseState.MOVING_CHART;
break;
} }
return true; // return ret; return true; // return ret;
@ -401,9 +451,20 @@ int main (string[] args) {
if (!point_in_chart(chart, event.x, event.y)) return true; if (!point_in_chart(chart, event.x, event.y)) return true;
//var ret = chart.button_release_event(event); switch (event.button) {
if (event.button == 2) { case 1: // start cursor position selection
draw_selection = false; if ((event.state & Gdk.ModifierType.SHIFT_MASK) != 0) { // remove cursor
chart.remove_active_cursor ();
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
mouse_state = MouseState.FREE;
} else { // add cursor
chart.add_active_cursor ();
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
mouse_state = MouseState.FREE;
}
break;
case 2:
sel_x1 = event.x; sel_x1 = event.x;
sel_y1 = event.y; sel_y1 = event.y;
if (sel_x1 > sel_x0 && sel_y1 > sel_y0) if (sel_x1 > sel_x0 && sel_y1 > sel_y0)
@ -411,11 +472,13 @@ int main (string[] args) {
else else
chart.zoom_out (); chart.zoom_out ();
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
} mouse_state = MouseState.FREE;
break;
if (event.button == 3) { case 3:
moving_chart = false;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
mouse_state = MouseState.FREE;
break;
} }
return true; // return ret; return true; // return ret;
@ -423,20 +486,25 @@ int main (string[] args) {
da.motion_notify_event.connect((event) => { da.motion_notify_event.connect((event) => {
if (!point_in_chart(chart, event.x, event.y)) return true; if (!point_in_chart(chart, event.x, event.y)) return true;
//var ret = chart.motion_notify_event(event); switch (mouse_state) {
case MouseState.DRAW_SELECTION:
if (draw_selection) {
sel_x1 = event.x; sel_x1 = event.x;
sel_y1 = event.y; sel_y1 = event.y;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
} break;
if (moving_chart) { case MouseState.MOVING_CHART:
var delta_x = event.x - mov_x0, delta_y = event.y - mov_y0; var delta_x = event.x - mov_x0, delta_y = event.y - mov_y0;
chart.move (delta_x, delta_y); chart.move (delta_x, delta_y);
mov_x0 = event.x; mov_x0 = event.x;
mov_y0 = event.y; mov_y0 = event.y;
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height()); da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
break;
case MouseState.CURSOR_SELECTION:
chart.set_active_cursor (event.x, event.y, true);
da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
break;
} }
return true; // return ret; return true; // return ret;
@ -462,6 +530,10 @@ int main (string[] args) {
vbox2.pack_start(radio_button2, false, false, 0); vbox2.pack_start(radio_button2, false, false, 0);
vbox2.pack_start(radio_button3, false, false, 0); vbox2.pack_start(radio_button3, false, false, 0);
vbox2.pack_start(radio_button4, false, false, 0); vbox2.pack_start(radio_button4, false, false, 0);
//vbox2.pack_start(radio_button5, false, false, 0);
//vbox2.pack_start(radio_button6, false, false, 0);
vbox2.pack_start(radio_button7, false, false, 0);
vbox2.pack_start(radio_button8, false, false, 0);
var hbox = new Box(Orientation.HORIZONTAL, 0); var hbox = new Box(Orientation.HORIZONTAL, 0);
hbox.pack_start(da, true, true, 0); hbox.pack_start(da, true, true, 0);