From 6073a4ebb5fea563eef7259a64edaed2d628f79d Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 09:55:07 -0500 Subject: [PATCH 01/10] make query ranges dragable --- implot.cpp | 77 +++++++++++++++++++++++++++++++++++++++++-------- implot.h | 2 +- implot_demo.cpp | 25 ++++++++++++++-- 3 files changed, 88 insertions(+), 16 deletions(-) diff --git a/implot.cpp b/implot.cpp index ffa5208..ff0849c 100644 --- a/implot.cpp +++ b/implot.cpp @@ -221,7 +221,7 @@ struct ImPlotAxis { /// Holds Plot state information that must persist between frames struct ImPlot { ImPlot() { - Selecting = Querying = Queried = false; + Selecting = Querying = Queried = DraggingQuery = false; SelectStart = QueryStart = ImVec2(0,0); Flags = ImPlotFlags_Default; ColorIdx = 0; @@ -234,7 +234,8 @@ struct ImPlot { bool Querying; bool Queried; ImVec2 QueryStart; - ImRect QueryRect; + ImRect QueryRect; // relative to BB_grid!! + bool DraggingQuery; ImPlotRange QueryRange; ImPlotAxis XAxis; ImPlotAxis YAxis; @@ -655,7 +656,57 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const bool hov_y_axis_region = yAxisRegion_bb.Contains(IO.MousePos); // legend hovered from last frame - const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; + const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; + + bool hov_query = false; + if (plot.Queried && !plot.Querying) { + ImRect bb_query; + if (HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { + bb_query = plot.QueryRect; + bb_query.Min += gp.BB_Grid.Min; + bb_query.Max += gp.BB_Grid.Min; + } + else { + gp.UpdateTransforms(); + ImVec2 p1 = gp.ToPixels(plot.QueryRange.XMin, plot.QueryRange.YMin); + ImVec2 p2 = gp.ToPixels(plot.QueryRange.XMax, plot.QueryRange.YMax); + bb_query.Min = ImVec2(ImMin(p1.x,p2.x), ImMin(p1.y,p2.y)); + bb_query.Max = ImVec2(ImMax(p1.x,p2.x), ImMax(p1.y,p2.y)); + } + hov_query = bb_query.Contains(IO.MousePos); + } + + // QUERY DRAG ------------------------------------------------------------- + if (plot.DraggingQuery && (IO.MouseReleased[0] || !IO.MouseDown[0])) { + plot.DraggingQuery = false; + } + if (plot.DraggingQuery) { + SetMouseCursor(ImGuiMouseCursor_ResizeAll); + if (!HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { + ImVec2 p1 = gp.ToPixels(plot.QueryRange.XMin, plot.QueryRange.YMin); + ImVec2 p2 = gp.ToPixels(plot.QueryRange.XMax, plot.QueryRange.YMax); + plot.QueryRect.Min = ImVec2(ImMin(p1.x,p2.x), ImMin(p1.y,p2.y)) + IO.MouseDelta; + plot.QueryRect.Max = ImVec2(ImMax(p1.x,p2.x), ImMax(p1.y,p2.y)) + IO.MouseDelta; + p1 = gp.FromPixels(plot.QueryRect.Min); + p2 = gp.FromPixels(plot.QueryRect.Max); + plot.QueryRect.Min -= gp.BB_Grid.Min; + plot.QueryRect.Max -= gp.BB_Grid.Min; + plot.QueryRange.XMin = ImMin(p1.x, p2.x); + plot.QueryRange.XMax = ImMax(p1.x, p2.x); + plot.QueryRange.YMin = ImMin(p1.y, p2.y); + plot.QueryRange.YMax = ImMax(p1.y, p2.y); + } + else { + plot.QueryRect.Min += IO.MouseDelta; + plot.QueryRect.Max += IO.MouseDelta; + } + } + if (gp.Hov_Frame && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { + SetMouseCursor(ImGuiMouseCursor_ResizeAll); + if (IO.MouseDown[0] && !plot.XAxis.Dragging && !plot.YAxis.Dragging) { + plot.DraggingQuery = true; + } + } // DRAG INPUT ------------------------------------------------------------- @@ -695,9 +746,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); } // start drag - if (gp.Hov_Frame && hov_x_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend) + if (gp.Hov_Frame && hov_x_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) plot.XAxis.Dragging = true; - if (gp.Hov_Frame && hov_y_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend) + if (gp.Hov_Frame && hov_y_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) plot.YAxis.Dragging = true; // SCROLL INPUT ----------------------------------------------------------- @@ -761,12 +812,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // update query if (plot.Querying) { gp.UpdateTransforms(); - plot.QueryRect.Min.x = IO.KeyAlt ? gp.BB_Grid.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x); - plot.QueryRect.Max.x = IO.KeyAlt ? gp.BB_Grid.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x); + plot.QueryRect.Min.x = IO.KeyAlt ? gp.BB_Grid.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x); + plot.QueryRect.Max.x = IO.KeyAlt ? gp.BB_Grid.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x); plot.QueryRect.Min.y = IO.KeyShift ? gp.BB_Grid.Min.y : ImMin(plot.QueryStart.y, IO.MousePos.y); plot.QueryRect.Max.y = IO.KeyShift ? gp.BB_Grid.Max.y : ImMax(plot.QueryStart.y, IO.MousePos.y); ImVec2 p1 = gp.FromPixels(plot.QueryRect.Min); ImVec2 p2 = gp.FromPixels(plot.QueryRect.Max); + plot.QueryRect.Min -= gp.BB_Grid.Min; + plot.QueryRect.Max -= gp.BB_Grid.Min; plot.QueryRange.XMin = ImMin(p1.x, p2.x); plot.QueryRange.XMax = ImMax(p1.x, p2.x); plot.QueryRange.YMin = ImMin(p1.y, p2.y); @@ -810,7 +863,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // DOUBLE CLICK ----------------------------------------------------------- - if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && gp.Hov_Grid && !hov_legend) + if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && gp.Hov_Grid && !hov_legend && !hov_query) gp.FitThisFrame = true; else gp.FitThisFrame = false; @@ -1078,8 +1131,8 @@ void EndPlot() { if (plot.Querying || (HasFlag(plot.Flags, ImPlotFlags_PixelQuery) && plot.Queried)) { if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) { - DrawList.AddRectFilled(plot.QueryRect.Min, plot.QueryRect.Max, gp.Col_QryBg); - DrawList.AddRect( plot.QueryRect.Min, plot.QueryRect.Max, gp.Col_QryBd); + DrawList.AddRectFilled(plot.QueryRect.Min + gp.BB_Grid.Min, plot.QueryRect.Max + gp.BB_Grid.Min, gp.Col_QryBg); + DrawList.AddRect( plot.QueryRect.Min + gp.BB_Grid.Min, plot.QueryRect.Max + gp.BB_Grid.Min, gp.Col_QryBd); } } else if (plot.Queried) { @@ -1273,8 +1326,8 @@ ImPlotRange GetPlotQuery() { ImPlot& plot = *gp.CurrentPlot; if (HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { gp.UpdateTransforms(); - ImVec2 p1 = gp.FromPixels(plot.QueryRect.Min); - ImVec2 p2 = gp.FromPixels(plot.QueryRect.Max); + ImVec2 p1 = gp.FromPixels(plot.QueryRect.Min + gp.BB_Grid.Min); + ImVec2 p2 = gp.FromPixels(plot.QueryRect.Max + gp.BB_Grid.Min); plot.QueryRange.XMin = ImMin(p1.x, p2.x); plot.QueryRange.XMax = ImMax(p1.x, p2.x); plot.QueryRange.YMin = ImMin(p1.y, p2.y); diff --git a/implot.h b/implot.h index ec8bcb3..a12c536 100644 --- a/implot.h +++ b/implot.h @@ -225,4 +225,4 @@ void PopPlotStyleVar(int count = 1); // Shows the ImPlot demo. Add implot_demo.cpp to your sources! void ShowImPlotDemoWindow(bool* p_open = NULL); -} // namespace ImGui +} // namespace ImGui \ No newline at end of file diff --git a/implot_demo.cpp b/implot_demo.cpp index af231ce..ee8a940 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -55,12 +55,21 @@ struct RollingData { } }; +// Put big data here +struct DemoData { + DemoData() { + + } +}; + } namespace ImGui { void ShowImPlotDemoWindow(bool* p_open) { + static DemoData data; + ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos; ImGui::SetNextWindowPos(ImVec2(main_viewport_pos.x + 650, main_viewport_pos.y + 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); @@ -389,6 +398,7 @@ void ShowImPlotDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Drag and Drop")) { + srand(10000000 * ImGui::GetTime()); static bool paused = false; static bool init = true; static ScrollingData data[10]; @@ -396,15 +406,17 @@ void ShowImPlotDemoWindow(bool* p_open) { if (init) { for (int i = 0; i < 10; ++i) { show[i] = false; - data[i].AddPoint(0, 0.25f + 0.5f * (float)rand() / float(RAND_MAX)); } init = false; } ImGui::BulletText("Drag data items from the left column onto the plot."); ImGui::BeginGroup(); if (ImGui::Button("Clear", {100, 0})) { - for (int i = 0; i < 10; ++i) + for (int i = 0; i < 10; ++i) { show[i] = false; + data[i].Data.shrink(0); + data[i].Offset = 0; + } } if (ImGui::Button(paused ? "Resume" : "Pause", {100,0})) paused = !paused; @@ -425,7 +437,10 @@ void ShowImPlotDemoWindow(bool* p_open) { if (!paused) { t += ImGui::GetIO().DeltaTime; for (int i = 0; i < 10; ++i) { - data[i].AddPoint(t, data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX))); + if (show[i]) + data[i].AddPoint(t, data[i].Data.empty() ? + 0.25f + 0.5f * (float)rand() / float(RAND_MAX) : + data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX))); } } ImGui::SetNextPlotRangeX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); @@ -479,6 +494,10 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::RestorePlotPalette(); } //------------------------------------------------------------------------- + // if (ImGui::CollapsingHeader("Benchmark")) { + + // } + //------------------------------------------------------------------------- ImGui::End(); } From cb3dfcd5c6081e8da89c7b4bddac15c07a07aaa7 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 14:22:27 -0500 Subject: [PATCH 02/10] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d86569..e85c35b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ImPlot ImPlot is an immediate mode plotting widget for [Dear ImGui](https://github.com/ocornut/imgui). It aims to provide a first-class API that will make ImGui users feel right at home. ImPlot is well suited for visualizing program data in real-time and requires minimal code to integrate. Just like ImGui, it does not burden the end user with GUI state managment, avoids STL containers and C++ headers, and has no external dependencies except for ImGui itself. - + ## Features @@ -83,6 +83,6 @@ A: Yes, you can use the C binding, [cimplot](https://github.com/cimgui/cimplot) ## Gallery - + - + From 022f44af006a58cec4807e1c10bddf7a96c74e04 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 14:24:40 -0500 Subject: [PATCH 03/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e85c35b..496c3c9 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,6 @@ A: Yes, you can use the C binding, [cimplot](https://github.com/cimgui/cimplot) ## Gallery - + From cab489a9b73e55de69332d88176307478b73451e Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 14:27:23 -0500 Subject: [PATCH 04/10] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 496c3c9..3f231f8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ ImPlot is an immediate mode plotting widget for [Dear ImGui](https://github.com/ + + ## Features - multiple plot types: line, scatter, vertical/horizontal bars, error bars, with more likely to come @@ -80,9 +82,3 @@ A: Not currently. Use your OS's screen capturing mechanisms if you need to captu **Q: Can ImPlot be used with other languages/bindings?** A: Yes, you can use the C binding, [cimplot](https://github.com/cimgui/cimplot) with most high level languages. - -## Gallery - - - - From 7929b17f0c40d430f139dc8f6cfd4d46a6f851ea Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 14:39:46 -0500 Subject: [PATCH 05/10] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f231f8..c122a34 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # ImPlot ImPlot is an immediate mode plotting widget for [Dear ImGui](https://github.com/ocornut/imgui). It aims to provide a first-class API that will make ImGui users feel right at home. ImPlot is well suited for visualizing program data in real-time and requires minimal code to integrate. Just like ImGui, it does not burden the end user with GUI state managment, avoids STL containers and C++ headers, and has no external dependencies except for ImGui itself. - + - + + ## Features From dd5390f4339283cb503850e9ac05ffe21d0b4028 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 14:41:39 -0500 Subject: [PATCH 06/10] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c122a34..8e67076 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,6 @@ Consult `implot_demo.cpp` for a comprehensive example of ImPlot's features. Just add `implot.h`, `implot.cpp`, and optionally `implot_demo.cpp` to your sources. This assumes you already have an ImGui-ready environment. If not, consider trying [mahi-gui](https://github.com/mahilab/mahi-gui), which bundles ImGui, ImPlot, and several other packages for you. -## Special Notes -- By default, no anti-aliasing is done on line plots for performance reasons. If you use 4x MSAA, then you likely won't even notice. However, you can re-enable AA with the `ImPlotFlags_AntiAliased` flag. -- If you plan to render several thousands lines or points, then you should consider enabling 32-bit indices by uncommenting `#define ImDrawIdx unsigned int` in your `imconfig.h` file, OR handling the `ImGuiBackendFlags_RendererHasVtxOffset` flag in your renderer (the official OpenGL3 renderer supports this). If you fail to do this, then you may at some point hit the maximum number of indices that can be rendered. - ## FAQ **Q: Why?** @@ -83,3 +79,7 @@ A: Not currently. Use your OS's screen capturing mechanisms if you need to captu **Q: Can ImPlot be used with other languages/bindings?** A: Yes, you can use the C binding, [cimplot](https://github.com/cimgui/cimplot) with most high level languages. + +## Special Notes +- By default, no anti-aliasing is done on line plots for performance reasons. If you use 4x MSAA, then you likely won't even notice. However, you can re-enable AA with the `ImPlotFlags_AntiAliased` flag. +- If you plan to render several thousands lines or points, then you should consider enabling 32-bit indices by uncommenting `#define ImDrawIdx unsigned int` in your `imconfig.h` file, OR handling the `ImGuiBackendFlags_RendererHasVtxOffset` flag in your renderer (the official OpenGL3 renderer supports this). If you fail to do this, then you may at some point hit the maximum number of indices that can be rendered. From 3c1ef115259affaf5042df57d1921180473fb18d Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 29 Apr 2020 15:39:02 -0500 Subject: [PATCH 07/10] add custom rendering utils --- implot.cpp | 29 +++++++++++++++++++++++ implot.h | 63 ++++++++++++++++++++++++++++++++----------------- implot_demo.cpp | 15 ++++++++++-- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/implot.cpp b/implot.cpp index ff0849c..8868733 100644 --- a/implot.cpp +++ b/implot.cpp @@ -1295,6 +1295,35 @@ void SetNextPlotRangeY(float y_min, float y_max, ImGuiCond cond) { gp.NextPlotData.YMax = y_max; } +ImVec2 GetPlotPos() { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotPos() Needs to be called between BeginPlot() and EndPlot()!"); + return gp.BB_Grid.Min; +} + +ImVec2 GetPlotSize() { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotSize() Needs to be called between BeginPlot() and EndPlot()!"); + return gp.BB_Grid.GetSize(); +} + +ImVec2 PixelsToPlot(const ImVec2& pix) { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() Needs to be called between BeginPlot() and EndPlot()!"); + return gp.FromPixels(pix); +} + +ImVec2 PlotToPixels(const ImVec2& plt) { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() Needs to be called between BeginPlot() and EndPlot()!"); + return gp.ToPixels(plt); +} + +void PushPlotClipRect() { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() Needs to be called between BeginPlot() and EndPlot()!"); + PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); +} + +void PopPlotClipRect() { + PopClipRect(); +} + bool IsPlotHovered() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() Needs to be called between BeginPlot() and EndPlot()!"); return gp.Hov_Grid; diff --git a/implot.h b/implot.h index a12c536..a1d0be0 100644 --- a/implot.h +++ b/implot.h @@ -147,28 +147,6 @@ bool BeginPlot(const char* title_id, // of an if statement conditioned on BeginPlot(). void EndPlot(); -/// Set the axes ranges of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes will be locked. -void SetNextPlotRange(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); -/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. -void SetNextPlotRangeX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); -/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. -void SetNextPlotRangeY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); - -//----------------------------------------------------------------------------- -// Plot Queries -//----------------------------------------------------------------------------- - -/// Returns true if the plot area in the current or most recent plot is hovered. -bool IsPlotHovered(); -/// Returns the mouse position in x,y coordinates of the current or most recent plot. -ImVec2 GetPlotMousePos(); -/// Returns the current or most recent plot axis range. -ImPlotRange GetPlotRange(); -/// Returns true if the current or most recent plot is being queried. -bool IsPlotQueried(); -/// Returns the current or most recent plot querey range. -ImPlotRange GetPlotQuery(); - //----------------------------------------------------------------------------- // Plot Items //----------------------------------------------------------------------------- @@ -192,6 +170,21 @@ void PlotErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx), // Plots a text label at point x,y. void PlotLabel(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); +//----------------------------------------------------------------------------- +// Plot Queries +//----------------------------------------------------------------------------- + +/// Returns true if the plot area in the current or most recent plot is hovered. +bool IsPlotHovered(); +/// Returns the mouse position in x,y coordinates of the current or most recent plot. +ImVec2 GetPlotMousePos(); +/// Returns the current or most recent plot axis range. +ImPlotRange GetPlotRange(); +/// Returns true if the current or most recent plot is being queried. +bool IsPlotQueried(); +/// Returns the current or most recent plot querey range. +ImPlotRange GetPlotQuery(); + //----------------------------------------------------------------------------- // Plot Styling //----------------------------------------------------------------------------- @@ -218,6 +211,32 @@ void PushPlotStyleVar(ImPlotStyleVar idx, int val); // Undo temporary style modification. void PopPlotStyleVar(int count = 1); +//----------------------------------------------------------------------------- +// Plot Utils +//----------------------------------------------------------------------------- + +/// Set the axes ranges of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes will be locked. +void SetNextPlotRange(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); +/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. +void SetNextPlotRangeX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); +/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. +void SetNextPlotRangeY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); + +// Get the current Plot position (top-left) in pixels. +ImVec2 GetPlotPos(); +// Get the curent Plot size in pixels. +ImVec2 GetPlotSize(); + +// Convert pixels to a position in the current plot's coordinate system. +ImVec2 PixelsToPlot(const ImVec2& pix); +// Convert a position in the current plot's coordinate system to pixels. +ImVec2 PlotToPixels(const ImVec2& plt); + +// Push clip rect for rendering to current plot area +void PushPlotClipRect(); +// Pop plot clip rect +void PopPlotClipRect(); + //----------------------------------------------------------------------------- // Demo //----------------------------------------------------------------------------- diff --git a/implot_demo.cpp b/implot_demo.cpp index ee8a940..58adf4f 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -23,7 +23,6 @@ // ImPlot v0.1 WIP #include -#include #include namespace { @@ -48,7 +47,7 @@ struct RollingData { ImVector Data; RollingData() { Data.reserve(1000); } void AddPoint(float x, float y) { - float xmod = ImFmod(x, Span); + float xmod = fmodf(x, Span); if (!Data.empty() && xmod < Data.back().x) Data.shrink(0); Data.push_back(ImVec2(xmod, y)); @@ -493,6 +492,18 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::PopPlotStyleVar(); ImGui::RestorePlotPalette(); } + if (ImGui::CollapsingHeader("Custom Rendering")) { + if (ImGui::BeginPlot("##CustomRend",NULL,NULL,{-1,300})) { + ImVec2 cntr = ImGui::PlotToPixels({0.5f, 0.5f}); + ImVec2 rmin = ImGui::PlotToPixels({0.25f, 0.75f}); + ImVec2 rmax = ImGui::PlotToPixels({0.75f, 0.25f}); + ImGui::PushPlotClipRect(); + ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); + ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); + ImGui::PopPlotClipRect(); + ImGui::EndPlot(); + } + } //------------------------------------------------------------------------- // if (ImGui::CollapsingHeader("Benchmark")) { From 23931c7f0701659fa97ca1f4b0e6bc1a710d6fc2 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 30 Apr 2020 08:13:44 -0500 Subject: [PATCH 08/10] add benchmark test, update double click fit, fix demo math include --- implot.cpp | 21 +++++++++++------ implot_demo.cpp | 60 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/implot.cpp b/implot.cpp index 8868733..a6992c5 100644 --- a/implot.cpp +++ b/implot.cpp @@ -259,6 +259,7 @@ struct ImNextPlotData { struct ImPlotContext { ImPlotContext() { CurrentPlot = NULL; + FitThisFrame = FitX = FitY = false; RestorePlotPalette(); } /// ALl Plots @@ -387,7 +388,7 @@ struct ImPlotContext { // Data extents ImRect Extents; - bool FitThisFrame; + bool FitThisFrame; bool FitX; bool FitY; int VisibleItemCount; // Render flags bool RenderX, RenderY; @@ -863,10 +864,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // DOUBLE CLICK ----------------------------------------------------------- - if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && gp.Hov_Grid && !hov_legend && !hov_query) + if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && (hov_x_axis_region || hov_y_axis_region) && !hov_legend && !hov_query) { gp.FitThisFrame = true; - else + gp.FitX = hov_x_axis_region; + gp.FitY = hov_y_axis_region; + } + else { gp.FitThisFrame = false; + gp.FitX = false; + gp.FitY = false; + } // FOCUS ------------------------------------------------------------------ @@ -1238,13 +1245,13 @@ void EndPlot() { // FIT DATA -------------------------------------------------------------- if (gp.FitThisFrame && (gp.VisibleItemCount > 0 || plot.Queried)) { - if (!HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.x)) + if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.x)) plot.XAxis.Min = gp.Extents.Min.x; - if (!HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.x)) + if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.x)) plot.XAxis.Max = gp.Extents.Max.x; - if (!HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.y)) + if (gp.FitY && !HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.y)) plot.YAxis.Min = gp.Extents.Min.y; - if (!HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.y)) + if (gp.FitY && !HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.y)) plot.YAxis.Max = gp.Extents.Max.y; } diff --git a/implot_demo.cpp b/implot_demo.cpp index 58adf4f..2c6e1fd 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -23,10 +23,15 @@ // ImPlot v0.1 WIP #include -#include +#include namespace { +float RandomRange( float min, float max ) { + float scale = rand() / (float) RAND_MAX; + return min + scale * ( max - min ); +} + struct ScrollingData { int MaxSize = 1000; int Offset = 0; @@ -54,11 +59,21 @@ struct RollingData { } }; -// Put big data here -struct DemoData { - DemoData() { - - } +struct BenchmarkItem { + BenchmarkItem() { + float y = RandomRange(0,1); + Xs = new float[1000]; + Ys = new float[1000]; + for (int i = 0; i < 1000; ++i) { + Xs[i] = i*0.001f; + Ys[i] = y + RandomRange(-0.01f,0.01f); + } + Col = ImVec4(RandomRange(0,1),RandomRange(0,1),RandomRange(0,1),1); + } + ~BenchmarkItem() { delete Xs; delete Ys; } + float* Xs; + float* Ys; + ImVec4 Col; }; } @@ -67,8 +82,6 @@ namespace ImGui { void ShowImPlotDemoWindow(bool* p_open) { - static DemoData data; - ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos; ImGui::SetNextWindowPos(ImVec2(main_viewport_pos.x + 650, main_viewport_pos.y + 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); @@ -77,9 +90,13 @@ void ShowImPlotDemoWindow(bool* p_open) { if (ImGui::CollapsingHeader("Help")) { ImGui::Text("USER GUIDE:"); ImGui::BulletText("Left click and drag within the plot area to pan X and Y axes."); - ImGui::BulletText("Left click and drag on an axis to pan an individual axis."); + ImGui::Indent(); + ImGui::BulletText("Left click and drag on an axis to pan an individual axis."); + ImGui::Unindent(); ImGui::BulletText("Scroll in the plot area to zoom both X any Y axes."); - ImGui::BulletText("Scroll on an axis to zoom an individual axis."); + ImGui::Indent(); + ImGui::BulletText("Scroll on an axis to zoom an individual axis."); + ImGui::Unindent(); ImGui::BulletText("Right click and drag to box select data."); ImGui::Indent(); ImGui::BulletText("Hold Alt to expand box selection horizontally."); @@ -92,6 +109,9 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::BulletText("Hold Shift to expand query vertically."); ImGui::Unindent(); ImGui::BulletText("Double left click to fit all visible data."); + ImGui::Indent(); + ImGui::BulletText("Double left click on an axis to fit the individual axis."); + ImGui::Unindent(); ImGui::BulletText("Double right click to open the plot context menu."); ImGui::BulletText("Click legend label icons to show/hide plot items."); } @@ -194,6 +214,7 @@ void ShowImPlotDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Realtime Plots")) { ImGui::BulletText("Move your mouse to change the data!"); + ImGui::BulletText("This example assumes 60 FPS. Higher FPS requires larger buffer size."); static bool paused = false; static ScrollingData sdata1, sdata2; static RollingData rdata1, rdata2; @@ -505,9 +526,22 @@ void ShowImPlotDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- - // if (ImGui::CollapsingHeader("Benchmark")) { - - // } + if (ImGui::CollapsingHeader("Benchmark")) { + static const int n_items = 100; + static BenchmarkItem items[n_items]; + ImGui::BulletText("Make sure VSync is disabled."); + ImGui::BulletText("%d lines with %d points each @ %.3f FPS.",n_items,1000,ImGui::GetIO().Framerate); + if (ImGui::BeginPlot("##Bench",NULL,NULL,{-1,300})) { + char buff[16]; + for (int i = 0; i < 100; ++i) { + sprintf(buff, "item_%d",i); + ImGui::PushPlotColor(ImPlotCol_Line, items[i].Col); + ImGui::Plot(buff, items[i].Xs, items[i].Ys, 1000); + ImGui::PopPlotColor(); + } + ImGui::EndPlot(); + } + } //------------------------------------------------------------------------- ImGui::End(); From 20a54e78ea36a47a005c152aec63033e37c8f029 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 30 Apr 2020 09:01:14 -0500 Subject: [PATCH 09/10] Update implot_demo.cpp --- implot_demo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 2c6e1fd..52b65ca 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -24,6 +24,7 @@ #include #include +#include namespace { @@ -547,4 +548,4 @@ void ShowImPlotDemoWindow(bool* p_open) { } -} // namespace ImGui \ No newline at end of file +} // namespace ImGui From 8adde097e71f00de191fd703530e65d757f55c1c Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 30 Apr 2020 09:02:02 -0500 Subject: [PATCH 10/10] Update implot_demo.cpp --- implot_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 52b65ca..2505bba 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include namespace {