@splunk/visualizations 28.3.0 → 28.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 (225) hide show
  1. package/Area/Area.d.ts.map +1 -1
  2. package/Area.config.js +0 -1
  3. package/Area.config.js.map +2 -2
  4. package/Area.js +495 -99
  5. package/Area.js.map +3 -3
  6. package/Bar/Bar.d.ts.map +1 -1
  7. package/Bar.config.js +0 -1
  8. package/Bar.config.js.map +2 -2
  9. package/Bar.js +505 -99
  10. package/Bar.js.map +3 -3
  11. package/Bubble.config.js +0 -1
  12. package/Bubble.config.js.map +2 -2
  13. package/Bubble.js +494 -86
  14. package/Bubble.js.map +3 -3
  15. package/CHANGELOG.external.md +76 -0
  16. package/ChoroplethSvg/ChoroplethSvg.d.ts +4 -3
  17. package/ChoroplethSvg/ChoroplethSvg.d.ts.map +1 -1
  18. package/ChoroplethSvg.config.js +1 -3
  19. package/ChoroplethSvg.config.js.map +2 -2
  20. package/ChoroplethSvg.js +539 -103
  21. package/ChoroplethSvg.js.map +4 -4
  22. package/Column/Column.d.ts.map +1 -1
  23. package/Column.config.js +0 -1
  24. package/Column.config.js.map +2 -2
  25. package/Column.js +495 -99
  26. package/Column.js.map +3 -3
  27. package/Ellipse.js +528 -104
  28. package/Ellipse.js.map +4 -4
  29. package/Events/PureEvents/PureEvents.d.ts.map +1 -1
  30. package/Events.js +612 -149
  31. package/Events.js.map +4 -4
  32. package/FillerGauge/FillerGauge.d.ts.map +1 -1
  33. package/FillerGauge/PureFillerGauge/FillerGauge.d.ts.map +1 -1
  34. package/FillerGauge.js +535 -140
  35. package/FillerGauge.js.map +4 -4
  36. package/Image/Image.d.ts.map +1 -1
  37. package/Image.js +564 -108
  38. package/Image.js.map +4 -4
  39. package/Line/Line.d.ts.map +1 -1
  40. package/Line/lineUtils.d.ts.map +1 -1
  41. package/Line/mockdata/LineData.d.ts +59 -0
  42. package/Line/mockdata/LineData.d.ts.map +1 -1
  43. package/Line.config.js +0 -1
  44. package/Line.config.js.map +2 -2
  45. package/Line.js +601 -100
  46. package/Line.js.map +3 -3
  47. package/LinkGraph/PureLinkGraph/PureLinkGraph.d.ts +5 -0
  48. package/LinkGraph/PureLinkGraph/PureLinkGraph.d.ts.map +1 -1
  49. package/LinkGraph/PureLinkGraph/PureLinkGraphUtils.d.ts.map +1 -1
  50. package/LinkGraph/PureLinkGraph/components/Graph.d.ts +9 -1
  51. package/LinkGraph/PureLinkGraph/components/Graph.d.ts.map +1 -1
  52. package/LinkGraph/PureLinkGraph/components/GraphStyles.d.ts.map +1 -1
  53. package/LinkGraph/PureLinkGraph/components/Node.d.ts +1 -0
  54. package/LinkGraph/PureLinkGraph/components/Node.d.ts.map +1 -1
  55. package/LinkGraph/PureLinkGraph/components/Nodes.d.ts +1 -0
  56. package/LinkGraph/PureLinkGraph/components/Nodes.d.ts.map +1 -1
  57. package/LinkGraph/PureLinkGraph/measurementUtils.d.ts +16 -0
  58. package/LinkGraph/PureLinkGraph/measurementUtils.d.ts.map +1 -0
  59. package/LinkGraph/PureLinkGraph/utils/iconLoader.d.ts.map +1 -1
  60. package/LinkGraph/config.d.ts.map +1 -1
  61. package/LinkGraph.config.js +15 -1
  62. package/LinkGraph.config.js.map +2 -2
  63. package/LinkGraph.js +1355 -654
  64. package/LinkGraph.js.map +4 -4
  65. package/Map/Map.d.ts +2 -2
  66. package/Map/Map.d.ts.map +1 -1
  67. package/Map/PureMap/BubbleLayer.d.ts +5 -0
  68. package/Map/PureMap/BubbleLayer.d.ts.map +1 -1
  69. package/Map/PureMap/LocalChoroplethLayer.d.ts.map +1 -1
  70. package/Map/PureMap/PureMap.d.ts.map +1 -1
  71. package/Map/PureMap/PureMapContainer.d.ts.map +1 -1
  72. package/Map/PureMap/Tooltip.d.ts.map +1 -1
  73. package/Map/config.d.ts.map +1 -1
  74. package/Map.config.js +0 -1
  75. package/Map.config.js.map +2 -2
  76. package/Map.js +738 -228
  77. package/Map.js.map +4 -4
  78. package/Markdown/Markdown.d.ts.map +1 -1
  79. package/Markdown.js +548 -95
  80. package/Markdown.js.map +4 -4
  81. package/MarkerGauge/MarkerGauge.d.ts +5 -1
  82. package/MarkerGauge/MarkerGauge.d.ts.map +1 -1
  83. package/MarkerGauge/PureMarkerGauge/MarkerGauge.d.ts +4 -0
  84. package/MarkerGauge/PureMarkerGauge/MarkerGauge.d.ts.map +1 -1
  85. package/MarkerGauge/config.d.ts.map +1 -1
  86. package/MarkerGauge.config.js +121 -3
  87. package/MarkerGauge.config.js.map +3 -3
  88. package/MarkerGauge.js +1318 -142
  89. package/MarkerGauge.js.map +4 -4
  90. package/NetworkGraph/NetworkGraph.d.ts +22 -0
  91. package/NetworkGraph/NetworkGraph.d.ts.map +1 -0
  92. package/NetworkGraph/PureNetworkGraph/PureNetworkGraph.d.ts +60 -0
  93. package/NetworkGraph/PureNetworkGraph/PureNetworkGraph.d.ts.map +1 -0
  94. package/NetworkGraph/PureNetworkGraph/components/Link.d.ts +19 -0
  95. package/NetworkGraph/PureNetworkGraph/components/Link.d.ts.map +1 -0
  96. package/NetworkGraph/PureNetworkGraph/components/NetworkGraphSvg.d.ts +29 -0
  97. package/NetworkGraph/PureNetworkGraph/components/NetworkGraphSvg.d.ts.map +1 -0
  98. package/NetworkGraph/PureNetworkGraph/components/Node.d.ts +27 -0
  99. package/NetworkGraph/PureNetworkGraph/components/Node.d.ts.map +1 -0
  100. package/NetworkGraph/PureNetworkGraph/components/Tooltip.d.ts +12 -0
  101. package/NetworkGraph/PureNetworkGraph/components/Tooltip.d.ts.map +1 -0
  102. package/NetworkGraph/PureNetworkGraph/components/ZoomControls.d.ts +13 -0
  103. package/NetworkGraph/PureNetworkGraph/components/ZoomControls.d.ts.map +1 -0
  104. package/NetworkGraph/PureNetworkGraph/mockdata/data.d.ts +140 -0
  105. package/NetworkGraph/PureNetworkGraph/mockdata/data.d.ts.map +1 -0
  106. package/NetworkGraph/PureNetworkGraph/mockdata/datasource.d.ts +89 -0
  107. package/NetworkGraph/PureNetworkGraph/mockdata/datasource.d.ts.map +1 -0
  108. package/NetworkGraph/PureNetworkGraph/utils/forceLayout.d.ts +47 -0
  109. package/NetworkGraph/PureNetworkGraph/utils/forceLayout.d.ts.map +1 -0
  110. package/NetworkGraph/PureNetworkGraph/utils/iconLoader.d.ts +78 -0
  111. package/NetworkGraph/PureNetworkGraph/utils/iconLoader.d.ts.map +1 -0
  112. package/NetworkGraph/PureNetworkGraph/utils/networkGraphShared.d.ts +111 -0
  113. package/NetworkGraph/PureNetworkGraph/utils/networkGraphShared.d.ts.map +1 -0
  114. package/NetworkGraph/PureNetworkGraph/utils/networkGraphUtils.d.ts +123 -0
  115. package/NetworkGraph/PureNetworkGraph/utils/networkGraphUtils.d.ts.map +1 -0
  116. package/NetworkGraph/config.d.ts +4 -0
  117. package/NetworkGraph/config.d.ts.map +1 -0
  118. package/NetworkGraph/index.d.ts +3 -0
  119. package/NetworkGraph/index.d.ts.map +1 -0
  120. package/NetworkGraph.config.js +938 -0
  121. package/NetworkGraph.config.js.map +7 -0
  122. package/NetworkGraph.js +6793 -0
  123. package/NetworkGraph.js.map +7 -0
  124. package/ParallelCoordinates.js +532 -93
  125. package/ParallelCoordinates.js.map +4 -4
  126. package/Pie/Pie.d.ts.map +1 -1
  127. package/Pie/pieUtils.d.ts.map +1 -1
  128. package/Pie.js +510 -101
  129. package/Pie.js.map +3 -3
  130. package/Punchcard.js +523 -84
  131. package/Punchcard.js.map +4 -4
  132. package/Rectangle.js +537 -113
  133. package/Rectangle.js.map +4 -4
  134. package/Sankey/PureSankey/SankeyTooltip.d.ts.map +1 -1
  135. package/Sankey.js +562 -111
  136. package/Sankey.js.map +4 -4
  137. package/Scatter/Scatter.d.ts.map +1 -1
  138. package/Scatter.config.js +0 -1
  139. package/Scatter.config.js.map +2 -2
  140. package/Scatter.js +505 -99
  141. package/Scatter.js.map +3 -3
  142. package/SingleValue/SingleValue.d.ts.map +1 -1
  143. package/SingleValue/config.d.ts.map +1 -1
  144. package/SingleValue.config.js +15 -2
  145. package/SingleValue.config.js.map +2 -2
  146. package/SingleValue.js +656 -173
  147. package/SingleValue.js.map +3 -3
  148. package/SingleValueBasic.js.map +1 -1
  149. package/SingleValueIcon/SingleValueIcon.d.ts.map +1 -1
  150. package/SingleValueIcon/config.d.ts.map +1 -1
  151. package/SingleValueIcon.config.js +0 -1
  152. package/SingleValueIcon.config.js.map +2 -2
  153. package/SingleValueIcon.js +512 -124
  154. package/SingleValueIcon.js.map +3 -3
  155. package/SingleValueRadial/PureSingleValueRadial/utils/gaugeUtils.d.ts +0 -8
  156. package/SingleValueRadial/PureSingleValueRadial/utils/gaugeUtils.d.ts.map +1 -1
  157. package/SingleValueRadial/SingleValueRadial.d.ts.map +1 -1
  158. package/SingleValueRadial.config.js +0 -1
  159. package/SingleValueRadial.config.js.map +2 -2
  160. package/SingleValueRadial.js +517 -124
  161. package/SingleValueRadial.js.map +4 -4
  162. package/SparkLine.js +46 -8
  163. package/SparkLine.js.map +2 -2
  164. package/Table/PureTable.d.ts +10 -0
  165. package/Table/PureTable.d.ts.map +1 -1
  166. package/Table/cells/SparklineCell.d.ts.map +1 -1
  167. package/Table/config.d.ts.map +1 -1
  168. package/Table/hooks.d.ts +4 -0
  169. package/Table/hooks.d.ts.map +1 -1
  170. package/Table.config.js +1 -1
  171. package/Table.config.js.map +2 -2
  172. package/Table.js +760 -223
  173. package/Table.js.map +4 -4
  174. package/Timeline/PureTimeline/src/CursorPlugin.d.ts.map +1 -1
  175. package/Timeline/PureTimeline/src/TimelineLegend.d.ts.map +1 -1
  176. package/Timeline/config.d.ts.map +1 -1
  177. package/Timeline.config.js +31 -12
  178. package/Timeline.config.js.map +4 -4
  179. package/Timeline.js +649 -211
  180. package/Timeline.js.map +4 -4
  181. package/common/Charting.d.ts +5 -0
  182. package/common/Charting.d.ts.map +1 -1
  183. package/common/Charting.js +12 -0
  184. package/common/Charting.js.map +2 -2
  185. package/common/OptionsDoc.js.map +1 -1
  186. package/common/ThemesDoc.js +0 -1
  187. package/common/ThemesDoc.js.map +2 -2
  188. package/common/TimeSeriesChartWrapper.d.ts +24 -11
  189. package/common/TimeSeriesChartWrapper.d.ts.map +1 -1
  190. package/common/TimeSeriesChartWrapper.js +561 -83
  191. package/common/TimeSeriesChartWrapper.js.map +4 -4
  192. package/common/chartingUtils.d.ts +45 -5
  193. package/common/chartingUtils.d.ts.map +1 -1
  194. package/common/chartingUtils.js +102 -8
  195. package/common/chartingUtils.js.map +3 -3
  196. package/common/editorConfig/AxesChartDataConfig.d.ts.map +1 -1
  197. package/common/hocs/withTrellis.d.ts.map +1 -1
  198. package/common/interfaces/DashboardVizProps.d.ts +0 -3
  199. package/common/interfaces/DashboardVizProps.d.ts.map +1 -1
  200. package/common/interfaces/DataSource.d.ts +1 -1
  201. package/common/interfaces/DataSource.d.ts.map +1 -1
  202. package/common/shapeUtils.js +5 -20
  203. package/common/shapeUtils.js.map +2 -2
  204. package/common/utils/dataUtils.d.ts.map +1 -1
  205. package/common/utils/dataUtils.js +5 -4
  206. package/common/utils/dataUtils.js.map +2 -2
  207. package/common/utils/mapUtils.js +16 -9
  208. package/common/utils/mapUtils.js.map +2 -2
  209. package/common/utils/singleValueUtils.js +17 -18
  210. package/common/utils/singleValueUtils.js.map +2 -2
  211. package/common/utils/textUtils.d.ts +20 -0
  212. package/common/utils/textUtils.d.ts.map +1 -0
  213. package/common/utils/textUtils.js +76 -0
  214. package/common/utils/textUtils.js.map +7 -0
  215. package/common/utils/trellisUtils.d.ts.map +1 -1
  216. package/common/utils/trellisUtils.js +12 -14
  217. package/common/utils/trellisUtils.js.map +2 -2
  218. package/common/withDashboardViz.d.ts.map +1 -1
  219. package/common/withDashboardViz.js +544 -84
  220. package/common/withDashboardViz.js.map +4 -4
  221. package/package.json +33 -26
  222. package/common/utils/styleUtils.d.ts +0 -2
  223. package/common/utils/styleUtils.d.ts.map +0 -1
  224. package/common/utils/styleUtils.js +0 -30
  225. package/common/utils/styleUtils.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/common/utils/dataUtils.ts", "esm-externals:@splunk/visualizations-shared/numberUtils"],
