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

Commit: #d67e2c2

Parent: #b75386a

In progress... Before Moscow 09.01

avatar Kolan Sh 7 days ago

Summary

  • src/Axis.vala (6) ---+++
  • src/Chart.vala (654) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • src/Color.vala (2) -+
  • src/Cursor.vala (23) +++++++++++++++++++++++
  • src/Font.vala (31) +++++++++++++++++++++++++++++++
  • src/FontStyle.vala (27) ---------------------------
  • src/Grid.vala (4) --++
  • src/Label.vala (12) ++++++++++++
  • src/LabelStyle.vala (8) --------
  • src/Legend.vala (198) ---+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • src/Line.vala (29) +++++++++++++++++++++++++++++
  • src/LineStyle.vala (24) ------------------------
  • src/Place.vala (68) ----------------------------------++++++++++++++++++++++++++++++++++
  • src/Point.vala (2) -+
  • src/Series.vala (6) ---+++
  • src/Text.vala (20) ----------++++++++++
  • src/cairo-chart-float128type.vapi (2) -+
  • test/ChartTest.vala (102) ---------------------------------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 // If one of axis:title or axis:min/max are different
3 3 // then draw separate axis for each/all series
4 4 // or specify series name near the axis
72 72 }
73 73 default = 2;
74 74 }
75 public FontStyle font_style = FontStyle ();
75 public Font.Style font_style = Font.Style ();
76 76 public Color color = Color ();
77 public LineStyle line_style = LineStyle ();
77 public Line.Style line_style = Line.Style ();
78 78 public double font_indent = 5;
79 79
80 80 public Axis copy () {
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2
2 3 public class Chart {
3 4
4 5 public double x_min = 0.0;
10 10 public Cairo.Context context = null;
11 11
12 12 public Color bg_color;
13 public bool show_legend = true;
14 13 public Text title = new Text ("Cairo Chart");
15 14 public Color border_color = Color(0, 0, 0, 0.3);
16 15
22 22 bg_color = Color (1, 1, 1);
23 23 }
24 24
25 protected double cur_x_min = 0.0;
26 protected double cur_x_max = 1.0;
27 protected double cur_y_min = 0.0;
28 protected double cur_y_max = 1.0;
25 public double cur_x_min = 0.0;
26 public double cur_x_max = 1.0;
27 public double cur_y_min = 0.0;
28 public double cur_y_max = 1.0;
29 29
30 public virtual void check_cur_values () {
30 protected virtual void check_cur_values () {
31 31 if (cur_x_min > cur_x_max)
32 32 cur_x_max = cur_x_min;
33 33 if (cur_y_min > cur_y_max)
48 48 draw_chart_title ();
49 49 check_cur_values ();
50 50
51 draw_legend ();
51 legend.draw (this);
52 52 check_cur_values ();
53 53
54 54 set_vertical_axes_titles ();
110 110 }
111 111 if (real_x0 >= s.axis_x.zoom_min) {
112 112 s.axis_x.zoom_min = real_x0;
113 s.place.zoom_x_low = 0.0;
113 s.place.zoom_x_min = 0.0;
114 114 } else {
115 s.place.zoom_x_low = (s.axis_x.zoom_min - real_x0) / (real_x1 - real_x0);
115 s.place.zoom_x_min = (s.axis_x.zoom_min - real_x0) / (real_x1 - real_x0);
116 116 }
117 117 if (real_x1 <= s.axis_x.zoom_max) {
118 118 s.axis_x.zoom_max = real_x1;
119 s.place.zoom_x_high = 1.0;
119 s.place.zoom_x_max = 1.0;
120 120 } else {
121 s.place.zoom_x_high = (s.axis_x.zoom_max - real_x0) / (real_x1 - real_x0);
121 s.place.zoom_x_max = (s.axis_x.zoom_max - real_x0) / (real_x1 - real_x0);
122 122 }
123 123 if (real_y1 >= s.axis_y.zoom_min) {
124 124 s.axis_y.zoom_min = real_y1;
125 s.place.zoom_y_low = 0.0;
125 s.place.zoom_y_min = 0.0;
126 126 } else {
127 s.place.zoom_y_low = (s.axis_y.zoom_min - real_y1) / (real_y0 - real_y1);
127 s.place.zoom_y_min = (s.axis_y.zoom_min - real_y1) / (real_y0 - real_y1);
128 128 }
129 129 if (real_y0 <= s.axis_y.zoom_max) {
130 130 s.axis_y.zoom_max = real_y0;
131 s.place.zoom_y_high = 1.0;
131 s.place.zoom_y_max = 1.0;
132 132 } else {
133 s.place.zoom_y_high = (s.axis_y.zoom_max - real_y1) / (real_y0 - real_y1);
133 s.place.zoom_y_max = (s.axis_y.zoom_max - real_y1) / (real_y0 - real_y1);
134 134 }
135 135 }
136 136
141 141 break;
142 142 }
143 143
144 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);
145 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);
146 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);
147 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);
144 var new_rel_zoom_x_min = rel_zoom_x_min + (x0 - plot_x_min) / (plot_x_max - plot_x_min) * (rel_zoom_x_max - rel_zoom_x_min);
145 var new_rel_zoom_x_max = rel_zoom_x_min + (x1 - plot_x_min) / (plot_x_max - plot_x_min) * (rel_zoom_x_max - rel_zoom_x_min);
146 var new_rel_zoom_y_min = rel_zoom_y_min + (y0 - plot_y_min) / (plot_y_max - plot_y_min) * (rel_zoom_y_max - rel_zoom_y_min);
147 var new_rel_zoom_y_max = rel_zoom_y_min + (y1 - plot_y_min) / (plot_y_max - plot_y_min) * (rel_zoom_y_max - rel_zoom_y_min);
148 148 rel_zoom_x_min = new_rel_zoom_x_min;
149 149 rel_zoom_x_max = new_rel_zoom_x_max;
150 150 rel_zoom_y_min = new_rel_zoom_y_min;
158 158 s.axis_x.zoom_max = s.axis_x.max;
159 159 s.axis_y.zoom_min = s.axis_y.min;
160 160 s.axis_y.zoom_max = s.axis_y.max;
161 s.place.zoom_x_low = s.place.x_low;
162 s.place.zoom_x_high = s.place.x_high;
163 s.place.zoom_y_low = s.place.y_low;
164 s.place.zoom_y_high = s.place.y_high;
161 s.place.zoom_x_min = s.place.x_min;
162 s.place.zoom_x_max = s.place.x_max;
163 s.place.zoom_y_min = s.place.y_min;
164 s.place.zoom_y_max = s.place.y_max;
165 165 }
166 166 rel_zoom_x_min = 0;
167 167 rel_zoom_x_max = 1;
172 172 }
173 173
174 174 public virtual void move (double delta_x, double delta_y) {
175 delta_x /= plot_area_x_max - plot_area_x_min; delta_x *= - 1.0;
176 delta_y /= plot_area_y_max - plot_area_y_min; delta_y *= - 1.0;
175 delta_x /= plot_x_max - plot_x_min; delta_x *= - 1.0;
176 delta_y /= plot_y_max - plot_y_min; delta_y *= - 1.0;
177 177 var rzxmin = rel_zoom_x_min, rzxmax = rel_zoom_x_max, rzymin = rel_zoom_y_min, rzymax = rel_zoom_y_max;
178 178 zoom_out();
179 179 //draw(); // TODO: optimize here
180 delta_x *= plot_area_x_max - plot_area_x_min;
181 delta_y *= plot_area_y_max - plot_area_y_min;
182 var xmin = plot_area_x_min + (plot_area_x_max - plot_area_x_min) * rzxmin;
183 var xmax = plot_area_x_min + (plot_area_x_max - plot_area_x_min) * rzxmax;
184 var ymin = plot_area_y_min + (plot_area_y_max - plot_area_y_min) * rzymin;
185 var ymax = plot_area_y_min + (plot_area_y_max - plot_area_y_min) * rzymax;
180 delta_x *= plot_x_max - plot_x_min;
181 delta_y *= plot_y_max - plot_y_min;
182 var xmin = plot_x_min + (plot_x_max - plot_x_min) * rzxmin;
183 var xmax = plot_x_min + (plot_x_max - plot_x_min) * rzxmax;
184 var ymin = plot_y_min + (plot_y_max - plot_y_min) * rzymin;
185 var ymax = plot_y_min + (plot_y_max - plot_y_min) * rzymax;
186 186
187 187 delta_x *= rzxmax - rzxmin; delta_y *= rzymax - rzymin;
188 188
189 if (xmin + delta_x < plot_area_x_min) delta_x = plot_area_x_min - xmin;
190 if (xmax + delta_x > plot_area_x_max) delta_x = plot_area_x_max - xmax;
191 if (ymin + delta_y < plot_area_y_min) delta_y = plot_area_y_min - ymin;
192 if (ymax + delta_y > plot_area_y_max) delta_y = plot_area_y_max - ymax;
189 if (xmin + delta_x < plot_x_min) delta_x = plot_x_min - xmin;
190 if (xmax + delta_x > plot_x_max) delta_x = plot_x_max - xmax;
191 if (ymin + delta_y < plot_y_min) delta_y = plot_y_min - ymin;
192 if (ymax + delta_y > plot_y_max) delta_y = plot_y_max - ymax;
193 193
194 194 zoom_in (xmin + delta_x, ymin + delta_y, xmax + delta_x, ymax + delta_y);
195 195 //draw(); // TODO: optimize here
196 196 }
197 197
198 protected double title_width = 0.0;
199 protected double title_height = 0.0;
198 public double title_width { get; protected set; default = 0.0; }
199 public double title_height { get; protected set; default = 0.0; }
200 200
201 public double title_vindent = 4;
201 public double title_indent = 4;
202 202
203 protected virtual void show_text(Text text) {
203 public virtual void show_text(Text text) {
204 204 context.select_font_face(text.style.family,
205 205 text.style.slant,
206 206 text.style.weight);
207 207 context.set_font_size(text.style.size);
208 if (text.style.orientation == FontOrient.VERTICAL) {
208 if (text.style.orientation == Font.Orientation.VERTICAL) {
209 209 context.rotate(- Math.PI / 2.0);
210 210 context.show_text(text.text);
211 211 context.rotate(Math.PI / 2.0);
215 215 }
216 216
217 217 protected virtual void draw_chart_title () {
218 var sz = title.size(context);
219 title_height = sz.height + (legend.position == Legend.Position.TOP ? title_vindent * 2 : title_vindent);
218 var sz = title.get_size(context);
219 title_height = sz.height + (legend.position == Legend.Position.TOP ? title_indent * 2 : title_indent);
220 220 cur_y_min += title_height;
221 221 set_source_rgba(title.color);
222 context.move_to (width/2 - sz.width/2, sz.height + title_vindent);
222 context.move_to (width/2 - sz.width/2, sz.height + title_indent);
223 223 show_text(title);
224 224 }
225 225
226 protected double legend_width = 0;
227 protected double legend_height = 0;
228
229 protected enum LegendProcessType {
230 CALC = 0, // default
231 DRAW
232 }
233
234 protected virtual void set_line_style (LineStyle style) {
226 public virtual void set_line_style (Line.Style style) {
235 227 set_source_rgba(style.color);
236 context.set_line_join(style.line_join);
237 context.set_line_cap(style.line_cap);
228 context.set_line_join(style.join);
229 context.set_line_cap(style.cap);
238 230 context.set_line_width(style.width);
239 231 context.set_dash(style.dashes, style.dash_offset);
240 232 }
241 233
242 protected virtual void draw_legend_rect (out double x0, out double y0) {
243 x0 = y0 = 0.0;
244 if (context != null) {
245 switch (legend.position) {
246 case Legend.Position.TOP:
247 x0 = (width - legend_width) / 2;
248 y0 = title_height;
249 break;
250
251 case Legend.Position.BOTTOM:
252 x0 = (width - legend_width) / 2;
253 y0 = height - legend_height;
254 break;
255
256 case Legend.Position.LEFT:
257 x0 = 0;
258 y0 = (height - legend_height) / 2;
259 break;
260
261 case Legend.Position.RIGHT:
262 x0 = width - legend_width;
263 y0 = (height - legend_height) / 2;
264 break;
265 }
266 set_source_rgba(legend.bg_color);
267 context.rectangle (x0, y0, legend_width, legend_height);
268 context.fill();
269 set_line_style(legend.border_style);
270 context.move_to (x0, y0);
271 context.rel_line_to (legend_width, 0);
272 context.rel_line_to (0, legend_height);
273 context.rel_line_to (-legend_width, 0);
274 context.rel_line_to (0, -legend_height);
275 context.stroke ();
276 }
277 }
278
279 public double legend_line_length = 30.0;
280 public double legend_text_hspace = 10.0;
281 public double legend_text_vspace = 2.0;
282 234 public double marker_size = 8.0;
283 235
284 protected virtual void draw_marker_at_pos (Series.MarkerType marker_type,
236 public virtual void draw_marker_at_pos (Series.MarkerType marker_type,
285 237 double x, double y) {
286 238 context.move_to (x, y);
287 239 switch (marker_type) {
277 277 }
278 278 }
279 279
280 double [] max_font_heights;
281 protected virtual void process_legend (LegendProcessType process_type) {
282 var legend_x0 = 0.0, legend_y0 = 0.0;
283 var heights_idx = 0;
284 var leg_width_sum = 0.0;
285 var leg_height_sum = 0.0;
286 double max_font_h = 0.0;
280 public Line.Style selection_style = Line.Style ();
287 281
288 // prepare
289 switch (process_type) {
290 case LegendProcessType.CALC:
291 legend_width = 0.0;
292 legend_height = 0.0;
293 max_font_heights = {};
294 heights_idx = 0;
295 break;
296 case LegendProcessType.DRAW:
297 draw_legend_rect(out legend_x0, out legend_y0);
298 break;
299 }
300
301 foreach (var s in series) {
302
303 if (!s.zoom_show) continue;
304
305 var title_sz = s.title.size(context);
306
307 // carry
308 switch (legend.position) {
309 case Legend.Position.TOP:
310 case Legend.Position.BOTTOM:
311 var ser_title_width = title_sz.width + legend_line_length;
312 if (leg_width_sum + (leg_width_sum == 0 ? 0 : legend_text_hspace) + ser_title_width > width) { // carry
313 leg_height_sum += max_font_h;
314 switch (process_type) {
315 case LegendProcessType.CALC:
316 max_font_heights += max_font_h;
317 legend_width = double.max(legend_width, leg_width_sum);
318 break;
319 case LegendProcessType.DRAW:
320 heights_idx++;
321 break;
322 }
323 leg_width_sum = 0.0;
324 max_font_h = 0;
325 }
326 break;
327 }
328
329 switch (process_type) {
330 case LegendProcessType.DRAW:
331 var x = legend_x0 + leg_width_sum + (leg_width_sum == 0.0 ? 0.0 : legend_text_hspace);
332 var y = legend_y0 + leg_height_sum + max_font_heights[heights_idx];
333
334 // series title
335 context.move_to (x + legend_line_length, y);
336 set_source_rgba (s.title.color);
337 show_text(s.title);
338
339 // series line style
340 context.move_to (x, y - title_sz.height / 2);
341 set_line_style(s.line_style);
342 context.rel_line_to (legend_line_length, 0);
343 context.stroke();
344 draw_marker_at_pos (s.marker_type, x + legend_line_length / 2, y - title_sz.height / 2);
345 break;
346 }
347
348 switch (legend.position) {
349 case Legend.Position.TOP:
350 case Legend.Position.BOTTOM:
351 var ser_title_width = title_sz.width + legend_line_length;
352 leg_width_sum += (leg_width_sum == 0 ? 0 : legend_text_hspace) + ser_title_width;
353 max_font_h = double.max (max_font_h, title_sz.height) + (leg_height_sum != 0 ? legend_text_vspace : 0);
354 break;
355
356 case Legend.Position.LEFT:
357 case Legend.Position.RIGHT:
358 switch (process_type) {
359 case LegendProcessType.CALC:
360 max_font_heights += title_sz.height + (leg_height_sum != 0 ? legend_text_vspace : 0);
361 legend_width = double.max (legend_width, title_sz.width + legend_line_length);
362 break;
363 case LegendProcessType.DRAW:
364 heights_idx++;
365 break;
366 }
367 leg_height_sum += title_sz.height + (leg_height_sum != 0 ? legend_text_vspace : 0);
368 break;
369 }
370 }
371
372 // TOP, BOTTOM
373 switch (legend.position) {
374 case Legend.Position.TOP:
375 case Legend.Position.BOTTOM:
376 if (leg_width_sum != 0) {
377 leg_height_sum += max_font_h;
378 switch (process_type) {
379 case LegendProcessType.CALC:
380 max_font_heights += max_font_h;
381 legend_width = double.max(legend_width, leg_width_sum);
382 break;
383 }
384 }
385 break;
386 }
387
388 switch (process_type) {
389 case LegendProcessType.CALC:
390 legend_height = leg_height_sum;
391 switch (legend.position) {
392 case Legend.Position.TOP:
393 cur_y_min += legend_height;
394 break;
395 case Legend.Position.BOTTOM:
396 cur_y_max -= legend_height;
397 break;
398 case Legend.Position.LEFT:
399 cur_x_min += legend_width;
400 break;
401 case Legend.Position.RIGHT:
402 cur_x_max -= legend_width;
403 break;
404 }
405 break;
406 }
407 }
408
409 protected virtual void draw_legend () {
410 process_legend (LegendProcessType.CALC);
411 process_legend (LegendProcessType.DRAW);
412 }
413
414 public LineStyle selection_style = LineStyle ();
415
416 282 public virtual void draw_selection (double x0, double y0, double x1, double y1) {
417 283 set_line_style (selection_style);
418 284 context.rectangle (x0, y0, x1 - x0, y1 - y0);
294 294 switch (axis.type) {
295 295 case Axis.Type.NUMBERS:
296 296 var text = new Text (axis.format.printf((LongDouble)x) + (is_horizontal ? "_" : ""), axis.font_style);
297 var sz = text.size(context);
297 var sz = text.get_size(context);
298 298 max_rec_width = double.max (max_rec_width, sz.width);
299 299 max_rec_height = double.max (max_rec_height, sz.height);
300 300 break;
305 305 var h = 0.0;
306 306 if (axis.date_format != "") {
307 307 var text = new Text (date + (is_horizontal ? "_" : ""), axis.font_style);
308 var sz = text.size(context);
308 var sz = text.get_size(context);
309 309 max_rec_width = double.max (max_rec_width, sz.width);
310 310 h = sz.height;
311 311 }
312 312 if (axis.time_format != "") {
313 313 var text = new Text (time + (is_horizontal ? "_" : ""), axis.font_style);
314 var sz = text.size(context);
314 var sz = text.get_size(context);
315 315 max_rec_width = double.max (max_rec_width, sz.width);
316 316 h += sz.height;
317 317 }
340 340 return step;
341 341 }
342 342
343 public double plot_area_x_min = 0;
344 public double plot_area_x_max = 0;
345 public double plot_area_y_min = 0;
346 public double plot_area_y_max = 0;
343 public double plot_x_min = 0;
344 public double plot_x_max = 0;
345 public double plot_y_min = 0;
346 public double plot_y_max = 0;
347 347
348 public bool common_x_axes { get; protected set; default = false; }
349 public bool common_y_axes { get; protected set; default = false; }
350 public Color common_axis_color = Color (0, 0, 0, 1);
348 public bool joint_x { get; protected set; default = false; }
349 public bool joint_y { get; protected set; default = false; }
350 public Color joint_axis_color = Color (0, 0, 0, 1);
351 351
352 352 bool are_intersect (double a_min, double a_max, double b_min, double b_max) {
353 353 if ( a_min < a_max <= b_min < b_max
359 359 protected virtual void set_vertical_axes_titles () {
360 360 for (var si = 0; si < series.length; ++si) {
361 361 var s = series[si];
362 s.axis_y.title.style.orientation = FontOrient.VERTICAL;
362 s.axis_y.title.style.orientation = Font.Orientation.VERTICAL;
363 363 }
364 364 }
365 365
366 366 protected virtual void calc_plot_area () {
367 plot_area_x_min = cur_x_min + legend.indent;
368 plot_area_x_max = cur_x_max - legend.indent;
369 plot_area_y_min = cur_y_min + legend.indent;
370 plot_area_y_max = cur_y_max - legend.indent;
367 plot_x_min = cur_x_min + legend.indent;
368 plot_x_max = cur_x_max - legend.indent;
369 plot_y_min = cur_y_min + legend.indent;
370 plot_y_max = cur_y_max - legend.indent;
371 371
372 // Check for common axes
373 common_x_axes = common_y_axes = true;
372 // Check for joint axes
373 joint_x = joint_y = true;
374 374 int nzoom_series_show = 0;
375 375 for (var si = series.length - 1; si >=0; --si) {
376 376 var s = series[si];
379 379 if ( s.axis_x.position != series[0].axis_x.position
380 380 || s.axis_x.zoom_min != series[0].axis_x.zoom_min
381 381 || s.axis_x.zoom_max != series[0].axis_x.zoom_max
382 || s.place.zoom_x_low != series[0].place.zoom_x_low
383 || s.place.zoom_x_high != series[0].place.zoom_x_high
382 || s.place.zoom_x_min != series[0].place.zoom_x_min
383 || s.place.zoom_x_max != series[0].place.zoom_x_max
384 384 || s.axis_x.type != series[0].axis_x.type)
385 common_x_axes = false;
385 joint_x = false;
386 386 if ( s.axis_y.position != series[0].axis_y.position
387 387 || s.axis_y.zoom_min != series[0].axis_y.zoom_min
388 388 || s.axis_y.zoom_max != series[0].axis_y.zoom_max
389 || s.place.zoom_y_low != series[0].place.zoom_y_low
390 || s.place.zoom_y_high != series[0].place.zoom_y_high)
391 common_y_axes = false;
389 || s.place.zoom_y_min != series[0].place.zoom_y_min
390 || s.place.zoom_y_max != series[0].place.zoom_y_max)
391 joint_y = false;
392 392 }
393 if (nzoom_series_show == 1) common_x_axes = common_y_axes = false;
393 if (nzoom_series_show == 1) joint_x = joint_y = false;
394 394
395 395 // Join and calc X-axes
396 396 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
410 410 for (int sk = si; sk > sj; --sk) {
411 411 var s3 = series[sk];
412 412 if (!s3.zoom_show) continue;
413 if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
413 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
414 414 || s2.axis_x.position != s3.axis_x.position
415 415 || s2.axis_x.type != s3.axis_x.type) {
416 416 has_intersection = true;
431 431 }
432 432 }
433 433
434 // for 4.2. Cursor values for common X axis
435 if (common_x_axes && si == zoom_first_show && cursors_orientation == CursorOrientation.VERTICAL && cursors_crossings.length != 0) {
434 // for 4.2. Cursor values for joint X axis
435 if (joint_x && si == zoom_first_show && cursor_style.orientation == Cursor.Orientation.VERTICAL && cursors_crossings.length != 0) {
436 436 switch (s.axis_x.position) {
437 case Axis.Position.LOW: plot_area_y_max -= max_rec_height + s.axis_x.font_indent; break;
438 case Axis.Position.HIGH: plot_area_y_min += max_rec_height + s.axis_x.font_indent; break;
437 case Axis.Position.LOW: plot_y_max -= max_rec_height + s.axis_x.font_indent; break;
438 case Axis.Position.HIGH: plot_y_min += max_rec_height + s.axis_x.font_indent; break;
439 439 }
440 440 }
441 441
442 if (!common_x_axes || si == zoom_first_show)
442 if (!joint_x || si == zoom_first_show)
443 443 switch (s.axis_x.position) {
444 case Axis.Position.LOW: plot_area_y_max -= max_rec_height + max_font_indent + max_axis_font_height; break;
445 case Axis.Position.HIGH: plot_area_y_min += max_rec_height + max_font_indent + max_axis_font_height; break;
444 case Axis.Position.LOW: plot_y_max -= max_rec_height + max_font_indent + max_axis_font_height; break;
445 case Axis.Position.HIGH: plot_y_min += max_rec_height + max_font_indent + max_axis_font_height; break;
446 446 }
447 447 }
448 448
464 464 for (int sk = si; sk > sj; --sk) {
465 465 var s3 = series[sk];
466 466 if (!s3.zoom_show) continue;
467 if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
467 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
468 468 || s2.axis_y.position != s3.axis_y.position
469 469 || s2.axis_x.type != s3.axis_x.type) {
470 470 has_intersection = true;
485 485 }
486 486 }
487 487
488 // for 4.2. Cursor values for common Y axis
489 if (common_y_axes && si == zoom_first_show && cursors_orientation == CursorOrientation.HORIZONTAL && cursors_crossings.length != 0) {
488 // for 4.2. Cursor values for joint Y axis
489 if (joint_y && si == zoom_first_show && cursor_style.orientation == Cursor.Orientation.HORIZONTAL && cursors_crossings.length != 0) {
490 490 switch (s.axis_y.position) {
491 case Axis.Position.LOW: plot_area_x_min += max_rec_width + s.axis_y.font_indent; break;
492 case Axis.Position.HIGH: plot_area_x_max -= max_rec_width + s.axis_y.font_indent; break;
491 case Axis.Position.LOW: plot_x_min += max_rec_width + s.axis_y.font_indent; break;
492 case Axis.Position.HIGH: plot_x_max -= max_rec_width + s.axis_y.font_indent; break;
493 493 }
494 494 }
495 495
496 if (!common_y_axes || si == zoom_first_show)
496 if (!joint_y || si == zoom_first_show)
497 497 switch (s.axis_y.position) {
498 case Axis.Position.LOW: plot_area_x_min += max_rec_width + max_font_indent + max_axis_font_width; break;
499 case Axis.Position.HIGH: plot_area_x_max -= max_rec_width + max_font_indent + max_axis_font_width; break;
498 case Axis.Position.LOW: plot_x_min += max_rec_width + max_font_indent + max_axis_font_width; break;
499 case Axis.Position.HIGH: plot_x_max -= max_rec_width + max_font_indent + max_axis_font_width; break;
500 500 }
501 501 }
502 502 }
508 508 }
509 509
510 510 protected virtual double compact_rec_x_pos (Series s, Float128 x, Text text) {
511 var sz = text.size(context);
511 var sz = text.get_size(context);
512 512 return get_scr_x(s, x) - sz.width / 2.0
513 513 - sz.width * (x - (s.axis_x.zoom_min + s.axis_x.zoom_max) / 2.0) / (s.axis_x.zoom_max - s.axis_x.zoom_min);
514 514 }
515 515
516 516 protected virtual double compact_rec_y_pos (Series s, Float128 y, Text text) {
517 var sz = text.size(context);
517 var sz = text.get_size(context);
518 518 return get_scr_y(s, y) + sz.height / 2.0
519 519 + 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);
520 520 }
532 532 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
533 533 var s = series[si];
534 534 if (!s.zoom_show) continue;
535 if (common_x_axes && si != zoom_first_show) continue;
535 if (joint_x && si != zoom_first_show) continue;
536 536
537 537 // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
538 538 double max_rec_width, max_rec_height;
539 539 calc_axis_rec_sizes (s.axis_x, out max_rec_width, out max_rec_height, true);
540 540
541 541 // 2. Calculate maximal available number of records, take into account the space width.
542 long max_nrecs = (long) ((plot_area_x_max - plot_area_x_min) * (s.place.zoom_x_high - s.place.zoom_x_low) / max_rec_width);
542 long max_nrecs = (long) ((plot_x_max - plot_x_min) * (s.place.zoom_x_max - s.place.zoom_x_min) / max_rec_width);
543 543
544 544 // 3. Calculate grid step.
545 545 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);
558 558 }
559 559 if (x_min < s.axis_x.zoom_min) x_min += step;
560 560
561 // 4.2. Cursor values for common X axis
562 if (common_x_axes && cursors_orientation == CursorOrientation.VERTICAL && cursors_crossings.length != 0) {
561 // 4.2. Cursor values for joint X axis
562 if (joint_x && cursor_style.orientation == Cursor.Orientation.VERTICAL && cursors_crossings.length != 0) {
563 563 switch (s.axis_x.position) {
564 564 case Axis.Position.LOW: cur_y_max -= max_rec_height + s.axis_x.font_indent; break;
565 565 case Axis.Position.HIGH: cur_y_min += max_rec_height + s.axis_x.font_indent; break;
566 566 }
567 567 }
568 568
569 var sz = s.axis_x.title.size(context);
569 var sz = s.axis_x.title.get_size(context);
570 570
571 571 // 4.5. Draw Axis title
572 572 if (s.axis_x.title.text != "") {
573 var scr_x = plot_area_x_min + (plot_area_x_max - plot_area_x_min) * (s.place.zoom_x_low + s.place.zoom_x_high) / 2.0;
573 var scr_x = plot_x_min + (plot_x_max - plot_x_min) * (s.place.zoom_x_min + s.place.zoom_x_max) / 2.0;
574 574 double scr_y = 0.0;
575 575 switch (s.axis_x.position) {
576 576 case Axis.Position.LOW: scr_y = cur_y_max - s.axis_x.font_indent; break;
578 578 }
579 579 context.move_to(scr_x - sz.width / 2.0, scr_y);
580 580 set_source_rgba(s.axis_x.color);
581 if (common_x_axes) set_source_rgba(common_axis_color);
581 if (joint_x) set_source_rgba(joint_axis_color);
582 582 show_text(s.axis_x.title);
583 583 }
584 584
585 585 // 5. Draw records, update cur_{x,y}_{min,max}.
586 586 for (Float128 x = x_min, x_max = s.axis_x.zoom_max; point_belong (x, x_min, x_max); x += step) {
587 if (common_x_axes) set_source_rgba(common_axis_color);
587 if (joint_x) set_source_rgba(joint_axis_color);
588 588 else set_source_rgba(s.axis_x.color);
589 589 string text = "", time_text = "";
590 590 switch (s.axis_x.type) {
614 614 if (s.axis_x.time_format != "") show_text(time_text_t);
615 615 break;
616 616 }
617 // 6. Draw grid lines to the s.place.zoom_y_low.
617 // 6. Draw grid lines to the s.place.zoom_y_min.
618 618 var line_style = s.grid.line_style;
619 if (common_x_axes) line_style.color = Color(0, 0, 0, 0.5);
619 if (joint_x) line_style.color = Color(0, 0, 0, 0.5);
620 620 set_line_style(line_style);
621 621 double y = cur_y_max - max_rec_height - s.axis_x.font_indent - (s.axis_x.title.text == "" ? 0 : sz.height + s.axis_x.font_indent);
622 622 context.move_to (scr_x, y);
623 if (common_x_axes)
624 context.line_to (scr_x, plot_area_y_min);
623 if (joint_x)
624 context.line_to (scr_x, plot_y_min);
625 625 else
626 context.line_to (scr_x, double.min (y, plot_area_y_max - (plot_area_y_max - plot_area_y_min) * s.place.zoom_y_high));
626 context.line_to (scr_x, double.min (y, plot_y_max - (plot_y_max - plot_y_min) * s.place.zoom_y_max));
627 627 break;
628 628 case Axis.Position.HIGH:
629 629 var print_y = cur_y_min + max_rec_height + s.axis_x.font_indent + (s.axis_x.title.text == "" ? 0 : sz.height + s.axis_x.font_indent);
642 642 if (s.axis_x.time_format != "") show_text(time_text_t);
643 643 break;
644 644 }
645 // 6. Draw grid lines to the s.place.zoom_y_high.
645 // 6. Draw grid lines to the s.place.zoom_y_max.
646 646 var line_style = s.grid.line_style;
647 if (common_x_axes) line_style.color = Color(0, 0, 0, 0.5);
647 if (joint_x) line_style.color = Color(0, 0, 0, 0.5);
648 648 set_line_style(line_style);
649 649 double y = cur_y_min + max_rec_height + s.axis_x.font_indent + (s.axis_x.title.text == "" ? 0 : sz.height + s.axis_x.font_indent);
650 650 context.move_to (scr_x, y);
651 if (common_x_axes)
652 context.line_to (scr_x, plot_area_y_max);
651 if (joint_x)
652 context.line_to (scr_x, plot_y_max);
653 653 else
654 context.line_to (scr_x, double.max (y, plot_area_y_max - (plot_area_y_max - plot_area_y_min) * s.place.zoom_y_low));
654 context.line_to (scr_x, double.max (y, plot_y_max - (plot_y_max - plot_y_min) * s.place.zoom_y_min));
655 655 break;
656 656 }
657 657 }
665 665 for (int sk = si; sk > sj; --sk) {
666 666 var s3 = series[sk];
667 667 if (!s3.zoom_show) continue;
668 if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
668 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
669 669 || s2.axis_x.position != s3.axis_x.position
670 670 || s2.axis_x.type != s3.axis_x.type) {
671 671 has_intersection = true;
698 698 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
699 699 var s = series[si];
700 700 if (!s.zoom_show) continue;
701 if (common_y_axes && si != zoom_first_show) continue;
701 if (joint_y && si != zoom_first_show) continue;
702 702 // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
703 703 double max_rec_width, max_rec_height;
704 704 calc_axis_rec_sizes (s.axis_y, out max_rec_width, out max_rec_height, false);
705 705
706 706 // 2. Calculate maximal available number of records, take into account the space width.
707 long max_nrecs = (long) ((plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_high - s.place.zoom_y_low) / max_rec_height);
707 long max_nrecs = (long) ((plot_y_max - plot_y_min) * (s.place.zoom_y_max - s.place.zoom_y_min) / max_rec_height);
708 708
709 709 // 3. Calculate grid step.
710 710 Float128 step = calc_round_step ((s.axis_y.zoom_max - s.axis_y.zoom_min) / max_nrecs);
723 723 }
724 724 if (y_min < s.axis_y.zoom_min) y_min += step;
725 725
726 // 4.2. Cursor values for common Y axis
727 if (common_y_axes && cursors_orientation == CursorOrientation.HORIZONTAL && cursors_crossings.length != 0) {
726 // 4.2. Cursor values for joint Y axis
727 if (joint_y && cursor_style.orientation == Cursor.Orientation.HORIZONTAL && cursors_crossings.length != 0) {
728 728 switch (s.axis_y.position) {
729 729 case Axis.Position.LOW: cur_x_min += max_rec_width + s.axis_y.font_indent; break;
730 730 case Axis.Position.HIGH: cur_x_max -= max_rec_width + s.axis_y.font_indent; break;
731 731 }
732 732 }
733 733
734 var sz = s.axis_y.title.size(context);
734 var sz = s.axis_y.title.get_size(context);
735 735
736 736 // 4.5. Draw Axis title
737 737 if (s.axis_y.title.text != "") {
738 var scr_y = plot_area_y_max - (plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_low + s.place.zoom_y_high) / 2.0;
738 var scr_y = plot_y_max - (plot_y_max - plot_y_min) * (s.place.zoom_y_min + s.place.zoom_y_max) / 2.0;
739 739 switch (s.axis_y.position) {
740 740 case Axis.Position.LOW:
741 741 var scr_x = cur_x_min + s.axis_y.font_indent + sz.width;
747 747 break;
748 748 }
749 749 set_source_rgba(s.axis_y.color);
750 if (common_y_axes) set_source_rgba(common_axis_color);
750 if (joint_y) set_source_rgba(joint_axis_color);
751 751 show_text(s.axis_y.title);
752 752 }
753 753
754 754 // 5. Draw records, update cur_{x,y}_{min,max}.
755 755 for (Float128 y = y_min, y_max = s.axis_y.zoom_max; point_belong (y, y_min, y_max); y += step) {
756 if (common_y_axes) set_source_rgba(common_axis_color);
756 if (joint_y) set_source_rgba(joint_axis_color);
757 757 else set_source_rgba(s.axis_y.color);
758 758 var text = s.axis_y.format.printf((LongDouble)y);
759 759 var scr_y = get_scr_y (s, y);
760 760 var text_t = new Text(text, s.axis_y.font_style, s.axis_y.color);
761 var text_sz = text_t.size(context);
761 var text_sz = text_t.get_size(context);
762 762 switch (s.axis_y.position) {
763 763 case Axis.Position.LOW:
764 764 context.move_to (cur_x_min + max_rec_width - text_sz.width + s.axis_y.font_indent
765 765 + (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent),
766 766 compact_rec_y_pos (s, y, text_t));
767 767 show_text(text_t);
768 // 6. Draw grid lines to the s.place.zoom_x_low.
768 // 6. Draw grid lines to the s.place.zoom_x_min.
769 769 var line_style = s.grid.line_style;
770 if (common_y_axes) line_style.color = Color(0, 0, 0, 0.5);
770 if (joint_y) line_style.color = Color(0, 0, 0, 0.5);
771 771 set_line_style(line_style);
772 772 double x = cur_x_min + max_rec_width + s.axis_y.font_indent + (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent);
773 773 context.move_to (x, scr_y);
774 if (common_y_axes)
775 context.line_to (plot_area_x_max, scr_y);
774 if (joint_y)
775 context.line_to (plot_x_max, scr_y);
776 776 else
777 context.line_to (double.max (x, plot_area_x_min + (plot_area_x_max - plot_area_x_min) * s.place.zoom_x_high), scr_y);
777 context.line_to (double.max (x, plot_x_min + (plot_x_max - plot_x_min) * s.place.zoom_x_max), scr_y);
778 778 break;
779 779 case Axis.Position.HIGH:
780 780 context.move_to (cur_x_max - text_sz.width - s.axis_y.font_indent
781 781 - (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent),
782 782 compact_rec_y_pos (s, y, text_t));
783 783 show_text(text_t);
784 // 6. Draw grid lines to the s.place.zoom_x_high.
784 // 6. Draw grid lines to the s.place.zoom_x_max.
785 785 var line_style = s.grid.line_style;
786 if (common_y_axes) line_style.color = Color(0, 0, 0, 0.5);
786 if (joint_y) line_style.color = Color(0, 0, 0, 0.5);
787 787 set_line_style(line_style);
788 788 double x = cur_x_max - max_rec_width - s.axis_y.font_indent - (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent);
789 789 context.move_to (x, scr_y);
790 if (common_y_axes)
791 context.line_to (plot_area_x_min, scr_y);
790 if (joint_y)
791 context.line_to (plot_x_min, scr_y);
792 792 else
793 context.line_to (double.min (x, plot_area_x_min + (plot_area_x_max - plot_area_x_min) * s.place.zoom_x_low), scr_y);
793 context.line_to (double.min (x, plot_x_min + (plot_x_max - plot_x_min) * s.place.zoom_x_min), scr_y);
794 794 break;
795 795 }
796 796 }
804 804 for (int sk = si; sk > sj; --sk) {
805 805 var s3 = series[sk];
806 806 if (!s3.zoom_show) continue;
807 if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
807 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
808 808 || s2.axis_y.position != s3.axis_y.position) {
809 809 has_intersection = true;
810 810 break;
833 833 protected virtual void draw_plot_area_border () {
834 834 set_source_rgba (border_color);
835 835 context.set_dash(null, 0);
836 context.move_to (plot_area_x_min, plot_area_y_min);
837 context.line_to (plot_area_x_min, plot_area_y_max);
838 context.line_to (plot_area_x_max, plot_area_y_max);
839 context.line_to (plot_area_x_max, plot_area_y_min);
840 context.line_to (plot_area_x_min, plot_area_y_min);
836 context.move_to (plot_x_min, plot_y_min);
837 context.line_to (plot_x_min, plot_y_max);
838 context.line_to (plot_x_max, plot_y_max);
839 context.line_to (plot_x_max, plot_y_min);
840 context.line_to (plot_x_min, plot_y_min);
841 841 context.stroke ();
842 842 }
843 843
844 844 protected virtual double get_scr_x (Series s, Float128 x) {
845 return plot_area_x_min + (plot_area_x_max - plot_area_x_min) * (s.place.zoom_x_low + (x - s.axis_x.zoom_min)
846 / (s.axis_x.zoom_max - s.axis_x.zoom_min) * (s.place.zoom_x_high - s.place.zoom_x_low));
845 return plot_x_min + (plot_x_max - plot_x_min) * (s.place.zoom_x_min + (x - s.axis_x.zoom_min)
846 / (s.axis_x.zoom_max - s.axis_x.zoom_min) * (s.place.zoom_x_max - s.place.zoom_x_min));
847 847 }
848 848
849 849 protected virtual double get_scr_y (Series s, Float128 y) {
850 return plot_area_y_max - (plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_low + (y - s.axis_y.zoom_min)
851 / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_high - s.place.zoom_y_low));
850 return plot_y_max - (plot_y_max - plot_y_min) * (s.place.zoom_y_min + (y - s.axis_y.zoom_min)
851 / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_max - s.place.zoom_y_min));
852 852 }
853 853 protected virtual Point get_scr_point (Series s, Point p) {
854 854 return Point (get_scr_x(s, p.x), get_scr_y(s, p.y));
855 855 }
856 856
857 857 protected virtual Float128 get_real_x (Series s, double scr_x) {
858 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)
859 * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_high - s.place.zoom_x_low);
858 return s.axis_x.zoom_min + ((scr_x - plot_x_min) / (plot_x_max - plot_x_min) - s.place.zoom_x_min)
859 * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_max - s.place.zoom_x_min);
860 860 }
861 861 protected virtual Float128 get_real_y (Series s, double scr_y) {
862 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)
863 * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_high - s.place.zoom_y_low);
862 return s.axis_y.zoom_min + ((plot_y_max - scr_y) / (plot_y_max - plot_y_min) - s.place.zoom_y_min)
863 * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_max - s.place.zoom_y_min);
864 864 }
865 865 protected virtual Point get_real_point (Series s, Point p) {
866 866 return Point (get_real_x(s, p.x), get_real_y(s, p.y));
879 879 }
880 880
881 881 protected virtual bool x_in_plot_area (double x) {
882 if (x_in_range(x, plot_area_x_min, plot_area_x_max))
882 if (x_in_range(x, plot_x_min, plot_x_max))
883 883 return true;
884 884 return false;
885 885 }
886 886
887 887 protected virtual bool y_in_plot_area (double y) {
888 if (y_in_range(y, plot_area_y_min, plot_area_y_max))
888 if (y_in_range(y, plot_y_min, plot_y_max))
889 889 return true;
890 890 return false;
891 891 }
897 897 }
898 898
899 899 protected virtual bool point_in_plot_area (Point p) {
900 if (point_in_rect (p, plot_area_x_min, plot_area_x_max, plot_area_y_min, plot_area_y_max))
900 if (point_in_rect (p, plot_x_min, plot_x_max, plot_y_min, plot_y_max))
901 901 return true;
902 902 return false;
903 903 }
939 939 int ncross = 0;
940 940 Float128 x = 0, y = 0;
941 941 Point pc[4];
942 if (hcross(a, b, plot_area_x_min, plot_area_x_max, plot_area_y_min, out x))
943 pc[ncross++] = Point(x, plot_area_y_min);
944 if (hcross(a, b, plot_area_x_min, plot_area_x_max, plot_area_y_max, out x))
945 pc[ncross++] = Point(x, plot_area_y_max);
946 if (vcross(a, b, plot_area_x_min, plot_area_y_min, plot_area_y_max, out y))
947 pc[ncross++] = Point(plot_area_x_min, y);
948 if (vcross(a, b, plot_area_x_max, plot_area_y_min, plot_area_y_max, out y))
949 pc[ncross++] = Point(plot_area_x_max, y);
942 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_min, out x))
943 pc[ncross++] = Point(x, plot_y_min);
944 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_max, out x))
945 pc[ncross++] = Point(x, plot_y_max);
946 if (vcross(a, b, plot_x_min, plot_y_min, plot_y_max, out y))
947 pc[ncross++] = Point(plot_x_min, y);
948 if (vcross(a, b, plot_x_max, plot_y_min, plot_y_max, out y))
949 pc[ncross++] = Point(plot_x_max, y);
950 950 c = a;
951 951 d = b;
952 952 if (ncross == 0) {
1034 1034 is_cursor_active = false;
1035 1035 }
1036 1036
1037 public enum CursorOrientation {
1038 VERTICAL = 0, // default
1039 HORIZONTAL
1040 }
1037 public Cursor.Style cursor_style = Cursor.Style();
1041 1038
1042 public CursorOrientation cursors_orientation = CursorOrientation.VERTICAL;
1043
1044 public double cursor_max_rm_distance = 32;
1045
1046 1039 public virtual void remove_active_cursor () {
1047 1040 if (cursors.length() == 0) return;
1048 1041 var distance = width * width;
1043 1043 uint i = 0;
1044 1044 foreach (var c in cursors) {
1045 1045 double d = distance;
1046 switch (cursors_orientation) {
1047 case CursorOrientation.VERTICAL:
1046 switch (cursor_style.orientation) {
1047 case Cursor.Orientation.VERTICAL:
1048 1048 d = (rel2scr_x(c.x) - rel2scr_x(active_cursor.x)).abs();
1049 1049 break;
1050 case CursorOrientation.HORIZONTAL:
1050 case Cursor.Orientation.HORIZONTAL:
1051 1051 d = (rel2scr_y(c.y) - rel2scr_y(active_cursor.y)).abs();
1052 1052 break;
1053 1053 }
1057 1057 }
1058 1058 ++i;
1059 1059 }
1060 if (distance < cursor_max_rm_distance)
1060 if (distance < cursor_style.select_distance)
1061 1061 cursors.delete_link(cursors.nth(rm_indx));
1062 1062 is_cursor_active = false;
1063 1063 }
1064 1064
1065 1065 protected virtual Float128 scr2rel_x (Float128 x) {
1066 return rel_zoom_x_min + (x - plot_area_x_min) / (plot_area_x_max - plot_area_x_min) * (rel_zoom_x_max - rel_zoom_x_min);
1066 return rel_zoom_x_min + (x - plot_x_min) / (plot_x_max - plot_x_min) * (rel_zoom_x_max - rel_zoom_x_min);
1067 1067 }
1068 1068 protected virtual Float128 scr2rel_y (Float128 y) {
1069 return rel_zoom_y_max - (plot_area_y_max - y) / (plot_area_y_max - plot_area_y_min) * (rel_zoom_y_max - rel_zoom_y_min);
1069 return rel_zoom_y_max - (plot_y_max - y) / (plot_y_max - plot_y_min) * (rel_zoom_y_max - rel_zoom_y_min);
1070 1070 }
1071 1071 protected virtual Point scr2rel_point (Point p) {
1072 1072 return Point (scr2rel_x(p.x), scr2rel_y(p.y));
1073 1073 }
1074 1074
1075 1075 protected virtual Float128 rel2scr_x(Float128 x) {
1076 return plot_area_x_min + (plot_area_x_max - plot_area_x_min) * (x - rel_zoom_x_min) / (rel_zoom_x_max - rel_zoom_x_min);
1076 return plot_x_min + (plot_x_max - plot_x_min) * (x - rel_zoom_x_min) / (rel_zoom_x_max - rel_zoom_x_min);
1077 1077 }
1078 1078
1079 1079 protected virtual Float128 rel2scr_y(Float128 y) {
1080 return plot_area_y_min + (plot_area_y_max - plot_area_y_min) * (y - rel_zoom_y_min) / (rel_zoom_y_max - rel_zoom_y_min);
1080 return plot_y_min + (plot_y_max - plot_y_min) * (y - rel_zoom_y_min) / (rel_zoom_y_max - rel_zoom_y_min);
1081 1081 }
1082 1082
1083 1083 protected virtual Point rel2scr_point (Point p) {
1084 1084 return Point (rel2scr_x(p.x), rel2scr_y(p.y));
1085 1085 }
1086 1086
1087 public LineStyle cursor_line_style = LineStyle(Color(0.2, 0.2, 0.2, 0.8));
1088
1089 1087 protected struct CursorCross {
1090 1088 uint series_index;
1091 1089 Point point;
1116 1116
1117 1117 for (var ci = 0, max_ci = all_cursors.length(); ci < max_ci; ++ci) {
1118 1118 var c = all_cursors.nth_data(ci);
1119 switch (cursors_orientation) {
1120 case CursorOrientation.VERTICAL:
1119 switch (cursor_style.orientation) {
1120 case Cursor.Orientation.VERTICAL:
1121 1121 if (c.x <= rel_zoom_x_min || c.x >= rel_zoom_x_max) continue; break;
1122 case CursorOrientation.HORIZONTAL:
1122 case Cursor.Orientation.HORIZONTAL:
1123 1123 if (c.y <= rel_zoom_y_min || c.y >= rel_zoom_y_max) continue; break;
1124 1124 }
1125 1125
1129 1129 if (!s.zoom_show) continue;
1130 1130
1131 1131 Point[] points = {};
1132 switch (cursors_orientation) {
1133 case CursorOrientation.VERTICAL:
1132 switch (cursor_style.orientation) {
1133 case Cursor.Orientation.VERTICAL:
1134 1134 points = sort_points (s, s.sort);
1135 1135 break;
1136 case CursorOrientation.HORIZONTAL:
1136 case Cursor.Orientation.HORIZONTAL:
1137 1137 points = sort_points (s, s.sort);
1138 1138 break;
1139 1139 }
1140 1140
1141 1141 for (var i = 0; i + 1 < points.length; ++i) {
1142 switch (cursors_orientation) {
1143 case CursorOrientation.VERTICAL:
1142 switch (cursor_style.orientation) {
1143 case Cursor.Orientation.VERTICAL:
1144 1144 Float128 y = 0.0;
1145 1145 if (vcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]), rel2scr_x(c.x),
1146 plot_area_y_min, plot_area_y_max, out y)) {
1146 plot_y_min, plot_y_max, out y)) {
1147 1147 var point = Point(get_real_x(s, rel2scr_x(c.x)), get_real_y(s, y));
1148 1148 Point size; bool show_x, show_date, show_time, show_y;
1149 1149 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
1152 1152 crossings += cc;
1153 1153 }
1154 1154 break;
1155 case CursorOrientation.HORIZONTAL:
1155 case Cursor.Orientation.HORIZONTAL:
1156 1156 Float128 x = 0.0;
1157 1157 if (hcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]),
1158 plot_area_x_min, plot_area_x_max, rel2scr_y(c.y), out x)) {
1158 plot_x_min, plot_x_max, rel2scr_y(c.y), out x)) {
1159 1159 var point = Point(get_real_x(s, x), get_real_y(s, rel2scr_y(c.y)));
1160 1160 Point size; bool show_x, show_date, show_time, show_y;
1161 1161 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
1190 1190 protected virtual void cross_what_to_show (Series s, out bool show_x, out bool show_time,
1191 1191 out bool show_date, out bool show_y) {
1192 1192 show_x = show_time = show_date = show_y = false;
1193 switch (cursors_orientation) {
1194 case CursorOrientation.VERTICAL:
1193 switch (cursor_style.orientation) {
1194 case Cursor.Orientation.VERTICAL:
1195 1195 show_y = true;
1196 if (!common_x_axes)
1196 if (!joint_x)
1197 1197 switch (s.axis_x.type) {
1198 1198 case Axis.Type.NUMBERS: show_x = true; break;
1199 1199 case Axis.Type.DATE_TIME:
1202 1202 break;
1203 1203 }
1204 1204 break;
1205 case CursorOrientation.HORIZONTAL:
1206 if (!common_y_axes) show_y = true;
1205 case Cursor.Orientation.HORIZONTAL:
1206 if (!joint_y) show_y = true;
1207 1207 switch (s.axis_x.type) {
1208 1208 case Axis.Type.NUMBERS: show_x = true; break;
1209 1209 case Axis.Type.DATE_TIME:
1228 1228 var x_t = new Text (s.axis_x.format.printf((LongDouble)p.x), s.axis_x.font_style, s.axis_x.color);
1229 1229 var y_t = new Text (s.axis_y.format.printf((LongDouble)p.y), s.axis_y.font_style, s.axis_y.color);
1230 1230 double h_x = 0.0, h_y = 0.0;
1231 if (show_x) { var sz = x_t.size(context); size.x = sz.width; h_x = sz.height; }
1232 if (show_date) { var sz = date_t.size(context); size.x = sz.width; h_x = sz.height; }
1233 if (show_time) { var sz = time_t.size(context); size.x = double.max(size.x, sz.width); h_x += sz.height; }
1234 if (show_y) { var sz = y_t.size(context); size.x += sz.width; h_y = sz.height; }
1231 if (show_x) { var sz = x_t.get_size(context); size.x = sz.width; h_x = sz.height; }
1232 if (show_date) { var sz = date_t.get_size(context); size.x = sz.width; h_x = sz.height; }
1233 if (show_time) { var sz = time_t.get_size(context); size.x = double.max(size.x, sz.width); h_x += sz.height; }
1234 if (show_y) { var sz = y_t.get_size(context); size.x += sz.width; h_y = sz.height; }
1235 1235 if ((show_x || show_date || show_time) && show_y) size.x += double.max(s.axis_x.font_indent, s.axis_y.font_indent);
1236 1236 if (show_date && show_time) h_x += s.axis_x.font_indent;
1237 1237 size.y = double.max (h_x, h_y);
1244 1244 calc_cursors_value_positions();
1245 1245
1246 1246 for (var cci = 0, max_cci = cursors_crossings.length; cci < max_cci; ++cci) {
1247 var low = Point(plot_area_x_max, plot_area_y_max); // low and high
1248 var high = Point(plot_area_x_min, plot_area_y_min); // points of the cursor
1247 var low = Point(plot_x_max, plot_y_max); // low and high
1248 var high = Point(plot_x_min, plot_y_min); // points of the cursor
1249 1249 unowned CursorCross[] ccs = cursors_crossings[cci].crossings;
1250 set_line_style(cursor_line_style);
1250 set_line_style(cursor_style.line_style);
1251 1251 for (var ci = 0, max_ci = ccs.length; ci < max_ci; ++ci) {
1252 1252 var si = ccs[ci].series_index;
1253 1253 var s = series[si];
1259 1259 if (scrx > high.x) high.x = scrx;
1260 1260 if (scry > high.y) high.y = scry;
1261 1261
1262 if (common_x_axes) {
1262 if (joint_x) {
1263 1263 switch (s.axis_x.position) {
1264 case Axis.Position.LOW: high.y = plot_area_y_max + s.axis_x.font_indent; break;
1265 case Axis.Position.HIGH: low.y = plot_area_y_min - s.axis_x.font_indent; break;
1264 case Axis.Position.LOW: high.y = plot_y_max + s.axis_x.font_indent; break;
1265 case Axis.Position.HIGH: low.y = plot_y_min - s.axis_x.font_indent; break;
1266 1266 case Axis.Position.BOTH:
1267 high.y = plot_area_y_max + s.axis_x.font_indent;
1268 low.y = plot_area_y_min - s.axis_x.font_indent;
1267 high.y = plot_y_max + s.axis_x.font_indent;
1268 low.y = plot_y_min - s.axis_x.font_indent;
1269 1269 break;
1270 1270 }
1271 1271 }
1272 if (common_y_axes) {
1272 if (joint_y) {
1273 1273 switch (s.axis_y.position) {
1274 case Axis.Position.LOW: low.x = plot_area_x_min - s.axis_y.font_indent; break;
1275 case Axis.Position.HIGH: high.x = plot_area_x_max + s.axis_y.font_indent; break;
1274 case Axis.Position.LOW: low.x = plot_x_min - s.axis_y.font_indent; break;
1275 case Axis.Position.HIGH: high.x = plot_x_max + s.axis_y.font_indent; break;
1276 1276 case Axis.Position.BOTH:
1277 low.x = plot_area_x_min - s.axis_y.font_indent;
1278 high.x = plot_area_x_max + s.axis_y.font_indent;
1277 low.x = plot_x_min - s.axis_y.font_indent;
1278 high.x = plot_x_max + s.axis_y.font_indent;
1279 1279 break;
1280 1280 }
1281 1281 }
1286 1286
1287 1287 var c = all_cursors.nth_data(cursors_crossings[cci].cursor_index);
1288 1288
1289 switch (cursors_orientation) {
1290 case CursorOrientation.VERTICAL:
1289 switch (cursor_style.orientation) {
1290 case Cursor.Orientation.VERTICAL:
1291 1291 if (low.y > high.y) continue;
1292 1292 context.move_to (rel2scr_x(c.x), low.y);
1293 1293 context.line_to (rel2scr_x(c.x), high.y);
1294 1294
1295 // show common X value
1296 if (common_x_axes) {
1295 // show joint X value
1296 if (joint_x) {
1297 1297 var s = series[zoom_first_show];
1298 1298 var x = get_real_x(s, rel2scr_x(c.x));
1299 1299 string text = "", time_text = "";
1308 1308 break;
1309 1309 }
1310 1310 var text_t = new Text(text, s.axis_x.font_style, s.axis_x.color);
1311 var sz = text_t.size(context);
1311 var sz = text_t.get_size(context);
1312 1312 var time_text_t = new Text(time_text, s.axis_x.font_style, s.axis_x.color);
1313 1313 var print_y = 0.0;
1314 1314 switch (s.axis_x.position) {
1315 1315 case Axis.Position.LOW: print_y = y_min + height - s.axis_x.font_indent
1316 - (legend.position == Legend.Position.BOTTOM ? legend_height : 0);
1316 - (legend.position == Legend.Position.BOTTOM ? legend.height : 0);
1317 1317 break;
1318 1318 case Axis.Position.HIGH: print_y = y_min + title_height + s.axis_x.font_indent
1319 + (legend.position == Legend.Position.TOP ? legend_height : 0);
1319 + (legend.position == Legend.Position.TOP ? legend.height : 0);
1320 1320 switch (s.axis_x.type) {
1321 1321 case Axis.Type.NUMBERS:
1322 1322 print_y += sz.height;
1345 1345 }
1346 1346 }
1347 1347 break;
1348 case CursorOrientation.HORIZONTAL:
1348 case Cursor.Orientation.HORIZONTAL:
1349 1349 if (low.x > high.x) continue;
1350 1350 context.move_to (low.x, rel2scr_y(c.y));
1351 1351 context.line_to (high.x, rel2scr_y(c.y));
1352 1352
1353 // show common Y value
1354 if (common_y_axes) {
1353 // show joint Y value
1354 if (joint_y) {
1355 1355 var s = series[zoom_first_show];
1356 1356 var y = get_real_y(s, rel2scr_y(c.y));
1357 1357 var text_t = new Text(s.axis_y.format.printf((LongDouble)y, s.axis_y.font_style));
1360 1360 switch (s.axis_y.position) {
1361 1361 case Axis.Position.LOW:
1362 1362 print_x = x_min + s.axis_y.font_indent
1363 + (legend.position == Legend.Position.LEFT ? legend_width : 0);
1363 + (legend.position == Legend.Position.LEFT ? legend.width : 0);
1364 1364 break;
1365 1365 case Axis.Position.HIGH:
1366 1366 print_x = x_min + width - text_t.get_width(context) - s.axis_y.font_indent
1367 - (legend.position == Legend.Position.RIGHT ? legend_width : 0);
1367 - (legend.position == Legend.Position.RIGHT ? legend.width : 0);
1368 1368 break;
1369 1369 }
1370 1370 context.move_to (print_x, print_y);
1394 1394 set_source_rgba(s.axis_x.color);
1395 1395 var text_t = new Text(s.axis_x.format.printf((LongDouble)point.x), s.axis_x.font_style);
1396 1396 context.move_to (svp.x - size.x / 2, svp.y + text_t.get_height(context) / 2);
1397 if (common_x_axes) set_source_rgba (common_axis_color);
1397 if (joint_x) set_source_rgba (joint_axis_color);
1398 1398 show_text(text_t);
1399 1399 }
1400 1400
1403 1403 string date = "", time = "";
1404 1404 format_date_time(s.axis_x, point.x, out date, out time);
1405 1405 var text_t = new Text(time, s.axis_x.font_style);
1406 var sz = text_t.size(context);
1406 var sz = text_t.get_size(context);
1407 1407 var y = svp.y + sz.height / 2;
1408 1408 if (show_date) y -= sz.height / 2 + s.axis_x.font_indent / 2;
1409 1409 context.move_to (svp.x - size.x / 2, y);
1410 if (common_x_axes) set_source_rgba (common_axis_color);
1410 if (joint_x) set_source_rgba (joint_axis_color);
1411 1411 show_text(text_t);
1412 1412 }
1413 1413
1416 1416 string date = "", time = "";
1417 1417 format_date_time(s.axis_x, point.x, out date, out time);
1418 1418 var text_t = new Text(date, s.axis_x.font_style);
1419 var sz = text_t.size(context);
1419 var sz = text_t.get_size(context);
1420 1420 var y = svp.y + sz.height / 2;
1421 1421 if (show_time) y += sz.height / 2 + s.axis_x.font_indent / 2;
1422 1422 context.move_to (svp.x - size.x / 2, y);
1423 if (common_x_axes) set_source_rgba (common_axis_color);
1423 if (joint_x) set_source_rgba (joint_axis_color);
1424 1424 show_text(text_t);
1425 1425 }
1426 1426
1427 1427 if (show_y) {
1428 1428 set_source_rgba(s.axis_y.color);
1429 1429 var text_t = new Text(s.axis_y.format.printf((LongDouble)point.y), s.axis_y.font_style);
1430 var sz = text_t.size(context);
1430 var sz = text_t.get_size(context);
1431 1431 context.move_to (svp.x + size.x / 2 - sz.width, svp.y + sz.height / 2);
1432 if (common_y_axes) set_source_rgba (common_axis_color);
1432 if (joint_y) set_source_rgba (joint_axis_color);
1433 1433 show_text(text_t);
1434 1434 }
1435 1435 }
1440 1440 delta = 0.0;
1441 1441 if (series.length == 0) return false;
1442 1442 if (cursors.length() + (is_cursor_active ? 1 : 0) != 2) return false;
1443 if (common_x_axes && cursors_orientation == CursorOrientation.VERTICAL) {
1443 if (joint_x && cursor_style.orientation == Cursor.Orientation.VERTICAL) {
1444 1444 Float128 val1 = get_real_x (series[zoom_first_show], rel2scr_x(cursors.nth_data(0).x));
1445 1445 Float128 val2 = 0;
1446 1446 if (is_cursor_active)
1453 1453 delta = val1 - val2;
1454 1454 return true;
1455 1455 }
1456 if (common_y_axes && cursors_orientation == CursorOrientation.HORIZONTAL) {
1456 if (joint_y && cursor_style.orientation == Cursor.Orientation.HORIZONTAL) {
1457 1457 Float128 val1 = get_real_y (series[zoom_first_show], rel2scr_y(cursors.nth_data(0).y));
1458 1458 Float128 val2 = 0;
1459 1459 if (is_cursor_active)
1474 1474 if (!get_cursors_delta(out delta)) return "";
1475 1475 var str = "";
1476 1476 var s = series[zoom_first_show];
1477 if (common_x_axes)
1477 if (joint_x)
1478 1478 switch (s.axis_x.type) {
1479 1479 case Axis.Type.NUMBERS:
1480 1480 str = s.axis_x.format.printf((LongDouble)delta);
1486 1486 str = days.to_string() + " + " + time;
1487 1487 break;
1488 1488 }
1489 if (common_y_axes) {
1489 if (joint_y) {
1490 1490 str = s.axis_y.format.printf((LongDouble)delta);
1491 1491 }
1492 1492 return str;
1498 1498 chart.axis_rec_npoints = this.axis_rec_npoints;
1499 1499 chart.bg_color = this.bg_color;
1500 1500 chart.border_color = this.border_color;
1501 chart.common_x_axes = this.common_x_axes;
1502 chart.common_y_axes = this.common_y_axes;
1501 chart.joint_x = this.joint_x;
1502 chart.joint_y = this.joint_y;
1503 1503 chart.context = this.context;
1504 1504 chart.cur_x_max = this.cur_x_max;
1505 1505 chart.cur_x_min = this.cur_x_min;
1506 1506 chart.cur_y_max = this.cur_y_max;
1507 1507 chart.cur_y_min = this.cur_y_min;
1508 chart.cursor_line_style = this.cursor_line_style;
1509 chart.cursor_max_rm_distance = this.cursor_max_rm_distance;
1508 chart.cursor_style = this.cursor_style;
1510 1509 chart.cursors = this.cursors.copy();
1511 1510 chart.cursors_crossings = this.cursors_crossings;
1512 chart.cursors_orientation = this.cursors_orientation;
1513 1511 chart.height = this.height;
1514 1512 chart.is_cursor_active = this.is_cursor_active;
1515 1513 chart.legend = this.legend.copy();
1516 chart.legend_height = this.legend_height;
1517 chart.legend_line_length = this.legend_line_length;
1518 chart.legend_text_hspace = this.legend_text_hspace;
1519 chart.legend_text_vspace = this.legend_text_vspace;
1520 chart.legend_width = this.legend_width;
1521 1514 chart.marker_size = this.marker_size;
1522 chart.max_font_heights = this.max_font_heights;
1523 chart.plot_area_x_max = this.plot_area_x_max;
1524 chart.plot_area_x_min = this.plot_area_x_min;
1525 chart.plot_area_y_max = this.plot_area_y_max;
1526 chart.plot_area_y_min = this.plot_area_y_min;
1515 chart.plot_x_max = this.plot_x_max;
1516 chart.plot_x_min = this.plot_x_min;
1517 chart.plot_y_max = this.plot_y_max;
1518 chart.plot_y_min = this.plot_y_min;
1527 1519 chart.rel_zoom_x_min = this.rel_zoom_x_min;
1528 1520 chart.rel_zoom_x_max = this.rel_zoom_x_max;
1529 1521 chart.rel_zoom_y_min = this.rel_zoom_y_min;
1530 1522 chart.rel_zoom_y_max = this.rel_zoom_y_max;
1531 1523 chart.selection_style = this.selection_style;
1532 1524 chart.series = this.series;
1533 chart.show_legend = this.show_legend;
1534 1525 chart.title = this.title.copy();
1535 1526 chart.title_height = this.title_height;
1536 chart.title_vindent = this.title_vindent;
1527 chart.title_indent = this.title_indent;
1537 1528 chart.title_width = this.title_width;
1538 1529 chart.width = this.width;
1539 1530 chart.x_min = this.x_min;
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 public struct Color {
3 3 double red;
4 4 double green;
1 namespace CairoChart {
2
3 public class Cursor {
4
5 public enum Orientation {
6 VERTICAL = 0, // default
7 HORIZONTAL
8 }
9
10 public struct Style {
11
12 public Orientation orientation;
13 public double select_distance;
14 public Line.Style line_style;
15
16 public Style () {
17 orientation = Orientation.VERTICAL;
18 select_distance = 32;
19 line_style = Line.Style(Color(0.2, 0.2, 0.2, 0.8));
20 }
21 }
22 }
23 }
1 namespace CairoChart {
2
3 public class Font {
4
5 public enum Orientation {
6 HORIZONTAL = 0,
7 VERTICAL
8 }
9
10 public struct Style {
11 string family;
12 Cairo.FontSlant slant;
13 Cairo.FontWeight weight;
14
15 Orientation orientation;
16 double size;
17
18 public Style (string family = "Sans",
19 Cairo.FontSlant slant = Cairo.FontSlant.NORMAL,
20 Cairo.FontWeight weight = Cairo.FontWeight.NORMAL,
21 double size = 10,
22 Font.Orientation orientation = Font.Orientation.HORIZONTAL) {
23 this.family = family;
24 this.slant = slant;
25 this.weight = weight;
26 this.size = size;
27 this.orientation = orientation;
28 }
29 }
30 }
31 }
1 namespace Gtk.CairoChart {
2 public enum FontOrient {
3 HORIZONTAL = 0,
4 VERTICAL
5 }
6
7 public struct FontStyle {
8 string family;
9 Cairo.FontSlant slant;
10 Cairo.FontWeight weight;
11
12 FontOrient orientation;
13 double size;
14
15 public FontStyle (string family = "Sans",
16 Cairo.FontSlant slant = Cairo.FontSlant.NORMAL,
17 Cairo.FontWeight weight = Cairo.FontWeight.NORMAL,
18 double size = 10,
19 FontOrient orientation = FontOrient.HORIZONTAL) {
20 this.family = family;
21 this.slant = slant;
22 this.weight = weight;
23 this.size = size;
24 this.orientation = orientation;
25 }
26 }
27 }
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 public class Grid {
3 3 /*public enum GridType {
4 4 PRICK_LINE = 0, // default
6 6 }*/
7 7 public Color color = Color (0, 0, 0, 0.1);
8 8
9 public LineStyle line_style = LineStyle ();
9 public Line.Style line_style = Line.Style ();
10 10
11 11 public Grid copy () {
12 12 var grid = new Grid ();
1 namespace CairoChart {
2
3 public class Label {
4
5 public struct Style {
6 Font.Style font_style;
7 Line.Style frame_line_style;
8 Color bg_color;
9 Color frame_color;
10 }
11 }
12 }
1 namespace Gtk.CairoChart {
2 public struct LabelStyle {
3 FontStyle font_style;
4 LineStyle frame_line_style;
5 Color bg_color;
6 Color frame_color;
7 }
8 }
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2
2 3 public class Legend {
4
3 5 public enum Position {
4 6 TOP = 0, // default
5 7 LEFT,
6 8 RIGHT,
7 9 BOTTOM
8 10 }
11
9 12 public Position position = Position.TOP;
10 public FontStyle font_style = FontStyle();
13 public Font.Style font_style = Font.Style();
11 14 public Color bg_color = Color(1, 1, 1);
12 public LineStyle border_style = LineStyle ();
15 public Line.Style border_style = Line.Style ();
13 16 public double indent = 5;
17 public double width = 0;
18 public double height = 0;
19 public double line_length = 30.0;
20 public double text_hspace = 10.0;
21 public double text_vspace = 2.0;
22 public bool show = true;
14 23
15 24 public Legend copy () {
16 25 var legend = new Legend ();
27 27 legend.font_style = this.font_style;
28 28 legend.bg_color = this.bg_color;
29 29 legend.indent = this.indent;
30 legend.height = this.height;
31 legend.line_length = this.line_length;
32 legend.text_hspace = this.text_hspace;
33 legend.text_vspace = this.text_vspace;
34 legend.width = this.width;
35 legend.show = this.show;
36 legend.max_font_heights = this.max_font_heights;
30 37 return legend;
31 38 }
32 39
33 40 public Legend () {
34 41 border_style.color = Color (0, 0, 0, 0.3);
42 }
43
44 public virtual void draw (Chart chart) {
45 process (chart, ProcessType.CALC);
46 process (chart, ProcessType.DRAW);
47 }
48
49 public virtual void draw_rect (Chart chart, out double x0, out double y0) {
50 x0 = y0 = 0.0;
51 if (chart.context != null) {
52 switch (position) {
53 case Position.TOP:
54 x0 = (chart.width - width) / 2;
55 y0 = chart.title_height;
56 break;
57
58 case Position.BOTTOM:
59 x0 = (chart.width - width) / 2;
60 y0 = chart.height - height;
61 break;
62
63 case Position.LEFT:
64 x0 = 0;
65 y0 = (chart.height - height) / 2;
66 break;
67
68 case Position.RIGHT:
69 x0 = chart.width - width;
70 y0 = (chart.height - height) / 2;
71 break;
72 }
73 chart.set_source_rgba(bg_color);
74 chart.context.rectangle (x0, y0, width, height);
75 chart.context.fill();
76 chart.set_line_style(border_style);
77 chart.context.move_to (x0, y0);
78 chart.context.rel_line_to (width, 0);
79 chart.context.rel_line_to (0, height);
80 chart.context.rel_line_to (-width, 0);
81 chart.context.rel_line_to (0, -height);
82 chart.context.stroke ();
83 }
84 }
85
86 public enum ProcessType {
87 CALC = 0, // default
88 DRAW
89 }
90
91 double [] max_font_heights;
92 public virtual void process (Chart chart, ProcessType process_type) {
93 var legend_x0 = 0.0, legend_y0 = 0.0;
94 var heights_idx = 0;
95 var leg_width_sum = 0.0;
96 var leg_height_sum = 0.0;
97 double max_font_h = 0.0;
98
99 // prepare
100 switch (process_type) {
101 case ProcessType.CALC:
102 width = 0.0;
103 height = 0.0;
104 max_font_heights = {};
105 heights_idx = 0;
106 break;
107 case ProcessType.DRAW:
108 draw_rect(chart, out legend_x0, out legend_y0);
109 break;
110 }
111
112 foreach (var s in chart.series) {
113
114 if (!s.zoom_show) continue;
115
116 var title_sz = s.title.get_size(chart.context);
117
118 // carry
119 switch (position) {
120 case Position.TOP:
121 case Position.BOTTOM:
122 var ser_title_width = title_sz.width + line_length;
123 if (leg_width_sum + (leg_width_sum == 0 ? 0 : text_hspace) + ser_title_width > chart.width) { // carry
124 leg_height_sum += max_font_h;
125 switch (process_type) {
126 case ProcessType.CALC:
127 max_font_heights += max_font_h;
128 width = double.max(width, leg_width_sum);
129 break;
130 case ProcessType.DRAW:
131 heights_idx++;
132 break;
133 }
134 leg_width_sum = 0.0;
135 max_font_h = 0;
136 }
137 break;
138 }
139
140 switch (process_type) {
141 case ProcessType.DRAW:
142 var x = legend_x0 + leg_width_sum + (leg_width_sum == 0.0 ? 0.0 : text_hspace);
143 var y = legend_y0 + leg_height_sum + max_font_heights[heights_idx];
144
145 // series title
146 chart.context.move_to (x + line_length, y);
147 chart.set_source_rgba (s.title.color);
148 chart.show_text(s.title);
149
150 // series line style
151 chart.context.move_to (x, y - title_sz.height / 2);
152 chart.set_line_style(s.line_style);
153 chart.context.rel_line_to (line_length, 0);
154 chart.context.stroke();
155 chart.draw_marker_at_pos (s.marker_type, x + line_length / 2, y - title_sz.height / 2);
156 break;
157 }
158
159 switch (position) {
160 case Position.TOP:
161 case Position.BOTTOM:
162 var ser_title_width = title_sz.width + line_length;
163 leg_width_sum += (leg_width_sum == 0 ? 0 : text_hspace) + ser_title_width;
164 max_font_h = double.max (max_font_h, title_sz.height) + (leg_height_sum != 0 ? text_vspace : 0);
165 break;
166
167 case Position.LEFT:
168 case Position.RIGHT:
169 switch (process_type) {
170 case ProcessType.CALC:
171 max_font_heights += title_sz.height + (leg_height_sum != 0 ? text_vspace : 0);
172 width = double.max (width, title_sz.width + line_length);
173 break;
174 case ProcessType.DRAW:
175 heights_idx++;
176 break;
177 }
178 leg_height_sum += title_sz.height + (leg_height_sum != 0 ? text_vspace : 0);
179 break;
180 }
181 }
182
183 // TOP, BOTTOM
184 switch (position) {
185 case Position.TOP:
186 case Position.BOTTOM:
187 if (leg_width_sum != 0) {
188 leg_height_sum += max_font_h;
189 switch (process_type) {
190 case ProcessType.CALC:
191 max_font_heights += max_font_h;
192 width = double.max(width, leg_width_sum);
193 break;
194 }
195 }
196 break;
197 }
198
199 switch (process_type) {
200 case ProcessType.CALC:
201 height = leg_height_sum;
202 switch (position) {
203 case Position.TOP:
204 chart.cur_y_min += height;
205 break;
206 case Position.BOTTOM:
207 chart.cur_y_max -= height;
208 break;
209 case Position.LEFT:
210 chart.cur_x_min += width;
211 break;
212 case Position.RIGHT:
213 chart.cur_x_max -= width;
214 break;
215 }
216 break;
217 }
35 218 }
36 219 }
37 220 }
1 namespace CairoChart {
2
3 public class Line {
4
5 public struct Style {
6
7 double width;
8 Cairo.LineJoin join;
9 Cairo.LineCap cap;
10 double[]? dashes;
11 double dash_offset;
12 Color color;
13
14 public Style (Color color = Color(),
15 double width = 1,
16 double[]? dashes = null, double dash_offset = 0,
17 Cairo.LineJoin join = Cairo.LineJoin.MITER,
18 Cairo.LineCap cap = Cairo.LineCap.ROUND
19 ) {
20 this.width = width;
21 this.join = join;
22 this.cap = cap;
23 this.dashes = dashes;
24 this.dash_offset = dash_offset;
25 this.color = color;
26 }
27 }
28 }
29 }
1 namespace Gtk.CairoChart {
2 public struct LineStyle {
3 double width;
4 Cairo.LineJoin line_join;
5 Cairo.LineCap line_cap;
6 double[]? dashes;
7 double dash_offset;
8 Color color;
9
10 public LineStyle (Color color = Color(),
11 double width = 1,
12 double[]? dashes = null, double dash_offset = 0,
13 Cairo.LineJoin line_join = Cairo.LineJoin.MITER,
14 Cairo.LineCap line_cap = Cairo.LineCap.ROUND
15 ) {
16 this.width = width;
17 this.line_join = line_join;
18 this.line_cap = line_cap;
19 this.dashes = dashes;
20 this.dash_offset = dash_offset;
21 this.color = color;
22 }
23 }
24 }
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 public class Place {
3 double _x_low = 0;
4 double _x_high = 0;
5 double _y_low = 0;
6 double _y_high = 0;
7 public double x_low {
8 get { return _x_low; }
9 set { _x_low = zoom_x_low = value; }
3 double _x_min = 0;
4 double _x_max = 0;
5 double _y_min = 0;
6 double _y_max = 0;
7 public double x_min {
8 get { return _x_min; }
9 set { _x_min = zoom_x_min = value; }
10 10 default = 0;
11 11 }
12 public double x_high {
13 get { return _x_high; }
14 set { _x_high = zoom_x_high = value; }
12 public double x_max {
13 get { return _x_max; }
14 set { _x_max = zoom_x_max = value; }
15 15 default = 0;
16 16 }
17 public double y_low {
18 get { return _y_low; }
19 set { _y_low = zoom_y_low = value; }
17 public double y_min {
18 get { return _y_min; }
19 set { _y_min = zoom_y_min = value; }
20 20 default = 0;
21 21 }
22 public double y_high {
23 get { return _y_high; }
24 set { _y_high = zoom_y_high = value; }
22 public double y_max {
23 get { return _y_max; }
24 set { _y_max = zoom_y_max = value; }
25 25 default = 0;
26 26 }
27 public double zoom_x_low = 0;
28 public double zoom_x_high = 1;
29 public double zoom_y_low = 0;
30 public double zoom_y_high = 1;
27 public double zoom_x_min = 0;
28 public double zoom_x_max = 1;
29 public double zoom_y_min = 0;
30 public double zoom_y_max = 1;
31 31
32 32 public Place copy () {
33 33 var place = new Place ();
34 place.x_low = this.x_low;
35 place.x_high = this.x_high;
36 place.y_low = this.y_low;
37 place.y_high = this.y_high;
34 place.x_min = this.x_min;
35 place.x_max = this.x_max;
36 place.y_min = this.y_min;
37 place.y_max = this.y_max;
38 38 return place;
39 39 }
40 40
41 public Place (double x_low = 0, double x_high = 1, double y_low = 0, double y_high = 1) {
42 this.x_low = x_low;
43 this.x_high = x_high;
44 this.y_low = y_low;
45 this.y_high = y_high;
46 zoom_x_low = x_low;
47 zoom_x_high = x_high;
48 zoom_y_low = y_low;
49 zoom_y_high = y_high;
41 public Place (double x_min = 0, double x_max = 1, double y_min = 0, double y_max = 1) {
42 this.x_min = x_min;
43 this.x_max = x_max;
44 this.y_min = y_min;
45 this.y_max = y_max;
46 zoom_x_min = x_min;
47 zoom_x_max = x_max;
48 zoom_y_min = y_min;
49 zoom_y_max = y_max;
50 50 }
51 51 }
52 52 }
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 public struct Point {
3 3 Float128 x;
4 4 Float128 y;
1 1 using Cairo;
2 2
3 namespace Gtk.CairoChart {
3 namespace CairoChart {
4 4
5 5 public class Series {
6 6
8 8 public enum Sort {
9 9 BY_X = 0,
10 10 BY_Y = 1,
11 NO_SORT
11 UNSORTED
12 12 }
13 13 public Sort sort = Sort.BY_X;
14 14
31 31
32 32 public Grid grid = new Grid ();
33 33
34 public LineStyle line_style = LineStyle ();
34 public Line.Style line_style = Line.Style ();
35 35
36 36 protected Color _color = Color (0.0, 0.0, 0.0, 1.0);
37 37 public Color color {
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 [Compact]
3 3 public class Text {
4 4 public string text = "";
5 public FontStyle style = FontStyle ();
5 public Font.Style style = Font.Style ();
6 6 public Color color = Color();
7 7
8 8 public Cairo.TextExtents get_extents (Cairo.Context context) {
16 16 public double get_width (Cairo.Context context) {
17 17 var extents = get_extents (context);
18 18 switch (style.orientation) {
19 case FontOrient.HORIZONTAL: return extents.width;
20 case FontOrient.VERTICAL: return extents.height;
19 case Font.Orientation.HORIZONTAL: return extents.width;
20 case Font.Orientation.VERTICAL: return extents.height;
21 21 default: return 0.0;
22 22 }
23 23 }
25 25 public double get_height (Cairo.Context context) {
26 26 var extents = get_extents (context);
27 27 switch (style.orientation) {
28 case FontOrient.HORIZONTAL: return extents.height;
29 case FontOrient.VERTICAL: return extents.width;
28 case Font.Orientation.HORIZONTAL: return extents.height;
29 case Font.Orientation.VERTICAL: return extents.width;
30 30 default: return 0.0;
31 31 }
32 32 }
36 36 double height;
37 37 }
38 38
39 public Size size (Cairo.Context context) {
39 public Size get_size (Cairo.Context context) {
40 40 var sz = Size();
41 41 var extents = get_extents (context);
42 42 switch (style.orientation) {
43 case FontOrient.HORIZONTAL:
43 case Font.Orientation.HORIZONTAL:
44 44 sz.width = extents.width + extents.x_bearing;
45 45 sz.height = extents.height;
46 46 break;
47 case FontOrient.VERTICAL:
47 case Font.Orientation.VERTICAL:
48 48 sz.width = extents.height; // + extents.x_bearing ?
49 49 sz.height = extents.width; // +- extents.y_bearing ?
50 50 break;
53 53 }
54 54
55 55 public Text (string text = "",
56 FontStyle style = FontStyle(),
56 Font.Style style = Font.Style(),
57 57 Color color = Color()) {
58 58 this.text = text;
59 59 this.style = style;
1 namespace Gtk.CairoChart {
1 namespace CairoChart {
2 2 [CCode (cname = "cairo_chart_float128", has_type_id = false, cheader_filename = "cairo-chart-float128type.h")]
3 3 public struct Float128 : double {}
4 4 [CCode (cname = "cairo_chart_long_double", has_type_id = false, cheader_filename = "cairo-chart-float128type.h")]
17 17
18 18 s1.axis_x.min = 0; s1.axis_x.max = 2;
19 19 s1.axis_y.min = 0; s1.axis_y.max = 3;
20 s1.place.x_low = 0.25; s1.place.x_high = 0.75;
21 s1.place.y_low = 0.3; s1.place.y_high = 0.9;
20 s1.place.x_min = 0.25; s1.place.x_max = 0.75;
21 s1.place.y_min = 0.3; s1.place.y_max = 0.9;
22 22
23 23 s2.axis_x.min = -15; s2.axis_x.max = 30;
24 24 s2.axis_y.min = -20; s2.axis_y.max = 200;
25 s2.place.x_low = 0.5; s2.place.x_high = 1;
26 s2.place.y_low = 0.0; s2.place.y_high = 0.5;
25 s2.place.x_min = 0.5; s2.place.x_max = 1;
26 s2.place.y_min = 0.0; s2.place.y_max = 0.5;
27 27
28 28 s3.axis_x.min = 0; s3.axis_x.max = 130;
29 29 s3.axis_y.min = 15; s3.axis_y.max = 35;
30 s3.place.x_low = 0; s3.place.x_high = 0.5;
31 s3.place.y_low = 0.5; s3.place.y_high = 1.0;
30 s3.place.x_min = 0; s3.place.x_max = 0.5;
31 s3.place.y_min = 0.5; s3.place.y_max = 1.0;
32 32
33 33 s2.marker_type = Series.MarkerType.CIRCLE;
34 34 s3.marker_type = Series.MarkerType.PRICLE_TRIANGLE;
60 60
61 61 s1.axis_x.min = -15; s1.axis_x.max = 30;
62 62 s1.axis_y.min = 0; s1.axis_y.max = 3;
63 s1.place.x_low = 0.0; s1.place.x_high = 1.0;
64 s1.place.y_low = 0.3; s1.place.y_high = 0.9;
63 s1.place.x_min = 0.0; s1.place.x_max = 1.0;
64 s1.place.y_min = 0.3; s1.place.y_max = 0.9;
65 65
66 66 s2.axis_x.min = -15; s2.axis_x.max = 30;
67 67 s2.axis_y.min = -20; s2.axis_y.max = 200;
68 s2.place.x_low = 0.0; s2.place.x_high = 1.0;
69 s2.place.y_low = 0.0; s2.place.y_high = 0.5;
68 s2.place.x_min = 0.0; s2.place.x_max = 1.0;
69 s2.place.y_min = 0.0; s2.place.y_max = 0.5;
70 70
71 71 s3.axis_x.min = -15; s3.axis_x.max = 30;
72 72 s3.axis_y.min = 15; s3.axis_y.max = 35;
73 s3.place.x_low = 0.0; s3.place.x_high = 1.0;
74 s3.place.y_low = 0.5; s3.place.y_high = 1.0;
73 s3.place.x_min = 0.0; s3.place.x_max = 1.0;
74 s3.place.y_min = 0.5; s3.place.y_max = 1.0;
75 75
76 76 s1.marker_type = Series.MarkerType.PRICLE_CIRCLE;
77 77 s2.marker_type = Series.MarkerType.PRICLE_SQUARE;
109 109
110 110 s1.axis_x.min = 0; s1.axis_x.max = 2;
111 111 s1.axis_y.min = -20; s1.axis_y.max = 200;
112 s1.place.x_low = 0.25; s1.place.x_high = 0.75;
113 s1.place.y_low = 0.0; s1.place.y_high = 1.0;
112 s1.place.x_min = 0.25; s1.place.x_max = 0.75;
113 s1.place.y_min = 0.0; s1.place.y_max = 1.0;
114 114
115 115 s2.axis_x.min = -15; s2.axis_x.max = 30;
116 116 s2.axis_y.min = -20; s2.axis_y.max = 200;
117 s2.place.x_low = 0.5; s2.place.x_high = 1;
118 s2.place.y_low = 0.0; s2.place.y_high = 1.0;
117 s2.place.x_min = 0.5; s2.place.x_max = 1;
118 s2.place.y_min = 0.0; s2.place.y_max = 1.0;
119 119
120 120 s3.axis_x.min = 0; s3.axis_x.max = 130;
121 121 s3.axis_y.min = -20; s3.axis_y.max = 200;
122 s3.place.x_low = 0; s3.place.x_high = 0.5;
123 s3.place.y_low = 0.0; s3.place.y_high = 1.0;
122 s3.place.x_min = 0; s3.place.x_max = 0.5;
123 s3.place.y_min = 0.0; s3.place.y_max = 1.0;
124 124
125 125 s2.marker_type = Series.MarkerType.PRICLE_CIRCLE;
126 126 s3.marker_type = Series.MarkerType.TRIANGLE;
167 167
168 168 s1.axis_x.min = now - 100000; s1.axis_x.max = now + 100000;
169 169 s1.axis_y.min = -20; s1.axis_y.max = 200;
170 s1.place.x_low = 0.25; s1.place.x_high = 0.75;
171 s1.place.y_low = 0.0; s1.place.y_high = 1.0;
170 s1.place.x_min = 0.25; s1.place.x_max = 0.75;
171 s1.place.y_min = 0.0; s1.place.y_max = 1.0;
172 172
173 173 s2.axis_x.min = -15; s2.axis_x.max = 30;
174 174 s2.axis_y.min = -20; s2.axis_y.max = 200;
175 s2.place.x_low = 0.2; s2.place.x_high = 1;
176 s2.place.y_low = 0.0; s2.place.y_high = 1.0;
175 s2.place.x_min = 0.2; s2.place.x_max = 1;
176 s2.place.y_min = 0.0; s2.place.y_max = 1.0;
177 177
178 178 s3.axis_x.min = high - 2; s3.axis_x.max = high + 1;
179 179 s3.axis_y.min = -20; s3.axis_y.max = 200;
180 s3.place.x_low = 0; s3.place.x_high = 0.8;
181 s3.place.y_low = 0.0; s3.place.y_high = 1.0;
180 s3.place.x_min = 0; s3.place.x_max = 0.8;
181 s3.place.y_min = 0.0; s3.place.y_max = 1.0;
182 182
183 183 s4.axis_x.min = high + 0.0049; s4.axis_x.max = high + 0.0054;
184 184 s4.axis_y.min = -20; s4.axis_y.max = 200;
185 s4.place.x_low = 0.2; s4.place.x_high = 1.0;
186 s4.place.y_low = 0.0; s4.place.y_high = 1.0;
185 s4.place.x_min = 0.2; s4.place.x_max = 1.0;
186 s4.place.y_min = 0.0; s4.place.y_max = 1.0;
187 187
188 188 s2.marker_type = Series.MarkerType.PRICLE_CIRCLE;
189 189 s3.marker_type = Series.MarkerType.TRIANGLE;
202 202 }
203 203
204 204 bool point_in_chart (Chart chart, double x, double y) {
205 if (x < chart.plot_area_x_min) return false;
206 if (x > chart.plot_area_x_max) return false;
207 if (y < chart.plot_area_y_min) return false;
208 if (y > chart.plot_area_y_max) return false;
205 if (x < chart.plot_x_min) return false;
206 if (x > chart.plot_x_max) return false;
207 if (y < chart.plot_y_min) return false;
208 if (y > chart.plot_y_max) return false;
209 209 return true;
210 210 }
211 211
230 230 var chart2 = new Chart();
231 231 var chart3 = new Chart();
232 232 var chart4 = new Chart();
233 var label = new Label ("Chart Test!");
233 var label = new Gtk.Label ("Chart Test!");
234 234 var button1 = new Button.with_label("Separate axes");
235 var button2 = new Button.with_label("Common X axes");
236 var button3 = new Button.with_label("Common Y axes");
235 var button2 = new Button.with_label("Joint X axes");
236 var button3 = new Button.with_label("Joint Y axes");
237 237 var button4 = new Button.with_label("Dates/Times");
238 238 var button5 = new Button.with_label("rm Axis Titles");
239 239 var button6 = new Button.with_label("Dates only");
245 245 plot_chart3 (chart3);
246 246 plot_chart4 (chart4);
247 247
248 chart1.selection_style = LineStyle(Color(0.3, 0.3, 0.3, 0.7), 1);
248 chart1.selection_style = Line.Style(Color(0.3, 0.3, 0.3, 0.7), 1);
249 249
250 250 var da = new DrawingArea();
251 251 da.set_events ( Gdk.EventMask.BUTTON_PRESS_MASK
270 270 case Legend.Position.LEFT: radio_button3.set_active(true); break;
271 271 case Legend.Position.BOTTOM: radio_button4.set_active(true); break;
272 272 }
273 switch (chart.cursors_orientation) {
274 case Chart.CursorOrientation.VERTICAL: radio_button7.set_active(true); break;
275 case Chart.CursorOrientation.HORIZONTAL: radio_button8.set_active(true); break;
273 switch (chart.cursor_style.orientation) {
274 case Cursor.Orientation.VERTICAL: radio_button7.set_active(true); break;
275 case Cursor.Orientation.HORIZONTAL: radio_button8.set_active(true); break;
276 276 }
277 277 });
278 278 button2.clicked.connect (() => {
283 283 case Legend.Position.LEFT: radio_button3.set_active(true); break;
284 284 case Legend.Position.BOTTOM: radio_button4.set_active(true); break;
285 285 }
286 switch (chart.cursors_orientation) {
287 case Chart.CursorOrientation.VERTICAL: radio_button7.set_active(true); break;
288 case Chart.CursorOrientation.HORIZONTAL: radio_button8.set_active(true); break;
286 switch (chart.cursor_style.orientation) {
287 case Cursor.Orientation.VERTICAL: radio_button7.set_active(true); break;
288 case Cursor.Orientation.HORIZONTAL: radio_button8.set_active(true); break;
289 289 }
290 290 });
291 291 button3.clicked.connect (() => {
296 296 case Legend.Position.LEFT: radio_button3.set_active(true); break;
297 297 case Legend.Position.BOTTOM: radio_button4.set_active(true); break;
298 298 }
299 switch (chart.cursors_orientation) {
300 case Chart.CursorOrientation.VERTICAL: radio_button7.set_active(true); break;
301 case Chart.CursorOrientation.HORIZONTAL: radio_button8.set_active(true); break;
299 switch (chart.cursor_style.orientation) {
300 case Cursor.Orientation.VERTICAL: radio_button7.set_active(true); break;
301 case Cursor.Orientation.HORIZONTAL: radio_button8.set_active(true); break;
302 302 }
303 303 });
304 304 button4.clicked.connect (() => {
309 309 case Legend.Position.LEFT: radio_button4.set_active(true); break;
310 310 case Legend.Position.BOTTOM: radio_button4.set_active(true); break;
311 311 }
312 switch (chart.cursors_orientation) {
313 case Chart.CursorOrientation.VERTICAL: radio_button7.set_active(true); break;
314 case Chart.CursorOrientation.HORIZONTAL: radio_button8.set_active(true); break;
312 switch (chart.cursor_style.orientation) {
313 case Cursor.Orientation.VERTICAL: radio_button7.set_active(true); break;
314 case Cursor.Orientation.HORIZONTAL: radio_button8.set_active(true); break;
315 315 }
316 316 });
317 317 button5.clicked.connect (() => {
393 393
394 394 radio_button7.toggled.connect ((button) => {
395 395 if (button.get_active()) {
396 chart.cursors_orientation = Chart.CursorOrientation.VERTICAL;
396 chart.cursor_style.orientation = Cursor.Orientation.VERTICAL;
397 397 da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
398 398 }
399 399 });
400 400 radio_button8.toggled.connect ((button) => {
401 401 if (button.get_active()) {
402 chart.cursors_orientation = Chart.CursorOrientation.HORIZONTAL;
402 chart.cursor_style.orientation = Cursor.Orientation.HORIZONTAL;
403 403 da.queue_draw_area(0, 0, da.get_allocated_width(), da.get_allocated_height());
404 404 }
405 405 });
431 431 var text_t = new Text(text);
432 432 var w = text_t.get_width(context);
433 433 var h = text_t.get_height(context);
434 var x0 = chart.plot_area_x_max - w - 5;
435 var y0 = chart.plot_area_y_min + h + 5;
434 var x0 = chart.plot_x_max - w - 5;
435 var y0 = chart.plot_y_min + h + 5;
436 436 chart.set_source_rgba(chart.legend.bg_color);
437 437 context.rectangle (x0, y0 - h, w, h);
438 438 context.fill();
439 439 context.move_to (x0, y0);
440 chart.set_source_rgba(chart.common_axis_color);
440 chart.set_source_rgba(chart.joint_axis_color);
441 441 context.show_text(text);
442 442 }
443 443

Comments