@perses-dev/heatmap-chart-plugin 0.4.0-rc.0 → 0.4.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 (81) hide show
  1. package/__mf/js/{HeatMapChart.64173994.js → HeatMapChart.a5f52cc0.js} +3 -3
  2. package/__mf/js/async/12.4ae967ba.js +2 -0
  3. package/__mf/js/async/180.c67f24c4.js +71 -0
  4. package/__mf/js/async/392.81aab132.js +2 -0
  5. package/__mf/js/async/980.092bc51a.js +83 -0
  6. package/__mf/js/async/__federation_expose_HeatMapChart.c74c73d1.js +23 -0
  7. package/__mf/js/{main.73ddd86d.js → main.69b7f04b.js} +3 -3
  8. package/lib/HeatMapChart.js +1 -1
  9. package/lib/HeatMapChart.js.map +1 -1
  10. package/lib/bootstrap.js +1 -1
  11. package/lib/bootstrap.js.map +1 -1
  12. package/lib/cjs/HeatMapChart.js +1 -1
  13. package/lib/cjs/bootstrap.js +1 -1
  14. package/lib/cjs/components/HeatMapChart.js +97 -20
  15. package/lib/cjs/components/HeatMapChartOptionsEditorSettings.js +61 -6
  16. package/lib/cjs/components/HeatMapChartPanel.js +87 -38
  17. package/lib/cjs/components/HeatMapTooltip.js +6 -6
  18. package/lib/cjs/components/index.js +1 -1
  19. package/lib/cjs/env.d.js +1 -1
  20. package/lib/cjs/getPluginModule.js +12 -0
  21. package/lib/cjs/heat-map-chart-model.js +25 -1
  22. package/lib/cjs/index-federation.js +1 -1
  23. package/lib/cjs/index.js +1 -1
  24. package/lib/cjs/setup-tests.js +1 -1
  25. package/lib/cjs/utils/data-transform.js +12 -0
  26. package/lib/cjs/utils/get-formatted-axis-label.js +1 -1
  27. package/lib/cjs/utils/index.js +1 -1
  28. package/lib/cjs/utils/thresholds.js +12 -0
  29. package/lib/components/HeatMapChart.d.ts +6 -3
  30. package/lib/components/HeatMapChart.d.ts.map +1 -1
  31. package/lib/components/HeatMapChart.js +97 -20
  32. package/lib/components/HeatMapChart.js.map +1 -1
  33. package/lib/components/HeatMapChartOptionsEditorSettings.d.ts.map +1 -1
  34. package/lib/components/HeatMapChartOptionsEditorSettings.js +64 -9
  35. package/lib/components/HeatMapChartOptionsEditorSettings.js.map +1 -1
  36. package/lib/components/HeatMapChartPanel.d.ts.map +1 -1
  37. package/lib/components/HeatMapChartPanel.js +87 -38
  38. package/lib/components/HeatMapChartPanel.js.map +1 -1
  39. package/lib/components/HeatMapTooltip.d.ts +1 -2
  40. package/lib/components/HeatMapTooltip.d.ts.map +1 -1
  41. package/lib/components/HeatMapTooltip.js +6 -6
  42. package/lib/components/HeatMapTooltip.js.map +1 -1
  43. package/lib/components/index.js +1 -1
  44. package/lib/components/index.js.map +1 -1
  45. package/lib/env.d.js +1 -1
  46. package/lib/env.d.js.map +1 -1
  47. package/lib/getPluginModule.d.ts.map +1 -1
  48. package/lib/getPluginModule.js +12 -0
  49. package/lib/getPluginModule.js.map +1 -1
  50. package/lib/heat-map-chart-model.d.ts +13 -0
  51. package/lib/heat-map-chart-model.d.ts.map +1 -1
  52. package/lib/heat-map-chart-model.js +19 -1
  53. package/lib/heat-map-chart-model.js.map +1 -1
  54. package/lib/index-federation.js +1 -1
  55. package/lib/index-federation.js.map +1 -1
  56. package/lib/index.js +1 -1
  57. package/lib/index.js.map +1 -1
  58. package/lib/setup-tests.js +1 -1
  59. package/lib/setup-tests.js.map +1 -1
  60. package/lib/utils/data-transform.d.ts.map +1 -1
  61. package/lib/utils/data-transform.js +12 -0
  62. package/lib/utils/data-transform.js.map +1 -1
  63. package/lib/utils/get-formatted-axis-label.js +1 -1
  64. package/lib/utils/get-formatted-axis-label.js.map +1 -1
  65. package/lib/utils/index.js +1 -1
  66. package/lib/utils/index.js.map +1 -1
  67. package/lib/utils/thresholds.d.ts.map +1 -1
  68. package/lib/utils/thresholds.js +12 -0
  69. package/lib/utils/thresholds.js.map +1 -1
  70. package/mf-manifest.json +13 -13
  71. package/mf-stats.json +13 -13
  72. package/package.json +4 -4
  73. package/__mf/js/async/12.4a0642db.js +0 -2
  74. package/__mf/js/async/277.34ae0ac5.js +0 -71
  75. package/__mf/js/async/392.de783cd4.js +0 -2
  76. package/__mf/js/async/700.a5530423.js +0 -83
  77. package/__mf/js/async/__federation_expose_HeatMapChart.5ef80ecb.js +0 -23
  78. /package/__mf/js/async/{12.4a0642db.js.LICENSE.txt → 12.4ae967ba.js.LICENSE.txt} +0 -0
  79. /package/__mf/js/async/{277.34ae0ac5.js.LICENSE.txt → 180.c67f24c4.js.LICENSE.txt} +0 -0
  80. /package/__mf/js/async/{392.de783cd4.js.LICENSE.txt → 392.81aab132.js.LICENSE.txt} +0 -0
  81. /package/__mf/js/async/{700.a5530423.js.LICENSE.txt → 980.092bc51a.js.LICENSE.txt} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { FormatOptions, TimeScale } from '@perses-dev/core';
