Skip to content

Commit d364e31

Browse files
committed
added offsets and multipliers for x-axis ticking so that it works as the user zooms in very far. only tested for negative x-axis numbers, and there could be bugs for positive numbers. Also want to extend the approach so that the x-axis ticking works when the user zooms out very far.
1 parent 524f9fc commit d364e31

2 files changed

Lines changed: 67 additions & 14 deletions

File tree

implot.cpp

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hov
757757
constexpr float TICK_FILL_X = 0.8f;
758758
constexpr float TICK_FILL_Y = 1.0f;
759759

760-
void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
760+
void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset, int* log10_multiplier) {
761761
if (range.Min == range.Max)
762762
return;
763763
const int nMinor = 10;
@@ -768,6 +768,27 @@ void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixel
768768
const double graphmax = ceil(range.Max / interval) * interval;
769769
bool first_major_set = false;
770770
int first_major_idx = 0;
771+
bool delta_mode = false;
772+
if((range.Max > 0) == (range.Min > 0)) {
773+
double min_abs = ImMin(ImAbs(range.Min),ImAbs(range.Max));
774+
*log10_multiplier = (int)IM_ROUND(ImLog10((range.Max - range.Min)));
775+
if(*log10_multiplier < 0) {
776+
*log10_multiplier = *log10_multiplier - 1;
777+
}
778+
*log10_multiplier = ImSign(static_cast<double>(*log10_multiplier)) * IM_TRUNC(ImAbs(static_cast<double>(*log10_multiplier)/3.)) * 3;
779+
780+
delta_mode = !(*log10_multiplier==0);
781+
782+
if(delta_mode) {
783+
double ten_base = ImPow(10.,-static_cast<double>(*log10_multiplier) + 2 * ((*log10_multiplier < 0) ? -1 : 1));
784+
785+
*offset = (range.Max > 0) ? floor(graphmin*ten_base) / ten_base : ceil(graphmax*ten_base) / ten_base;
786+
787+
} else {
788+
*offset = 0;
789+
}
790+
791+
}
771792
const int idx0 = ticker.TickCount(); // ticker may have user custom ticks
772793
ImVec2 total_size(0,0);
773794
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
@@ -779,12 +800,18 @@ void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixel
779800
first_major_idx = ticker.TickCount();
780801
first_major_set = true;
781802
}
782-
total_size += ticker.AddTick(major, true, 0, true, formatter, formatter_data).LabelSize;
803+
char label[16];
804+
sprintf(label, (char *) formatter_data, (major - (delta_mode ? *offset : 0.))* (delta_mode ? pow(10,-*log10_multiplier) : 1));
805+
total_size += ticker.AddTick(major, true, 0, true, label).LabelSize;
806+
// total_size += ticker.AddTick(major, true, 0, true, formatter, formatter_data).LabelSize;
783807
}
784808
for (int i = 1; i < nMinor; ++i) {
785809
double minor = major + i * interval / nMinor;
786810
if (range.Contains(minor)) {
787-
total_size += ticker.AddTick(minor, false, 0, true, formatter, formatter_data).LabelSize;
811+
char label[16];
812+
sprintf(label, (char *) formatter_data, (minor - (delta_mode ? *offset : 0.))* (delta_mode ? pow(10,-*log10_multiplier) : 1));
813+
total_size += ticker.AddTick(minor, false, 0, true, label).LabelSize;
814+
// total_size += ticker.AddTick(minor, false, 0, true, formatter, formatter_data).LabelSize;
788815
}
789816
}
790817
}
@@ -837,7 +864,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, int exp_min, int exp_max, int
837864
}
838865
}
839866

