tinybase 8.5.0-beta.1 → 8.5.0-beta.3

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.
Files changed (35) hide show
  1. package/@types/ui-react-dom-charts/index.d.ts +355 -23
  2. package/@types/ui-react-dom-charts/with-schemas/index.d.ts +406 -39
  3. package/min/ui-react/index.js +1 -1
  4. package/min/ui-react/index.js.gz +0 -0
  5. package/min/ui-react/with-schemas/index.js +1 -1
  6. package/min/ui-react/with-schemas/index.js.gz +0 -0
  7. package/min/ui-react-dom/index.js +1 -1
  8. package/min/ui-react-dom/index.js.gz +0 -0
  9. package/min/ui-react-dom/with-schemas/index.js +1 -1
  10. package/min/ui-react-dom/with-schemas/index.js.gz +0 -0
  11. package/min/ui-react-dom-charts/index.js +1 -1
  12. package/min/ui-react-dom-charts/index.js.gz +0 -0
  13. package/min/ui-react-dom-charts/with-schemas/index.js +1 -1
  14. package/min/ui-react-dom-charts/with-schemas/index.js.gz +0 -0
  15. package/min/ui-react-inspector/index.js +1 -1
  16. package/min/ui-react-inspector/index.js.gz +0 -0
  17. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  18. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  19. package/package.json +13 -13
  20. package/readme.md +2 -6
  21. package/releases.md +56 -26
  22. package/ui-react/index.js +3 -0
  23. package/ui-react/with-schemas/index.js +3 -0
  24. package/ui-react-dom/index.js +8 -5
  25. package/ui-react-dom/with-schemas/index.js +8 -5
  26. package/ui-react-dom-charts/index.js +1360 -723
  27. package/ui-react-dom-charts/with-schemas/index.js +1360 -723
  28. package/ui-react-inspector/index.js +13 -10
  29. package/ui-react-inspector/with-schemas/index.js +13 -10
  30. package/ui-svelte/index.js +1 -1
  31. package/ui-svelte/with-schemas/index.js +1 -1
  32. package/ui-svelte-dom/index.js +2 -2
  33. package/ui-svelte-dom/with-schemas/index.js +2 -2
  34. package/ui-svelte-inspector/index.js +2 -2
  35. package/ui-svelte-inspector/with-schemas/index.js +2 -2
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import {Fragment, jsx, jsxs} from 'react/jsx-runtime';
2
+ import {Fragment as Fragment$1, jsx, jsxs} from 'react/jsx-runtime';
3
3
 
4
4
  const getTypeOf = (thing) => typeof thing;
5
5
  const TINYBASE = 'tinybase';
@@ -23,6 +23,7 @@ const getIfNotFunction = (predicate) => (value, then, otherwise) =>
23
23
  : then(value);
24
24
  const GLOBAL = globalThis;
25
25
  const number = Number;
26
+ const string = String;
26
27
  const mathMax = math.max;
27
28
  const mathMin = math.min;
28
29
  const mathCeil = math.ceil;
@@ -38,15 +39,59 @@ const isInteger = number.isInteger;
38
39
  const isNullish = (thing) => thing == null;
39
40
  const isUndefined = (thing) => thing === void 0;
40
41
  const isNull = (thing) => thing === null;
42
+ const isTrue = (thing) => thing === true;
43
+ const isFalse = (thing) => thing === false;
41
44
  const ifNotNullish = getIfNotFunction(isNullish);
42
45
  const ifNotUndefined = getIfNotFunction(isUndefined);
43
46
  const isString = (thing) => getTypeOf(thing) == STRING;
44
47
  const isNumber = (thing) => getTypeOf(thing) == NUMBER;
45
48
  const isArray = (thing) => Array.isArray(thing);
46
49
  const size = (arrayOrString) => arrayOrString.length;
50
+ const test = (regex, subject) => regex.test(subject);
51
+
52
+ const {
53
+ Children,
54
+ Fragment,
55
+ PureComponent,
56
+ createContext,
57
+ isValidElement,
58
+ useCallback,
59
+ useContext,
60
+ useEffect,
61
+ useLayoutEffect,
62
+ useMemo,
63
+ useRef,
64
+ useState,
65
+ useSyncExternalStore,
66
+ } = React;
67
+
68
+ var SourceType = /* @__PURE__ */ ((SourceType2) => {
69
+ SourceType2[(SourceType2['None'] = 0)] = 'None';
70
+ SourceType2[(SourceType2['Query'] = 1)] = 'Query';
71
+ SourceType2[(SourceType2['Table'] = 2)] = 'Table';
72
+ return SourceType2;
73
+ })(SourceType || {});
74
+ const SERIES = '_tinybaseChartSeries';
75
+ const X_AXIS = '_tinybaseChartXAxis';
76
+ const Y_AXIS = '_tinybaseChartYAxis';
77
+ const isSeriesComponent = (component) =>
78
+ typeof component == 'function' && component[SERIES] === true;
79
+ const isXAxisComponent = (component) =>
80
+ typeof component == 'function' && component[X_AXIS] === true;
81
+ const isYAxisComponent = (component) =>
82
+ typeof component == 'function' && component[Y_AXIS] === true;
83
+ const CartesianChartContext = createContext(null);
84
+ const useCartesianChartContext = () => {
85
+ const context = useContext(CartesianChartContext);
86
+ if (context == null) {
87
+ throw new Error('Series components must be used inside a CartesianChart');
88
+ }
89
+ return context;
90
+ };
47
91
 
48
92
  const arrayNew = (size2, cb) =>
49
93
  arrayMap(new Array(size2).fill(0), (_, index) => cb(index));
94
+ const arrayHas = (array, value) => array.includes(value);
50
95
  const arrayIndexOf = (array, value) => array.indexOf(value);
51
96
  const arrayEvery = (array, cb) => array.every(cb);
52
97
  const arrayIsEqual = (array1, array2) =>
@@ -56,90 +101,14 @@ const arrayOrValueEqual = (value1, value2) =>
56
101
  isArray(value1) && isArray(value2)
57
102
  ? arrayIsEqual(value1, value2)
58
103
  : value1 === value2;
104
+ const arraySort = (array, sorter) => array.sort(sorter);
59
105
  const arrayForEach = (array, cb) => array.forEach(cb);
60
106
  const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
61
107
  const arrayMap = (array, cb) => array.map(cb);
62
108
  const arrayIsEmpty = (array) => size(array) == 0;
63
109
  const arrayFilter = (array, cb) => array.filter(cb);
64
-
65
- const {
66
- PureComponent,
67
- createContext,
68
- useCallback,
69
- useContext,
70
- useEffect,
71
- useLayoutEffect,
72
- useMemo,
73
- useRef,
74
- useState,
75
- useSyncExternalStore,
76
- } = React;
77
-
78
- const DEFAULT_SIZE = [1e3, 1e3];
79
- const DEFAULT_FONT_SIZE = 12;
80
- const DEFAULT_STYLE = [0.5, 0.5, 0.25, 3.5, 4, 1, 1];
81
- const useLayout = () => {
82
- const svgRef = useRef(null);
83
- const [chartLayout, setChartLayout] = useState([
84
- DEFAULT_SIZE,
85
- getDefaultStyle(DEFAULT_FONT_SIZE),
86
- ]);
87
- useLayoutEffect(() => {
88
- const svg = svgRef.current;
89
- if (isNull(svg)) {
90
- return;
91
- }
92
- const updateLayout = ({contentRect}) => {
93
- const style = svg.ownerDocument.defaultView?.getComputedStyle(svg);
94
- const nextLayout = [getSvgSize(contentRect), getStyle(style)];
95
- setChartLayout((chartLayout2) =>
96
- isLayoutEqual(chartLayout2, nextLayout) ? chartLayout2 : nextLayout,
97
- );
98
- };
99
- const observer = new ResizeObserver(([entry]) => updateLayout(entry));
100
- observer.observe(svg);
101
- return () => observer.disconnect();
102
- }, []);
103
- return [svgRef, ...chartLayout];
104
- };
105
- const getPlotSize = ([, chartSize, chartStyle]) => {
106
- const [, , width, height] = getPlotFrame(chartSize, chartStyle);
107
- return [width, height];
108
- };
109
- const getLabelSize = ([, , chartStyle]) => chartStyle[6];
110
- const getPlotFrame = (
111
- [width, height],
112
- [, , , xAxisHeight, yAxisWidth, inset, fontSize],
113
- ) => {
114
- const plotX = inset + mathMax(mathMin(yAxisWidth, width / 2 - 2 * inset), 0);
115
- const plotY = inset + fontSize / 2;
116
- const plotRight = inset + fontSize / 2;
117
- const plotHeight = mathMax(
118
- height -
119
- plotY -
120
- mathMax(mathMin(xAxisHeight, height / 2 - plotY - inset), 0) -
121
- inset,
122
- 0,
123
- );
124
- return [plotX, plotY, mathMax(width - plotX - plotRight, 0), plotHeight];
125
- };
126
- const getDefaultStyle = (fontSize) =>
127
- arrayMap(DEFAULT_STYLE, (value) => value * fontSize);
128
- const getStyle = (style) => {
129
- const fontSize = parseFloat(style?.fontSize ?? '');
130
- return getDefaultStyle(
131
- isFiniteNumber(fontSize) ? fontSize : DEFAULT_FONT_SIZE,
132
- );
133
- };
134
- const getSvgSize = ({width, height}) => [
135
- mathRound(width) || DEFAULT_SIZE[0],
136
- mathRound(height) || DEFAULT_SIZE[1],
137
- ];
138
- const isLayoutEqual = ([chartSize1, chartStyle1], [chartSize2, chartStyle2]) =>
139
- arrayIsEqual(chartSize1, chartSize2) &&
140
- arrayIsEqual(chartStyle1, chartStyle2);
141
-
142
- const CURRENT_COLOR = 'currentColor';
110
+ const arrayPush = (array, ...values) => array.push(...values);
111
+ const arrayShift = (array) => array.shift();
143
112
 
144
113
  const collSize = (coll) => coll?.size ?? 0;
145
114
 
@@ -282,6 +251,9 @@ const getScaledPoints = (
282
251
  points,
283
252
  [xMin, xMax, yMin, yMax],
284
253
  [width, height],
254
+ xValues,
255
+ xTitle,
256
+ yTitle,
285
257
  ) => {
286
258
  const numericX =
287
259
  kind == 'line' &&
@@ -289,17 +261,24 @@ const getScaledPoints = (
289
261
  const xDomain = numericX ? [xMin, xMax] : [0, 0];
290
262
  const yDomain = [yMin ?? 0, yMax ?? 0];
291
263
  const xCategories = /* @__PURE__ */ new Map();
292
- arrayForEach(points, ([, xValue]) => {
293
- if (!xCategories.has(xValue)) {
294
- xCategories.set(xValue, collSize(xCategories));
295
- }
296
- });
264
+ arrayForEach(
265
+ xValues == null || arrayIsEmpty(xValues)
266
+ ? arrayMap(points, ([, xValue]) => xValue)
267
+ : xValues,
268
+ (xValue) => {
269
+ if (!xCategories.has(xValue)) {
270
+ xCategories.set(xValue, collSize(xCategories));
271
+ }
272
+ },
273
+ );
297
274
  return arrayMap(points, ([rowId, xValue, yValue]) => [
298
275
  rowId,
299
276
  xValue,
300
277
  yValue,
301
278
  getX(xValue, numericX, xDomain, xCategories, width, kind),
302
279
  getY(yValue, yDomain, height),
280
+ xTitle,
281
+ yTitle,
303
282
  ]);
304
283
  };
305
284
  const getX = (xValue, numericX, [xMin, xMax], xCategories, width, kind) =>
@@ -328,7 +307,7 @@ const getBounds = (kind, points) => {
328
307
  }
329
308
  return [points[0]?.[1], points[size(points) - 1]?.[1], yMin, yMax];
330
309
  };