3
- export type HeatMapData = [number, number, number | undefined];
3
+ import { LOG_BASE } from '../heat-map-chart-model';
4
+ export type HeatMapData = [number, number, number, number | undefined];
4
5
  export interface HeatMapDataItem {
5
6
  value: HeatMapData;
6
7
  label: string;
@@ -15,13 +16,15 @@ export interface HeatMapChartProps {
15
16
  height: number;
16
17
  data: HeatMapDataItem[];
17
18
  xAxisCategories: number[];
18
- yAxisCategories: string[];
19
19
  yAxisFormat?: FormatOptions;
20
20
  countFormat?: FormatOptions;
21
21
  countMin?: number;
22
22
  countMax?: number;
23
23
  timeScale?: TimeScale;
24
24
  showVisualMap?: boolean;
25
+ min?: number;
26
+ max?: number;
27
+ logBase?: LOG_BASE;
25
28
  }
26
- export declare function HeatMapChart({ width, height, data, xAxisCategories, yAxisCategories, yAxisFormat, countFormat, countMin, countMax, timeScale, showVisualMap, }: HeatMapChartProps): ReactElement | null;
29
+ export declare function HeatMapChart({ width, height, data, xAxisCategories, yAxisFormat, countFormat, countMin, countMax, timeScale, showVisualMap, min, max, logBase, }: HeatMapChartProps): ReactElement | null;
27
30
  //# sourceMappingURL=HeatMapChart.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HeatMapChart.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChart.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAyB5D,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE;QACV,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CAEzB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,IAAI,EACJ,eAAe,EACf,eAAe,EACf,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,GACd,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI,CA0GzC"}
1
+ {"version":3,"file":"HeatMapChart.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChart.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAe,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAMzE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAqBnD,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE;QACV,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,IAAI,EACJ,eAAe,EACf,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,EACb,GAAG,EACH,GAAG,EACH,OAAO,GACR,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAqJzC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- // Copyright 2025 The Perses Authors
2
+ // Copyright The Perses Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
5
5
  // You may obtain a copy of the License at
@@ -12,14 +12,15 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { useMemo } from 'react';
15
- import { EChart, getFormattedAxis, useChartsTheme, useTimeZone } from '@perses-dev/components';
15
+ import { formatValue } from '@perses-dev/core';
16
+ import { EChart, useChartsTheme, useTimeZone } from '@perses-dev/components';
16
17
  import { use } from 'echarts/core';
17
- import { HeatmapChart as EChartsHeatmapChart } from 'echarts/charts';
18
+ import { CustomChart } from 'echarts/charts';
18
19
  import { useTheme } from '@mui/material';
19
20
  import { getFormattedHeatmapAxisLabel } from '../utils';
20
21
  import { generateTooltipHTML } from './HeatMapTooltip';
21
22
  use([
22
- EChartsHeatmapChart
23
+ CustomChart
23
24
  ]);
24
25
  // The default coloring is a blue->yellow->red gradient
25
26
  const DEFAULT_VISUAL_MAP_COLORS = [
@@ -35,7 +36,7 @@ const DEFAULT_VISUAL_MAP_COLORS = [
35
36
  '#d73027',
36
37
  '#a50026'
37
38
  ];
38
- export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCategories, yAxisFormat, countFormat, countMin, countMax, timeScale, showVisualMap }) {
39
+ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisFormat, countFormat, countMin, countMax, timeScale, showVisualMap, min, max, logBase }) {
39
40
  const chartsTheme = useChartsTheme();
40
41
  const theme = useTheme();
41
42
  const { timeZone } = useTimeZone();
@@ -49,7 +50,6 @@ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCatego
49
50
  label: params.data.label,
50
51
  marker: params.marker,
51
52
  xAxisCategories,
52
- yAxisCategories,
53
53
  theme,
54
54
  yAxisFormat: yAxisFormat,
55
55
  countFormat: countFormat
@@ -64,10 +64,27 @@ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCatego
64
64
  formatter: getFormattedHeatmapAxisLabel(timeScale?.rangeMs ?? 0, timeZone)
65
65
  }
66
66
  },
67
- yAxis: getFormattedAxis({
68
- type: 'category',
69
- data: yAxisCategories
70
- }, yAxisFormat),
67
+ yAxis: {
68
+ type: logBase !== undefined ? 'log' : 'value',
69
+ logBase: logBase,
70
+ boundaryGap: [
71
+ 0,
72
+ '10%'
73
+ ],
74
+ min: min,
75
+ max: max,
76
+ axisLabel: {
77
+ hideOverlap: true,
78
+ formatter: (value)=>{
79
+ // On log scales, ECharts may generate a tick at 0 which is mathematically
80
+ // invalid (log(0) is undefined). Return empty string to hide such labels.
81
+ if (logBase !== undefined && value === 0) {
82
+ return '';
83
+ }
84
+ return formatValue(value, yAxisFormat);
85
+ }
86
+ }
87
+ },
71
88
  visualMap: {
72
89
  show: showVisualMap ?? false,
73
90
  type: 'continuous',
@@ -86,19 +103,77 @@ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCatego
86
103
  color: theme.palette.text.primary,
87
104
  textBorderColor: theme.palette.background.default,
88
105
  textBorderWidth: 5
89
- }
106
+ },
107
+ // Color by the count dimension (index 3)
108
+ dimension: 3
90
109
  },
