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 b75386a to 76fb9d8

Commits

avatar Kolan Sh In progress... Before Moscow 09.01 d67e2c2 7 days ago
avatar Kolan Sh In progress... show_text() -> Text.vala 6f5e577 7 days ago
avatar Kolan Sh In progress... show_text() -> Text.vala #2 0027889 7 days ago
avatar Kolan Sh rel_zoom -> rz eeb6fca 7 days ago
avatar Kolan Sh set_line_style() -> Line.vala 94ed3ec 7 days ago
avatar Kolan Sh Marker.vala created #1 6e57789 7 days ago
avatar Kolan Sh Marker.vala ... #2 76fb9d8 7 days ago

Summary

  • src/Axis.vala (6) ---+++
  • src/Chart.vala (806) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • 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 (37) +++++++++++++++++++++++++++++++++++++
  • src/LineStyle.vala (24) ------------------------
  • src/Marker.vala (71) +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • src/Place.vala (68) ----------------------------------++++++++++++++++++++++++++++++++++
  • src/Point.vala (2) -+
  • src/Series.vala (20) ---------------+++++
  • src/Text.vala (34) ----------++++++++++++++++++++++++
  • src/cairo-chart-float128type.vapi (2) -+
  • test/ChartTest.vala (120) ------------------------------------------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 ();
