mirror of
https://github.com/gwm17/implot.git
synced 2024-11-13 22:48:50 -05:00
time-axes almost working!
This commit is contained in:
parent
e5f1cf4bdf
commit
0c76ffe81e
182
implot.cpp
182
implot.cpp
|
@ -517,11 +517,11 @@ void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
|
|||
}
|
||||
}
|
||||
|
||||
void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, ImPlotTimeUnit unit) {
|
||||
char temp[16];
|
||||
void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, ImPlotTimeFmt fmt) {
|
||||
char temp[32];
|
||||
if (tick.ShowLabel) {
|
||||
tick.BufferOffset = buffer.size();
|
||||
FormatTime(tick.PlotPos, temp, 16, unit);
|
||||
FormatTime(tick.PlotPos, temp, 32, fmt);
|
||||
buffer.append(temp, temp + strlen(temp) + 1);
|
||||
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
|
||||
}
|
||||
|
@ -575,17 +575,82 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect
|
|||
}
|
||||
}
|
||||
|
||||
void AddTicksTime(const ImPlotRange& range, ImPlotTickCollection& ticks) {
|
||||
ImPlotTimeUnit unit_range = GetUnitForRange(range.Min, range.Max);
|
||||
ImPlotTimeUnit unit_ticks = unit_range == 0 ? ImPlotTimeUnit_Us : unit_range - 1;
|
||||
printf("%d\n",(int)unit_ticks);
|
||||
double t = FloorTime(range.Min, unit_range);
|
||||
while (t < range.Max) {
|
||||
t = AddTime(t, unit_ticks, 1);
|
||||
ImPlotTick tick(t,false,true);
|
||||
LabelTickTime(tick,ticks.Labels,unit_ticks);
|
||||
ticks.AddTick(tick);
|
||||
// splits
|
||||
// mo: 6 3 2
|
||||
// day:
|
||||
// hr: 12, 6, 3, 2, 1
|
||||
// min: 30: 15, 10, 5, 1
|
||||
|
||||
void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollection& ticks) {
|
||||
const ImPlotTimeUnit unit0 = GetUnitForRange(range.Size() / (plot_width / 100)); // level = 0 (top)
|
||||
const ImPlotTimeUnit unit1 = unit0 + 1; // level = 1 (bottom)
|
||||
|
||||
// maximum allowable density of labels
|
||||
const float max_density = 0.5f;
|
||||
// pixels per major (level 1) division
|
||||
const float pix_per_major_div = plot_width / (float)(range.Size() / TimeUnitSpans[unit1]);
|
||||
// nominal pixels taken up by minor (level 0) label
|
||||
const float minor_label_width = GetTimeLabelWidth(TimeFormatLevel0[unit0]);
|
||||
// the maximum number of minor (level 0) labels that can fit between major (level 1) divisions
|
||||
const int minor_per_major = (int)(max_density * pix_per_major_div / minor_label_width);
|
||||
|
||||
if (unit1 != ImPlotTimeUnit_COUNT) {
|
||||
double t = FloorTime(range.Min, unit1);
|
||||
while (t < range.Max) {
|
||||
if (range.Contains(t)) {
|
||||
ImPlotTick tick_maj(t,true,true);
|
||||
tick_maj.Level = 1;
|
||||
LabelTickTime(tick_maj,ticks.Labels,TimeFormatLevel1[unit1]);
|
||||
ticks.AddTick(tick_maj);
|
||||
ImPlotTick tick_min(t,true,true);
|
||||
tick_min.Level = 0;
|
||||
LabelTickTime(tick_min,ticks.Labels,TimeFormatLevel0[unit0]);
|
||||
ticks.AddTick(tick_min);
|
||||
}
|
||||
// add minor ticks up until next major
|
||||
if (minor_per_major > 1) {
|
||||
double t2 = AddTime(t, unit1, 1);
|
||||
double inc = (t2 - t) / minor_per_major;
|
||||
for (int i = 1; i < minor_per_major; ++i) {
|
||||
double t3 = t + i * inc;
|
||||
if (range.Contains(t3)) {
|
||||
ImPlotTick tick(t3,false,true);
|
||||
tick.Level = 0;
|
||||
LabelTickTime(tick,ticks.Labels,TimeFormatLevel0[unit0]);
|
||||
ticks.AddTick(tick);
|
||||
}
|
||||
}
|
||||
|
||||
if (unit0 == ImPlotTimeUnit_Us) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_Ms) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_S) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_Min) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_Hr) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_Day) {
|
||||
|
||||
}
|
||||
else if (unit0 == ImPlotTimeUnit_Mo) {
|
||||
|
||||
}
|
||||
}
|
||||
t = AddTime(t, unit1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
// printf("%d\n",minor_per_major);
|
||||
}
|
||||
|
||||
void AddTicksCustom(const double* values, const char** labels, int n, ImPlotTickCollection& ticks) {
|
||||
|
@ -614,6 +679,12 @@ void ConstrainAxis(ImPlotAxis& axis) {
|
|||
axis.Range.Min = ConstrainLog(axis.Range.Min);
|
||||
axis.Range.Max = ConstrainLog(axis.Range.Max);
|
||||
}
|
||||
if (ImHasFlag(axis.Flags, ImPlotAxisFlags_Time)) {
|
||||
axis.Range.Min = ConstrainTime(axis.Range.Min);
|
||||
axis.Range.Max = ConstrainTime(axis.Range.Max);
|
||||
// if (axis.Range.Size() < 0.0001)
|
||||
// axis.Range.Max = axis.Range.Min + 0.0001; // TBD
|
||||
}
|
||||
if (axis.Range.Max <= axis.Range.Min)
|
||||
axis.Range.Max = axis.Range.Min + DBL_EPSILON;
|
||||
}
|
||||
|
@ -743,7 +814,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
|
|||
UpdateAxisColors(ImPlotCol_YAxis2, &gp.Col_Y[1]);
|
||||
UpdateAxisColors(ImPlotCol_YAxis3, &gp.Col_Y[2]);
|
||||
|
||||
// BB AND HOVER -----------------------------------------------------------
|
||||
// BB, PADDING, HOVER -----------------------------------------------------------
|
||||
|
||||
// frame
|
||||
ImVec2 frame_size = ImGui::CalcItemSize(size, IMPLOT_DEFAULT_W, IMPLOT_DEFAULT_H);
|
||||
|
@ -767,48 +838,57 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
|
|||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) ||
|
||||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels));
|
||||
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
|
||||
gp.RenderY[i] =
|
||||
gp.Y[i].Present &&
|
||||
(ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
|
||||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
|
||||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels));
|
||||
}
|
||||
// get ticks
|
||||
if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) {
|
||||
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.XAxis.Range, (int)(gp.BB_Canvas.GetWidth() * 0.01f), gp.XTicks);
|
||||
else if (gp.X.IsTime)
|
||||
AddTicksTime(plot.XAxis.Range, gp.XTicks);
|
||||
else
|
||||
AddTicksDefault(plot.XAxis.Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth())), IMPLOT_SUB_DIV, gp.XTicks);
|
||||
}
|
||||
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
|
||||
if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
|
||||
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.YAxis[i].Range, (int)(gp.BB_Canvas.GetHeight() * 0.02f) ,gp.YTicks[i]);
|
||||
else
|
||||
AddTicksDefault(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight())), IMPLOT_SUB_DIV, gp.YTicks[i]);
|
||||
}
|
||||
gp.RenderY[i] = gp.Y[i].Present &&
|
||||
(ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
|
||||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
|
||||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels));
|
||||
}
|
||||
|
||||
// plot bb
|
||||
|
||||
|
||||
// (1) calc top/bot padding and plot height
|
||||
const ImVec2 title_size = ImGui::CalcTextSize(title, NULL, true);
|
||||
const float txt_height = ImGui::GetTextLineHeight();
|
||||
|
||||
const float pad_top = title_size.x > 0.0f ? txt_height + gp.Style.LabelPadding.y : 0;
|
||||
const float pad_bot = (gp.X.HasLabels ? txt_height + gp.Style.LabelPadding.y : 0)
|
||||
+ (x_label ? txt_height + gp.Style.LabelPadding.y : 0)
|
||||
+ (gp.X.IsTime ? txt_height + gp.Style.LabelPadding.y : 0);
|
||||
const float pad_top = title_size.x > 0.0f ? txt_height + gp.Style.LabelPadding.y : 0;
|
||||
const float pad_bot = (gp.X.HasLabels ? txt_height + gp.Style.LabelPadding.y : 0)
|
||||
+ (x_label ? txt_height + gp.Style.LabelPadding.y : 0)
|
||||
+ (gp.X.IsTime ? txt_height + gp.Style.LabelPadding.y : 0);
|
||||
|
||||
const float plot_height = gp.BB_Canvas.GetHeight() - pad_top - pad_bot;
|
||||
|
||||
// (2) get y tick labels (needed for left/right pad)
|
||||
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
|
||||
if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
|
||||
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(plot_height * 0.02f)) ,gp.YTicks[i]);
|
||||
else
|
||||
AddTicksDefault(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(0.0025 * plot_height)), IMPLOT_SUB_DIV, gp.YTicks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// (3) calc left/right pad
|
||||
const float pad_left = (y_label ? txt_height + gp.Style.LabelPadding.x : 0)
|
||||
+ (gp.Y[0].HasLabels ? gp.YTicks[0].MaxWidth + gp.Style.LabelPadding.x : 0);
|
||||
const float pad_right = ((gp.Y[1].Present && gp.Y[1].HasLabels) ? gp.YTicks[1].MaxWidth + gp.Style.LabelPadding.x : 0)
|
||||
+ ((gp.Y[1].Present && gp.Y[2].Present) ? gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y : 0)
|
||||
+ ((gp.Y[2].Present && gp.Y[2].HasLabels) ? gp.YTicks[2].MaxWidth + gp.Style.LabelPadding.x : 0);
|
||||
|
||||
const float plot_width = gp.BB_Canvas.GetWidth() - pad_left - pad_right;
|
||||
|
||||
gp.BB_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot));
|
||||
gp.Hov_Plot = gp.BB_Plot.Contains(IO.MousePos);
|
||||
// (4) get x ticks
|
||||
if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) {
|
||||
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.XAxis.Range, (int)IM_ROUND(plot_width * 0.01f), gp.XTicks);
|
||||
else if (gp.X.IsTime)
|
||||
AddTicksTime(plot.XAxis.Range, plot_width, gp.XTicks);
|
||||
else
|
||||
AddTicksDefault(plot.XAxis.Range, ImMax(2, (int)IM_ROUND(0.0025 * plot_width)), IMPLOT_SUB_DIV, gp.XTicks);
|
||||
}
|
||||
|
||||
// (5) calc plot bb
|
||||
gp.BB_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot));
|
||||
gp.Hov_Plot = gp.BB_Plot.Contains(IO.MousePos);
|
||||
|
||||
// x axis region bb and hover
|
||||
const ImRect xAxisRegion_bb(gp.BB_Plot.GetBL(), ImVec2(gp.BB_Plot.Max.x, gp.BB_Frame.Max.y));
|
||||
|
@ -1132,10 +1212,12 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
|
|||
ImU32 col_min32 = ImGui::ColorConvertFloat4ToU32(col_min);
|
||||
for (int t = 0; t < gp.XTicks.Size; t++) {
|
||||
ImPlotTick& xt = gp.XTicks.Ticks[t];
|
||||
if (xt.Major)
|
||||
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), gp.Col_X.Major, gp.Style.MajorGridSize.x);
|
||||
else if (density < 0.2f)
|
||||
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), col_min32, gp.Style.MinorGridSize.x);
|
||||
if (xt.Level == 0) {
|
||||
if (xt.Major)
|
||||
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), gp.Col_X.Major, gp.Style.MajorGridSize.x);
|
||||
else if (density < 0.2f)
|
||||
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), col_min32, gp.Style.MinorGridSize.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1182,7 +1264,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
|
|||
for (int t = 0; t < gp.XTicks.Size; t++) {
|
||||
ImPlotTick *xt = &gp.XTicks.Ticks[t];
|
||||
if (xt->ShowLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1)
|
||||
DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + gp.Style.LabelPadding.y), xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTicks.GetLabel(t));
|
||||
DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + gp.Style.LabelPadding.y + xt->Level * (txt_height + gp.Style.LabelPadding.y)),
|
||||
xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTicks.GetLabel(t));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
|
||||
|
@ -1241,6 +1324,7 @@ inline void ShowAxisContextMenu(ImPlotAxisState& state) {
|
|||
ImGui::PushItemWidth(75);
|
||||
bool total_lock = state.HasRange && state.RangeCond == ImGuiCond_Always;
|
||||
bool logscale = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
|
||||
bool timesale = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_Time);
|
||||
bool grid = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines);
|
||||
bool ticks = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_TickMarks);
|
||||
bool labels = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_TickLabels);
|
||||
|
@ -1272,6 +1356,8 @@ inline void ShowAxisContextMenu(ImPlotAxisState& state) {
|
|||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_Invert);
|
||||
if (ImGui::Checkbox("Log Scale", &logscale))
|
||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
|
||||
if (ImGui::Checkbox("Time", ×ale))
|
||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_Time);
|
||||
ImGui::Separator();
|
||||
if (ImGui::Checkbox("Grid Lines", &grid))
|
||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines);
|
||||
|
|
|
@ -77,6 +77,8 @@ extern ImPlotContext* GImPlot; // Current implicit context pointer
|
|||
#define IMPLOT_SUB_DIV 10
|
||||
// Zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click)
|
||||
#define IMPLOT_ZOOM_RATE 0.1f
|
||||
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC)
|
||||
#define IMPLOT_MAX_TIME 32503680000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Generic Helpers
|
||||
|
@ -150,7 +152,7 @@ struct ImPlotPointArray {
|
|||
|
||||
typedef int ImPlotScale; // -> enum ImPlotScale_
|
||||
typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_
|
||||
typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_
|
||||
typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_
|
||||
|
||||
// XY axes scaling combinations
|
||||
enum ImPlotScale_ {
|
||||
|
@ -160,18 +162,6 @@ enum ImPlotScale_ {
|
|||
ImPlotScale_LogLog // log x, log y
|
||||
};
|
||||
|
||||
enum ImPlotTimeUnit_ {
|
||||
ImPlotTimeUnit_Us, // microsecond (:29.428 552)
|
||||
ImPlotTimeUnit_Ms, // millisecond (:29.428)
|
||||
ImPlotTimeUnit_S, // second (:29)
|
||||
ImPlotTimeUnit_Min, // minute (7:21pm)
|
||||
ImPlotTimeUnit_Hr, // hour (7pm)
|
||||
ImPlotTimeUnit_Day, // day (10/3)
|
||||
ImPlotTimeUnit_Mo, // month (Oct)
|
||||
ImPlotTimeUnit_Yr, // year (1991)
|
||||
ImPlotTimeUnit_COUNT
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImPlot Structs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -205,12 +195,14 @@ struct ImPlotTick
|
|||
int BufferOffset;
|
||||
bool Major;
|
||||
bool ShowLabel;
|
||||
int Level;
|
||||
|
||||
ImPlotTick(double value, bool major, bool show_label) {
|
||||
PlotPos = value;
|
||||
Major = major;
|
||||
ShowLabel = show_label;
|
||||
BufferOffset = -1;
|
||||
Level = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -585,7 +577,7 @@ void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer);
|
|||
// Label a tick with scientific formating.
|
||||
void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer);
|
||||
// Label a tick with time formatting.
|
||||
void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, ImPlotTimeUnit fmt);
|
||||
void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, ImPlotTimeFmt fmt);
|
||||
|
||||
// Populates a list of ImPlotTicks with normal spaced and formatted ticks
|
||||
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTickCollection& ticks);
|
||||
|
@ -642,6 +634,8 @@ inline double ConstrainNan(double val) { return isnan(val) ? 0 : val; }
|
|||
inline double ConstrainInf(double val) { return val == HUGE_VAL ? DBL_MAX : val == -HUGE_VAL ? - DBL_MAX : val; }
|
||||
// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?)
|
||||
inline double ConstrainLog(double val) { return val <= 0 ? 0.001f : val; }
|
||||
// Turns numbers less than 0 to zero
|
||||
inline double ConstrainTime(double val) { return val < 0 ? 0 : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); }
|
||||
// Computes order of magnitude of double.
|
||||
inline int OrderOfMagnitude(double val) { return val == 0 ? 0 : (int)(floor(log10(fabs(val)))); }
|
||||
// Returns the precision required for a order of magnitude.
|
||||
|
@ -677,18 +671,67 @@ inline T OffsetAndStride(const T* data, int idx, int count, int offset, int stri
|
|||
// [SECTION] Time Utils
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const int DaysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
static const double ImPlotTimeUnitSpans[ImPlotTimeUnit_COUNT] = {0.000001, 0.001, 1, 60, 3600, 86400, 2629800, 31557600};
|
||||
enum ImPlotTimeUnit_ { // primary
|
||||
ImPlotTimeUnit_Us, // microsecond :29.428552
|
||||
ImPlotTimeUnit_Ms, // millisecond :29.428
|
||||
ImPlotTimeUnit_S, // second :29
|
||||
ImPlotTimeUnit_Min, // minute 7:21pm
|
||||
ImPlotTimeUnit_Hr, // hour 7pm
|
||||
ImPlotTimeUnit_Day, // day 10/3
|
||||
ImPlotTimeUnit_Mo, // month Oct
|
||||
ImPlotTimeUnit_Yr, // year 1991
|
||||
ImPlotTimeUnit_COUNT
|
||||
};
|
||||
|
||||
inline ImPlotTimeUnit GetUnitForRange(double smin, double smax) {
|
||||
double range = smax - smin;
|
||||
enum ImPlotTimeFmt_ {
|
||||
ImPlotTimeFmt_SUs, // :29.428552
|
||||
ImPlotTimeFmt_SMs, // :29.428
|
||||
ImPlotTimeFmt_S, // :29
|
||||
ImPlotTimeFmt_HrMin, // 7:21pm
|
||||
ImPlotTimeFmt_Hr, // 7pm
|
||||
ImPlotTimeFmt_DayMo, // 10/3
|
||||
ImPlotTimeFmt_DayMoHrMin, // 10/3 7:21pm
|
||||
ImPlotTimeFmt_DayMoYrHrMin, // 10/3/1991 7:21pm
|
||||
ImPlotTimeFmt_Mo, // Oct
|
||||
ImPlotTimeFmt_Yr // 1991
|
||||
};
|
||||
|
||||
static const int DaysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
static const double TimeUnitSpans[ImPlotTimeUnit_COUNT] = {0.000001, 0.001, 1, 60, 3600, 86400, 2629800, 31557600};
|
||||
static const ImPlotTimeFmt TimeFormatLevel0[ImPlotTimeUnit_COUNT] =
|
||||
{
|
||||
ImPlotTimeFmt_SUs,
|
||||
ImPlotTimeFmt_SMs,
|
||||
ImPlotTimeFmt_S,
|
||||
ImPlotTimeFmt_HrMin,
|
||||
ImPlotTimeFmt_Hr,
|
||||
ImPlotTimeFmt_DayMo,
|
||||
ImPlotTimeFmt_Mo,
|
||||
ImPlotTimeFmt_Yr
|
||||
};
|
||||
static const ImPlotTimeFmt TimeFormatLevel1[ImPlotTimeUnit_COUNT] =
|
||||
{
|
||||
ImPlotTimeFmt_DayMoHrMin,
|
||||
ImPlotTimeFmt_DayMoHrMin,
|
||||
ImPlotTimeFmt_DayMoHrMin,
|
||||
ImPlotTimeFmt_DayMoHrMin,
|
||||
ImPlotTimeFmt_DayMo,
|
||||
ImPlotTimeFmt_DayMo,
|
||||
ImPlotTimeFmt_Yr,
|
||||
ImPlotTimeFmt_Yr
|
||||
};
|
||||
|
||||
|
||||
inline ImPlotTimeUnit GetUnitForRange(double range) {
|
||||
static double cutoffs[ImPlotTimeUnit_COUNT] = {0.001, 1, 60, 3600, 86400, 2629800, 31557600, IMPLOT_MAX_TIME};
|
||||
for (int i = 0; i < ImPlotTimeUnit_COUNT; ++i) {
|
||||
if (range <= ImPlotTimeUnitSpans[i])
|
||||
if (range <= cutoffs[i])
|
||||
return (ImPlotTimeUnit)i;
|
||||
}
|
||||
return ImPlotTimeUnit_Yr;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if year is leap year (366 days long)
|
||||
inline bool IsLeapYear(int year) {
|
||||
if (year % 4 != 0) return false;
|
||||
|
@ -741,13 +784,13 @@ inline double AddTime(double t, ImPlotTimeUnit unit, int count) {
|
|||
case ImPlotTimeUnit_Day: return t + count * 86400;
|
||||
case ImPlotTimeUnit_Yr: count *= 12; // fall-through
|
||||
case ImPlotTimeUnit_Mo: for (int i = 0; i < count; ++i) {
|
||||
time_t s = (time_t)t;
|
||||
GmTime(&s, &GImPlot->Tm);
|
||||
int days = GetDaysInMonth(GImPlot->Tm.tm_year, GImPlot->Tm.tm_mon);
|
||||
t = AddTime(t, ImPlotTimeUnit_Day, days);
|
||||
}
|
||||
return t;
|
||||
default: return t;
|
||||
time_t s = (time_t)t;
|
||||
GmTime(&s, &GImPlot->Tm);
|
||||
int days = GetDaysInMonth(GImPlot->Tm.tm_year, GImPlot->Tm.tm_mon);
|
||||
t = AddTime(t, ImPlotTimeUnit_Day, days);
|
||||
}
|
||||
return t;
|
||||
default: return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,43 +817,86 @@ inline double CeilTime(double t, ImPlotTimeUnit unit) {
|
|||
return AddTime(FloorTime(t, unit), unit, 1);
|
||||
}
|
||||
|
||||
inline void FormatTime(double t, char* buffer, int size, ImPlotTimeUnit unit) {
|
||||
inline void FormatTime(double t, char* buffer, int size, ImPlotTimeFmt fmt) {
|
||||
time_t s = (time_t)t;
|
||||
int ms = (int)(t * 1000 - floor(t) * 1000);
|
||||
int us = (int)(t * 1000000 - floor(t) * 1000000);
|
||||
tm& Tm = GImPlot->Tm;
|
||||
GmTime(&s, &Tm);
|
||||
switch(unit) {
|
||||
case ImPlotTimeUnit_Yr: strftime(buffer, size, "%Y", &Tm); break;
|
||||
case ImPlotTimeUnit_Mo: strftime(buffer, size, "%b", &Tm); break;
|
||||
case ImPlotTimeUnit_Day: strftime(buffer, size, "%m/%d", &Tm); break;
|
||||
case ImPlotTimeUnit_Hr:
|
||||
IM_ASSERT(GmTime(&s, &Tm) != NULL);
|
||||
switch(fmt) {
|
||||
case ImPlotTimeFmt_Yr: strftime(buffer, size, "%Y", &Tm); break;
|
||||
case ImPlotTimeFmt_Mo: strftime(buffer, size, "%b", &Tm); break;
|
||||
case ImPlotTimeFmt_DayMo: snprintf(buffer, size, "%d/%d", Tm.tm_mon + 1, Tm.tm_mday); break;
|
||||
case ImPlotTimeFmt_DayMoHrMin:
|
||||
if (Tm.tm_hour == 0)
|
||||
snprintf(buffer, size, "%d/%d 12:%02dam", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_min);
|
||||
else if (Tm.tm_hour == 12)
|
||||
snprintf(buffer, size, "%d/%d 12%02dpm", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_min);
|
||||
else if (Tm.tm_hour < 12)
|
||||
snprintf(buffer, size, "%d/%d %u:%02dam", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_hour, Tm.tm_min);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%d/%d %u:%02dpm", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_hour - 12, Tm.tm_min);
|
||||
break;
|
||||
case ImPlotTimeFmt_DayMoYrHrMin:
|
||||
if (Tm.tm_hour == 0)
|
||||
snprintf(buffer, size, "%d/%d/%d 12:%02dam", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_year + 1900, Tm.tm_min);
|
||||
else if (Tm.tm_hour == 12)
|
||||
snprintf(buffer, size, "%d/%d/%d 12:%02dpm", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_year + 1900, Tm.tm_min);
|
||||
else if (Tm.tm_hour < 12)
|
||||
snprintf(buffer, size, "%d/%d/%d %u:%02dam", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_year + 1900, Tm.tm_hour, Tm.tm_min);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%d/%d/%d %u:%02dpm", Tm.tm_mon + 1, Tm.tm_mday, Tm.tm_year + 1900, Tm.tm_hour - 12, Tm.tm_min);
|
||||
break;
|
||||
case ImPlotTimeFmt_Hr:
|
||||
if (Tm.tm_hour == 0)
|
||||
snprintf(buffer, size, "12am");
|
||||
else if (Tm.tm_hour == 12)
|
||||
snprintf(buffer, size, "12pm");
|
||||
else if (Tm.tm_hour < 12)
|
||||
snprintf(buffer, size, "%uam", Tm.tm_hour);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%upm", Tm.tm_hour - 12);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%upm", Tm.tm_hour - 12);
|
||||
break;
|
||||
case ImPlotTimeUnit_Min:
|
||||
case ImPlotTimeFmt_HrMin:
|
||||
if (Tm.tm_hour == 0)
|
||||
snprintf(buffer, size, "12:%02dam", Tm.tm_min);
|
||||
else if (Tm.tm_hour == 12)
|
||||
snprintf(buffer, size, "12%02dpm", Tm.tm_min);
|
||||
snprintf(buffer, size, "12:%02dpm", Tm.tm_min);
|
||||
else if (Tm.tm_hour < 12)
|
||||
snprintf(buffer, size, "%u:%02dam", Tm.tm_hour, Tm.tm_min);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%u:%02dpm", Tm.tm_hour - 12, Tm.tm_min);
|
||||
snprintf(buffer, size, "%d:%02dam", Tm.tm_hour, Tm.tm_min);
|
||||
else if (Tm.tm_hour > 12)
|
||||
snprintf(buffer, size, "%d:%02dpm", Tm.tm_hour - 12, Tm.tm_min);
|
||||
break;
|
||||
case ImPlotTimeUnit_S: snprintf(buffer, size, ":%02d", Tm.tm_sec); break;
|
||||
case ImPlotTimeUnit_Ms: snprintf(buffer, size, ":%02d.%03d", Tm.tm_sec, ms); break;
|
||||
case ImPlotTimeUnit_Us: snprintf(buffer, size, ":%02d.%06d", Tm.tm_sec, us); break;
|
||||
case ImPlotTimeFmt_S: snprintf(buffer, size, ":%02d", Tm.tm_sec); break;
|
||||
case ImPlotTimeFmt_SMs: snprintf(buffer, size, ":%02d.%03d", Tm.tm_sec, ms); break;
|
||||
case ImPlotTimeFmt_SUs: snprintf(buffer, size, ":%02d.%06d", Tm.tm_sec, us); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void PrintTime(double t, ImPlotTimeFmt fmt) {
|
||||
char buff[32];
|
||||
FormatTime(t, buff, 32, fmt);
|
||||
printf("%s\n",buff);
|
||||
}
|
||||
|
||||
// Returns the nominally largest possible width for a time format
|
||||
inline float GetTimeLabelWidth(ImPlotTimeFmt fmt) {
|
||||
switch (fmt) {
|
||||
case ImPlotTimeFmt_SUs: return ImGui::CalcTextSize(":88.888888").x; // :29.428552
|
||||
case ImPlotTimeFmt_SMs: return ImGui::CalcTextSize(":88.888").x; // :29.428
|
||||
case ImPlotTimeFmt_S: return ImGui::CalcTextSize(":88").x; // :29
|
||||
case ImPlotTimeFmt_HrMin: return ImGui::CalcTextSize("88:88pm").x; // 7:21pm
|
||||
case ImPlotTimeFmt_Hr: return ImGui::CalcTextSize("8pm").x; // 7pm
|
||||
case ImPlotTimeFmt_DayMo: return ImGui::CalcTextSize("88/88").x; // 10/3
|
||||
case ImPlotTimeFmt_DayMoHrMin: return ImGui::CalcTextSize("88/88 88:88pm").x; // 10/3 7:21pm
|
||||
case ImPlotTimeFmt_DayMoYrHrMin: return ImGui::CalcTextSize("88/88/8888 88:88pm").x; // 10/3/1991 7:21pm
|
||||
case ImPlotTimeFmt_Mo: return ImGui::CalcTextSize("MMM").x; // Oct
|
||||
case ImPlotTimeFmt_Yr: return ImGui::CalcTextSize("8888").x; // 1991
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Internal / Experimental Plotters
|
||||
// No guarantee of forward compatibility here!
|
||||
|
|
Loading…
Reference in New Issue
Block a user