91
110
  series: [
92
111
  {
93
- name: 'Gaussian',
94
- type: 'heatmap',
95
- data: data,
96
- emphasis: {
97
- itemStyle: {
98
- borderColor: '#333',
99
- borderWidth: 1
112
+ name: 'HeatMap',
113
+ type: 'custom',
114
+ renderItem: function(params, api) {
115
+ const xIndex = api.value(0);
116
+ const yLower = api.value(1);
117
+ const yUpper = api.value(2);
118
+ // Pixel coordinates
119
+ const upperStart = api.coord([
120
+ xIndex,
121
+ yUpper
122
+ ]);
123
+ const lowerStart = api.coord([
124
+ xIndex,
125
+ yLower
126
+ ]);
127
+ const upperNext = api.coord([
128
+ xIndex + 1,
129
+ yUpper
130
+ ]);
131
+ const startX = upperStart?.[0];
132
+ const upperY = upperStart?.[1];
133
+ const lowerY = lowerStart?.[1];
134
+ const nextX = upperNext?.[0];
135
+ if (startX === undefined || upperY === undefined || lowerY === undefined || nextX === undefined) {
136
+ return null;
100
137
  }
138
+ const topY = Math.min(upperY, lowerY);
139
+ const bottomY = Math.max(upperY, lowerY);
140
+ const width = nextX - startX;
141
+ const height = bottomY - topY;
142
+ return {
143
+ type: 'rect',
144
+ shape: {
145
+ x: startX,
146
+ y: topY,
147
+ width,
148
+ height
149
+ },
150
+ style: {
151
+ fill: api.visual('color')
152
+ }
153
+ };
101
154
  },
155
+ label: {
156
+ show: false
157
+ },
158
+ dimensions: [
159
+ 'xIndex',
160
+ 'yLower',
161
+ 'yUpper',
162
+ 'count'
163
+ ],
164
+ encode: {
165
+ x: 0,
166
+ y: [
167
+ 1,
168
+ 2
169
+ ],
170
+ tooltip: [
171
+ 1,
172
+ 2,
173
+ 3
174
+ ]
175
+ },
176
+ data: data,
102
177
  progressive: 1000,
103
178
  animation: false
104
179
  }
@@ -108,7 +183,6 @@ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCatego
108
183
  xAxisCategories,
109
184
  timeScale?.rangeMs,
110
185
  timeZone,
111
- yAxisCategories,
112
186
  yAxisFormat,
113
187
  showVisualMap,
114
188
  countMin,
@@ -116,7 +190,10 @@ export function HeatMapChart({ width, height, data, xAxisCategories, yAxisCatego
116
190
  height,
117
191
  theme,
118
192
  data,
119
- countFormat
193
+ countFormat,
194
+ min,
195
+ max,
196
+ logBase
120
197
  ]);
121
198
  const chart = useMemo(()=>/*#__PURE__*/ _jsx(EChart, {
122
199
  style: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/HeatMapChart.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { FormatOptions, TimeScale } from '@perses-dev/core';\nimport { EChart, getFormattedAxis, useChartsTheme, useTimeZone } from '@perses-dev/components';\nimport { use, EChartsCoreOption } from 'echarts/core';\nimport { HeatmapChart as EChartsHeatmapChart } from 'echarts/charts';\nimport { useTheme } from '@mui/material';\nimport { getFormattedHeatmapAxisLabel } from '../utils';\nimport { generateTooltipHTML } from './HeatMapTooltip';\n\nuse([EChartsHeatmapChart]);\n\n// The default coloring is a blue->yellow->red gradient\nconst DEFAULT_VISUAL_MAP_COLORS = [\n '#313695',\n '#4575b4',\n '#74add1',\n '#abd9e9',\n '#e0f3f8',\n '#ffffbf',\n '#fee090',\n '#fdae61',\n '#f46d43',\n '#d73027',\n '#a50026',\n];\n\nexport type HeatMapData = [number, number, number | undefined]; // [x, y, value]\n\nexport interface HeatMapDataItem {\n value: HeatMapData;\n label: string;\n itemStyle?: {\n color?: string;\n borderColor?: string;\n borderWidth?: number;\n };\n}\n\nexport interface HeatMapChartProps {\n width: number;\n height: number;\n data: HeatMapDataItem[];\n xAxisCategories: number[];\n yAxisCategories: string[];\n yAxisFormat?: FormatOptions;\n countFormat?: FormatOptions;\n countMin?: number;\n countMax?: number;\n timeScale?: TimeScale;\n showVisualMap?: boolean;\n // TODO: exponential?: boolean;\n}\n\nexport function HeatMapChart({\n width,\n height,\n data,\n xAxisCategories,\n yAxisCategories,\n yAxisFormat,\n countFormat,\n countMin,\n countMax,\n timeScale,\n showVisualMap,\n}: HeatMapChartProps): ReactElement | null {\n const chartsTheme = useChartsTheme();\n const theme = useTheme();\n const { timeZone } = useTimeZone();\n\n const option: EChartsCoreOption = useMemo(() => {\n return {\n tooltip: {\n appendToBody: true,\n formatter: (params: { data: HeatMapDataItem; marker: string }) => {\n return generateTooltipHTML({\n data: params.data.value,\n label: params.data.label,\n marker: params.marker,\n xAxisCategories,\n yAxisCategories,\n theme,\n yAxisFormat: yAxisFormat,\n countFormat: countFormat,\n });\n },\n },\n xAxis: {\n type: 'category',\n data: xAxisCategories,\n axisLabel: {\n hideOverlap: true,\n formatter: getFormattedHeatmapAxisLabel(timeScale?.rangeMs ?? 0, timeZone),\n },\n },\n yAxis: getFormattedAxis(\n {\n type: 'category',\n data: yAxisCategories,\n },\n yAxisFormat\n ),\n visualMap: {\n show: showVisualMap ?? false,\n type: 'continuous',\n min: countMin,\n max: countMax,\n realtime: false,\n itemHeight: height - 30,\n itemWidth: 10,\n orient: 'vertical',\n left: 'right',\n top: 'center',\n inRange: {\n color: DEFAULT_VISUAL_MAP_COLORS,\n },\n textStyle: {\n color: theme.palette.text.primary,\n textBorderColor: theme.palette.background.default,\n textBorderWidth: 5,\n },\n },\n series: [\n {\n name: 'Gaussian',\n type: 'heatmap',\n data: data,\n emphasis: {\n itemStyle: {\n borderColor: '#333',\n borderWidth: 1,\n },\n },\n progressive: 1000,\n animation: false,\n },\n ],\n };\n }, [\n xAxisCategories,\n timeScale?.rangeMs,\n timeZone,\n yAxisCategories,\n yAxisFormat,\n showVisualMap,\n countMin,\n countMax,\n height,\n theme,\n data,\n countFormat,\n ]);\n\n const chart = useMemo(\n () => (\n <EChart\n style={{\n width: width,\n height: height,\n }}\n sx={{\n padding: `${chartsTheme.container.padding.default}px`,\n }}\n option={option}\n theme={chartsTheme.echartsTheme}\n />\n ),\n [chartsTheme.container.padding.default, chartsTheme.echartsTheme, height, option, width]\n );\n\n return <>{chart}</>;\n}\n"],"names":["useMemo","EChart","getFormattedAxis","useChartsTheme","useTimeZone","use","HeatmapChart","EChartsHeatmapChart","useTheme","getFormattedHeatmapAxisLabel","generateTooltipHTML","DEFAULT_VISUAL_MAP_COLORS","HeatMapChart","width","height","data","xAxisCategories","yAxisCategories","yAxisFormat","countFormat","countMin","countMax","timeScale","showVisualMap","chartsTheme","theme","timeZone","option","tooltip","appendToBody","formatter","params","value","label","marker","xAxis","type","axisLabel","hideOverlap","rangeMs","yAxis","visualMap","show","min","max","realtime","itemHeight","itemWidth","orient","left","top","inRange","color","textStyle","palette","text","primary","textBorderColor","background","default","textBorderWidth","series","name","emphasis","itemStyle","borderColor","borderWidth","progressive","animation","chart","style","sx","padding","container","echartsTheme"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/HeatMapChart.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { formatValue, FormatOptions, TimeScale } from '@perses-dev/core';\nimport { EChart, useChartsTheme, useTimeZone } from '@perses-dev/components';\nimport { use, EChartsCoreOption } from 'echarts/core';\nimport { CustomChart } from 'echarts/charts';\nimport type { CustomSeriesRenderItemAPI, CustomSeriesRenderItemParams } from 'echarts';\nimport { useTheme } from '@mui/material';\nimport { LOG_BASE } from '../heat-map-chart-model';\nimport { getFormattedHeatmapAxisLabel } from '../utils';\nimport { generateTooltipHTML } from './HeatMapTooltip';\n\nuse([CustomChart]);\n\n// The default coloring is a blue->yellow->red gradient\nconst DEFAULT_VISUAL_MAP_COLORS = [\n '#313695',\n '#4575b4',\n '#74add1',\n '#abd9e9',\n '#e0f3f8',\n '#ffffbf',\n '#fee090',\n '#fdae61',\n '#f46d43',\n '#d73027',\n '#a50026',\n];\n\nexport type HeatMapData = [number, number, number, number | undefined]; // [xIndex, yLower, yUpper, count]\n\nexport interface HeatMapDataItem {\n value: HeatMapData;\n label: string;\n itemStyle?: {\n color?: string;\n borderColor?: string;\n borderWidth?: number;\n };\n}\n\nexport interface HeatMapChartProps {\n width: number;\n height: number;\n data: HeatMapDataItem[];\n xAxisCategories: number[];\n yAxisFormat?: FormatOptions;\n countFormat?: FormatOptions;\n countMin?: number;\n countMax?: number;\n timeScale?: TimeScale;\n showVisualMap?: boolean;\n min?: number;\n max?: number;\n logBase?: LOG_BASE;\n}\n\nexport function HeatMapChart({\n width,\n height,\n data,\n xAxisCategories,\n yAxisFormat,\n countFormat,\n countMin,\n countMax,\n timeScale,\n showVisualMap,\n min,\n max,\n logBase,\n}: HeatMapChartProps): ReactElement | null {\n const chartsTheme = useChartsTheme();\n const theme = useTheme();\n const { timeZone } = useTimeZone();\n\n const option: EChartsCoreOption = useMemo(() => {\n return {\n tooltip: {\n appendToBody: true,\n formatter: (params: { data: HeatMapDataItem; marker: string }) => {\n return generateTooltipHTML({\n data: params.data.value,\n label: params.data.label,\n marker: params.marker,\n xAxisCategories,\n theme,\n yAxisFormat: yAxisFormat,\n countFormat: countFormat,\n });\n },\n },\n xAxis: {\n type: 'category',\n data: xAxisCategories,\n axisLabel: {\n hideOverlap: true,\n formatter: getFormattedHeatmapAxisLabel(timeScale?.rangeMs ?? 0, timeZone),\n },\n },\n yAxis: {\n type: logBase !== undefined ? 'log' : 'value',\n logBase: logBase,\n boundaryGap: [0, '10%'],\n min: min,\n max: max,\n axisLabel: {\n hideOverlap: true,\n formatter: (value: number): string => {\n // On log scales, ECharts may generate a tick at 0 which is mathematically\n // invalid (log(0) is undefined). Return empty string to hide such labels.\n if (logBase !== undefined && value === 0) {\n return '';\n }\n return formatValue(value, yAxisFormat);\n },\n },\n },\n visualMap: {\n show: showVisualMap ?? false,\n type: 'continuous',\n min: countMin,\n max: countMax,\n realtime: false,\n itemHeight: height - 30,\n itemWidth: 10,\n orient: 'vertical',\n left: 'right',\n top: 'center',\n inRange: {\n color: DEFAULT_VISUAL_MAP_COLORS,\n },\n textStyle: {\n color: theme.palette.text.primary,\n textBorderColor: theme.palette.background.default,\n textBorderWidth: 5,\n },\n // Color by the count dimension (index 3)\n dimension: 3,\n },\n series: [\n {\n name: 'HeatMap',\n type: 'custom',\n renderItem: function (params: CustomSeriesRenderItemParams, api: CustomSeriesRenderItemAPI) {\n const xIndex = api.value(0) as number;\n const yLower = api.value(1) as number;\n const yUpper = api.value(2) as number;\n\n // Pixel coordinates\n const upperStart = api.coord([xIndex, yUpper]);\n const lowerStart = api.coord([xIndex, yLower]);\n const upperNext = api.coord([xIndex + 1, yUpper]);\n\n const startX = upperStart?.[0];\n const upperY = upperStart?.[1];\n const lowerY = lowerStart?.[1];\n const nextX = upperNext?.[0];\n\n if (startX === undefined || upperY === undefined || lowerY === undefined || nextX === undefined) {\n return null;\n }\n\n const topY = Math.min(upperY, lowerY);\n const bottomY = Math.max(upperY, lowerY);\n const width = nextX - startX;\n const height = bottomY - topY;\n\n return {\n type: 'rect',\n shape: { x: startX, y: topY, width, height },\n style: {\n fill: api.visual('color'),\n },\n };\n },\n label: { show: false },\n dimensions: ['xIndex', 'yLower', 'yUpper', 'count'],\n encode: { x: 0, y: [1, 2], tooltip: [1, 2, 3] },\n data: data,\n progressive: 1000,\n animation: false,\n },\n ],\n };\n }, [\n xAxisCategories,\n timeScale?.rangeMs,\n timeZone,\n yAxisFormat,\n showVisualMap,\n countMin,\n countMax,\n height,\n theme,\n data,\n countFormat,\n min,\n max,\n logBase,\n ]);\n\n const chart = useMemo(\n () => (\n <EChart\n style={{\n width: width,\n height: height,\n }}\n sx={{\n padding: `${chartsTheme.container.padding.default}px`,\n }}\n option={option}\n theme={chartsTheme.echartsTheme}\n />\n ),\n [chartsTheme.container.padding.default, chartsTheme.echartsTheme, height, option, width]\n );\n\n return <>{chart}</>;\n}\n"],"names":["useMemo","formatValue","EChart","useChartsTheme","useTimeZone","use","CustomChart","useTheme","getFormattedHeatmapAxisLabel","generateTooltipHTML","DEFAULT_VISUAL_MAP_COLORS","HeatMapChart","width","height","data","xAxisCategories","yAxisFormat","countFormat","countMin","countMax","timeScale","showVisualMap","min","max","logBase","chartsTheme","theme","timeZone","option","tooltip","appendToBody","formatter","params","value","label","marker","xAxis","type","axisLabel","hideOverlap","rangeMs","yAxis","undefined","boundaryGap","visualMap","show","realtime","itemHeight","itemWidth","orient","left","top","inRange","color","textStyle","palette","text","primary","textBorderColor","background","default","textBorderWidth","dimension","series","name","renderItem","api","xIndex","yLower","yUpper","upperStart","coord","lowerStart","upperNext","startX","upperY","lowerY","nextX","topY","Math","bottomY","shape","x","y","style","fill","visual","dimensions","encode","progressive","animation","chart","sx","padding","container","echartsTheme"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HeatMapChartOptionsEditorSettings.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChartOptionsEditorSettings.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAuC,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAE9G,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,8BAA8B,GAAG,YAAY,CAiDrG"}
1
+ {"version":3,"file":"HeatMapChartOptionsEditorSettings.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChartOptionsEditorSettings.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAGL,8BAA8B,EAG/B,MAAM,yBAAyB,CAAC;AAEjC,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,8BAA8B,GAAG,YAAY,CA4GrG"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // Copyright 2025 The Perses Authors
2
+ // Copyright The Perses Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
5
5
  // You may obtain a copy of the License at
@@ -11,11 +11,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { Switch } from '@mui/material';
15
- import { FormatControls, OptionsEditorColumn, OptionsEditorControl, OptionsEditorGrid, OptionsEditorGroup } from '@perses-dev/components';
14
+ import { Switch, TextField } from '@mui/material';
15
+ import { FormatControls, OptionsEditorColumn, OptionsEditorControl, OptionsEditorGrid, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';
16
16
  import { produce } from 'immer';
17
17
  import merge from 'lodash/merge';
18
- import { DEFAULT_FORMAT } from '../heat-map-chart-model';
18
+ import { DEFAULT_FORMAT, LOG_BASE_CONFIG, LOG_BASE_OPTIONS } from '../heat-map-chart-model';
19
19
  export function HeatMapChartOptionsEditorSettings(props) {
20
20
  const { onChange, value } = props;
21
21
  const handleYAxisFormatChange = (newFormat)=>{
@@ -36,6 +36,9 @@ export function HeatMapChartOptionsEditorSettings(props) {
36
36
  // ensures decimalPlaces defaults to correct value
37
37
  const yAxisFormat = merge({}, DEFAULT_FORMAT, value.yAxisFormat);
38
38
  const countFormat = merge({}, DEFAULT_FORMAT, value.countFormat);
39
+ // Get the current log base configuration, defaulting to 'none' if not set
40
+ const logBaseKey = value.logBase ? String(value.logBase) : 'none';
41
+ const logBase = LOG_BASE_CONFIG[logBaseKey] ?? LOG_BASE_CONFIG['none'];
39
42
  return /*#__PURE__*/ _jsxs(OptionsEditorGrid, {
40
43
  children: [
41
44
  /*#__PURE__*/ _jsx(OptionsEditorColumn, {
@@ -57,12 +60,64 @@ export function HeatMapChartOptionsEditorSettings(props) {
57
60
  })
58
61
  }),
59
62
  /*#__PURE__*/ _jsx(OptionsEditorColumn, {
60
- children: /*#__PURE__*/ _jsx(OptionsEditorGroup, {
63
+ children: /*#__PURE__*/ _jsxs(OptionsEditorGroup, {
61
64
  title: "Y Axis",
62
- children: /*#__PURE__*/ _jsx(FormatControls, {
63
- value: yAxisFormat,
64
- onChange: handleYAxisFormatChange
65
- })
65
+ children: [
66
+ /*#__PURE__*/ _jsx(FormatControls, {
67
+ value: yAxisFormat,
68
+ onChange: handleYAxisFormatChange
69
+ }),
70
+ /*#__PURE__*/ _jsx(OptionsEditorControl, {
71
+ label: "Min",
72
+ control: /*#__PURE__*/ _jsx(TextField, {
73
+ type: "number",
74
+ value: value.min ?? '',
75
+ onChange: (e)=>{
76
+ const newValue = e.target.value ? Number(e.target.value) : undefined;
77
+ onChange(produce(value, (draft)=>{
78
+ draft.min = newValue;
79
+ }));
80
+ },
81
+ placeholder: "Auto",
82
+ sx: {
83
+ width: '100%'
84
+ }
85
+ })
86
+ }),
87
+ /*#__PURE__*/ _jsx(OptionsEditorControl, {
88
+ label: "Max",
89
+ control: /*#__PURE__*/ _jsx(TextField, {
90
+ type: "number",
91
+ value: value.max ?? '',
92
+ onChange: (e)=>{
93
+ const newValue = e.target.value ? Number(e.target.value) : undefined;
94
+ onChange(produce(value, (draft)=>{
95
+ draft.max = newValue;
96
+ }));
97
+ },
98
+ placeholder: "Auto",
99
+ sx: {
100
+ width: '100%'
101
+ }
102
+ })
103
+ }),
104
+ /*#__PURE__*/ _jsx(OptionsEditorControl, {
105
+ label: "Log Base",
106
+ control: /*#__PURE__*/ _jsx(SettingsAutocomplete, {
107
+ value: {
108
+ ...logBase,
109
+ id: logBase?.label ?? 'None'
110
+ },
111
+ options: LOG_BASE_OPTIONS,
112
+ onChange: (__, newValue)=>{
113
+ onChange(produce(value, (draft)=>{
114
+ draft.logBase = newValue.log;
115
+ }));
116
+ },
117
+ disableClearable: true
118
+ })
119
+ })
120
+ ]
66
121
  })
67
122
  })
68
123
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/HeatMapChartOptionsEditorSettings.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Switch, SwitchProps } from '@mui/material';\nimport {\n FormatControls,\n FormatControlsProps,\n OptionsEditorColumn,\n OptionsEditorControl,\n OptionsEditorGrid,\n OptionsEditorGroup,\n} from '@perses-dev/components';\nimport { produce } from 'immer';\nimport merge from 'lodash/merge';\nimport { ReactElement } from 'react';\nimport { DEFAULT_FORMAT, HeatMapChartOptions, HeatMapChartOptionsEditorProps } from '../heat-map-chart-model';\n\nexport function HeatMapChartOptionsEditorSettings(props: HeatMapChartOptionsEditorProps): ReactElement {\n const { onChange, value } = props;\n\n const handleYAxisFormatChange: FormatControlsProps['onChange'] = (newFormat) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.yAxisFormat = newFormat;\n })\n );\n };\n\n const handleCountFormatChange: FormatControlsProps['onChange'] = (newFormat) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.countFormat = newFormat;\n })\n );\n };\n\n const handleShowVisualMapChange: SwitchProps['onChange'] = (_: unknown, checked: boolean) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.showVisualMap = checked;\n })\n );\n };\n\n // ensures decimalPlaces defaults to correct value\n const yAxisFormat = merge({}, DEFAULT_FORMAT, value.yAxisFormat);\n const countFormat = merge({}, DEFAULT_FORMAT, value.countFormat);\n\n return (\n <OptionsEditorGrid>\n <OptionsEditorColumn>\n <OptionsEditorGroup title=\"Bucket Count\">\n <FormatControls value={countFormat} onChange={handleCountFormatChange} />\n <OptionsEditorControl\n label=\"Show Visual Map\"\n control={<Switch checked={!!value.showVisualMap} onChange={handleShowVisualMapChange} />}\n />\n </OptionsEditorGroup>\n </OptionsEditorColumn>\n <OptionsEditorColumn>\n <OptionsEditorGroup title=\"Y Axis\">\n <FormatControls value={yAxisFormat} onChange={handleYAxisFormatChange} />\n </OptionsEditorGroup>\n </OptionsEditorColumn>\n </OptionsEditorGrid>\n );\n}\n"],"names":["Switch","FormatControls","OptionsEditorColumn","OptionsEditorControl","OptionsEditorGrid","OptionsEditorGroup","produce","merge","DEFAULT_FORMAT","HeatMapChartOptionsEditorSettings","props","onChange","value","handleYAxisFormatChange","newFormat","draft","yAxisFormat","handleCountFormatChange","countFormat","handleShowVisualMapChange","_","checked","showVisualMap","title","label","control"],"mappings":";AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,MAAM,QAAqB,gBAAgB;AACpD,SACEC,cAAc,EAEdC,mBAAmB,EACnBC,oBAAoB,EACpBC,iBAAiB,EACjBC,kBAAkB,QACb,yBAAyB;AAChC,SAASC,OAAO,QAAQ,QAAQ;AAChC,OAAOC,WAAW,eAAe;AAEjC,SAASC,cAAc,QAA6D,0BAA0B;AAE9G,OAAO,SAASC,kCAAkCC,KAAqC;IACrF,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAE,GAAGF;IAE5B,MAAMG,0BAA2D,CAACC;QAChEH,SACEL,QAAQM,OAAO,CAACG;YACdA,MAAMC,WAAW,GAAGF;QACtB;IAEJ;IAEA,MAAMG,0BAA2D,CAACH;QAChEH,SACEL,QAAQM,OAAO,CAACG;YACdA,MAAMG,WAAW,GAAGJ;QACtB;IAEJ;IAEA,MAAMK,4BAAqD,CAACC,GAAYC;QACtEV,SACEL,QAAQM,OAAO,CAACG;YACdA,MAAMO,aAAa,GAAGD;QACxB;IAEJ;IAEA,kDAAkD;IAClD,MAAML,cAAcT,MAAM,CAAC,GAAGC,gBAAgBI,MAAMI,WAAW;IAC/D,MAAME,cAAcX,MAAM,CAAC,GAAGC,gBAAgBI,MAAMM,WAAW;IAE/D,qBACE,MAACd;;0BACC,KAACF;0BACC,cAAA,MAACG;oBAAmBkB,OAAM;;sCACxB,KAACtB;4BAAeW,OAAOM;4BAAaP,UAAUM;;sCAC9C,KAACd;4BACCqB,OAAM;4BACNC,uBAAS,KAACzB;gCAAOqB,SAAS,CAAC,CAACT,MAAMU,aAAa;gCAAEX,UAAUQ;;;;;;0BAIjE,KAACjB;0BACC,cAAA,KAACG;oBAAmBkB,OAAM;8BACxB,cAAA,KAACtB;wBAAeW,OAAOI;wBAAaL,UAAUE;;;;;;AAKxD"}
1
+ {"version":3,"sources":["../../../src/components/HeatMapChartOptionsEditorSettings.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Switch, SwitchProps, TextField } from '@mui/material';\nimport {\n FormatControls,\n FormatControlsProps,\n OptionsEditorColumn,\n OptionsEditorControl,\n OptionsEditorGrid,\n OptionsEditorGroup,\n SettingsAutocomplete,\n} from '@perses-dev/components';\nimport { produce } from 'immer';\nimport merge from 'lodash/merge';\nimport { ReactElement } from 'react';\nimport {\n DEFAULT_FORMAT,\n HeatMapChartOptions,\n HeatMapChartOptionsEditorProps,\n LOG_BASE_CONFIG,\n LOG_BASE_OPTIONS,\n} from '../heat-map-chart-model';\n\nexport function HeatMapChartOptionsEditorSettings(props: HeatMapChartOptionsEditorProps): ReactElement {\n const { onChange, value } = props;\n\n const handleYAxisFormatChange: FormatControlsProps['onChange'] = (newFormat) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.yAxisFormat = newFormat;\n })\n );\n };\n\n const handleCountFormatChange: FormatControlsProps['onChange'] = (newFormat) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.countFormat = newFormat;\n })\n );\n };\n\n const handleShowVisualMapChange: SwitchProps['onChange'] = (_: unknown, checked: boolean) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.showVisualMap = checked;\n })\n );\n };\n\n // ensures decimalPlaces defaults to correct value\n const yAxisFormat = merge({}, DEFAULT_FORMAT, value.yAxisFormat);\n const countFormat = merge({}, DEFAULT_FORMAT, value.countFormat);\n\n // Get the current log base configuration, defaulting to 'none' if not set\n const logBaseKey = value.logBase ? String(value.logBase) : 'none';\n const logBase = LOG_BASE_CONFIG[logBaseKey] ?? LOG_BASE_CONFIG['none'];\n\n return (\n <OptionsEditorGrid>\n <OptionsEditorColumn>\n <OptionsEditorGroup title=\"Bucket Count\">\n <FormatControls value={countFormat} onChange={handleCountFormatChange} />\n <OptionsEditorControl\n label=\"Show Visual Map\"\n control={<Switch checked={!!value.showVisualMap} onChange={handleShowVisualMapChange} />}\n />\n </OptionsEditorGroup>\n </OptionsEditorColumn>\n <OptionsEditorColumn>\n <OptionsEditorGroup title=\"Y Axis\">\n <FormatControls value={yAxisFormat} onChange={handleYAxisFormatChange} />\n <OptionsEditorControl\n label=\"Min\"\n control={\n <TextField\n type=\"number\"\n value={value.min ?? ''}\n onChange={(e) => {\n const newValue = e.target.value ? Number(e.target.value) : undefined;\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.min = newValue;\n })\n );\n }}\n placeholder=\"Auto\"\n sx={{ width: '100%' }}\n />\n }\n />\n <OptionsEditorControl\n label=\"Max\"\n control={\n <TextField\n type=\"number\"\n value={value.max ?? ''}\n onChange={(e) => {\n const newValue = e.target.value ? Number(e.target.value) : undefined;\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.max = newValue;\n })\n );\n }}\n placeholder=\"Auto\"\n sx={{ width: '100%' }}\n />\n }\n />\n <OptionsEditorControl\n label=\"Log Base\"\n control={\n <SettingsAutocomplete\n value={{ ...logBase, id: logBase?.label ?? 'None' }}\n options={LOG_BASE_OPTIONS}\n onChange={(__, newValue) => {\n onChange(\n produce(value, (draft: HeatMapChartOptions) => {\n draft.logBase = newValue.log;\n })\n );\n }}\n disableClearable\n />\n }\n />\n </OptionsEditorGroup>\n </OptionsEditorColumn>\n </OptionsEditorGrid>\n );\n}\n"],"names":["Switch","TextField","FormatControls","OptionsEditorColumn","OptionsEditorControl","OptionsEditorGrid","OptionsEditorGroup","SettingsAutocomplete","produce","merge","DEFAULT_FORMAT","LOG_BASE_CONFIG","LOG_BASE_OPTIONS","HeatMapChartOptionsEditorSettings","props","onChange","value","handleYAxisFormatChange","newFormat","draft","yAxisFormat","handleCountFormatChange","countFormat","handleShowVisualMapChange","_","checked","showVisualMap","logBaseKey","logBase","String","title","label","control","type","min","e","newValue","target","Number","undefined","placeholder","sx","width","max","id","options","__","log","disableClearable"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HeatMapChartPanel.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChartPanel.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAyB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAkB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAO9E,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;AAErF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,GAAG,IAAI,CAmKpF"}
1
+ {"version":3,"file":"HeatMapChartPanel.d.ts","sourceRoot":"","sources":["../../../src/components/HeatMapChartPanel.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAyB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAkB,mBAAmB,EAAY,MAAM,yBAAyB,CAAC;AAiBxF,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;AAErF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,GAAG,IAAI,CA0MpF"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // Copyright 2025 The Perses Authors
2
+ // Copyright The Perses Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
5
5
  // You may obtain a copy of the License at
@@ -17,19 +17,29 @@ import { useMemo } from 'react';
17
17
  import { DEFAULT_FORMAT } from '../heat-map-chart-model';
18
18
  import { generateCompleteTimestamps, getCommonTimeScaleForQueries } from '../utils';
19
19
  import { HeatMapChart } from './HeatMapChart';
20
- const HEATMAP_MIN_HEIGHT = 200;
21
- const HEATMAP_ITEM_MIN_HEIGHT = 2;
20
+ /**
21
+ * Helper function to get the effective lower bound for log scale.
22
+ * For values <= 0, we use a small fraction of the upper bound.
23
+ */ const getEffectiveLowerBound = (lowerBound, upperBound, logBase)=>{
24
+ if (logBase === undefined || lowerBound > 0) {
25
+ return lowerBound;
26
+ }
27
+ // For log scales with non-positive lower bounds, use a small fraction of upper bound
28
+ // This ensures the bucket is still visible on the log scale
29
+ return upperBound * 0.001;
30
+ };
22
31
  export function HeatMapChartPanel(props) {
23
32
  const { spec: pluginSpec, contentDimensions, queryResults } = props;
24
33
  // ensures all default format properties set if undef
25
34
  const yAxisFormat = merge({}, DEFAULT_FORMAT, pluginSpec.yAxisFormat);
26
35
  const countFormat = merge({}, DEFAULT_FORMAT, pluginSpec.countFormat);
27
- const { data, xAxisCategories, yAxisCategories, countMin, countMax, timeScale } = useMemo(()=>{
36
+ const { data, xAxisCategories, min, max, countMin, countMax, timeScale } = useMemo(()=>{
28
37
  if (!queryResults || queryResults.length === 0) {
29
38
  return {
30
39
  data: [],
31
40
  xAxisCategories: [],
32
- yAxisCategories: [],
41
+ min: 0,
42
+ max: 0,
33
43
  countMin: 0,
34
44
  countMax: 0,
35
45
  timeScale: undefined
@@ -39,7 +49,8 @@ export function HeatMapChartPanel(props) {
39
49
  return {
40
50
  data: [],
41
51
  xAxisCategories: [],
42
- yAxisCategories: [],
52
+ min: 0,
53
+ max: 0,
43
54
  countMin: 0,
44
55
  countMax: 0,
45
56
  timeScale: undefined
@@ -48,19 +59,26 @@ export function HeatMapChartPanel(props) {
48
59
  const series = queryResults[0].data.series[0];
49
60
  const timeScale = getCommonTimeScaleForQueries(queryResults);
50
61
  const xAxisCategories = generateCompleteTimestamps(timeScale);
62
+ const logBase = pluginSpec.logBase;
51
63
  // Dummy value that will be replaced at the first iteration
52
64
  let lowestBound = Infinity;
53
65
  let highestBound = -Infinity;
54
66
  let countMin = Infinity;
55
67
  let countMax = -Infinity;
56
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
57
- for (const [_, histogram] of series?.histograms ?? []){
68
+ for (const [, histogram] of series?.histograms ?? []){
58
69
  for (const bucket of histogram?.buckets ?? []){
59
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
60
- const [_, lowerBound, upperBound, count] = bucket;
61
- const lowerBoundFloat = parseFloat(lowerBound);
70
+ const [, lowerBound, upperBound, count] = bucket;
71
+ let lowerBoundFloat = parseFloat(lowerBound);
62
72
  const upperBoundFloat = parseFloat(upperBound);
63
73
  const countFloat = parseFloat(count);
74
+ // For logarithmic scales, skip buckets that would be entirely non-positive
75
+ if (logBase !== undefined && upperBoundFloat <= 0) {
76
+ continue;
77
+ }
78
+ // For log scales, adjust non-positive lower bounds
79
+ if (logBase !== undefined) {
80
+ lowerBoundFloat = getEffectiveLowerBound(lowerBoundFloat, upperBoundFloat, logBase);
81
+ }
64
82
  if (lowerBoundFloat < lowestBound) {
65
83
  lowestBound = lowerBoundFloat;
66
84
  }
@@ -75,48 +93,77 @@ export function HeatMapChartPanel(props) {
75
93
  }
76
94
  }
77
95
  }
78
- const height = contentDimensions?.height ?? HEATMAP_MIN_HEIGHT;
79
- const totalRange = highestBound - lowestBound;
80
- const rangePerItem = totalRange * HEATMAP_ITEM_MIN_HEIGHT / height;
81
- const totalItems = Math.ceil(height / HEATMAP_ITEM_MIN_HEIGHT);
82
- // Generating value of the Y axis based on the height divided by the size of a cell (item)
83
- const yAxisCategories = Array.from({
84
- length: totalItems
85
- }, (_, index)=>(lowestBound + index * rangePerItem).toFixed(3));
86
96
  const data = [];
87
- // Logic for filling all cells where a bucket is present
97
+ // Each bucket becomes a rectangle spanning [lowerBound, upperBound] at the given x index
88
98
  for (const [time, histogram] of series?.histograms ?? []){
89
99
  const itemIndexOnXaxis = xAxisCategories.findIndex((v)=>v === time * 1000);
90
100
  for (const bucket of histogram?.buckets ?? []){
91
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
92
- const [_, lowerBound, upperBound, count] = bucket;
93
- const yLowerBoundItem = Math.floor((parseFloat(lowerBound) - lowestBound) / rangePerItem);
94
- const yUpperBoundItem = Math.ceil((parseFloat(upperBound) - lowestBound) / rangePerItem);
95
- for(let i = 0; i < yUpperBoundItem - yLowerBoundItem; i++){
96
- // TODO: some bucket may have overlapping cells, we could use avg value. Probably will need to move to a matrix data structure for performance reasons
97
- data.push({
98
- value: [
99
- itemIndexOnXaxis,
100
- yLowerBoundItem + i,
101
- parseFloat(count)
102
- ],
103
- label: count
104
- });
101
+ const [, lowerBound, upperBound, count] = bucket;
102
+ let lowerBoundFloat = parseFloat(lowerBound);
103
+ const upperBoundFloat = parseFloat(upperBound);
104
+ // For logarithmic scales, skip buckets that would be entirely non-positive
105
+ if (logBase !== undefined && upperBoundFloat <= 0) {
106
+ continue;
105
107
  }
108
+ // For log scales, adjust non-positive lower bounds
109
+ if (logBase !== undefined) {
110
+ lowerBoundFloat = getEffectiveLowerBound(lowerBoundFloat, upperBoundFloat, logBase);
111
+ }
112
+ data.push({
113
+ value: [
114
+ itemIndexOnXaxis,
115
+ lowerBoundFloat,
116
+ upperBoundFloat,
117
+ parseFloat(count)
118
+ ],
119
+ label: count
120
+ });
106
121
  }
107
122
  }
108
123
  return {
109
124
  data,
110
125
  xAxisCategories,
111
- yAxisCategories,
126
+ min: lowestBound === Infinity ? undefined : lowestBound,
127
+ max: highestBound === -Infinity ? undefined : highestBound,
112
128
  countMin,
113
129
  countMax,
114
130
  timeScale
115
131
  };
116
132
  }, [
117
- contentDimensions?.height,
133
+ pluginSpec.logBase,
118
134
  queryResults
119
135
  ]);
136
+ // Use configured min/max if provided, otherwise use calculated values
137
+ // For logarithmic scales, ignore user-provided min if it's <= 0 (log of non-positive is undefined)
138
+ // and let ECharts auto-calculate the range to avoid rendering issues
139
+ const finalMin = useMemo(()=>{
140
+ if (pluginSpec.logBase !== undefined) {
141
+ // For log scale, ignore min if it's <= 0 or let ECharts auto-calculate
142
+ if (pluginSpec.min !== undefined && pluginSpec.min <= 0) {
143
+ return undefined; // Let ECharts auto-calculate
144
+ }
145
+ return pluginSpec.min ?? min;
146
+ }
147
+ return pluginSpec.min ?? min;
148
+ }, [
149
+ pluginSpec.logBase,
150
+ pluginSpec.min,
151
+ min
152
+ ]);
153
+ const finalMax = useMemo(()=>{
154
+ if (pluginSpec.logBase !== undefined) {
155
+ // For log scale, ignore max if it's <= 0
156
+ if (pluginSpec.max !== undefined && pluginSpec.max <= 0) {
157
+ return undefined; // Let ECharts auto-calculate
158
+ }
159
+ return pluginSpec.max ?? max;
160
+ }
161
+ return pluginSpec.max ?? max;
162
+ }, [
163
+ pluginSpec.logBase,
164
+ pluginSpec.max,
165
+ max
166
+ ]);
120
167
  // TODO: add support for multiple queries
121
168
  if (queryResults.length > 1) {
122
169
  return /*#__PURE__*/ _jsx(Stack, {
@@ -151,13 +198,15 @@ export function HeatMapChartPanel(props) {
151
198
  height: contentDimensions.height,
152
199
  data: data,
153
200
  xAxisCategories: xAxisCategories,
154
- yAxisCategories: yAxisCategories,
155
201
  yAxisFormat: yAxisFormat,
156
202
  countFormat: countFormat,
157
203
  countMin: countMin,
158
204
  countMax: countMax,
159
205
  timeScale: timeScale,
160
- showVisualMap: pluginSpec.showVisualMap
206
+ showVisualMap: pluginSpec.showVisualMap,
207
+ min: finalMin,
208
+ max: finalMax,
209
+ logBase: pluginSpec.logBase
161
210
  })
162
211
  });
163
212
  }