@spider-analyzer/timeline 5.0.4 → 5.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spider-analyzer/timeline",
3
- "version": "5.0.4",
3
+ "version": "5.0.6",
4
4
  "description": "React graphical component to display metric over time with a time selection feature.",
5
5
  "author": "Thibaut Raballand <spider.analyzer@gmail.com> (https://spider-analyzer.io)",
6
6
  "license": "MIT",
package/src/TimeLine.tsx CHANGED
@@ -189,15 +189,31 @@ const TimeLineInner = forwardRef<TimeLineHandle, any>(function TimeLine(props, r
189
189
  xAxis.clamp(true);
190
190
  xAxisRef.current = xAxis;
191
191
 
192
- const ticks = xAxis.ticks(_floor(histoWidth / p.xAxis.spaceBetweenTicks));
192
+ const tickCount = _floor(histoWidth / p.xAxis.spaceBetweenTicks);
193
+ const ticks = xAxis.ticks(tickCount);
194
+ // intervalMs should be domainSpan/(visibleTickCount*barsBetweenTicks).
195
+ // Use ticks[1]-ticks[0] when d3 gives us >= 2 "nice" ticks (preserves
196
+ // the original intent of snapping to minute/hour-aligned intervals);
197
+ // otherwise fall back to domainSpan/tickCount so we never regress to
198
+ // smallestResolution on the very first render (when tick generation
199
+ // can be momentarily sparse).
200
+ const tickIntervalMs = ticks.length >= 2
201
+ ? ticks[1].getTime() - ticks[0].getTime()
202
+ : (+domain.max - +domain.min) / Math.max(tickCount, 1);
193
203
  const intervalMs = _max([
194
- _round(moment(ticks[1]).diff(moment(ticks[0])) / p.xAxis.barsBetweenTicks),
204
+ _round(tickIntervalMs / p.xAxis.barsBetweenTicks),
195
205
  propsRef.current.smallestResolution.asMilliseconds(),
196
206
  ]) as number;
197
207
 
198
208
  patchState({ histoWidth, isActive: true, ticks });
199
209
 
200
- if (shouldReload && intervalMs) {
210
+ // Gate the fetch on a usable histoWidth. Before the first valid
211
+ // width is measured (React mount, ResizeObserver, consumer layout)
212
+ // histoWidth can be <= 0 — in that case we'd otherwise hit the
213
+ // domainSpan/1 fallback and ask the backend for smallestResolution
214
+ // / tickCount=1 granularity over the whole domain. Wait for the
215
+ // width-change effect to re-run getItems with a real width.
216
+ if (shouldReload && intervalMs && histoWidth > 0) {
201
217
  widthOfLastUpdateRef.current = p.width;
202
218
  patchState({ waitForLoad: true });
203
219
  p.onLoadHisto(intervalMs, domain.min, domain.max);
@@ -237,14 +253,19 @@ const TimeLineInner = forwardRef<TimeLineHandle, any>(function TimeLine(props, r
237
253
  return;
238
254
  }
239
255
  const s = stateRef.current;
240
- if (s.isActive) {
256
+ patchState(computeMarginAndWidth(props));
257
+ // Re-run getItems whenever width/margin changes AND we have a
258
+ // domain. Was previously guarded on s.isActive which meant the
259
+ // first getItems call (with an as-yet unknown width) locked us
260
+ // into a bad intervalMs: it set isActive=true but skipped the
261
+ // fetch (histoWidth <= 0 gate), and this effect wouldn't re-fetch
262
+ // because isActive was now true but big=false.
263
+ if (s.domain) {
241
264
  const big =
242
265
  widthOfLastUpdateRef.current !== null
243
266
  && Math.abs((props.width ?? 0) - (widthOfLastUpdateRef.current ?? 0)) > 30;
244
- getItems(props, s.domain, big);
245
- patchState(computeMarginAndWidth(props));
246
- } else {
247
- patchState(computeMarginAndWidth(props));
267
+ const shouldReload = !s.isActive || big || widthOfLastUpdateRef.current === null;
268
+ getItems(props, s.domain, shouldReload);
248
269
  }
249
270
 
250
271
  if (stateRef.current.domain) {