diff --git a/implot.cpp b/implot.cpp index ba213b8..a3ebb53 100644 --- a/implot.cpp +++ b/implot.cpp @@ -415,6 +415,16 @@ void FitPoint(const ImPlotPoint& p) { } } +void PushLinkedAxis(ImPlotAxis& axis) { + if (axis.LinkedMin) { *axis.LinkedMin = axis.Range.Min; } + if (axis.LinkedMax) { *axis.LinkedMax = axis.Range.Max; } +} + +void PullLinkedAxis(ImPlotAxis& axis) { + if (axis.LinkedMin) { axis.SetMin(*axis.LinkedMin); } + if (axis.LinkedMax) { axis.SetMax(*axis.LinkedMax); } +} + //----------------------------------------------------------------------------- // Coordinate Utils //----------------------------------------------------------------------------- @@ -1094,6 +1104,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // NextPlotData ----------------------------------------------------------- + // linked axes + plot.XAxis.LinkedMin = gp.NextPlotData.LinkedXmin; + plot.XAxis.LinkedMax = gp.NextPlotData.LinkedXmax; + PullLinkedAxis(plot.XAxis); + for (int i = 0; i < IMPLOT_Y_AXES; ++i) { + plot.YAxis[i].LinkedMin = gp.NextPlotData.LinkedYmin[i]; + plot.YAxis[i].LinkedMax = gp.NextPlotData.LinkedYmax[i]; + PullLinkedAxis(plot.YAxis[i]); + } + if (gp.NextPlotData.HasXRange) { if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) plot.XAxis.SetRange(gp.NextPlotData.X); @@ -2099,6 +2119,13 @@ void EndPlot() { ImGui::PopID(); } + + // LINKED AXES ------------------------------------------------------------ + + PushLinkedAxis(plot.XAxis); + for (int i = 0; i < IMPLOT_Y_AXES; ++i) + PushLinkedAxis(plot.YAxis[i]); + // CLEANUP ---------------------------------------------------------------- // reset the plot items for the next frame @@ -2147,6 +2174,18 @@ void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond, int y_axis) gp.NextPlotData.Y[y_axis].Max = y_max; } +void LinkNextPlotLimits(double* xmin, double* xmax, double* ymin, double* ymax, double* ymin2, double* ymax2, double* ymin3, double* ymax3) { + ImPlotContext& gp = *GImPlot; + gp.NextPlotData.LinkedXmin = xmin; + gp.NextPlotData.LinkedXmax = xmax; + gp.NextPlotData.LinkedYmin[0] = ymin; + gp.NextPlotData.LinkedYmax[0] = ymax; + gp.NextPlotData.LinkedYmin[1] = ymin2; + gp.NextPlotData.LinkedYmax[1] = ymax2; + gp.NextPlotData.LinkedYmin[2] = ymin3; + gp.NextPlotData.LinkedYmax[2] = ymax3; +} + void FitNextPlotAxes(bool x, bool y, bool y2, bool y3) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "FitNextPlotAxes() needs to be called before BeginPlot()!"); diff --git a/implot.h b/implot.h index 1c4a6d9..abbee22 100644 --- a/implot.h +++ b/implot.h @@ -382,11 +382,13 @@ void PlotText(const char* text, double x, double y, bool vertical = false, const //----------------------------------------------------------------------------- // Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked. -void SetNextPlotLimits(double x_min, double x_max, double y_min, double y_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimits(double xmin, double xmax, double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once); // Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the X axis limits will be locked. -void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimitsX(double xmin, double xmax, ImGuiCond cond = ImGuiCond_Once); // Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the Y axis limits will be locked. -void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); +void SetNextPlotLimitsY(double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); +// Links the next plot limits to external values. Set to NULL for no linkage. The pointer data must remain valid until the matching call EndPlot. +void LinkNextPlotLimits(double* xmin, double* xmax, double* ymin, double* ymax, double* ymin2 = NULL, double* ymax2 = NULL, double* ymin3 = NULL, double* ymax3 = NULL); // Fits the next plot axes to all plotted data if they are unlocked (equivalent to double-clicks). void FitNextPlotAxes(bool x = true, bool y = true, bool y2 = true, bool y3 = true); diff --git a/implot_demo.cpp b/implot_demo.cpp index f170e19..0ac4a70 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -693,6 +693,25 @@ void ShowDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- + if (ImGui::CollapsingHeader("Linked Axes")) { + static double xmin = 0, xmax = 1, ymin = 0, ymax = 1; + static bool linkx = true, linky = true; + t_float data[2] = {0,1}; + ImGui::Checkbox("Link X", &linkx); + ImGui::SameLine(); + ImGui::Checkbox("Link Y", &linky); + ImPlot::LinkNextPlotLimits(linkx ? &xmin : NULL , linkx ? &xmax : NULL, linky ? &ymin : NULL, linky ? &ymax : NULL); + if (ImPlot::BeginPlot("Plot A")) { + ImPlot::PlotLine("Line",data,2); + ImPlot::EndPlot(); + } + ImPlot::LinkNextPlotLimits(linkx ? &xmin : NULL , linkx ? &xmax : NULL, linky ? &ymin : NULL, linky ? &ymax : NULL); + if (ImPlot::BeginPlot("Plot B")) { + ImPlot::PlotLine("Line",data,2); + ImPlot::EndPlot(); + } + } + //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Querying")) { static ImVector data; static ImPlotLimits range, query; diff --git a/implot_internal.h b/implot_internal.h index d359308..9b97719 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -295,6 +295,8 @@ struct ImPlotAxis bool Dragging; bool HoveredExt; bool HoveredTot; + double* LinkedMin; + double* LinkedMax; ImPlotAxis() { Flags = PreviousFlags = ImPlotAxisFlags_None; @@ -303,6 +305,7 @@ struct ImPlotAxis Dragging = false; HoveredExt = false; HoveredTot = false; + LinkedMin = LinkedMax = NULL; } bool SetMin(double _min) { @@ -453,15 +456,21 @@ struct ImPlotNextPlotData bool ShowDefaultTicksY[IMPLOT_Y_AXES]; bool FitX; bool FitY[IMPLOT_Y_AXES]; + double* LinkedXmin; + double* LinkedXmax; + double* LinkedYmin[IMPLOT_Y_AXES]; + double* LinkedYmax[IMPLOT_Y_AXES]; ImPlotNextPlotData() { HasXRange = false; ShowDefaultTicksX = true; FitX = false; + LinkedXmin = LinkedXmax = NULL; for (int i = 0; i < IMPLOT_Y_AXES; ++i) { HasYRange[i] = false; ShowDefaultTicksY[i] = true; FitY[i] = false; + LinkedYmin[i] = LinkedYmax[i] = NULL; } } }; @@ -675,6 +684,11 @@ void FitPoint(const ImPlotPoint& p); inline bool RangesOverlap(const ImPlotRange& r1, const ImPlotRange& r2) { return r1.Min <= r2.Max && r2.Min <= r1.Max; } +// Updates pointers for linked axes from axis internal range. +void PushLinkedAxis(ImPlotAxis& axis); +// Updates axis internal range from points for linked axes. +void PullLinkedAxis(ImPlotAxis& axis); + //----------------------------------------------------------------------------- // [SECTION] Legend Utils //-----------------------------------------------------------------------------