@perses-dev/components 0.38.0 → 0.39.0

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 (87) hide show
  1. package/dist/BarChart/BarChart.d.ts.map +1 -1
  2. package/dist/BarChart/BarChart.js +9 -3
  3. package/dist/BarChart/BarChart.js.map +1 -1
  4. package/dist/GaugeChart/GaugeChart.js +1 -1
  5. package/dist/GaugeChart/GaugeChart.js.map +1 -1
  6. package/dist/LineChart/LineChart.d.ts.map +1 -1
  7. package/dist/LineChart/LineChart.js +7 -8
  8. package/dist/LineChart/LineChart.js.map +1 -1
  9. package/dist/StatChart/StatChart.js +1 -1
  10. package/dist/StatChart/StatChart.js.map +1 -1
  11. package/dist/StatChart/calculateFontSize.js +3 -3
  12. package/dist/StatChart/calculateFontSize.js.map +1 -1
  13. package/dist/ThresholdsEditor/ThresholdColorPicker.js +1 -1
  14. package/dist/ThresholdsEditor/ThresholdColorPicker.js.map +1 -1
  15. package/dist/ThresholdsEditor/ThresholdsEditor.d.ts.map +1 -1
  16. package/dist/ThresholdsEditor/ThresholdsEditor.js +3 -2
  17. package/dist/ThresholdsEditor/ThresholdsEditor.js.map +1 -1
  18. package/dist/TimeChart/TimeChart.d.ts +1 -1
  19. package/dist/TimeChart/TimeChart.d.ts.map +1 -1
  20. package/dist/TimeChart/TimeChart.js +100 -53
  21. package/dist/TimeChart/TimeChart.js.map +1 -1
  22. package/dist/TimeSeriesTooltip/LineChartTooltip.d.ts +1 -0
  23. package/dist/TimeSeriesTooltip/LineChartTooltip.d.ts.map +1 -1
  24. package/dist/TimeSeriesTooltip/LineChartTooltip.js +3 -2
  25. package/dist/TimeSeriesTooltip/LineChartTooltip.js.map +1 -1
  26. package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts +1 -0
  27. package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts.map +1 -1
  28. package/dist/TimeSeriesTooltip/TimeChartTooltip.js +3 -2
  29. package/dist/TimeSeriesTooltip/TimeChartTooltip.js.map +1 -1
  30. package/dist/TimeSeriesTooltip/TooltipHeader.d.ts +1 -0
  31. package/dist/TimeSeriesTooltip/TooltipHeader.d.ts.map +1 -1
  32. package/dist/TimeSeriesTooltip/TooltipHeader.js +5 -5
  33. package/dist/TimeSeriesTooltip/TooltipHeader.js.map +1 -1
  34. package/dist/TimeSeriesTooltip/nearby-series.d.ts.map +1 -1
  35. package/dist/TimeSeriesTooltip/nearby-series.js +13 -17
  36. package/dist/TimeSeriesTooltip/nearby-series.js.map +1 -1
  37. package/dist/TimeSeriesTooltip/tooltip-model.d.ts +4 -0
  38. package/dist/TimeSeriesTooltip/tooltip-model.d.ts.map +1 -1
  39. package/dist/TimeSeriesTooltip/tooltip-model.js +6 -0
  40. package/dist/TimeSeriesTooltip/tooltip-model.js.map +1 -1
  41. package/dist/cjs/BarChart/BarChart.js +10 -4
  42. package/dist/cjs/GaugeChart/GaugeChart.js +2 -2
  43. package/dist/cjs/LineChart/LineChart.js +6 -7
  44. package/dist/cjs/StatChart/StatChart.js +2 -2
  45. package/dist/cjs/StatChart/calculateFontSize.js +3 -3
  46. package/dist/cjs/ThresholdsEditor/ThresholdColorPicker.js +2 -2
  47. package/dist/cjs/ThresholdsEditor/ThresholdsEditor.js +3 -2
  48. package/dist/cjs/TimeChart/TimeChart.js +97 -50
  49. package/dist/cjs/TimeSeriesTooltip/LineChartTooltip.js +3 -2
  50. package/dist/cjs/TimeSeriesTooltip/TimeChartTooltip.js +3 -2
  51. package/dist/cjs/TimeSeriesTooltip/TooltipHeader.js +4 -4
  52. package/dist/cjs/TimeSeriesTooltip/nearby-series.js +12 -16
  53. package/dist/cjs/TimeSeriesTooltip/tooltip-model.js +10 -1
  54. package/dist/cjs/context/{ChartsThemeProvider.js → ChartsProvider.js} +24 -5
  55. package/dist/cjs/context/index.js +30 -0
  56. package/dist/cjs/index.js +1 -3
  57. package/dist/cjs/test-utils/theme.js +32 -19
  58. package/dist/cjs/utils/axis.js +4 -4
  59. package/dist/cjs/utils/chart-actions.js +39 -1
  60. package/dist/context/ChartsProvider.d.ts +19 -0
  61. package/dist/context/ChartsProvider.d.ts.map +1 -0
  62. package/dist/context/{ChartsThemeProvider.js → ChartsProvider.js} +24 -6
  63. package/dist/context/ChartsProvider.js.map +1 -0
  64. package/dist/context/index.d.ts +4 -0
  65. package/dist/context/index.d.ts.map +1 -0
  66. package/dist/context/index.js +17 -0
  67. package/dist/context/index.js.map +1 -0
  68. package/dist/index.d.ts +1 -3
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +1 -3
  71. package/dist/index.js.map +1 -1
  72. package/dist/test-utils/theme.d.ts +2 -0
  73. package/dist/test-utils/theme.d.ts.map +1 -1
  74. package/dist/test-utils/theme.js +23 -16
  75. package/dist/test-utils/theme.js.map +1 -1
  76. package/dist/utils/axis.d.ts +3 -3
  77. package/dist/utils/axis.d.ts.map +1 -1
  78. package/dist/utils/axis.js +4 -4
  79. package/dist/utils/axis.js.map +1 -1
  80. package/dist/utils/chart-actions.d.ts +5 -1
  81. package/dist/utils/chart-actions.d.ts.map +1 -1
  82. package/dist/utils/chart-actions.js +42 -0
  83. package/dist/utils/chart-actions.js.map +1 -1
  84. package/package.json +3 -3
  85. package/dist/context/ChartsThemeProvider.d.ts +0 -10
  86. package/dist/context/ChartsThemeProvider.d.ts.map +0 -1
  87. package/dist/context/ChartsThemeProvider.js.map +0 -1