4
- "sourcesContent": ["import type { FieldEntry } from '@splunk/visualizations-shared/dataSourceUtils';\nimport { startsWithNumber } from '@splunk/visualizations-shared/numberUtils';\nimport type { DashboardVizProps, DataSource, VizConfig } from '../interfaces';\nimport { VizBehavior } from '../interfaces';\nimport { ChartEvent } from '../interfaces/ChartEvent';\n\n// TODO: utilize this fn in ParallelCoordinates\n\nexport const convertToArrOfObjects = (columns: (string | any[])[], fields: any[]): any[] => {\n if (!columns || !columns[0] || !columns[0].length) return [];\n\n const data = [];\n\n for (let i = 0; i < columns[0].length; i += 1) {\n const newObj = {};\n fields.forEach((field, index) => {\n const fieldName = typeof field === 'string' ? field : field.name;\n if (columns[index][i] === '') {\n newObj[fieldName] = null;\n } else {\n newObj[fieldName] = columns[index][i];\n }\n });\n data.push(newObj);\n }\n\n return data;\n};\n\n// LTTB algorithm which can be used to downsample time series data while striving to maintain\n// the spikes and overall shape of the chart\n// Copied from https://github.com/sveinn-steinarsson/flot-downsample/blob/0815010016fc94b1bbc6a010afb8aad13ada6d0d/jquery.flot.downsample.js\n// Modifications include:\n// 1) Convert to modern JavaScript(use const, let, and use array.push to push to last element of array)\n// 2) Convert to camel case\n// 3) Convert to TS and also return the indices of the points that are in the downsampled result.\n// 4) Add a new parameter preferredDownsampleIndices that correspond to the indices of points\n// that should be used in case of a tie of the max area in a bucket\nconst largestTriangleThreeBuckets = (\n data: [Date | number, number][],\n threshold: number,\n preferredDownsampleIndices: Set<number>\n): {\n downsampledData: [Date | number, number][];\n downsampledIndices: number[];\n} => {\n const dataLength = data.length;\n const downsampledIndices = [];\n if (threshold >= dataLength || threshold === 0) {\n const allIndices = data.map((values, index) => index);\n return { downsampledData: data, downsampledIndices: allIndices }; // Nothing to do\n }\n\n const sampled: [Date | number, number][] = [];\n let sampledIndex = 0;\n\n // Bucket size. Leave room for start and end data points\n const every = (dataLength - 2) / (threshold - 2);\n\n let a = 0; // Initially a is the first point in the triangle\n let maxAreaPoint: [Date | number, number];\n let maxArea: number | undefined;\n let area: number | undefined;\n let nextA: number | undefined;\n\n sampled.push(data[a]); // Always add the first point\n downsampledIndices.push(0);\n\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < threshold - 2; i++) {\n // Calculate point average for next bucket (containing c)\n let avgX = 0;\n let avgY = 0;\n let avgRangeStart = Math.floor((i + 1) * every) + 1;\n let avgRangeEnd = Math.floor((i + 2) * every) + 1;\n avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;\n\n const avgRangeLength = avgRangeEnd - avgRangeStart;\n\n // eslint-disable-next-line no-plusplus\n for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {\n avgX += Number(data[avgRangeStart][0]); // * 1 enforces Number (value may be Date)\n avgY += data[avgRangeStart][1] * 1;\n }\n avgX /= avgRangeLength;\n avgY /= avgRangeLength;\n\n // Get the range for this bucket\n let rangeOffs = Math.floor((i + 0) * every) + 1;\n const rangeTo = Math.floor((i + 1) * every) + 1;\n\n // Point a\n const pointAX = Number(data[a][0]); // Enforce Number (value may be Date)\n const pointAY = data[a][1] * 1;\n\n // eslint-disable-next-line no-multi-assign\n maxArea = area = -1;\n let maxAreaIndex = rangeOffs;\n\n // eslint-disable-next-line no-plusplus\n for (; rangeOffs < rangeTo; rangeOffs++) {\n // Calculate triangle area over three buckets\n area =\n Math.abs(\n (pointAX - avgX) * (data[rangeOffs][1] - pointAY) -\n (pointAX - Number(data[rangeOffs][0])) * (avgY - pointAY)\n ) * 0.5;\n // Modification: try to downsample the least amount of points possible when there are multiple series\n // If all points in a bucket have the same area, prioritize the one with an x index\n // that also existed from another series so we don't add another point unnecessarily.\n // By default LTTB picks the leftmost point in the bucket\n if (area > maxArea || (area === maxArea && preferredDownsampleIndices.has(rangeOffs))) {\n maxArea = area;\n maxAreaPoint = data[rangeOffs];\n nextA = rangeOffs; // Next a is this b\n // Modification: save the index of the point with the most area\n maxAreaIndex = rangeOffs;\n }\n }\n\n // eslint-disable-next-line no-plusplus\n sampled[sampledIndex++] = maxAreaPoint; // Pick this point from the bucket\n downsampledIndices.push(maxAreaIndex);\n a = nextA; // This a is the next a (chosen b)\n }\n\n // eslint-disable-next-line no-plusplus\n sampled[sampledIndex++] = data[dataLength - 1]; // Always add last\n downsampledIndices.push(dataLength - 1);\n\n return { downsampledData: sampled, downsampledIndices };\n};\n\nexport type DownsampleOptions = { threshold: number } & Pick<DashboardVizProps, 'dataSources' | 'options'>;\n\ntype CoerceYColumnResult = {\n canDownsampleColumn: boolean;\n canLooselyCoerceSomeValues: boolean;\n coercedColumn: number[];\n};\n\n/**\n * Strictly coerces the entire column to numbers if it only consists of numeric strings or numbers. Also determines\n * if at least one of the values in the column can be loosely coerced to a number.\n * If the column cannot be strictly downsampled (if it contains nulls or non-numeric strings), returns an empty array and\n * returns that it cannot downsample the column.\n */\nconst strictlyCoerceYColumn = (\n column: (string | number)[] | number[],\n options: DownsampleOptions['options']\n): CoerceYColumnResult => {\n const isNullCoercionEnabled = options.nullValueDisplay === 'zero';\n // Splunk charting allows for numbers in formats such as negative hex that\n // Number() does not support and also allows loose coercion of hex numbers (but not other formats)\n // We want to identify columns which contain at least one value that can be loosely coerced\n const canLooselyCoerceSomeValues =\n column.findIndex(\n value => startsWithNumber(`${value}`) || (isNullCoercionEnabled && value === null)\n ) >= 0;\n\n // If not all values in column can be strictly coerced to a number, we do not downsample\n const coercedColumn: number[] = [];\n const canDownsampleColumn = !column.some(value => {\n const coercedValue = Number(value);\n const coerceValueToZero = isNullCoercionEnabled && value === null;\n\n // if it can't be parsed or isn't safe, fail\n if (\n Number.isNaN(coercedValue) ||\n coercedValue <= Number.MIN_SAFE_INTEGER ||\n coercedValue >= Number.MAX_SAFE_INTEGER ||\n (typeof value !== 'string' && typeof value !== 'number' && !coerceValueToZero)\n ) {\n return true;\n }\n // save value and continue to next\n coercedColumn.push(coercedValue);\n return false;\n });\n\n return {\n canDownsampleColumn,\n canLooselyCoerceSomeValues,\n coercedColumn: canDownsampleColumn ? coercedColumn : [],\n };\n};\n\n/**\n * Tries to coerce the x-column to numbers or dates, if it is eligible for downsampling.\n * Only strictly increasing x-columns are eligible for downsampling.\n * If the column is not eligible for downsampling, returns an empty array.\n */\nconst strictlyCoerceXColumn = (column: (string | number)[], fieldType: string): Date[] | number[] => {\n if (fieldType === 'number') {\n const coercedXColumn = column.map(xValue => Number(xValue));\n if (isColumnStrictlyIncreasing(coercedXColumn, fieldType)) {\n return coercedXColumn;\n }\n } else if (fieldType === 'time') {\n const coercedXColumn = column.map(xValue => new Date(xValue));\n if (isColumnStrictlyIncreasing(coercedXColumn, fieldType)) {\n return coercedXColumn;\n }\n }\n return [];\n};\n\nexport const isDownsamplingEnabledForViz = ({ vizConfig }: { vizConfig: VizConfig }) => {\n return vizConfig.supports?.includes(VizBehavior.DOWNSAMPLING);\n};\n\nexport const calculateThresholdOnRangeSelect = ({\n firstIndex,\n lastIndex,\n dataSources,\n width,\n}: Pick<DashboardVizProps, 'dataSources'> & {\n firstIndex: number;\n lastIndex: number;\n width: number | string;\n}): number => {\n const window = lastIndex - firstIndex + 1;\n // eslint-disable-next-line no-unsafe-optional-chaining\n const ratio = Math.round(Number(dataSources?.primary?.data?.columns[0]?.length / window) * 10) / 10;\n return Math.round(ratio * Number(width));\n};\n\n/**\n * Calculates the downsampling threshold based on the range selection. If search zoom is enabled or there is no selection,\n * then returns the width of the visualization.\n *\n * Otherwise calculates the threshold based on the ratio of the window selected compared to the size of the non-downsampled\n * data sources. Returns null if the chart event's dataset does not match the passed in primary data source or if the chart is zoomed\n * in for a categorical chart.\n */\nexport const calculateDownsamplingThreshold = ({\n enableSearchZoom,\n dataSources,\n selectChartEvent,\n width,\n xField,\n}: {\n enableSearchZoom: boolean;\n dataSources: Record<string, DataSource> | null;\n selectChartEvent: ChartEvent<'chartRangeSelect'> | null;\n width: number;\n xField: string;\n}): number | null => {\n if (enableSearchZoom || !selectChartEvent) {\n return Number(width);\n }\n\n const primaryDataSource = dataSources?.primary;\n if (!primaryDataSource) {\n return null;\n }\n\n const { startXIndex, endXIndex, currentTarget } = selectChartEvent;\n\n try {\n const xFieldIndex = primaryDataSource?.data?.fields.findIndex(field => {\n const name = typeof field === 'string' ? field : field.name;\n return name === xField;\n });\n const downsampledXFieldIndex = currentTarget.dataSet?.fields.findIndex(field => field === xField);\n\n if (xFieldIndex === -1 || downsampledXFieldIndex === -1) {\n return null;\n }\n\n const fullSeries = primaryDataSource?.data?.columns[xFieldIndex];\n const downsampledSeries = currentTarget.dataSet.seriesList[downsampledXFieldIndex];\n\n const firstIndex = fullSeries.findIndex(x => {\n return downsampledSeries[startXIndex] === x;\n });\n const lastIndex = fullSeries.findIndex(x => {\n return downsampledSeries[endXIndex] === x;\n });\n\n if (firstIndex >= 0 && lastIndex >= 0 && firstIndex <= lastIndex) {\n return calculateThresholdOnRangeSelect({\n firstIndex,\n lastIndex,\n dataSources,\n width,\n });\n }\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('Error occurred while setting downsample threshold on range select event', e);\n }\n\n return null;\n};\n\nconst isColumnStrictlyIncreasing = (column: (number | Date)[], fieldType: 'number' | 'time') => {\n return column.every((value, index) => {\n if (fieldType === 'number') {\n if (Number.isNaN(value)) {\n return false;\n }\n }\n\n if (fieldType === 'time') {\n if (Number.isNaN((value as Date).getTime())) {\n return false;\n }\n }\n if (index === 0) {\n return true;\n }\n return value > column[index - 1];\n });\n};\n\n/**\n * Verifies that all of the columns that are displayed in a chart can be downsampled. Valid columns that can be\n * displayed are those that contain at least one number. We can only downsample columns that only consist of numbers.\n *\n * If all columns can be downsampled, returns the x column coerced to time/number and y columns coerced to numbers.\n * If not all columns can be downsampled, then returns empty arrays for both x and y\n */\nconst tryToCoerceAllDisplayedFields = (\n ds: DataSource,\n xField: string,\n yFields: Set<string>,\n fieldTypes: string[],\n options: DownsampleOptions['options']\n): { xColumn: Date[] | number[]; yColumns: number[][] } => {\n let xColumn: Date[] | number[] = [];\n const yColumns: number[][] = [];\n\n const canDownsample = !ds.data.fields.some((field, index) => {\n const fieldName = (field as FieldEntry).name ?? field;\n const fieldType = fieldTypes[index] ?? 'unknown';\n const column = ds.data.columns[index];\n let hasDisplayedColumnThatCantBeDownsampled = false;\n\n if (fieldName === xField) {\n xColumn = strictlyCoerceXColumn(column, fieldType);\n } else if (yFields.has(fieldName)) {\n const { coercedColumn, canLooselyCoerceSomeValues, canDownsampleColumn } = strictlyCoerceYColumn(\n ds.data.columns[index],\n options\n );\n // do not perform downsampling if a column can possibly be displayed but cannot\n // be downsampled using LTTB\n hasDisplayedColumnThatCantBeDownsampled = canLooselyCoerceSomeValues && !canDownsampleColumn;\n if (hasDisplayedColumnThatCantBeDownsampled) {\n return true;\n }\n if (canDownsampleColumn) {\n yColumns.push(coercedColumn);\n }\n }\n return false;\n });\n\n if (canDownsample) {\n return { xColumn, yColumns };\n }\n return { xColumn: [], yColumns: [] };\n};\n\nconst pickIndicesFromDataSource = (ds: DataSource, indices: Set<number>): DataSource => {\n const sortedIndices = Array.from(indices).sort((a: number, b: number) => a - b);\n const slicedColumns = [];\n ds.data.columns.forEach(column => {\n const slicedColumn = [];\n sortedIndices.forEach(index => {\n slicedColumn.push(column[index]);\n });\n slicedColumns.push(slicedColumn);\n });\n\n // update data columns with downsampled columns\n return {\n ...ds,\n data: {\n ...ds.data,\n columns: slicedColumns,\n },\n };\n};\n\nexport const downsampleDataSources = ({ dataSources, threshold, options }: DownsampleOptions) => {\n const primaryDS = dataSources?.primary;\n // only downsample time series when number of data points are over threshold\n const numPoints = primaryDS?.data?.columns[0]?.length ?? 0;\n if (Number.isNaN(threshold) || numPoints <= threshold || threshold < 2) {\n return dataSources;\n }\n\n const { xField, yFields, fieldTypes } = options;\n if (!xField || !yFields?.length || !fieldTypes?.length) {\n return dataSources;\n }\n\n const nonInternalYFields = new Set<string>(yFields.filter(yField => !yField.startsWith('_')));\n const maxPointsInDownsample = Math.min(nonInternalYFields.size * threshold, numPoints);\n\n // Do not try to downsample if there are too many downsampled pts\n // At the worst case, each series has non-overlapping downsampled pts\n // which will mean that all points will be included in the downsampled result\n // This will just lead to additional overhead due to coercing each\n // x and y field to number\n if (maxPointsInDownsample >= numPoints) {\n return dataSources;\n }\n\n const { xColumn, yColumns } = tryToCoerceAllDisplayedFields(\n primaryDS,\n xField,\n nonInternalYFields,\n fieldTypes,\n options\n );\n\n if (!yColumns.length || !xColumn.length) {\n return dataSources;\n }\n\n const downsampledDataSources = { ...dataSources };\n const downsampledIndices = new Set<number>();\n\n yColumns.forEach((yColumn, columnIndex) => {\n // perform LTTB downsampling for current series, LTTB takes an [x, y] pair\n const xyPair: [Date | number, number][] = yColumn.map((yValue, index) => {\n return [xColumn[index], yValue];\n });\n\n try {\n const { downsampledIndices: downsampledIndicesForSeries } = largestTriangleThreeBuckets(\n xyPair,\n threshold,\n downsampledIndices\n );\n downsampledIndicesForSeries.forEach(downsampleIndex => downsampledIndices.add(downsampleIndex));\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error(`Error occurred while downsampling column ${columnIndex}`, e);\n }\n });\n // update data columns with downsampled columns\n downsampledDataSources.primary = pickIndicesFromDataSource(primaryDS, downsampledIndices);\n\n return downsampledDataSources;\n};\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/numberUtils\";\nexport * from \"@splunk/visualizations-shared/numberUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { FieldEntry } from '@splunk/visualizations-shared/dataSourceUtils';\nimport { startsWithNumber } from '@splunk/visualizations-shared/numberUtils';\nimport type { DashboardVizProps, DataSource, VizConfig } from '../interfaces';\nimport { VizBehavior } from '../interfaces';\nimport { ChartEvent } from '../interfaces/ChartEvent';\n\nexport const convertToArrOfObjects = (columns: (string | any[])[], fields: any[]): any[] => {\n if (!columns || !columns[0] || !columns[0].length) return [];\n\n const data = [];\n\n for (let i = 0; i < columns[0].length; i += 1) {\n const newObj = {};\n fields.forEach((field, index) => {\n const fieldName = getFieldName(field);\n if (columns[index][i] === '') {\n newObj[fieldName] = null;\n } else {\n newObj[fieldName] = columns[index][i];\n }\n });\n data.push(newObj);\n }\n\n return data;\n};\n\nconst getFieldName = (field: FieldEntry | string): string => (typeof field === 'string' ? field : field.name);\n\n// LTTB algorithm which can be used to downsample time series data while striving to maintain\n// the spikes and overall shape of the chart\n// Copied from https://github.com/sveinn-steinarsson/flot-downsample/blob/0815010016fc94b1bbc6a010afb8aad13ada6d0d/jquery.flot.downsample.js\n// Modifications include:\n// 1) Convert to modern JavaScript(use const, let, and use array.push to push to last element of array)\n// 2) Convert to camel case\n// 3) Convert to TS and also return the indices of the points that are in the downsampled result.\n// 4) Add a new parameter preferredDownsampleIndices that correspond to the indices of points\n// that should be used in case of a tie of the max area in a bucket\nconst largestTriangleThreeBuckets = (\n data: [Date | number, number][],\n threshold: number,\n preferredDownsampleIndices: Set<number>\n): {\n downsampledData: [Date | number, number][];\n downsampledIndices: number[];\n} => {\n const dataLength = data.length;\n const downsampledIndices = [];\n if (threshold >= dataLength || threshold === 0) {\n const allIndices = data.map((values, index) => index);\n return { downsampledData: data, downsampledIndices: allIndices }; // Nothing to do\n }\n\n const sampled: [Date | number, number][] = [];\n let sampledIndex = 0;\n\n // Bucket size. Leave room for start and end data points\n const every = (dataLength - 2) / (threshold - 2);\n\n let a = 0; // Initially a is the first point in the triangle\n let maxAreaPoint: [Date | number, number];\n let maxArea: number | undefined;\n let area: number | undefined;\n let nextA: number | undefined;\n\n sampled.push(data[a]); // Always add the first point\n downsampledIndices.push(0);\n\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < threshold - 2; i++) {\n // Calculate point average for next bucket (containing c)\n let avgX = 0;\n let avgY = 0;\n let avgRangeStart = Math.floor((i + 1) * every) + 1;\n let avgRangeEnd = Math.floor((i + 2) * every) + 1;\n avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;\n\n const avgRangeLength = avgRangeEnd - avgRangeStart;\n\n // eslint-disable-next-line no-plusplus\n for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {\n avgX += Number(data[avgRangeStart][0]); // * 1 enforces Number (value may be Date)\n avgY += data[avgRangeStart][1] * 1;\n }\n avgX /= avgRangeLength;\n avgY /= avgRangeLength;\n\n // Get the range for this bucket\n let rangeOffs = Math.floor((i + 0) * every) + 1;\n const rangeTo = Math.floor((i + 1) * every) + 1;\n\n // Point a\n const pointAX = Number(data[a][0]); // Enforce Number (value may be Date)\n const pointAY = data[a][1] * 1;\n\n // eslint-disable-next-line no-multi-assign\n maxArea = area = -1;\n let maxAreaIndex = rangeOffs;\n\n // eslint-disable-next-line no-plusplus\n for (; rangeOffs < rangeTo; rangeOffs++) {\n // Calculate triangle area over three buckets\n area =\n Math.abs(\n (pointAX - avgX) * (data[rangeOffs][1] - pointAY) -\n (pointAX - Number(data[rangeOffs][0])) * (avgY - pointAY)\n ) * 0.5;\n // Modification: try to downsample the least amount of points possible when there are multiple series\n // If all points in a bucket have the same area, prioritize the one with an x index\n // that also existed from another series so we don't add another point unnecessarily.\n // By default LTTB picks the leftmost point in the bucket\n if (area > maxArea || (area === maxArea && preferredDownsampleIndices.has(rangeOffs))) {\n maxArea = area;\n maxAreaPoint = data[rangeOffs];\n nextA = rangeOffs; // Next a is this b\n // Modification: save the index of the point with the most area\n maxAreaIndex = rangeOffs;\n }\n }\n\n // eslint-disable-next-line no-plusplus\n sampled[sampledIndex++] = maxAreaPoint; // Pick this point from the bucket\n downsampledIndices.push(maxAreaIndex);\n a = nextA; // This a is the next a (chosen b)\n }\n\n // eslint-disable-next-line no-plusplus\n sampled[sampledIndex++] = data[dataLength - 1]; // Always add last\n downsampledIndices.push(dataLength - 1);\n\n return { downsampledData: sampled, downsampledIndices };\n};\n\nexport type DownsampleOptions = { threshold: number } & Pick<DashboardVizProps, 'dataSources' | 'options'>;\n\ntype CoerceYColumnResult = {\n canDownsampleColumn: boolean;\n canLooselyCoerceSomeValues: boolean;\n coercedColumn: number[];\n};\n\n/**\n * Strictly coerces the entire column to numbers if it only consists of numeric strings or numbers. Also determines\n * if at least one of the values in the column can be loosely coerced to a number.\n * If the column cannot be strictly downsampled (if it contains nulls or non-numeric strings), returns an empty array and\n * returns that it cannot downsample the column.\n */\nconst strictlyCoerceYColumn = (\n column: (string | number)[] | number[],\n options: DownsampleOptions['options']\n): CoerceYColumnResult => {\n const isNullCoercionEnabled = options.nullValueDisplay === 'zero';\n // Splunk charting allows for numbers in formats such as negative hex that\n // Number() does not support and also allows loose coercion of hex numbers (but not other formats)\n // We want to identify columns which contain at least one value that can be loosely coerced\n const canLooselyCoerceSomeValues =\n column.findIndex(\n value => startsWithNumber(`${value}`) || (isNullCoercionEnabled && value === null)\n ) >= 0;\n\n // If not all values in column can be strictly coerced to a number, we do not downsample\n const coercedColumn: number[] = [];\n const canDownsampleColumn = !column.some(value => {\n const coercedValue = Number(value);\n const coerceValueToZero = isNullCoercionEnabled && value === null;\n\n // if it can't be parsed or isn't safe, fail\n if (\n Number.isNaN(coercedValue) ||\n coercedValue <= Number.MIN_SAFE_INTEGER ||\n coercedValue >= Number.MAX_SAFE_INTEGER ||\n (typeof value !== 'string' && typeof value !== 'number' && !coerceValueToZero)\n ) {\n return true;\n }\n // save value and continue to next\n coercedColumn.push(coercedValue);\n return false;\n });\n\n return {\n canDownsampleColumn,\n canLooselyCoerceSomeValues,\n coercedColumn: canDownsampleColumn ? coercedColumn : [],\n };\n};\n\n/**\n * Tries to coerce the x-column to numbers or dates, if it is eligible for downsampling.\n * Only strictly increasing x-columns are eligible for downsampling.\n * If the column is not eligible for downsampling, returns an empty array.\n */\nconst strictlyCoerceXColumn = (column: (string | number)[], fieldType: string): Date[] | number[] => {\n if (fieldType === 'number') {\n const coercedXColumn = column.map(xValue => Number(xValue));\n if (isColumnStrictlyIncreasing(coercedXColumn, fieldType)) {\n return coercedXColumn;\n }\n } else if (fieldType === 'time') {\n const coercedXColumn = column.map(xValue => new Date(xValue));\n if (isColumnStrictlyIncreasing(coercedXColumn, fieldType)) {\n return coercedXColumn;\n }\n }\n return [];\n};\n\nexport const isDownsamplingEnabledForViz = ({ vizConfig }: { vizConfig: VizConfig }) => {\n return vizConfig.supports?.includes(VizBehavior.DOWNSAMPLING);\n};\n\nexport const calculateThresholdOnRangeSelect = ({\n firstIndex,\n lastIndex,\n dataSources,\n width,\n}: Pick<DashboardVizProps, 'dataSources'> & {\n firstIndex: number;\n lastIndex: number;\n width: number | string;\n}): number => {\n const window = lastIndex - firstIndex + 1;\n // eslint-disable-next-line no-unsafe-optional-chaining\n const ratio = Math.round(Number(dataSources?.primary?.data?.columns[0]?.length / window) * 10) / 10;\n return Math.round(ratio * Number(width));\n};\n\n/**\n * Calculates the downsampling threshold based on the range selection. If search zoom is enabled or there is no selection,\n * then returns the width of the visualization.\n *\n * Otherwise calculates the threshold based on the ratio of the window selected compared to the size of the non-downsampled\n * data sources. Returns null if the chart event's dataset does not match the passed in primary data source or if the chart is zoomed\n * in for a categorical chart.\n */\nexport const calculateDownsamplingThreshold = ({\n enableSearchZoom,\n dataSources,\n selectChartEvent,\n width,\n xField,\n}: {\n enableSearchZoom: boolean;\n dataSources: Record<string, DataSource> | null;\n selectChartEvent: ChartEvent<'chartRangeSelect'> | null;\n width: number;\n xField: string;\n}): number | null => {\n if (enableSearchZoom || !selectChartEvent) {\n return Number(width);\n }\n\n const primaryDataSource = dataSources?.primary;\n if (!primaryDataSource) {\n return null;\n }\n\n const { startXIndex, endXIndex, currentTarget } = selectChartEvent;\n\n try {\n const xFieldIndex = primaryDataSource?.data?.fields.findIndex(field => {\n const name = typeof field === 'string' ? field : field.name;\n return name === xField;\n });\n const downsampledXFieldIndex = currentTarget.dataSet?.fields.findIndex(field => field === xField);\n\n if (xFieldIndex === -1 || downsampledXFieldIndex === -1) {\n return null;\n }\n\n const fullSeries = primaryDataSource?.data?.columns[xFieldIndex];\n const downsampledSeries = currentTarget.dataSet.seriesList[downsampledXFieldIndex];\n\n const firstIndex = fullSeries.findIndex(x => {\n return downsampledSeries[startXIndex] === x;\n });\n const lastIndex = fullSeries.findIndex(x => {\n return downsampledSeries[endXIndex] === x;\n });\n\n if (firstIndex >= 0 && lastIndex >= 0 && firstIndex <= lastIndex) {\n return calculateThresholdOnRangeSelect({\n firstIndex,\n lastIndex,\n dataSources,\n width,\n });\n }\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('Error occurred while setting downsample threshold on range select event', e);\n }\n\n return null;\n};\n\nconst isColumnStrictlyIncreasing = (column: (number | Date)[], fieldType: 'number' | 'time') => {\n return column.every((value, index) => {\n if (fieldType === 'number') {\n if (Number.isNaN(value)) {\n return false;\n }\n }\n\n if (fieldType === 'time') {\n if (Number.isNaN((value as Date).getTime())) {\n return false;\n }\n }\n if (index === 0) {\n return true;\n }\n return value > column[index - 1];\n });\n};\n\n/**\n * Verifies that all of the columns that are displayed in a chart can be downsampled. Valid columns that can be\n * displayed are those that contain at least one number. We can only downsample columns that only consist of numbers.\n *\n * If all columns can be downsampled, returns the x column coerced to time/number and y columns coerced to numbers.\n * If not all columns can be downsampled, then returns empty arrays for both x and y\n */\nconst tryToCoerceAllDisplayedFields = (\n ds: DataSource,\n xField: string,\n yFields: Set<string>,\n fieldTypes: string[],\n options: DownsampleOptions['options']\n): { xColumn: Date[] | number[]; yColumns: number[][] } => {\n let xColumn: Date[] | number[] = [];\n const yColumns: number[][] = [];\n\n const canDownsample = !ds.data.fields.some((field, index) => {\n const fieldName = getFieldName(field);\n const fieldType = fieldTypes[index] ?? 'unknown';\n const column = ds.data.columns[index];\n let hasDisplayedColumnThatCantBeDownsampled = false;\n\n if (fieldName === xField) {\n xColumn = strictlyCoerceXColumn(column, fieldType);\n } else if (yFields.has(fieldName)) {\n const { coercedColumn, canLooselyCoerceSomeValues, canDownsampleColumn } = strictlyCoerceYColumn(\n ds.data.columns[index],\n options\n );\n // do not perform downsampling if a column can possibly be displayed but cannot\n // be downsampled using LTTB\n hasDisplayedColumnThatCantBeDownsampled = canLooselyCoerceSomeValues && !canDownsampleColumn;\n if (hasDisplayedColumnThatCantBeDownsampled) {\n return true;\n }\n if (canDownsampleColumn) {\n yColumns.push(coercedColumn);\n }\n }\n return false;\n });\n\n if (canDownsample) {\n return { xColumn, yColumns };\n }\n return { xColumn: [], yColumns: [] };\n};\n\nconst pickIndicesFromDataSource = (ds: DataSource, indices: Set<number>): DataSource => {\n const sortedIndices = Array.from(indices).sort((a: number, b: number) => a - b);\n const slicedColumns = [];\n ds.data.columns.forEach(column => {\n const slicedColumn = [];\n sortedIndices.forEach(index => {\n slicedColumn.push(column[index]);\n });\n slicedColumns.push(slicedColumn);\n });\n\n // update data columns with downsampled columns\n return {\n ...ds,\n data: {\n ...ds.data,\n columns: slicedColumns,\n },\n };\n};\n\nexport const downsampleDataSources = ({ dataSources, threshold, options }: DownsampleOptions) => {\n const primaryDS = dataSources?.primary;\n // only downsample time series when number of data points are over threshold\n const numPoints = primaryDS?.data?.columns[0]?.length ?? 0;\n if (Number.isNaN(threshold) || numPoints <= threshold || threshold < 2) {\n return dataSources;\n }\n\n const { xField, yFields, fieldTypes } = options;\n if (!xField || !yFields?.length || !fieldTypes?.length) {\n return dataSources;\n }\n\n const nonInternalYFields = new Set<string>(yFields.filter(yField => !yField.startsWith('_')));\n const maxPointsInDownsample = Math.min(nonInternalYFields.size * threshold, numPoints);\n\n // Do not try to downsample if there are too many downsampled pts\n // At the worst case, each series has non-overlapping downsampled pts\n // which will mean that all points will be included in the downsampled result\n // This will just lead to additional overhead due to coercing each\n // x and y field to number\n if (maxPointsInDownsample >= numPoints) {\n return dataSources;\n }\n\n const { xColumn, yColumns } = tryToCoerceAllDisplayedFields(\n primaryDS,\n xField,\n nonInternalYFields,\n fieldTypes,\n options\n );\n\n if (!yColumns.length || !xColumn.length) {\n return dataSources;\n }\n\n const downsampledDataSources = { ...dataSources };\n const downsampledIndices = new Set<number>();\n\n yColumns.forEach((yColumn, columnIndex) => {\n // perform LTTB downsampling for current series, LTTB takes an [x, y] pair\n const xyPair: [Date | number, number][] = yColumn.map((yValue, index) => {\n return [xColumn[index], yValue];\n });\n\n try {\n const { downsampledIndices: downsampledIndicesForSeries } = largestTriangleThreeBuckets(\n xyPair,\n threshold,\n downsampledIndices\n );\n downsampledIndicesForSeries.forEach(downsampleIndex => downsampledIndices.add(downsampleIndex));\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error(`Error occurred while downsampling column ${columnIndex}`, e);\n }\n });\n // update data columns with downsampled columns\n downsampledDataSources.primary = pickIndicesFromDataSource(primaryDS, downsampledIndices);\n\n return downsampledDataSources;\n};\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/numberUtils\";\nexport * from \"@splunk/visualizations-shared/numberUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -265,19 +265,24 @@ var themes_default = "default" in defaultImport20 ? defaultImport20.default : de
265
265
 
266
266
  // src/Map/PureMap/Tooltip.tsx
267
267
  var StyledPopover = styled_components_default(Popover_default)`
268
- width: 250px;
268
+ min-width: 250px;
269
+ max-width: 332px;
270
+ max-width: fit-content;
269
271
  font-size: 12px;
270
272
  `;
271
273
  var StyledTable = styled_components_default.table`
272
274
  margin: 2px 6px 2px 6px;
273
- table-layout: fixed;
274
275
  width: calc(100% - 12px);
275
276
  `;
276
277
  var StyledTitleColumn = styled_components_default.td`
277
278
  opacity: 0.85;
279
+ word-break: break-all;
280
+ vertical-align: top;
278
281
  `;
279
282
  var StyledValueColumn = styled_components_default.td`
280
283
  text-align: right;
284
+ word-break: break-all;
285
+ vertical-align: top;
281
286
  `;
282
287
  var StyledColorBlock = styled_components_default.div`
283
288
  background-color: ${(props) => props.color};
@@ -288,10 +293,6 @@ var StyledColorBlock = styled_components_default.div`
288
293
  height: 11px;
289
294
  transform: translateY(1px);
290
295
  `;
291
- var StyledFieldLabel = styled_components_default.span`
292
- display: inline-block;
293
- white-space: nowrap;
294
- `;
295
296
  var StyledIconWrapper = styled_components_default.span`
296
297
  margin-left: 4px;
297
298
  display: inline-block;
@@ -358,7 +359,7 @@ var Tooltip = ({
358
359
  "data-test": "map-marker-tooltip",
359
360
  defaultPlacement: "above"
360
361
  },
361
- /* @__PURE__ */ react_exports.createElement(StyledTable, null, tooltipHeader && /* @__PURE__ */ react_exports.createElement(StyledTooltipHeader, { "data-test": "tooltip-header" }, /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement("th", { colSpan: 2 }, /* @__PURE__ */ react_exports.createElement("span", { "data-test": "tooltip-header-value" }, tooltipHeader)))), /* @__PURE__ */ react_exports.createElement("tbody", null, areaId && areaValue && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, { "data-test": "area-id" }, areaId), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "area-value" }, areaValue)), Boolean(showCoordinates && latitude) && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, null, (0, i18n_exports._)("Latitude")), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "latitude" }, convertDegToDMS(latitude, "latitude"))), Boolean(showCoordinates && longitude) && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, null, (0, i18n_exports._)("Longitude")), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "longitude" }, convertDegToDMS(longitude, "longitude"))), additionalFields.filter(({ value }) => value && String(value) !== "0").map(({ name, value, color, icon }) => /* @__PURE__ */ react_exports.createElement("tr", { key: (0, id_exports.createDOMID)() }, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, { "data-test": "field-title" }, color ? /* @__PURE__ */ react_exports.createElement(StyledColorBlock, { "data-test": "field-color", color }) : null, /* @__PURE__ */ react_exports.createElement(StyledFieldLabel, null, name, isTooltipIconFlagEnabled && icon && ((0, iconUtils_exports.isRemoteIcon)(icon) || (0, iconUtils_exports.isDataURI)(icon)) ? /* @__PURE__ */ react_exports.createElement(StyledIconWrapper, { "data-test": "field-icon" }, /* @__PURE__ */ react_exports.createElement(RemoteIcon_default, { iconURL: icon, width: 16, height: 16 })) : null)), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "field-value" }, value)))))
362
+ /* @__PURE__ */ react_exports.createElement(StyledTable, null, tooltipHeader && /* @__PURE__ */ react_exports.createElement(StyledTooltipHeader, { "data-test": "tooltip-header" }, /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement("th", { colSpan: 2 }, /* @__PURE__ */ react_exports.createElement("span", { "data-test": "tooltip-header-value" }, tooltipHeader)))), /* @__PURE__ */ react_exports.createElement("tbody", null, Boolean(areaId && areaValue) && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, { "data-test": "area-id" }, areaId), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "area-value" }, areaValue)), Boolean(showCoordinates && latitude) && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, null, (0, i18n_exports._)("Latitude")), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "latitude" }, convertDegToDMS(latitude, "latitude"))), Boolean(showCoordinates && longitude) && /* @__PURE__ */ react_exports.createElement("tr", null, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, null, (0, i18n_exports._)("Longitude")), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "longitude" }, convertDegToDMS(longitude, "longitude"))), additionalFields.filter(({ value }) => value && String(value) !== "0").map(({ name, value, color, icon }) => /* @__PURE__ */ react_exports.createElement("tr", { key: (0, id_exports.createDOMID)() }, /* @__PURE__ */ react_exports.createElement(StyledTitleColumn, { "data-test": "field-title" }, color ? /* @__PURE__ */ react_exports.createElement(StyledColorBlock, { "data-test": "field-color", color }) : null, /* @__PURE__ */ react_exports.createElement("span", null, name, isTooltipIconFlagEnabled && icon && ((0, iconUtils_exports.isRemoteIcon)(icon) || (0, iconUtils_exports.isDataURI)(icon)) ? /* @__PURE__ */ react_exports.createElement(StyledIconWrapper, { "data-test": "field-icon" }, /* @__PURE__ */ react_exports.createElement(RemoteIcon_default, { iconURL: icon, width: 16, height: 16 })) : null)), /* @__PURE__ */ react_exports.createElement(StyledValueColumn, { "data-test": "field-value" }, value)))))
362
363
  );
