@perses-dev/components 0.37.2 → 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 (140) hide show
  1. package/README.md +1 -0
  2. package/dist/BarChart/BarChart.d.ts +16 -0
  3. package/dist/BarChart/BarChart.d.ts.map +1 -0
  4. package/dist/BarChart/BarChart.js +129 -0
  5. package/dist/BarChart/BarChart.js.map +1 -0
  6. package/dist/BarChart/index.d.ts +2 -0
  7. package/dist/BarChart/index.d.ts.map +1 -0
  8. package/dist/BarChart/index.js +15 -0
  9. package/dist/BarChart/index.js.map +1 -0
  10. package/dist/Dialog/DiscardChangesConfirmationDialog.d.ts +10 -0
  11. package/dist/Dialog/DiscardChangesConfirmationDialog.d.ts.map +1 -0
  12. package/dist/Dialog/DiscardChangesConfirmationDialog.js +47 -0
  13. package/dist/Dialog/DiscardChangesConfirmationDialog.js.map +1 -0
  14. package/dist/Dialog/index.d.ts +1 -0
  15. package/dist/Dialog/index.d.ts.map +1 -1
  16. package/dist/Dialog/index.js +1 -0
  17. package/dist/Dialog/index.js.map +1 -1
  18. package/dist/GaugeChart/GaugeChart.js +1 -1
  19. package/dist/GaugeChart/GaugeChart.js.map +1 -1
  20. package/dist/Legend/ListLegendItem.d.ts +1 -1
  21. package/dist/LineChart/LineChart.d.ts.map +1 -1
  22. package/dist/LineChart/LineChart.js +9 -9
  23. package/dist/LineChart/LineChart.js.map +1 -1
  24. package/dist/ModeSelector/ModeSelector.d.ts +9 -0
  25. package/dist/ModeSelector/ModeSelector.d.ts.map +1 -0
  26. package/dist/ModeSelector/ModeSelector.js +43 -0
  27. package/dist/ModeSelector/ModeSelector.js.map +1 -0
  28. package/dist/ModeSelector/index.d.ts +2 -0
  29. package/dist/ModeSelector/index.d.ts.map +1 -0
  30. package/dist/ModeSelector/index.js +15 -0
  31. package/dist/ModeSelector/index.js.map +1 -0
  32. package/dist/SortSelector/SortSelector.d.ts +8 -0
  33. package/dist/SortSelector/SortSelector.d.ts.map +1 -0
  34. package/dist/SortSelector/SortSelector.js +42 -0
  35. package/dist/SortSelector/SortSelector.js.map +1 -0
  36. package/dist/SortSelector/index.d.ts +2 -0
  37. package/dist/SortSelector/index.d.ts.map +1 -0
  38. package/dist/SortSelector/index.js +15 -0
  39. package/dist/SortSelector/index.js.map +1 -0
  40. package/dist/StatChart/StatChart.js +1 -1
  41. package/dist/StatChart/StatChart.js.map +1 -1
  42. package/dist/StatChart/calculateFontSize.js +3 -3
  43. package/dist/StatChart/calculateFontSize.js.map +1 -1
  44. package/dist/ThresholdsEditor/ThresholdColorPicker.js +1 -1
  45. package/dist/ThresholdsEditor/ThresholdColorPicker.js.map +1 -1
  46. package/dist/ThresholdsEditor/ThresholdsEditor.d.ts.map +1 -1
  47. package/dist/ThresholdsEditor/ThresholdsEditor.js +3 -2
  48. package/dist/ThresholdsEditor/ThresholdsEditor.js.map +1 -1
  49. package/dist/TimeChart/TimeChart.d.ts +2 -1
  50. package/dist/TimeChart/TimeChart.d.ts.map +1 -1
  51. package/dist/TimeChart/TimeChart.js +120 -36
  52. package/dist/TimeChart/TimeChart.js.map +1 -1
  53. package/dist/TimeSeriesTooltip/LineChartTooltip.d.ts +6 -0
  54. package/dist/TimeSeriesTooltip/LineChartTooltip.d.ts.map +1 -1
  55. package/dist/TimeSeriesTooltip/LineChartTooltip.js +14 -6
  56. package/dist/TimeSeriesTooltip/LineChartTooltip.js.map +1 -1
  57. package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts +1 -0
  58. package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts.map +1 -1
  59. package/dist/TimeSeriesTooltip/TimeChartTooltip.js +3 -2
  60. package/dist/TimeSeriesTooltip/TimeChartTooltip.js.map +1 -1
  61. package/dist/TimeSeriesTooltip/TooltipHeader.d.ts +1 -0
  62. package/dist/TimeSeriesTooltip/TooltipHeader.d.ts.map +1 -1
  63. package/dist/TimeSeriesTooltip/TooltipHeader.js +5 -5
  64. package/dist/TimeSeriesTooltip/TooltipHeader.js.map +1 -1
  65. package/dist/TimeSeriesTooltip/nearby-series.d.ts +1 -1
  66. package/dist/TimeSeriesTooltip/nearby-series.d.ts.map +1 -1
  67. package/dist/TimeSeriesTooltip/nearby-series.js +97 -110
  68. package/dist/TimeSeriesTooltip/nearby-series.js.map +1 -1
  69. package/dist/TimeSeriesTooltip/tooltip-model.d.ts +4 -0
  70. package/dist/TimeSeriesTooltip/tooltip-model.d.ts.map +1 -1
  71. package/dist/TimeSeriesTooltip/tooltip-model.js +6 -0
  72. package/dist/TimeSeriesTooltip/tooltip-model.js.map +1 -1
  73. package/dist/UnitSelector/UnitSelector.d.ts +2 -1
  74. package/dist/UnitSelector/UnitSelector.d.ts.map +1 -1
  75. package/dist/UnitSelector/UnitSelector.js +3 -2
  76. package/dist/UnitSelector/UnitSelector.js.map +1 -1
  77. package/dist/cjs/BarChart/BarChart.js +135 -0
  78. package/dist/cjs/BarChart/index.js +28 -0
  79. package/dist/cjs/Dialog/DiscardChangesConfirmationDialog.js +53 -0
  80. package/dist/cjs/Dialog/index.js +1 -0
  81. package/dist/cjs/GaugeChart/GaugeChart.js +2 -2
  82. package/dist/cjs/LineChart/LineChart.js +8 -8
  83. package/dist/cjs/ModeSelector/ModeSelector.js +49 -0
  84. package/dist/cjs/ModeSelector/index.js +28 -0
  85. package/dist/cjs/SortSelector/SortSelector.js +48 -0
  86. package/dist/cjs/SortSelector/index.js +28 -0
  87. package/dist/cjs/StatChart/StatChart.js +2 -2
  88. package/dist/cjs/StatChart/calculateFontSize.js +3 -3
  89. package/dist/cjs/ThresholdsEditor/ThresholdColorPicker.js +2 -2
  90. package/dist/cjs/ThresholdsEditor/ThresholdsEditor.js +3 -2
  91. package/dist/cjs/TimeChart/TimeChart.js +121 -32
  92. package/dist/cjs/TimeSeriesTooltip/LineChartTooltip.js +13 -5
  93. package/dist/cjs/TimeSeriesTooltip/TimeChartTooltip.js +3 -2
  94. package/dist/cjs/TimeSeriesTooltip/TooltipHeader.js +4 -4
  95. package/dist/cjs/TimeSeriesTooltip/nearby-series.js +97 -110
  96. package/dist/cjs/TimeSeriesTooltip/tooltip-model.js +10 -1
  97. package/dist/cjs/UnitSelector/UnitSelector.js +3 -2
  98. package/dist/cjs/context/{ChartsThemeProvider.js → ChartsProvider.js} +24 -5
  99. package/dist/cjs/context/index.js +30 -0
  100. package/dist/cjs/index.js +4 -3
  101. package/dist/cjs/model/graph.js +35 -3
  102. package/dist/cjs/test-utils/theme.js +32 -19
  103. package/dist/cjs/utils/axis.js +4 -4
  104. package/dist/cjs/utils/chart-actions.js +99 -1
  105. package/dist/cjs/utils/theme-gen.js +34 -6
  106. package/dist/context/ChartsProvider.d.ts +19 -0
  107. package/dist/context/ChartsProvider.d.ts.map +1 -0
  108. package/dist/context/{ChartsThemeProvider.js → ChartsProvider.js} +24 -6
  109. package/dist/context/ChartsProvider.js.map +1 -0
  110. package/dist/context/index.d.ts +4 -0
  111. package/dist/context/index.d.ts.map +1 -0
  112. package/dist/context/index.js +17 -0
  113. package/dist/context/index.js.map +1 -0
  114. package/dist/index.d.ts +4 -3
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +4 -3
  117. package/dist/index.js.map +1 -1
  118. package/dist/model/graph.d.ts +11 -2
  119. package/dist/model/graph.d.ts.map +1 -1
  120. package/dist/model/graph.js +25 -0
  121. package/dist/model/graph.js.map +1 -1
  122. package/dist/test-utils/theme.d.ts +2 -0
  123. package/dist/test-utils/theme.d.ts.map +1 -1
  124. package/dist/test-utils/theme.js +23 -16
  125. package/dist/test-utils/theme.js.map +1 -1
  126. package/dist/utils/axis.d.ts +3 -3
  127. package/dist/utils/axis.d.ts.map +1 -1
  128. package/dist/utils/axis.js +4 -4
  129. package/dist/utils/axis.js.map +1 -1
  130. package/dist/utils/chart-actions.d.ts +7 -0
  131. package/dist/utils/chart-actions.d.ts.map +1 -1
  132. package/dist/utils/chart-actions.js +108 -0
  133. package/dist/utils/chart-actions.js.map +1 -1
  134. package/dist/utils/theme-gen.d.ts.map +1 -1
  135. package/dist/utils/theme-gen.js +34 -6
  136. package/dist/utils/theme-gen.js.map +1 -1
  137. package/package.json +3 -3
  138. package/dist/context/ChartsThemeProvider.d.ts +0 -10
  139. package/dist/context/ChartsThemeProvider.d.ts.map +0 -1
  140. package/dist/context/ChartsThemeProvider.js.map +0 -1