55 55
56 56 get_cursors_crossings();
57 57
58 calc_plot_area (); // Calculate plot area
58 calc_plot_area ();
59 59
60 60 draw_horizontal_axis ();
61 61 check_cur_values ();
87 87 }
88 88 }
89 89
90 protected double rel_zoom_x_min = 0.0;
91 protected double rel_zoom_x_max = 1.0;
92 protected double rel_zoom_y_min = 0.0;
93 protected double rel_zoom_y_max = 1.0;
90 // relative zoom limits
91 protected double rz_x_min = 0.0;
92 protected double rz_x_max = 1.0;
93 protected double rz_y_min = 0.0;
94 protected double rz_y_max = 1.0;
94 95
95 96 int zoom_first_show = 0;
96 97
111 111 }
112 112 if (real_x0 >= s.axis_x.zoom_min) {
113 113 s.axis_x.zoom_min = real_x0;
114 s.place.zoom_x_low = 0.0;
114 s.place.zoom_x_min = 0.0;
115 115 } else {
116 s.place.zoom_x_low = (s.axis_x.zoom_min - real_x0) / (real_x1 - real_x0);
116 s.place.zoom_x_min = (s.axis_x.zoom_min - real_x0) / (real_x1 - real_x0);
117 117 }
118 118 if (real_x1 <= s.axis_x.zoom_max) {
119 119 s.axis_x.zoom_max = real_x1;
120 s.place.zoom_x_high = 1.0;
120 s.place.zoom_x_max = 1.0;
121 121 } else {
122 s.place.zoom_x_high = (s.axis_x.zoom_max - real_x0) / (real_x1 - real_x0);
122 s.place.zoom_x_max = (s.axis_x.zoom_max - real_x0) / (real_x1 - real_x0);
123 123 }
124 124 if (real_y1 >= s.axis_y.zoom_min) {
125 125 s.axis_y.zoom_min = real_y1;
126 s.place.zoom_y_low = 0.0;
126 s.place.zoom_y_min = 0.0;
127 127 } else {
128 s.place.zoom_y_low = (s.axis_y.zoom_min - real_y1) / (real_y0 - real_y1);
128 s.place.zoom_y_min = (s.axis_y.zoom_min - real_y1) / (real_y0 - real_y1);
129 129 }
130 130 if (real_y0 <= s.axis_y.zoom_max) {
131 131 s.axis_y.zoom_max = real_y0;
132 s.place.zoom_y_high = 1.0;
132 s.place.zoom_y_max = 1.0;
133 133 } else {
134 s.place.zoom_y_high = (s.axis_y.zoom_max - real_y1) / (real_y0 - real_y1);
134 s.place.zoom_y_max = (s.axis_y.zoom_max - real_y1) / (real_y0 - real_y1);
135 135 }
136 136 }
137 137
142 142 break;
143 143 }
144 144
145 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);
146 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);
147 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);
148 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);
149 rel_zoom_x_min = new_rel_zoom_x_min;
150 rel_zoom_x_max = new_rel_zoom_x_max;
151 rel_zoom_y_min = new_rel_zoom_y_min;
152 rel_zoom_y_max = new_rel_zoom_y_max;
145 var new_rz_x_min = rz_x_min + (x0 - plot_x_min) / (plot_x_max - plot_x_min) * (rz_x_max - rz_x_min);
146 var new_rz_x_max = rz_x_min + (x1 - plot_x_min) / (plot_x_max - plot_x_min) * (rz_x_max - rz_x_min);
147 var new_rz_y_min = rz_y_min + (y0 - plot_y_min) / (plot_y_max - plot_y_min) * (rz_y_max - rz_y_min);
148 var new_rz_y_max = rz_y_min + (y1 - plot_y_min) / (plot_y_max - plot_y_min) * (rz_y_max - rz_y_min);
149 rz_x_min = new_rz_x_min;
150 rz_x_max = new_rz_x_max;
151 rz_y_min = new_rz_y_min;
152 rz_y_max = new_rz_y_max;
153 153 }
154 154
155 155 public virtual void zoom_out () {
159 159 s.axis_x.zoom_max = s.axis_x.max;
160 160 s.axis_y.zoom_min = s.axis_y.min;
161 161 s.axis_y.zoom_max = s.axis_y.max;
162 s.place.zoom_x_low = s.place.x_low;
163 s.place.zoom_x_high = s.place.x_high;
164 s.place.zoom_y_low = s.place.y_low;
165 s.place.zoom_y_high = s.place.y_high;
162 s.place.zoom_x_min = s.place.x_min;
163 s.place.zoom_x_max = s.place.x_max;
164 s.place.zoom_y_min = s.place.y_min;
165 s.place.zoom_y_max = s.place.y_max;
166 166 }
167 rel_zoom_x_min = 0;
168 rel_zoom_x_max = 1;
169 rel_zoom_y_min = 0;
170 rel_zoom_y_max = 1;
167 rz_x_min = 0;
168 rz_x_max = 1;
169 rz_y_min = 0;
170 rz_y_max = 1;
171 171
172 172 zoom_first_show = 0;
173 173 }
174 174
175 175 public virtual void move (double delta_x, double delta_y) {
176 delta_x /= plot_area_x_max - plot_area_x_min; delta_x *= - 1.0;
177 delta_y /= plot_area_y_max - plot_area_y_min; delta_y *= - 1.0;
178 var rzxmin = rel_zoom_x_min, rzxmax = rel_zoom_x_max, rzymin = rel_zoom_y_min, rzymax = rel_zoom_y_max;
176 delta_x /= plot_x_max - plot_x_min; delta_x *= - 1.0;
177 delta_y /= plot_y_max - plot_y_min; delta_y *= - 1.0;
178 var rzxmin = rz_x_min, rzxmax = rz_x_max, rzymin = rz_y_min, rzymax = rz_y_max;
179 179 zoom_out();
180 180 //draw(); // TODO: optimize here
181 delta_x *= plot_area_x_max - plot_area_x_min;
182 delta_y *= plot_area_y_max - plot_area_y_min;
183 var xmin = plot_area_x_min + (plot_area_x_max - plot_area_x_min) * rzxmin;
184 var xmax = plot_area_x_min + (plot_area_x_max - plot_area_x_min) * rzxmax;
185 var ymin = plot_area_y_min + (plot_area_y_max - plot_area_y_min) * rzymin;
186 var ymax = plot_area_y_min + (plot_area_y_max - plot_area_y_min) * rzymax;
181 delta_x *= plot_x_max - plot_x_min;
182 delta_y *= plot_y_max - plot_y_min;
183 var xmin = plot_x_min + (plot_x_max - plot_x_min) * rzxmin;
184 var xmax = plot_x_min + (plot_x_max - plot_x_min) * rzxmax;
185 var ymin = plot_y_min + (plot_y_max - plot_y_min) * rzymin;
186 var ymax = plot_y_min + (plot_y_max - plot_y_min) * rzymax;
187 187
188 188 delta_x *= rzxmax - rzxmin; delta_y *= rzymax - rzymin;
189 189
190 if (xmin + delta_x < plot_area_x_min) delta_x = plot_area_x_min - xmin;
191 if (xmax + delta_x > plot_area_x_max) delta_x = plot_area_x_max - xmax;
192 if (ymin + delta_y < plot_area_y_min) delta_y = plot_area_y_min - ymin;
193 if (ymax + delta_y > plot_area_y_max) delta_y = plot_area_y_max - ymax;
190 if (xmin + delta_x < plot_x_min) delta_x = plot_x_min - xmin;
191 if (xmax + delta_x > plot_x_max) delta_x = plot_x_max - xmax;
192 if (ymin + delta_y < plot_y_min) delta_y = plot_y_min - ymin;
193 if (ymax + delta_y > plot_y_max) delta_y = plot_y_max - ymax;
194 194
195 195 zoom_in (xmin + delta_x, ymin + delta_y, xmax + delta_x, ymax + delta_y);
196 196 //draw(); // TODO: optimize here
197 197 }
198 198
199 protected double title_width = 0.0;
200 protected double title_height = 0.0;
199 public double title_width { get; protected set; default = 0.0; }
200 public double title_height { get; protected set; default = 0.0; }
201 201
202 public double title_vindent = 4;
202 public double title_indent = 4;
203 203
204 protected virtual void show_text(Text text) {
205 context.select_font_face(text.style.family,
206 text.style.slant,
207 text.style.weight);
208 context.set_font_size(text.style.size);
209 if (text.style.orientation == FontOrient.VERTICAL) {
210 context.rotate(- Math.PI / 2.0);
211 context.show_text(text.text);
212 context.rotate(Math.PI / 2.0);
213 } else {
214 context.show_text(text.text);
215 }
216 }
217
218 204 protected virtual void draw_chart_title () {
219 var sz = title.size(context);
220 title_height = sz.height + (legend.position == Legend.Position.TOP ? title_vindent * 2 : title_vindent);
205 var sz = title.get_size(context);
206 title_height = sz.height + (legend.position == Legend.Position.TOP ? title_indent * 2 : title_indent);
221 207 cur_y_min += title_height;
222 208 set_source_rgba(title.color);
223 context.move_to (width/2 - sz.width/2, sz.height + title_vindent);
224 show_text(title);
209 context.move_to (width/2 - sz.width/2, sz.height + title_indent);
210 title.show(context);
225 211 }
226 212
227 protected double legend_width = 0;
228 protected double legend_height = 0;
213 public Line.Style selection_style = Line.Style ();
229 214
230 protected enum LegendProcessType {
231 CALC = 0, // default
232 DRAW
233 }
234
235 protected virtual void set_line_style (LineStyle style) {
236 set_source_rgba(style.color);
237 context.set_line_join(style.line_join);
238 context.set_line_cap(style.line_cap);
239 context.set_line_width(style.width);
240 context.set_dash(style.dashes, style.dash_offset);
241 }
242
243 protected virtual void draw_legend_rect (out double x0, out double y0) {
244 x0 = y0 = 0.0;
245 if (context != null) {
246 switch (legend.position) {
247 case Legend.Position.TOP:
248 x0 = (width - legend_width) / 2;
249 y0 = title_height;
250 break;
251
252 case Legend.Position.BOTTOM:
253 x0 = (width - legend_width) / 2;
254 y0 = height - legend_height;
255 break;
256
257 case Legend.Position.LEFT:
258 x0 = 0;
259 y0 = (height - legend_height) / 2;
260 break;
261
262 case Legend.Position.RIGHT:
263 x0 = width - legend_width;
264 y0 = (height - legend_height) / 2;
265 break;
266 }
267 set_source_rgba(legend.bg_color);
268 context.rectangle (x0, y0, legend_width, legend_height);
269 context.fill();
270 set_line_style(legend.border_style);
271 context.move_to (x0, y0);
272 context.rel_line_to (legend_width, 0);
273 context.rel_line_to (0, legend_height);
274 context.rel_line_to (-legend_width, 0);
275 context.rel_line_to (0, -legend_height);
276 context.stroke ();
277 }
278 }
279
280 public double legend_line_length = 30.0;
281 public double legend_text_hspace = 10.0;
282 public double legend_text_vspace = 2.0;
283 public double marker_size = 8.0;
284
285 protected virtual void draw_marker_at_pos (Series.MarkerType marker_type,
286 double x, double y) {
287 context.move_to (x, y);
288 switch (marker_type) {
289 case Series.MarkerType.SQUARE:
290 context.rectangle (x - marker_size / 2, y - marker_size / 2,
291 marker_size, marker_size);
292 context.fill();
293 break;
294
295 case Series.MarkerType.CIRCLE:
296 context.arc (x, y, marker_size / 2, 0, 2*Math.PI);
297 context.fill();
298 break;
299
300 case Series.MarkerType.TRIANGLE:
301 context.move_to (x - marker_size / 2, y - marker_size / 2);
302 context.line_to (x + marker_size / 2, y - marker_size / 2);
303 context.line_to (x, y + marker_size / 2);
304 context.line_to (x - marker_size / 2, y - marker_size / 2);
305 context.fill();
306 break;
307
308 case Series.MarkerType.PRICLE_SQUARE:
309 context.rectangle (x - marker_size / 2, y - marker_size / 2,
310 marker_size, marker_size);
311 context.stroke();
312 break;
313
314 case Series.MarkerType.PRICLE_CIRCLE:
315 context.arc (x, y, marker_size / 2, 0, 2*Math.PI);
316 context.stroke();
317 break;
318
319 case Series.MarkerType.PRICLE_TRIANGLE:
320 context.move_to (x - marker_size / 2, y - marker_size / 2);
321 context.line_to (x + marker_size / 2, y - marker_size / 2);
322 context.line_to (x, y + marker_size / 2);
323 context.line_to (x - marker_size / 2, y - marker_size / 2);
324 context.stroke();
325 break;
326 }
327 }
328
329 double [] max_font_heights;
330 protected virtual void process_legend (LegendProcessType process_type) {
331 var legend_x0 = 0.0, legend_y0 = 0.0;
332 var heights_idx = 0;
333 var leg_width_sum = 0.0;
334 var leg_height_sum = 0.0;
335 double max_font_h = 0.0;
336
337 // prepare
338 switch (process_type) {
339 case LegendProcessType.CALC:
340 legend_width = 0.0;
341 legend_height = 0.0;
342 max_font_heights = {};
343 heights_idx = 0;
344 break;
345 case LegendProcessType.DRAW:
346 draw_legend_rect(out legend_x0, out legend_y0);
347 break;
348 }
349
350 foreach (var s in series) {
351
352 if (!s.zoom_show) continue;
353
354 var title_sz = s.title.size(context);
355
356 // carry
357 switch (legend.position) {
358 case Legend.Position.TOP:
359 case Legend.Position.BOTTOM:
360 var ser_title_width = title_sz.width + legend_line_length;
361 if (leg_width_sum + (leg_width_sum == 0 ? 0 : legend_text_hspace) + ser_title_width > width) { // carry
362 leg_height_sum += max_font_h;
363 switch (process_type) {
364 case LegendProcessType.CALC:
365 max_font_heights += max_font_h;
366 legend_width = double.max(legend_width, leg_width_sum);
367 break;
368 case LegendProcessType.DRAW:
369 heights_idx++;
370 break;
371 }
372 leg_width_sum = 0.0;
373 max_font_h = 0;
374 }
375 break;
376 }
377
378 switch (process_type) {
379 case LegendProcessType.DRAW:
380 var x = legend_x0 + leg_width_sum + (leg_width_sum == 0.0 ? 0.0 : legend_text_hspace);
381 var y = legend_y0 + leg_height_sum + max_font_heights[heights_idx];
382
383 // series title
384 context.move_to (x + legend_line_length, y);
385 set_source_rgba (s.title.color);
386 show_text(s.title);
387
388 // series line style
389 context.move_to (x, y - title_sz.height / 2);
390 set_line_style(s.line_style);
391 context.rel_line_to (legend_line_length, 0);
392 context.stroke();
393 draw_marker_at_pos (s.marker_type, x + legend_line_length / 2, y - title_sz.height / 2);
394 break;
395 }
396
397 switch (legend.position) {
398 case Legend.Position.TOP:
399 case Legend.Position.BOTTOM:
400 var ser_title_width = title_sz.width + legend_line_length;
401 leg_width_sum += (leg_width_sum == 0 ? 0 : legend_text_hspace) + ser_title_width;
402 max_font_h = double.max (max_font_h, title_sz.height) + (leg_height_sum != 0 ? legend_text_vspace : 0);
403 break;
404
405 case Legend.Position.LEFT:
406 case Legend.Position.RIGHT:
407 switch (process_type) {
408 case LegendProcessType.CALC:
409 max_font_heights += title_sz.height + (leg_height_sum != 0 ? legend_text_vspace : 0);
410 legend_width = double.max (legend_width, title_sz.width + legend_line_length);
411 break;
412 case LegendProcessType.DRAW:
413 heights_idx++;
414 break;
415 }
416 leg_height_sum += title_sz.height + (leg_height_sum != 0 ? legend_text_vspace : 0);
417 break;
418 }
419 }
420
421 // TOP, BOTTOM
422 switch (legend.position) {
423 case Legend.Position.TOP:
424 case Legend.Position.BOTTOM:
425 if (leg_width_sum != 0) {
426 leg_height_sum += max_font_h;
427 switch (process_type) {
428 case LegendProcessType.CALC:
429 max_font_heights += max_font_h;
430 legend_width = double.max(legend_width, leg_width_sum);
431 break;
432 }
433 }
434 break;
435 }
436
437 switch (process_type) {
438 case LegendProcessType.CALC:
439 legend_height = leg_height_sum;
440 switch (legend.position) {
441 case Legend.Position.TOP:
442 cur_y_min += legend_height;
443 break;
444 case Legend.Position.BOTTOM:
445 cur_y_max -= legend_height;
446 break;
447 case Legend.Position.LEFT:
448 cur_x_min += legend_width;
449 break;
450 case Legend.Position.RIGHT:
451 cur_x_max -= legend_width;
452 break;
453 }
454 break;
455 }
456 }
457
458 protected virtual void draw_legend () {
459 process_legend (LegendProcessType.CALC);
460 process_legend (LegendProcessType.DRAW);
461 }
462
463 public LineStyle selection_style = LineStyle ();
464
465 215 public virtual void draw_selection (double x0, double y0, double x1, double y1) {
466 set_line_style (selection_style);
216 selection_style.set(this);
467 217 context.rectangle (x0, y0, x1 - x0, y1 - y0);
468 218 context.stroke();
469 219 }
227 227 switch (axis.type) {
228 228 case Axis.Type.NUMBERS:
229 229 var text = new Text (axis.format.printf((LongDouble)x) + (is_horizontal ? "_" : ""), axis.font_style);
230 var sz = text.size(context);
230 var sz = text.get_size(context);
231 231 max_rec_width = double.max (max_rec_width, sz.width);
232 232 max_rec_height = double.max (max_rec_height, sz.height);
233 233 break;
238 238 var h = 0.0;
239 239 if (axis.date_format != "") {
240 240 var text = new Text (date + (is_horizontal ? "_" : ""), axis.font_style);
241 var sz = text.size(context);
241 var sz = text.get_size(context);
242 242 max_rec_width = double.max (max_rec_width, sz.width);
243 243 h = sz.height;
244 244 }
245 245 if (axis.time_format != "") {
246 246 var text = new Text (time + (is_horizontal ? "_" : ""), axis.font_style);
247 var sz = text.size(context);
247 var sz = text.get_size(context);
248 248 max_rec_width = double.max (max_rec_width, sz.width);
249 249 h += sz.height;
250 250 }
273 273 return step;
274 274 }
275 275
276 public double plot_area_x_min = 0;
277 public double plot_area_x_max = 0;
278 public double plot_area_y_min = 0;
279 public double plot_area_y_max = 0;
276 public double plot_x_min = 0;
277 public double plot_x_max = 0;
278 public double plot_y_min = 0;
279 public double plot_y_max = 0;
280 280
281 public bool common_x_axes { get; protected set; default = false; }
282 public bool common_y_axes { get; protected set; default = false; }
283 public Color common_axis_color = Color (0, 0, 0, 1);
281 public bool joint_x { get; protected set; default = false; }
282 public bool joint_y { get; protected set; default = false; }
283 public Color joint_axis_color = Color (0, 0, 0, 1);
284 284
285 285 bool are_intersect (double a_min, double a_max, double b_min, double b_max) {
286 286 if ( a_min < a_max <= b_min < b_max
292 292 protected virtual void set_vertical_axes_titles () {
293 293 for (var si = 0; si < series.length; ++si) {
294 294 var s = series[si];
295 s.axis_y.title.style.orientation = FontOrient.VERTICAL;
295 s.axis_y.title.style.orientation = Font.Orientation.VERTICAL;
296 296 }
297 297 }
298 298
299 299 protected virtual void calc_plot_area () {
300 plot_area_x_min = cur_x_min + legend.indent;
301 plot_area_x_max = cur_x_max - legend.indent;
302 plot_area_y_min = cur_y_min + legend.indent;
303 plot_area_y_max = cur_y_max - legend.indent;
300 plot_x_min = cur_x_min + legend.indent;
301 plot_x_max = cur_x_max - legend.indent;
302 plot_y_min = cur_y_min + legend.indent;
303 plot_y_max = cur_y_max - legend.indent;
304 304
305 // Check for common axes
306 common_x_axes = common_y_axes = true;
305 // Check for joint axes
306 joint_x = joint_y = true;
307 307 int nzoom_series_show = 0;
308 308 for (var si = series.length - 1; si >=0; --si) {
309 309 var s = series[si];
312 312 if ( s.axis_x.position != series[0].axis_x.position
313 313 || s.axis_x.zoom_min != series[0].axis_x.zoom_min
314 314 || s.axis_x.zoom_max != series[0].axis_x.zoom_max
315 || s.place.zoom_x_low != series[0].place.zoom_x_low
316 || s.place.zoom_x_high != series[0].place.zoom_x_high
315 || s.place.zoom_x_min != series[0].place.zoom_x_min
316 || s.place.zoom_x_max != series[0].place.zoom_x_max
317 317 || s.axis_x.type != series[0].axis_x.type)
318 common_x_axes = false;
318 joint_x = false;
319 319 if ( s.axis_y.position != series[0].axis_y.position
320 320 || s.axis_y.zoom_min != series[0].axis_y.zoom_min
321 321 || s.axis_y.zoom_max != series[0].axis_y.zoom_max
322 || s.place.zoom_y_low != series[0].place.zoom_y_low
323 || s.place.zoom_y_high != series[0].place.zoom_y_high)
324 common_y_axes = false;
322 || s.place.zoom_y_min != series[0].place.zoom_y_min
323 || s.place.zoom_y_max != series[0].place.zoom_y_max)
324 joint_y = false;
325 325 }
326 if (nzoom_series_show == 1) common_x_axes = common_y_axes = false;
326 if (nzoom_series_show == 1) joint_x = joint_y = false;
327 327
328 328 // Join and calc X-axes
329 329 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
343 343 for (int sk = si; sk > sj; --sk) {
344 344 var s3 = series[sk];
345 345 if (!s3.zoom_show) continue;
346 if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
346 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
347 347 || s2.axis_x.position != s3.axis_x.position
348 348 || s2.axis_x.type != s3.axis_x.type) {
349 349 has_intersection = true;
364 364 }
365 365 }
366 366
367 // for 4.2. Cursor values for common X axis
368 if (common_x_axes && si == zoom_first_show && cursors_orientation == CursorOrientation.VERTICAL && cursors_crossings.length != 0) {
367 // for 4.2. Cursor values for joint X axis
368 if (joint_x && si == zoom_first_show && cursor_style.orientation == Cursor.Orientation.VERTICAL && cursors_crossings.length != 0) {
369 369 switch (s.axis_x.position) {
370 case Axis.Position.LOW: plot_area_y_max -= max_rec_height + s.axis_x.font_indent; break;
371 case Axis.Position.HIGH: plot_area_y_min += max_rec_height + s.axis_x.font_indent; break;
370 case Axis.Position.LOW: plot_y_max -= max_rec_height + s.axis_x.font_indent; break;
371 case Axis.Position.HIGH: plot_y_min += max_rec_height + s.axis_x.font_indent; break;
372 372 }
373 373 }
374 374
375 if (!common_x_axes || si == zoom_first_show)
375 if (!joint_x || si == zoom_first_show)
376 376 switch (s.axis_x.position) {
377 case Axis.Position.LOW: plot_area_y_max -= max_rec_height + max_font_indent + max_axis_font_height; break;
378 case Axis.Position.HIGH: plot_area_y_min += max_rec_height + max_font_indent + max_axis_font_height; break;
377 case Axis.Position.LOW: plot_y_max -= max_rec_height + max_font_indent + max_axis_font_height; break;
378 case Axis.Position.HIGH: plot_y_min += max_rec_height + max_font_indent + max_axis_font_height; break;
379 379 }
380 380 }
381 381
397 397 for (int sk = si; sk > sj; --sk) {
398 398 var s3 = series[sk];
399 399 if (!s3.zoom_show) continue;
400 if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
400 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
401 401 || s2.axis_y.position != s3.axis_y.position
402 402 || s2.axis_x.type != s3.axis_x.type) {
403 403 has_intersection = true;
418 418 }
419 419 }
420 420
421 // for 4.2. Cursor values for common Y axis
422 if (common_y_axes && si == zoom_first_show && cursors_orientation == CursorOrientation.HORIZONTAL && cursors_crossings.length != 0) {
421 // for 4.2. Cursor values for joint Y axis
422 if (joint_y && si == zoom_first_show && cursor_style.orientation == Cursor.Orientation.HORIZONTAL && cursors_crossings.length != 0) {
423 423 switch (s.axis_y.position) {
424 case Axis.Position.LOW: plot_area_x_min += max_rec_width + s.axis_y.font_indent; break;
425 case Axis.Position.HIGH: plot_area_x_max -= max_rec_width + s.axis_y.font_indent; break;
424 case Axis.Position.LOW: plot_x_min += max_rec_width + s.axis_y.font_indent; break;
425 case Axis.Position.HIGH: plot_x_max -= max_rec_width + s.axis_y.font_indent; break;
426 426 }
427 427 }
428 428
429 if (!common_y_axes || si == zoom_first_show)
429 if (!joint_y || si == zoom_first_show)
430 430 switch (s.axis_y.position) {
431 case Axis.Position.LOW: plot_area_x_min += max_rec_width + max_font_indent + max_axis_font_width; break;
432 case Axis.Position.HIGH: plot_area_x_max -= max_rec_width + max_font_indent + max_axis_font_width; break;
431 case Axis.Position.LOW: plot_x_min += max_rec_width + max_font_indent + max_axis_font_width; break;
432 case Axis.Position.HIGH: plot_x_max -= max_rec_width + max_font_indent + max_axis_font_width; break;
433 433 }
434 434 }
435 435 }
441 441 }
442 442
443 443 protected virtual double compact_rec_x_pos (Series s, Float128 x, Text text) {
444 var sz = text.size(context);
444 var sz = text.get_size(context);
445 445 return get_scr_x(s, x) - sz.width / 2.0
446 446 - 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);
447 447 }
448 448
449 449 protected virtual double compact_rec_y_pos (Series s, Float128 y, Text text) {
450 var sz = text.size(context);
450 var sz = text.get_size(context);
451 451 return get_scr_y(s, y) + sz.height / 2.0
452 452 + 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);
453 453 }
465 465 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
466 466 var s = series[si];
467 467 if (!s.zoom_show) continue;
468 if (common_x_axes && si != zoom_first_show) continue;
468 if (joint_x && si != zoom_first_show) continue;
469 469
470 470 // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
471 471 double max_rec_width, max_rec_height;
472 472 calc_axis_rec_sizes (s.axis_x, out max_rec_width, out max_rec_height, true);
473 473
474 474 // 2. Calculate maximal available number of records, take into account the space width.
475 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);
475 long max_nrecs = (long) ((plot_x_max - plot_x_min) * (s.place.zoom_x_max - s.place.zoom_x_min) / max_rec_width);
476 476
477 477 // 3. Calculate grid step.
478 478 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);
491 491 }
492 492 if (x_min < s.axis_x.zoom_min) x_min += step;
493 493
494 // 4.2. Cursor values for common X axis
495 if (common_x_axes && cursors_orientation == CursorOrientation.VERTICAL && cursors_crossings.length != 0) {
494 // 4.2. Cursor values for joint X axis
495 if (joint_x && cursor_style.orientation == Cursor.Orientation.VERTICAL && cursors_crossings.length != 0) {
496 496 switch (s.axis_x.position) {
497 497 case Axis.Position.LOW: cur_y_max -= max_rec_height + s.axis_x.font_indent; break;
498 498 case Axis.Position.HIGH: cur_y_min += max_rec_height + s.axis_x.font_indent; break;
499 499 }
500 500 }
501 501
502 var sz = s.axis_x.title.size(context);
502 var sz = s.axis_x.title.get_size(context);
503 503
504 504 // 4.5. Draw Axis title
505 505 if (s.axis_x.title.text != "") {
506 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;
506 var scr_x = plot_x_min + (plot_x_max - plot_x_min) * (s.place.zoom_x_min + s.place.zoom_x_max) / 2.0;
507 507 double scr_y = 0.0;
508 508 switch (s.axis_x.position) {
509 509 case Axis.Position.LOW: scr_y = cur_y_max - s.axis_x.font_indent; break;
511 511 }
512 512 context.move_to(scr_x - sz.width / 2.0, scr_y);
513 513 set_source_rgba(s.axis_x.color);
514 if (common_x_axes) set_source_rgba(common_axis_color);
515 show_text(s.axis_x.title);
514 if (joint_x) set_source_rgba(joint_axis_color);
515 s.axis_x.title.show(context);
516 516 }
517 517
518 518 // 5. Draw records, update cur_{x,y}_{min,max}.
519 519 for (Float128 x = x_min, x_max = s.axis_x.zoom_max; point_belong (x, x_min, x_max); x += step) {
520 if (common_x_axes) set_source_rgba(common_axis_color);
520 if (joint_x) set_source_rgba(joint_axis_color);
521 521 else set_source_rgba(s.axis_x.color);
522 522 string text = "", time_text = "";
523 523 switch (s.axis_x.type) {
537 537 context.move_to (print_x, print_y);
538 538 switch (s.axis_x.type) {
539 539 case Axis.Type.NUMBERS:
540 show_text(text_t);
540 text_t.show(context);
541 541 break;
542 542 case Axis.Type.DATE_TIME:
543 if (s.axis_x.date_format != "") show_text(text_t);
543 if (s.axis_x.date_format != "") text_t.show(context);
544 544 var time_text_t = new Text(time_text, s.axis_x.font_style, s.axis_x.color);
545 545 print_x = compact_rec_x_pos (s, x, time_text_t);
546 546 context.move_to (print_x, print_y - (s.axis_x.date_format == "" ? 0 : text_t.get_height(context) + s.axis_x.font_indent));
547 if (s.axis_x.time_format != "") show_text(time_text_t);
547 if (s.axis_x.time_format != "") time_text_t.show(context);
548 548 break;
549 549 }
550 // 6. Draw grid lines to the s.place.zoom_y_low.
550 // 6. Draw grid lines to the s.place.zoom_y_min.
551 551 var line_style = s.grid.line_style;
552 if (common_x_axes) line_style.color = Color(0, 0, 0, 0.5);
553 set_line_style(line_style);
552 if (joint_x) line_style.color = Color(0, 0, 0, 0.5);
553 line_style.set(this);
554 554 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);
555 555 context.move_to (scr_x, y);
556 if (common_x_axes)
557 context.line_to (scr_x, plot_area_y_min);
556 if (joint_x)
557 context.line_to (scr_x, plot_y_min);
558 558 else
559 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));
559 context.line_to (scr_x, double.min (y, plot_y_max - (plot_y_max - plot_y_min) * s.place.zoom_y_max));
560 560 break;
561 561 case Axis.Position.HIGH:
562 562 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);
565 565
566 566 switch (s.axis_x.type) {
567 567 case Axis.Type.NUMBERS:
568 show_text(text_t);
568 text_t.show(context);
569 569 break;
570 570 case Axis.Type.DATE_TIME:
571 if (s.axis_x.date_format != "") show_text(text_t);
571 if (s.axis_x.date_format != "") text_t.show(context);
572 572 var time_text_t = new Text(time_text, s.axis_x.font_style, s.axis_x.color);
573 573 print_x = compact_rec_x_pos (s, x, time_text_t);
574 574 context.move_to (print_x, print_y - (s.axis_x.date_format == "" ? 0 : text_t.get_height(context) + s.axis_x.font_indent));
575 if (s.axis_x.time_format != "") show_text(time_text_t);
575 if (s.axis_x.time_format != "") time_text_t.show(context);
576 576 break;
577 577 }
578 // 6. Draw grid lines to the s.place.zoom_y_high.
578 // 6. Draw grid lines to the s.place.zoom_y_max.
579 579 var line_style = s.grid.line_style;
580 if (common_x_axes) line_style.color = Color(0, 0, 0, 0.5);
581 set_line_style(line_style);
580 if (joint_x) line_style.color = Color(0, 0, 0, 0.5);
581 line_style.set(this);
582 582 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);
583 583 context.move_to (scr_x, y);
584 if (common_x_axes)
585 context.line_to (scr_x, plot_area_y_max);
584 if (joint_x)
585 context.line_to (scr_x, plot_y_max);
586 586 else
587 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));
587 context.line_to (scr_x, double.max (y, plot_y_max - (plot_y_max - plot_y_min) * s.place.zoom_y_min));
588 588 break;
589 589 }
590 590 }
598 598 for (int sk = si; sk > sj; --sk) {
599 599 var s3 = series[sk];
600 600 if (!s3.zoom_show) continue;
601 if (are_intersect(s2.place.zoom_x_low, s2.place.zoom_x_high, s3.place.zoom_x_low, s3.place.zoom_x_high)
601 if (are_intersect(s2.place.zoom_x_min, s2.place.zoom_x_max, s3.place.zoom_x_min, s3.place.zoom_x_max)
602 602 || s2.axis_x.position != s3.axis_x.position
603 603 || s2.axis_x.type != s3.axis_x.type) {
604 604 has_intersection = true;
631 631 for (var si = series.length - 1, nskip = 0; si >=0; --si) {
632 632 var s = series[si];
633 633 if (!s.zoom_show) continue;
634 if (common_y_axes && si != zoom_first_show) continue;
634 if (joint_y && si != zoom_first_show) continue;
635 635 // 1. Detect max record width/height by axis_rec_npoints equally selected points using format.
636 636 double max_rec_width, max_rec_height;
637 637 calc_axis_rec_sizes (s.axis_y, out max_rec_width, out max_rec_height, false);
638 638
639 639 // 2. Calculate maximal available number of records, take into account the space width.
640 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);
640 long max_nrecs = (long) ((plot_y_max - plot_y_min) * (s.place.zoom_y_max - s.place.zoom_y_min) / max_rec_height);
641 641
642 642 // 3. Calculate grid step.
643 643 Float128 step = calc_round_step ((s.axis_y.zoom_max - s.axis_y.zoom_min) / max_nrecs);
656 656 }
657 657 if (y_min < s.axis_y.zoom_min) y_min += step;
658 658
659 // 4.2. Cursor values for common Y axis
660 if (common_y_axes && cursors_orientation == CursorOrientation.HORIZONTAL && cursors_crossings.length != 0) {
659 // 4.2. Cursor values for joint Y axis
660 if (joint_y && cursor_style.orientation == Cursor.Orientation.HORIZONTAL && cursors_crossings.length != 0) {
661 661 switch (s.axis_y.position) {
662 662 case Axis.Position.LOW: cur_x_min += max_rec_width + s.axis_y.font_indent; break;
663 663 case Axis.Position.HIGH: cur_x_max -= max_rec_width + s.axis_y.font_indent; break;
664 664 }
665 665 }
666 666
667 var sz = s.axis_y.title.size(context);
667 var sz = s.axis_y.title.get_size(context);
668 668
669 669 // 4.5. Draw Axis title
670 670 if (s.axis_y.title.text != "") {
671 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;
671 var scr_y = plot_y_max - (plot_y_max - plot_y_min) * (s.place.zoom_y_min + s.place.zoom_y_max) / 2.0;
672 672 switch (s.axis_y.position) {
673 673 case Axis.Position.LOW:
674 674 var scr_x = cur_x_min + s.axis_y.font_indent + sz.width;
680 680 break;
681 681 }
682 682 set_source_rgba(s.axis_y.color);
683 if (common_y_axes) set_source_rgba(common_axis_color);
684 show_text(s.axis_y.title);
683 if (joint_y) set_source_rgba(joint_axis_color);
684 s.axis_y.title.show(context);
685 685 }
686 686
687 687 // 5. Draw records, update cur_{x,y}_{min,max}.
688 688 for (Float128 y = y_min, y_max = s.axis_y.zoom_max; point_belong (y, y_min, y_max); y += step) {
689 if (common_y_axes) set_source_rgba(common_axis_color);
689 if (joint_y) set_source_rgba(joint_axis_color);
690 690 else set_source_rgba(s.axis_y.color);
691 691 var text = s.axis_y.format.printf((LongDouble)y);
692 692 var scr_y = get_scr_y (s, y);
693 693 var text_t = new Text(text, s.axis_y.font_style, s.axis_y.color);
694 var text_sz = text_t.size(context);
694 var text_sz = text_t.get_size(context);
695 695 switch (s.axis_y.position) {
696 696 case Axis.Position.LOW:
697 697 context.move_to (cur_x_min + max_rec_width - text_sz.width + s.axis_y.font_indent
698 698 + (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent),
699 699 compact_rec_y_pos (s, y, text_t));
700 show_text(text_t);
701 // 6. Draw grid lines to the s.place.zoom_x_low.
700 text_t.show(context);
701 // 6. Draw grid lines to the s.place.zoom_x_min.
702 702 var line_style = s.grid.line_style;
703 if (common_y_axes) line_style.color = Color(0, 0, 0, 0.5);
704 set_line_style(line_style);
703 if (joint_y) line_style.color = Color(0, 0, 0, 0.5);
704 line_style.set(this);
705 705 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);
706 706 context.move_to (x, scr_y);
707 if (common_y_axes)
708 context.line_to (plot_area_x_max, scr_y);
707 if (joint_y)
708 context.line_to (plot_x_max, scr_y);
709 709 else
710 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);
710 context.line_to (double.max (x, plot_x_min + (plot_x_max - plot_x_min) * s.place.zoom_x_max), scr_y);
711 711 break;
712 712 case Axis.Position.HIGH:
713 713 context.move_to (cur_x_max - text_sz.width - s.axis_y.font_indent
714 714 - (s.axis_y.title.text == "" ? 0 : sz.width + s.axis_y.font_indent),
715 715 compact_rec_y_pos (s, y, text_t));
716 show_text(text_t);
717 // 6. Draw grid lines to the s.place.zoom_x_high.
716 text_t.show(context);
717 // 6. Draw grid lines to the s.place.zoom_x_max.
718 718 var line_style = s.grid.line_style;
719 if (common_y_axes) line_style.color = Color(0, 0, 0, 0.5);
720 set_line_style(line_style);
719 if (joint_y) line_style.color = Color(0, 0, 0, 0.5);
720 line_style.set(this);
721 721 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);
722 722 context.move_to (x, scr_y);
723 if (common_y_axes)
724 context.line_to (plot_area_x_min, scr_y);
723 if (joint_y)
724 context.line_to (plot_x_min, scr_y);
725 725 else
726 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);
726 context.line_to (double.min (x, plot_x_min + (plot_x_max - plot_x_min) * s.place.zoom_x_min), scr_y);
727 727 break;
728 728 }
729 729 }
737 737 for (int sk = si; sk > sj; --sk) {
738 738 var s3 = series[sk];
739 739 if (!s3.zoom_show) continue;
740 if (are_intersect(s2.place.zoom_y_low, s2.place.zoom_y_high, s3.place.zoom_y_low, s3.place.zoom_y_high)
740 if (are_intersect(s2.place.zoom_y_min, s2.place.zoom_y_max, s3.place.zoom_y_min, s3.place.zoom_y_max)
741 741 || s2.axis_y.position != s3.axis_y.position) {
742 742 has_intersection = true;
743 743 break;
766 766 protected virtual void draw_plot_area_border () {
767 767 set_source_rgba (border_color);
768 768 context.set_dash(null, 0);
769 context.move_to (plot_area_x_min, plot_area_y_min);
770 context.line_to (plot_area_x_min, plot_area_y_max);
771 context.line_to (plot_area_x_max, plot_area_y_max);
772 context.line_to (plot_area_x_max, plot_area_y_min);
773 context.line_to (plot_area_x_min, plot_area_y_min);
769 context.move_to (plot_x_min, plot_y_min);
770 context.line_to (plot_x_min, plot_y_max);
771 context.line_to (plot_x_max, plot_y_max);
772 context.line_to (plot_x_max, plot_y_min);
773 context.line_to (plot_x_min, plot_y_min);
774 774 context.stroke ();
775 775 }
776 776
777 777 protected virtual double get_scr_x (Series s, Float128 x) {
778 return plot_area_x_min + (plot_area_x_max - plot_area_x_min) * (s.place.zoom_x_low + (x - s.axis_x.zoom_min)
779 / (s.axis_x.zoom_max - s.axis_x.zoom_min) * (s.place.zoom_x_high - s.place.zoom_x_low));
778 return plot_x_min + (plot_x_max - plot_x_min) * (s.place.zoom_x_min + (x - s.axis_x.zoom_min)
779 / (s.axis_x.zoom_max - s.axis_x.zoom_min) * (s.place.zoom_x_max - s.place.zoom_x_min));
780 780 }
781 781
782 782 protected virtual double get_scr_y (Series s, Float128 y) {
783 return plot_area_y_max - (plot_area_y_max - plot_area_y_min) * (s.place.zoom_y_low + (y - s.axis_y.zoom_min)
784 / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_high - s.place.zoom_y_low));
783 return plot_y_max - (plot_y_max - plot_y_min) * (s.place.zoom_y_min + (y - s.axis_y.zoom_min)
784 / (s.axis_y.zoom_max - s.axis_y.zoom_min) * (s.place.zoom_y_max - s.place.zoom_y_min));
785 785 }
786 786 protected virtual Point get_scr_point (Series s, Point p) {
787 787 return Point (get_scr_x(s, p.x), get_scr_y(s, p.y));
788 788 }
789 789
790 790 protected virtual Float128 get_real_x (Series s, double scr_x) {
791 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)
792 * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_high - s.place.zoom_x_low);
791 return s.axis_x.zoom_min + ((scr_x - plot_x_min) / (plot_x_max - plot_x_min) - s.place.zoom_x_min)
792 * (s.axis_x.zoom_max - s.axis_x.zoom_min) / (s.place.zoom_x_max - s.place.zoom_x_min);
793 793 }
794 794 protected virtual Float128 get_real_y (Series s, double scr_y) {
795 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)
796 * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_high - s.place.zoom_y_low);
795 return s.axis_y.zoom_min + ((plot_y_max - scr_y) / (plot_y_max - plot_y_min) - s.place.zoom_y_min)
796 * (s.axis_y.zoom_max - s.axis_y.zoom_min) / (s.place.zoom_y_max - s.place.zoom_y_min);
797 797 }
798 798 protected virtual Point get_real_point (Series s, Point p) {
799 799 return Point (get_real_x(s, p.x), get_real_y(s, p.y));
812 812 }
813 813
814 814 protected virtual bool x_in_plot_area (double x) {
815 if (x_in_range(x, plot_area_x_min, plot_area_x_max))
815 if (x_in_range(x, plot_x_min, plot_x_max))
816 816 return true;
817 817 return false;
818 818 }
819 819
820 820 protected virtual bool y_in_plot_area (double y) {
821 if (y_in_range(y, plot_area_y_min, plot_area_y_max))
821 if (y_in_range(y, plot_y_min, plot_y_max))
822 822 return true;
823 823 return false;
824 824 }
830 830 }
831 831
832 832 protected virtual bool point_in_plot_area (Point p) {
833 if (point_in_rect (p, plot_area_x_min, plot_area_x_max, plot_area_y_min, plot_area_y_max))
833 if (point_in_rect (p, plot_x_min, plot_x_max, plot_y_min, plot_y_max))
834 834 return true;
835 835 return false;
836 836 }
872 872 int ncross = 0;
873 873 Float128 x = 0, y = 0;
874 874 Point pc[4];
875 if (hcross(a, b, plot_area_x_min, plot_area_x_max, plot_area_y_min, out x))
876 pc[ncross++] = Point(x, plot_area_y_min);
877 if (hcross(a, b, plot_area_x_min, plot_area_x_max, plot_area_y_max, out x))
878 pc[ncross++] = Point(x, plot_area_y_max);
879 if (vcross(a, b, plot_area_x_min, plot_area_y_min, plot_area_y_max, out y))
880 pc[ncross++] = Point(plot_area_x_min, y);
881 if (vcross(a, b, plot_area_x_max, plot_area_y_min, plot_area_y_max, out y))
882 pc[ncross++] = Point(plot_area_x_max, y);
875 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_min, out x))
876 pc[ncross++] = Point(x, plot_y_min);
877 if (hcross(a, b, plot_x_min, plot_x_max, plot_y_max, out x))
878 pc[ncross++] = Point(x, plot_y_max);
879 if (vcross(a, b, plot_x_min, plot_y_min, plot_y_max, out y))
880 pc[ncross++] = Point(plot_x_min, y);
881 if (vcross(a, b, plot_x_max, plot_y_min, plot_y_max, out y))
882 pc[ncross++] = Point(plot_x_max, y);
883 883 c = a;
884 884 d = b;
885 885 if (ncross == 0) {
932 932 if (!s.zoom_show) continue;
933 933 if (s.points.length == 0) continue;
934 934 var points = sort_points(s, s.sort);
935 set_line_style(s.line_style);
935 s.line_style.set(this);
936 936 // draw series line
937 937 for (int i = 1; i < points.length; ++i) {
938 938 Point c, d;
948 948 var x = get_scr_x(s, points[i].x);
949 949 var y = get_scr_y(s, points[i].y);
950 950 if (point_in_plot_area (Point (x, y)))
951 draw_marker_at_pos(s.marker_type, x, y);
951 s.marker.draw_at_pos(this, x, y);
952 952 }
953 953 }
954 954 }
967 967 is_cursor_active = false;
968 968 }
969 969
970 public enum CursorOrientation {
971 VERTICAL = 0, // default
972 HORIZONTAL
973 }
970 public Cursor.Style cursor_style = Cursor.Style();
974 971
975 public CursorOrientation cursors_orientation = CursorOrientation.VERTICAL;
976
977 public double cursor_max_rm_distance = 32;
978
979 972 public virtual void remove_active_cursor () {
980 973 if (cursors.length() == 0) return;
981 974 var distance = width * width;
976 976 uint i = 0;
977 977 foreach (var c in cursors) {
978 978 double d = distance;
979 switch (cursors_orientation) {
980 case CursorOrientation.VERTICAL:
979 switch (cursor_style.orientation) {
980 case Cursor.Orientation.VERTICAL:
981 981 d = (rel2scr_x(c.x) - rel2scr_x(active_cursor.x)).abs();
982 982 break;
983 case CursorOrientation.HORIZONTAL:
983 case Cursor.Orientation.HORIZONTAL:
984 984 d = (rel2scr_y(c.y) - rel2scr_y(active_cursor.y)).abs();
985 985 break;
986 986 }
990 990 }
991 991 ++i;
992 992 }
993 if (distance < cursor_max_rm_distance)
993 if (distance < cursor_style.select_distance)
994 994 cursors.delete_link(cursors.nth(rm_indx));
995 995 is_cursor_active = false;
996 996 }
997 997
998 998 protected virtual Float128 scr2rel_x (Float128 x) {
999 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);
999 return rz_x_min + (x - plot_x_min) / (plot_x_max - plot_x_min) * (rz_x_max - rz_x_min);
1000 1000 }
1001 1001 protected virtual Float128 scr2rel_y (Float128 y) {
1002 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);
1002 return rz_y_max - (plot_y_max - y) / (plot_y_max - plot_y_min) * (rz_y_max - rz_y_min);
1003 1003 }
1004 1004 protected virtual Point scr2rel_point (Point p) {
1005 1005 return Point (scr2rel_x(p.x), scr2rel_y(p.y));
1006 1006 }
1007 1007
1008 1008 protected virtual Float128 rel2scr_x(Float128 x) {
1009 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);
1009 return plot_x_min + (plot_x_max - plot_x_min) * (x - rz_x_min) / (rz_x_max - rz_x_min);
1010 1010 }
1011 1011
1012 1012 protected virtual Float128 rel2scr_y(Float128 y) {
1013 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);
1013 return plot_y_min + (plot_y_max - plot_y_min) * (y - rz_y_min) / (rz_y_max - rz_y_min);
1014 1014 }
1015 1015
1016 1016 protected virtual Point rel2scr_point (Point p) {
1017 1017 return Point (rel2scr_x(p.x), rel2scr_y(p.y));
1018 1018 }
1019 1019
1020 public LineStyle cursor_line_style = LineStyle(Color(0.2, 0.2, 0.2, 0.8));
1021
1022 1020 protected struct CursorCross {
1023 1021 uint series_index;
1024 1022 Point point;
1049 1049
1050 1050 for (var ci = 0, max_ci = all_cursors.length(); ci < max_ci; ++ci) {
1051 1051 var c = all_cursors.nth_data(ci);
1052 switch (cursors_orientation) {
1053 case CursorOrientation.VERTICAL:
1054 if (c.x <= rel_zoom_x_min || c.x >= rel_zoom_x_max) continue; break;
1055 case CursorOrientation.HORIZONTAL:
1056 if (c.y <= rel_zoom_y_min || c.y >= rel_zoom_y_max) continue; break;
1052 switch (cursor_style.orientation) {
1053 case Cursor.Orientation.VERTICAL:
1054 if (c.x <= rz_x_min || c.x >= rz_x_max) continue; break;
1055 case Cursor.Orientation.HORIZONTAL:
1056 if (c.y <= rz_y_min || c.y >= rz_y_max) continue; break;
1057 1057 }
1058 1058
1059 1059 CursorCross[] crossings = {};
1062 1062 if (!s.zoom_show) continue;
1063 1063
1064 1064 Point[] points = {};
1065 switch (cursors_orientation) {
1066 case CursorOrientation.VERTICAL:
1065 switch (cursor_style.orientation) {
1066 case Cursor.Orientation.VERTICAL:
1067 1067 points = sort_points (s, s.sort);
1068 1068 break;
1069 case CursorOrientation.HORIZONTAL:
1069 case Cursor.Orientation.HORIZONTAL:
1070 1070 points = sort_points (s, s.sort);
1071 1071 break;
1072 1072 }
1073 1073
1074 1074 for (var i = 0; i + 1 < points.length; ++i) {
1075 switch (cursors_orientation) {
1076 case CursorOrientation.VERTICAL:
1075 switch (cursor_style.orientation) {
1076 case Cursor.Orientation.VERTICAL:
1077 1077 Float128 y = 0.0;
1078 1078 if (vcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]), rel2scr_x(c.x),
1079 plot_area_y_min, plot_area_y_max, out y)) {
1079 plot_y_min, plot_y_max, out y)) {
1080 1080 var point = Point(get_real_x(s, rel2scr_x(c.x)), get_real_y(s, y));
1081 1081 Point size; bool show_x, show_date, show_time, show_y;
1082 1082 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
1085 1085 crossings += cc;
1086 1086 }
1087 1087 break;
1088 case CursorOrientation.HORIZONTAL:
1088 case Cursor.Orientation.HORIZONTAL:
1089 1089 Float128 x = 0.0;
1090 1090 if (hcross(get_scr_point(s, points[i]), get_scr_point(s, points[i+1]),
1091 plot_area_x_min, plot_area_x_max, rel2scr_y(c.y), out x)) {
1091 plot_x_min, plot_x_max, rel2scr_y(c.y), out x)) {
1092 1092 var point = Point(get_real_x(s, x), get_real_y(s, rel2scr_y(c.y)));
1093 1093 Point size; bool show_x, show_date, show_time, show_y;
1094 1094 cross_what_to_show(s, out show_x, out show_time, out show_date, out show_y);
1123 1123 protected virtual void cross_what_to_show (Series s, out bool show_x, out bool show_time,
1124 1124 out bool show_date, out bool show_y) {
1125 1125 show_x = show_time = show_date = show_y = false;
1126 switch (cursors_orientation) {
1127 case CursorOrientation.VERTICAL:
1126 switch (cursor_style.orientation) {
1127 case Cursor.Orientation.VERTICAL:
1128 1128 show_y = true;
1129 if (!common_x_axes)
1129 if (!joint_x)
1130 1130 switch (s.axis_x.type) {
1131 1131 case Axis.Type.NUMBERS: show_x = true; break;
1132 1132 case Axis.Type.DATE_TIME:
1135 1135 break;
1136 1136 }
1137 1137 break;
1138 case CursorOrientation.HORIZONTAL:
1139 if (!common_y_axes) show_y = true;
1138 case Cursor.Orientation.HORIZONTAL:
1139 if (!joint_y) show_y = true;
1140 1140 switch (s.axis_x.type) {
1141 1141 case Axis.Type.NUMBERS: show_x = true; break;
1142 1142 case Axis.Type.DATE_TIME:
1161 1161 var x_t = new Text (s.axis_x.format.printf((LongDouble)p.x), s.axis_x.font_style, s.axis_x.color);
1162 1162 var y_t = new Text (s.axis_y.format.printf((LongDouble)p.y), s.axis_y.font_style, s.axis_y.color);
1163 1163 double h_x = 0.0, h_y = 0.0;
1164 if (show_x) { var sz = x_t.size(context); size.x = sz.width; h_x = sz.height; }
1165 if (show_date) { var sz = date_t.size(context); size.x = sz.width; h_x = sz.height; }
1166 if (show_time) { var sz = time_t.size(context); size.x = double.max(size.x, sz.width); h_x += sz.height; }
1167 if (show_y) { var sz = y_t.size(context); size.x += sz.width; h_y = sz.height; }
1164 if (show_x) { var sz = x_t.get_size(context); size.x = sz.width; h_x = sz.height; }
1165 if (show_date) { var sz = date_t.get_size(context); size.x = sz.width; h_x = sz.height; }
1166 if (show_time) { var sz = time_t.get_size(context); size.x = double.max(size.x, sz.width); h_x += sz.height; }
1167 if (show_y) { var sz = y_t.get_size(context); size.x += sz.width; h_y = sz.height; }
1168 1168 if ((show_x || show_date || show_time) && show_y) size.x += double.max(s.axis_x.font_indent, s.axis_y.font_indent);
1169 1169 if (show_date && show_time) h_x += s.axis_x.font_indent;
1170 1170 size.y = double.max (h_x, h_y);
1177 1177 calc_cursors_value_positions();
1178 1178
1179 1179 for (var cci = 0, max_cci = cursors_crossings.length; cci < max_cci; ++cci) {
1180 var low = Point(plot_area_x_max, plot_area_y_max); // low and high
1181 var high = Point(plot_area_x_min, plot_area_y_min); // points of the cursor
1180 var low = Point(plot_x_max, plot_y_max); // low and high
1181 var high = Point(plot_x_min, plot_y_min); // points of the cursor
1182 1182 unowned CursorCross[] ccs = cursors_crossings[cci].crossings;
1183 set_line_style(cursor_line_style);
1183 cursor_style.line_style.set(this);
1184 1184 for (var ci = 0, max_ci = ccs.length; ci < max_ci; ++ci) {
1185 1185 var si = ccs[ci].series_index;
1186 1186 var s = series[si];
1192 1192 if (scrx > high.x) high.x = scrx;
1193 1193 if (scry > high.y) high.y = scry;
1194 1194
1195 if (common_x_axes) {
1195 if (joint_x) {
1196 1196 switch (s.axis_x.position) {
1197 case Axis.Position.LOW: high.y = plot_area_y_max + s.axis_x.font_indent; break;
1198 case Axis.Position.HIGH: low.y = plot_area_y_min - s.axis_x.font_indent; break;
1197 case Axis.Position.LOW: high.y = plot_y_max + s.axis_x.font_indent; break;
1198 case Axis.Position.HIGH: low.y = plot_y_min - s.axis_x.font_indent; break;
1199 1199 case Axis.Position.BOTH:
1200 high.y = plot_area_y_max + s.axis_x.font_indent;
1201 low.y = plot_area_y_min - s.axis_x.font_indent;
1200 high.y = plot_y_max + s.axis_x.font_indent;
1201 low.y = plot_y_min - s.axis_x.font_indent;
1202 1202 break;
1203 1203 }
1204 1204 }
1205 if (common_y_axes) {
1205 if (joint_y) {
1206 1206 switch (s.axis_y.position) {
1207 case Axis.Position.LOW: low.x = plot_area_x_min - s.axis_y.font_indent; break;
1208 case Axis.Position.HIGH: high.x = plot_area_x_max + s.axis_y.font_indent; break;
1207 case Axis.Position.LOW: low.x = plot_x_min - s.axis_y.font_indent; break;
1208 case Axis.Position.HIGH: high.x = plot_x_max + s.axis_y.font_indent; break;
1209 1209 case Axis.Position.BOTH:
1210 low.x = plot_area_x_min - s.axis_y.font_indent;
1211 high.x = plot_area_x_max + s.axis_y.font_indent;
1210 low.x = plot_x_min - s.axis_y.font_indent;
1211 high.x = plot_x_max + s.axis_y.font_indent;
1212 1212 break;
1213 1213 }
1214 1214 }
1219 1219
1220 1220 var c = all_cursors.nth_data(cursors_crossings[cci].cursor_index);
1221 1221
1222 switch (cursors_orientation) {
1223 case CursorOrientation.VERTICAL:
1222 switch (cursor_style.orientation) {
1223 case Cursor.Orientation.VERTICAL:
1224 1224 if (low.y > high.y) continue;
1225 1225 context.move_to (rel2scr_x(c.x), low.y);
1226 1226 context.line_to (rel2scr_x(c.x), high.y);
1227 1227
1228 // show common X value
1229 if (common_x_axes) {
1228 // show joint X value
1229 if (joint_x) {
1230 1230 var s = series[zoom_first_show];
1231 1231 var x = get_real_x(s, rel2scr_x(c.x));
1232 1232 string text = "", time_text = "";
1241 1241 break;
1242 1242 }
1243 1243 var text_t = new Text(text, s.axis_x.font_style, s.axis_x.color);
1244 var sz = text_t.size(context);
1244 var sz = text_t.get_size(context);
1245 1245 var time_text_t = new Text(time_text, s.axis_x.font_style, s.axis_x.color);
1246 1246 var print_y = 0.0;
1247 1247 switch (s.axis_x.position) {
1248 1248 case Axis.Position.LOW: print_y = y_min + height - s.axis_x.font_indent
1249 - (legend.position == Legend.Position.BOTTOM ? legend_height : 0);
1249 - (legend.position == Legend.Position.BOTTOM ? legend.height : 0);
1250 1250 break;
1251 1251 case Axis.Position.HIGH: print_y = y_min + title_height + s.axis_x.font_indent
1252 + (legend.position == Legend.Position.TOP ? legend_height : 0);
1252 + (legend.position == Legend.Position.TOP ? legend.height : 0);
1253 1253 switch (s.axis_x.type) {
1254 1254 case Axis.Type.NUMBERS:
1255 1255 print_y += sz.height;
1267 1267
1268 1268 switch (s.axis_x.type) {
1269 1269 case Axis.Type.NUMBERS:
1270 show_text(text_t);
1270 text_t.show(context);
1271 1271 break;
1272 1272 case Axis.Type.DATE_TIME:
1273 if (s.axis_x.date_format != "") show_text(text_t);
1273 if (s.axis_x.date_format != "") text_t.show(context);
1274 1274 print_x = compact_rec_x_pos (s, x, time_text_t);
1275 1275 context.move_to (print_x, print_y - (s.axis_x.date_format == "" ? 0 : sz.height + s.axis_x.font_indent));
1276 if (s.axis_x.time_format != "") show_text(time_text_t);
1276 if (s.axis_x.time_format != "") time_text_t.show(context);
1277 1277 break;
1278 1278 }
1279 1279 }
1280 1280 break;
1281 case CursorOrientation.HORIZONTAL:
1281 case Cursor.Orientation.HORIZONTAL:
1282 1282 if (low.x > high.x) continue;
1283 1283 context.move_to (low.x, rel2scr_y(c.y));
1284 1284 context.line_to (high.x, rel2scr_y(c.y));
1285 1285
1286 // show common Y value
1287 if (common_y_axes) {
1286 // show joint Y value
1287 if (joint_y) {
1288 1288 var s = series[zoom_first_show];
1289 1289 var y = get_real_y(s, rel2scr_y(c.y));
1290 1290 var text_t = new Text(s.axis_y.format.printf((LongDouble)y, s.axis_y.font_style));
1293 1293 switch (s.axis_y.position) {
1294 1294 case Axis.Position.LOW:
1295 1295 print_x = x_min + s.axis_y.font_indent
1296 + (legend.position == Legend.Position.LEFT ? legend_width : 0);
1296 + (legend.position == Legend.Position.LEFT ? legend.width : 0);
1297 1297 break;
1298 1298 case Axis.Position.HIGH:
1299 1299 print_x = x_min + width - text_t.get_width(context) - s.axis_y.font_indent
1300 - (legend.position == Legend.Position.RIGHT ? legend_width : 0);
1300 - (legend.position == Legend.Position.RIGHT ? legend.width : 0);
1301 1301 break;
1302 1302 }
1303 1303 context.move_to (print_x, print_y);
1304 show_text(text_t);
1304 text_t.show(context);
1305 1305 }
1306 1306 break;
1307 1307 }
1327 1327 set_source_rgba(s.axis_x.color);
1328 1328 var text_t = new Text(s.axis_x.format.printf((LongDouble)point.x), s.axis_x.font_style);
1329 1329 context.move_to (svp.x - size.x / 2, svp.y + text_t.get_height(context) / 2);
1330 if (common_x_axes) set_source_rgba (common_axis_color);
1331 show_text(text_t);
1330 if (joint_x) set_source_rgba (joint_axis_color);
1331 text_t.show(context);
1332 1332 }
1333 1333
1334 1334 if (show_time) {
1336 1336 string date = "", time = "";
1337 1337 format_date_time(s.axis_x, point.x, out date, out time);
1338 1338 var text_t = new Text(time, s.axis_x.font_style);
1339 var sz = text_t.size(context);
1339 var sz = text_t.get_size(context);
1340 1340 var y = svp.y + sz.height / 2;
1341 1341 if (show_date) y -= sz.height / 2 + s.axis_x.font_indent / 2;
1342 1342 context.move_to (svp.x - size.x / 2, y);
1343 if (common_x_axes) set_source_rgba (common_axis_color);
1344 show_text(text_t);
1343 if (joint_x) set_source_rgba (joint_axis_color);
1344 text_t.show(context);
1345 1345 }
1346 1346
1347 1347 if (show_date) {
1349 1349 string date = "", time = "";
1350 1350 format_date_time(s.axis_x, point.x, out date, out time);
1351 1351 var text_t = new Text(date, s.axis_x.font_style);
1352 var sz = text_t.size(context);
1352 var sz = text_t.get_size(context);
1353 1353 var y = svp.y + sz.height / 2;
1354 1354 if (show_time) y += sz.height / 2 + s.axis_x.font_indent / 2;
1355 1355 context.move_to (svp.x - size.x / 2, y);
1356 if (common_x_axes) set_source_rgba (common_axis_color);
1357 show_text(text_t);
1356 if (joint_x) set_source_rgba (joint_axis_color);
1357 text_t.show(context);
1358 1358 }
1359 1359
1360 1360 if (show_y) {
1361 1361 set_source_rgba(s.axis_y.color);
1362 1362 var text_t = new Text(s.axis_y.format.printf((LongDouble)point.y), s.axis_y.font_style);
1363 var sz = text_t.size(context);
1363 var sz = text_t.get_size(context);
1364 1364 context.move_to (svp.x + size.x / 2 - sz.width, svp.y + sz.height / 2);
1365 if (common_y_axes) set_source_rgba (common_axis_color);
1366 show_text(text_t);
1365 if (joint_y) set_source_rgba (joint_axis_color);
1366 text_t.show(context);
1367 1367 }
1368 1368 }
1369 1369 }
1373 1373 delta = 0.0;
1374 1374 if (series.length == 0) return false;
1375 1375 if (cursors.length() + (is_cursor_active ? 1 : 0) != 2) return false;
1376 if (common_x_axes && cursors_orientation == CursorOrientation.VERTICAL) {
1376 if (joint_x && cursor_style.orientation == Cursor.Orientation.VERTICAL) {
1377 1377 Float128 val1 = get_real_x (series[zoom_first_show], rel2scr_x(cursors.nth_data(0).x));
1378 1378 Float128 val2 = 0;
1379 1379 if (is_cursor_active)
1386 1386 delta = val1 - val2;
1387 1387 return true;
1388 1388 }
1389 if (common_y_axes && cursors_orientation == CursorOrientation.HORIZONTAL) {
1389 if (joint_y && cursor_style.orientation == Cursor.Orientation.HORIZONTAL) {
1390 1390 Float128 val1 = get_real_y (series[zoom_first_show], rel2scr_y(cursors.nth_data(0).y));
1391 1391 Float128 val2 = 0;
1392 1392 if (is_cursor_active)
1407 1407 if (!get_cursors_delta(out delta)) return "";
1408 1408 var str = "";
1409 1409 var s = series[zoom_first_show];
1410 if (common_x_axes)
1410 if (joint_x)
1411 1411 switch (s.axis_x.type) {
1412 1412 case Axis.Type.NUMBERS:
1413 1413 str = s.axis_x.format.printf((LongDouble)delta);
1419 1419 str = days.to_string() + " + " + time;
1420 1420 break;
1421 1421 }
1422 if (common_y_axes) {
1422 if (joint_y) {
1423 1423 str = s.axis_y.format.printf((LongDouble)delta);
1424 1424 }
1425 1425 return str;
1431 1431 chart.axis_rec_npoints = this.axis_rec_npoints;
1432 1432 chart.bg_color = this.bg_color;
1433 1433 chart.border_color = this.border_color;
1434 chart.common_x_axes = this.common_x_axes;
1435 chart.common_y_axes = this.common_y_axes;
1434 chart.joint_x = this.joint_x;
1435 chart.joint_y = this.joint_y;
1436 1436 chart.context = this.context;
1437 1437 chart.cur_x_max = this.cur_x_max;
1438 1438 chart.cur_x_min = this.cur_x_min;
1439 1439 chart.cur_y_max = this.cur_y_max;
1440 1440 chart.cur_y_min = this.cur_y_min;
1441 chart.cursor_line_style = this.cursor_line_style;
1442 chart.cursor_max_rm_distance = this.cursor_max_rm_distance;
1441 chart.cursor_style = this.cursor_style;
1443 1442 chart.cursors = this.cursors.copy();
1444 1443 chart.cursors_crossings = this.cursors_crossings;
1445 chart.cursors_orientation = this.cursors_orientation;
1446 1444 chart.height = this.height;
1447 1445 chart.is_cursor_active = this.is_cursor_active;
1448 1446 chart.legend = this.legend.copy();
1449 chart.legend_height = this.legend_height;
1450 chart.legend_line_length = this.legend_line_length;
1451 chart.legend_text_hspace = this.legend_text_hspace;
1452 chart.legend_text_vspace = this.legend_text_vspace;
1453 chart.legend_width = this.legend_width;
1454 chart.marker_size = this.marker_size;
1455 chart.max_font_heights = this.max_font_heights;
1456 chart.plot_area_x_max = this.plot_area_x_max;
1457 chart.plot_area_x_min = this.plot_area_x_min;
1458 chart.plot_area_y_max = this.plot_area_y_max;
1459 chart.plot_area_y_min = this.plot_area_y_min;
1460 chart.rel_zoom_x_min = this.rel_zoom_x_min;
1461 chart.rel_zoom_x_max = this.rel_zoom_x_max;
1462 chart.rel_zoom_y_min = this.rel_zoom_y_min;
1463 chart.rel_zoom_y_max = this.rel_zoom_y_max;
1447 chart.plot_x_max = this.plot_x_max;
1448 chart.plot_x_min = this.plot_x_min;
1449 chart.plot_y_max = this.plot_y_max;
1450 chart.plot_y_min = this.plot_y_min;
1451 chart.rz_x_min = this.rz_x_min;
1452 chart.rz_x_max = this.rz_x_max;
1453 chart.rz_y_min = this.rz_y_min;
1454 chart.rz_y_max = this.rz_y_max;
1464 1455 chart.selection_style = this.selection_style;
1465 1456 chart.series = this.series;
1466 chart.show_legend = this.show_legend;
1467 1457 chart.title = this.title.copy();
1468 1458 chart.title_height = this.title_height;
1469 chart.title_vindent = this.title_vindent;
1459 chart.title_indent = this.title_indent;
1470 1460 chart.title_width = this.title_width;
1471 1461 chart.width = this.width;
1472 1462 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 border_style.set(chart);
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 s.title.show(chart.context);
149
150 // series line style
151 chart.context.move_to (x, y - title_sz.height / 2);
152 s.line_style.set(chart);
153 chart.context.rel_line_to (line_length, 0);
154 chart.context.stroke();
155 s.marker.draw_at_pos (chart, 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 public void set (Chart chart) {
29 chart.set_source_rgba(color);
30 chart.context.set_line_join(join);
31 chart.context.set_line_cap(cap);
32 chart.context.set_line_width(width);
33 chart.context.set_dash(dashes, dash_offset);
34 }
35 }
36 }
37 }
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 CairoChart {
2
3 public class Marker {
4
5 public enum Type {
6 NONE = 0, // default
7 SQUARE,
8 CIRCLE,
9 TRIANGLE,
10 PRICLE_SQUARE,
11 PRICLE_CIRCLE,
12 PRICLE_TRIANGLE
13 }
14
15 public Type type = Type.NONE;
16 public double size = 8.0;
17
18 public Marker (Type type = Type.NONE, double size = 8.0) {
19 this.type = type;
20 this.size = size;
21 }
22
23 public Marker copy () {
24 return new Marker (type, size);
25 }
26
27 public virtual void draw_at_pos (Chart chart, double x, double y) {
28 chart.context.move_to (x, y);
29 switch (type) {
30 case Type.SQUARE:
31 chart.context.rectangle (x - size / 2, y - size / 2, size, size);
32 chart.context.fill();
33 break;
34
35 case Type.CIRCLE:
36 chart.context.arc (x, y, size / 2, 0, 2*Math.PI);
37 chart.context.fill();
38 break;
39
40 case Type.TRIANGLE:
41 chart.context.move_to (x - size / 2, y - size / 2);
42 chart.context.line_to (x + size / 2, y - size / 2);
43 chart.context.line_to (x, y + size / 2);
44 chart.context.line_to (x - size / 2, y - size / 2);
45 chart.context.fill();
46 break;
47
48 case Type.PRICLE_SQUARE:
49 chart.context.rectangle (x - size / 2, y - size / 2,
50 size, size);
51 chart.context.stroke();
52 break;
53
54 case Type.PRICLE_CIRCLE:
55 chart.context.arc (x, y, size / 2, 0, 2*Math.PI);
56 chart.context.stroke();
57 break;
58
59 case Type.PRICLE_TRIANGLE:
60 chart.context.move_to (x - size / 2, y - size / 2);
61 chart.context.line_to (x + size / 2, y - size / 2);
62 chart.context.line_to (x, y + size / 2);
63 chart.context.line_to (x - size / 2, y - size / 2);
64 chart.context.stroke();
65 break;
66 }
67 }
68 }
69 }
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
15 15 public Axis axis_x = new Axis();
16 16 public Axis axis_y = new Axis();
17 17
18 public enum MarkerType {
19 NONE = 0, // default
20 SQUARE,
21 CIRCLE,
22 TRIANGLE,
23 PRICLE_SQUARE,
24 PRICLE_CIRCLE,
25 PRICLE_TRIANGLE
26 }
27
28 18 public Place place = new Place();
29 19 public Text title = new Text ();
30 public MarkerType marker_type = MarkerType.SQUARE;
20 public Marker marker = new Marker ();
31 21
32 22 public Grid grid = new Grid ();
33 23
34 public LineStyle line_style = LineStyle ();
24 public Line.Style line_style = Line.Style ();
35 25
36 26 protected Color _color = Color (0.0, 0.0, 0.0, 1.0);
37 27 public Color color {
48 48 series.axis_y = this.axis_y.copy ();
49 49 series.grid = this.grid.copy ();
50 50 series.line_style = this.line_style;
51 series.marker_type = this.marker_type;
51 series.marker = this.marker;
52 52 series.place = this.place.copy();
53 53 series.points = this.points;
54 54 series.sort = this.sort;
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;
52 52 return sz;
53 53 }
54 54
55 public void show (Cairo.Context context) {
56 context.select_font_face(style.family,
57 style.slant,
58 style.weight);
59 context.set_font_size(style.size);
60 if (style.orientation == Font.Orientation.VERTICAL) {
61 context.rotate(- Math.PI / 2.0);
62 context.show_text(text);
63 context.rotate(Math.PI / 2.0);
64 } else {
65 context.show_text(text);
66 }
67 }
68
55 69 public Text (string text = "",
56 FontStyle style = FontStyle(),
70 Font.Style style = Font.Style(),
57 71 Color color = Color()) {
58 72 this.text = text;
59 73 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 s2.marker_type = Series.MarkerType.CIRCLE;
34 s3.marker_type = Series.MarkerType.PRICLE_TRIANGLE;
33 s2.marker.type = Marker.Type.CIRCLE;
34 s3.marker.type = Marker.Type.PRICLE_TRIANGLE;
35 35
36 36 s1.axis_x.title = new Text("Series 1: Axis X.");
37 37 s1.axis_y.title = new Text("Series 1: Axis Y.");
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 s1.marker_type = Series.MarkerType.PRICLE_CIRCLE;
77 s2.marker_type = Series.MarkerType.PRICLE_SQUARE;
76 s1.marker.type = Marker.Type.PRICLE_CIRCLE;
77 s2.marker.type = Marker.Type.PRICLE_SQUARE;
78 78
79 79 s1.axis_x.title = new Text("All Series: Axis X.");
80 80 s1.axis_y.title = new Text("Series 1: Axis Y.");
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 s2.marker_type = Series.MarkerType.PRICLE_CIRCLE;
126 s3.marker_type = Series.MarkerType.TRIANGLE;
125 s2.marker.type = Marker.Type.PRICLE_CIRCLE;
126 s3.marker.type = Marker.Type.TRIANGLE;
127 127
128 128 s1.axis_x.title = new Text("Series 1: Axis X.");
129 129 s1.axis_y.title = new Text("Series 1: Axis Y.");
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 s2.marker_type = Series.MarkerType.PRICLE_CIRCLE;
189 s3.marker_type = Series.MarkerType.TRIANGLE;
190 s4.marker_type = Series.MarkerType.PRICLE_SQUARE;
188 s2.marker.type = Marker.Type.PRICLE_CIRCLE;
189 s3.marker.type = Marker.Type.TRIANGLE;
190 s4.marker.type = Marker.Type.PRICLE_SQUARE;
191 191
192 192 s1.axis_x.title = new Text("Series 1: Axis X.");
193 193 s1.axis_y.title = new Text("Series 1: Axis Y.");
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