331
- const getYTicks = ([, , yMin, yMax], [, height], labelSize) => {
310
+ const getYTicks = ([, , yMin, yMax], [, height], labelSize, tickCount) => {
332
311
  if (isUndefined(yMin) || isUndefined(yMax)) {
333
312
  return [];
334
313
  }
@@ -338,31 +317,95 @@ const getYTicks = ([, , yMin, yMax], [, height], labelSize) => {
338
317
  return getTicks(
339
318
  yMin,
340
319
  yMax,
341
- TARGET_TICKS,
320
+ getTickCount(tickCount),
342
321
  labelSize,
343
322
  height,
344
323
  isInteger(yMin) && isInteger(yMax),
345
324
  );
346
325
  };
347
- const getXTicks = (kind, [xMin, xMax], [width], labelSize) =>
326
+ const getXTicks = (kind, [xMin, xMax], [width], labelSize, tickCount) =>
348
327
  kind == 'line' && isNumber(xMin) && isNumber(xMax) && xMin != xMax
349
328
  ? getTicks(
350
329
  xMin,
351
330
  xMax,
352
- TARGET_TICKS,
331
+ getTickCount(tickCount),
353
332
  labelSize,
354
333
  width,
355
334
  isInteger(xMin) && isInteger(xMax),
356
335
  )
357
336
  : [];
358
337
  const getTickBounds = ([xMin, xMax, yMin, yMax], xTicks, yTicks) => [
359
- arrayIsEmpty(xTicks) ? xMin : mathMin(xMin, xTicks[0]),
360
- arrayIsEmpty(xTicks) ? xMax : mathMax(xMax, xTicks[size(xTicks) - 1]),
338
+ arrayIsEmpty(xTicks) ? xMin : getMinTickBound(xMin, xTicks[0]),
339
+ arrayIsEmpty(xTicks) ? xMax : getMaxTickBound(xMax, xTicks[size(xTicks) - 1]),
361
340
  arrayIsEmpty(yTicks) ? yMin : mathMin(yMin ?? infinity, yTicks[0]),
362
341
  arrayIsEmpty(yTicks)
363
342
  ? yMax
364
343
  : mathMax(yMax ?? -infinity, yTicks[size(yTicks) - 1]),
365
344
  ];
345
+ const getSeriesSummary = (kind, points, xCellId, yCellId, yLabel) => {
346
+ const [xMin, xMax, yMin, yMax] = getBounds(kind, points);
347
+ const xValues = [];
348
+ const continuousX =
349
+ kind == 'line' &&
350
+ arrayIsEmpty(arrayFilter(points, ([, xValue]) => !isNumber(xValue)));
351
+ arrayForEach(points, ([, xValue]) => {
352
+ if (!arrayHas(xValues, xValue)) {
353
+ arrayPush(xValues, xValue);
354
+ }
355
+ });
356
+ return {
357
+ continuousX,
358
+ xCellId,
359
+ xMin,
360
+ xMax,
361
+ yMin,
362
+ yMax,
363
+ yCellId,
364
+ yLabel,
365
+ xValues,
366
+ };
367
+ };
368
+ const getDomainState = (summaries) => {
369
+ const xValues = [];
370
+ const xMins = [];
371
+ const xMaxes = [];
372
+ const yMins = [];
373
+ const yMaxes = [];
374
+ let continuousX = true;
375
+ let xMin;
376
+ let xMax;
377
+ arrayForEach(summaries, (summary) => {
378
+ continuousX &&= summary.continuousX;
379
+ arrayForEach(summary.xValues, (xValue) => {
380
+ if (!arrayHas(xValues, xValue)) {
381
+ arrayPush(xValues, xValue);
382
+ }
383
+ });
384
+ if (isNumber(summary.xMin) && isNumber(summary.xMax)) {
385
+ xMins.push(summary.xMin);
386
+ xMaxes.push(summary.xMax);
387
+ } else {
388
+ xMin ??= summary.xMin;
389
+ xMax = summary.xMax ?? xMax;
390
+ }
391
+ if (!isUndefined(summary.yMin)) {
392
+ yMins.push(summary.yMin);
393
+ }
394
+ if (!isUndefined(summary.yMax)) {
395
+ yMaxes.push(summary.yMax);
396
+ }
397
+ });
398
+ return {
399
+ bounds: [
400
+ arrayIsEmpty(xMins) ? xMin : mathMin(...xMins),
401
+ arrayIsEmpty(xMaxes) ? xMax : mathMax(...xMaxes),
402
+ arrayIsEmpty(yMins) ? void 0 : mathMin(...yMins),
403
+ arrayIsEmpty(yMaxes) ? void 0 : mathMax(...yMaxes),
404
+ ],
405
+ continuousX: !arrayIsEmpty(summaries) && continuousX,
406
+ xValues,
407
+ };
408
+ };
366
409
  const getYDomain = (points, kind = 'bar') =>
367
410
  getDomain([
368
411
  ...(kind == 'bar' ? [0] : []),
@@ -372,6 +415,12 @@ const getDomain = (values) => {
372
415
  const min = mathMin(...values);
373
416
  return min == infinity ? [0, 0] : [min, mathMax(...values)];
374
417
  };
418
+ const getMinTickBound = (bound, tick) =>
419
+ isNumber(bound) ? mathMin(bound, tick) : tick;
420
+ const getMaxTickBound = (bound, tick) =>
421
+ isNumber(bound) ? mathMax(bound, tick) : tick;
422
+ const getTickCount = (tickCount = TARGET_TICKS) =>
423
+ isFiniteNumber(tickCount) ? mathMax(mathRound(tickCount), 1) : TARGET_TICKS;
375
424
  const getRounded = (value) => mathRound(value * 1e6) / 1e6;
376
425
  const getXValue = (cell) =>
377
426
  isNumber(cell)
@@ -380,527 +429,117 @@ const getXValue = (cell) =>
380
429
  : void 0
381
430
  : isString(cell)
382
431
  ? cell
383
- : void 0;
432
+ : isTrue(cell) || isFalse(cell)
433
+ ? cell
434
+ : void 0;
384
435
  const getYValue = (cell) =>
385
436
  isNumber(cell) && isFiniteNumber(cell) ? cell : void 0;
386
437
 
387
- const XAxis = ({
438
+ const CURRENT_COLOR = 'currentColor';
439
+
440
+ const Bars = ({
388
441
  points,
389
- xTicks,
390
- xMin,
391
- xMax,
392
- xTitle,
393
442
  plotFrame,
394
- tickSize,
395
- tickGap,
396
- axisHeight,
397
- fontSize,
443
+ barGap,
444
+ barSeriesCount,
445
+ barSeriesIndex,
446
+ setTooltipPoint,
447
+ yMin = 0,
448
+ yMax = 0,
398
449
  }) => {
399
- const [plotX, plotY, plotWidth, plotHeight] = plotFrame;
400
- const titleGap = mathMax(axisHeight - tickSize - tickGap - 2 * fontSize, 0);
401
- return /* @__PURE__ */ jsxs('g', {
402
- className: 'x',
403
- dominantBaseline: 'hanging',
404
- textAnchor: 'middle',
405
- children: [
406
- /* @__PURE__ */ jsx('path', {
407
- className: 'line',
408
- d: `M${plotX},${plotY + plotHeight}h${plotWidth}`,
409
- fill: 'none',
410
- stroke: CURRENT_COLOR,
411
- strokeOpacity: 0.5,
412
- strokeWidth: 1,
413
- }),
414
- /* @__PURE__ */ jsx('g', {
415
- className: 'ticks',
416
- children:
417
- arrayIsEmpty(xTicks) || !isNumber(xMin) || !isNumber(xMax)
418
- ? arrayMap(points, ([rowId, xValue, , x]) =>
419
- /* @__PURE__ */ jsx(
420
- 'text',
421
- {
422
- x: plotX + x,
423
- y: plotY + plotHeight + tickSize + tickGap,
424
- children: xValue,
425
- },
426
- rowId,
427
- ),
428
- )
429
- : arrayMap(xTicks, (tick) => {
430
- const x = getScale(tick, xMin, xMax, plotWidth);
431
- return /* @__PURE__ */ jsx(
432
- 'text',
433
- {
434
- x: plotX + x,
435
- y: plotY + plotHeight + tickSize + tickGap,
436
- children: tick,
437
- },
438
- tick,
439
- );
440
- }),
441
- }),
442
- /* @__PURE__ */ jsx('text', {
443
- className: 'title',
444
- x: plotX + plotWidth / 2,
445
- y: plotY + plotHeight + tickSize + tickGap + fontSize + titleGap,
446
- children: xTitle,
447
- }),
448
- ],
450
+ const [plotX, plotY, width, height] = plotFrame;
451
+ const baselineY = height - getScale(0, yMin, yMax, height);
452
+ const pointsSize = size(points);
453
+ const fullBarWidth = arrayIsEmpty(points) ? 0 : width / pointsSize;
454
+ const barCount = mathMax(barSeriesCount, 1);
455
+ const barIndex = mathMax(barSeriesIndex, 0);
456
+ const barGroupWidth = mathMax(fullBarWidth - barGap, 0);
457
+ const barWidth = mathMax(
458
+ (barGroupWidth - barGap * (barCount - 1)) / barCount,
459
+ 0,
460
+ );
461
+ return arrayMap(points, (point) => {
462
+ const [rowId, , , x, pointY] = point;
463
+ const y = mathMin(pointY, baselineY);
464
+ return /* @__PURE__ */ jsx(
465
+ 'rect',
466
+ {
467
+ className: 'bar',
468
+ height: mathAbs(baselineY - pointY),
469
+ onPointerEnter: () => setTooltipPoint(point),
470
+ onPointerLeave: () => setTooltipPoint(void 0),
471
+ width: barWidth,
472
+ x: plotX + x - barGroupWidth / 2 + (barWidth + barGap) * barIndex,
473
+ y: plotY + y,
474
+ },
475
+ rowId,
476
+ );
449
477
  });
450
478
  };
451
479
 
452
- const YAxis = ({
453
- yTicks,
454
- yMin,
455
- yMax,
456
- yTitle,
457
- plotFrame,
458
- tickSize,
459
- tickGap,
460
- axisWidth,
461
- }) => {
462
- const [plotX, plotY, , plotHeight] = plotFrame;
463
- return isNullish(yMin) || isNullish(yMax)
464
- ? null
465
- : /* @__PURE__ */ jsxs('g', {
466
- className: 'y',
467
- children: [
468
- /* @__PURE__ */ jsx('path', {
469
- className: 'line',
470
- d: `M${plotX},${plotY}v${plotHeight}`,
471
- fill: 'none',
472
- stroke: CURRENT_COLOR,
473
- strokeOpacity: 0.5,
474
- strokeWidth: 1,
475
- }),
476
- /* @__PURE__ */ jsx('g', {
477
- className: 'ticks',
478
- dominantBaseline: 'middle',
479
- textAnchor: 'end',
480
- children: arrayMap(yTicks, (tick) => {
481
- const y = plotHeight - getScale(tick, yMin, yMax, plotHeight);
482
- return /* @__PURE__ */ jsx(
483
- 'text',
484
- {x: plotX - tickSize - tickGap, y: plotY + y, children: tick},
485
- tick,
486
- );
487
- }),
488
- }),
489
- /* @__PURE__ */ jsx('text', {
490
- className: 'title',
491
- dominantBaseline: 'text-before-edge',
492
- textAnchor: 'middle',
493
- transform: `translate(${plotX - axisWidth} ${plotFrame[1] + plotFrame[3] / 2}) rotate(-90)`,
494
- children: yTitle,
495
- }),
496
- ],
497
- });
498
- };
480
+ const object = Object;
481
+ const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
482
+ const objEntries = object.entries;
483
+ const isObject = (obj) =>
484
+ !isNullish(obj) &&
485
+ ifNotNullish(
486
+ getPrototypeOf(obj),
487
+ (objPrototype) =>
488
+ objPrototype == object.prototype ||
489
+ isNullish(getPrototypeOf(objPrototype)),
499
490
 
500
- const Axes = ({
501
- points,
502
- xTicks,
503
- yTicks,
504
- bounds: [xMin, xMax, yMin, yMax],
505
- titles: [xTitle, yTitle],
506
- xAxisHeight,
507
- yAxisWidth,
508
- fontSize,
509
- ...sharedProps
510
- }) => {
511
- return /* @__PURE__ */ jsxs('g', {
512
- className: 'axes',
513
- fill: CURRENT_COLOR,
514
- fillOpacity: 0.75,
515
- children: [
516
- /* @__PURE__ */ jsx(YAxis, {
517
- ...sharedProps,
518
- yTicks,
519
- yMin,
520
- yMax,
521
- yTitle,
522
- axisWidth: yAxisWidth,
523
- }),
524
- /* @__PURE__ */ jsx(XAxis, {
525
- ...sharedProps,
526
- points,
527
- xTicks,
528
- xMin,
529
- xMax,
530
- xTitle,
531
- axisHeight: xAxisHeight,
532
- fontSize,
533
- }),
534
- ],
535
- });
536
- };
491
+ /* istanbul ignore next */
492
+ () => true,
493
+ );
494
+ const objIds = object.keys;
495
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
496
+ const objValues = (obj) => object.values(obj);
497
+ const objSize = (obj) => size(objIds(obj));
537
498
 
538
- const Grid = ({
539
- points,
540
- xTicks,
541
- yTicks,
542
- bounds: [xMin, xMax, yMin, yMax],
543
- plotFrame,
544
- tickSize,
545
- }) => {
546
- const [plotX, plotY, width, height] = plotFrame;
547
- return /* @__PURE__ */ jsxs('g', {
548
- className: 'grid',
549
- stroke: CURRENT_COLOR,
550
- strokeOpacity: 0.75,
551
- strokeWidth: 0.5,
552
- children: [
553
- isNullish(yMin) || isNullish(yMax)
554
- ? null
555
- : /* @__PURE__ */ jsx('path', {
556
- className: 'y',
557
- d: arrayJoin(
558
- arrayMap(
559
- arrayFilter(
560
- yTicks,
561
- (tick) => getScale(tick, yMin, yMax, height) != 0,
562
- ),
563
- (tick) =>
564
- `M${plotX - tickSize},${plotY + height - getScale(tick, yMin, yMax, height)}h${width + tickSize}`,
565
- ),
566
- ' ',
567
- ),
568
- }),
569
- arrayIsEmpty(xTicks) || !isNumber(xMin) || !isNumber(xMax)
570
- ? /* @__PURE__ */ jsx('path', {
571
- className: 'x',
572
- d: arrayJoin(
573
- arrayMap(
574
- arrayFilter(points, ([, , , x]) => x != 0),
575
- ([, , , x]) => `M${plotX + x},${plotY}v${height + tickSize}`,
576
- ),
577
- ' ',
578
- ),
579
- })
580
- : /* @__PURE__ */ jsx('path', {
581
- className: 'x',
582
- d: arrayJoin(
583
- arrayMap(
584
- arrayFilter(
585
- xTicks,
586
- (tick) => getScale(tick, xMin, xMax, width) != 0,
587
- ),
588
- (tick) =>
589
- `M${plotX + getScale(tick, xMin, xMax, width)},${plotY}v${height + tickSize}`,
590
- ),
591
- ' ',
592
- ),
593
- }),
594
- ],
595
- });
499
+ /* istanbul ignore next */
500
+ const objIsEqual = (
501
+ obj1,
502
+ obj2,
503
+ isEqual = (value1, value2) => value1 === value2,
504
+ ) => {
505
+ const entries1 = objEntries(obj1);
506
+ return (
507
+ size(entries1) === objSize(obj2) &&
508
+ arrayEvery(entries1, ([index, value1]) =>
509
+ isObject(value1)
510
+ ? /* istanbul ignore next */
511
+ isObject(obj2[index])
512
+ ? objIsEqual(obj2[index], value1, isEqual)
513
+ : false
514
+ : isEqual(value1, obj2[index]),
515
+ )
516
+ );
596
517
  };
597
518
 
598
- const Marks = ({getMark, points, setTooltipPoint}) =>
599
- arrayMap(points, (point, index) => {
600
- const [rowId] = point;
601
- return /* @__PURE__ */ jsx(
602
- 'g',
603
- {
604
- onPointerEnter: () => setTooltipPoint(point),
605
- onPointerLeave: () => setTooltipPoint(void 0),
606
- children: getMark(point, index),
607
- },
608
- rowId,
609
- );
610
- });
519
+ const jsonString = JSON.stringify;
611
520
 
612
- const Bars = ({
613
- points,
614
- plotFrame,
615
- barGap,
616
- setTooltipPoint,
617
- yMin = 0,
618
- yMax = 0,
619
- }) => {
620
- const [plotX, plotY, width, height] = plotFrame;
621
- const baselineY = height - getScale(0, yMin, yMax, height);
622
- const pointsSize = size(points);
623
- const fullBarWidth = arrayIsEmpty(points) ? 0 : width / pointsSize;
624
- const barWidth = arrayIsEmpty(points) ? 0 : mathMax(fullBarWidth - barGap, 0);
625
- return /* @__PURE__ */ jsx(Marks, {
626
- points,
627
- getMark: ([, , , x, pointY]) => {
628
- const y = mathMin(pointY, baselineY);
629
- return /* @__PURE__ */ jsx('rect', {
630
- className: 'bar',
631
- fill: CURRENT_COLOR,
632
- x: plotX + x - barWidth / 2,
633
- y: plotY + y,
634
- width: barWidth,
635
- height: mathAbs(baselineY - pointY),
636
- });
637
- },
638
- setTooltipPoint,
639
- });
521
+ const TINYBASE_CONTEXT = TINYBASE + '_uirc';
522
+ const Context = GLOBAL[TINYBASE_CONTEXT]
523
+ ? /* istanbul ignore next */
524
+ GLOBAL[TINYBASE_CONTEXT]
525
+ : (GLOBAL[TINYBASE_CONTEXT] = createContext([]));
526
+ const useThing = (id, offset) => {
527
+ const contextValue = useContext(Context);
528
+ return isUndefined(id)
529
+ ? contextValue[offset * 2]
530
+ : isString(id)
531
+ ? objGet(contextValue[offset * 2 + 1], id)
532
+ : id;
640
533
  };
641
-
642
- const Line = ({plotFrame, points, setTooltipPoint}) => {
643
- const [plotX, plotY, , height] = plotFrame;
644
- return /* @__PURE__ */ jsxs(Fragment, {
645
- children: [
646
- /* @__PURE__ */ jsx('path', {
647
- className: 'area',
648
- d: getAreaPath(points, plotX, plotY, height),
649
- fill: CURRENT_COLOR,
650
- fillOpacity: 0.25,
651
- stroke: 'none',
652
- }),
653
- /* @__PURE__ */ jsx('path', {
654
- className: 'line',
655
- d: getLinePath(points, plotX, plotY),
656
- fill: 'none',
657
- stroke: CURRENT_COLOR,
658
- strokeOpacity: 0.75,
659
- strokeWidth: 2,
660
- }),
661
- /* @__PURE__ */ jsx('g', {
662
- className: 'points',
663
- fill: CURRENT_COLOR,
664
- children: arrayMap(points, (point) => {
665
- const [rowId, , , x, y] = point;
666
- return /* @__PURE__ */ jsx(
667
- 'circle',
668
- {
669
- cx: plotX + x,
670
- cy: plotY + y,
671
- onPointerEnter: () => setTooltipPoint(point),
672
- onPointerLeave: () => setTooltipPoint(void 0),
673
- r: 5,
674
- },
675
- rowId,
676
- );
677
- }),
678
- }),
679
- ],
680
- });
534
+ const useThingOrThingById = (thingOrThingId, offset) => {
535
+ const thing = useThing(thingOrThingId, offset);
536
+ return isUndefined(thingOrThingId) || isString(thingOrThingId)
537
+ ? thing
538
+ : thingOrThingId;
681
539
  };
682
- const getLinePath = (points, plotX, plotY) =>
683
- arrayJoin(
684
- arrayMap(
685
- points,
686
- ([, , , x, y], index) =>
687
- `${index == 0 ? 'M' : 'L'}${plotX + x},${plotY + y}`,
688
- ),
689
- ' ',
690
- );
691
- const getAreaPath = (points, plotX, plotY, height) =>
692
- arrayIsEmpty(points)
693
- ? ''
694
- : `${getLinePath(points, plotX, plotY)} L${plotX + points[size(points) - 1][3]},${plotY + height} L${plotX + points[0][3]},${plotY + height} Z`;
695
540
 
696
- const Plot = ({
697
- kind,
698
- points,
699
- plotFrame,
700
- barGap,
701
- setTooltipPoint,
702
- bounds: [, , yMin, yMax],
703
- }) => {
704
- const sharedProps = {points, setTooltipPoint};
705
- return /* @__PURE__ */ jsx('g', {
706
- className: 'plot',
707
- children:
708
- kind == 'line'
709
- ? /* @__PURE__ */ jsx(Line, {...sharedProps, plotFrame})
710
- : /* @__PURE__ */ jsx(Bars, {
711
- ...sharedProps,
712
- plotFrame,
713
- barGap,
714
- yMin,
715
- yMax,
716
- }),
717
- });
718
- };
719
-
720
- const TOOLTIP_WIDTH = 160;
721
- const TOOLTIP_HEIGHT = 60;
722
- const TOOLTIP_GAP = 12;
723
- const TOOLTIP_PADDING = 12;
724
- const Tooltip = ({
725
- point,
726
- width,
727
- height,
728
- plotFrame,
729
- titles: [xTitle, yTitle],
730
- }) => {
731
- if (isNullish(point)) {
732
- return null;
733
- }
734
- const [, xValue, yValue, x, y] = point;
735
- const [plotX, plotY] = plotFrame;
736
- const tooltipX =
737
- x + TOOLTIP_GAP + TOOLTIP_WIDTH > width
738
- ? x - TOOLTIP_GAP - TOOLTIP_WIDTH
739
- : x + TOOLTIP_GAP;
740
- const tooltipY = mathMax(
741
- mathMin(y - TOOLTIP_GAP - TOOLTIP_HEIGHT, height - TOOLTIP_HEIGHT),
742
- 0,
743
- );
744
- return /* @__PURE__ */ jsxs(Fragment, {
745
- children: [
746
- /* @__PURE__ */ jsx('path', {
747
- className: 'tooltip-lines',
748
- pointerEvents: 'none',
749
- stroke: CURRENT_COLOR,
750
- strokeOpacity: 0.25,
751
- strokeWidth: 1,
752
- d: `M${plotX + x},${plotY}v${height}M${plotX},${plotY + y}h${width}`,
753
- }),
754
- /* @__PURE__ */ jsxs('g', {
755
- className: 'tooltip',
756
- transform: `translate(${plotX + tooltipX} ${plotY + tooltipY})`,
757
- fill: CURRENT_COLOR,
758
- children: [
759
- /* @__PURE__ */ jsx('rect', {
760
- fillOpacity: 0.25,
761
- width: TOOLTIP_WIDTH,
762
- height: TOOLTIP_HEIGHT,
763
- rx: 4,
764
- }),
765
- /* @__PURE__ */ jsxs('text', {
766
- x: TOOLTIP_PADDING,
767
- y: 22,
768
- children: [xTitle, ': ', xValue],
769
- }),
770
- /* @__PURE__ */ jsxs('text', {
771
- x: TOOLTIP_PADDING,
772
- y: 46,
773
- children: [yTitle, ': ', yValue],
774
- }),
775
- ],
776
- }),
777
- ],
778
- });
779
- };
780
-
781
- const Layout = ({
782
- className,
783
- kind,
784
- titles,
785
- layout: [svgRef, chartSize, chartStyle],
786
- ...sharedProps
787
- }) => {
788
- const [width, height] = chartSize;
789
- const plotFrame = getPlotFrame(chartSize, chartStyle);
790
- const [, , plotWidth, plotHeight] = plotFrame;
791
- const [tickSize, tickGap, barGap, xAxisHeight, yAxisWidth, , fontSize] =
792
- chartStyle;
793
- const [tooltipPoint, setTooltipPoint] = useState();
794
- const chartProps = {...sharedProps, plotFrame};
795
- return /* @__PURE__ */ jsxs('svg', {
796
- className,
797
- preserveAspectRatio: 'none',
798
- ref: svgRef,
799
- viewBox: `0 0 ${width} ${height}`,
800
- children: [
801
- /* @__PURE__ */ jsx(Grid, {...chartProps, tickSize}),
802
- /* @__PURE__ */ jsx(Axes, {
803
- ...chartProps,
804
- titles,
805
- tickSize,
806
- tickGap,
807
- xAxisHeight,
808
- yAxisWidth,
809
- fontSize,
810
- }),
811
- /* @__PURE__ */ jsx(Plot, {
812
- ...chartProps,
813
- kind,
814
- barGap,
815
- setTooltipPoint,
816
- }),
817
- /* @__PURE__ */ jsx(Tooltip, {
818
- point: tooltipPoint,
819
- width: plotWidth,
820
- height: plotHeight,
821
- plotFrame,
822
- titles,
823
- }),
824
- ],
825
- });
826
- };
827
-
828
- const EmptyChart = ({className, kind, xCellId, yCellId}) => {
829
- const layout = useLayout();
830
- return /* @__PURE__ */ jsx(Layout, {
831
- className,
832
- kind,
833
- points: [],
834
- bounds: [],
835
- titles: [xCellId, yCellId],
836
- xTicks: [],
837
- yTicks: [],
838
- layout,
839
- });
840
- };
841
-
842
- const object = Object;
843
- const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
844
- const objEntries = object.entries;
845
- const isObject = (obj) =>
846
- !isNullish(obj) &&
847
- ifNotNullish(
848
- getPrototypeOf(obj),
849
- (objPrototype) =>
850
- objPrototype == object.prototype ||
851
- isNullish(getPrototypeOf(objPrototype)),
852
-
853
- /* istanbul ignore next */
854
- () => true,
855
- );
856
- const objIds = object.keys;
857
- const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
858
- const objSize = (obj) => size(objIds(obj));
859
-
860
- /* istanbul ignore next */
861
- const objIsEqual = (
862
- obj1,
863
- obj2,
864
- isEqual = (value1, value2) => value1 === value2,
865
- ) => {
866
- const entries1 = objEntries(obj1);
867
- return (
868
- size(entries1) === objSize(obj2) &&
869
- arrayEvery(entries1, ([index, value1]) =>
870
- isObject(value1)
871
- ? /* istanbul ignore next */
872
- isObject(obj2[index])
873
- ? objIsEqual(obj2[index], value1, isEqual)
874
- : false
875
- : isEqual(value1, obj2[index]),
876
- )
877
- );
878
- };
879
-
880
- const jsonString = JSON.stringify;
881
-
882
- const TINYBASE_CONTEXT = TINYBASE + '_uirc';
883
- const Context = GLOBAL[TINYBASE_CONTEXT]
884
- ? /* istanbul ignore next */
885
- GLOBAL[TINYBASE_CONTEXT]
886
- : (GLOBAL[TINYBASE_CONTEXT] = createContext([]));
887
- const useThing = (id, offset) => {
888
- const contextValue = useContext(Context);
889
- return isUndefined(id)
890
- ? contextValue[offset * 2]
891
- : isString(id)
892
- ? objGet(contextValue[offset * 2 + 1], id)
893
- : id;
894
- };
895
- const useThingOrThingById = (thingOrThingId, offset) => {
896
- const thing = useThing(thingOrThingId, offset);
897
- return isUndefined(thingOrThingId) || isString(thingOrThingId)
898
- ? thing
899
- : thingOrThingId;
900
- };
901
-
902
- const OFFSET_STORE = 0;
903
- const OFFSET_QUERIES = 4;
541
+ const OFFSET_STORE = 0;
542
+ const OFFSET_QUERIES = 4;
904
543
 
905
544
  const EMPTY_ARRAY = [];
906
545
  const DEFAULTS = [
@@ -1067,163 +706,1161 @@ const useResultCellListener = (
1067
706
  [queryId, rowId, cellId],
1068
707
  );
1069
708
 
1070
- const useData = (kind, rowIds, chartSize, labelSize, getXCell, getYCell) => {
709
+ const EMPTY_ID = '';
710
+ const useSeriesData = ({
711
+ descending,
712
+ limit,
713
+ offset,
714
+ sortCellId,
715
+ xCellId,
716
+ yCellId,
717
+ }) => {
1071
718
  const [, rerender] = useState();
719
+ const context = useCartesianChartContext();
720
+ const {
721
+ getSeriesId,
722
+ queries,
723
+ queriesOrQueriesId,
724
+ queryId,
725
+ releaseSeriesId,
726
+ sourceType,
727
+ store,
728
+ storeOrStoreId,
729
+ tableId,
730
+ } = context;
731
+ const [seriesId] = useState(getSeriesId);
1072
732
  const handleChange = useCallback(() => rerender([]), [rerender]);
1073
- const points = getDataPoints(rowIds, (rowId) =>
1074
- getDataPoint(rowId, getXCell(rowId), getYCell(rowId)),
733
+ const tableRowIds = useSortedRowIds(
734
+ tableId ?? EMPTY_ID,
735
+ sortCellId ?? xCellId,
736
+ descending,
737
+ offset,
738
+ limit,
739
+ storeOrStoreId,
740
+ );
741
+ const queryRowIds = useResultSortedRowIds(
742
+ queryId ?? EMPTY_ID,
743
+ sortCellId ?? xCellId,
744
+ descending,
745
+ offset,
746
+ limit,
747
+ queriesOrQueriesId,
748
+ );
749
+ const rowIds = sourceType == SourceType.Table ? tableRowIds : queryRowIds;
750
+ const points =
751
+ yCellId == null
752
+ ? []
753
+ : getDataPoints(rowIds, (rowId) =>
754
+ getDataPoint(
755
+ rowId,
756
+ getCell(
757
+ sourceType,
758
+ store,
759
+ queries,
760
+ tableId,
761
+ queryId,
762
+ rowId,
763
+ xCellId,
764
+ ),
765
+ getCell(
766
+ sourceType,
767
+ store,
768
+ queries,
769
+ tableId,
770
+ queryId,
771
+ rowId,
772
+ yCellId,
773
+ ),
774
+ ),
775
+ );
776
+ useCellListener(
777
+ sourceType == SourceType.Table ? (tableId ?? null) : null,
778
+ null,
779
+ xCellId,
780
+ handleChange,
781
+ [handleChange],
782
+ false,
783
+ storeOrStoreId,
784
+ );
785
+ useCellListener(
786
+ sourceType == SourceType.Table ? (tableId ?? null) : null,
787
+ null,
788
+ yCellId ?? null,
789
+ handleChange,
790
+ [handleChange],
791
+ false,
792
+ storeOrStoreId,
793
+ );
794
+ useResultCellListener(
795
+ sourceType == SourceType.Query ? (queryId ?? null) : null,
796
+ null,
797
+ xCellId,
798
+ handleChange,
799
+ [handleChange],
800
+ queriesOrQueriesId,
801
+ );
802
+ useResultCellListener(
803
+ sourceType == SourceType.Query ? (queryId ?? null) : null,
804
+ null,
805
+ yCellId ?? null,
806
+ handleChange,
807
+ [handleChange],
808
+ queriesOrQueriesId,
809
+ );
810
+ useLayoutEffect(
811
+ () => () => releaseSeriesId(seriesId),
812
+ [releaseSeriesId, seriesId],
813
+ );
814
+ return [seriesId, points];
815
+ };
816
+ const getSeriesClassName = (baseClassName, className) =>
817
+ className == null ? baseClassName : `${baseClassName} ${className}`;
818
+ const getCell = (
819
+ sourceType,
820
+ store,
821
+ queries,
822
+ tableId,
823
+ queryId,
824
+ rowId,
825
+ cellId,
826
+ ) =>
827
+ sourceType == SourceType.Table
828
+ ? store?.getCell(tableId, rowId, cellId)
829
+ : queries?.getResultCell(queryId, rowId, cellId);
830
+
831
+ const BarSeries = (props) => {
832
+ const {
833
+ barSeriesCount,
834
+ bounds,
835
+ getBarSeriesIndex,
836
+ layout: [, , [, , barGap]],
837
+ plotFrame,
838
+ plotSize,
839
+ registerBarSeries,
840
+ releaseBarSeries,
841
+ setSeriesSummary,
842
+ setTooltipPoint,
843
+ xValues,
844
+ } = useCartesianChartContext();
845
+ const {className, label, xCellId, yCellId} = props;
846
+ const [seriesId, rawPoints] = useSeriesData(props);
847
+ const barSeriesIndex = getBarSeriesIndex(seriesId);
848
+ const [, , yMin, yMax] = bounds;
849
+ const points = getScaledPoints(
850
+ 'bar',
851
+ rawPoints,
852
+ bounds,
853
+ plotSize,
854
+ xValues,
855
+ xCellId,
856
+ label ?? yCellId,
857
+ );
858
+ useLayoutEffect(() => {
859
+ setSeriesSummary(
860
+ seriesId,
861
+ getSeriesSummary('bar', rawPoints, xCellId, yCellId, label),
862
+ );
863
+ });
864
+ useLayoutEffect(() => {
865
+ registerBarSeries(seriesId);
866
+ return () => releaseBarSeries(seriesId);
867
+ }, [registerBarSeries, releaseBarSeries, seriesId]);
868
+ return /* @__PURE__ */ jsx('g', {
869
+ className: getSeriesClassName('bar-series', className),
870
+ fill: CURRENT_COLOR,
871
+ children: /* @__PURE__ */ jsx(Bars, {
872
+ barGap,
873
+ barSeriesCount,
874
+ barSeriesIndex,
875
+ plotFrame,
876
+ points,
877
+ setTooltipPoint,
878
+ yMax,
879
+ yMin,
880
+ }),
881
+ });
882
+ };
883
+ BarSeries[SERIES] = true;
884
+
885
+ const INTEGER = /^\d+$/;
886
+ const getPoolFunctions = () => {
887
+ const pool = [];
888
+ let nextId = 0;
889
+ return [
890
+ (reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
891
+ (id) => {
892
+ if (test(INTEGER, id) && size(pool) < 1e3) {
893
+ arrayPush(pool, id);
894
+ }
895
+ },
896
+ ];
897
+ };
898
+
899
+ const DEFAULT_SIZE = [1e3, 1e3];
900
+ const DEFAULT_FONT_SIZE = 12;
901
+ const DEFAULT_STYLE = [0.5, 0.5, 0.25, 3.5, 4, 1, 1];
902
+ const useLayout = () => {
903
+ const svgRef = useRef(null);
904
+ const chartLayoutRef = useRef([
905
+ DEFAULT_SIZE,
906
+ getDefaultStyle(DEFAULT_FONT_SIZE),
907
+ ]);
908
+ const [chartLayout, setChartLayout] = useState([
909
+ DEFAULT_SIZE,
910
+ getDefaultStyle(DEFAULT_FONT_SIZE),
911
+ ]);
912
+ useLayoutEffect(() => {
913
+ const svg = svgRef.current;
914
+ if (isNull(svg)) {
915
+ return;
916
+ }
917
+ const updateLayout = ({contentRect}) => {
918
+ const style = svg.ownerDocument.defaultView?.getComputedStyle(svg);
919
+ const nextLayout = [getSvgSize(contentRect), getStyle(style)];
920
+ if (!isLayoutEqual(chartLayoutRef.current, nextLayout)) {
921
+ chartLayoutRef.current = nextLayout;
922
+ setChartLayout(nextLayout);
923
+ }
924
+ };
925
+ const observer = new ResizeObserver(([entry]) => updateLayout(entry));
926
+ observer.observe(svg);
927
+ return () => observer.disconnect();
928
+ }, []);
929
+ return [svgRef, ...chartLayout];
930
+ };
931
+ const getPlotSize = ([, chartSize, chartStyle]) => {
932
+ const [, , width, height] = getPlotFrame(chartSize, chartStyle);
933
+ return [width, height];
934
+ };
935
+ const getLabelSize = ([, , chartStyle]) => chartStyle[6];
936
+ const getPlotFrame = (
937
+ [width, height],
938
+ [, , , xAxisHeight, yAxisWidth, inset, fontSize],
939
+ ) => {
940
+ const plotX = inset + mathMax(mathMin(yAxisWidth, width / 2 - 2 * inset), 0);
941
+ const plotY = inset + fontSize / 2;
942
+ const plotRight = inset + fontSize / 2;
943
+ const plotHeight = mathMax(
944
+ height -
945
+ plotY -
946
+ mathMax(mathMin(xAxisHeight, height / 2 - plotY - inset), 0) -
947
+ inset,
948
+ 0,
949
+ );
950
+ return [plotX, plotY, mathMax(width - plotX - plotRight, 0), plotHeight];
951
+ };
952
+ const getDefaultStyle = (fontSize) =>
953
+ arrayMap(DEFAULT_STYLE, (value) => value * fontSize);
954
+ const getStyle = (style) => {
955
+ const fontSize = parseFloat(style?.fontSize ?? '');
956
+ return getDefaultStyle(
957
+ isFiniteNumber(fontSize) ? fontSize : DEFAULT_FONT_SIZE,
958
+ );
959
+ };
960
+ const getSvgSize = ({width, height}) => [
961
+ mathRound(width) || DEFAULT_SIZE[0],
962
+ mathRound(height) || DEFAULT_SIZE[1],
963
+ ];
964
+ const isLayoutEqual = ([chartSize1, chartStyle1], [chartSize2, chartStyle2]) =>
965
+ arrayIsEqual(chartSize1, chartSize2) &&
966
+ arrayIsEqual(chartStyle1, chartStyle2);
967
+
968
+ const XAxis$1 = ({
969
+ className,
970
+ points,
971
+ tickFormatter,
972
+ xTicks,
973
+ xMin,
974
+ xMax,
975
+ xTitle,
976
+ plotFrame,
977
+ tickSize,
978
+ tickGap,
979
+ axisHeight,
980
+ fontSize,
981
+ }) => {
982
+ const [plotX, plotY, plotWidth, plotHeight] = plotFrame;
983
+ const titleGap = mathMax(axisHeight - tickSize - tickGap - 2 * fontSize, 0);
984
+ return /* @__PURE__ */ jsxs('g', {
985
+ className: getAxisClassName$1('x', className),
986
+ dominantBaseline: 'hanging',
987
+ textAnchor: 'middle',
988
+ children: [
989
+ /* @__PURE__ */ jsx('path', {
990
+ className: 'line',
991
+ d: `M${plotX},${plotY + plotHeight}h${plotWidth}`,
992
+ fill: 'none',
993
+ stroke: CURRENT_COLOR,
994
+ strokeOpacity: 0.5,
995
+ strokeWidth: 1,
996
+ }),
997
+ /* @__PURE__ */ jsx('g', {
998
+ className: 'ticks',
999
+ children:
1000
+ arrayIsEmpty(xTicks) || !isNumber(xMin) || !isNumber(xMax)
1001
+ ? arrayMap(points, ([rowId, xValue, , x]) =>
1002
+ /* @__PURE__ */ jsx(
1003
+ 'text',
1004
+ {
1005
+ x: plotX + x,
1006
+ y: plotY + plotHeight + tickSize + tickGap,
1007
+ children: getTickLabel(xValue, tickFormatter),
1008
+ },
1009
+ rowId,
1010
+ ),
1011
+ )
1012
+ : arrayMap(xTicks, (tick) => {
1013
+ const x = getScale(tick, xMin, xMax, plotWidth);
1014
+ return /* @__PURE__ */ jsx(
1015
+ 'text',
1016
+ {
1017
+ x: plotX + x,
1018
+ y: plotY + plotHeight + tickSize + tickGap,
1019
+ children: getTickLabel(tick, tickFormatter),
1020
+ },
1021
+ tick,
1022
+ );
1023
+ }),
1024
+ }),
1025
+ /* @__PURE__ */ jsx('text', {
1026
+ className: 'title',
1027
+ x: plotX + plotWidth / 2,
1028
+ y: plotY + plotHeight + tickSize + tickGap + fontSize + titleGap,
1029
+ children: xTitle,
1030
+ }),
1031
+ ],
1032
+ });
1033
+ };
1034
+ const getAxisClassName$1 = (baseClassName, className) =>
1035
+ className == null ? baseClassName : `${baseClassName} ${className}`;
1036
+ const getTickLabel = (tick, tickFormatter) =>
1037
+ tickFormatter?.(tick) ?? string(tick);
1038
+
1039
+ const YAxis$1 = ({
1040
+ className,
1041
+ tickFormatter,
1042
+ yTicks,
1043
+ yMin,
1044
+ yMax,
1045
+ yTitle,
1046
+ plotFrame,
1047
+ tickSize,
1048
+ tickGap,
1049
+ axisWidth,
1050
+ }) => {
1051
+ const [plotX, plotY, , plotHeight] = plotFrame;
1052
+ return isNullish(yMin) || isNullish(yMax)
1053
+ ? null
1054
+ : /* @__PURE__ */ jsxs('g', {
1055
+ className: getAxisClassName('y', className),
1056
+ children: [
1057
+ /* @__PURE__ */ jsx('path', {
1058
+ className: 'line',
1059
+ d: `M${plotX},${plotY}v${plotHeight}`,
1060
+ fill: 'none',
1061
+ stroke: CURRENT_COLOR,
1062
+ strokeOpacity: 0.5,
1063
+ strokeWidth: 1,
1064
+ }),
1065
+ /* @__PURE__ */ jsx('g', {
1066
+ className: 'ticks',
1067
+ dominantBaseline: 'middle',
1068
+ textAnchor: 'end',
1069
+ children: arrayMap(yTicks, (tick) => {
1070
+ const y = plotHeight - getScale(tick, yMin, yMax, plotHeight);
1071
+ return /* @__PURE__ */ jsx(
1072
+ 'text',
1073
+ {
1074
+ x: plotX - tickSize - tickGap,
1075
+ y: plotY + y,
1076
+ children: tickFormatter?.(tick) ?? string(tick),
1077
+ },
1078
+ tick,
1079
+ );
1080
+ }),
1081
+ }),
1082
+ /* @__PURE__ */ jsx('text', {
1083
+ className: 'title',
1084
+ dominantBaseline: 'text-before-edge',
1085
+ textAnchor: 'middle',
1086
+ transform: `translate(${plotX - axisWidth} ${plotFrame[1] + plotFrame[3] / 2}) rotate(-90)`,
1087
+ children: yTitle,
1088
+ }),
1089
+ ],
1090
+ });
1091
+ };
1092
+ const getAxisClassName = (baseClassName, className) =>
1093
+ className == null ? baseClassName : `${baseClassName} ${className}`;
1094
+
1095
+ const Axes = ({
1096
+ xAxis,
1097
+ yAxis,
1098
+ points,
1099
+ xTicks,
1100
+ yTicks,
1101
+ bounds: [xMin, xMax, yMin, yMax],
1102
+ titles: [xTitle, yTitle],
1103
+ xAxisHeight,
1104
+ yAxisWidth,
1105
+ fontSize,
1106
+ ...sharedProps
1107
+ }) => {
1108
+ return /* @__PURE__ */ jsxs('g', {
1109
+ className: 'axes',
1110
+ fill: CURRENT_COLOR,
1111
+ fillOpacity: 0.75,
1112
+ children: [
1113
+ /* @__PURE__ */ jsx(YAxis$1, {
1114
+ ...sharedProps,
1115
+ className: yAxis?.className,
1116
+ tickFormatter: yAxis?.tickFormatter,
1117
+ yTicks,
1118
+ yMin,
1119
+ yMax,
1120
+ yTitle,
1121
+ axisWidth: yAxisWidth,
1122
+ }),
1123
+ /* @__PURE__ */ jsx(XAxis$1, {
1124
+ ...sharedProps,
1125
+ className: xAxis?.className,
1126
+ points,
1127
+ tickFormatter: xAxis?.tickFormatter,
1128
+ xTicks,
1129
+ xMin,
1130
+ xMax,
1131
+ xTitle,
1132
+ axisHeight: xAxisHeight,
1133
+ fontSize,
1134
+ }),
1135
+ ],
1136
+ });
1137
+ };
1138
+
1139
+ const Grid = ({
1140
+ points,
1141
+ xTicks,
1142
+ yTicks,
1143
+ bounds: [xMin, xMax, yMin, yMax],
1144
+ plotFrame,
1145
+ tickSize,
1146
+ }) => {
1147
+ const [plotX, plotY, width, height] = plotFrame;
1148
+ return /* @__PURE__ */ jsxs('g', {
1149
+ className: 'grid',
1150
+ stroke: CURRENT_COLOR,
1151
+ strokeOpacity: 0.75,
1152
+ strokeWidth: 0.5,
1153
+ children: [
1154
+ isNullish(yMin) || isNullish(yMax)
1155
+ ? null
1156
+ : /* @__PURE__ */ jsx('path', {
1157
+ className: 'y',
1158
+ d: arrayJoin(
1159
+ arrayMap(
1160
+ arrayFilter(
1161
+ yTicks,
1162
+ (tick) => getScale(tick, yMin, yMax, height) != 0,
1163
+ ),
1164
+ (tick) =>
1165
+ `M${plotX - tickSize},${plotY + height - getScale(tick, yMin, yMax, height)}h${width + tickSize}`,
1166
+ ),
1167
+ ' ',
1168
+ ),
1169
+ }),
1170
+ arrayIsEmpty(xTicks) || !isNumber(xMin) || !isNumber(xMax)
1171
+ ? /* @__PURE__ */ jsx('path', {
1172
+ className: 'x',
1173
+ d: arrayJoin(
1174
+ arrayMap(
1175
+ arrayFilter(points, ([, , , x]) => x != 0),
1176
+ ([, , , x]) => `M${plotX + x},${plotY}v${height + tickSize}`,
1177
+ ),
1178
+ ' ',
1179
+ ),
1180
+ })
1181
+ : /* @__PURE__ */ jsx('path', {
1182
+ className: 'x',
1183
+ d: arrayJoin(
1184
+ arrayMap(
1185
+ arrayFilter(
1186
+ xTicks,
1187
+ (tick) => getScale(tick, xMin, xMax, width) != 0,
1188
+ ),
1189
+ (tick) =>
1190
+ `M${plotX + getScale(tick, xMin, xMax, width)},${plotY}v${height + tickSize}`,
1191
+ ),
1192
+ ' ',
1193
+ ),
1194
+ }),
1195
+ ],
1196
+ });
1197
+ };
1198
+
1199
+ const TOOLTIP_WIDTH = 160;
1200
+ const TOOLTIP_HEIGHT = 60;
1201
+ const TOOLTIP_GAP = 12;
1202
+ const TOOLTIP_PADDING = 12;
1203
+ const TOOLTIP_BACKGROUND = '#111827';
1204
+ const TOOLTIP_TEXT = '#fff';
1205
+ const Tooltip = ({
1206
+ point,
1207
+ width,
1208
+ height,
1209
+ plotFrame,
1210
+ titles: [xTitle, yTitle],
1211
+ }) => {
1212
+ if (isNullish(point)) {
1213
+ return null;
1214
+ }
1215
+ const [, xValue, yValue, x, y, pointXTitle, pointYTitle] = point;
1216
+ const [plotX, plotY] = plotFrame;
1217
+ const tooltipX =
1218
+ x + TOOLTIP_GAP + TOOLTIP_WIDTH > width
1219
+ ? x - TOOLTIP_GAP - TOOLTIP_WIDTH
1220
+ : x + TOOLTIP_GAP;
1221
+ const tooltipY = mathMax(
1222
+ mathMin(y - TOOLTIP_GAP - TOOLTIP_HEIGHT, height - TOOLTIP_HEIGHT),
1223
+ 0,
1075
1224
  );
1076
- const dataBounds = getBounds(kind, points);
1077
- const xTicks = getXTicks(kind, dataBounds, chartSize, labelSize);
1078
- const yTicks = getYTicks(dataBounds, chartSize, labelSize);
1079
- const bounds = getTickBounds(dataBounds, xTicks, yTicks);
1080
- return [
1081
- handleChange,
1082
- getScaledPoints(kind, points, bounds, chartSize),
1083
- bounds,
1084
- xTicks,
1085
- yTicks,
1086
- ];
1225
+ return /* @__PURE__ */ jsxs(Fragment$1, {
1226
+ children: [
1227
+ /* @__PURE__ */ jsx('path', {
1228
+ className: 'tooltip-lines',
1229
+ pointerEvents: 'none',
1230
+ stroke: CURRENT_COLOR,
1231
+ strokeOpacity: 0.25,
1232
+ strokeWidth: 1,
1233
+ d: `M${plotX + x},${plotY}v${height}M${plotX},${plotY + y}h${width}`,
1234
+ }),
1235
+ /* @__PURE__ */ jsxs('g', {
1236
+ className: 'tooltip',
1237
+ transform: `translate(${plotX + tooltipX} ${plotY + tooltipY})`,
1238
+ fontFamily: 'sans-serif',
1239
+ fontWeight: 600,
1240
+ pointerEvents: 'none',
1241
+ children: [
1242
+ /* @__PURE__ */ jsx('rect', {
1243
+ fill: TOOLTIP_BACKGROUND,
1244
+ fillOpacity: 0.9,
1245
+ width: TOOLTIP_WIDTH,
1246
+ height: TOOLTIP_HEIGHT,
1247
+ rx: 6,
1248
+ }),
1249
+ /* @__PURE__ */ jsxs('text', {
1250
+ fill: TOOLTIP_TEXT,
1251
+ x: TOOLTIP_PADDING,
1252
+ y: 22,
1253
+ children: [pointXTitle ?? xTitle, ': ', string(xValue)],
1254
+ }),
1255
+ /* @__PURE__ */ jsxs('text', {
1256
+ fill: TOOLTIP_TEXT,
1257
+ x: TOOLTIP_PADDING,
1258
+ y: 46,
1259
+ children: [pointYTitle ?? yTitle, ': ', yValue],
1260
+ }),
1261
+ ],
1262
+ }),
1263
+ ],
1264
+ });
1087
1265
  };
1088
1266
 
1089
- const QueryChart = ({
1090
- descending,
1267
+ const EMPTY_DOMAIN_STATE = {
1268
+ bounds: [],
1269
+ continuousX: false,
1270
+ xValues: [],
1271
+ };
1272
+ const CartesianChart = ({
1273
+ children,
1091
1274
  className,
1092
- kind,
1093
- limit,
1094
- offset,
1095
- queriesOrQueriesId,
1275
+ initialSummary,
1276
+ queries,
1096
1277
  queryId,
1097
- sortCellId,
1098
- xCellId,
1099
- yCellId,
1278
+ store,
1279
+ tableId,
1100
1280
  }) => {
1101
1281
  const layout = useLayout();
1102
- const queries = useQueriesOrQueriesById(queriesOrQueriesId);
1103
- const rowIds = useResultSortedRowIds(
1104
- queryId,
1105
- sortCellId ?? xCellId,
1106
- descending,
1107
- offset,
1108
- limit,
1109
- queriesOrQueriesId,
1282
+ const [svgRef, chartSize, chartStyle] = layout;
1283
+ const [tickSize, tickGap, , xAxisHeight, yAxisWidth, , fontSize] = chartStyle;
1284
+ const plotFrame = getPlotFrame(chartSize, chartStyle);
1285
+ const plotSize = getPlotSize(layout);
1286
+ const labelSize = getLabelSize(layout);
1287
+ const storeObject = useStoreOrStoreById(store);
1288
+ const queriesObject = useQueriesOrQueriesById(queries);
1289
+ const sourceType =
1290
+ tableId == null
1291
+ ? queryId == null
1292
+ ? SourceType.None
1293
+ : SourceType.Query
1294
+ : SourceType.Table;
1295
+ const initialSummaries = initialSummary == null ? {} : {0: initialSummary};
1296
+ const initialDomainState =
1297
+ initialSummary == null
1298
+ ? EMPTY_DOMAIN_STATE
1299
+ : getDomainState(objValues(initialSummaries));
1300
+ const initialXTitle = getTitle(initialSummaries, 'xCellId');
1301
+ const initialYTitle = getTitle(initialSummaries, 'yCellId');
1302
+ const summariesRef = useRef(initialSummaries);
1303
+ const boundsRef = useRef(initialDomainState.bounds);
1304
+ const domainStateRef = useRef(initialDomainState);
1305
+ const xTitleRef = useRef(initialXTitle);
1306
+ const yTitleRef = useRef(initialYTitle);
1307
+ const pool = useRef(getPoolFunctions());
1308
+ const [domainState, setDomainState] = useState(initialDomainState);
1309
+ const [xTitle, setXTitle] = useState(initialXTitle);
1310
+ const [yTitle, setYTitle] = useState(initialYTitle);
1311
+ const barSeriesIdsRef = useRef([]);
1312
+ const [barSeriesIds, setBarSeriesIds] = useState([]);
1313
+ const [tooltipPoint, setTooltipPoint] = useState();
1314
+ const [chartChildren, xAxis, yAxis] = getParsedChildren(children);
1315
+ const xValues = domainState.xValues;
1316
+ const numericX =
1317
+ domainState.continuousX ||
1318
+ (arrayIsEmpty(xValues) && hasNumericXAxisDefinition(xAxis));
1319
+ const dataBounds = getAxisBounds(domainState.bounds, numericX, xAxis, yAxis);
1320
+ const axisKind = numericX || arrayIsEmpty(barSeriesIds) ? 'line' : 'bar';
1321
+ const xTicks =
1322
+ numericX && xAxis?.ticks != null
1323
+ ? getAxisTicks(xAxis.ticks)
1324
+ : getXTicks(axisKind, dataBounds, plotSize, labelSize, xAxis?.tickCount);
1325
+ const yTicks =
1326
+ yAxis?.ticks == null
1327
+ ? getYTicks(dataBounds, plotSize, labelSize, yAxis?.tickCount)
1328
+ : getAxisTicks(yAxis.ticks);
1329
+ const tickBounds = getTickBounds(dataBounds, xTicks, yTicks);
1330
+ const axisPoints = getScaledPoints(
1331
+ axisKind,
1332
+ xValues.map((xValue, index) => [`${index}`, xValue, 0]),
1333
+ tickBounds,
1334
+ plotSize,
1335
+ xValues,
1110
1336
  );
1111
- const [handleChange, points, bounds, xTicks, yTicks] = useData(
1112
- kind,
1113
- rowIds,
1114
- getPlotSize(layout),
1115
- getLabelSize(layout),
1116
- (rowId) => queries?.getResultCell(queryId, rowId, xCellId),
1117
- (rowId) => queries?.getResultCell(queryId, rowId, yCellId),
1337
+ const setNextDomainState = useCallback((summaryById) => {
1338
+ const nextDomainState = getDomainState(objValues(summaryById));
1339
+ const nextBounds = nextDomainState.bounds;
1340
+ if (
1341
+ !boundsAreEqual(boundsRef.current, nextBounds) ||
1342
+ !arrayIsEqual(domainStateRef.current.xValues, nextDomainState.xValues)
1343
+ ) {
1344
+ boundsRef.current = nextBounds;
1345
+ domainStateRef.current = nextDomainState;
1346
+ setDomainState(nextDomainState);
1347
+ }
1348
+ }, []);
1349
+ const setNextTitles = useCallback((summaryById) => {
1350
+ const nextXTitle = getTitle(summaryById, 'xCellId');
1351
+ const nextYTitle = getTitle(summaryById, 'yCellId');
1352
+ if (xTitleRef.current != nextXTitle) {
1353
+ xTitleRef.current = nextXTitle;
1354
+ setXTitle(nextXTitle);
1355
+ }
1356
+ if (yTitleRef.current != nextYTitle) {
1357
+ yTitleRef.current = nextYTitle;
1358
+ setYTitle(nextYTitle);
1359
+ }
1360
+ }, []);
1361
+ const setIncrementalDomainState = useCallback((summary) => {
1362
+ const currentBounds = boundsRef.current;
1363
+ const nextBounds = [
1364
+ getMin(currentBounds[0], summary.xMin),
1365
+ getMax(currentBounds[1], summary.xMax),
1366
+ getNumberMin(currentBounds[2], summary.yMin),
1367
+ getNumberMax(currentBounds[3], summary.yMax),
1368
+ ];
1369
+ if (!boundsAreEqual(currentBounds, nextBounds)) {
1370
+ boundsRef.current = nextBounds;
1371
+ domainStateRef.current = {
1372
+ bounds: nextBounds,
1373
+ continuousX: domainStateRef.current.continuousX,
1374
+ xValues: domainStateRef.current.xValues,
1375
+ };
1376
+ setDomainState(domainStateRef.current);
1377
+ }
1378
+ }, []);
1379
+ const setSeriesSummary = useCallback(
1380
+ (seriesId, summary) => {
1381
+ const currentSummaries = summariesRef.current;
1382
+ const currentSummary = currentSummaries[seriesId];
1383
+ if (summary == null) {
1384
+ if (currentSummary == null) {
1385
+ return;
1386
+ }
1387
+ delete currentSummaries[seriesId];
1388
+ setNextTitles(currentSummaries);
1389
+ setNextDomainState(currentSummaries);
1390
+ return;
1391
+ }
1392
+ currentSummaries[seriesId] = summary;
1393
+ setNextTitles(currentSummaries);
1394
+ if (
1395
+ currentSummary == null
1396
+ ? addsXValues(summary.xValues, domainStateRef.current.xValues) ||
1397
+ summary.continuousX != domainStateRef.current.continuousX
1398
+ : ownsBound(currentSummary, boundsRef.current) ||
1399
+ currentSummary.continuousX != summary.continuousX ||
1400
+ !arrayIsEqual(currentSummary.xValues, summary.xValues)
1401
+ ) {
1402
+ setNextDomainState(currentSummaries);
1403
+ return;
1404
+ }
1405
+ setIncrementalDomainState(summary);
1406
+ },
1407
+ [setIncrementalDomainState, setNextDomainState, setNextTitles],
1118
1408
  );
1119
- useResultCellListener(
1120
- queryId,
1121
- null,
1122
- xCellId,
1123
- handleChange,
1124
- [handleChange],
1125
- queries,
1409
+ const [getId, releaseId] = pool.current;
1410
+ const getSeriesId = useCallback(() => getId(1), [getId]);
1411
+ const releaseSeriesId = useCallback(
1412
+ (seriesId) => {
1413
+ setSeriesSummary(seriesId, void 0);
1414
+ releaseId(seriesId);
1415
+ },
1416
+ [releaseId, setSeriesSummary],
1126
1417
  );
1127
- useResultCellListener(
1418
+ const registerBarSeries = useCallback((seriesId) => {
1419
+ if (!arrayHas(barSeriesIdsRef.current, seriesId)) {
1420
+ const barSeriesIds2 = [...barSeriesIdsRef.current];
1421
+ arrayPush(barSeriesIds2, seriesId);
1422
+ barSeriesIdsRef.current = barSeriesIds2;
1423
+ setBarSeriesIds(barSeriesIds2);
1424
+ }
1425
+ }, []);
1426
+ const releaseBarSeries = useCallback((seriesId) => {
1427
+ if (arrayHas(barSeriesIdsRef.current, seriesId)) {
1428
+ const barSeriesIds2 = arrayFilter(
1429
+ barSeriesIdsRef.current,
1430
+ (barSeriesId) => barSeriesId != seriesId,
1431
+ );
1432
+ barSeriesIdsRef.current = barSeriesIds2;
1433
+ setBarSeriesIds(barSeriesIds2);
1434
+ }
1435
+ }, []);
1436
+ const getBarSeriesIndex = useCallback(
1437
+ (seriesId) => arrayIndexOf(barSeriesIdsRef.current, seriesId),
1438
+ [],
1439
+ );
1440
+ const context = useMemo(
1441
+ () => ({
1442
+ bounds: tickBounds,
1443
+ barSeriesCount: size(barSeriesIds),
1444
+ domainState,
1445
+ getBarSeriesIndex,
1446
+ getSeriesId,
1447
+ layout,
1448
+ plotFrame,
1449
+ plotSize,
1450
+ queries: queriesObject,
1451
+ queriesOrQueriesId: queries,
1452
+ queryId,
1453
+ registerBarSeries,
1454
+ releaseBarSeries,
1455
+ releaseSeriesId,
1456
+ setSeriesSummary,
1457
+ setTooltipPoint,
1458
+ sourceType,
1459
+ store: storeObject,
1460
+ storeOrStoreId: store,
1461
+ tableId,
1462
+ xTicks,
1463
+ xValues,
1464
+ yTicks,
1465
+ }),
1466
+ [
1467
+ barSeriesIds,
1468
+ domainState,
1469
+ getBarSeriesIndex,
1470
+ getSeriesId,
1471
+ layout,
1472
+ plotFrame,
1473
+ plotSize,
1474
+ queries,
1475
+ queriesObject,
1476
+ queryId,
1477
+ registerBarSeries,
1478
+ releaseBarSeries,
1479
+ releaseSeriesId,
1480
+ setSeriesSummary,
1481
+ sourceType,
1482
+ store,
1483
+ storeObject,
1484
+ tableId,
1485
+ tickBounds,
1486
+ xTicks,
1487
+ xValues,
1488
+ yTicks,
1489
+ ],
1490
+ );
1491
+ return /* @__PURE__ */ jsx(CartesianChartContext.Provider, {
1492
+ value: context,
1493
+ children: /* @__PURE__ */ jsxs('svg', {
1494
+ className,
1495
+ preserveAspectRatio: 'none',
1496
+ ref: svgRef,
1497
+ viewBox: `0 0 ${chartSize[0]} ${chartSize[1]}`,
1498
+ children: [
1499
+ /* @__PURE__ */ jsx(Grid, {
1500
+ bounds: tickBounds,
1501
+ points: axisPoints,
1502
+ plotFrame,
1503
+ tickSize,
1504
+ xTicks,
1505
+ yTicks,
1506
+ }),
1507
+ /* @__PURE__ */ jsx(Axes, {
1508
+ bounds: tickBounds,
1509
+ fontSize,
1510
+ points: axisPoints,
1511
+ plotFrame,
1512
+ tickGap,
1513
+ tickSize,
1514
+ titles: [xAxis?.title ?? xTitle, yAxis?.title ?? yTitle],
1515
+ xAxis,
1516
+ xAxisHeight,
1517
+ xTicks,
1518
+ yAxis,
1519
+ yAxisWidth,
1520
+ yTicks,
1521
+ }),
1522
+ /* @__PURE__ */ jsx('g', {className: 'plot', children: chartChildren}),
1523
+ /* @__PURE__ */ jsx(Tooltip, {
1524
+ height: plotSize[1],
1525
+ point: tooltipPoint,
1526
+ plotFrame,
1527
+ titles: [xAxis?.title ?? xTitle, yAxis?.title ?? yTitle],
1528
+ width: plotSize[0],
1529
+ }),
1530
+ ],
1531
+ }),
1532
+ });
1533
+ };
1534
+ const boundsAreEqual = (bounds1, bounds2) =>
1535
+ bounds1[0] === bounds2[0] &&
1536
+ bounds1[1] === bounds2[1] &&
1537
+ bounds1[2] === bounds2[2] &&
1538
+ bounds1[3] === bounds2[3];
1539
+ const ownsBound = (
1540
+ {xMin, xMax, yMin, yMax},
1541
+ [boundXMin, boundXMax, boundYMin, boundYMax],
1542
+ ) =>
1543
+ xMin === boundXMin ||
1544
+ xMax === boundXMax ||
1545
+ yMin === boundYMin ||
1546
+ yMax === boundYMax;
1547
+ const addsXValues = (xValues, currentXValues) => {
1548
+ let adds = false;
1549
+ arrayForEach(xValues, (xValue) => {
1550
+ if (!arrayHas(currentXValues, xValue)) {
1551
+ adds = true;
1552
+ }
1553
+ });
1554
+ return adds;
1555
+ };
1556
+ const getMin = (value1, value2) =>
1557
+ isNumber(value1) && isNumber(value2)
1558
+ ? mathMin(value1, value2)
1559
+ : (value1 ?? value2);
1560
+ const getMax = (value1, value2) =>
1561
+ isNumber(value1) && isNumber(value2)
1562
+ ? mathMax(value1, value2)
1563
+ : (value1 ?? value2);
1564
+ const getNumberMin = (value1, value2) =>
1565
+ value1 == null || value2 == null
1566
+ ? (value1 ?? value2)
1567
+ : mathMin(value1, value2);
1568
+ const getNumberMax = (value1, value2) =>
1569
+ value1 == null || value2 == null
1570
+ ? (value1 ?? value2)
1571
+ : mathMax(value1, value2);
1572
+ const getTitle = (summaryById, cellIdType) => {
1573
+ const titles = [];
1574
+ arrayForEach(objValues(summaryById), (summary) => {
1575
+ const title =
1576
+ cellIdType == 'yCellId'
1577
+ ? (summary.yLabel ?? summary.yCellId)
1578
+ : summary.xCellId;
1579
+ if (title != null && !arrayHas(titles, title)) {
1580
+ arrayPush(titles, title);
1581
+ }
1582
+ });
1583
+ return arrayIsEmpty(titles) ? '' : titles.join(' & ');
1584
+ };
1585
+ const getAxisBounds = ([xMin, xMax, yMin, yMax], numericX, xAxis, yAxis) => [
1586
+ numericX ? getAxisBound(xAxis?.min, xMin) : xMin,
1587
+ numericX ? getAxisBound(xAxis?.max, xMax) : xMax,
1588
+ getNumberAxisBound(yAxis?.min, yMin),
1589
+ getNumberAxisBound(yAxis?.max, yMax),
1590
+ ];
1591
+ const getAxisBound = (value, bound) => (isFiniteNumber(value) ? value : bound);
1592
+ const getNumberAxisBound = (value, bound) =>
1593
+ isFiniteNumber(value) ? value : bound;
1594
+ const getAxisTicks = (ticks) =>
1595
+ arraySort(arrayFilter([...ticks], isFiniteNumber), (tick1, tick2) => {
1596
+ return tick1 - tick2;
1597
+ });
1598
+ const hasNumericXAxisDefinition = (xAxis) =>
1599
+ isFiniteNumber(xAxis?.min) ||
1600
+ isFiniteNumber(xAxis?.max) ||
1601
+ xAxis?.ticks != null;
1602
+ const getParsedChildren = (children) => {
1603
+ const chartChildren = [];
1604
+ let xAxis;
1605
+ let yAxis;
1606
+ Children.forEach(children, (child) => {
1607
+ if (isValidElement(child)) {
1608
+ if (child.type === Fragment) {
1609
+ const [childChildren, childXAxis, childYAxis] = getParsedChildren(
1610
+ child.props.children,
1611
+ );
1612
+ arrayForEach(childChildren, (chartChild) =>
1613
+ arrayPush(chartChildren, chartChild),
1614
+ );
1615
+ xAxis ??= childXAxis;
1616
+ yAxis ??= childYAxis;
1617
+ } else if (isSeriesComponent(child.type)) {
1618
+ arrayPush(chartChildren, child);
1619
+ } else if (xAxis == null && isXAxisComponent(child.type)) {
1620
+ xAxis = child.props;
1621
+ } else if (yAxis == null && isYAxisComponent(child.type)) {
1622
+ yAxis = child.props;
1623
+ }
1624
+ }
1625
+ });
1626
+ return [chartChildren, xAxis, yAxis];
1627
+ };
1628
+
1629
+ const useInitialSeriesSummary = (
1630
+ kind,
1631
+ {
1632
+ descending,
1633
+ limit,
1634
+ offset,
1635
+ queries,
1128
1636
  queryId,
1129
- null,
1637
+ sortCellId,
1638
+ store,
1639
+ tableId,
1640
+ xCellId,
1130
1641
  yCellId,
1131
- handleChange,
1132
- [handleChange],
1133
- queries,
1134
- );
1135
- return /* @__PURE__ */ jsx(Layout, {
1136
- className,
1642
+ },
1643
+ ) => {
1644
+ const storeObject = useStoreOrStoreById(store);
1645
+ const queriesObject = useQueriesOrQueriesById(queries);
1646
+ return useMemo(() => {
1647
+ const points =
1648
+ tableId == null
1649
+ ? getDataPoints(
1650
+ queriesObject?.getResultSortedRowIds(
1651
+ queryId ?? '',
1652
+ sortCellId ?? xCellId,
1653
+ descending,
1654
+ offset,
1655
+ limit,
1656
+ ) ?? [],
1657
+ (rowId) =>
1658
+ getDataPoint(
1659
+ rowId,
1660
+ queriesObject?.getResultCell(queryId ?? '', rowId, xCellId),
1661
+ queriesObject?.getResultCell(queryId ?? '', rowId, yCellId),
1662
+ ),
1663
+ )
1664
+ : getDataPoints(
1665
+ storeObject?.getSortedRowIds(
1666
+ tableId,
1667
+ sortCellId ?? xCellId,
1668
+ descending,
1669
+ offset,
1670
+ limit,
1671
+ ) ?? [],
1672
+ (rowId) =>
1673
+ getDataPoint(
1674
+ rowId,
1675
+ storeObject?.getCell(tableId, rowId, xCellId),
1676
+ storeObject?.getCell(tableId, rowId, yCellId),
1677
+ ),
1678
+ );
1679
+ return getSeriesSummary(kind, points, xCellId, yCellId);
1680
+ }, [
1681
+ descending,
1137
1682
  kind,
1138
- points,
1139
- bounds,
1140
- titles: [xCellId, yCellId],
1141
- xTicks,
1142
- yTicks,
1143
- layout,
1144
- });
1683
+ limit,
1684
+ offset,
1685
+ queriesObject,
1686
+ queryId,
1687
+ sortCellId,
1688
+ storeObject,
1689
+ tableId,
1690
+ xCellId,
1691
+ yCellId,
1692
+ ]);
1145
1693
  };
1146
1694
 
1147
- const TableChart = ({
1695
+ const BarChart = (props) => {
1696
+ const initialSummary = useInitialSeriesSummary('bar', props);
1697
+ return /* @__PURE__ */ jsx(CartesianChart, {
1698
+ ...getSourceProps$1(props),
1699
+ initialSummary,
1700
+ children: /* @__PURE__ */ jsx(BarSeries, {...getSeriesProps$1(props)}),
1701
+ });
1702
+ };
1703
+ const getSourceProps$1 = (props) =>
1704
+ props.tableId == null
1705
+ ? {
1706
+ className: props.className,
1707
+ queries: props.queries,
1708
+ queryId: props.queryId,
1709
+ }
1710
+ : {className: props.className, store: props.store, tableId: props.tableId};
1711
+ const getSeriesProps$1 = ({
1148
1712
  descending,
1149
- className,
1150
- kind,
1151
1713
  limit,
1152
1714
  offset,
1153
1715
  sortCellId,
1154
- storeOrStoreId,
1155
- tableId,
1156
1716
  xCellId,
1157
1717
  yCellId,
1158
- }) => {
1159
- const layout = useLayout();
1160
- const store = useStoreOrStoreById(storeOrStoreId);
1161
- const rowIds = useSortedRowIds(
1162
- tableId,
1163
- sortCellId ?? xCellId,
1164
- descending,
1165
- offset,
1166
- limit,
1167
- storeOrStoreId,
1168
- );
1169
- const [handleChange, points, bounds, xTicks, yTicks] = useData(
1170
- kind,
1171
- rowIds,
1172
- getPlotSize(layout),
1173
- getLabelSize(layout),
1174
- (rowId) => store?.getCell(tableId, rowId, xCellId),
1175
- (rowId) => store?.getCell(tableId, rowId, yCellId),
1718
+ }) => ({
1719
+ descending,
1720
+ limit,
1721
+ offset,
1722
+ sortCellId,
1723
+ xCellId,
1724
+ yCellId,
1725
+ });
1726
+
1727
+ const Line = ({plotFrame, points, setTooltipPoint}) => {
1728
+ const [plotX, plotY, , height] = plotFrame;
1729
+ return /* @__PURE__ */ jsxs(Fragment$1, {
1730
+ children: [
1731
+ /* @__PURE__ */ jsx('path', {
1732
+ className: 'area',
1733
+ d: getAreaPath(points, plotX, plotY, height),
1734
+ fill: CURRENT_COLOR,
1735
+ fillOpacity: 0.25,
1736
+ stroke: 'none',
1737
+ }),
1738
+ /* @__PURE__ */ jsx('path', {
1739
+ className: 'line',
1740
+ d: getLinePath(points, plotX, plotY),
1741
+ fill: 'none',
1742
+ stroke: CURRENT_COLOR,
1743
+ strokeOpacity: 0.75,
1744
+ strokeWidth: 2,
1745
+ }),
1746
+ /* @__PURE__ */ jsx('g', {
1747
+ className: 'points',
1748
+ fill: CURRENT_COLOR,
1749
+ children: arrayMap(points, (point) => {
1750
+ const [rowId, , , x, y] = point;
1751
+ return /* @__PURE__ */ jsx(
1752
+ 'circle',
1753
+ {
1754
+ cx: plotX + x,
1755
+ cy: plotY + y,
1756
+ onPointerEnter: () => setTooltipPoint(point),
1757
+ onPointerLeave: () => setTooltipPoint(void 0),
1758
+ r: 5,
1759
+ },
1760
+ rowId,
1761
+ );
1762
+ }),
1763
+ }),
1764
+ ],
1765
+ });
1766
+ };
1767
+ const getLinePath = (points, plotX, plotY) =>
1768
+ arrayJoin(
1769
+ arrayMap(
1770
+ points,
1771
+ ([, , , x, y], index) =>
1772
+ `${index == 0 ? 'M' : 'L'}${plotX + x},${plotY + y}`,
1773
+ ),
1774
+ ' ',
1176
1775
  );
1177
- useCellListener(
1178
- tableId,
1179
- null,
1776
+ const getAreaPath = (points, plotX, plotY, height) =>
1777
+ arrayIsEmpty(points)
1778
+ ? ''
1779
+ : `${getLinePath(points, plotX, plotY)} L${plotX + points[size(points) - 1][3]},${plotY + height} L${plotX + points[0][3]},${plotY + height} Z`;
1780
+
1781
+ const LineSeries = (props) => {
1782
+ const {
1783
+ barSeriesCount,
1784
+ bounds,
1785
+ domainState,
1786
+ plotFrame,
1787
+ plotSize,
1788
+ setSeriesSummary,
1789
+ setTooltipPoint,
1790
+ xValues,
1791
+ } = useCartesianChartContext();
1792
+ const {className, label, xCellId, yCellId} = props;
1793
+ const [seriesId, rawPoints] = useSeriesData(props);
1794
+ const points = getScaledPoints(
1795
+ domainState.continuousX || barSeriesCount == 0 ? 'line' : 'bar',
1796
+ rawPoints,
1797
+ bounds,
1798
+ plotSize,
1799
+ xValues,
1180
1800
  xCellId,
1181
- handleChange,
1182
- [handleChange],
1183
- false,
1184
- storeOrStoreId,
1185
- );
1186
- useCellListener(
1187
- tableId,
1188
- null,
1189
- yCellId,
1190
- handleChange,
1191
- [handleChange],
1192
- false,
1193
- storeOrStoreId,
1801
+ label ?? yCellId,
1194
1802
  );
1195
- return /* @__PURE__ */ jsx(Layout, {
1196
- className,
1197
- kind,
1198
- points,
1199
- bounds,
1200
- titles: [xCellId, yCellId],
1201
- xTicks,
1202
- yTicks,
1203
- layout,
1803
+ useLayoutEffect(() => {
1804
+ setSeriesSummary(
1805
+ seriesId,
1806
+ getSeriesSummary('line', rawPoints, xCellId, yCellId, label),
1807
+ );
1808
+ });
1809
+ return /* @__PURE__ */ jsx('g', {
1810
+ className: getSeriesClassName('line-series', className),
1811
+ children: /* @__PURE__ */ jsx(Line, {
1812
+ plotFrame,
1813
+ points,
1814
+ setTooltipPoint,
1815
+ }),
1204
1816
  });
1205
1817
  };
1818
+ LineSeries[SERIES] = true;
1206
1819
 
1207
- const Chart = ({className, store, tableId, queries, queryId, ...props}) =>
1208
- isUndefined(tableId)
1209
- ? isUndefined(queryId)
1210
- ? /* @__PURE__ */ jsx(EmptyChart, {...props, className})
1211
- : /* @__PURE__ */ jsx(QueryChart, {
1212
- ...props,
1213
- className,
1214
- queriesOrQueriesId: queries,
1215
- queryId,
1216
- })
1217
- : /* @__PURE__ */ jsx(TableChart, {
1218
- ...props,
1219
- className,
1220
- storeOrStoreId: store,
1221
- tableId,
1222
- });
1820
+ const LineChart = (props) => {
1821
+ const initialSummary = useInitialSeriesSummary('line', props);
1822
+ return /* @__PURE__ */ jsx(CartesianChart, {
1823
+ ...getSourceProps(props),
1824
+ initialSummary,
1825
+ children: /* @__PURE__ */ jsx(LineSeries, {...getSeriesProps(props)}),
1826
+ });
1827
+ };
1828
+ const getSourceProps = (props) =>
1829
+ props.tableId == null
1830
+ ? {
1831
+ className: props.className,
1832
+ queries: props.queries,
1833
+ queryId: props.queryId,
1834
+ }
1835
+ : {className: props.className, store: props.store, tableId: props.tableId};
1836
+ const getSeriesProps = ({
1837
+ descending,
1838
+ limit,
1839
+ offset,
1840
+ sortCellId,
1841
+ xCellId,
1842
+ yCellId,
1843
+ }) => ({
1844
+ descending,
1845
+ limit,
1846
+ offset,
1847
+ sortCellId,
1848
+ xCellId,
1849
+ yCellId,
1850
+ });
1223
1851
 
1224
- const BarChart = (props) => /* @__PURE__ */ jsx(Chart, {...props, kind: 'bar'});
1852
+ const XAxis = () => null;
1853
+ XAxis[X_AXIS] = true;
1225
1854
 
1226
- const LineChart = (props) =>
1227
- /* @__PURE__ */ jsx(Chart, {...props, kind: 'line'});
1855
+ const YAxis = () => null;
1856
+ YAxis[Y_AXIS] = true;
1228
1857
 
1229
- export {BarChart, LineChart};
1858
+ export {
1859
+ BarChart,
1860
+ BarSeries,
1861
+ CartesianChart,
1862
+ LineChart,
1863
+ LineSeries,
1864
+ XAxis,
1865
+ YAxis,
1866
+ };