@@ -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);
@@ -21,6 +21,8 @@ Object.defineProperty(exports, "TimeChart", {
21
21
  const _jsxRuntime = require("react/jsx-runtime");
22
22
  const _react = require("react");
23
23
  const _material = require("@mui/material");
24
+ const _merge = /*#__PURE__*/ _interopRequireDefault(require("lodash/merge"));
25
+ const _isEqual = /*#__PURE__*/ _interopRequireDefault(require("lodash/isEqual"));
24
26
  const _dateFnsTz = require("date-fns-tz");
25
27
  const _core = require("@perses-dev/core");
26
28
  const _core1 = require("echarts/core");
@@ -28,12 +30,19 @@ const _charts = require("echarts/charts");
28
30
  const _components = require("echarts/components");
29
31
  const _renderers = require("echarts/renderers");
30
32
  const _echart = require("../EChart");
31
- const _chartsThemeProvider = require("../context/ChartsThemeProvider");
33
+ const _model = require("../model");
34
+ const _chartsProvider = require("../context/ChartsProvider");
32
35
  const _utils = require("../utils");
33
36
  const _timeSeriesTooltip = require("../TimeSeriesTooltip");
34
37
  const _timeZoneProvider = require("../context/TimeZoneProvider");
38
+ function _interopRequireDefault(obj) {
39
+ return obj && obj.__esModule ? obj : {
40
+ default: obj
41
+ };
42
+ }
35
43
  (0, _core1.use)([
36
44
  _charts.LineChart,
45
+ _charts.BarChart,
37
46
  _components.GridComponent,
38
47
  _components.DatasetComponent,
39
48
  _components.DataZoomComponent,
@@ -45,14 +54,14 @@ const _timeZoneProvider = require("../context/TimeZoneProvider");
45
54
  _components.TooltipComponent,
46
55
  _renderers.CanvasRenderer
47
56
  ]);
48
- const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height , data , seriesMapping , timeScale: timeScaleProp , yAxis , unit , grid , tooltipConfig ={
49
- wrapLabels: true
50
- } , 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) {
51
58
  var ref1;
52
- const chartsTheme = (0, _chartsThemeProvider.useChartsTheme)();
59
+ const { chartsTheme , enablePinning , lastTooltipPinnedCoords , setLastTooltipPinnedCoords } = (0, _chartsProvider.useChartsContext)();
60
+ const isPinningEnabled = tooltipConfig.enablePinning && enablePinning;
53
61
  const chartRef = (0, _react.useRef)();
54
62
  const [showTooltip, setShowTooltip] = (0, _react.useState)(true);
55
63
  const [tooltipPinnedCoords, setTooltipPinnedCoords] = (0, _react.useState)(null);
64
+ const [pinnedCrosshair, setPinnedCrosshair] = (0, _react.useState)(null);
56
65
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
57
66
  const [startX, setStartX] = (0, _react.useState)(0);
58
67
  const { timeZone } = (0, _timeZoneProvider.useTimeZone)();
@@ -122,19 +131,19 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
122
131
  };
123
132
  onDataZoom(zoomEvent);
124
133
  }
