util.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import mean from 'lodash/mean'
  21. import { IAxisConfig } from '../../components/Workbench/ConfigSections/AxisSection'
  22. import { ILabelConfig } from '../../components/Workbench/ConfigSections/LabelSection'
  23. import { ILegendConfig } from '../../components/Workbench/ConfigSections/LegendSection'
  24. import { getFormattedValue } from '../../components/Config/Format'
  25. import { CHART_LEGEND_POSITIONS, DEFAULT_SPLITER } from 'app/globalConstants'
  26. import { EChartOption } from 'echarts'
  27. import { IWidgetMetric } from '../../components/Widget'
  28. import {
  29. metricAxisLabelFormatter,
  30. decodeMetricName,
  31. getTextWidth,
  32. getAggregatorLocale
  33. } from '../../components/util'
  34. import { FieldSortTypes } from '../../components/Config/Sort'
  35. import { getFieldAlias } from '../../components/Config/Field'
  36. import {
  37. IReference,
  38. IReferenceLineData,
  39. IReferenceBandData
  40. } from '../../components/Workbench/Reference/types'
  41. import {
  42. ReferenceType,
  43. ReferenceValueType
  44. } from '../../components/Workbench/Reference/constants'
  45. import ChartTypes from '../../config/chart/ChartTypes'
  46. interface ISplitLineConfig {
  47. showLine: boolean
  48. lineStyle: 'solid' | 'dashed' | 'dotted'
  49. lineSize: string
  50. lineColor: string
  51. }
  52. export function getDimetionAxisOption(
  53. dimetionAxisConfig: IAxisConfig,
  54. splitLineConfig: ISplitLineConfig,
  55. data: string[]
  56. ): EChartOption.XAxis {
  57. const {
  58. inverse,
  59. showLine: showLineX,
  60. lineStyle: lineStyleX,
  61. lineSize: lineSizeX,
  62. lineColor: lineColorX,
  63. showLabel: showLabelX,
  64. labelFontFamily: labelFontFamilyX,
  65. labelFontSize: labelFontSizeX,
  66. labelColor: labelColorX,
  67. nameLocation,
  68. nameGap,
  69. nameRotate,
  70. showInterval,
  71. xAxisInterval,
  72. xAxisRotate
  73. } = dimetionAxisConfig
  74. const { showLine, lineStyle, lineSize, lineColor } = splitLineConfig
  75. const intervalOption = showInterval ? { interval: xAxisInterval } : null
  76. return {
  77. data,
  78. inverse,
  79. axisLabel: {
  80. show: showLabelX,
  81. color: labelColorX,
  82. fontFamily: labelFontFamilyX,
  83. fontSize: Number(labelFontSizeX),
  84. rotate: xAxisRotate,
  85. ...intervalOption
  86. },
  87. axisLine: {
  88. show: showLineX,
  89. lineStyle: {
  90. color: lineColorX,
  91. width: Number(lineSizeX),
  92. type: lineStyleX
  93. }
  94. },
  95. axisTick: {
  96. show: showLabelX,
  97. lineStyle: {
  98. color: lineColorX
  99. }
  100. },
  101. splitLine: {
  102. show: showLine,
  103. lineStyle: {
  104. color: lineColor,
  105. width: Number(lineSize),
  106. type: lineStyle
  107. }
  108. },
  109. nameLocation,
  110. nameRotate,
  111. nameGap
  112. }
  113. }
  114. export function getMetricAxisOption(
  115. metricAxisConfig: IAxisConfig,
  116. splitLineConfig: ISplitLineConfig,
  117. title: string,
  118. axis: 'x' | 'y' = 'y',
  119. percentage?: boolean
  120. ): EChartOption.YAxis {
  121. const {
  122. inverse,
  123. showLine: showLineY,
  124. lineStyle: lineStyleY,
  125. lineSize: lineSizeY,
  126. lineColor: lineColorY,
  127. showLabel: showLabelY,
  128. labelFontFamily: labelFontFamilyY,
  129. labelFontSize: labelFontSizeY,
  130. labelColor: labelColorY,
  131. showTitleAndUnit,
  132. titleFontFamily,
  133. titleFontSize,
  134. titleColor,
  135. nameLocation,
  136. nameRotate,
  137. nameGap,
  138. min,
  139. max
  140. } = metricAxisConfig
  141. const { showLine, lineStyle, lineSize, lineColor } = splitLineConfig
  142. return {
  143. type: 'value',
  144. inverse,
  145. min: percentage ? 0 : min,
  146. max: percentage ? 100 : max,
  147. axisLabel: {
  148. show: showLabelY,
  149. color: labelColorY,
  150. fontFamily: labelFontFamilyY,
  151. fontSize: Number(labelFontSizeY),
  152. formatter: percentage ? '{value}%' : metricAxisLabelFormatter
  153. },
  154. axisLine: {
  155. show: showLineY,
  156. lineStyle: {
  157. color: lineColorY,
  158. width: Number(lineSizeY),
  159. type: lineStyleY
  160. }
  161. },
  162. axisTick: {
  163. show: showLabelY,
  164. lineStyle: {
  165. color: lineColorY
  166. }
  167. },
  168. name: showTitleAndUnit ? title : '',
  169. nameLocation,
  170. nameGap,
  171. nameRotate,
  172. nameTextStyle: {
  173. color: titleColor,
  174. fontFamily: titleFontFamily,
  175. fontSize: Number(titleFontSize)
  176. },
  177. splitLine: {
  178. show: showLine,
  179. lineStyle: {
  180. color: lineColor,
  181. width: Number(lineSize),
  182. type: lineStyle
  183. }
  184. }
  185. }
  186. }
  187. export function getLabelOption(
  188. type: string,
  189. labelConfig: ILabelConfig,
  190. metrics,
  191. emphasis?: boolean,
  192. options?: object
  193. ) {
  194. const {
  195. showLabel,
  196. labelPosition,
  197. labelFontFamily,
  198. labelFontSize,
  199. labelColor,
  200. pieLabelPosition,
  201. funnelLabelPosition
  202. } = labelConfig
  203. let position
  204. switch (type) {
  205. case 'pie':
  206. position = pieLabelPosition
  207. break
  208. case 'funnel':
  209. position = funnelLabelPosition
  210. break
  211. default:
  212. position = labelPosition
  213. break
  214. }
  215. let formatter
  216. switch (type) {
  217. case 'line':
  218. formatter = (params) => {
  219. const { value, seriesId } = params
  220. const m = metrics.find(
  221. (m) =>
  222. m.name === seriesId.split(`${DEFAULT_SPLITER}${DEFAULT_SPLITER}`)[0]
  223. )
  224. const formattedValue = getFormattedValue(value, m.format)
  225. return formattedValue
  226. }
  227. break
  228. case 'waterfall':
  229. formatter = (params) => {
  230. const { value } = params
  231. const formattedValue = getFormattedValue(value, metrics[0].format)
  232. return formattedValue
  233. }
  234. break
  235. case 'scatter':
  236. formatter = (params) => {
  237. const { value } = params
  238. const formattedValue = getFormattedValue(value[0], metrics[0].format)
  239. return formattedValue
  240. }
  241. break
  242. case 'pie':
  243. case 'funnel':
  244. formatter = (params) => {
  245. const { name, value, percent, dataIndex, data } = params
  246. const formattedValue = getFormattedValue(
  247. value,
  248. metrics[metrics.length > 1 ? dataIndex : 0].format
  249. )
  250. const { labelParts } = labelConfig
  251. if (!labelParts) {
  252. return `${name}\n${formattedValue}(${percent}%)`
  253. }
  254. const labels: string[] = []
  255. const multiRate =
  256. labelParts.filter((label) =>
  257. ['percentage', 'conversion', 'arrival'].includes(label)
  258. ).length > 1
  259. if (labelParts.includes('dimensionValue')) {
  260. labels.push(name)
  261. }
  262. if (labelParts.includes('indicatorValue')) {
  263. labels.push(formattedValue)
  264. }
  265. if (labelParts.includes('conversion') && data.conversion) {
  266. labels.push(`${multiRate ? '转化率:' : ''}${data.conversion}%`)
  267. }
  268. if (labelParts.includes('arrival') && data.arrival) {
  269. labels.push(`${multiRate ? '到达率:' : ''}${data.arrival}%`)
  270. }
  271. if (labelParts.includes('percentage')) {
  272. labels.push(`${multiRate ? '百分比:' : ''}${percent}%`)
  273. }
  274. return labels.join('\n')
  275. }
  276. break
  277. case 'radar':
  278. formatter = (params) => {
  279. const { name, value, dataIndex, data } = params
  280. const metricIdx = data.name ? dataIndex : data.value.indexOf(value)
  281. const formattedValue = getFormattedValue(
  282. value,
  283. metrics[metricIdx].format
  284. )
  285. const labelName =
  286. name ||
  287. getFieldAlias(metrics[metricIdx].field, {}) ||
  288. decodeMetricName(metrics[metricIdx].name)
  289. const { labelParts } = labelConfig
  290. if (!labelParts) {
  291. return `${labelName}\n${formattedValue}`
  292. }
  293. const labels: string[] = []
  294. if (labelParts.includes('indicatorName')) {
  295. labels.push(labelName)
  296. }
  297. if (labelParts.includes('indicatorValue')) {
  298. labels.push(formattedValue)
  299. }
  300. if (labels.length > 1) {
  301. labels.splice(1, 0, '\n')
  302. }
  303. return labels.join('')
  304. }
  305. break
  306. case 'lines':
  307. formatter = (param) => {
  308. const { name, data } = param
  309. return `${name}(${data.value[2]})`
  310. }
  311. break
  312. }
  313. const labelOption = {
  314. normal: {
  315. show: type === 'pie' && pieLabelPosition === 'center' ? false : showLabel,
  316. position,
  317. distance: 15,
  318. color: labelColor,
  319. fontFamily: labelFontFamily,
  320. fontSize: labelFontSize,
  321. formatter,
  322. ...options
  323. },
  324. ...(emphasis && {
  325. emphasis: {
  326. show: showLabel,
  327. position,
  328. distance: 15,
  329. color: labelColor,
  330. fontFamily: labelFontFamily,
  331. fontSize: labelFontSize,
  332. formatter,
  333. ...options
  334. }
  335. })
  336. }
  337. return labelOption
  338. }
  339. export function getLegendOption(
  340. legendConfig: ILegendConfig,
  341. seriesNames: string[]
  342. ) {
  343. const {
  344. showLegend,
  345. legendPosition,
  346. legendType,
  347. selectAll,
  348. fontFamily,
  349. fontSize,
  350. color
  351. } = legendConfig
  352. let orient
  353. let positions
  354. let type
  355. switch (legendType) {
  356. case 'plain':
  357. type = 'plain'
  358. break
  359. case 'scroll':
  360. type = 'scroll'
  361. break
  362. default:
  363. break
  364. }
  365. switch (legendPosition) {
  366. case 'top':
  367. orient = { orient: 'horizontal' }
  368. positions = { top: 8, left: 8, right: 8, height: 32 }
  369. break
  370. case 'bottom':
  371. orient = { orient: 'horizontal' }
  372. positions = { bottom: 8, left: 8, right: 8, height: 32 }
  373. break
  374. case 'left':
  375. orient = { orient: 'vertical' }
  376. positions = { left: 8, top: 16, bottom: 24, width: 96 }
  377. break
  378. default:
  379. orient = { orient: 'vertical' }
  380. positions = { right: 8, top: 16, bottom: 24, width: 96 }
  381. break
  382. }
  383. const selected = {
  384. selected: seriesNames.reduce(
  385. (obj, name) => ({
  386. ...obj,
  387. [name]: selectAll
  388. }),
  389. {}
  390. )
  391. }
  392. return {
  393. show: showLegend && seriesNames.length > 1,
  394. data: seriesNames,
  395. type,
  396. textStyle: {
  397. fontFamily,
  398. fontSize,
  399. color
  400. },
  401. ...orient,
  402. ...positions,
  403. ...selected
  404. }
  405. }
  406. export function getGridPositions(
  407. legendConfig: Partial<ILegendConfig>,
  408. seriesNames,
  409. chartName?: string,
  410. isHorizontalBar?: boolean,
  411. yAxisConfig?: IAxisConfig,
  412. dimetionAxisConfig?: IAxisConfig,
  413. xAxisData?: string[]
  414. ) {
  415. const { showLegend, legendPosition, fontSize } = legendConfig
  416. return CHART_LEGEND_POSITIONS.reduce((grid, pos) => {
  417. const val = pos.value
  418. grid[val] = getGridBase(
  419. val,
  420. chartName,
  421. dimetionAxisConfig,
  422. xAxisData,
  423. isHorizontalBar,
  424. yAxisConfig
  425. )
  426. if (showLegend && seriesNames.length > 1) {
  427. grid[val] +=
  428. legendPosition === val
  429. ? ['top', 'bottom'].includes(val)
  430. ? 64
  431. : 64 +
  432. Math.max(
  433. ...seriesNames.map((s) => getTextWidth(s, '', `${fontSize}px`))
  434. )
  435. : 0
  436. }
  437. return grid
  438. }, {})
  439. }
  440. function getGridBase(
  441. pos,
  442. chartName,
  443. dimetionAxisConfig?: IAxisConfig,
  444. xAxisData?: string[],
  445. isHorizontalBar?: boolean,
  446. yAxisConfig?: IAxisConfig
  447. ) {
  448. const labelFontSize = dimetionAxisConfig
  449. ? dimetionAxisConfig.labelFontSize
  450. : 12
  451. const xAxisRotate = dimetionAxisConfig ? dimetionAxisConfig.xAxisRotate : 0
  452. const maxWidth =
  453. xAxisData && xAxisData.length
  454. ? Math.max(
  455. ...xAxisData.map((s) => getTextWidth(s, '', `${labelFontSize}px`))
  456. )
  457. : 0
  458. const bottomDistance =
  459. dimetionAxisConfig && dimetionAxisConfig.showLabel
  460. ? isHorizontalBar
  461. ? 50
  462. : xAxisRotate
  463. ? 50 + Math.sin((xAxisRotate * Math.PI) / 180) * maxWidth
  464. : 50
  465. : 50
  466. const yAxisConfigLeft =
  467. yAxisConfig && !yAxisConfig.showLabel && !yAxisConfig.showTitleAndUnit
  468. ? 24
  469. : 64
  470. const leftDistance =
  471. dimetionAxisConfig && dimetionAxisConfig.showLabel
  472. ? isHorizontalBar
  473. ? xAxisRotate === void 0
  474. ? 64
  475. : 24 + Math.cos((xAxisRotate * Math.PI) / 180) * maxWidth
  476. : yAxisConfigLeft
  477. : isHorizontalBar
  478. ? 24
  479. : yAxisConfigLeft
  480. switch (pos) {
  481. case 'top':
  482. return 24
  483. case 'left':
  484. return leftDistance
  485. case 'right':
  486. return chartName === 'doubleYAxis' ? 64 : 24
  487. case 'bottom':
  488. return bottomDistance
  489. }
  490. }
  491. export function makeGrouped(
  492. data: object[],
  493. groupColumns: string[],
  494. xAxisColumn: string,
  495. metrics: IWidgetMetric[],
  496. xAxisData: string[]
  497. ) {
  498. const grouped = {}
  499. data.forEach((d) => {
  500. const groupingKey = groupColumns.map((col) => d[col]).join(' ')
  501. const colKey = d[xAxisColumn] || 'default'
  502. if (!grouped[groupingKey]) {
  503. grouped[groupingKey] = {}
  504. }
  505. if (!grouped[groupingKey][colKey]) {
  506. grouped[groupingKey][colKey] = []
  507. }
  508. grouped[groupingKey][colKey].push(d)
  509. })
  510. Object.keys(grouped).forEach((groupingKey) => {
  511. const currentGroupValues = grouped[groupingKey]
  512. grouped[groupingKey] = xAxisData.length
  513. ? xAxisData.map((xd) => {
  514. if (currentGroupValues[xd]) {
  515. return currentGroupValues[xd][0]
  516. } else {
  517. return metrics.reduce(
  518. (obj, m) => ({
  519. ...obj,
  520. [`${m.agg}(${decodeMetricName(m.name)})`]: 0
  521. }),
  522. {
  523. [xAxisColumn]: xd
  524. // []: groupingKey
  525. }
  526. )
  527. }
  528. })
  529. : [currentGroupValues['default'][0]]
  530. })
  531. return grouped
  532. }
  533. // TODO: function explanation
  534. export function getGroupedXaxis(data, xAxisColumn, metrics) {
  535. if (xAxisColumn) {
  536. const metricsInSorting = metrics.filter(
  537. ({ sort }) => sort && sort.sortType !== FieldSortTypes.Default
  538. )
  539. const appliedMetric = metricsInSorting.length ? metricsInSorting[0] : void 0
  540. const dataGroupByXaxis = data.reduce((grouped, d) => {
  541. const colKey = d[xAxisColumn]
  542. if (grouped[colKey] === void 0) {
  543. grouped[colKey] = 0
  544. }
  545. if (appliedMetric) {
  546. const { agg, name } = appliedMetric
  547. grouped[colKey] += d[`${agg}(${decodeMetricName(name)})`]
  548. }
  549. return grouped
  550. }, {})
  551. if (appliedMetric) {
  552. return Object.entries(dataGroupByXaxis)
  553. .sort((p1: [string, number], p2: [string, number]) => {
  554. return appliedMetric.sort.sortType === FieldSortTypes.Asc
  555. ? p1[1] - p2[1]
  556. : appliedMetric.sort.sortType === FieldSortTypes.Desc
  557. ? p2[1] - p1[1]
  558. : 0
  559. })
  560. .map(([key, value]) => key)
  561. } else {
  562. return Object.keys(dataGroupByXaxis)
  563. }
  564. }
  565. return []
  566. }
  567. export function getSymbolSize(sizeRate, size) {
  568. return sizeRate ? Math.ceil(size / sizeRate) : size
  569. }
  570. export function getCartesianChartMetrics(metrics: IWidgetMetric[]) {
  571. return metrics.map((metric) => {
  572. const { name, agg } = metric
  573. const decodedMetricName = decodeMetricName(name)
  574. const duplicates = metrics.filter(
  575. (m) => decodeMetricName(m.name) === decodedMetricName && m.agg === agg
  576. )
  577. const prefix = agg !== 'sum' ? `[${getAggregatorLocale(agg)}] ` : ''
  578. const suffix =
  579. duplicates.length > 1
  580. ? duplicates.indexOf(metric)
  581. ? duplicates.indexOf(metric) + 1
  582. : ''
  583. : ''
  584. return {
  585. ...metric,
  586. displayName: `${prefix}${decodedMetricName}${suffix}`
  587. }
  588. })
  589. }
  590. export function getCartesianChartReferenceOptions(
  591. references: IReference[],
  592. chartType: ChartTypes,
  593. metrics: IWidgetMetric[],
  594. sourcedata: any[],
  595. barChart?: boolean
  596. ) {
  597. if (references) {
  598. const markLines = []
  599. const markAreas = []
  600. references.forEach((ref) => {
  601. const { name, type, data } = ref
  602. if (type === ReferenceType.Line) {
  603. const {
  604. metric,
  605. type: valueType,
  606. value,
  607. label,
  608. line
  609. } = data as IReferenceLineData
  610. const axis = getReferenceDataMetricAxis(chartType, {
  611. barChart,
  612. metrics,
  613. metric
  614. })
  615. if (axis) {
  616. const metricData = sourcedata.map((d) => {
  617. const metricObject = metrics.find((m) => m.name === metric)
  618. return (
  619. metricObject &&
  620. d[`${metricObject.agg}(${decodeMetricName(metric)})`]
  621. )
  622. })
  623. markLines.push({
  624. ...getReferenceDataOptions(metricData, valueType, value, axis),
  625. name,
  626. label: {
  627. show: label.visible,
  628. position: label.position,
  629. color: label.font.color,
  630. fontSize: label.font.size,
  631. fontFamily: label.font.family
  632. },
  633. lineStyle: {
  634. color: line.color,
  635. width: line.width,
  636. type: line.type
  637. }
  638. })
  639. }
  640. } else {
  641. const areaData = (data as [IReferenceBandData, IReferenceBandData]).map(
  642. (d, index) => {
  643. const { metric, type: valueType, value, label, band } = d
  644. const axis = getReferenceDataMetricAxis(chartType, {
  645. barChart,
  646. metrics,
  647. metric
  648. })
  649. if (axis) {
  650. const metricData = sourcedata.map((d) => {
  651. const metricObject = metrics.find((m) => m.name === metric)
  652. return (
  653. metricObject &&
  654. d[`${metricObject.agg}(${decodeMetricName(metric)})`]
  655. )
  656. })
  657. const dataOptions = getReferenceDataOptions(
  658. metricData,
  659. valueType,
  660. value,
  661. axis
  662. )
  663. return !index
  664. ? dataOptions
  665. : {
  666. ...dataOptions,
  667. name,
  668. label: {
  669. show: label.visible,
  670. position: label.position,
  671. color: label.font.color,
  672. fontSize: label.font.size,
  673. fontFamily: label.font.family
  674. },
  675. emphasis: {
  676. label: {
  677. position: label.position
  678. }
  679. },
  680. itemStyle: {
  681. color: band.color,
  682. borderColor: band.border.color,
  683. borderWidth: band.border.width,
  684. borderType: band.border.type
  685. }
  686. }
  687. } else {
  688. return void 0
  689. }
  690. }
  691. )
  692. if (areaData.every((d) => !!d)) {
  693. markAreas.push(areaData)
  694. }
  695. }
  696. })
  697. return {
  698. ...(markLines.length && { markLine: { data: markLines } }),
  699. ...(markAreas.length && { markArea: { data: markAreas } })
  700. }
  701. }
  702. }
  703. function getReferenceDataOptions(
  704. metricData: number[],
  705. valueType: ReferenceValueType,
  706. value: any,
  707. axis: string
  708. ) {
  709. const option: any = {}
  710. if (valueType === ReferenceValueType.Constant) {
  711. option[axis] = value
  712. } else {
  713. option[axis] = calcAggregateReferenceData(valueType, metricData)
  714. }
  715. return option
  716. }
  717. function getReferenceDataMetricAxis(
  718. chartType: ChartTypes,
  719. options?: {
  720. barChart?: boolean
  721. metrics?: IWidgetMetric[]
  722. metric?: string
  723. }
  724. ) {
  725. switch (chartType) {
  726. case ChartTypes.Bar:
  727. return options.barChart ? 'xAxis' : 'yAxis'
  728. case ChartTypes.Scatter:
  729. const axisIndexMapping = ['xAxis', 'yAxis']
  730. const metricIndex = options.metrics.findIndex(
  731. (m) => m.name === options.metric
  732. )
  733. return axisIndexMapping[metricIndex]
  734. default:
  735. return 'yAxis'
  736. }
  737. }
  738. function calcAggregateReferenceData(
  739. valueType: ReferenceValueType,
  740. metricData: number[]
  741. ) {
  742. switch (valueType) {
  743. case ReferenceValueType.Max:
  744. return Math.max(...metricData)
  745. case ReferenceValueType.Min:
  746. return Math.min(...metricData)
  747. case ReferenceValueType.Average:
  748. return mean(metricData)
  749. }
  750. }