@@ -121,10 +121,16 @@ function formatDateByGranularity(date: Date, granularity: TimeGranularity): stri
121121 * Snap a millisecond value up to the nearest "nice" interval
122122 */
123123function snapToNiceInterval(ms: number): number {
124- const MINUTE = 60 * 1000;
124+ const SECOND = 1000;
125+ const MINUTE = 60 * SECOND;
125126 const HOUR = 60 * MINUTE;
126127 const DAY = 24 * HOUR;
127128
129+ if (ms <= SECOND) return SECOND;
130+ if (ms <= 5 * SECOND) return 5 * SECOND;
131+ if (ms <= 10 * SECOND) return 10 * SECOND;
132+ if (ms <= 15 * SECOND) return 15 * SECOND;
133+ if (ms <= 30 * SECOND) return 30 * SECOND;
128134 if (ms <= MINUTE) return MINUTE;
129135 if (ms <= 5 * MINUTE) return 5 * MINUTE;
130136 if (ms <= 10 * MINUTE) return 10 * MINUTE;
@@ -187,20 +193,7 @@ function fillTimeGaps(
187193 // If filling would create too many points, increase the interval to stay within limits
188194 let effectiveInterval = interval;
189195 if (estimatedPoints > maxPoints) {
190- effectiveInterval = Math.ceil(range / maxPoints);
191- // Round up to a nice interval
192- const MINUTE = 60 * 1000;
193- const HOUR = 60 * MINUTE;
194- if (effectiveInterval < 5 * MINUTE) effectiveInterval = 5 * MINUTE;
195- else if (effectiveInterval < 10 * MINUTE) effectiveInterval = 10 * MINUTE;
196- else if (effectiveInterval < 15 * MINUTE) effectiveInterval = 15 * MINUTE;
197- else if (effectiveInterval < 30 * MINUTE) effectiveInterval = 30 * MINUTE;
198- else if (effectiveInterval < HOUR) effectiveInterval = HOUR;
199- else if (effectiveInterval < 2 * HOUR) effectiveInterval = 2 * HOUR;
200- else if (effectiveInterval < 4 * HOUR) effectiveInterval = 4 * HOUR;
201- else if (effectiveInterval < 6 * HOUR) effectiveInterval = 6 * HOUR;
202- else if (effectiveInterval < 12 * HOUR) effectiveInterval = 12 * HOUR;
203- else effectiveInterval = 24 * HOUR;
196+ effectiveInterval = snapToNiceInterval(Math.ceil(range / maxPoints));
204197 }
205198
206199 // Create a map to collect values for each bucket (for aggregation)
@@ -363,9 +356,12 @@ function generateTimeTicks(minTime: number, maxTime: number, maxTicks = 8): numb
363356 * Always includes time when the data point has a non-midnight time,
364357 * so hovering a specific bar at e.g. 14:00 shows the full timestamp
365358 * even when the axis labels only show the day.
359+ * Seconds are shown whenever the granularity is "seconds" or the
360+ * specific data point has non-zero seconds.
366361 */
367362function formatDateForTooltip(date: Date, granularity: TimeGranularity): string {
368363 const hasTime = date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0;
364+ const hasSeconds = date.getSeconds() !== 0;
369365
370366 if (
371367 granularity === "seconds" ||
@@ -377,7 +373,7 @@ function formatDateForTooltip(date: Date, granularity: TimeGranularity): string
377373 year: "numeric",
378374 hour: "2-digit",
379375 minute: "2-digit",
380- second: granularity === "seconds" ? "2-digit" : undefined,
376+ second: granularity === "seconds" || hasSeconds ? "2-digit" : undefined,
381377 hour12: false,
382378 });
383379 }
0 commit comments