134
+ },
135
+ finished: ()=>{
136
+ if (chartRef.current !== undefined) {
137
+ (0, _utils.enableDataZoom)(chartRef.current);
138
+ }
125
139
  }
126
140
  };
127
141
  }, [
128
142
  onDataZoom,
129
143
  setTooltipPinnedCoords
130
144
  ]);
131
- if (chartRef.current !== undefined) {
132
- (0, _utils.enableDataZoom)(chartRef.current);
133
- }
134
145
  const { noDataOption } = chartsTheme;
135
146
  const option = (0, _react.useMemo)(()=>{
136
- // TODO: fix loading state and noData variants
137
- // if (data === undefined) return {};
138
147
  // The "chart" `noDataVariant` is only used when the `timeSeries` is an
139
148
  // empty array because a `null` value will throw an error.
140
149
  if (data === null || data.length === 0 && noDataVariant === 'message') return noDataOption;
@@ -161,10 +170,14 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
161
170
  ]
162
171
  });
163
172
  });
173
+ const updatedSeriesMapping = enablePinning && pinnedCrosshair !== null ? [
174
+ ...seriesMapping,
175
+ pinnedCrosshair
176
+ ] : seriesMapping;
164
177
  var _rangeMs;
165
178
  const option = {
166
179
  dataset: dataset,
167
- series: seriesMapping,
180
+ series: updatedSeriesMapping,
168
181
  xAxis: {
169
182
  type: 'time',
170
183
  min: isLocalTimeZone ? timeScale.startMs : (0, _dateFnsTz.utcToZonedTime)(timeScale.startMs, timeZone),
@@ -172,14 +185,20 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
172
185
  axisLabel: {
173
186
  hideOverlap: true,
174
187
  formatter: (0, _utils.getFormattedAxisLabel)((_rangeMs = timeScale.rangeMs) !== null && _rangeMs !== void 0 ? _rangeMs : 0)
188
+ },
189
+ axisPointer: {
190
+ snap: false
175
191
  }
176
192
  },
177
- yAxis: (0, _utils.getYAxes)(yAxis, unit),
193
+ yAxis: (0, _utils.getFormattedAxis)(yAxis, unit),
178
194
  animation: false,
179
195
  tooltip: {
180
196
  show: true,
181
- trigger: 'axis',
182
- showContent: false
197
+ // ECharts tooltip content hidden by default since we use custom tooltip instead.
198
+ // Stacked bar uses ECharts tooltip so subgroup data shows correctly.
199
+ showContent: isStackedBar,
200
+ trigger: isStackedBar ? 'item' : 'axis',
201
+ appendToBody: true
183
202
  },
184
203
  // https://echarts.apache.org/en/option.html#axisPointer
185
204
  axisPointer: {
@@ -187,7 +206,7 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
187
206
  z: 0,
188
207
  triggerEmphasis: false,
189
208
  triggerTooltip: false,
190
- snap: true
209
+ snap: false
191
210
  },
192
211
  toolbox: {
193
212
  feature: {
@@ -213,36 +232,102 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
213
232
  noDataOption,
214
233
  __experimentalEChartsOptionsOverride,
215
234
  noDataVariant,
216
- timeZone
235
+ timeZone,
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
217
258
  ]);
218
259
  return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Box, {
219
260
  sx: {
220
261
  height
221
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
+ // }}
222
267
  onClick: (e)=>{
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
+ }
273
+ // Determine where on chart canvas to plot pinned crosshair as markLine.
274
+ const pointInGrid = (0, _utils.getPointInGrid)(e.nativeEvent.offsetX, e.nativeEvent.offsetY, chartRef.current);
275
+ if (pointInGrid === null) {
276
+ return;
277
+ }
223
278
  // Pin and unpin when clicking on chart canvas but not tooltip text.
224
- 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
+ };
225
296
  setTooltipPinnedCoords((current)=>{
226
297
  if (current === null) {
227
- return {
228
- page: {
229
- x: e.pageX,
230
- y: e.pageY
231
- },
232
- client: {
233
- x: e.clientX,
234
- y: e.clientY
235
- },
236
- plotCanvas: {
237
- x: e.nativeEvent.offsetX,
238
- y: e.nativeEvent.offsetY
239
- },
240
- target: e.target
241
- };
298
+ return pinnedPos;
242
299
  } else {
300
+ setPinnedCrosshair(null);
243
301
  return null;
244
302
  }
245
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;
323
+ } else {
324
+ // Clear previously set pinned crosshair
325
+ return null;
326
+ }
327
+ });
328
+ if (!isControlKeyPressed) {
329
+ setLastTooltipPinnedCoords(pinnedPos);
330
+ }
246
331
  }
