@spider-analyzer/timeline 5.0.6 → 5.0.9

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/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ ## 5.0.9
2
+
3
+ - Perf: cursor edge now tracks the pointer during drag/resize/draw, as
4
+ it did in the pre-hooks class component. Drag/resize hot paths
5
+ (`moveTimeLine`, `onDragCursor`, `onResizeLeftCursor`,
6
+ `onResizeRightCursor`, `onDrawCursor`) commit state via a
7
+ `flushSync`-wrapped `patchStateSync`. React 18 otherwise batches
8
+ updates from d3-drag's native listeners to its scheduler, adding ~1
9
+ frame of latency between pointer and cursor border. Also wrapped
10
+ `Histogram`, `XAxis`, `XGrid` in `React.memo` so the synchronous
11
+ per-event render only reconciles the Cursor subtree; heavy
12
+ histogram/axis/grid trees are skipped when only `start`/`stop`
13
+ change.
14
+
15
+ ## 5.0.8
16
+
17
+ - Perf: memoize the per-render histogram bar list and vertical scale.
18
+ Previously every cursor drag / resize / draw event (60×/sec) rebuilt
19
+ the entire bar list (~550 bars in Network-View's default view) from
20
+ scratch. Under the Luxon-backed shim each rebuild allocated 550 new
21
+ DateTime/MomentLike objects and re-ran d3's time scale — ~150 ms per
22
+ render, i.e. ≈6 fps drag. Wrap `prepareHistogram` and
23
+ `prepareVerticalScale` with `useMemo` keyed on the actual dependencies
24
+ (`domain`, `histoWidth`, `histo`) so they only recompute when those
25
+ change. Cursor drag returns to single-digit-ms render time.
26
+
27
+ ## 5.0.7
28
+
29
+ - Fix: silence the `Invalid prop 'time' of type '_MomentLike', expected
30
+ instance of 'moment2'` React warnings that internal components
31
+ (Histogram, Cursor, XAxis, QualityLine, DragOverlay, CursorSelection,
32
+ HistoToolTip) emitted under every render. The Luxon-backed moment
33
+ shim is a factory function, not a class, so `PropTypes.instanceOf` is
34
+ the wrong check. Replaced with a `momentType` validator that uses
35
+ `moment.isMoment()`. No runtime behavior change — warnings only.
36
+
1
37
  ## 5.0.6
2
38
 
3
39
  - Fix: don't issue the first `onLoadHisto` with a stale `intervalMs`
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var react = require('react');
6
+ var reactDom = require('react-dom');
6
7
  var luxon = require('luxon');
7
8
  var d3Scale = require('d3-scale');
8
9
  var PropTypes11 = require('prop-types');
@@ -172,6 +173,25 @@ moment.tz = (x, zone) => {
172
173
  const base = toDT(x);
173
174
  return new MomentLike(base.setZone(zone));
174
175
  };
176
+ function validate(props, propName, componentName) {
177
+ const v = props[propName];
178
+ if (v == null) return null;
179
+ if (moment.isMoment(v)) return null;
180
+ return new Error(
181
+ `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected a moment-like object.`
182
+ );
183
+ }
184
+ var required = (props, propName, componentName) => {
185
+ const v = props[propName];
186
+ if (v == null) {
187
+ return new Error(
188
+ `The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is \`${v}\`.`
189
+ );
190
+ }
191
+ return validate(props, propName, componentName);
192
+ };
193
+ var momentType = validate;
194
+ momentType.isRequired = required;
175
195
  var moment_shim_default = moment;
176
196
 
177
197
  // src/utils.ts
@@ -375,8 +395,8 @@ DragOverlay.propTypes = {
375
395
  width: PropTypes11__default.default.number.isRequired,
376
396
  marginBottom: PropTypes11__default.default.number,
377
397
  items: PropTypes11__default.default.arrayOf(PropTypes11__default.default.shape({
378
- start: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
379
- end: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
398
+ start: momentType.isRequired,
399
+ end: momentType.isRequired,
380
400
  x1: PropTypes11__default.default.number,
381
401
  x2: PropTypes11__default.default.number,
382
402
  metrics: PropTypes11__default.default.arrayOf(PropTypes11__default.default.number).isRequired,
@@ -686,8 +706,8 @@ CursorSelection.propTypes = {
686
706
  showToolTipLeft: PropTypes11__default.default.func.isRequired,
687
707
  showToolTipRight: PropTypes11__default.default.func.isRequired,
688
708
  items: PropTypes11__default.default.arrayOf(PropTypes11__default.default.shape({
689
- start: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
690
- end: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
709
+ start: momentType.isRequired,
710
+ end: momentType.isRequired,
691
711
  x1: PropTypes11__default.default.number,
692
712
  x2: PropTypes11__default.default.number,
693
713
  metrics: PropTypes11__default.default.arrayOf(PropTypes11__default.default.number).isRequired,
@@ -1273,8 +1293,8 @@ Cursor.propTypes = {
1273
1293
  overlayHeight: PropTypes11__default.default.number.isRequired,
1274
1294
  overlayWidth: PropTypes11__default.default.number.isRequired,
1275
1295
  items: PropTypes11__default.default.arrayOf(PropTypes11__default.default.shape({
1276
- start: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1277
- end: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1296
+ start: momentType.isRequired,
1297
+ end: momentType.isRequired,
1278
1298
  x1: PropTypes11__default.default.number,
1279
1299
  x2: PropTypes11__default.default.number,
1280
1300
  metrics: PropTypes11__default.default.arrayOf(PropTypes11__default.default.number).isRequired,
@@ -1383,8 +1403,8 @@ function Histogram({
1383
1403
  Histogram.propTypes = {
1384
1404
  classes: PropTypes11__default.default.object,
1385
1405
  items: PropTypes11__default.default.arrayOf(PropTypes11__default.default.shape({
1386
- start: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1387
- end: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1406
+ start: momentType.isRequired,
1407
+ end: momentType.isRequired,
1388
1408
  x1: PropTypes11__default.default.number,
1389
1409
  x2: PropTypes11__default.default.number,
1390
1410
  metrics: PropTypes11__default.default.arrayOf(PropTypes11__default.default.number).isRequired,
@@ -1410,6 +1430,7 @@ Histogram.propTypes = {
1410
1430
  barHovered: PropTypes11__default.default.number,
1411
1431
  tooltipVisible: PropTypes11__default.default.bool
1412
1432
  };
1433
+ var Histogram_default = react.memo(Histogram);
1413
1434
 
1414
1435
  // src/timeLineElements/axesStyles.jsx
1415
1436
  var arrow = `m 0,-5 5,5 -5,5`;
@@ -1484,8 +1505,8 @@ function XAxis({ min, max: max2, origin, axisWidth, marks, xAxis, classes, arrow
1484
1505
  XAxis.propTypes = {
1485
1506
  axisWidth: PropTypes11__default.default.number.isRequired,
1486
1507
  classes: PropTypes11__default.default.object,
1487
- min: PropTypes11__default.default.instanceOf(moment_shim_default),
1488
- max: PropTypes11__default.default.instanceOf(moment_shim_default),
1508
+ min: momentType,
1509
+ max: momentType,
1489
1510
  origin: PropTypes11__default.default.shape({
1490
1511
  x: PropTypes11__default.default.number.isRequired,
1491
1512
  y: PropTypes11__default.default.number.isRequired
@@ -1495,6 +1516,7 @@ XAxis.propTypes = {
1495
1516
  arrowPath: PropTypes11__default.default.string,
1496
1517
  onFormatTimeLegend: PropTypes11__default.default.func.isRequired
1497
1518
  };
1519
+ var XAxis_default = react.memo(XAxis);
1498
1520
  function YAxis({ classes, marks, yAxis, onFormatMetricLegend, maxHeight, origin, arrowPath = arrow }) {
1499
1521
  const className = (n) => cn(n, classes);
1500
1522
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1810,8 +1832,8 @@ function HistoTooltip({ metricsDefinition, item, onFormatTimeToolTips, onFormatM
1810
1832
  HistoTooltip.propTypes = {
1811
1833
  classes: PropTypes11__default.default.object,
1812
1834
  item: PropTypes11__default.default.shape({
1813
- start: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1814
- end: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1835
+ start: momentType.isRequired,
1836
+ end: momentType.isRequired,
1815
1837
  x1: PropTypes11__default.default.number,
1816
1838
  x2: PropTypes11__default.default.number,
1817
1839
  metrics: PropTypes11__default.default.arrayOf(PropTypes11__default.default.number).isRequired,
@@ -1879,7 +1901,7 @@ QualityLine.propTypes = {
1879
1901
  xAxis: PropTypes11__default.default.func.isRequired,
1880
1902
  quality: PropTypes11__default.default.shape({
1881
1903
  items: PropTypes11__default.default.arrayOf(PropTypes11__default.default.shape({
1882
- time: PropTypes11__default.default.instanceOf(moment_shim_default).isRequired,
1904
+ time: momentType.isRequired,
1883
1905
  quality: PropTypes11__default.default.number.isRequired,
1884
1906
  tip: PropTypes11__default.default.node
1885
1907
  })),
@@ -1949,6 +1971,7 @@ XAxis2.propTypes = {
1949
1971
  xAxis: PropTypes11__default.default.func,
1950
1972
  yAxisHeight: PropTypes11__default.default.number
1951
1973
  };
1974
+ var XGrid_default = react.memo(XAxis2);
1952
1975
 
1953
1976
  // src/time.ts
1954
1977
  function toMoment(x, zone) {
@@ -1971,8 +1994,8 @@ function timeSpanToMoments(t, zone) {
1971
1994
  return { start: toMomentOpt(t.start, zone), stop: toMomentOpt(t.stop, zone) };
1972
1995
  }
1973
1996
  var Cursor2 = Cursor;
1974
- var Histogram2 = Histogram;
1975
- var XAxis3 = XAxis;
1997
+ var Histogram2 = Histogram_default;
1998
+ var XAxis3 = XAxis_default;
1976
1999
  var YAxis3 = YAxis;
1977
2000
  var Legend2 = Legend;
1978
2001
  var Tools2 = Tools;
@@ -2067,6 +2090,11 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2067
2090
  const patchState = react.useCallback((patch) => {
2068
2091
  setStateRaw((s) => ({ ...s, ...typeof patch === "function" ? patch(s) : patch }));
2069
2092
  }, []);
2093
+ const patchStateSync = react.useCallback((patch) => {
2094
+ reactDom.flushSync(() => {
2095
+ setStateRaw((s) => ({ ...s, ...typeof patch === "function" ? patch(s) : patch }));
2096
+ });
2097
+ }, []);
2070
2098
  const checkAndCorrectDomain = react.useCallback(({ domain: domain2 }) => {
2071
2099
  return checkAndCorrectDomainPure({
2072
2100
  domain: domain2,
@@ -2310,9 +2338,9 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2310
2338
  movedSinceLastFetchedRef.current = 0;
2311
2339
  getItems(p, { min, max: max2 });
2312
2340
  }
2313
- patchState({ domain: { min, max: max2 }, minTime, maxTime, ticks: ticks2 });
2341
+ patchStateSync({ domain: { min, max: max2 }, minTime, maxTime, ticks: ticks2 });
2314
2342
  }
2315
- }, [moveTimeLineCore, getItems, patchState]);
2343
+ }, [moveTimeLineCore, getItems, patchStateSync]);
2316
2344
  const onResizeLeftCursor = react.useCallback((delta, mouse) => {
2317
2345
  const xAxis = xAxisRef.current;
2318
2346
  const s = stateRef.current;
@@ -2332,9 +2360,9 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2332
2360
  }
2333
2361
  handleAutoSliding(mouse, onResizeLeftCursor);
2334
2362
  if (newStop !== s.stop && newStop.isSameOrBefore(s.domain.max) || newStart.isSameOrAfter(s.domain.min)) {
2335
- patchState({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2363
+ patchStateSync({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2336
2364
  }
2337
- }, [handleAutoSliding, patchState]);
2365
+ }, [handleAutoSliding, patchStateSync]);
2338
2366
  const onResizeRightCursor = react.useCallback((delta, mouse) => {
2339
2367
  const xAxis = xAxisRef.current;
2340
2368
  const s = stateRef.current;
@@ -2354,9 +2382,9 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2354
2382
  }
2355
2383
  handleAutoSliding(mouse, onResizeRightCursor);
2356
2384
  if (newStop.isSameOrBefore(s.domain.max) && newStart.isSameOrAfter(s.domain.min)) {
2357
- patchState({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2385
+ patchStateSync({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2358
2386
  }
2359
- }, [handleAutoSliding, patchState]);
2387
+ }, [handleAutoSliding, patchStateSync]);
2360
2388
  const onDragCursor = react.useCallback((delta, mouse) => {
2361
2389
  const xAxis = xAxisRef.current;
2362
2390
  const s = stateRef.current;
@@ -2370,8 +2398,8 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2370
2398
  if (maxDomain.min && newStart.isBefore(maxDomain.min)) newStart = moment_shim_default(maxDomain.min);
2371
2399
  if (maxDomain.max && newStop.isAfter(maxDomain.max)) newStop = moment_shim_default(maxDomain.max);
2372
2400
  handleAutoSliding(mouse, onDragCursor);
2373
- patchState({ start: newStart, stop: newStop });
2374
- }, [handleAutoSliding, patchState]);
2401
+ patchStateSync({ start: newStart, stop: newStop });
2402
+ }, [handleAutoSliding, patchStateSync]);
2375
2403
  const onStartDrawCursor = react.useCallback((pos) => {
2376
2404
  const xAxis = xAxisRef.current;
2377
2405
  patchState({
@@ -2399,9 +2427,9 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2399
2427
  }
2400
2428
  handleAutoSliding(mouse, onDrawCursor);
2401
2429
  if (newStop.isSameOrBefore(s.domain.max) && newStart.isSameOrAfter(s.domain.min)) {
2402
- patchState({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2430
+ patchStateSync({ start: newStart, stop: newStop, maxTimespan: maxTimespan2 });
2403
2431
  }
2404
- }, [handleAutoSliding, patchState]);
2432
+ }, [handleAutoSliding, patchStateSync]);
2405
2433
  const onEndDrawCursor = react.useCallback(() => {
2406
2434
  stopAutoMove();
2407
2435
  const { onCustomRange, selectBarOnClick } = propsRef.current;
@@ -2564,13 +2592,17 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2564
2592
  ticks,
2565
2593
  dragging
2566
2594
  } = state;
2595
+ const verticalScaleData = react.useMemo(() => prepareVerticalScale(), [prepareVerticalScale]);
2596
+ const items = react.useMemo(
2597
+ () => prepareHistogram({ domain, verticalScale: verticalScaleData.verticalScale }),
2598
+ [prepareHistogram, domain, verticalScaleData, histoWidth]
2599
+ );
2600
+ itemsRef.current = items;
2567
2601
  const xAxisHeight = xAxisProp.height || xAxisDefault.height;
2568
2602
  const pointZero = { x: 0, y: height - margin.bottom - xAxisHeight };
2569
2603
  const originCursor = { x: 0, y: margin.top - 5 };
2570
2604
  if (!isFunction(xAxisRef.current)) return null;
2571
- const { verticalScale, verticalMarks, maxHeight } = prepareVerticalScale();
2572
- const items = prepareHistogram({ domain, verticalScale });
2573
- itemsRef.current = items;
2605
+ const { verticalScale, verticalMarks, maxHeight } = verticalScaleData;
2574
2606
  return /* @__PURE__ */ jsxRuntime.jsx(
2575
2607
  "svg",
2576
2608
  {
@@ -2590,7 +2622,7 @@ var TimeLineInner = react.forwardRef(function TimeLine(props, ref) {
2590
2622
  }
2591
2623
  ),
2592
2624
  xAxisProp.showGrid && /* @__PURE__ */ jsxRuntime.jsx(
2593
- XAxis2,
2625
+ XGrid_default,
2594
2626
  {
2595
2627
  classes,
2596
2628
  origin: pointZero,