@@ -27,7 +27,7 @@ const _core1 = require("echarts/core");
27
27
  const _charts = require("echarts/charts");
28
28
  const _components = require("echarts/components");
29
29
  const _renderers = require("echarts/renderers");
30
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
30
+ const _chartsProvider = require("../context/ChartsProvider");
31
31
  const _echart = require("../EChart");
32
32
  const _calculateFontSize = require("./calculateFontSize");
33
33
  function _interopRequireDefault(obj) {
@@ -50,7 +50,7 @@ const VALUE_FONT_WEIGHT = 700;
50
50
  function StatChart(props) {
51
51
  var ref, ref1;
52
52
  const { width , height , data , unit , color , sparkline , showSeriesName , valueFontSize } = props;
53
- const chartsTheme = (0, _chartsThemeProvider.useChartsTheme)();
53
+ const chartsTheme = (0, _chartsProvider.useChartsTheme)();
54
54
  let formattedValue = '';
55
55
  if (data.calculatedValue === null) {
56
56
  formattedValue = 'null';
@@ -18,7 +18,7 @@ Object.defineProperty(exports, "useOptimalFontSize", {
18
18
  enumerable: true,
19
19
  get: ()=>useOptimalFontSize
20
20
  });
21
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
21
+ const _chartsProvider = require("../context/ChartsProvider");
22
22
  let canvasContext;
23
23
  function getGlobalCanvasContext() {
24
24
  if (!canvasContext) {
@@ -31,12 +31,12 @@ function getGlobalCanvasContext() {
31
31
  }
32
32
  function useOptimalFontSize({ text , fontWeight , width , height , lineHeight , maxSize , fontSizeOverride }) {
33
33
  const ctx = getGlobalCanvasContext();
34
- const chartsTheme = (0, _chartsThemeProvider.useChartsTheme)();
34
+ const { echartsTheme } = (0, _chartsProvider.useChartsTheme)();
35
35
  // if user has selected a font size in the settings, use it instead of calculating the optimal size
36
36
  if (fontSizeOverride !== undefined) {
37
37
  return Number(fontSizeOverride);
38
38
  }
39
- const textStyle = chartsTheme.echartsTheme.textStyle;
39
+ const textStyle = echartsTheme.textStyle;
40
40
  var ref;
41
41
  const fontSize = (ref = Number(textStyle === null || textStyle === void 0 ? void 0 : textStyle.fontSize)) !== null && ref !== void 0 ? ref : 12;
42
42
  var ref1;
@@ -22,7 +22,7 @@ const _jsxRuntime = require("react/jsx-runtime");
22
22
  const _react = /*#__PURE__*/ _interopRequireDefault(require("react"));
23
23
  const _material = require("@mui/material");
24
24
  const _circle = /*#__PURE__*/ _interopRequireDefault(require("mdi-material-ui/Circle"));
25
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
25
+ const _chartsProvider = require("../context/ChartsProvider");
26
26
  const _colorPicker = require("../ColorPicker");
27
27
  function _interopRequireDefault(obj) {
28
28
  return obj && obj.__esModule ? obj : {
@@ -38,7 +38,7 @@ function ThresholdColorPicker({ color , onColorChange , label }) {
38
38
  const closeColorPicker = ()=>{
39
39
  setAnchorEl(null);
40
40
  };
41
- const { thresholds: { defaultColor , palette } , } = (0, _chartsThemeProvider.useChartsTheme)();
41
+ const { thresholds: { defaultColor , palette } , } = (0, _chartsProvider.useChartsTheme)();
42
42
  return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
43
43
  children: [
44
44
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(ColorIconButton, {
@@ -24,7 +24,7 @@ const _immer = /*#__PURE__*/ _interopRequireDefault(require("immer"));
24
24
  const _material = require("@mui/material");
25
25
  const _plus = /*#__PURE__*/ _interopRequireDefault(require("mdi-material-ui/Plus"));
26
26
  const _system = require("@mui/system");
27
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
27
+ const _chartsProvider = require("../context/ChartsProvider");
28
28
  const _optionsEditorLayout = require("../OptionsEditorLayout");
29
29
  const _infoTooltip = require("../InfoTooltip");
30
30
  const _thresholdColorPicker = require("./ThresholdColorPicker");
@@ -75,7 +75,8 @@ function _interopRequireWildcard(obj, nodeInterop) {
75
75
  }
76
76
  const DEFAULT_STEP = 10;
77
77
  function ThresholdsEditor({ thresholds , onChange , hideDefault , disablePercentMode }) {
78
- const { thresholds: { defaultColor , palette } , } = (0, _chartsThemeProvider.useChartsTheme)();
78
+ const chartsTheme = (0, _chartsProvider.useChartsTheme)();
79
+ const { thresholds: { defaultColor , palette } , } = chartsTheme;
79
80
  var ref;
80
81
  const defaultThresholdColor = (ref = thresholds === null || thresholds === void 0 ? void 0 : thresholds.default_color) !== null && ref !== void 0 ? ref : defaultColor;
81
82
  const [steps, setSteps] = (0, _react.useState)(thresholds === null || thresholds === void 0 ? void 0 : thresholds.steps);
@@ -22,6 +22,7 @@ const _jsxRuntime = require("react/jsx-runtime");
22
22
  const _react = require("react");
23
23
  const _material = require("@mui/material");
24
24
  const _merge = /*#__PURE__*/ _interopRequireDefault(require("lodash/merge"));
25
+ const _isEqual = /*#__PURE__*/ _interopRequireDefault(require("lodash/isEqual"));
25
26
  const _dateFnsTz = require("date-fns-tz");
26
27
  const _core = require("@perses-dev/core");
27
28
  const _core1 = require("echarts/core");
@@ -29,8 +30,8 @@ const _charts = require("echarts/charts");
29
30
  const _components = require("echarts/components");
30
31
  const _renderers = require("echarts/renderers");
31
32
  const _echart = require("../EChart");
32
- const _graph = require("../model/graph");
33
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
33
+ const _model = require("../model");
34
+ const _chartsProvider = require("../context/ChartsProvider");
34
35
  const _utils = require("../utils");
35
36
  const _timeSeriesTooltip = require("../TimeSeriesTooltip");
36
37
  const _timeZoneProvider = require("../context/TimeZoneProvider");
@@ -53,14 +54,14 @@ function _interopRequireDefault(obj) {
53
54
  _components.TooltipComponent,
54
55
  _renderers.CanvasRenderer
55
56
  ]);
56
- const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height , data , seriesMapping , timeScale: timeScaleProp , yAxis , unit , grid , isStackedBar =false , tooltipConfig ={
57
- wrapLabels: true
58
- } , noDataVariant ='message' , syncGroup , onDataZoom , onDoubleClick , __experimentalEChartsOptionsOverride , }, ref) {
57
+ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height , data , seriesMapping , timeScale: timeScaleProp , yAxis , unit , grid , isStackedBar =false , tooltipConfig =_timeSeriesTooltip.DEFAULT_TOOLTIP_CONFIG , noDataVariant ='message' , syncGroup , onDataZoom , onDoubleClick , __experimentalEChartsOptionsOverride , }, ref) {
59
58
  var ref1;
60
- const chartsTheme = (0, _chartsThemeProvider.useChartsTheme)();
59
+ const { chartsTheme , enablePinning , lastTooltipPinnedCoords , setLastTooltipPinnedCoords } = (0, _chartsProvider.useChartsContext)();
60
+ const isPinningEnabled = tooltipConfig.enablePinning && enablePinning;
61
61
  const chartRef = (0, _react.useRef)();
62
62
  const [showTooltip, setShowTooltip] = (0, _react.useState)(true);
63
63
  const [tooltipPinnedCoords, setTooltipPinnedCoords] = (0, _react.useState)(null);
64
+ const [pinnedCrosshair, setPinnedCrosshair] = (0, _react.useState)(null);
64
65
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
65
66
  const [startX, setStartX] = (0, _react.useState)(0);
66
67
  const { timeZone } = (0, _timeZoneProvider.useTimeZone)();
@@ -169,10 +170,14 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
169
170
  ]
170
171
  });
171
172
  });
173
+ const updatedSeriesMapping = enablePinning && pinnedCrosshair !== null ? [
174
+ ...seriesMapping,
175
+ pinnedCrosshair
176
+ ] : seriesMapping;
172
177
  var _rangeMs;
173
178
  const option = {
174
179
  dataset: dataset,
175
- series: seriesMapping,
180
+ series: updatedSeriesMapping,
176
181
  xAxis: {
177
182
  type: 'time',
178
183
  min: isLocalTimeZone ? timeScale.startMs : (0, _dateFnsTz.utcToZonedTime)(timeScale.startMs, timeZone),
@@ -185,13 +190,14 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
185
190
  snap: false
186
191
  }
187
192
  },
188
- yAxis: (0, _utils.getYAxes)(yAxis, unit),
193
+ yAxis: (0, _utils.getFormattedAxis)(yAxis, unit),
189
194
  animation: false,
190
195
  tooltip: {
191
196
  show: true,
192
- trigger: isStackedBar ? 'item' : 'axis',
193
- // ECharts tooltip content hidden since we use custom tooltip instead
197
+ // ECharts tooltip content hidden by default since we use custom tooltip instead.
198
+ // Stacked bar uses ECharts tooltip so subgroup data shows correctly.
194
199
  showContent: isStackedBar,
200
+ trigger: isStackedBar ? 'item' : 'axis',
195
201
  appendToBody: true
196
202
  },
197
203
  // https://echarts.apache.org/en/option.html#axisPointer
@@ -216,8 +222,6 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
216
222
  return __experimentalEChartsOptionsOverride(option);
217
223
  }
218
224
  return option;
219
- // tooltipPinnedCoords is needed in dep array so crosshair stays beside pinned tooltip onClick
220
- // eslint-disable-next-line react-hooks/exhaustive-deps
221
225
  }, [
222
226
  data,
223
227
  seriesMapping,
@@ -229,60 +233,101 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
229
233
  __experimentalEChartsOptionsOverride,
230
234
  noDataVariant,
231
235
  timeZone,
232
- tooltipPinnedCoords,
233
- isStackedBar
236
+ isStackedBar,
237
+ enablePinning,
238
+ pinnedCrosshair
239
+ ]);
240
+ // Update adjacent charts so tooltip is unpinned when current chart is clicked.
241
+ (0, _react.useEffect)(()=>{
242
+ // Only allow pinning one tooltip at a time, subsequent tooltip click unpins previous.
243
+ // Multiple tooltips can only be pinned if Ctrl or Cmd key is pressed while clicking.
244
+ const multipleTooltipsPinned = tooltipPinnedCoords !== null && lastTooltipPinnedCoords !== null;
245
+ if (multipleTooltipsPinned) {
246
+ if (!(0, _isEqual.default)(lastTooltipPinnedCoords, tooltipPinnedCoords)) {
247
+ setTooltipPinnedCoords(null);
248
+ if (tooltipPinnedCoords !== null && pinnedCrosshair !== null) {
249
+ setPinnedCrosshair(null);
250
+ }
251
+ }
252
+ }
253
+ // tooltipPinnedCoords CANNOT be in dep array or tooltip pinning breaks in the current chart's onClick
254
+ // eslint-disable-next-line react-hooks/exhaustive-deps
255
+ }, [
256
+ lastTooltipPinnedCoords,
257
+ seriesMapping
234
258
  ]);
235
259
  return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Box, {
236
260
  sx: {
237
261
  height
238
262
  },
263
+ // onContextMenu={(e) => {
264
+ // // TODO: confirm tooltip pinning works correctly on Windows, should e.preventDefault() be added here
265
+ // e.preventDefault(); // Prevent the default behaviour when right clicked
266
+ // }}
239
267
  onClick: (e)=>{
240
- var ref;
268
+ // Allows user to opt-in to multi tooltip pinning when Ctrl or Cmd key held down
269
+ const isControlKeyPressed = e.ctrlKey || e.metaKey;
270
+ if (isControlKeyPressed) {
271
+ e.preventDefault();
272
+ }
241
273
  // Determine where on chart canvas to plot pinned crosshair as markLine.
242
274
  const pointInGrid = (0, _utils.getPointInGrid)(e.nativeEvent.offsetX, e.nativeEvent.offsetY, chartRef.current);
243
275
  if (pointInGrid === null) {
244
276
  return;
245
277
  }
246
- // Clear previously set pinned crosshair
247
- const isCrosshairPinned = ((ref = seriesMapping[seriesMapping.length - 1]) === null || ref === void 0 ? void 0 : ref.name) === _graph.PINNED_CROSSHAIR_SERIES_NAME;
248
- if (tooltipPinnedCoords !== null && isCrosshairPinned) {
249
- seriesMapping.pop();
250
- } else if (seriesMapping.length !== data.length + 1) {
251
- // Only add pinned crosshair line series when there is not one already in seriesMapping.
252
- const pinnedCrosshair = (0, _merge.default)(_graph.DEFAULT_PINNED_CROSSHAIR, {
253
- markLine: {
254
- data: [
255
- {
256
- xAxis: pointInGrid[0]
257
- }
258
- ]
259
- }
260
- });
261
- seriesMapping.push(pinnedCrosshair);
262
- }
263
278
  // Pin and unpin when clicking on chart canvas but not tooltip text.
264
- if (e.target instanceof HTMLCanvasElement) {
279
+ if (isPinningEnabled && e.target instanceof HTMLCanvasElement) {
280
+ // Pin tooltip and update shared charts context to remember these coordinates.
281
+ const pinnedPos = {
282
+ page: {
283
+ x: e.pageX,
284
+ y: e.pageY
285
+ },
286
+ client: {
287
+ x: e.clientX,
288
+ y: e.clientY
289
+ },
290
+ plotCanvas: {
291
+ x: e.nativeEvent.offsetX,
292
+ y: e.nativeEvent.offsetY
293
+ },
294
+ target: e.target
295
+ };
265
296
  setTooltipPinnedCoords((current)=>{
266
297
  if (current === null) {
267
- return {
268
- page: {
269
- x: e.pageX,
270
- y: e.pageY
271
- },
272
- client: {
273
- x: e.clientX,
274
- y: e.clientY
275
- },
276
- plotCanvas: {
277
- x: e.nativeEvent.offsetX,
278
- y: e.nativeEvent.offsetY
279
- },
280
- target: e.target
281
- };
298
+ return pinnedPos;
299
+ } else {
300
+ setPinnedCrosshair(null);
301
+ return null;
302
+ }
303
+ });
304
+ setPinnedCrosshair((current)=>{
305
+ // Only add pinned crosshair line series when there is not one already in seriesMapping.
306
+ if (current === null) {
307
+ var ref;
308
+ const cursorX = pointInGrid[0];
309
+ // Only need to loop through first dataset source since getCommonTimeScale ensures xAxis timestamps are consistent
310
+ const firstTimeSeriesValues = (ref = data[0]) === null || ref === void 0 ? void 0 : ref.values;
311
+ const closestTimestamp = (0, _utils.getClosestTimestamp)(firstTimeSeriesValues, cursorX);
312
+ // Crosshair snaps to nearest timestamp since cursor may be slightly to left or right
313
+ const pinnedCrosshair = (0, _merge.default)({}, _model.DEFAULT_PINNED_CROSSHAIR, {
314
+ markLine: {
315
+ data: [
316
+ {
317
+ xAxis: closestTimestamp
318
+ }
319
+ ]
320
+ }
321
+ });
322
+ return pinnedCrosshair;
282
323
  } else {
324
+ // Clear previously set pinned crosshair
283
325
  return null;
284
326
  }
285
327
  });
328
+ if (!isControlKeyPressed) {
329
+ setLastTooltipPinnedCoords(pinnedPos);
330
+ }
286
331
  }
287
332
  },
288
333
  onMouseDown: (e)=>{
@@ -341,12 +386,14 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
341
386
  data: data,
342
387
  seriesMapping: seriesMapping,
343
388
  wrapLabels: tooltipConfig.wrapLabels,
389
+ enablePinning: isPinningEnabled,
344
390
  pinnedPos: tooltipPinnedCoords,
345
391
  unit: unit,
346
392
  onUnpinClick: ()=>{
393
+ // Unpins tooltip when clicking Pin icon in TooltipHeader.
347
394
  setTooltipPinnedCoords(null);
348
- // Clear previously set pinned crosshair
349
- seriesMapping.pop();
395
+ // Clear previously set pinned crosshair.
396
+ setPinnedCrosshair(null);
350
397
  }
351
398
  }),
352
399
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(_echart.EChart, {
@@ -32,12 +32,12 @@ function _interopRequireDefault(obj) {
32
32
  default: obj
33
33
  };
34
34
  }
35
- const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartTooltip({ chartRef , chartData , wrapLabels , unit , onUnpinClick , pinnedPos , containerId }) {
35
+ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartTooltip({ chartRef , chartData , enablePinning =true , wrapLabels , unit , onUnpinClick , pinnedPos , containerId }) {
36
36
  const [showAllSeries, setShowAllSeries] = (0, _react.useState)(false);
37
37
  const mousePos = (0, _tooltipModel.useMousePosition)();
38
38
  const { height , width , ref: tooltipRef } = (0, _useResizeObserver.default)();
39
39
  const transform = (0, _react.useRef)('');
40
- const isTooltipPinned = pinnedPos !== null;
40
+ const isTooltipPinned = pinnedPos !== null && enablePinning;
41
41
  if (mousePos === null || mousePos.target === null) return null;
42
42
  // Ensure user is hovering over a chart before checking for nearby series.
43
43
  if (pinnedPos === null && mousePos.target.tagName !== 'CANVAS') return null;
@@ -102,6 +102,7 @@ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartToolti
102
102
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(_tooltipHeader.TooltipHeader, {
103
103
  nearbySeries: nearbySeries,
104
104
  totalSeries: totalSeries,
105
+ enablePinning: enablePinning,
105
106
  isTooltipPinned: isTooltipPinned,
106
107
  showAllSeries: showAllSeries,
107
108
  onShowAllClick: (checked)=>setShowAllSeries(checked),
@@ -32,12 +32,12 @@ function _interopRequireDefault(obj) {
32
32
  default: obj
33
33
  };
34
34
  }
35
- const TimeChartTooltip = /*#__PURE__*/ (0, _react.memo)(function TimeChartTooltip({ containerId , chartRef , data , seriesMapping , wrapLabels , unit , onUnpinClick , pinnedPos }) {
35
+ const TimeChartTooltip = /*#__PURE__*/ (0, _react.memo)(function TimeChartTooltip({ containerId , chartRef , data , seriesMapping , enablePinning =true , wrapLabels , unit , onUnpinClick , pinnedPos }) {
36
36
  const [showAllSeries, setShowAllSeries] = (0, _react.useState)(false);
37
37
  const transform = (0, _react.useRef)('');
38
38
  const mousePos = (0, _tooltipModel.useMousePosition)();
39
39
  const { height , width , ref: tooltipRef } = (0, _useResizeObserver.default)();
40
- const isTooltipPinned = pinnedPos !== null;
40
+ const isTooltipPinned = pinnedPos !== null && enablePinning;
41
41
  if (mousePos === null || mousePos.target === null || data === null) return null;
42
42
  // Ensure user is hovering over a chart before checking for nearby series.
43
43
  if (pinnedPos === null && mousePos.target.tagName !== 'CANVAS') return null;
@@ -78,6 +78,7 @@ const TimeChartTooltip = /*#__PURE__*/ (0, _react.memo)(function TimeChartToolti
78
78
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(_tooltipHeader.TooltipHeader, {
79
79
  nearbySeries: nearbySeries,
80
80
  totalSeries: totalSeries,
81
+ enablePinning: enablePinning,
81
82
  isTooltipPinned: isTooltipPinned,
82
83
  showAllSeries: showAllSeries,
83
84
  onShowAllClick: (checked)=>setShowAllSeries(checked),
@@ -30,7 +30,7 @@ function _interopRequireDefault(obj) {
30
30
  default: obj
31
31
  };
32
32
  }
33
- const TooltipHeader = /*#__PURE__*/ (0, _react.memo)(function TooltipHeader({ nearbySeries , totalSeries , isTooltipPinned , showAllSeries , onShowAllClick , onUnpinClick }) {
33
+ const TooltipHeader = /*#__PURE__*/ (0, _react.memo)(function TooltipHeader({ nearbySeries , totalSeries , isTooltipPinned , showAllSeries , enablePinning =true , onShowAllClick , onUnpinClick }) {
34
34
  var ref;
35
35
  var ref1;
36
36
  const seriesTimeMs = (ref1 = (ref = nearbySeries[0]) === null || ref === void 0 ? void 0 : ref.date) !== null && ref1 !== void 0 ? ref1 : null;
@@ -60,8 +60,8 @@ const TooltipHeader = /*#__PURE__*/ (0, _react.memo)(function TooltipHeader({ ne
60
60
  });
61
61
  };
62
62
  // TODO: accurately calc whether more series are outside scrollable region using yBuffer, avg series name length, TOOLTIP_MAX_HEIGHT
63
- const showAllSeriesToggle = totalSeries > 5;
64
- const pinTooltipHelpText = isTooltipPinned ? 'Click to unpin' : 'Click chart to pin';
63
+ const showAllSeriesToggle = enablePinning && totalSeries > 5;
64
+ const pinTooltipHelpText = isTooltipPinned ? _tooltipModel.UNPIN_TOOLTIP_HELP_TEXT : _tooltipModel.PIN_TOOLTIP_HELP_TEXT;
65
65
  var ref2;
66
66
  return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Box, {
67
67
  sx: (theme)=>{
@@ -127,7 +127,7 @@ const TooltipHeader = /*#__PURE__*/ (0, _react.memo)(function TooltipHeader({ ne
127
127
  })
128
128
  ]
129
129
  }),
130
- /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
130
+ enablePinning && /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
131
131
  direction: "row",
132
132
  alignItems: "center",
133
133
  children: [
@@ -38,11 +38,12 @@ const INCREASE_NEARBY_SERIES_MULTIPLIER = 5.5; // adjusts how many series show i
38
38
  const DYNAMIC_NEARBY_SERIES_MULTIPLIER = 30; // used for adjustment after series number divisor
39
39
  const SHOW_FEWER_SERIES_LIMIT = 5;
40
40
  function checkforNearbyTimeSeries(data, seriesMapping, pointInGrid, yBuffer, chart, unit) {
41
- const currentNearbySeriesData = [];
42
41
  var ref;
43
- const cursorX = (ref = pointInGrid[0]) !== null && ref !== void 0 ? ref : null;
42
+ const currentNearbySeriesData = [];
44
43
  var ref1;
45
- const cursorY = (ref1 = pointInGrid[1]) !== null && ref1 !== void 0 ? ref1 : null;
44
+ const cursorX = (ref1 = pointInGrid[0]) !== null && ref1 !== void 0 ? ref1 : null;
45
+ var ref2;
46
+ const cursorY = (ref2 = pointInGrid[1]) !== null && ref2 !== void 0 ? ref2 : null;
46
47
  if (cursorX === null || cursorY === null) return currentNearbySeriesData;
47
48
  if (chart.dispatchAction === undefined) return currentNearbySeriesData;
48
49
  if (!Array.isArray(data)) return currentNearbySeriesData;
@@ -53,8 +54,12 @@ function checkforNearbyTimeSeries(data, seriesMapping, pointInGrid, yBuffer, cha
53
54
  const duplicateDatapoints = [];
54
55
  const totalSeries = data.length;
55
56
  const yValueCounts = new Map();
56
- let closestTimestamp = null;
57
- let closestDistance = Infinity;
57
+ // Only need to loop through first dataset source since getCommonTimeScale ensures xAxis timestamps are consistent
58
+ const firstTimeSeriesValues = (ref = data[0]) === null || ref === void 0 ? void 0 : ref.values;
59
+ const closestTimestamp = (0, _utils.getClosestTimestamp)(firstTimeSeriesValues, cursorX);
60
+ if (closestTimestamp === null) {
61
+ return [];
62
+ }
58
63
  // find the timestamp with data that is closest to cursorX
59
64
  for(let seriesIdx = 0; seriesIdx < totalSeries; seriesIdx++){
60
65
  const currentSeries = seriesMapping[seriesIdx];
@@ -62,15 +67,6 @@ function checkforNearbyTimeSeries(data, seriesMapping, pointInGrid, yBuffer, cha
62
67
  const currentDataset = totalSeries > 0 ? data[seriesIdx] : null;
63
68
  if (currentDataset == null) break;
64
69
  const currentDatasetValues = currentDataset.values;
65
- // Determine closestTimestamp before checking whether it is equal to xValue. Consolidating
66
- // with second currentDatasetValues loop below would result in duplicate nearby series
67
- for (const [timestamp] of currentDatasetValues){
68
- const distance = Math.abs(timestamp - cursorX);
69
- if (distance < closestDistance) {
70
- closestTimestamp = timestamp;
71
- closestDistance = distance;
72
- }
73
- }
74
70
  if (currentDatasetValues === undefined || !Array.isArray(currentDatasetValues)) break;
75
71
  const lineSeries = currentSeries;
76
72
  const currentSeriesName = lineSeries.name ? lineSeries.name.toString() : '';
@@ -97,10 +93,10 @@ function checkforNearbyTimeSeries(data, seriesMapping, pointInGrid, yBuffer, cha
97
93
  if (isClosestToCursor) {
98
94
  // shows as bold in tooltip, customize 'emphasis' options in getTimeSeries util
99
95
  emphasizedSeriesIndexes.push(seriesIdx);
100
- var ref2;
96
+ var ref3;
101
97
  // Used to determine which datapoint to apply select styles to.
102
98
  // Accounts for cases where lines may be rendered directly on top of eachother.
103
- const duplicateValuesCount = (ref2 = yValueCounts.get(yValue)) !== null && ref2 !== void 0 ? ref2 : 0;
99
+ const duplicateValuesCount = (ref3 = yValueCounts.get(yValue)) !== null && ref3 !== void 0 ? ref3 : 0;
104
100
  yValueCounts.set(yValue, duplicateValuesCount + 1);
105
101
  if (duplicateValuesCount > 0) {
106
102
  duplicateDatapoints.push({
@@ -34,7 +34,10 @@ _export(exports, {
34
34
  TOOLTIP_DATE_FORMAT: ()=>TOOLTIP_DATE_FORMAT,
35
35
  defaultCursorData: ()=>defaultCursorData,
36
36
  emptyTooltipData: ()=>emptyTooltipData,
37
- useMousePosition: ()=>useMousePosition
37
+ useMousePosition: ()=>useMousePosition,
38
+ DEFAULT_TOOLTIP_CONFIG: ()=>DEFAULT_TOOLTIP_CONFIG,
39
+ PIN_TOOLTIP_HELP_TEXT: ()=>PIN_TOOLTIP_HELP_TEXT,
40
+ UNPIN_TOOLTIP_HELP_TEXT: ()=>UNPIN_TOOLTIP_HELP_TEXT
38
41
  });
39
42
  const _react = require("react");
40
43
  const TOOLTIP_MIN_WIDTH = 375;
@@ -108,3 +111,9 @@ const useMousePosition = ()=>{
108
111
  }, []);
109
112
  return coords;
110
113
  };
114
+ const DEFAULT_TOOLTIP_CONFIG = {
115
+ wrapLabels: true,
116
+ enablePinning: true
117
+ };
118
+ const PIN_TOOLTIP_HELP_TEXT = 'Click chart to pin';
119
+ const UNPIN_TOOLTIP_HELP_TEXT = 'Click chart to unpin';
@@ -21,8 +21,9 @@ function _export(target, all) {
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- ChartsThemeProvider: ()=>ChartsThemeProvider,
24
+ ChartsProvider: ()=>ChartsProvider,
25
25
  ChartsThemeContext: ()=>ChartsThemeContext,
26
+ useChartsContext: ()=>useChartsContext,
26
27
  useChartsTheme: ()=>useChartsTheme
27
28
  });
28
29
  const _jsxRuntime = require("react/jsx-runtime");
@@ -66,18 +67,36 @@ function _interopRequireWildcard(obj, nodeInterop) {
66
67
  }
67
68
  return newObj;
68
69
  }
69
- function ChartsThemeProvider(props) {
70
- const { children , chartsTheme } = props;
70
+ function ChartsProvider(props) {
71
+ const { children , chartsTheme , enablePinning =false } = props;
72
+ const [lastTooltipPinnedCoords, setLastTooltipPinnedCoords] = (0, _react.useState)(null);
73
+ const ctx = (0, _react.useMemo)(()=>{
74
+ return {
75
+ chartsTheme,
76
+ enablePinning,
77
+ lastTooltipPinnedCoords,
78
+ setLastTooltipPinnedCoords
79
+ };
80
+ }, [
81
+ chartsTheme,
82
+ enablePinning,
83
+ lastTooltipPinnedCoords,
84
+ setLastTooltipPinnedCoords
85
+ ]);
71
86
  return /*#__PURE__*/ (0, _jsxRuntime.jsx)(ChartsThemeContext.Provider, {
72
- value: chartsTheme,
87
+ value: ctx,
73
88
  children: children
74
89
  });
75
90
  }
76
91
  const ChartsThemeContext = /*#__PURE__*/ (0, _react.createContext)(undefined);
77
- function useChartsTheme() {
92
+ function useChartsContext() {
78
93
  const ctx = (0, _react.useContext)(ChartsThemeContext);
79
94
  if (ctx === undefined) {
80
95
  throw new Error('No ChartsThemeContext found. Did you forget a Provider?');
81
96
  }
82
97
  return ctx;
83
98
  }
99
+ function useChartsTheme() {
100
+ const ctx = useChartsContext();
101
+ return ctx.chartsTheme;
102
+ }
@@ -0,0 +1,30 @@
1
+ // Copyright 2023 The Perses Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ "use strict";
14
+ Object.defineProperty(exports, "__esModule", {
15
+ value: true
16
+ });
17
+ _exportStar(require("./ChartsProvider"), exports);
18
+ _exportStar(require("./SnackbarProvider"), exports);
19
+ _exportStar(require("./TimeZoneProvider"), exports);
20
+ function _exportStar(from, to) {
21
+ Object.keys(from).forEach(function(k) {
22
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) Object.defineProperty(to, k, {
23
+ enumerable: true,
24
+ get: function() {
25
+ return from[k];
26
+ }
27
+ });
28
+ });
29
+ return from;
30
+ }
package/dist/cjs/index.js CHANGED
@@ -40,9 +40,7 @@ _exportStar(require("./TimeChart"), exports);
40
40
  _exportStar(require("./TimeSeriesTooltip"), exports);
41
41
  _exportStar(require("./UnitSelector"), exports);
42
42
  _exportStar(require("./YAxisLabel"), exports);
43
- _exportStar(require("./context/ChartsThemeProvider"), exports);
44
- _exportStar(require("./context/TimeZoneProvider"), exports);
45
- _exportStar(require("./context/SnackbarProvider"), exports);
43
+ _exportStar(require("./context"), exports);
46
44
  _exportStar(require("./utils"), exports);
47
45
  _exportStar(require("./model"), exports);
48
46
  _exportStar(require("./test-utils"), exports);
@@ -14,28 +14,41 @@
14
14
  Object.defineProperty(exports, "__esModule", {
15
15
  value: true
16
16
  });
17
- Object.defineProperty(exports, "testChartsTheme", {
18
- enumerable: true,
19
- get: ()=>testChartsTheme
17
+ function _export(target, all) {
18
+ for(var name in all)Object.defineProperty(target, name, {
19
+ enumerable: true,
20
+ get: all[name]
21
+ });
22
+ }
23
+ _export(exports, {
24
+ testChartsTheme: ()=>testChartsTheme,
25
+ mockChartsContext: ()=>mockChartsContext
20
26
  });
21
- const testChartsTheme = {
22
- echartsTheme: {},
23
- noDataOption: {},
24
- sparkline: {
25
- width: 1,
26
- color: '#000000'
27
+ const _material = require("@mui/material");
28
+ const _utils = require("../utils");
29
+ // app specific echarts option overrides
30
+ const TEST_ECHARTS_THEME_OVERRIDES = {
31
+ textStyle: {
32
+ fontFamily: 'Lato'
27
33
  },
28
- container: {
29
- padding: {
30
- default: 12
34
+ categoryAxis: {
35
+ splitLine: {
36
+ show: false
31
37
  }
32
38
  },
33
- thresholds: {
34
- defaultColor: '#59CC8D',
35
- palette: [
36
- '#438FEB',
37
- '#FFB249',
38
- '#EE6C6C'
39
- ]
39
+ timeAxis: {
40
+ splitLine: {
41
+ show: false
42
+ }
43
+ },
44
+ bar: {
45
+ barCategoryGap: 2
40
46
  }
41
47
  };
48
+ const testChartsTheme = (0, _utils.generateChartsTheme)((0, _material.createTheme)({}), TEST_ECHARTS_THEME_OVERRIDES);
49
+ const mockChartsContext = {
50
+ chartsTheme: testChartsTheme,
51
+ enablePinning: false,
52
+ lastTooltipPinnedCoords: null,
53
+ setLastTooltipPinnedCoords: ()=>null
54
+ };