363
364
  };
364
365
  var Tooltip_default = Tooltip;
@@ -473,8 +474,9 @@ var PieSegment = react_exports.memo(
473
474
  );
474
475
  if (end - start === 1) {
475
476
  return /* @__PURE__ */ react_exports.createElement(
476
- "circle",
477
+ BubbleSegment,
477
478
  {
479
+ as: "circle",
478
480
  onClick: handleSegmentClick,
479
481
  cx: radius,
480
482
  cy: radius,
@@ -494,8 +496,9 @@ var PieSegment = react_exports.memo(
494
496
  const y1 = Math.sin(a1);
495
497
  const arc = end - start > 0.5 ? 1 : 0;
496
498
  return /* @__PURE__ */ react_exports.createElement(
497
- "path",
499
+ BubbleSegment,
498
500
  {
501
+ as: "path",
499
502
  onClick: handleSegmentClick,
500
503
  d: `M ${radius} ${radius} L ${radius + radius * x0} ${radius + radius * y0} A ${radius} ${radius} 0 ${arc} 1 ${radius + radius * x1} ${radius + radius * y1} L ${radius} ${radius} A 0 0 0 ${arc} 0 ${radius} ${radius}`,
501
504
  fill: color,
@@ -508,6 +511,10 @@ var PieSegment = react_exports.memo(
508
511
  }
509
512
  );
510
513
  PieSegment.displayName = "MapBubblePieSegment";
514
+ var BubbleSegment = styled_components_default.path`
515
+ transition: 0.2s ease-in-out;
516
+ transition-property: fill, stroke;
517
+ `;
511
518
  var StyledMarkerWrapper = styled_components_default(MarkerWrapper_default)`
512
519
  cursor: pointer;
513
520
  `;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/common/utils/mapUtils.ts", "esm-externals:@splunk/visualization-encoding/utils/types", "esm-externals:@splunk/visualization-encoding/utils/dsl", "esm-externals:@splunk/visualizations-shared/hocUtils", "esm-externals:@splunk/visualizations-shared/JSONSchemaUtils", "esm-externals:react", "esm-externals:styled-components", "esm-externals:lodash", "esm-externals:@splunk/visualizations-shared/iconUtils", "esm-externals:@splunk/visualizations-shared/colorUtils", "esm-externals:@splunk/visualizations-shared/RemoteIcon", "esm-externals:@splunk/visualization-context/FeatureFlagContext", "esm-externals:@splunk/ui-utils/id", "esm-externals:d3-scale", "esm-externals:chroma-js", "esm-externals:@splunk/visualization-color-palettes", "esm-externals:@splunk/visualization-schemas", "../../src/Map/PureMap/MapUtils.ts", "esm-externals:maplibre-gl", "esm-externals:@splunk/react-ui/Popover", "esm-externals:@splunk/ui-utils/i18n", "esm-externals:@splunk/themes", "../../src/Map/PureMap/Tooltip.tsx", "../../src/Map/PureMap/MarkerWrapper.tsx", "../../src/Map/PureMap/BubbleLayer.tsx"],
4
- "sourcesContent": ["import { isNumber } from '@splunk/visualization-encoding/utils/types';\nimport { getFieldsFromDSL } from '@splunk/visualization-encoding/utils/dsl';\nimport { deepMergeWithArrayPrimitiveOverrides } from '@splunk/visualizations-shared/hocUtils';\nimport { pickFieldFromJSONSchema } from '@splunk/visualizations-shared/JSONSchemaUtils';\nimport { GEO_LAT_AND_LONG_FIELD } from '../../Map/PureMap/BubbleLayer';\n\nexport const columnsNullToZeros = (config, dataSources, options) => {\n const { primary } = dataSources;\n const { columns, fields } = primary.data;\n let newColumns = columns;\n const mergedOptions = deepMergeWithArrayPrimitiveOverrides(\n {},\n options,\n pickFieldFromJSONSchema(config.optionsSchema, 'default')\n );\n if (mergedOptions.layers?.[0]?.type === 'bubble') {\n const latitudeField = getFieldsFromDSL(mergedOptions.layers[0].latitude, dataSources)[0] || '';\n const longitudeField = getFieldsFromDSL(mergedOptions.layers[0].longitude, dataSources)[0] || '';\n const stringsFields = getFieldsFromDSL(\"> primary | frameBySeriesTypes('string')\", dataSources);\n const excludedFields = Array.from(\n new Set([\n latitudeField,\n longitudeField,\n 'geobin',\n 'name',\n ...stringsFields,\n ...GEO_LAT_AND_LONG_FIELD,\n ])\n );\n const indicesToEvaluate = new Set(\n fields.reduce((arr, e, i) => {\n const field = typeof e === 'string' ? e : e.name.toString();\n if (!excludedFields.includes(field)) {\n arr.push(i);\n }\n return arr;\n }, [])\n );\n\n newColumns = columns.map((column, i) => {\n if (indicesToEvaluate.has(i)) {\n // sanitize value and convert string to numeric numbers\n return column.map(value => (!value || !isNumber(value) ? 0 : +value));\n }\n return column;\n });\n }\n\n const modifiedDatasources = {\n ...dataSources,\n primary: {\n ...primary,\n data: {\n ...primary.data,\n columns: newColumns,\n },\n },\n };\n\n return modifiedDatasources;\n};\n", "\nimport * as defaultImport from \"@splunk/visualization-encoding/utils/types\";\nexport * from \"@splunk/visualization-encoding/utils/types\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-encoding/utils/dsl\";\nexport * from \"@splunk/visualization-encoding/utils/dsl\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/hocUtils\";\nexport * from \"@splunk/visualizations-shared/hocUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/JSONSchemaUtils\";\nexport * from \"@splunk/visualizations-shared/JSONSchemaUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"react\";\nexport * from \"react\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"styled-components\";\nexport * from \"styled-components\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"lodash\";\nexport * from \"lodash\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/iconUtils\";\nexport * from \"@splunk/visualizations-shared/iconUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/colorUtils\";\nexport * from \"@splunk/visualizations-shared/colorUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/RemoteIcon\";\nexport * from \"@splunk/visualizations-shared/RemoteIcon\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-context/FeatureFlagContext\";\nexport * from \"@splunk/visualization-context/FeatureFlagContext\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/ui-utils/id\";\nexport * from \"@splunk/ui-utils/id\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"d3-scale\";\nexport * from \"d3-scale\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"chroma-js\";\nexport * from \"chroma-js\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-color-palettes\";\nexport * from \"@splunk/visualization-color-palettes\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-schemas\";\nexport * from \"@splunk/visualization-schemas\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "import { forEach, sum, isNumber, min as lodashMin, max as lodashMax, get, isEqual, isObject } from 'lodash';\nimport { LngLatBoundsLike } from 'maplibre-gl';\nimport { scalePow } from 'd3-scale';\nimport chroma from 'chroma-js';\nimport type { MapContextInterface, BaseTileConfig } from '@splunk/visualization-context/MapContext';\nimport { isColor } from '@splunk/visualizations-shared/colorUtils';\nimport { VIZ_CATEGORICAL } from '@splunk/visualization-color-palettes';\nimport { isNumber as isNumberUtil } from '@splunk/visualization-encoding/utils/types';\nimport type { GeoJsonDataType } from '@splunk/visualizations-shared/mapUtils';\nimport { LAYER_TYPE } from '@splunk/visualization-schemas';\n\nexport const MAX_LATITUDE = 90;\nexport const MIN_LATITUDE = -90;\nexport const MAX_LONGITUDE = 180;\nexport const MIN_LONGITUDE = -180;\nexport const DEFAULT_RESULT_LIMIT = 1000;\nexport const DEFAULT_CLUSTER_COLOR = '#909090';\nexport const DEFAULT_SERIES_COLORS = VIZ_CATEGORICAL;\n// MapLibre requires a map style specification number which is always 8\nexport const MAP_STYLE_VERSION_NUMBER = 8;\n// currently using one [min, max] value set for bubbles across all zoom levels\nexport const MIN_BUBBLE_RADIUS = 7.11; // 10px\nexport const MAX_BUBBLE_RADIUS = 45.26; // 85px\nexport const DEFAULT_OPACITY = 0.8;\nconst LONGITUDE = 'longitude';\nconst LATITUDE = 'latitude';\nexport type MaybeBaseTileConfig = BaseTileConfig | Record<string, never>;\ninterface GenericLayerType {\n type: string;\n latitude: number[];\n longitude: number[];\n dataColors?: string[] | '';\n seriesColors: string[];\n additionalTooltipFields?: string[];\n tooltipHeaderField?: string[];\n resultLimit: number;\n metadata?: Array<{ [key: string]: number | string }>;\n}\n\nexport interface MarkerLayerType extends GenericLayerType {\n type: LAYER_TYPE.Marker;\n}\n\nexport interface BubbleLayerType extends GenericLayerType {\n type: LAYER_TYPE.Bubble;\n bubbleSize?: number[][] | number[];\n bubbleSizeFields: string[];\n dataValuesField?: string;\n tooltipHeaderFieldName?: string;\n geobin?: string[];\n icon?: string[];\n tooltipFieldIcons?: string;\n}\n\ninterface BubbleLayerDatumType {\n zoom: number;\n values: number[];\n sanitizedValues: number[];\n coordinates: number[];\n}\n\nexport interface BubbleLayerDataType {\n data: BubbleLayerDatumType[];\n dataRange: number[];\n isPie: boolean;\n resultLimit: number;\n bubbleSizeFields: string[];\n}\n\nexport interface ChoroplethLayerType {\n type: LAYER_TYPE.Choropleth;\n areaIds: string[];\n areaValues: number[];\n dataColors: string[];\n additionalTooltipFields?: string[];\n tooltipHeaderField?: string[];\n geom?: GeoJsonDataType[] | null;\n resultLimit?: number;\n metadata?: Array<{ [key: string]: number | string | GeoJsonDataType }>;\n source?: string;\n width?: string | number;\n height?: string | number;\n choroplethEmptyAreaColor?: string;\n choroplethStrokeColor?: string;\n choroplethOpacity?: number;\n}\n\nexport interface MapLayerClickPayloadType {\n name?: string;\n value?: string | number;\n /* cell values of all cells of clicked row with the field and value - in shape row.<field>.value */\n [key: string]: string | number;\n}\n\nexport type ClusterLayerType = BubbleLayerType | MarkerLayerType;\nexport type LayerType = ClusterLayerType | ChoroplethLayerType;\n/**\n * Construct a tile preset {key: config} by combining the default + custom tile configs\n * Also returns the default tile config for each theme - light/dark\n * @param {MapContextInterface} args\n * @param {BaseTileConfig[]} args.defaultTileConfig\n * @param {BaseTileConfig[]} args.customTileConfig\n * @returns {Object} tile preset\n */\nexport const getTilePreset = ({\n defaultTileConfig = [],\n customTileConfig = [],\n}: MapContextInterface): {\n tilePreset: Record<string, BaseTileConfig>;\n defaultTileLight: MaybeBaseTileConfig;\n defaultTileDark: MaybeBaseTileConfig;\n} => {\n const tilePreset: Record<string, BaseTileConfig> = {};\n let defaultTileLight: MaybeBaseTileConfig = {};\n let defaultTileDark: MaybeBaseTileConfig = {};\n const tileConfigs = [...defaultTileConfig, ...customTileConfig];\n forEach(tileConfigs, tileConfig => {\n const key = tileConfig?.key;\n if (!key) {\n return;\n }\n const updatedConfig: BaseTileConfig = {\n ...tileConfig,\n version: MAP_STYLE_VERSION_NUMBER,\n };\n tilePreset[key] = updatedConfig;\n });\n\n if (defaultTileConfig.length > 0) {\n defaultTileLight =\n defaultTileConfig.find(config => config.theme === 'light') ??\n defaultTileConfig.find(config => config.theme === undefined) ??\n {};\n defaultTileDark =\n defaultTileConfig.find(config => config.theme === 'dark') ??\n defaultTileConfig.find(config => config.theme === undefined) ??\n {};\n }\n\n return { tilePreset, defaultTileLight, defaultTileDark };\n};\n\n/**\n * Check if baseLayerTileServer is in tilePreset and config matches current theme, if yes, return.\n * If no, construct a mapStyle with baseLayerTilerServer and baseLayerTileServerType\n * Else return default tile config based on current theme\n * @param {Object} args\n * @param {BaseTileConfig[]} args.tilePreset\n * @param {String} args.baseLayerTilerServer\n * @param {String} args.baseLayerTileServerType\n * @param {String} args.colorScheme\n * @param {BaseTileConfig} args.defaultTileDark\n * @param {BaseTileConfig} args.defaultTileLight\n * @returns {BaseTileConfig} mapStyle\n */\nexport const getMapStyle = ({\n showBaseLayer,\n baseLayerTileServer = '',\n baseLayerTileServerType = '',\n tilePreset = {},\n colorScheme = 'light',\n defaultTileLight = {},\n defaultTileDark = {},\n}: {\n showBaseLayer: boolean;\n baseLayerTileServer?: string;\n baseLayerTileServerType?: string;\n tilePreset?: Record<string, BaseTileConfig>;\n colorScheme?: string;\n defaultTileLight?: MaybeBaseTileConfig;\n defaultTileDark?: MaybeBaseTileConfig;\n}): MaybeBaseTileConfig => {\n if (!showBaseLayer) {\n return {\n name: 'empty-base-layer',\n key: 'empty-base-layer',\n version: MAP_STYLE_VERSION_NUMBER,\n sources: {\n 'base-tiles': {\n type: 'raster',\n tiles: [\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n ],\n tileSize: 256,\n },\n },\n layers: [\n {\n id: 'base-layer',\n type: 'raster',\n source: 'base-tiles',\n minzoom: 0,\n maxzoom: 22,\n },\n ],\n };\n }\n\n if (\n baseLayerTileServer &&\n tilePreset[baseLayerTileServer] &&\n (!tilePreset[baseLayerTileServer].theme || tilePreset[baseLayerTileServer].theme === colorScheme)\n ) {\n return tilePreset[baseLayerTileServer];\n }\n\n if (baseLayerTileServer && baseLayerTileServerType) {\n let tiles: string[] = [];\n /**\n * Tile Server URLs (eg: http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png) can specify the variable {s} which refers to a subdomain\n * Subdomains are used to help with browser parallel requests per domain limitation. These subdomains are typically single letters 'a', 'b' and 'c'\n * Refer to https://leafletjs.com/SlavaUkraini/reference.html#tilelayer and https://wiki.openstreetmap.org/wiki/Tile_servers\n */\n if (/^(https?):\\/\\/{[sS]}\\./.exec(baseLayerTileServer)) {\n /**\n * sXML (Leaflet) allows users to define their own tile server URLs + list of available subdomains\n * In order to preserve this behavior during conversion to splunk.map,\n * if the variable {s} or {S} is detected, replace it with 'a', 'b' and 'c' - default values for subdomains\n */\n tiles = [\n baseLayerTileServer.replace(/{[sS]}/, 'a'),\n baseLayerTileServer.replace(/{[sS]}/, 'b'),\n baseLayerTileServer.replace(/{[sS]}/, 'c'),\n ];\n } else {\n tiles = [baseLayerTileServer];\n }\n const mapStyle: BaseTileConfig = {\n name: baseLayerTileServer,\n key: baseLayerTileServer,\n version: MAP_STYLE_VERSION_NUMBER,\n sources: {\n 'base-tiles': {\n type: baseLayerTileServerType,\n tiles,\n tileSize: 256,\n },\n },\n layers: [\n {\n id: 'base-layer',\n type: 'raster',\n source: 'base-tiles',\n minzoom: 0,\n maxzoom: 24, // https://maplibre.org/maplibre-gl-js-docs/api/map/\n },\n ],\n };\n return mapStyle;\n }\n\n // if tile server is not present in the preset AND we can't construct a mapStyle, fall back on defaults\n return colorScheme === 'light' ? defaultTileLight : defaultTileDark;\n};\n\nexport interface ZoomConstraints {\n minZoom: number;\n maxZoom: number;\n}\n\nexport const getZoomConstraintsFromTileConfig = (\n tileConfig: BaseTileConfig,\n baseLayerTileServer?: string\n): ZoomConstraints => {\n const { sources, layers } = tileConfig;\n let matchedBaseLayerTileServer = false;\n // check sources for minzoom maxzoom first\n const sourceKeys = Object.keys(sources);\n // eslint-disable-next-line\n for (const key of sourceKeys) {\n const source = sources[key] as { [key: string]: unknown };\n const { minzoom, maxzoom } = source;\n const tiles = Array.isArray(source?.tiles) ? (source.tiles as string[]) : [];\n if (baseLayerTileServer && tiles.includes(baseLayerTileServer)) {\n matchedBaseLayerTileServer = true;\n }\n if (\n ((baseLayerTileServer && matchedBaseLayerTileServer) || !baseLayerTileServer) &&\n isNumber(minzoom) &&\n isNumber(maxzoom)\n ) {\n return {\n minZoom: minzoom,\n maxZoom: maxzoom,\n };\n }\n }\n // then check layers\n // eslint-disable-next-line\n for (const layer of layers) {\n const { minzoom, maxzoom } = layer;\n if (\n ((baseLayerTileServer && matchedBaseLayerTileServer) || !baseLayerTileServer) &&\n isNumber(minzoom) &&\n isNumber(maxzoom)\n ) {\n return {\n minZoom: minzoom,\n maxZoom: maxzoom,\n };\n }\n }\n // Maplibre default - would reset previous min/maxZoom https://maplibre.org/maplibre-gl-js-docs/api/map/\n return {\n minZoom: 0,\n maxZoom: 24,\n };\n};\n\nexport const isBaseTileConfig = (config: MaybeBaseTileConfig): config is BaseTileConfig =>\n Boolean(config && 'name' in config && 'key' in config && 'sources' in config && 'layers' in config);\n\nexport const getZoomLevelFromGeobin = (geobinStr: string): number => {\n if (!geobinStr) {\n return null;\n }\n // geostats cmds return geobin with zoom level 0-18, 0-99 in the geobinPattern covers the range\n const geobinPattern = /bin_id_zl_(\\d{1,2})_y_/g;\n const match = geobinPattern.exec(geobinStr);\n return (match?.length && parseInt(match[1], 10)) ?? null;\n};\n\n// Bubble colors - static\nexport const getStaticColors = (colorCount: number, colorArray: string[]): string[] => {\n if (colorCount < 0 || !colorCount) {\n return [DEFAULT_CLUSTER_COLOR];\n }\n if (!colorArray?.length) {\n return [...Array(colorCount).keys()].map(i => DEFAULT_SERIES_COLORS[i]);\n }\n // loop through colorArray to pick the first $colorCount colors\n // start from begining again if colorCount > colorArray.length\n return [...Array(colorCount).keys()].map(i =>\n isColor(colorArray[i % colorArray.length]) ? colorArray[i % colorArray.length] : DEFAULT_CLUSTER_COLOR\n );\n};\n\n// Bubble size\nexport const matchBubbleSize = (dataRange: number[], data: number): any => {\n const size = scalePow().exponent(0.2).domain(dataRange).range([MIN_BUBBLE_RADIUS, MAX_BUBBLE_RADIUS])(\n data\n );\n\n if (size > MAX_BUBBLE_RADIUS) {\n return MAX_BUBBLE_RADIUS;\n }\n if (size < MIN_BUBBLE_RADIUS) {\n return MIN_BUBBLE_RADIUS;\n }\n return size;\n};\n\nexport const transposeArray = (array: number[][]): number[][] => {\n if (!array?.length || !array[0]?.length) {\n return [];\n }\n return array[0].map((_, i) => array.map(row => row[i]));\n};\n\n// sanitize values: update all null, undefined, or negative values to 0\nexport const sanitizeValues = (values: number[] | number[][]) => {\n // null / undefined\n if (!values) {\n return 0;\n }\n // number\n if (!Array.isArray(values)) {\n return values > 0 ? values : 0;\n }\n // array\n return values.map(arr => sanitizeValues(arr));\n};\n\n// eslint-disable-next-line consistent-return\nexport const sortByValuesField = (bubbleLayer: BubbleLayerType) => {\n const { bubbleSizeFields, dataValuesField } = bubbleLayer;\n\n // Find the index of dataValuesField in fields\n const index = bubbleSizeFields.indexOf(dataValuesField);\n if (index === -1) return bubbleLayer; // If not found, return as is\n\n // Move dataValuesField and corresponding sizes to the first position\n bubbleLayer.bubbleSizeFields.unshift(bubbleLayer.bubbleSizeFields.splice(index, 1)[0]);\n bubbleLayer.bubbleSize.unshift(bubbleLayer.bubbleSize.splice(index, 1)[0] as number & number[]);\n};\n\nexport const bakeBubbleData = (layer: BubbleLayerType): BubbleLayerDataType => {\n if (\n !layer?.bubbleSize?.length ||\n !layer?.geobin?.length ||\n !layer?.latitude?.length ||\n !layer?.longitude?.length\n ) {\n return null;\n }\n // if bubbleSize is passed as an array of single number array (data series)\n // e.g. [value0, value1, ...]\n // format each value as an array to unify data operations for data series and frames\n const sanitizedBubbleSize = sanitizeValues(layer.bubbleSize);\n let transposedBubbleSize: number[][];\n let transposedSanitizedBubbleSize: number[][];\n let isPie = false;\n // format array if bubbleSize is passed as an array of array (data frame)\n if (Array.isArray(layer.bubbleSize[0])) {\n // one-time array transpose,\n // e.g. from [column0data, column0data] (multi series)\n // to [[column0datum0, column1datum0], [column0datum1, column1data1], ...]\n // or e.g. from [column0data] (single series)\n // to [[column0data]]\n // for easy access of values at each geo location,\n // and min max pie size computation\n transposedBubbleSize = transposeArray(layer.bubbleSize as number[][]);\n transposedSanitizedBubbleSize = transposeArray(sanitizedBubbleSize);\n // if multiple series in the dataframe, set isPie to true\n if (layer.bubbleSize.length > 1) {\n isPie = true;\n // when dynamic coloring is enabled,\n // set the configured dataValues field as the first field\n // to apply dynamic colors only to the first pie slice.\n if (layer.dataValuesField && !!layer.dataColors) {\n sortByValuesField(layer); // here\n }\n }\n } else {\n transposedBubbleSize = layer.bubbleSize.map(n => [n]);\n transposedSanitizedBubbleSize = sanitizedBubbleSize.map(n => [n]);\n }\n if (!transposedBubbleSize?.length) {\n return null;\n }\n const data = layer.latitude\n .map((lat, i) => ({\n zoom: getZoomLevelFromGeobin(layer.geobin[i]),\n values: transposedBubbleSize[i],\n sanitizedValues: transposedSanitizedBubbleSize[i],\n coordinates: [layer.longitude[i], lat],\n metadata: layer.metadata ? layer.metadata[i] : {},\n }))\n .filter(d => Boolean(d.values));\n\n // compute the min/max value to encode min/max pie or bubble size\n let min = sum(transposedSanitizedBubbleSize[0]);\n let max = sum(transposedSanitizedBubbleSize[1]);\n transposedSanitizedBubbleSize.forEach(row => {\n const bubbleSize = sum(row);\n max = bubbleSize > max ? bubbleSize : max;\n min = bubbleSize < min ? bubbleSize : min;\n });\n return {\n data,\n dataRange: [min, max],\n isPie,\n resultLimit: layer.resultLimit,\n bubbleSizeFields: layer.bubbleSizeFields,\n };\n};\n\nexport const isValidLatLon = (latlon: Array<number | string>): boolean => {\n if (!latlon || !Array.isArray(latlon) || latlon.length !== 2) {\n return false;\n }\n const [lat, lon] = latlon;\n if (!isNumberUtil(lat) || !(Number(lat) >= MIN_LATITUDE && Number(lat) <= MAX_LATITUDE)) {\n return false;\n }\n if (!isNumberUtil(lon) || !(Number(lon) >= MIN_LONGITUDE && Number(lon) <= MAX_LONGITUDE)) {\n return false;\n }\n return true;\n};\n\nexport const getChoroplethValues = (field: string, choroplethLayer: ChoroplethLayerType): number[] => {\n if (!Array.isArray(choroplethLayer.geom) || choroplethLayer.geom.length === 0) {\n return [];\n }\n const limit = choroplethLayer.resultLimit ?? DEFAULT_RESULT_LIMIT;\n const slicedGeomList = choroplethLayer.geom.slice(0, limit);\n const flatCoordinates = slicedGeomList.flatMap(geomObject => {\n if (!geomObject) {\n return [];\n }\n if (geomObject.type === 'MultiPolygon') {\n return geomObject.coordinates.flat(2);\n }\n if (geomObject.type === 'Polygon') {\n return geomObject.coordinates.flat();\n }\n return [];\n });\n return flatCoordinates.map(coord => coord[field === LONGITUDE ? 0 : 1]);\n};\n\n/**\n * Returns a list of all lat or lon coordinates used in a specified layer\n * @param {LayerType[]} layer\n * @param {string} field\n * @returns {number[]} list of lat coordinates or lon coordinates\n */\nconst getLatOrLonCoordinates = (layer: LayerType, field: string): number[] => {\n const getClusterValues = (clusterLayer: ClusterLayerType): number[] =>\n get(clusterLayer, field, []).slice(\n 0,\n clusterLayer.type === LAYER_TYPE.Marker && clusterLayer.resultLimit\n ? clusterLayer.resultLimit\n : DEFAULT_RESULT_LIMIT\n );\n return layer.type === LAYER_TYPE.Choropleth ? getChoroplethValues(field, layer) : getClusterValues(layer);\n};\n\n/**\n * Returns the min and max LongLat pairs to determine the layer boundaries to fit all markers/bubbles\n * @param {LayerType[]} layers\n * @returns {LngLatBoundsLike}\n */\nexport const getGlobalLayerBoundaries = (layers: LayerType[]): LngLatBoundsLike => {\n const isLayerValid = (field: string): boolean =>\n layers.every(layer => layer[field] || (layer as ChoroplethLayerType).geom);\n const getDefaultMax = (field: string) => (field === LONGITUDE ? MAX_LONGITUDE : MAX_LATITUDE);\n const getDefaultMin = (field: string) => (field === LONGITUDE ? MIN_LONGITUDE : MIN_LATITUDE);\n\n if (!layers || !Array.isArray(layers) || !layers.length) {\n return null;\n }\n\n const getMin = (field: string): number => {\n if (!isLayerValid(field)) {\n return getDefaultMin(field);\n }\n return layers.reduce((prevVal, layer) => {\n const coordinatesNumArr = getLatOrLonCoordinates(layer, field).map(x => +x);\n return lodashMin([prevVal, ...coordinatesNumArr]);\n }, getDefaultMax(field));\n };\n\n const getMax = (field: string): number => {\n if (!isLayerValid(field)) {\n return getDefaultMax(field);\n }\n return layers.reduce((prevVal, layer) => {\n const coordinatesNumArr = getLatOrLonCoordinates(layer, field).map(Number);\n return lodashMax([prevVal, ...coordinatesNumArr]);\n }, getDefaultMin(field));\n };\n\n return [\n [getMin(LONGITUDE), getMin(LATITUDE)],\n [getMax(LONGITUDE), getMax(LATITUDE)],\n ];\n};\n\nexport const formatTooltipFieldValue = (value: unknown): string | number => {\n if (value === null || value === undefined) {\n return '';\n }\n if (typeof value === 'string' || typeof value === 'number') {\n return value;\n }\n return JSON.stringify(value);\n};\n\nexport const getScaledOpacities = (colors: string[], cfgOpacity: number): number[] => {\n // extract opacity information from 8 digit hex codes\n const opacities = colors?.map(color => (color?.length === 9 ? (chroma(color).alpha() ?? 1) : 1));\n // opacity cannot be greater than configured opacity\n return opacities?.map(opacity => opacity * cfgOpacity);\n};\n\nexport const compareBaseStyles = (curr, next): boolean => {\n const currBaseLayer = curr?.layers?.find(layer => layer?.id === 'base-layer');\n const nextBaseLayer = next?.layers?.find(layer => layer?.id === 'base-layer');\n const currBaseSource = get(curr?.sources, (currBaseLayer?.source as string) ?? '');\n const nextBaseSource = get(next?.sources, (nextBaseLayer?.source as string) ?? '');\n\n if (!currBaseLayer || !nextBaseLayer || !currBaseSource || !nextBaseSource) {\n return false;\n }\n\n return isEqual(currBaseLayer, nextBaseLayer) && isEqual(currBaseSource, nextBaseSource);\n};\n\nexport const formatMetadata = (\n choroplethLayer: ChoroplethLayerType,\n i: number\n): { [key: string]: string } => {\n if (!choroplethLayer?.areaIds || !choroplethLayer?.areaValues) return {};\n if (i >= choroplethLayer.areaIds.length) return {};\n\n const metadata = choroplethLayer.metadata ? choroplethLayer.metadata[i] : {};\n const name = choroplethLayer.areaIds[i];\n const value = choroplethLayer.areaValues[i];\n const base = { name, value: String(value) };\n\n return Object.keys(metadata).reduce((result, curr) => {\n const key = `row.${curr}.value`;\n const val = isObject(metadata[curr]) ? JSON.stringify(metadata[curr]) : String(metadata[curr]);\n return { ...result, [key]: val };\n }, base);\n};\n", "\nimport * as defaultImport from \"maplibre-gl\";\nexport * from \"maplibre-gl\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/react-ui/Popover\";\nexport * from \"@splunk/react-ui/Popover\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/ui-utils/i18n\";\nexport * from \"@splunk/ui-utils/i18n\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/themes\";\nexport * from \"@splunk/themes\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "import * as React from 'react';\nimport styled from 'styled-components';\nimport Popover from '@splunk/react-ui/Popover';\nimport { isRemoteIcon, isDataURI } from '@splunk/visualizations-shared/iconUtils';\nimport { _ } from '@splunk/ui-utils/i18n';\nimport FeatureFlagContext from '@splunk/visualization-context/FeatureFlagContext';\nimport RemoteIcon from '@splunk/visualizations-shared/RemoteIcon';\nimport { variables } from '@splunk/themes';\nimport { createDOMID } from '@splunk/ui-utils/id';\n\nconst StyledPopover = styled(Popover)`\n width: 250px;\n font-size: 12px;\n`;\n\nconst StyledTable = styled.table`\n margin: 2px 6px 2px 6px;\n table-layout: fixed;\n width: calc(100% - 12px);\n`;\n\nconst StyledTitleColumn = styled.td`\n opacity: 0.85;\n`;\n\nconst StyledValueColumn = styled.td`\n text-align: right;\n`;\n\nconst StyledColorBlock = styled.div`\n background-color: ${props => props.color};\n display: inline-block;\n margin-right: 4px;\n border-radius: 2px;\n width: 6px;\n height: 11px;\n transform: translateY(1px);\n`;\n\nconst StyledFieldLabel = styled.span`\n display: inline-block;\n white-space: nowrap;\n`;\n\nconst StyledIconWrapper = styled.span`\n margin-left: 4px;\n display: inline-block;\n vertical-align: middle;\n`;\n\nconst StyledTooltipHeader = styled.thead`\n th {\n height: 16px;\n color: ${variables.contentColorActive};\n padding: 0;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 100%;\n }\n`;\n\nexport const convertDegToDMS = (decimalDegree: number, type: 'latitude' | 'longitude'): string => {\n const truncate = n => (n > 0 ? Math.floor(n) : Math.ceil(n));\n const absoluteDegree = Math.abs(decimalDegree);\n let degrees = truncate(absoluteDegree);\n let minutes = truncate((absoluteDegree - degrees) * 60);\n let seconds = Math.round((absoluteDegree - degrees - minutes / 60) * 3600);\n if (seconds === 60) {\n minutes += 1;\n seconds = 0;\n }\n if (minutes === 60) {\n degrees += 1;\n minutes = 0;\n }\n let direction: string;\n if (type === 'longitude') {\n direction = decimalDegree < 0 ? 'W' : 'E';\n } else if (type === 'latitude') {\n direction = decimalDegree < 0 ? 'S' : 'N';\n }\n return `${degrees}\u00B0 ${minutes}' ${seconds}\" ${direction}`;\n};\n\nexport interface TooltipProps {\n open?: boolean;\n anchor?: HTMLElement;\n latitude?: number;\n longitude?: number;\n areaId?: string;\n areaValue?: number;\n additionalFields?: Array<{ name: string; value: number | string; color?: string; icon?: string }>;\n showCoordinates?: boolean;\n tooltipHeader?: string;\n}\n// only want latitude/longitude for marker and bubble\n// omit for choropleth, and put areaid, areavalue instead\nconst Tooltip = ({\n open,\n anchor,\n latitude,\n longitude,\n areaId,\n areaValue,\n additionalFields = [],\n showCoordinates = true,\n tooltipHeader = null,\n}: TooltipProps): JSX.Element => {\n const featureFlagContext = React.useContext<FeatureFlagContext>(FeatureFlagContext);\n const isTooltipIconFlagEnabled = Boolean(\n featureFlagContext && featureFlagContext.visualizations_enableTooltipIcon\n );\n return (\n <StyledPopover\n open={open}\n animation={false}\n anchor={anchor}\n data-test=\"map-marker-tooltip\"\n defaultPlacement=\"above\"\n >\n <StyledTable>\n {tooltipHeader && (\n <StyledTooltipHeader data-test=\"tooltip-header\">\n <tr>\n <th colSpan={2}>\n <span data-test=\"tooltip-header-value\">{tooltipHeader}</span>\n </th>\n </tr>\n </StyledTooltipHeader>\n )}\n <tbody>\n {areaId && areaValue && (\n <tr>\n <StyledTitleColumn data-test=\"area-id\">{areaId}</StyledTitleColumn>\n <StyledValueColumn data-test=\"area-value\">{areaValue}</StyledValueColumn>\n </tr>\n )}\n {Boolean(showCoordinates && latitude) && (\n <tr>\n <StyledTitleColumn>{_('Latitude')}</StyledTitleColumn>\n <StyledValueColumn data-test=\"latitude\">\n {convertDegToDMS(latitude, 'latitude')}\n </StyledValueColumn>\n </tr>\n )}\n {Boolean(showCoordinates && longitude) && (\n <tr>\n <StyledTitleColumn>{_('Longitude')}</StyledTitleColumn>\n <StyledValueColumn data-test=\"longitude\">\n {convertDegToDMS(longitude, 'longitude')}\n </StyledValueColumn>\n </tr>\n )}\n {additionalFields\n .filter(({ value }) => value && String(value) !== '0')\n .map(({ name, value, color, icon }) => (\n <tr key={createDOMID()}>\n <StyledTitleColumn data-test=\"field-title\">\n {color ? (\n <StyledColorBlock data-test=\"field-color\" color={color} />\n ) : null}\n <StyledFieldLabel>\n {name}\n {isTooltipIconFlagEnabled &&\n icon &&\n (isRemoteIcon(icon) || isDataURI(icon)) ? (\n <StyledIconWrapper data-test=\"field-icon\">\n <RemoteIcon iconURL={icon} width={16} height={16} />\n </StyledIconWrapper>\n ) : null}\n </StyledFieldLabel>\n </StyledTitleColumn>\n <StyledValueColumn data-test=\"field-value\">{value}</StyledValueColumn>\n </tr>\n ))}\n </tbody>\n </StyledTable>\n </StyledPopover>\n );\n};\n\nexport default Tooltip;\n", "import type { Map } from 'maplibre-gl';\nimport { Marker } from 'maplibre-gl';\nimport * as React from 'react';\nimport type { TooltipProps } from './Tooltip';\nimport Tooltip from './Tooltip';\n\nexport interface MarkerWrapperProps extends React.HTMLAttributes<HTMLDivElement> {\n latitude: number;\n longitude: number;\n areaId?: string;\n areaValue?: number;\n additionalFields?: TooltipProps['additionalFields'];\n tooltipHeader?: TooltipProps['tooltipHeader'];\n map: React.MutableRefObject<Map>;\n isChoroplethTooltipOpen?: boolean;\n showCoordinates?: boolean;\n}\n\nconst MarkerWrapper = ({\n longitude,\n latitude,\n areaId,\n areaValue,\n additionalFields = [],\n tooltipHeader = null,\n map,\n isChoroplethTooltipOpen,\n children,\n showCoordinates = true,\n ...otherProps\n}: MarkerWrapperProps): JSX.Element => {\n const container = React.useRef<HTMLDivElement>();\n const marker = React.useRef<Marker>();\n const [isTooltipOpen, setTooltipOpenStatus] = React.useState(false);\n\n const isChoroplethTooltip = React.useCallback(\n () => isChoroplethTooltipOpen !== undefined,\n [isChoroplethTooltipOpen]\n );\n\n const openTooltip = React.useCallback(() => setTooltipOpenStatus(true), []);\n const closeTooltip = React.useCallback(() => setTooltipOpenStatus(false), []);\n\n const cleanupMarker = React.useCallback(() => {\n if (marker.current) {\n marker.current.remove();\n marker.current = undefined;\n }\n }, []);\n\n React.useEffect(() => {\n try {\n if (marker.current) {\n marker.current.setLngLat([longitude, latitude]);\n } else {\n marker.current = new Marker({ element: container.current });\n marker.current.setLngLat([longitude, latitude]);\n marker.current.addTo(map.current);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(error);\n cleanupMarker();\n }\n }, [latitude, longitude, map]);\n\n React.useEffect(() => cleanupMarker, []);\n const filteredAdditionalFields = additionalFields.filter(({ value }) => value && String(value) !== '0');\n const showTooltip = showCoordinates || filteredAdditionalFields.length || (areaId && areaValue);\n return (\n <div style={{ visibility: isChoroplethTooltip() ? 'hidden' : 'visible' }}>\n <div\n style={{\n visibility: isChoroplethTooltip() ? 'hidden' : 'visible',\n }}\n ref={container}\n data-test=\"map-marker\"\n onMouseOver={openTooltip}\n onMouseLeave={closeTooltip}\n onFocus={openTooltip}\n onBlur={closeTooltip}\n {...otherProps}\n >\n {children}\n </div>\n <div>\n {showTooltip && (\n <Tooltip\n open={isChoroplethTooltip() ? isChoroplethTooltipOpen : isTooltipOpen}\n anchor={container.current}\n latitude={isChoroplethTooltip() ? null : latitude}\n longitude={isChoroplethTooltip() ? null : longitude}\n areaId={areaId}\n areaValue={areaValue}\n additionalFields={additionalFields}\n showCoordinates={showCoordinates}\n tooltipHeader={tooltipHeader}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport default MarkerWrapper;\n", "import * as React from 'react';\nimport styled from 'styled-components';\nimport type { Map } from 'maplibre-gl';\nimport { sum } from 'lodash';\nimport { isRemoteIcon, isDataURI } from '@splunk/visualizations-shared/iconUtils';\nimport { isColor } from '@splunk/visualizations-shared/colorUtils';\nimport RemoteIcon from '@splunk/visualizations-shared/RemoteIcon';\nimport FeatureFlagContext from '@splunk/visualization-context/FeatureFlagContext';\nimport { createDOMID } from '@splunk/ui-utils/id';\nimport {\n bakeBubbleData,\n BubbleLayerType,\n DEFAULT_SERIES_COLORS,\n DEFAULT_RESULT_LIMIT,\n DEFAULT_CLUSTER_COLOR,\n getStaticColors,\n matchBubbleSize,\n} from './MapUtils';\nimport MarkerWrapper from './MarkerWrapper';\nimport type { TooltipProps } from './Tooltip';\n\nexport const GEO_BOUND_PREFIX = '_geo_bounds_';\nexport const GEO_LAT_AND_LONG_FIELD = ['_geo_long_field', '_geo_lat_field'];\nexport const ICON_DISPLAY_CUTOFF = 16;\nexport interface PieSegmentProps {\n start: number;\n end: number;\n radius: number;\n color: string;\n themeColor: string;\n segmentMetadata?: { name: string; value: number; color: string };\n handleBubbleClick?: (e: Event, name: string, count: number) => void;\n}\n\nexport const PieSegment = React.memo(\n ({\n start,\n end,\n radius,\n color,\n themeColor,\n segmentMetadata,\n handleBubbleClick,\n }: PieSegmentProps): JSX.Element => {\n const { name, value } = segmentMetadata ?? {};\n const handleSegmentClick = React.useCallback(\n e => {\n handleBubbleClick(e, name, value);\n },\n [name, value, handleBubbleClick]\n );\n\n if (end - start === 1) {\n return (\n <circle\n onClick={handleSegmentClick}\n cx={radius}\n cy={radius}\n r={radius}\n fill={color}\n fillOpacity={0.5}\n strokeWidth={1.5}\n stroke={color}\n />\n );\n }\n const a0 = 2 * Math.PI * (start - 0.25);\n const a1 = 2 * Math.PI * (end - 0.25);\n const x0 = Math.cos(a0);\n const y0 = Math.sin(a0);\n const x1 = Math.cos(a1);\n const y1 = Math.sin(a1);\n const arc = end - start > 0.5 ? 1 : 0;\n\n return (\n <path\n onClick={handleSegmentClick}\n d={`M ${radius} ${radius} L ${radius + radius * x0} ${\n radius + radius * y0\n } A ${radius} ${radius} 0 ${arc} 1 ${radius + radius * x1} ${\n radius + radius * y1\n } L ${radius} ${radius} A 0 0 0 ${arc} 0 ${radius} ${radius}`}\n fill={color}\n fillOpacity={0.8}\n stroke={themeColor}\n strokeWidth={2}\n strokeOpacity={0.3}\n />\n );\n }\n);\n\nPieSegment.displayName = 'MapBubblePieSegment';\n\nconst StyledMarkerWrapper = styled(MarkerWrapper)`\n cursor: pointer;\n`;\n\nexport interface BubbleProps {\n originalValues: number[];\n valueRange: number[];\n colors: string[];\n themeColor: string;\n isPie: boolean;\n latitude: number;\n longitude: number;\n bubbleSize: Required<TooltipProps['additionalFields'][number] & { value: number }>[];\n additionalFields?: TooltipProps['additionalFields'];\n tooltipHeader?: TooltipProps['tooltipHeader'];\n map: React.MutableRefObject<Map>;\n handleMapClick?: any;\n icon?: string;\n showCoordinates?: boolean;\n}\n\nexport const Bubble = React.memo(\n ({\n originalValues,\n valueRange,\n colors,\n themeColor,\n isPie,\n latitude,\n longitude,\n bubbleSize,\n additionalFields = [],\n tooltipHeader = null,\n map,\n handleMapClick,\n icon,\n showCoordinates,\n }: BubbleProps): JSX.Element => {\n const featureFlagContext = React.useContext<FeatureFlagContext>(FeatureFlagContext);\n const isBubbleMapIconFlagEnabled = Boolean(\n featureFlagContext && featureFlagContext.visualizations_enableBubbleMapIcon\n );\n\n const onBubbleClick = React.useCallback(\n (e, name, value) => {\n handleMapClick(e, name, value);\n e.stopPropagation();\n },\n [handleMapClick]\n );\n\n // sanitize values\n const allZeros = originalValues.every(v => v === 0);\n const values = originalValues.map(v => (v > 0 ? v : 0));\n const total = values.reduce((totalValue, v) => totalValue + v, 0);\n const radius = matchBubbleSize(valueRange, total);\n\n const bubble = React.useMemo(() => {\n if (allZeros || !originalValues.length) return null;\n\n const offsets: number[] = [];\n let runningTotal = 0;\n values.forEach(count => {\n offsets.push(runningTotal);\n runningTotal += count;\n });\n\n const width = radius * 2;\n return (\n <svg width={width} height={width} viewBox={`-3 -3 ${width + 6} ${width + 6}`}>\n {isPie && (\n <circle\n cx={radius}\n cy={radius}\n r={radius}\n fill=\"none\"\n strokeWidth={2}\n stroke={themeColor}\n strokeOpacity={0.3}\n />\n )}\n {values.map((v, i) => (\n <PieSegment\n key={createDOMID()}\n start={offsets[i] / total}\n end={(offsets[i] + v) / total}\n radius={radius}\n color={colors[i]}\n themeColor={themeColor}\n segmentMetadata={bubbleSize[i]}\n handleBubbleClick={onBubbleClick}\n />\n ))}\n </svg>\n );\n }, [\n bubbleSize,\n colors,\n isPie,\n onBubbleClick,\n originalValues,\n themeColor,\n allZeros,\n radius,\n total,\n values,\n ]);\n\n if (!bubble) {\n return null;\n }\n\n return (\n <StyledMarkerWrapper\n longitude={longitude}\n latitude={latitude}\n additionalFields={[...bubbleSize, ...additionalFields]}\n tooltipHeader={tooltipHeader}\n map={map}\n data-test-type=\"bubble\"\n showCoordinates={showCoordinates}\n >\n {bubble}\n {isBubbleMapIconFlagEnabled &&\n radius >= ICON_DISPLAY_CUTOFF &&\n icon &&\n (isRemoteIcon(icon) || isDataURI(icon)) && (\n <div\n data-test=\"bubble-icon-wrapper\"\n style={{\n position: 'absolute',\n top: `${radius}px`,\n left: `${radius}px`,\n transform: 'translate(-50%, -50%)',\n pointerEvents: 'none',\n }}\n >\n <RemoteIcon iconURL={icon} width={radius * 0.8} height={radius * 0.8} />\n </div>\n )}\n </StyledMarkerWrapper>\n );\n }\n);\nBubble.displayName = 'MapBubble';\n\nexport interface BubbleLayerProps {\n bubbleLayer: BubbleLayerType;\n themeColorScheme: string;\n zoom: number;\n map: React.MutableRefObject<Map>;\n onMapClick?: any;\n showCoordinates?: boolean;\n}\n\nconst BubbleLayer = (props: BubbleLayerProps): JSX.Element => {\n const { bubbleLayer, themeColorScheme, map, zoom, onMapClick, showCoordinates } = props;\n\n bubbleLayer.seriesColors = bubbleLayer.seriesColors || DEFAULT_SERIES_COLORS;\n bubbleLayer.bubbleSize = bubbleLayer.bubbleSize || [];\n bubbleLayer.icon = bubbleLayer.icon || [];\n const bakedData = React.useMemo(() => bakeBubbleData(bubbleLayer), [bubbleLayer]);\n const staticColors = React.useMemo(\n () => getStaticColors(bubbleLayer.bubbleSize.length, bubbleLayer.seriesColors),\n [bubbleLayer.bubbleSize.length, bubbleLayer.seriesColors]\n );\n const { data = [], dataRange = [], resultLimit, bubbleSizeFields, isPie } = bakedData ?? {};\n const { additionalTooltipFields = [], tooltipHeaderFieldName = null } = bubbleLayer;\n const roundedZoom = Math.round(zoom);\n const themeColor = themeColorScheme === 'light' ? '#ffffff' : '#1a1c20';\n const dynamicColors = bubbleLayer.dataColors;\n\n // filter data for the current zoom level and sort base on values\n const dataToRender = React.useMemo(\n () =>\n data\n .reduce((acc, datum, i) => {\n if (datum.zoom === roundedZoom) {\n acc.push({ data: datum, idx: i });\n }\n return acc;\n }, [])\n .slice(0, resultLimit || DEFAULT_RESULT_LIMIT)\n .sort((a, b) => sum(b.data.values) - sum(a.data.values)),\n [data, resultLimit, roundedZoom]\n );\n\n const handleMapClick = React.useCallback(\n (e, name, value, i) => {\n // retrieve metadata from the appropriate datum, indexed by i\n const metadata = dataToRender[i]?.data?.metadata ?? {};\n const payload = Object.keys(metadata).reduce(\n (acc, curr) => {\n const key = `row.${curr}.value`;\n const val = String(metadata[curr]);\n return { ...acc, [key]: val };\n },\n { name, value: String(value) }\n );\n\n onMapClick({ e, payload });\n },\n [dataToRender, onMapClick]\n );\n\n return (\n <>\n {dataToRender.map((datum, i) => {\n const colors = dynamicColors\n ? [\n dataToRender.map(obj =>\n isColor(dynamicColors[obj.idx]) ? dynamicColors[obj.idx] : DEFAULT_CLUSTER_COLOR\n )[i],\n ]\n : staticColors;\n\n const [longitude, latitude] = datum.data.coordinates;\n const bubbleSize = datum.data.values.map((value, index) => ({\n name: bubbleSizeFields[index],\n value,\n color: colors[index],\n }));\n\n const additionalFields = bubbleLayer.metadata\n ? additionalTooltipFields.map(field => ({\n name: field,\n value: datum.data.metadata[field],\n icon: bubbleLayer.tooltipFieldIcons?.[field],\n }))\n : [];\n\n const tooltipHeaderField =\n bubbleLayer.metadata && datum.data.metadata[tooltipHeaderFieldName];\n\n return (\n <Bubble\n // eslint-disable-next-line\n key={String(i)}\n originalValues={datum.data.values}\n valueRange={dataRange}\n colors={colors}\n themeColor={themeColor}\n isPie={isPie}\n longitude={longitude}\n latitude={latitude}\n bubbleSize={bubbleSize}\n additionalFields={additionalFields}\n tooltipHeader={tooltipHeaderField}\n map={map}\n handleMapClick={(e, name, value) => handleMapClick(e, name, value, i)}\n icon={bubbleLayer.icon[datum.idx]}\n showCoordinates={showCoordinates}\n />\n );\n })}\n </>\n );\n};\n\nexport default BubbleLayer;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { isNumber } from '@splunk/visualization-encoding/utils/types';\nimport { getFieldsFromDSL } from '@splunk/visualization-encoding/utils/dsl';\nimport { deepMergeWithArrayPrimitiveOverrides } from '@splunk/visualizations-shared/hocUtils';\nimport { pickFieldFromJSONSchema } from '@splunk/visualizations-shared/JSONSchemaUtils';\nimport { GEO_LAT_AND_LONG_FIELD } from '../../Map/PureMap/BubbleLayer';\n\nexport const columnsNullToZeros = (config, dataSources, options) => {\n const { primary } = dataSources;\n const { columns, fields } = primary.data;\n let newColumns = columns;\n const mergedOptions = deepMergeWithArrayPrimitiveOverrides(\n {},\n options,\n pickFieldFromJSONSchema(config.optionsSchema, 'default')\n );\n if (mergedOptions.layers?.[0]?.type === 'bubble') {\n const latitudeField = getFieldsFromDSL(mergedOptions.layers[0].latitude, dataSources)[0] || '';\n const longitudeField = getFieldsFromDSL(mergedOptions.layers[0].longitude, dataSources)[0] || '';\n const stringsFields = getFieldsFromDSL(\"> primary | frameBySeriesTypes('string')\", dataSources);\n const excludedFields = Array.from(\n new Set([\n latitudeField,\n longitudeField,\n 'geobin',\n 'name',\n ...stringsFields,\n ...GEO_LAT_AND_LONG_FIELD,\n ])\n );\n const indicesToEvaluate = new Set(\n fields.reduce((arr, e, i) => {\n const field = typeof e === 'string' ? e : e.name.toString();\n if (!excludedFields.includes(field)) {\n arr.push(i);\n }\n return arr;\n }, [])\n );\n\n newColumns = columns.map((column, i) => {\n if (indicesToEvaluate.has(i)) {\n // sanitize value and convert string to numeric numbers\n return column.map(value => (!value || !isNumber(value) ? 0 : +value));\n }\n return column;\n });\n }\n\n const modifiedDatasources = {\n ...dataSources,\n primary: {\n ...primary,\n data: {\n ...primary.data,\n columns: newColumns,\n },\n },\n };\n\n return modifiedDatasources;\n};\n", "\nimport * as defaultImport from \"@splunk/visualization-encoding/utils/types\";\nexport * from \"@splunk/visualization-encoding/utils/types\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-encoding/utils/dsl\";\nexport * from \"@splunk/visualization-encoding/utils/dsl\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/hocUtils\";\nexport * from \"@splunk/visualizations-shared/hocUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/JSONSchemaUtils\";\nexport * from \"@splunk/visualizations-shared/JSONSchemaUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"react\";\nexport * from \"react\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"styled-components\";\nexport * from \"styled-components\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"lodash\";\nexport * from \"lodash\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/iconUtils\";\nexport * from \"@splunk/visualizations-shared/iconUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/colorUtils\";\nexport * from \"@splunk/visualizations-shared/colorUtils\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualizations-shared/RemoteIcon\";\nexport * from \"@splunk/visualizations-shared/RemoteIcon\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-context/FeatureFlagContext\";\nexport * from \"@splunk/visualization-context/FeatureFlagContext\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/ui-utils/id\";\nexport * from \"@splunk/ui-utils/id\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"d3-scale\";\nexport * from \"d3-scale\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"chroma-js\";\nexport * from \"chroma-js\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-color-palettes\";\nexport * from \"@splunk/visualization-color-palettes\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/visualization-schemas\";\nexport * from \"@splunk/visualization-schemas\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "import { forEach, sum, isNumber, min as lodashMin, max as lodashMax, get, isEqual, isObject } from 'lodash';\nimport { LngLatBoundsLike } from 'maplibre-gl';\nimport { scalePow } from 'd3-scale';\nimport chroma from 'chroma-js';\nimport type { MapContextInterface, BaseTileConfig } from '@splunk/visualization-context/MapContext';\nimport { isColor } from '@splunk/visualizations-shared/colorUtils';\nimport { VIZ_CATEGORICAL } from '@splunk/visualization-color-palettes';\nimport { isNumber as isNumberUtil } from '@splunk/visualization-encoding/utils/types';\nimport type { GeoJsonDataType } from '@splunk/visualizations-shared/mapUtils';\nimport { LAYER_TYPE } from '@splunk/visualization-schemas';\n\nexport const MAX_LATITUDE = 90;\nexport const MIN_LATITUDE = -90;\nexport const MAX_LONGITUDE = 180;\nexport const MIN_LONGITUDE = -180;\nexport const DEFAULT_RESULT_LIMIT = 1000;\nexport const DEFAULT_CLUSTER_COLOR = '#909090';\nexport const DEFAULT_SERIES_COLORS = VIZ_CATEGORICAL;\n// MapLibre requires a map style specification number which is always 8\nexport const MAP_STYLE_VERSION_NUMBER = 8;\n// currently using one [min, max] value set for bubbles across all zoom levels\nexport const MIN_BUBBLE_RADIUS = 7.11; // 10px\nexport const MAX_BUBBLE_RADIUS = 45.26; // 85px\nexport const DEFAULT_OPACITY = 0.8;\nconst LONGITUDE = 'longitude';\nconst LATITUDE = 'latitude';\nexport type MaybeBaseTileConfig = BaseTileConfig | Record<string, never>;\ninterface GenericLayerType {\n type: string;\n latitude: number[];\n longitude: number[];\n dataColors?: string[] | '';\n seriesColors: string[];\n additionalTooltipFields?: string[];\n tooltipHeaderField?: string[];\n resultLimit: number;\n metadata?: Array<{ [key: string]: number | string }>;\n}\n\nexport interface MarkerLayerType extends GenericLayerType {\n type: LAYER_TYPE.Marker;\n}\n\nexport interface BubbleLayerType extends GenericLayerType {\n type: LAYER_TYPE.Bubble;\n bubbleSize?: number[][] | number[];\n bubbleSizeFields: string[];\n dataValuesField?: string;\n tooltipHeaderFieldName?: string;\n geobin?: string[];\n icon?: string[];\n tooltipFieldIcons?: string;\n}\n\ninterface BubbleLayerDatumType {\n zoom: number;\n values: number[];\n sanitizedValues: number[];\n coordinates: number[];\n}\n\nexport interface BubbleLayerDataType {\n data: BubbleLayerDatumType[];\n dataRange: number[];\n isPie: boolean;\n resultLimit: number;\n bubbleSizeFields: string[];\n}\n\nexport interface ChoroplethLayerType {\n type: LAYER_TYPE.Choropleth;\n areaIds: string[];\n areaValues: number[];\n dataColors: string[];\n additionalTooltipFields?: string[];\n tooltipHeaderField?: string[];\n geom?: GeoJsonDataType[] | null;\n resultLimit?: number;\n metadata?: Array<{ [key: string]: number | string | GeoJsonDataType }>;\n source?: string;\n width?: string | number;\n height?: string | number;\n choroplethEmptyAreaColor?: string;\n choroplethStrokeColor?: string;\n choroplethOpacity?: number;\n}\n\nexport interface MapLayerClickPayloadType {\n name?: string;\n value?: string | number;\n /* cell values of all cells of clicked row with the field and value - in shape row.<field>.value */\n [key: string]: string | number;\n}\n\nexport type ClusterLayerType = BubbleLayerType | MarkerLayerType;\nexport type LayerType = ClusterLayerType | ChoroplethLayerType;\n/**\n * Construct a tile preset {key: config} by combining the default + custom tile configs\n * Also returns the default tile config for each theme - light/dark\n * @param {MapContextInterface} args\n * @param {BaseTileConfig[]} args.defaultTileConfig\n * @param {BaseTileConfig[]} args.customTileConfig\n * @returns {Object} tile preset\n */\nexport const getTilePreset = ({\n defaultTileConfig = [],\n customTileConfig = [],\n}: MapContextInterface): {\n tilePreset: Record<string, BaseTileConfig>;\n defaultTileLight: MaybeBaseTileConfig;\n defaultTileDark: MaybeBaseTileConfig;\n} => {\n const tilePreset: Record<string, BaseTileConfig> = {};\n let defaultTileLight: MaybeBaseTileConfig = {};\n let defaultTileDark: MaybeBaseTileConfig = {};\n const tileConfigs = [...defaultTileConfig, ...customTileConfig];\n forEach(tileConfigs, tileConfig => {\n const key = tileConfig?.key;\n if (!key) {\n return;\n }\n const updatedConfig: BaseTileConfig = {\n ...tileConfig,\n version: MAP_STYLE_VERSION_NUMBER,\n };\n tilePreset[key] = updatedConfig;\n });\n\n if (defaultTileConfig.length > 0) {\n defaultTileLight =\n defaultTileConfig.find(config => config.theme === 'light') ??\n defaultTileConfig.find(config => config.theme === undefined) ??\n {};\n defaultTileDark =\n defaultTileConfig.find(config => config.theme === 'dark') ??\n defaultTileConfig.find(config => config.theme === undefined) ??\n {};\n }\n\n return { tilePreset, defaultTileLight, defaultTileDark };\n};\n\n/**\n * Check if baseLayerTileServer is in tilePreset and config matches current theme, if yes, return.\n * If no, construct a mapStyle with baseLayerTilerServer and baseLayerTileServerType\n * Else return default tile config based on current theme\n * @param {Object} args\n * @param {BaseTileConfig[]} args.tilePreset\n * @param {String} args.baseLayerTilerServer\n * @param {String} args.baseLayerTileServerType\n * @param {String} args.colorScheme\n * @param {BaseTileConfig} args.defaultTileDark\n * @param {BaseTileConfig} args.defaultTileLight\n * @returns {BaseTileConfig} mapStyle\n */\nexport const getMapStyle = ({\n showBaseLayer,\n baseLayerTileServer = '',\n baseLayerTileServerType = '',\n tilePreset = {},\n colorScheme = 'light',\n defaultTileLight = {},\n defaultTileDark = {},\n}: {\n showBaseLayer: boolean;\n baseLayerTileServer?: string;\n baseLayerTileServerType?: string;\n tilePreset?: Record<string, BaseTileConfig>;\n colorScheme?: string;\n defaultTileLight?: MaybeBaseTileConfig;\n defaultTileDark?: MaybeBaseTileConfig;\n}): MaybeBaseTileConfig => {\n if (!showBaseLayer) {\n return {\n name: 'empty-base-layer',\n key: 'empty-base-layer',\n version: MAP_STYLE_VERSION_NUMBER,\n sources: {\n 'base-tiles': {\n type: 'raster',\n tiles: [\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n ],\n tileSize: 256,\n },\n },\n layers: [\n {\n id: 'base-layer',\n type: 'raster',\n source: 'base-tiles',\n minzoom: 0,\n maxzoom: 22,\n },\n ],\n };\n }\n\n if (\n baseLayerTileServer &&\n tilePreset[baseLayerTileServer] &&\n (!tilePreset[baseLayerTileServer].theme || tilePreset[baseLayerTileServer].theme === colorScheme)\n ) {\n return tilePreset[baseLayerTileServer];\n }\n\n if (baseLayerTileServer && baseLayerTileServerType) {\n let tiles: string[] = [];\n /**\n * Tile Server URLs (eg: http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png) can specify the variable {s} which refers to a subdomain\n * Subdomains are used to help with browser parallel requests per domain limitation. These subdomains are typically single letters 'a', 'b' and 'c'\n * Refer to https://leafletjs.com/SlavaUkraini/reference.html#tilelayer and https://wiki.openstreetmap.org/wiki/Tile_servers\n */\n if (/^(https?):\\/\\/{[sS]}\\./.exec(baseLayerTileServer)) {\n /**\n * sXML (Leaflet) allows users to define their own tile server URLs + list of available subdomains\n * In order to preserve this behavior during conversion to splunk.map,\n * if the variable {s} or {S} is detected, replace it with 'a', 'b' and 'c' - default values for subdomains\n */\n tiles = [\n baseLayerTileServer.replace(/{[sS]}/, 'a'),\n baseLayerTileServer.replace(/{[sS]}/, 'b'),\n baseLayerTileServer.replace(/{[sS]}/, 'c'),\n ];\n } else {\n tiles = [baseLayerTileServer];\n }\n const mapStyle: BaseTileConfig = {\n name: baseLayerTileServer,\n key: baseLayerTileServer,\n version: MAP_STYLE_VERSION_NUMBER,\n sources: {\n 'base-tiles': {\n type: baseLayerTileServerType,\n tiles,\n tileSize: 256,\n },\n },\n layers: [\n {\n id: 'base-layer',\n type: 'raster',\n source: 'base-tiles',\n minzoom: 0,\n maxzoom: 24, // https://maplibre.org/maplibre-gl-js-docs/api/map/\n },\n ],\n };\n return mapStyle;\n }\n\n // if tile server is not present in the preset AND we can't construct a mapStyle, fall back on defaults\n return colorScheme === 'light' ? defaultTileLight : defaultTileDark;\n};\n\nexport interface ZoomConstraints {\n minZoom: number;\n maxZoom: number;\n}\n\nexport const getZoomConstraintsFromTileConfig = (\n tileConfig: BaseTileConfig,\n baseLayerTileServer?: string\n): ZoomConstraints => {\n const { sources, layers } = tileConfig;\n let matchedBaseLayerTileServer = false;\n // check sources for minzoom maxzoom first\n const sourceKeys = Object.keys(sources);\n // eslint-disable-next-line\n for (const key of sourceKeys) {\n const source = sources[key] as { [key: string]: unknown };\n const { minzoom, maxzoom } = source;\n const tiles = Array.isArray(source?.tiles) ? (source.tiles as string[]) : [];\n if (baseLayerTileServer && tiles.includes(baseLayerTileServer)) {\n matchedBaseLayerTileServer = true;\n }\n if (\n ((baseLayerTileServer && matchedBaseLayerTileServer) || !baseLayerTileServer) &&\n isNumber(minzoom) &&\n isNumber(maxzoom)\n ) {\n return {\n minZoom: minzoom,\n maxZoom: maxzoom,\n };\n }\n }\n // then check layers\n // eslint-disable-next-line\n for (const layer of layers) {\n const { minzoom, maxzoom } = layer;\n if (\n ((baseLayerTileServer && matchedBaseLayerTileServer) || !baseLayerTileServer) &&\n isNumber(minzoom) &&\n isNumber(maxzoom)\n ) {\n return {\n minZoom: minzoom,\n maxZoom: maxzoom,\n };\n }\n }\n // Maplibre default - would reset previous min/maxZoom https://maplibre.org/maplibre-gl-js-docs/api/map/\n return {\n minZoom: 0,\n maxZoom: 24,\n };\n};\n\nexport const isBaseTileConfig = (config: MaybeBaseTileConfig): config is BaseTileConfig =>\n Boolean(config && 'name' in config && 'key' in config && 'sources' in config && 'layers' in config);\n\nexport const getZoomLevelFromGeobin = (geobinStr: string): number => {\n if (!geobinStr) {\n return null;\n }\n // geostats cmds return geobin with zoom level 0-18, 0-99 in the geobinPattern covers the range\n const geobinPattern = /bin_id_zl_(\\d{1,2})_y_/g;\n const match = geobinPattern.exec(geobinStr);\n return (match?.length && parseInt(match[1], 10)) ?? null;\n};\n\n// Bubble colors - static\nexport const getStaticColors = (colorCount: number, colorArray: string[]): string[] => {\n if (colorCount < 0 || !colorCount) {\n return [DEFAULT_CLUSTER_COLOR];\n }\n if (!colorArray?.length) {\n return [...Array(colorCount).keys()].map(i => DEFAULT_SERIES_COLORS[i]);\n }\n // loop through colorArray to pick the first $colorCount colors\n // start from begining again if colorCount > colorArray.length\n return [...Array(colorCount).keys()].map(i =>\n isColor(colorArray[i % colorArray.length]) ? colorArray[i % colorArray.length] : DEFAULT_CLUSTER_COLOR\n );\n};\n\n// Bubble size\nexport const matchBubbleSize = (dataRange: number[], data: number): any => {\n const size = scalePow().exponent(0.2).domain(dataRange).range([MIN_BUBBLE_RADIUS, MAX_BUBBLE_RADIUS])(\n data\n );\n\n if (size > MAX_BUBBLE_RADIUS) {\n return MAX_BUBBLE_RADIUS;\n }\n if (size < MIN_BUBBLE_RADIUS) {\n return MIN_BUBBLE_RADIUS;\n }\n return size;\n};\n\nexport const transposeArray = (array: number[][]): number[][] => {\n if (!array?.length || !array[0]?.length) {\n return [];\n }\n return array[0].map((_, i) => array.map(row => row[i]));\n};\n\n// sanitize values: update all null, undefined, or negative values to 0\nexport const sanitizeValues = (values: number[] | number[][]) => {\n // null / undefined\n if (!values) {\n return 0;\n }\n // number\n if (!Array.isArray(values)) {\n return values > 0 ? values : 0;\n }\n // array\n return values.map(arr => sanitizeValues(arr));\n};\n\n// eslint-disable-next-line consistent-return\nexport const sortByValuesField = (bubbleLayer: BubbleLayerType) => {\n const { bubbleSizeFields, dataValuesField } = bubbleLayer;\n\n // Find the index of dataValuesField in fields\n const index = bubbleSizeFields.indexOf(dataValuesField);\n if (index === -1) return bubbleLayer; // If not found, return as is\n\n // Move dataValuesField and corresponding sizes to the first position\n bubbleLayer.bubbleSizeFields.unshift(bubbleLayer.bubbleSizeFields.splice(index, 1)[0]);\n bubbleLayer.bubbleSize.unshift(bubbleLayer.bubbleSize.splice(index, 1)[0] as number & number[]);\n};\n\nexport const bakeBubbleData = (layer: BubbleLayerType): BubbleLayerDataType => {\n if (\n !layer?.bubbleSize?.length ||\n !layer?.geobin?.length ||\n !layer?.latitude?.length ||\n !layer?.longitude?.length\n ) {\n return null;\n }\n // if bubbleSize is passed as an array of single number array (data series)\n // e.g. [value0, value1, ...]\n // format each value as an array to unify data operations for data series and frames\n const sanitizedBubbleSize = sanitizeValues(layer.bubbleSize);\n let transposedBubbleSize: number[][];\n let transposedSanitizedBubbleSize: number[][];\n let isPie = false;\n // format array if bubbleSize is passed as an array of array (data frame)\n if (Array.isArray(layer.bubbleSize[0])) {\n // one-time array transpose,\n // e.g. from [column0data, column0data] (multi series)\n // to [[column0datum0, column1datum0], [column0datum1, column1data1], ...]\n // or e.g. from [column0data] (single series)\n // to [[column0data]]\n // for easy access of values at each geo location,\n // and min max pie size computation\n transposedBubbleSize = transposeArray(layer.bubbleSize as number[][]);\n transposedSanitizedBubbleSize = transposeArray(sanitizedBubbleSize);\n // if multiple series in the dataframe, set isPie to true\n if (layer.bubbleSize.length > 1) {\n isPie = true;\n // when dynamic coloring is enabled,\n // set the configured dataValues field as the first field\n // to apply dynamic colors only to the first pie slice.\n if (layer.dataValuesField && !!layer.dataColors) {\n sortByValuesField(layer); // here\n }\n }\n } else {\n transposedBubbleSize = layer.bubbleSize.map(n => [n]);\n transposedSanitizedBubbleSize = sanitizedBubbleSize.map(n => [n]);\n }\n if (!transposedBubbleSize?.length) {\n return null;\n }\n const data = layer.latitude\n .map((lat, i) => ({\n zoom: getZoomLevelFromGeobin(layer.geobin[i]),\n values: transposedBubbleSize[i],\n sanitizedValues: transposedSanitizedBubbleSize[i],\n coordinates: [layer.longitude[i], lat],\n metadata: layer.metadata ? layer.metadata[i] : {},\n }))\n .filter(d => Boolean(d.values));\n\n // compute the min/max value to encode min/max pie or bubble size\n let min = sum(transposedSanitizedBubbleSize[0]);\n let max = sum(transposedSanitizedBubbleSize[1]);\n transposedSanitizedBubbleSize.forEach(row => {\n const bubbleSize = sum(row);\n max = bubbleSize > max ? bubbleSize : max;\n min = bubbleSize < min ? bubbleSize : min;\n });\n return {\n data,\n dataRange: [min, max],\n isPie,\n resultLimit: layer.resultLimit,\n bubbleSizeFields: layer.bubbleSizeFields,\n };\n};\n\nexport const isValidLatLon = (latlon: Array<number | string>): boolean => {\n if (!latlon || !Array.isArray(latlon) || latlon.length !== 2) {\n return false;\n }\n const [lat, lon] = latlon;\n if (!isNumberUtil(lat) || !(Number(lat) >= MIN_LATITUDE && Number(lat) <= MAX_LATITUDE)) {\n return false;\n }\n if (!isNumberUtil(lon) || !(Number(lon) >= MIN_LONGITUDE && Number(lon) <= MAX_LONGITUDE)) {\n return false;\n }\n return true;\n};\n\nexport const getChoroplethValues = (field: string, choroplethLayer: ChoroplethLayerType): number[] => {\n if (!Array.isArray(choroplethLayer.geom) || choroplethLayer.geom.length === 0) {\n return [];\n }\n const limit = choroplethLayer.resultLimit ?? DEFAULT_RESULT_LIMIT;\n const slicedGeomList = choroplethLayer.geom.slice(0, limit);\n const flatCoordinates = slicedGeomList.flatMap(geomObject => {\n if (!geomObject) {\n return [];\n }\n if (geomObject.type === 'MultiPolygon') {\n return geomObject.coordinates.flat(2);\n }\n if (geomObject.type === 'Polygon') {\n return geomObject.coordinates.flat();\n }\n return [];\n });\n return flatCoordinates.map(coord => coord[field === LONGITUDE ? 0 : 1]);\n};\n\n/**\n * Returns a list of all lat or lon coordinates used in a specified layer\n * @param {LayerType[]} layer\n * @param {string} field\n * @returns {number[]} list of lat coordinates or lon coordinates\n */\nconst getLatOrLonCoordinates = (layer: LayerType, field: string): number[] => {\n const getClusterValues = (clusterLayer: ClusterLayerType): number[] =>\n get(clusterLayer, field, []).slice(\n 0,\n clusterLayer.type === LAYER_TYPE.Marker && clusterLayer.resultLimit\n ? clusterLayer.resultLimit\n : DEFAULT_RESULT_LIMIT\n );\n return layer.type === LAYER_TYPE.Choropleth ? getChoroplethValues(field, layer) : getClusterValues(layer);\n};\n\n/**\n * Returns the min and max LongLat pairs to determine the layer boundaries to fit all markers/bubbles\n * @param {LayerType[]} layers\n * @returns {LngLatBoundsLike}\n */\nexport const getGlobalLayerBoundaries = (layers: LayerType[]): LngLatBoundsLike => {\n const isLayerValid = (field: string): boolean =>\n layers.every(layer => layer[field] || (layer as ChoroplethLayerType).geom);\n const getDefaultMax = (field: string) => (field === LONGITUDE ? MAX_LONGITUDE : MAX_LATITUDE);\n const getDefaultMin = (field: string) => (field === LONGITUDE ? MIN_LONGITUDE : MIN_LATITUDE);\n\n if (!layers || !Array.isArray(layers) || !layers.length) {\n return null;\n }\n\n const getMin = (field: string): number => {\n if (!isLayerValid(field)) {\n return getDefaultMin(field);\n }\n return layers.reduce((prevVal, layer) => {\n const coordinatesNumArr = getLatOrLonCoordinates(layer, field).map(x => +x);\n return lodashMin([prevVal, ...coordinatesNumArr]);\n }, getDefaultMax(field));\n };\n\n const getMax = (field: string): number => {\n if (!isLayerValid(field)) {\n return getDefaultMax(field);\n }\n return layers.reduce((prevVal, layer) => {\n const coordinatesNumArr = getLatOrLonCoordinates(layer, field).map(Number);\n return lodashMax([prevVal, ...coordinatesNumArr]);\n }, getDefaultMin(field));\n };\n\n return [\n [getMin(LONGITUDE), getMin(LATITUDE)],\n [getMax(LONGITUDE), getMax(LATITUDE)],\n ];\n};\n\nexport const formatTooltipFieldValue = (value: unknown): string | number => {\n if (value === null || value === undefined) {\n return '';\n }\n if (typeof value === 'string' || typeof value === 'number') {\n return value;\n }\n return JSON.stringify(value);\n};\n\nexport const getScaledOpacities = (colors: string[], cfgOpacity: number): number[] => {\n // extract opacity information from 8 digit hex codes\n const opacities = colors?.map(color => (color?.length === 9 ? (chroma(color).alpha() ?? 1) : 1));\n // opacity cannot be greater than configured opacity\n return opacities?.map(opacity => opacity * cfgOpacity);\n};\n\nexport const compareBaseStyles = (curr, next): boolean => {\n const currBaseLayer = curr?.layers?.find(layer => layer?.id === 'base-layer');\n const nextBaseLayer = next?.layers?.find(layer => layer?.id === 'base-layer');\n const currBaseSource = get(curr?.sources, (currBaseLayer?.source as string) ?? '');\n const nextBaseSource = get(next?.sources, (nextBaseLayer?.source as string) ?? '');\n\n if (!currBaseLayer || !nextBaseLayer || !currBaseSource || !nextBaseSource) {\n return false;\n }\n\n return isEqual(currBaseLayer, nextBaseLayer) && isEqual(currBaseSource, nextBaseSource);\n};\n\nexport const formatMetadata = (\n choroplethLayer: ChoroplethLayerType,\n i: number\n): { [key: string]: string } => {\n if (!choroplethLayer?.areaIds || !choroplethLayer?.areaValues) return {};\n if (i >= choroplethLayer.areaIds.length) return {};\n\n const metadata = choroplethLayer.metadata ? choroplethLayer.metadata[i] : {};\n const name = choroplethLayer.areaIds[i];\n const value = choroplethLayer.areaValues[i];\n const base = { name, value: String(value) };\n\n return Object.keys(metadata).reduce((result, curr) => {\n const key = `row.${curr}.value`;\n const val = isObject(metadata[curr]) ? JSON.stringify(metadata[curr]) : String(metadata[curr]);\n return { ...result, [key]: val };\n }, base);\n};\n", "\nimport * as defaultImport from \"maplibre-gl\";\nexport * from \"maplibre-gl\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/react-ui/Popover\";\nexport * from \"@splunk/react-ui/Popover\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/ui-utils/i18n\";\nexport * from \"@splunk/ui-utils/i18n\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "\nimport * as defaultImport from \"@splunk/themes\";\nexport * from \"@splunk/themes\";\nexport default ('default' in defaultImport ? defaultImport.default : defaultImport);\n", "import * as React from 'react';\nimport styled from 'styled-components';\nimport Popover from '@splunk/react-ui/Popover';\nimport { isRemoteIcon, isDataURI } from '@splunk/visualizations-shared/iconUtils';\nimport { _ } from '@splunk/ui-utils/i18n';\nimport FeatureFlagContext from '@splunk/visualization-context/FeatureFlagContext';\nimport RemoteIcon from '@splunk/visualizations-shared/RemoteIcon';\nimport { variables } from '@splunk/themes';\nimport { createDOMID } from '@splunk/ui-utils/id';\n\ntype FeatureFlagContextValue = Record<string, boolean | undefined> | null;\n\nconst StyledPopover = styled(Popover)`\n min-width: 250px;\n max-width: 332px;\n max-width: fit-content;\n font-size: 12px;\n`;\n\nconst StyledTable = styled.table`\n margin: 2px 6px 2px 6px;\n width: calc(100% - 12px);\n`;\n\nconst StyledTitleColumn = styled.td`\n opacity: 0.85;\n word-break: break-all;\n vertical-align: top;\n`;\n\nconst StyledValueColumn = styled.td`\n text-align: right;\n word-break: break-all;\n vertical-align: top;\n`;\n\nconst StyledColorBlock = styled.div`\n background-color: ${props => props.color};\n display: inline-block;\n margin-right: 4px;\n border-radius: 2px;\n width: 6px;\n height: 11px;\n transform: translateY(1px);\n`;\n\nconst StyledIconWrapper = styled.span`\n margin-left: 4px;\n display: inline-block;\n vertical-align: middle;\n`;\n\nconst StyledTooltipHeader = styled.thead`\n th {\n height: 16px;\n color: ${variables.contentColorActive};\n padding: 0;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 100%;\n }\n`;\n\nexport const convertDegToDMS = (decimalDegree: number, type: 'latitude' | 'longitude'): string => {\n const truncate = n => (n > 0 ? Math.floor(n) : Math.ceil(n));\n const absoluteDegree = Math.abs(decimalDegree);\n let degrees = truncate(absoluteDegree);\n let minutes = truncate((absoluteDegree - degrees) * 60);\n let seconds = Math.round((absoluteDegree - degrees - minutes / 60) * 3600);\n if (seconds === 60) {\n minutes += 1;\n seconds = 0;\n }\n if (minutes === 60) {\n degrees += 1;\n minutes = 0;\n }\n let direction: string;\n if (type === 'longitude') {\n direction = decimalDegree < 0 ? 'W' : 'E';\n } else if (type === 'latitude') {\n direction = decimalDegree < 0 ? 'S' : 'N';\n }\n return `${degrees}\u00B0 ${minutes}' ${seconds}\" ${direction}`;\n};\n\nexport interface TooltipProps {\n open?: boolean;\n anchor?: HTMLElement;\n latitude?: number;\n longitude?: number;\n areaId?: string;\n areaValue?: number;\n additionalFields?: Array<{ name: string; value: number | string; color?: string; icon?: string }>;\n showCoordinates?: boolean;\n tooltipHeader?: string;\n}\n// only want latitude/longitude for marker and bubble\n// omit for choropleth, and put areaid, areavalue instead\nconst Tooltip = ({\n open,\n anchor,\n latitude,\n longitude,\n areaId,\n areaValue,\n additionalFields = [],\n showCoordinates = true,\n tooltipHeader = null,\n}: TooltipProps): JSX.Element => {\n const featureFlagContext = React.useContext<FeatureFlagContextValue>(FeatureFlagContext);\n const isTooltipIconFlagEnabled = Boolean(\n featureFlagContext && featureFlagContext.visualizations_enableTooltipIcon\n );\n return (\n <StyledPopover\n open={open}\n animation={false}\n anchor={anchor}\n data-test=\"map-marker-tooltip\"\n defaultPlacement=\"above\"\n >\n <StyledTable>\n {tooltipHeader && (\n <StyledTooltipHeader data-test=\"tooltip-header\">\n <tr>\n <th colSpan={2}>\n <span data-test=\"tooltip-header-value\">{tooltipHeader}</span>\n </th>\n </tr>\n </StyledTooltipHeader>\n )}\n <tbody>\n {Boolean(areaId && areaValue) && (\n <tr>\n <StyledTitleColumn data-test=\"area-id\">{areaId}</StyledTitleColumn>\n <StyledValueColumn data-test=\"area-value\">{areaValue}</StyledValueColumn>\n </tr>\n )}\n {Boolean(showCoordinates && latitude) && (\n <tr>\n <StyledTitleColumn>{_('Latitude')}</StyledTitleColumn>\n <StyledValueColumn data-test=\"latitude\">\n {convertDegToDMS(latitude, 'latitude')}\n </StyledValueColumn>\n </tr>\n )}\n {Boolean(showCoordinates && longitude) && (\n <tr>\n <StyledTitleColumn>{_('Longitude')}</StyledTitleColumn>\n <StyledValueColumn data-test=\"longitude\">\n {convertDegToDMS(longitude, 'longitude')}\n </StyledValueColumn>\n </tr>\n )}\n {additionalFields\n .filter(({ value }) => value && String(value) !== '0')\n .map(({ name, value, color, icon }) => (\n <tr key={createDOMID()}>\n <StyledTitleColumn data-test=\"field-title\">\n {color ? (\n <StyledColorBlock data-test=\"field-color\" color={color} />\n ) : null}\n <span>\n {name}\n {isTooltipIconFlagEnabled &&\n icon &&\n (isRemoteIcon(icon) || isDataURI(icon)) ? (\n <StyledIconWrapper data-test=\"field-icon\">\n <RemoteIcon iconURL={icon} width={16} height={16} />\n </StyledIconWrapper>\n ) : null}\n </span>\n </StyledTitleColumn>\n <StyledValueColumn data-test=\"field-value\">{value}</StyledValueColumn>\n </tr>\n ))}\n </tbody>\n </StyledTable>\n </StyledPopover>\n );\n};\n\nexport default Tooltip;\n", "import type { Map } from 'maplibre-gl';\nimport { Marker } from 'maplibre-gl';\nimport * as React from 'react';\nimport type { TooltipProps } from './Tooltip';\nimport Tooltip from './Tooltip';\n\nexport interface MarkerWrapperProps extends React.HTMLAttributes<HTMLDivElement> {\n latitude: number;\n longitude: number;\n areaId?: string;\n areaValue?: number;\n additionalFields?: TooltipProps['additionalFields'];\n tooltipHeader?: TooltipProps['tooltipHeader'];\n map: React.MutableRefObject<Map>;\n isChoroplethTooltipOpen?: boolean;\n showCoordinates?: boolean;\n}\n\nconst MarkerWrapper = ({\n longitude,\n latitude,\n areaId,\n areaValue,\n additionalFields = [],\n tooltipHeader = null,\n map,\n isChoroplethTooltipOpen,\n children,\n showCoordinates = true,\n ...otherProps\n}: MarkerWrapperProps): JSX.Element => {\n const container = React.useRef<HTMLDivElement>();\n const marker = React.useRef<Marker>();\n const [isTooltipOpen, setTooltipOpenStatus] = React.useState(false);\n\n const isChoroplethTooltip = React.useCallback(\n () => isChoroplethTooltipOpen !== undefined,\n [isChoroplethTooltipOpen]\n );\n\n const openTooltip = React.useCallback(() => setTooltipOpenStatus(true), []);\n const closeTooltip = React.useCallback(() => setTooltipOpenStatus(false), []);\n\n const cleanupMarker = React.useCallback(() => {\n if (marker.current) {\n marker.current.remove();\n marker.current = undefined;\n }\n }, []);\n\n React.useEffect(() => {\n try {\n if (marker.current) {\n marker.current.setLngLat([longitude, latitude]);\n } else {\n marker.current = new Marker({ element: container.current });\n marker.current.setLngLat([longitude, latitude]);\n marker.current.addTo(map.current);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(error);\n cleanupMarker();\n }\n }, [latitude, longitude, map]);\n\n React.useEffect(() => cleanupMarker, []);\n const filteredAdditionalFields = additionalFields.filter(({ value }) => value && String(value) !== '0');\n const showTooltip = showCoordinates || filteredAdditionalFields.length || (areaId && areaValue);\n return (\n <div style={{ visibility: isChoroplethTooltip() ? 'hidden' : 'visible' }}>\n <div\n style={{\n visibility: isChoroplethTooltip() ? 'hidden' : 'visible',\n }}\n ref={container}\n data-test=\"map-marker\"\n onMouseOver={openTooltip}\n onMouseLeave={closeTooltip}\n onFocus={openTooltip}\n onBlur={closeTooltip}\n {...otherProps}\n >\n {children}\n </div>\n <div>\n {showTooltip && (\n <Tooltip\n open={isChoroplethTooltip() ? isChoroplethTooltipOpen : isTooltipOpen}\n anchor={container.current}\n latitude={isChoroplethTooltip() ? null : latitude}\n longitude={isChoroplethTooltip() ? null : longitude}\n areaId={areaId}\n areaValue={areaValue}\n additionalFields={additionalFields}\n showCoordinates={showCoordinates}\n tooltipHeader={tooltipHeader}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport default MarkerWrapper;\n", "import * as React from 'react';\nimport styled from 'styled-components';\nimport type { Map } from 'maplibre-gl';\nimport { sum } from 'lodash';\nimport { isRemoteIcon, isDataURI } from '@splunk/visualizations-shared/iconUtils';\nimport { isColor } from '@splunk/visualizations-shared/colorUtils';\nimport RemoteIcon from '@splunk/visualizations-shared/RemoteIcon';\nimport FeatureFlagContext from '@splunk/visualization-context/FeatureFlagContext';\nimport { createDOMID } from '@splunk/ui-utils/id';\nimport {\n bakeBubbleData,\n BubbleLayerType,\n DEFAULT_SERIES_COLORS,\n DEFAULT_RESULT_LIMIT,\n DEFAULT_CLUSTER_COLOR,\n getStaticColors,\n matchBubbleSize,\n} from './MapUtils';\nimport MarkerWrapper from './MarkerWrapper';\nimport type { TooltipProps } from './Tooltip';\n\ntype FeatureFlagContextValue = Record<string, boolean | undefined> | null;\n\nexport const GEO_BOUND_PREFIX = '_geo_bounds_';\nexport const GEO_LAT_AND_LONG_FIELD = ['_geo_long_field', '_geo_lat_field'];\nexport const ICON_DISPLAY_CUTOFF = 16;\nexport interface PieSegmentProps {\n start: number;\n end: number;\n radius: number;\n color: string;\n themeColor: string;\n segmentMetadata?: { name: string; value: number; color: string };\n handleBubbleClick?: (e: Event, name: string, count: number) => void;\n}\n\nexport const PieSegment = React.memo(\n ({\n start,\n end,\n radius,\n color,\n themeColor,\n segmentMetadata,\n handleBubbleClick,\n }: PieSegmentProps): JSX.Element => {\n const { name, value } = segmentMetadata ?? {};\n const handleSegmentClick = React.useCallback(\n e => {\n handleBubbleClick(e, name, value);\n },\n [name, value, handleBubbleClick]\n );\n\n if (end - start === 1) {\n return (\n <BubbleSegment\n as=\"circle\"\n onClick={handleSegmentClick}\n cx={radius}\n cy={radius}\n r={radius}\n fill={color}\n fillOpacity={0.5}\n strokeWidth={1.5}\n stroke={color}\n />\n );\n }\n const a0 = 2 * Math.PI * (start - 0.25);\n const a1 = 2 * Math.PI * (end - 0.25);\n const x0 = Math.cos(a0);\n const y0 = Math.sin(a0);\n const x1 = Math.cos(a1);\n const y1 = Math.sin(a1);\n const arc = end - start > 0.5 ? 1 : 0;\n\n return (\n <BubbleSegment\n as=\"path\"\n onClick={handleSegmentClick}\n d={`M ${radius} ${radius} L ${radius + radius * x0} ${\n radius + radius * y0\n } A ${radius} ${radius} 0 ${arc} 1 ${radius + radius * x1} ${\n radius + radius * y1\n } L ${radius} ${radius} A 0 0 0 ${arc} 0 ${radius} ${radius}`}\n fill={color}\n fillOpacity={0.8}\n stroke={themeColor}\n strokeWidth={2}\n strokeOpacity={0.3}\n />\n );\n }\n);\n\nPieSegment.displayName = 'MapBubblePieSegment';\n\nexport const BubbleSegment = styled.path`\n transition: 0.2s ease-in-out;\n transition-property: fill, stroke;\n`;\n\nexport const BUBBLE_SEGMENT_DIMMED_STYLES = {\n fill: 'rgba(150, 150, 150, 0.3)',\n stroke: 'rgba(200, 200, 200, 0.4)',\n} as const;\n\nconst StyledMarkerWrapper = styled(MarkerWrapper)`\n cursor: pointer;\n`;\n\nexport interface BubbleProps {\n originalValues: number[];\n valueRange: number[];\n colors: string[];\n themeColor: string;\n isPie: boolean;\n latitude: number;\n longitude: number;\n bubbleSize: Required<TooltipProps['additionalFields'][number] & { value: number }>[];\n additionalFields?: TooltipProps['additionalFields'];\n tooltipHeader?: TooltipProps['tooltipHeader'];\n map: React.MutableRefObject<Map>;\n handleMapClick?: any;\n icon?: string;\n showCoordinates?: boolean;\n}\n\nexport const Bubble = React.memo(\n ({\n originalValues,\n valueRange,\n colors,\n themeColor,\n isPie,\n latitude,\n longitude,\n bubbleSize,\n additionalFields = [],\n tooltipHeader = null,\n map,\n handleMapClick,\n icon,\n showCoordinates,\n }: BubbleProps): JSX.Element => {\n const featureFlagContext = React.useContext<FeatureFlagContextValue>(FeatureFlagContext);\n const isBubbleMapIconFlagEnabled = Boolean(\n featureFlagContext && featureFlagContext.visualizations_enableBubbleMapIcon\n );\n\n const onBubbleClick = React.useCallback(\n (e, name, value) => {\n handleMapClick(e, name, value);\n e.stopPropagation();\n },\n [handleMapClick]\n );\n\n // sanitize values\n const allZeros = originalValues.every(v => v === 0);\n const values = originalValues.map(v => (v > 0 ? v : 0));\n const total = values.reduce((totalValue, v) => totalValue + v, 0);\n const radius = matchBubbleSize(valueRange, total);\n\n const bubble = React.useMemo(() => {\n if (allZeros || !originalValues.length) return null;\n\n const offsets: number[] = [];\n let runningTotal = 0;\n values.forEach(count => {\n offsets.push(runningTotal);\n runningTotal += count;\n });\n\n const width = radius * 2;\n return (\n <svg width={width} height={width} viewBox={`-3 -3 ${width + 6} ${width + 6}`}>\n {isPie && (\n <circle\n cx={radius}\n cy={radius}\n r={radius}\n fill=\"none\"\n strokeWidth={2}\n stroke={themeColor}\n strokeOpacity={0.3}\n />\n )}\n {values.map((v, i) => (\n <PieSegment\n key={createDOMID()}\n start={offsets[i] / total}\n end={(offsets[i] + v) / total}\n radius={radius}\n color={colors[i]}\n themeColor={themeColor}\n segmentMetadata={bubbleSize[i]}\n handleBubbleClick={onBubbleClick}\n />\n ))}\n </svg>\n );\n }, [\n bubbleSize,\n colors,\n isPie,\n onBubbleClick,\n originalValues,\n themeColor,\n allZeros,\n radius,\n total,\n values,\n ]);\n\n if (!bubble) {\n return null;\n }\n\n return (\n <StyledMarkerWrapper\n longitude={longitude}\n latitude={latitude}\n additionalFields={[...bubbleSize, ...additionalFields]}\n tooltipHeader={tooltipHeader}\n map={map}\n data-test-type=\"bubble\"\n showCoordinates={showCoordinates}\n >\n {bubble}\n {isBubbleMapIconFlagEnabled &&\n radius >= ICON_DISPLAY_CUTOFF &&\n icon &&\n (isRemoteIcon(icon) || isDataURI(icon)) && (\n <div\n data-test=\"bubble-icon-wrapper\"\n style={{\n position: 'absolute',\n top: `${radius}px`,\n left: `${radius}px`,\n transform: 'translate(-50%, -50%)',\n pointerEvents: 'none',\n }}\n >\n <RemoteIcon iconURL={icon} width={radius * 0.8} height={radius * 0.8} />\n </div>\n )}\n </StyledMarkerWrapper>\n );\n }\n);\nBubble.displayName = 'MapBubble';\n\nexport interface BubbleLayerProps {\n bubbleLayer: BubbleLayerType;\n themeColorScheme: string;\n zoom: number;\n map: React.MutableRefObject<Map>;\n onMapClick?: any;\n showCoordinates?: boolean;\n}\n\nconst BubbleLayer = (props: BubbleLayerProps): JSX.Element => {\n const { bubbleLayer, themeColorScheme, map, zoom, onMapClick, showCoordinates } = props;\n\n bubbleLayer.seriesColors = bubbleLayer.seriesColors || DEFAULT_SERIES_COLORS;\n bubbleLayer.bubbleSize = bubbleLayer.bubbleSize || [];\n bubbleLayer.icon = bubbleLayer.icon || [];\n const bakedData = React.useMemo(() => bakeBubbleData(bubbleLayer), [bubbleLayer]);\n const staticColors = React.useMemo(\n () => getStaticColors(bubbleLayer.bubbleSize.length, bubbleLayer.seriesColors),\n [bubbleLayer.bubbleSize.length, bubbleLayer.seriesColors]\n );\n const { data = [], dataRange = [], resultLimit, bubbleSizeFields, isPie } = bakedData ?? {};\n const { additionalTooltipFields = [], tooltipHeaderFieldName = null } = bubbleLayer;\n const roundedZoom = Math.round(zoom);\n const themeColor = themeColorScheme === 'light' ? '#ffffff' : '#1a1c20';\n const dynamicColors = bubbleLayer.dataColors;\n\n // filter data for the current zoom level and sort base on values\n const dataToRender = React.useMemo(\n () =>\n data\n .reduce((acc, datum, i) => {\n if (datum.zoom === roundedZoom) {\n acc.push({ data: datum, idx: i });\n }\n return acc;\n }, [])\n .slice(0, resultLimit || DEFAULT_RESULT_LIMIT)\n .sort((a, b) => sum(b.data.values) - sum(a.data.values)),\n [data, resultLimit, roundedZoom]\n );\n\n const handleMapClick = React.useCallback(\n (e, name, value, i) => {\n // retrieve metadata from the appropriate datum, indexed by i\n const metadata = dataToRender[i]?.data?.metadata ?? {};\n const payload = Object.keys(metadata).reduce(\n (acc, curr) => {\n const key = `row.${curr}.value`;\n const val = String(metadata[curr]);\n return { ...acc, [key]: val };\n },\n { name, value: String(value) }\n );\n\n onMapClick({ e, payload });\n },\n [dataToRender, onMapClick]\n );\n\n return (\n <>\n {dataToRender.map((datum, i) => {\n const colors = dynamicColors\n ? [\n dataToRender.map(obj =>\n isColor(dynamicColors[obj.idx]) ? dynamicColors[obj.idx] : DEFAULT_CLUSTER_COLOR\n )[i],\n ]\n : staticColors;\n\n const [longitude, latitude] = datum.data.coordinates;\n const bubbleSize = datum.data.values.map((value, index) => ({\n name: bubbleSizeFields[index],\n value,\n color: colors[index],\n }));\n\n const additionalFields = bubbleLayer.metadata\n ? additionalTooltipFields.map(field => ({\n name: field,\n value: datum.data.metadata[field],\n icon: bubbleLayer.tooltipFieldIcons?.[field],\n }))\n : [];\n\n const tooltipHeaderField =\n bubbleLayer.metadata && datum.data.metadata[tooltipHeaderFieldName];\n\n return (\n <Bubble\n // eslint-disable-next-line\n key={String(i)}\n originalValues={datum.data.values}\n valueRange={dataRange}\n colors={colors}\n themeColor={themeColor}\n isPie={isPie}\n longitude={longitude}\n latitude={latitude}\n bubbleSize={bubbleSize}\n additionalFields={additionalFields}\n tooltipHeader={tooltipHeaderField}\n map={map}\n handleMapClick={(e, name, value) => handleMapClick(e, name, value, i)}\n icon={bubbleLayer.icon[datum.idx]}\n showCoordinates={showCoordinates}\n />\n );\n })}\n </>\n );\n};\n\nexport default BubbleLayer;\n"],
5
+ "mappings": "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",
6
6
  "names": ["defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport", "defaultImport"]
7
7
  }
@@ -221,7 +221,6 @@ var computeText = ({
221
221
  }) => {
222
222
  let text = (0, numberUtils_exports.isNumerial)(value) ? (0, numberUtils_exports.formatNumber)(value, numberPrecision, {
223
223
  useThousandSeparators: shouldUseThousandSeparators,
224
- // todo: need update formatNumber
225
224
  useTrendUnits: shouldAbbreviateValue
226
225
  }) : value;
227
226
  text = text || "";
@@ -298,13 +297,10 @@ var getTrendFontSize = ({ width, height, trendText, spaceRatio = 1 }) => {
298
297
  return trendFontSize;
299
298
  };
300
299
  var getUnderLabelHeight = (height) => height > DEFAULT_FONT ? DEFAULT_FONT : height;
301
- var getUnderLabel = ({ underLabel, width, height }) => (
302
- // todo: may need truncate underLabel later
303
- computeFontSize(underLabel, {
304
- width,
305
- height
306
- })
307
- );
300
+ var getUnderLabel = ({ underLabel, width, height }) => computeFontSize(underLabel, {
301
+ width,
302
+ height
303
+ });
308
304
  var getMajorAndTrend = ({
309
305
  width,
310
306
  height,
@@ -629,16 +625,19 @@ var changeColor = (color, ratio) => {
629
625
  };
630
626
  var lighten = (color) => changeColor(color, 1.3);
631
627
  var darken = (color) => changeColor(color, 0.5);
632
- var handleValueClickCallback = (ev, majorValue, majorValueField, trendValue, onValueClick, trellisEnabled = false, trellisSplitBy = "", trellisKey = "") => onValueClick(__spreadProps(__spreadValues({}, ev), {
633
- payload: __spreadValues({
634
- trendValue,
635
- value: majorValue,
636
- name: majorValueField
637
- }, trellisEnabled && {
638
- "trellis.name": trellisSplitBy,
639
- "trellis.value": trellisKey
640
- })
641
- }));
628
+ var handleValueClickCallback = (ev, majorValue, majorValueField, trendValue, onValueClick, trellisContext = {}) => {
629
+ const { trellisEnabled = false, trellisSplitBy = "", trellisKey = "" } = trellisContext;
630
+ return onValueClick(__spreadProps(__spreadValues({}, ev), {
631
+ payload: __spreadValues({
632
+ trendValue,
633
+ value: majorValue,
634
+ name: majorValueField
635
+ }, trellisEnabled && {
636
+ "trellis.name": trellisSplitBy,
637
+ "trellis.value": trellisKey
638
+ })
639
+ }));
640
+ };
642
641
  var getTrendColorWithPercent = (options) => {
643
642
  const shouldUsePercentTrendColor = options.trendColor === "> trendValue | rangeValue(trendColorEditorConfig)" && options.trendDisplay === "percent";
644
643
  return shouldUsePercentTrendColor ? {