plot
Header-only C++ SVG charts — heatmap, line, scatter — GR-style API + Solarized themes
Loading...
Searching...
No Matches
axis.hpp
1/* Copyright (c) 2026 Steven Varga, Toronto, ON, Canada
2 * MIT License — see LICENSE
3 *
4 * X/Y axis elements: lay out tick labels along a grid and render them through
5 * the canvas. Ported from plot:: into plot::. Dependency-free.
6 */
7#ifndef PLOT_AXIS_HPP
8#define PLOT_AXIS_HPP
9
10#include <vector>
11#include <string>
12#include <optional>
13#include <cmath>
14#include <cstddef>
15
16#include "attributes.hpp"
17#include "canvas.hpp"
18#include "utils.hpp"
19#include "meta.hpp"
20
21namespace plot::axis {
22 constexpr float rad = 3.14159265358979f / 180.0f;
23
24 template <class T, class... Ts>
25 struct x : public attribute::element_t, public impl::io_t< x<T,Ts...>> {
26 using value_type = tag::axis::x_t;
27 using attribute::element_t::color;
28 using attribute::element_t::position;
29 using font_t = attribute::font_t;
30 using layout_t = attribute::layout_t;
31 using degree_t = attribute::degree_t;
32 using position_t = attribute::position_t;
33 using attribute_t = plot::attribute::element_t;
34
35 x(const std::vector<T>& labels, Ts... args)
36 : attribute::element_t(args...), labels(labels) {
37 if( !rotate ) rotate = degree_t{-90.0} ;
38 dx.resize(labels.size()); dy.resize(labels.size());
39 set_font( arg::get<font_t>(args...) );
40 }
41 void ostream( impl::canvas_t& os ) const {
42 os.grid_x = grid;
43 attribute_t text_attr;
44 text_attr.rotate = this->rotate;
45 os.group(position->x, position->y, *this,
46 [&]() -> void {
47 for(std::size_t i=0; i<labels.size(); i++)
48 os.text(labels[i], static_cast<std::size_t>(dx[i]), static_cast<std::size_t>(dy[i]), text_attr);
49 });
50 }
51 void set_font( const std::optional<font_t>& font_ ){
52 this->font = font_ ? font_ : font_t{"Ubuntu Mono", "bold", 6};
53 this->grid = 1.6f * font->size;
54 for (std::size_t i=0; i < labels.size(); i++)
55 dy[i] = 0.0f, dx[i] = i * grid;
56 float angle = rotate->value * rad;
57 float max = utils::size_of_max_value( labels ) * 0.6f * font->size * std::abs(std::sin(angle));
58 if( !position )
59 position = position_t{static_cast<std::size_t>(2 * grid), static_cast<std::size_t>(max)};
60 }
61 float get_x(){
62 return static_cast<float>(
63 std::get<std::size_t>(position->x)) - 0.5f * grid;
64 }
65 const std::vector<T>& labels;
66 std::vector<float> dx,dy;
67 float grid = 0, max_x = 0;
68 };
69
70 template <class T, class... Ts>
71 struct y : public attribute::element_t, impl::io_t< y<T, Ts...>> {
72 using value_type = tag::axis::y_t;
73 using attribute::element_t::position;
74 using attribute::element_t::color;
75 using font_t = attribute::font_t;
76 using layout_t = attribute::layout_t;
77 using degree_t = attribute::degree_t;
78 using position_t = attribute::position_t;
79 using attribute_t = plot::attribute::element_t;
80
81 y(const std::vector<T>& labels, Ts... args)
82 : attribute::element_t(args...), labels(labels) {
83 if( !rotate ) rotate = degree_t{0.0} ;
84 this->layout = plot::layout::vertical;
85 dx.resize(labels.size()); dy.resize(labels.size());
86 set_font( arg::get<font_t>(args...) );
87 }
88
89 void ostream( impl::canvas_t& os ) const {
90 os.grid_y = grid;
91
92 attribute_t text_attr;
93 os.group(position->x, position->y, *this,
94 [&]() -> void {
95 for(std::size_t i=0; i<labels.size(); i++)
96 os.text(labels[i], static_cast<std::size_t>(dx[i]), static_cast<std::size_t>(dy[i] + .25 * grid), text_attr);
97 });
98 }
99
100 void set_font( const std::optional<font_t>& font_ ){
101 this->font = font_ ? font_ : font_t{"Ubuntu Mono", "bold", 6};
102 this->grid = 1.2f * font->size;
103 for (std::size_t i=0; i < labels.size(); i++)
104 dx[i] = 0.0f, dy[i] = i * grid;
105 if( !position )
106 position = position_t{std::size_t{0}, std::size_t{0}};
107 }
108
109 float get_y(){
110 return dy.back() + grid;
111 }
112 float get_x(){
113 float angle = rotate->value * rad;
114 float max = utils::size_of_max_value( labels ) * 0.6f * font->size * std::abs(std::cos(angle));
115
116 return static_cast<float>(
117 std::get<std::size_t>(position->x)) + max;
118 }
119
120 const std::vector<T>& labels;
121 std::vector<float> dx,dy;
122 float grid = 0, max_x = 0, max_y = 0;
123 };
124}
125#endif