doubleYAxis.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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 { IChartProps } from 'containers/Widget/components/Chart'
  21. import {
  22. decodeMetricName,
  23. metricAxisLabelFormatter
  24. } from 'containers/Widget/components/util'
  25. import {
  26. getLegendOption,
  27. getGridPositions,
  28. getDimetionAxisOption,
  29. getCartesianChartReferenceOptions
  30. } from './util'
  31. import { getFormattedValue } from 'containers/Widget/components/Config/Format'
  32. import { getFieldAlias } from 'containers/Widget/components/Config/Field'
  33. import ChartTypes from 'containers/Widget/config/chart/ChartTypes'
  34. import { getMetricsExtendMinAndMax } from './helper'
  35. export default function (chartProps: IChartProps, drillOptions) {
  36. const {
  37. data,
  38. cols,
  39. metrics,
  40. chartStyles,
  41. // color,
  42. // tip,
  43. references
  44. } = chartProps
  45. const { legend, spec, doubleYAxis, xAxis, splitLine } = chartStyles
  46. const { stack, smooth, step, symbol, label } = spec
  47. const { yAxisLeft, yAxisRight, yAxisSplitNumber } = doubleYAxis
  48. const { showLabel } = xAxis
  49. const {
  50. showVerticalLine,
  51. verticalLineColor,
  52. verticalLineSize,
  53. verticalLineStyle
  54. } = splitLine
  55. const labelOption = {
  56. label: {
  57. normal: {
  58. show: label,
  59. position: 'top'
  60. }
  61. }
  62. }
  63. const { selectedItems } = drillOptions
  64. const { secondaryMetrics } = chartProps
  65. const xAxisData = showLabel ? data.map((d) => d[cols[0].name]) : []
  66. const seriesData = secondaryMetrics
  67. ? getAixsMetrics(
  68. 'metrics',
  69. metrics,
  70. data,
  71. stack,
  72. labelOption,
  73. references,
  74. selectedItems,
  75. { key: 'yAxisLeft', type: yAxisLeft }
  76. ).concat(
  77. getAixsMetrics(
  78. 'secondaryMetrics',
  79. secondaryMetrics,
  80. data,
  81. stack,
  82. labelOption,
  83. references,
  84. selectedItems,
  85. { key: 'yAxisRight', type: yAxisRight }
  86. )
  87. )
  88. : getAixsMetrics(
  89. 'metrics',
  90. metrics,
  91. data,
  92. stack,
  93. labelOption,
  94. references,
  95. selectedItems,
  96. { key: 'yAxisLeft', type: yAxisLeft }
  97. )
  98. const seriesObj = {
  99. series: seriesData.map((series) => {
  100. if (series.type === 'line') {
  101. return {
  102. ...series,
  103. symbol: symbol ? 'emptyCircle' : 'none',
  104. smooth,
  105. step
  106. }
  107. } else {
  108. return series
  109. }
  110. })
  111. }
  112. let legendOption
  113. let gridOptions
  114. if (seriesData.length > 1) {
  115. const seriesNames = seriesData.map((s) => s.name)
  116. legendOption = {
  117. legend: getLegendOption(legend, seriesNames)
  118. }
  119. gridOptions = {
  120. grid: getGridPositions(
  121. legend,
  122. seriesNames,
  123. 'doubleYAxis',
  124. false,
  125. null,
  126. xAxis,
  127. xAxisData
  128. )
  129. }
  130. }
  131. const xAxisSplitLineConfig = {
  132. showLine: showVerticalLine,
  133. lineColor: verticalLineColor,
  134. lineSize: verticalLineSize,
  135. lineStyle: verticalLineStyle
  136. }
  137. const allMetrics = secondaryMetrics
  138. ? [].concat(metrics).concat(secondaryMetrics)
  139. : metrics
  140. const { leftY, rightY } = getMetricsExtendMinAndMax(
  141. metrics,
  142. secondaryMetrics,
  143. data,
  144. stack,
  145. yAxisSplitNumber
  146. )
  147. const [leftExtentMin, leftExtentMax, leftInterval] = leftY
  148. const [rightExtentMin, rightExtentMax, rightInterval] = rightY
  149. const option = {
  150. tooltip: {
  151. trigger: 'axis',
  152. axisPointer: { type: 'cross' },
  153. formatter(params) {
  154. const tooltipLabels = [
  155. getFormattedValue(params[0].name, cols[0].format),
  156. '<br/>'
  157. ]
  158. params.reduce((acc, param) => {
  159. const { color, value, seriesIndex } = param
  160. if (color) {
  161. acc.push(
  162. `<span class="widget-tooltip-circle" style="background: ${color}"></span>`
  163. )
  164. }
  165. acc.push(
  166. getFieldAlias(allMetrics[seriesIndex].field, {}) ||
  167. decodeMetricName(allMetrics[seriesIndex].name)
  168. )
  169. acc.push(
  170. ': ',
  171. getFormattedValue(value, allMetrics[seriesIndex].format),
  172. '<br/>'
  173. )
  174. return acc
  175. }, tooltipLabels)
  176. return tooltipLabels.join('')
  177. }
  178. },
  179. xAxis: getDimetionAxisOption(xAxis, xAxisSplitLineConfig, xAxisData),
  180. yAxis: [
  181. {
  182. type: 'value',
  183. key: 'yAxisIndex0',
  184. min: rightExtentMin,
  185. max: rightExtentMax,
  186. interval: +rightInterval,
  187. position: 'right',
  188. showTitleAndUnit: true,
  189. name: getYAxisName(secondaryMetrics),
  190. nameLocation: 'middle',
  191. nameGap: 50,
  192. nameRotate: 90,
  193. nameTextStyle: {
  194. color: '#666',
  195. fontFamily: 'PingFang SC',
  196. fontSize: 12
  197. },
  198. ...getDoubleYAxis(doubleYAxis)
  199. },
  200. {
  201. type: 'value',
  202. key: 'yAxisIndex1',
  203. min: leftExtentMin,
  204. max: leftExtentMax,
  205. interval: +leftInterval,
  206. position: 'left',
  207. showTitleAndUnit: true,
  208. name: getYAxisName(metrics),
  209. nameLocation: 'middle',
  210. nameGap: 50,
  211. nameRotate: 90,
  212. nameTextStyle: {
  213. color: '#666',
  214. fontFamily: 'PingFang SC',
  215. fontSize: 12
  216. },
  217. ...getDoubleYAxis(doubleYAxis)
  218. }
  219. ],
  220. ...seriesObj,
  221. ...gridOptions,
  222. ...legendOption
  223. }
  224. return option
  225. }
  226. export function getAixsMetrics(
  227. type,
  228. axisMetrics,
  229. data,
  230. stack,
  231. labelOption,
  232. references,
  233. selectedItems,
  234. axisPosition?: { key: string; type: string }
  235. ) {
  236. const seriesNames = []
  237. const seriesAxis = []
  238. const referenceOptions = getCartesianChartReferenceOptions(
  239. references,
  240. ChartTypes.DoubleYAxis,
  241. axisMetrics,
  242. data
  243. )
  244. axisMetrics.forEach((m, amIndex) => {
  245. const decodedMetricName = decodeMetricName(m.name)
  246. seriesNames.push(decodedMetricName)
  247. const stackOption =
  248. stack && axisPosition.type === 'bar' && axisMetrics.length > 1
  249. ? { stack: axisPosition.key }
  250. : null
  251. const itemData = data.map((g, index) => {
  252. const itemStyle =
  253. selectedItems &&
  254. selectedItems.length &&
  255. selectedItems.some((item) => item === index)
  256. ? { itemStyle: { normal: { opacity: 1, borderWidth: 6 } } }
  257. : null
  258. return {
  259. value: g[`${m.agg}(${decodedMetricName})`],
  260. ...itemStyle
  261. }
  262. })
  263. seriesAxis.push({
  264. name: decodedMetricName,
  265. type:
  266. axisPosition && axisPosition.type
  267. ? axisPosition.type
  268. : type === 'metrics'
  269. ? 'line'
  270. : 'bar',
  271. ...stackOption,
  272. yAxisIndex: type === 'metrics' ? 1 : 0,
  273. data: itemData,
  274. ...labelOption,
  275. ...(amIndex === axisMetrics.length - 1 && referenceOptions),
  276. itemStyle: {
  277. normal: {
  278. opacity: selectedItems && selectedItems.length > 0 ? 0.25 : 1
  279. }
  280. }
  281. })
  282. })
  283. return seriesAxis
  284. }
  285. export function getYAxisName(metrics) {
  286. return metrics
  287. .map((m) => (m.field.alias ? m.field.alias : decodeMetricName(m.name)))
  288. .join(` / `)
  289. }
  290. export function getDoubleYAxis(doubleYAxis) {
  291. const {
  292. inverse,
  293. showLine,
  294. lineStyle,
  295. lineSize,
  296. lineColor,
  297. showLabel,
  298. labelFontFamily,
  299. labelFontSize,
  300. labelColor
  301. } = doubleYAxis
  302. return {
  303. inverse,
  304. axisLine: {
  305. show: showLine,
  306. lineStyle: {
  307. color: lineColor,
  308. width: Number(lineSize),
  309. type: lineStyle
  310. }
  311. },
  312. axisLabel: {
  313. show: showLabel,
  314. color: labelColor,
  315. fontFamily: labelFontFamily,
  316. fontSize: Number(labelFontSize),
  317. formatter: metricAxisLabelFormatter
  318. }
  319. }
  320. }