CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
plot_view.cppm
Go to the documentation of this file.
1//
2// Created by castle on 8/11/24.
3//
4
5module;
7
9
10import cydui;
11
12import reflect;
13import fabric.linalg;
14import fabric.logging;
15
16import :series;
17
18using la = with_precision<double>;
19
20
21namespace charts {
22 COMPONENT(PlotView, {
23 const data_series_t* series;
24 la::scalar min_x = 0, max_x = 1;
25 la::scalar min_y = 0, max_y = 1;
26 bool show_data_points = true;
27 bool show_lines = true;
28 std::function<void(vg::fragment_t&, int x, int y)> data_point_fragment =
29 [](vg::fragment_t&, int, int) {};
30 std::function<void(vg::fragment_t&, int x1, int y1, int x2, int y2)> line_fragment =
31 [](vg::fragment_t&, int, int, int, int) {};
32 }) {
33 ON_REDRAW {
34 return {};
35 }
36
37 FRAGMENT {
38 const auto size = props.series->size();
39
40 bool out_of_frame = false;
41 auto data_point = (*props.series)[0];
42 auto prev = in_screen_space(data_point, $width, $height);
43 if (data_point[0] < props.min_x || data_point[0] > props.max_x ||
44 data_point[1] < props.min_y || data_point[1] > props.max_y) {
45 out_of_frame = true;
46 }
47 if (props.show_lines) {
48 for (std::size_t i = 1; i < size; ++i) {
49 data_point = (*props.series)[i];
50 const auto current = in_screen_space(data_point, $width, $height);
51 if ((current - prev).mag2() > 2) {
52 if (out_of_frame && (data_point[0] >= props.min_x && data_point[0] <= props.max_x &&
53 data_point[1] >= props.min_y && data_point[1] <= props.max_y)) {
54 out_of_frame = false;
55 }
56
57 if (!out_of_frame) {
58 props.line_fragment(fragment, prev[0], prev[1], current[0], current[1]);
59 }
60 prev = current;
61
62 if (!out_of_frame && (data_point[0] < props.min_x || data_point[0] > props.max_x ||
63 data_point[1] < props.min_y || data_point[1] > props.max_y)) {
64 out_of_frame = true;
65 }
66 }
67 }
68 }
69 if (props.show_data_points) {
70 for (std::size_t i = 0; i < size; ++i) {
71 data_point = (*props.series)[i];
72 auto current = in_screen_space(data_point, $width, $height);
73 if (data_point[0] >= props.min_x && data_point[0] <= props.max_x &&
74 data_point[1] >= props.min_y && data_point[1] <= props.max_y) {
75 props.data_point_fragment(fragment, current[0], current[1]);
76 }
77 }
78 }
79 }
80
81 private:
82 la::vec<2> in_screen_space(const la::vec<2>& point, auto $width, auto $height) const {
83 return {
84 la::scalar{$width.value} * ((point[0] - props.min_x) / (props.max_x - props.min_x)),
85 la::scalar{$height.value} -
86 la::scalar{$height.value} * ((point[1] - props.min_y) / (props.max_y - props.min_y)),
87 };
88 }
89 };
90
91 export template <class C>
92 struct view_map_t;
93
94 template <class C>
95 struct view_t {
96 explicit view_t(C& plot, const std::size_t index)
97 : ref_(&plot), index_(index) {
98 }
99
100 view_t(const view_t& rhl)
101 : ref_(rhl.ref_) {
102 index_ = rhl.index_;
103 show_data_points_ = rhl.show_data_points_;
104 show_line_ = rhl.show_line_;
105 }
106
107 view_t(view_t&& rhl) = delete;
108
109 C& show_data_points(const bool show_points) {
110 show_data_points_ = show_points;
111 return *ref_;
112 }
113
114 C& show_line(const bool show_) {
115 show_line_ = show_;
116 return *ref_;
117 }
118
119 private:
120 view_t& operator=(const view_t& rhl) {
121 index_ = rhl.index_;
122 show_data_points_ = rhl.show_data_points_;
123 show_line_ = rhl.show_line_;
124 return *this;
125 }
126 view_t& operator=(view_t&& rhl) = delete;
127
128 C& set_ref(C& ref) {
129 ref_ = &ref;
130 return *ref_;
131 }
132
133 bool exists_in_plot() const {
134 return ref_->props.series.size() > index_;
135 }
136
137 PlotView build_component(auto& x, auto& y, auto& w, auto& h) const {
138 PlotView pa {
139 {
140 .series = &ref_->props.series[index_],
141 .min_x = ref_->bottom_axis.min_value_,
142 .max_x = ref_->bottom_axis.max_value_,
143 .min_y = ref_->left_axis.min_value_,
144 .max_y = ref_->left_axis.max_value_,
145 .show_data_points = show_data_points_,
146 .show_lines = show_line_,
147 .data_point_fragment = [](vg::fragment_t& fragment, int x, int y) {
148 fragment.append(vg::circle { }
149 .cx(x).cy(y)
150 .r(3)
151 .fill("#FCAE1E"_color)
152 .stroke_width(1));
153 },
154 .line_fragment = [](vg::fragment_t& fragment, int x1, int y1, int x2, int y2) {
155 fragment.append(vg::line { }
156 .x1(x1).y1(y1)
157 .x2(x2).y2(y2)
158 .stroke("#FCAE1E"_color)
159 .stroke_width(2));
160 },
161 }
162 };
163 pa.x(x).y(y).width(w).height(h);
164 return pa;
165 }
166
167 friend C;
168 friend typename C::event_handler_t;
169 template <class> friend struct view_map_t;
170
171 private:
172 bool show_data_points_ = true;
173 bool show_line_ = true;
174
175 private:
176 C* ref_;
177 std::size_t index_;
178 };
179
180 template <class C>
182
183 template <class C>
184 struct view_map_t {
185 explicit view_map_t(C& plot)
186 : ref_(&plot) {
187 }
188
190 : ref_(rhl.ref_) {
191 for (auto &[index, view] : rhl.views_) {
192 views_.emplace(index, view);
193 views_.at(index).set_ref(*ref_);
194 }
195 }
196
197 view_map_t(view_map_t&& rhl) = delete;
198
199 view_t<C>& operator[](const std::size_t index) {
200 if (!views_.contains(index)) {
201 views_.emplace(index, view_t<C> {*ref_, index});
202 }
203 return views_.at(index);
204 }
205
206 private:
207 view_map_t& operator=(const view_map_t& rhl) {
208 for (auto &[index, view] : rhl.views_) {
209 views_.emplace(index, view);
210 views_.at(index).set_ref(*ref_);
211 }
212
213 return *this;
214 }
215 view_map_t& operator=(view_map_t&& rhl) = delete;
216
217 C& set_ref(C& ref) {
218 ref_ = &ref;
219 for (auto &[index, view] : views_) {
220 view.set_ref(*ref_);
221 }
222 return *ref_;
223 }
224
225 std::vector<PlotView> build_component(auto&& x, auto&& y, auto&& w, auto&& h) const {
226 std::vector<PlotView> result{};
227 for (const auto & [index, view] : views_) {
228 if (!view.exists_in_plot()) { continue; }
229 result.push_back(view.build_component(x, y, w, h));
230 }
231 return result;
232 }
233
234 friend C;
235 friend typename C::event_handler_t;
236
237 private:
238 std::map<std::size_t, view_t<C>> views_{};
239 private:
240 C* ref_;
241 };
242
243 export template <class C>
245
246}
#define FRAGMENT
#define COMPONENT(NAME,...)
#define ON_REDRAW
view_map_t(C &) -> view_map_t< C >
view_t(C &) -> view_t< C >
with_precision< double > la
Definition plot.cppm:19
view_map_t(view_map_t &&rhl)=delete
view_map_t(const view_map_t &rhl)
view_t< C > & operator[](const std::size_t index)
view_t(view_t &&rhl)=delete
C & show_line(const bool show_)
view_t(C &plot, const std::size_t index)
friend struct view_map_t
C & show_data_points(const bool show_points)
view_t(const view_t &rhl)
void append(T &&... _elements)
Definition fragment.cppm:31