28#include "attributes.hpp"
37 struct hole {
using value_type = tag::hole_t;
double value; };
41 template <
class... opt_t>
42 double hole_of(
double fallback,
const opt_t&... opts){
43 using d_t =
typename arg::tpos<tag::hole_t, opt_t...>;
44 if constexpr( d_t::present ){
45 auto tuple = std::forward_as_tuple(opts...);
46 double r = std::get<d_t::position>(tuple).value;
47 if( r < 0 ) r = 0;
else if( r > 0.95 ) r = 0.95;
53 template <
class... opt_t>
55 using value_type = tag::view_t;
56 std::vector<std::string> labels;
57 std::vector<double> values;
58 std::tuple<opt_t...> opts;
59 double default_inner = 0.0;
61 std::pair<std::size_t,std::size_t> natural()
const {
62 return std::apply([](
const auto&... o){
63 return impl::natural_size(std::size_t{500}, std::size_t{500}, o...); }, opts);
65 void draw_into(canvas_t& cv,
float x,
float y,
float w,
float h)
const {
66 std::apply([&](
const auto&... o){
67 const theme_t& th = impl::resolve_theme(o...);
68 auto [title, xl, yl] = impl::texts(o...);
69 const double inner = impl::hole_of(default_inner, o...);
70 using attribute_t = plot::attribute::element_t;
72 const std::size_t n = std::min(labels.size(), values.size());
73 double total = 0.0;
for(std::size_t i=0;i<n;++i)
if(values[i]>0) total += values[i];
74 if( total <= 0.0 ) total = 1.0;
76 cv.group(
static_cast<std::size_t
>(x),
static_cast<std::size_t
>(y), attribute_t{},
78 { attribute_t bg; bg.color = plot::attribute::color_t{ th.bg };
79 cv.rect(0,0, w, h, 0,0, bg); }
80 float top = title.empty() ? 8.0f : 26.0f;
82 attribute_t a; a.color = plot::attribute::color_t{ th.fg };
83 a.font = plot::attribute::font_t{
"Arial, sans-serif",
"bold", 13u};
84 a.align = plot::attribute::align_t::center;
85 cv.text(title, std::size_t(w/2), std::size_t(16), a);
87 float cx = w*0.5f, cy = top + (h - top)*0.5f;
88 float Ro = std::max(8.0f, std::min(w, h - top)*0.5f - 30.0f);
89 float Ri = float(inner) * Ro;
91 double a0 = -1.5707963267948966;
92 const double TWO_PI = 6.283185307179586;
93 for(std::size_t i=0;i<n;++i){
94 double frac = (values[i] > 0 ? values[i] : 0.0) / total;
95 double a1 = a0 + frac*TWO_PI;
97 std::size_t segs = std::max<std::size_t>(2,
98 static_cast<std::size_t
>(std::ceil(frac*64.0)));
99 std::vector<float> X, Y;
101 for(std::size_t s=0;s<=segs;++s){
102 double a = a0 + (a1-a0)*
double(s)/double(segs);
103 X.push_back(cx + Ro*
float(std::cos(a)));
104 Y.push_back(cy + Ro*
float(std::sin(a)));
108 for(std::size_t s=0;s<=segs;++s){
109 double a = a1 + (a0-a1)*
double(s)/double(segs);
110 X.push_back(cx + Ri*
float(std::cos(a)));
111 Y.push_back(cy + Ri*
float(std::sin(a)));
114 X.push_back(cx); Y.push_back(cy);
117 X.push_back(X.front()); Y.push_back(Y.front());
119 std::uint32_t col = th.series.empty()? th.fg
120 : th.series[i % th.series.size()];
121 attribute_t pa; pa.color = plot::attribute::color_t{ col };
124 pa.stroke = plot::attribute::stroke_t{1.0f, 1.0f, {}, {}, {}};
125 cv.polygon(X, Y, pa);
128 double am = 0.5*(a0+a1);
129 float lr = Ro + 12.0f;
130 attribute_t ta; ta.color = plot::attribute::color_t{ th.fg };
131 ta.font = plot::attribute::font_t{
"Arial, sans-serif",
"normal", 10u};
132 ta.align = plot::attribute::align_t::center;
133 float lx = cx + lr*float(std::cos(am));
134 float ly = cy + lr*float(std::sin(am));
135 cv.text(labels[i], std::size_t(lx<0?0:lx), std::size_t(ly+3), ta);
145 template <
class... opt_t>
146 impl::pie_view<opt_t...> pie(std::vector<std::string> labels,
147 std::vector<double> values, opt_t... opts){
148 return impl::pie_view<opt_t...>{ std::move(labels), std::move(values),
149 std::make_tuple(opts...) };
153 template <
class... opt_t>
154 impl::pie_view<opt_t...> donut(std::vector<std::string> labels,
155 std::vector<double> values, opt_t... opts){
156 return impl::pie_view<opt_t...>{ std::move(labels), std::move(values),
157 std::make_tuple(opts...), 0.55 };