30 #include <glm/vec2.hpp>
32 #include "eng3d/ui/piechart.hpp"
33 #include "eng3d/ui/widget.hpp"
34 #include "eng3d/ui/ui.hpp"
35 #include "eng3d/ui/tooltip.hpp"
36 #include "eng3d/texture.hpp"
37 #include "eng3d/rectangle.hpp"
38 #include "eng3d/state.hpp"
49 on_hover = &PieChart::on_hover_default;
54 max = std::accumulate(data.begin(), data.end(), 0.f, [](
const auto a,
const auto& e) {
59 inline void PieChart::draw_triangle(
float start_ratio,
float end_ratio,
Eng3D::Color color) {
60 const float x_center =
width / 2.f;
61 const float y_center =
height / 2.f;
62 const float radius = glm::min<float>(
width,
height) * 0.5;
63 float x_offset, y_offset, scale;
65 x_offset = glm::cos((start_ratio - 0.25f) * 2 * glm::pi<float>());
66 y_offset = glm::sin((start_ratio - 0.25f) * 2 * glm::pi<float>());
67 scale = glm::min<float>(1.f / glm::abs(x_offset), 1.f / glm::abs(y_offset));
74 mesh.buffer.emplace_back(glm::vec2(x_center + x_offset * radius, y_center + y_offset * radius), glm::vec2(0.5f + x_offset * 0.5f, 0.5f + y_offset * 0.5f));
76 x_offset = glm::cos((end_ratio - 0.25f) * 2 * glm::pi<float>());
77 y_offset = glm::sin((end_ratio - 0.25f) * 2 * glm::pi<float>());
78 scale = glm::min<float>(1.f / glm::abs(x_offset), 1.f / glm::abs(y_offset));
81 mesh.buffer.emplace_back(glm::vec2(x_center + x_offset * radius, y_center + y_offset * radius), glm::vec2(0.5f + x_offset * 0.5f, 0.5f + y_offset * 0.5f));
82 mesh.buffer.emplace_back(glm::vec2(x_center, y_center), glm::vec2(0.5f, 0.5f));
90 float last_corner = -0.125f;
92 for(
auto& slice : data) {
93 if(slice.num == 0.f)
continue;
95 float ratio = counter / max;
96 while(ratio > last_corner + 0.25f) {
98 draw_triangle(last_ratio, last_corner, slice.color);
99 last_ratio = last_corner;
101 draw_triangle(last_ratio, ratio, slice.color);
106 static inline bool in_triangle(glm::vec2 p, glm::vec2 center,
float radius,
float start_ratio,
float end_ratio) {
107 if(start_ratio == 0.f || end_ratio == 0.f)
return false;
109 auto x_offset = glm::cos((start_ratio - 0.25f) * 2.f * glm::pi<float>());
110 auto y_offset = glm::sin((start_ratio - 0.25f) * 2.f * glm::pi<float>());
112 if(abs(x_offset) == 0.f || abs(y_offset) == 0.f)
return false;
113 auto scale = glm::min<float>(1.f / abs(x_offset), 1.f / abs(y_offset));
116 glm::vec2 a{ center.x + x_offset * radius, center.y + y_offset * radius };
118 x_offset = glm::cos((end_ratio - 0.25f) * 2.f * glm::pi<float>());
119 y_offset = glm::sin((end_ratio - 0.25f) * 2.f * glm::pi<float>());
121 if(abs(x_offset) == 0.f || abs(y_offset) == 0.f)
return false;
122 scale = glm::min<float>(1.f / abs(x_offset), 1.f / abs(y_offset));
125 glm::vec2 b{ center.x + x_offset * radius, center.y + y_offset * radius };
126 glm::vec2 c{ center.x, center.y };
128 float A = 0.5f * (-b.y * c.x + a.y * (-b.x + c.x) + a.x * (b.y - c.y) + b.x * c.y);
129 float sign = A < 0 ? -1 : 1;
130 float s = (a.y * c.x - a.x * c.y + (c.y - a.y) * p.x + (a.x - c.x) * p.y) * sign;
131 float t = (a.x * b.y - a.y * b.x + (a.y - b.y) * p.x + (b.x - a.x) * p.y) * sign;
133 return s > 0 && t > 0 && (s + t) < 2 * A * sign;
136 void PieChart::on_hover_default(
Widget& w, glm::ivec2 mouse_pos, glm::ivec2 widget_pos) {
137 auto& piechart =
static_cast<PieChart&
>(w);
138 mouse_pos -= widget_pos;
140 float x_center = piechart.
width / 2.f;
141 float y_center = piechart.height / 2.f;
142 glm::ivec2 center{ x_center, y_center };
143 float radius = glm::min<float>(piechart.width, piechart.height) * 0.5;
145 glm::vec2 centered_pos = mouse_pos - center;
146 if(glm::length(centered_pos) > radius)
return;
148 float counter = 0.f, last_corner = -0.125f, last_ratio = 0.f;
149 for(
auto& slice : piechart.data) {
150 if(slice.num == 0.f)
continue;
151 counter += slice.num;
152 float ratio = counter / piechart.max;
153 while(ratio > last_corner + 0.25f) {
154 last_corner += 0.25f;
155 bool is_inside = in_triangle(mouse_pos, center, radius, last_ratio, last_corner);
157 piechart.set_tooltip(slice.info);
160 last_ratio = last_corner;
163 bool is_inside = in_triangle(mouse_pos, center, radius, last_ratio, last_corner);
165 piechart.set_tooltip(slice.info);
static State & get_instance()
Generalized chart data, used mostly by chart widgets, however it's not specific to any widget.
The UI context that handles all the ui widgets.
std::unique_ptr< Eng3D::OpenGL::Program > obj_shader
std::shared_ptr< Eng3D::Texture > piechart_overlay
PieChart(int x, int y, unsigned w, unsigned h, std::vector< ChartData > data=std::vector< ChartData >(), Widget *_parent=nullptr)
virtual void on_render(Context &ctx, Eng3D::Rect viewport) override
void set_data(std::vector< ChartData > data)
WidgetType
The type of the widget, some widgets share types between them to keep simplicity.
Primitive color type used through the engine.
Packed model - packs both vertices and texcoords into the same buffer.