247
332
  },
248
333
  onMouseDown: (e)=>{
@@ -301,10 +386,14 @@ const TimeChart = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ heig
301
386
  data: data,
302
387
  seriesMapping: seriesMapping,
303
388
  wrapLabels: tooltipConfig.wrapLabels,
389
+ enablePinning: isPinningEnabled,
304
390
  pinnedPos: tooltipPinnedCoords,
305
391
  unit: unit,
306
392
  onUnpinClick: ()=>{
393
+ // Unpins tooltip when clicking Pin icon in TooltipHeader.
307
394
  setTooltipPinnedCoords(null);
395
+ // Clear previously set pinned crosshair.
396
+ setPinnedCrosshair(null);
308
397
  }
309
398
  }),
310
399
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(_echart.EChart, {
@@ -32,18 +32,18 @@ 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 }) {
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
- const isTooltipPinned = pinnedPos !== null;
39
+ const transform = (0, _react.useRef)('');
40
+ const isTooltipPinned = pinnedPos !== null && enablePinning;
40
41
  if (mousePos === null || mousePos.target === null) return null;
41
42
  // Ensure user is hovering over a chart before checking for nearby series.
42
43
  if (pinnedPos === null && mousePos.target.tagName !== 'CANVAS') return null;
43
44
  const chart = chartRef.current;
44
45
  var ref;
45
46
  const chartWidth = (ref = chart === null || chart === void 0 ? void 0 : chart.getWidth()) !== null && ref !== void 0 ? ref : _tooltipModel.FALLBACK_CHART_WIDTH; // Fallback width not likely to ever be needed.
46
- const cursorTransform = (0, _utils.assembleTransform)(mousePos, chartWidth, pinnedPos, height !== null && height !== void 0 ? height : 0, width !== null && width !== void 0 ? width : 0);
47
47
  // Get series nearby the cursor and pass into tooltip content children.
48
48
  const nearbySeries = (0, _nearbySeries.legacyGetNearbySeriesData)({
49
49
  mousePos,
@@ -57,8 +57,15 @@ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartToolti
57
57
  return null;
58
58
  }
59
59
  const totalSeries = chartData.timeSeries.length;
60
+ const containerElement = containerId ? document.querySelector(containerId) : undefined;
61
+ // if tooltip is attached to a container, set max height to the height of the container so tooltip does not get cut off
62
+ const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined;
63
+ if (!isTooltipPinned) {
64
+ transform.current = (0, _utils.assembleTransform)(mousePos, chartWidth, pinnedPos, height !== null && height !== void 0 ? height : 0, width !== null && width !== void 0 ? width : 0, containerElement);
65
+ }
60
66
  var ref1;
61
67
  return /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Portal, {
68
+ container: containerElement,
62
69
  children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Box, {
63
70
  ref: tooltipRef,
64
71
  sx: (theme)=>{
@@ -66,7 +73,7 @@ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartToolti
66
73
  return {
67
74
  minWidth: _tooltipModel.TOOLTIP_MIN_WIDTH,
68
75
  maxWidth: _tooltipModel.TOOLTIP_MAX_WIDTH,
69
- maxHeight: _tooltipModel.TOOLTIP_MAX_HEIGHT,
76
+ maxHeight: maxHeight !== null && maxHeight !== void 0 ? maxHeight : _tooltipModel.TOOLTIP_MAX_HEIGHT,
70
77
  padding: 0,
71
78
  position: 'absolute',
72
79
  top: 0,
@@ -87,7 +94,7 @@ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartToolti
87
94
  };
88
95
  },
89
96
  style: {
90
- transform: cursorTransform
97
+ transform: transform.current
91
98
  },
92
99
  children: /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
93
100
  spacing: 0.5,
@@ -95,6 +102,7 @@ const LineChartTooltip = /*#__PURE__*/ (0, _react.memo)(function LineChartToolti
95
102
  /*#__PURE__*/ (0, _jsxRuntime.jsx)(_tooltipHeader.TooltipHeader, {
96
103
  nearbySeries: nearbySeries,
97
104
  totalSeries: totalSeries,
105
+ enablePinning: enablePinning,
98
106
  isTooltipPinned: isTooltipPinned,
99
107
  showAllSeries: showAllSeries,
100
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: [