gtk / cairo-chart

SSH Git

To clone this repository:

git clone git@git.backbone.ws:gtk/cairo-chart.git

To push to this repository:

# Add a new remote
git remote add origin git@git.backbone.ws:gtk/cairo-chart.git

# Push the master branch to the newly added origin, and configure
# this remote and branch as the default:
git push -u origin master

# From now on you can push master to the "origin" remote with:
git push

Diffs from d114385 to 4fdde11

Commits

avatar Kolan Sh Math.vala created #1 912446f 7 days ago
avatar Kolan Sh Math.vala updated #2 3a57fdf 7 days ago
avatar Kolan Sh Math.vala updated #3 348fae7 7 days ago
avatar Kolan Sh In progress... 4fdde11 7 days ago

Summary

  • src/Chart.vala (187) -----------------------------------------------------------------------------------------------------------------------------------------------------------------++++++++++++++++++++++++++
  • src/Marker.vala (4) --++
  • src/Math.vala (151) +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • src/Text.vala (4) --++
216 216 context.stroke();
217 217 }
218 218
219 protected virtual Float128 calc_round_step (Float128 aver_step, bool date_time = false) {
220 Float128 step = 1.0;
221
222 if (aver_step > 1.0) {
223 if (date_time) while (step < aver_step) step *= 60;
224 if (date_time) while (step < aver_step) step *= 60;
225 if (date_time) while (step < aver_step) step *= 24;
226 while (step < aver_step) step *= 10;
227 if (step / 5 > aver_step) step /= 5;
228 while (step / 2 > aver_step) step /= 2;
229 } else if (aver_step > 0) {
230 while (step / 10 > aver_step) step /= 10;
231 if (step / 5 > aver_step) step /= 5;
232 while (step / 2 > aver_step) step /= 2;
233 }
234
235 return step;
236 }
237
238 219 public double plot_x_min = 0;
239 220 public double plot_x_max = 0;
240 221 public double plot_y_min = 0;
225 225 public bool joint_y { get; protected set; default = false; }
226 226 public Color joint_axis_color = Color (0, 0, 0, 1);
227 227
228 bool are_intersect (double a_min, double a_max, double b_min, double b_max) {
229 if ( a_min < a_max <= b_min < b_max
230 || b_min < b_max <= a_min < a_max)
231 return false;
232 return true;
233 }
234
235 228 protected virtual void set_vertical_axes_titles () {
236 229 for (var si = 0; si < series.length; ++si) {
237 230 var s = series[si];
279 279 for (int sk = si; sk > sj; --sk) {
280 280 var s3 = series[sk];
281 281 if (!s3.zoom_show) continue;
282 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
282 if (math.are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
283 283 || s2.axis_x.position != s3.axis_x.position
284 284 || s2.axis_x.type != s3.axis_x.type) {
285 285 has_intersection = true;
333 333 for (int sk = si; sk > sj; --sk) {
334 334 var s3 = series[sk];
335 335 if (!s3.zoom_show) continue;
336 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
336 if (math.are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
337 337 || s2.axis_y.position != s3.axis_y.position
338 338 || s2.axis_x.type != s3.axis_x.type) {
339 339 has_intersection = true;
370 370 }
371 371 }
372 372
373 bool point_belong (Float128 p, Float128 a, Float128 b) {
374 if (a > b) { Float128 tmp = a; a = b; b = tmp; }
375 if (a <= p <= b) return true;
376 return false;
377 }
378
379 373 protected virtual double compact_rec_x_pos (Series s, Float128 x, Text text) {
380 374 var sz = text.get_size(context);
381 375 return get_scr_x(s, x) - sz.width / 2.0
382 382 + sz.height * (y - (s.axis_y.zoom_min + s.axis_y.zoom_max) / 2.0) / (s.axis_y.zoom_max - s.axis_y.zoom_min);
383 383 }
384 384
385 protected CairoChart.Math math = new Math();
386
385 387 protected virtual void draw_horizontal_axis () {
386 388 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
387 389 var s = series[si];
398 398 long max_nrecs = (long) ((plot_x_max - plot_x_min) * (s.place.zoom_x_max - s.place.zoom_x_min) / max_rec_width);
399 399
400 400 // 3. Calculate grid step.
401 Float128 step = calc_round_step ((s.axis_x.zoom_max - s.axis_x.zoom_min) / max_nrecs, s.axis_x.type == Axis.Type.DATE_TIME);
401 Float128 step = math.calc_round_step ((s.axis_x.zoom_max - s.axis_x.zoom_min) / max_nrecs, s.axis_x.type == Axis.Type.DATE_TIME);
402 402 if (step > s.axis_x.zoom_max - s.axis_x.zoom_min)
403 403 step = s.axis_x.zoom_max - s.axis_x.zoom_min;
404 404
439 439 }
440 440
441 441 // 5. Draw records, update cur_{x,y}_{min,max}.
442 for (Float128 x = x_min, x_max = s.axis_x.zoom_max; point_belong (x, x_min, x_max); x += step) {
442 for (Float128 x = x_min, x_max = s.axis_x.zoom_max; math.point_belong (x, x_min, x_max); x += step) {
443 443 if (joint_x) set_source_rgba(joint_axis_color);
444 444 else set_source_rgba(s.axis_x.color);
445 445 string text = "", time_text = "";
521 521 for (int sk = si; sk > sj; --sk) {
522 522 var s3 = series[sk];
523 523 if (!s3.zoom_show) continue;
524 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
524 if (math.are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
525 525 || s2.axis_x.position != s3.axis_x.position
526 526 || s2.axis_x.type != s3.axis_x.type) {
527 527 has_intersection = true;
563 563 long max_nrecs = (long) ((plot_y_max - plot_y_min) * (s.place.zoom_y_max - s.place.zoom_y_min) / max_rec_height);
564 564
565 565 // 3. Calculate grid step.
566 Float128 step = calc_round_step ((s.axis_y.zoom_max - s.axis_y.zoom_min) / max_nrecs);
566 Float128 step = math.calc_round_step ((s.axis_y.zoom_max - s.axis_y.zoom_min) / max_nrecs);
567 567 if (step > s.axis_y.zoom_max - s.axis_y.zoom_min)
568 568 step = s.axis_y.zoom_max - s.axis_y.zoom_min;
569 569
608 608 }
609 609
610 610 // 5. Draw records, update cur_{x,y}_{min,max}.
611 for (Float128 y = y_min, y_max = s.axis_y.zoom_max; point_belong (y, y_min, y_max); y += step) {
611 for (Float128 y = y_min, y_max = s.axis_y.zoom_max; math.point_belong (y, y_min, y_max); y += step) {
612 612 if (joint_y) set_source_rgba(joint_axis_color);
613 613 else set_source_rgba(s.axis_y.color);
614 614 var text = s.axis_y.format.printf((LongDouble)y);
660 660 for (int sk = si; sk > sj; --sk) {
661 661 var s3 = series[sk];
662 662 if (!s3.zoom_show) continue;
663 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
663 if (math.are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
664 664 || s2.axis_y.position != s3.axis_y.position) {
665 665 has_intersection = true;
666 666 break;
706 706 return plot_y_max - (plot_y_max - plot_y_min) * (s.place.zoom_y_min + (y - s.axis_y.zoom_min)
707 707 / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_max - s.place.zoom_y_min));
708 708 }
709
709 710 protected virtual Point get_scr_point (Series s, Point p) {
710 711 return Point (get_scr_x(s, p.x), get_scr_y(s, p.y));
711 712 }
715 715 return s.axis_x.zoom_min + ((scr_x - plot_x_min) / (plot_x_max - plot_x_min) - s.place.zoom_x_min)
716 716 * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_max - s.place.zoom_x_min);
717 717 }
718
718 719 protected virtual Float128 get_real_y (Series s, double scr_y) {
719 720 return s.axis_y.zoom_min + ((plot_y_max - scr_y) / (plot_y_max - plot_y_min) - s.place.zoom_y_min)
720 721 * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_max - s.place.zoom_y_min);
721 722 }
723
722 724 protected virtual Point get_real_point (Series s, Point p) {
723 725 return Point (get_real_x(s, p.x), get_real_y(s, p.y));
724 726 }
725 727
726 protected virtual bool x_in_range (double x, double x0, double x1) {
727 if (x0 <= x <= x1 || x1 <= x <= x0)
728 return true;
729 return false;
730 }
731
732 protected virtual bool y_in_range (double y, double y0, double y1) {
733 if (y0 <= y <= y1 || y1 <= y <= y0)
734 return true;
735 return false;
736 }
737
738 728 protected virtual bool x_in_plot_area (double x) {
739 if (x_in_range(x, plot_x_min, plot_x_max))
729 if (math.x_in_range(x, plot_x_min, plot_x_max))
740 730 return true;
741 731 return false;
742 732 }
743 733
744 734 protected virtual bool y_in_plot_area (double y) {
745 if (y_in_range(y, plot_y_min, plot_y_max))
735 if (math.y_in_range(y, plot_y_min, plot_y_max))
746 736 return true;
747 737 return false;
748 738 }
749 739
750 protected virtual bool point_in_rect (Point p, double x0, double x1, double y0, double y1) {
751 if (x_in_range(p.x, x0, x1) && y_in_range(p.y, y0, y1))
752 return true;
753 return false;
754 }
755
756 740 protected virtual bool point_in_plot_area (Point p) {
757 if (point_in_rect (p, plot_x_min, plot_x_max, plot_y_min, plot_y_max))
741 if (math.point_in_rect (p, plot_x_min, plot_x_max, plot_y_min, plot_y_max))
758 742 return true;
759 743 return false;
760 744 }
761 745
762 protected virtual bool hcross (Point a1, Point a2, Float128 h_x1, Float128 h_x2, Float128 h_y, out Float128 x) {
763 x = 0;
764 if (a1.y == a2.y) return false;
765 if (a1.y >= h_y && a2.y >= h_y || a1.y <= h_y && a2.y <= h_y) return false;
766 x = a1.x + (a2.x - a1.x) * (h_y - a1.y) / (a2.y - a1.y);
767 if (h_x1 <= x <= h_x2 || h_x2 <= x <= h_x1)
768 return true;
769 return false;
770 }
771
772 protected virtual bool vcross (Point a1, Point a2, Float128 v_x, Float128 v_y1, Float128 v_y2, out Float128 y) {
773 y = 0;
774 if (a1.x == a2.x) return false;
775 if (a1.x >= v_x && a2.x >= v_x || a1.x <= v_x && a2.x <= v_x) return false;
776 y = a1.y + (a2.y - a1.y) * (v_x - a1.x) / (a2.x - a1.x);
777 if (v_y1 <= y <= v_y2 || v_y2 <= y <= v_y1)
778 return true;
779 return false;
780 }
781
782 delegate int PointComparator(Point a, Point b);
783 void sort_points_delegate(Point[] points, PointComparator compare) {
784 for(var i = 0; i < points.length; ++i) {
785 for(var j = i + 1; j < points.length; ++j) {
786 if(compare(points[i], points[j]) > 0) {
787 var tmp = points[i];
788 points[i] = points[j];
789 points[j] = tmp;
790 }
791 }
792 }
793 }
794
795 protected virtual bool cut_line (Point a, Point b, out Point c, out Point d) {
796 int ncross = 0;
797 Float128 x = 0, y = 0;
798 Point pc[4];
799 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_min, out x))
800 pc[ncross++] = Point(x, plot_y_min);
801 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_max, out x))
802 pc[ncross++] = Point(x, plot_y_max);
803 if (vcross(a, b, plot_x_min, plot_y_min, plot_y_max, out y))
804 pc[ncross++] = Point(plot_x_min, y);
805 if (vcross(a, b, plot_x_max, plot_y_min, plot_y_max, out y))
806 pc[ncross++] = Point(plot_x_max, y);
807 c = a;
808 d = b;
809 if (ncross == 0) {
810 if (point_in_plot_area (a) && point_in_plot_area (b))
811 return true;
812 return false;
813 }
814 if (ncross >= 2) {
815 c = pc[0]; d = pc[1];
816 return true;
817 }
818 if (ncross == 1) {
819 if (point_in_plot_area (a)) {
820 c = a;
821 d = pc[0];
822 return true;
823 } else if (point_in_plot_area (b)) {
824 c = b;
825 d = pc[0];
826 return true;
827 }
828 }
829 return false;
830 }
831
832 protected virtual Point[] sort_points (Series s, Series.Sort sort) {
833 var points = s.points;
834 switch(sort) {
835 case Series.Sort.BY_X:
836 sort_points_delegate(points, (a, b) => {
837 if (a.x < b.x) return -1;
838 if (a.x > b.x) return 1;
839 return 0;
840 });
841 break;
842 case Series.Sort.BY_Y:
843 sort_points_delegate(points, (a, b) => {
844 if (a.y < b.y) return -1;
845 if (a.y > b.y) return 1;
846 return 0;
847 });
848 break;
849 }
850 return points;
851 }
852
853 746 protected virtual void draw_series () {
854 747 for (var si = 0; si < series.length; ++si) {
855 748 var s = series[si];
856 749 if (!s.zoom_show) continue;
857 750 if (s.points.length == 0) continue;
858 var points = sort_points(s, s.sort);
751 var points = math.sort_points(s, s.sort);
859 752 s.line_style.set(this);
860 753 // draw series line
861 754 for (int i = 1; i < points.length; ++i) {
862 755 Point c, d;
863 if (cut_line (Point(get_scr_x(s, points[i - 1].x), get_scr_y(s, points[i - 1].y)),
864 Point(get_scr_x(s, points[i].x), get_scr_y(s, points[i].y)),
756 if (math.cut_line (Point(plot_x_min, plot_y_min), Point(plot_x_max, plot_y_max),
757 Point(get_scr_x(s, points[i - 1].x), get_scr_y(s, points[i - 1].y)),
758 Point(get_scr_x(s, points[i].x), get_scr_y(s, points[i].y)),
865 759 out c, out d)) {
866 760 context.move_to (c.x, c.y);
867 761 context.line_to (d.x, d.y);
882 882 Point[] points = {};
883 883 switch (cursor_style.orientation) {
884 884 case Cursor.Orientation.VERTICAL:
885 points = sort_points (s, s.sort);
885 points = math.sort_points (s, s.sort);
886 886 break;
887 887 case Cursor.Orientation.HORIZONTAL:
888 points = sort_points (s, s.sort);
888 points = math.sort_points (s, s.sort);
889 889 break;
890 890 }
891 891
893 893 switch (cursor_style.orientation) {
894 894 case Cursor.Orientation.VERTICAL:
895 895 Float128 y = 0.0;
896 if (vcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]), rel2scr_x(c.x),
897 plot_y_min, plot_y_max, out y)) {
896 if (math.vcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]), rel2scr_x(c.x),
897 plot_y_min, plot_y_max, out y)) {
898 898 var point = Point(get_real_x(s, rel2scr_x(c.x)), get_real_y(s, y));
899 899 Point size; bool show_x, show_date, show_time, show_y;
900 900 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
905 905 break;
906 906 case Cursor.Orientation.HORIZONTAL:
907 907 Float128 x = 0.0;
908 if (hcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]),
909 plot_x_min, plot_x_max, rel2scr_y(c.y), out x)) {
908 if (math.hcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]),
909 plot_x_min, plot_x_max, rel2scr_y(c.y), out x)) {
910 910 var point = Point(get_real_x(s, x), get_real_y(s, rel2scr_y(c.y)));
911 911 Point size; bool show_x, show_date, show_time, show_y;
912 912 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
33 33 break;
34 34
35 35 case Type.CIRCLE:
36 chart.context.arc (x, y, size / 2, 0, 2*Math.PI);
36 chart.context.arc (x, y, size / 2, 0, 2 * GLib.Math.PI);
37 37 chart.context.fill();
38 38 break;
39 39
52 52 break;
53 53
54 54 case Type.PRICLE_CIRCLE:
55 chart.context.arc (x, y, size / 2, 0, 2*Math.PI);
55 chart.context.arc (x, y, size / 2, 0, 2 * GLib.Math.PI);
56 56 chart.context.stroke();
57 57 break;
58 58
1 namespace CairoChart {
2
3 public class Math {
4
5 public virtual Float128 calc_round_step (Float128 aver_step, bool date_time = false) {
6 Float128 step = 1.0;
7
8 if (aver_step > 1.0) {
9 if (date_time) while (step < aver_step) step *= 60;
10 if (date_time) while (step < aver_step) step *= 60;
11 if (date_time) while (step < aver_step) step *= 24;
12 while (step < aver_step) step *= 10;
13 if (step / 5 > aver_step) step /= 5;
14 while (step / 2 > aver_step) step /= 2;
15 } else if (aver_step > 0) {
16 while (step / 10 > aver_step) step /= 10;
17 if (step / 5 > aver_step) step /= 5;
18 while (step / 2 > aver_step) step /= 2;
19 }
20
21 return step;
22 }
23
24 public virtual bool are_intersect (double a_min, double a_max, double b_min, double b_max) {
25 if ( a_min < a_max <= b_min < b_max
26 || b_min < b_max <= a_min < a_max)
27 return false;
28 return true;
29 }
30
31 public virtual bool point_belong (Float128 p, Float128 a, Float128 b) {
32 if (a > b) { Float128 tmp = a; a = b; b = tmp; }
33 if (a <= p <= b) return true;
34 return false;
35 }
36
37 public virtual bool x_in_range (double x, double x0, double x1) {
38 if (x0 <= x <= x1 || x1 <= x <= x0)
39 return true;
40 return false;
41 }
42
43 public virtual bool y_in_range (double y, double y0, double y1) {
44 if (y0 <= y <= y1 || y1 <= y <= y0)
45 return true;
46 return false;
47 }
48
49 public virtual bool point_in_rect (Point p, double x0, double x1, double y0, double y1) {
50 if (x_in_range(p.x, x0, x1) && y_in_range(p.y, y0, y1))
51 return true;
52 return false;
53 }
54
55 public virtual bool hcross (Point a1, Point a2, Float128 h_x1, Float128 h_x2, Float128 h_y, out Float128 x) {
56 x = 0;
57 if (a1.y == a2.y) return false;
58 if (a1.y >= h_y && a2.y >= h_y || a1.y <= h_y && a2.y <= h_y) return false;
59 x = a1.x + (a2.x - a1.x) * (h_y - a1.y) / (a2.y - a1.y);
60 if (h_x1 <= x <= h_x2 || h_x2 <= x <= h_x1)
61 return true;
62 return false;
63 }
64
65 public virtual bool vcross (Point a1, Point a2, Float128 v_x, Float128 v_y1, Float128 v_y2, out Float128 y) {
66 y = 0;
67 if (a1.x == a2.x) return false;
68 if (a1.x >= v_x && a2.x >= v_x || a1.x <= v_x && a2.x <= v_x) return false;
69 y = a1.y + (a2.y - a1.y) * (v_x - a1.x) / (a2.x - a1.x);
70 if (v_y1 <= y <= v_y2 || v_y2 <= y <= v_y1)
71 return true;
72 return false;
73 }
74
75 public delegate int PointComparator(Point a, Point b);
76
77 public virtual void sort_points_delegate(Point[] points, PointComparator compare) {
78 for(var i = 0; i < points.length; ++i) {
79 for(var j = i + 1; j < points.length; ++j) {
80 if(compare(points[i], points[j]) > 0) {
81 var tmp = points[i];
82 points[i] = points[j];
83 points[j] = tmp;
84 }
85 }
86 }
87 }
88
89 public virtual bool cut_line (Point p_min, Point p_max, Point a, Point b, out Point c, out Point d) {
90 int ncross = 0;
91 Float128 x = 0, y = 0;
92 Point pc[4];
93 if (hcross(a, b, p_min.x, p_max.x, p_min.y, out x))
94 pc[ncross++] = Point(x, p_min.y);
95 if (hcross(a, b, p_min.x, p_max.x, p_max.y, out x))
96 pc[ncross++] = Point(x, p_max.y);
97 if (vcross(a, b, p_min.x, p_min.y, p_max.y, out y))
98 pc[ncross++] = Point(p_min.x, y);
99 if (vcross(a, b, p_max.x, p_min.y, p_max.y, out y))
100 pc[ncross++] = Point(p_max.x, y);
101 c = a;
102 d = b;
103 if (ncross == 0) {
104 if ( point_in_rect (a, p_min.x, p_max.x, p_min.y, p_max.y)
105 && point_in_rect (b, p_min.x, p_max.x, p_min.y, p_max.y))
106 return true;
107 return false;
108 }
109 if (ncross >= 2) {
110 c = pc[0]; d = pc[1];
111 return true;
112 }
113 if (ncross == 1) {
114 if (point_in_rect (a, p_min.x, p_max.x, p_min.y, p_max.y)) {
115 c = a;
116 d = pc[0];
117 return true;
118 } else if (point_in_rect (b, p_min.x, p_max.x, p_min.y, p_max.y)) {
119 c = b;
120 d = pc[0];
121 return true;
122 }
123 }
124 return false;
125 }
126
127 public virtual Point[] sort_points (Series s, Series.Sort sort) {
128 var points = s.points;
129 switch(sort) {
130 case Series.Sort.BY_X:
131 sort_points_delegate(points, (a, b) => {
132 if (a.x < b.x) return -1;
133 if (a.x > b.x) return 1;
134 return 0;
135 });
136 break;
137 case Series.Sort.BY_Y:
138 sort_points_delegate(points, (a, b) => {
139 if (a.y < b.y) return -1;
140 if (a.y > b.y) return 1;
141 return 0;
142 });
143 break;
144 }
145 return points;
146 }
147
148
149 public Math () {}
150 }
151 }
58 58 style.weight);
59 59 context.set_font_size(style.size);
60 60 if (style.orientation == Font.Orientation.VERTICAL) {
61 context.rotate(- Math.PI / 2.0);
61 context.rotate(- GLib.Math.PI / 2.0);
62 62 context.show_text(text);
63 context.rotate(Math.PI / 2.0);
63 context.rotate(GLib.Math.PI / 2.0);
64 64 } else {
65 65 context.show_text(text);
66 66 }