840-
void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
867+
void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset, int* log10_multiplier) {
841868
int exp_min, exp_max, exp_step;
842869
if (CalcLogarithmicExponents(range, pixels, vertical, exp_min, exp_max, exp_step))
843870
AddTicksLogarithmic(range, exp_min, exp_max, exp_step, ticker, formatter, formatter_data);
@@ -854,7 +881,7 @@ float CalcSymLogPixel(double plt, const ImPlotRange& range, float pixels) {
854881
return (float)(0 + scaleToPixels * (plt - range.Min));
855882
}
856883

857-
void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
884+
void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset, int* log10_multiplier) {
858885
if (range.Min >= -1 && range.Max <= 1) {
859886
Locator_Default(ticker, range, pixels, vertical, formatter, formatter_data);
860887
}
@@ -1257,7 +1284,7 @@ inline ImPlotDateTimeSpec GetDateTimeFmt(const ImPlotDateTimeSpec* ctx, ImPlotTi
12571284
return fmt;
12581285
}
12591286

1260-
void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
1287+
void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset, int* log10_multiplier) {
12611288
IM_ASSERT_USER_ERROR(vertical == false, "Cannot locate Time ticks on vertical axis!");
12621289
(void)vertical;
12631290
// get units for level 0 and level 1 labels
@@ -2618,10 +2645,12 @@ void SetupFinish() {
26182645
const float plot_height = plot.CanvasRect.GetHeight() - pad_top - pad_bot;
26192646

26202647
// (2) get y tick labels (needed for left/right pad)
2648+
double y_offset = 0.;
2649+
int y_log10_multiplier = 0.;
26212650
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
26222651
ImPlotAxis& axis = plot.YAxis(i);
26232652
if (axis.WillRender() && axis.ShowDefaultTicks && plot_height > 0) {
2624-
axis.Locator(axis.Ticker, axis.Range, plot_height, true, axis.Formatter, axis.FormatterData);
2653+
axis.Locator(axis.Ticker, axis.Range, plot_height, true, axis.Formatter, axis.FormatterData, &y_offset, &y_log10_multiplier);
26252654
}
26262655
}
26272656

@@ -2631,10 +2660,12 @@ void SetupFinish() {
26312660
const float plot_width = plot.CanvasRect.GetWidth() - pad_left - pad_right;
26322661

26332662
// (4) get x ticks
2663+
double x_offset = 0.;
2664+
int x_log10_multiplier = 0.;
26342665
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
26352666
ImPlotAxis& axis = plot.XAxis(i);
26362667
if (axis.WillRender() && axis.ShowDefaultTicks && plot_width > 0) {
2637-
axis.Locator(axis.Ticker, axis.Range, plot_width, false, axis.Formatter, axis.FormatterData);
2668+
axis.Locator(axis.Ticker, axis.Range, plot_width, false, axis.Formatter, axis.FormatterData, &x_offset, &x_log10_multiplier);
26382669
}
26392670
}
26402671

@@ -2754,7 +2785,28 @@ void SetupFinish() {
27542785
const ImPlotTicker& tkr = ax.Ticker;
27552786
const bool opp = ax.IsOpposite();
27562787
if (ax.HasLabel()) {
2757-
const char* label = plot.GetAxisLabel(ax);
2788+
const char* base_label = plot.GetAxisLabel(ax);
2789+
char label[36];
2790+
if(x_offset==0. && x_log10_multiplier==0) {
2791+
strcpy(label, base_label);
2792+
} else {
2793+
strcpy(label, "(");
2794+
strcat(label, base_label);
2795+
char label_offset_label[12];
2796+
sprintf(label_offset_label, (char *)ax.FormatterData, ImAbs(x_offset));
2797+
if(x_offset>0) {
2798+
strcat(label," - ");
2799+
} else if (x_offset < 0){
2800+
strcat(label," + ");
2801+
}
2802+
char label_log10_label[12];
2803+
sprintf(label_log10_label, ") x 10^%d", -x_log10_multiplier);
2804+
if(x_offset!=0) {
2805+
strcat(label, label_offset_label);
2806+
}
2807+
strcat(label, label_log10_label);
2808+
}
2809+
27582810
const ImVec2 label_size = ImGui::CalcTextSize(label);
27592811
const float label_offset = (ax.HasTickLabels() ? tkr.MaxSize.y + gp.Style.LabelPadding.y : 0.0f)
27602812
+ (tkr.Levels - 1) * (txt_height + gp.Style.LabelPadding.y)
@@ -2763,6 +2815,7 @@ void SetupFinish() {
27632815
opp ? ax.Datum1 - label_offset - label_size.y : ax.Datum1 + label_offset);
27642816
DrawList.AddText(label_pos, ax.ColorTxt, label);
27652817
}
2818+
27662819
if (ax.HasTickLabels()) {
27672820
for (int j = 0; j < tkr.TickCount(); ++j) {
27682821
const ImPlotTick& tk = tkr.Ticks[j];

implot_internal.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ enum ImPlotMarkerInternal_ {
279279
// [SECTION] Callbacks
280280
//-----------------------------------------------------------------------------
281281

282-
typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
282+
typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset, int* log10_multiplier);
283283

284284
//-----------------------------------------------------------------------------
285285
// [SECTION] Structs
@@ -1703,10 +1703,10 @@ static inline int Formatter_Time(double, char* buff, int size, void* data) {
17031703
// [SECTION] Locator
17041704
//------------------------------------------------------------------------------
17051705

1706-
IMPLOT_API void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
1707-
IMPLOT_API void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
1708-
IMPLOT_API void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
1709-
IMPLOT_API void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
1706+
IMPLOT_API void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset = nullptr, int* log10_multiplier = nullptr);
1707+
IMPLOT_API void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset = nullptr, int* log10_multiplier = nullptr);
1708+
IMPLOT_API void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset = nullptr, int* log10_multiplier = nullptr);
1709+
IMPLOT_API void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data, double* offset = nullptr, int* log10_multiplier = nullptr);
17101710

17111711
} // namespace ImPlot
17121712

0 commit comments

Comments
 (0)