#include "viz/sparkline.h" #include "imgui.h" // Implementacion comun. Si auto_y=true, calcula min/max de values; si no, // usa [y_min, y_max] explicitos. static void sparkline_impl(const char* id, const float* values, int count, ImVec4 color, float width, float height, bool auto_y, float y_min, float y_max) { if (count <= 0) return; ImGui::PushID(id); ImVec2 pos = ImGui::GetCursorScreenPos(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImGui::Dummy(ImVec2(width, height)); if (auto_y) { y_min = values[0]; y_max = values[0]; for (int i = 1; i < count; i++) { if (values[i] < y_min) y_min = values[i]; if (values[i] > y_max) y_max = values[i]; } } float range = y_max - y_min; if (range < 1e-6f) range = 1.0f; auto y_at = [&](float v) { // Clamp visualmente al rango — para fixed Y sirve para que outliers // no salgan del card; para auto Y es no-op. if (v < y_min) v = y_min; if (v > y_max) v = y_max; return pos.y + height - ((v - y_min) / range) * height; }; // Fade gradient v1.2: alpha sube de older->newer. // El segmento [i, i+1] se pinta con alpha proporcional al endpoint derecho // (mas cercano a "ahora"). Hace efecto de rastro / trail. const int r_ = (int)(color.x * 255); const int g_ = (int)(color.y * 255); const int b_ = (int)(color.z * 255); auto seg_t = [&](int i) { return (count > 1) ? (float)(i + 1) / (float)(count - 1) : 1.0f; }; if (count >= 2) { float x0 = pos.x; float y_base = pos.y + height; for (int i = 0; i + 1 < count; i++) { float t = seg_t(i); int fill_a = (int)((0.10f + 0.70f * t) * 40.0f); // 4..28 alpha ImU32 fill_color = IM_COL32(r_, g_, b_, fill_a); float xa = x0 + ((float)i / (count - 1)) * width; float xb = x0 + ((float)(i + 1) / (count - 1)) * width; float ya = y_at(values[i]); float yb = y_at(values[i + 1]); draw_list->AddQuadFilled( ImVec2(xa, y_base), ImVec2(xa, ya), ImVec2(xb, yb), ImVec2(xb, y_base), fill_color); } } for (int i = 0; i + 1 < count; i++) { float t = seg_t(i); float a = 0.20f + 0.80f * t; ImU32 line_color = IM_COL32(r_, g_, b_, (int)(color.w * a * 255)); float xa = pos.x + ((float)i / (count - 1)) * width; float xb = pos.x + ((float)(i + 1) / (count - 1)) * width; float ya = y_at(values[i]); float yb = y_at(values[i + 1]); draw_list->AddLine(ImVec2(xa, ya), ImVec2(xb, yb), line_color, 1.5f); } ImGui::PopID(); } void sparkline(const char* id, const float* values, int count, ImVec4 color, float width, float height) { sparkline_impl(id, values, count, color, width, height, /*auto_y=*/true, 0.0f, 0.0f); } void sparkline(const char* id, const float* values, int count, float width, float height) { sparkline(id, values, count, ImVec4(0.35f, 0.85f, 0.45f, 1.0f), width, height); } void sparkline(const char* id, const float* values, int count, ImVec4 color, float y_min, float y_max, float width, float height) { sparkline_impl(id, values, count, color, width, height, /*auto_y=*/false, y_min, y_max); } void sparkline(const char* id, const float* values, int count, float y_min, float y_max, float width, float height) { sparkline(id, values, count, ImVec4(0.35f, 0.85f, 0.45f, 1.0f), y_min, y_max, width, height); }