pie.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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 '../../components/Chart'
  21. import { decodeMetricName, getTextWidth } from '../../components/util'
  22. import { getLegendOption, getLabelOption } from './util'
  23. import { EChartOption } from 'echarts'
  24. import { getFormattedValue } from '../../components/Config/Format'
  25. import defaultTheme from 'assets/json/echartsThemes/default.project.json'
  26. const defaultThemeColors = defaultTheme.theme.color
  27. export default function (chartProps: IChartProps, drillOptions?: any) {
  28. const {
  29. width,
  30. height,
  31. data,
  32. cols,
  33. metrics,
  34. chartStyles,
  35. color,
  36. tip
  37. } = chartProps
  38. const { label, legend, spec, toolbox } = chartStyles
  39. const { legendPosition, fontSize } = legend
  40. const { circle, roseType } = spec
  41. const { selectedItems } = drillOptions
  42. // formatter: '{b}({d}%)'
  43. const labelOption = {
  44. label: getLabelOption('pie', label, metrics)
  45. }
  46. const roseTypeValue = roseType ? 'radius' : ''
  47. const radiusValue =
  48. (!circle && !roseType) || (!circle && roseType) ? `70%` : ['48%', '70%']
  49. let seriesObj = {}
  50. const seriesArr = []
  51. let legendData = []
  52. let grouped: { [key: string]: object[] } = {}
  53. if (metrics.length <= 1) {
  54. const groupColumns = color.items
  55. .map((c) => c.name)
  56. .concat(cols.map((c) => c.name))
  57. .reduce((distinctColumns, col) => {
  58. if (!distinctColumns.includes(col)) {
  59. distinctColumns.push(col)
  60. }
  61. return distinctColumns
  62. }, [])
  63. grouped = data.reduce<{ [key: string]: object[] }>((obj, val) => {
  64. const groupingKey = groupColumns
  65. .reduce((keyArr, col) => keyArr.concat(val[col]), [])
  66. .join(String.fromCharCode(0))
  67. if (!obj[groupingKey]) {
  68. obj[groupingKey] = []
  69. }
  70. obj[groupingKey].push(val)
  71. return obj
  72. }, {})
  73. metrics.forEach((metric) => {
  74. const decodedMetricName = decodeMetricName(metric.name)
  75. const seriesData = []
  76. Object.entries(grouped).forEach(([key, value]) => {
  77. const legendStr = key.replace(String.fromCharCode(0), ' ')
  78. legendData.push(legendStr)
  79. value.forEach((v) => {
  80. const obj = {
  81. name: legendStr,
  82. value: v[`${metric.agg}(${decodedMetricName})`]
  83. }
  84. seriesData.push(obj)
  85. })
  86. })
  87. let leftValue
  88. let topValue
  89. const pieLeft =
  90. 56 +
  91. Math.max(...legendData.map((s) => getTextWidth(s, '', `${fontSize}px`)))
  92. switch (legendPosition) {
  93. case 'top':
  94. leftValue = width / 2
  95. topValue = (height + 32) / 2
  96. break
  97. case 'bottom':
  98. leftValue = width / 2
  99. topValue = (height - 32) / 2
  100. break
  101. case 'left':
  102. leftValue = (width + pieLeft) / 2
  103. topValue = height / 2
  104. break
  105. case 'right':
  106. leftValue = (width - pieLeft) / 2
  107. topValue = height / 2
  108. break
  109. }
  110. seriesObj = {
  111. name: '',
  112. type: 'pie',
  113. avoidLabelOverlap: false,
  114. center: legend.showLegend
  115. ? [leftValue, topValue]
  116. : [width / 2, height / 2],
  117. data: seriesData.map((data, index) => {
  118. return {
  119. ...data,
  120. itemStyle: {
  121. normal: {
  122. ...color.items.length && {
  123. color: color.items[0].config.values[data.name]
  124. },
  125. opacity: selectedItems && selectedItems.length
  126. ? selectedItems.includes(index) ? 1 : 0.25
  127. : 1
  128. }
  129. }
  130. }
  131. }),
  132. itemStyle: {
  133. emphasis: {
  134. shadowBlur: 10,
  135. shadowOffsetX: 0,
  136. shadowColor: 'rgba(0, 0, 0, 0.5)'
  137. }
  138. },
  139. ...labelOption,
  140. roseType: roseTypeValue,
  141. radius: radiusValue
  142. }
  143. seriesArr.push(seriesObj)
  144. })
  145. } else {
  146. legendData = []
  147. seriesObj = {
  148. type: 'pie',
  149. avoidLabelOverlap: false,
  150. center: [width / 2, height / 2],
  151. data: metrics.map((metric, index) => {
  152. const decodedMetricName = decodeMetricName(metric.name)
  153. legendData.push(decodedMetricName)
  154. return {
  155. name: decodedMetricName,
  156. value: data.reduce((sum, record) => sum + record[`${metric.agg}(${decodedMetricName})`], 0),
  157. itemStyle: {
  158. normal: {
  159. color: color.value[metric.name] || defaultThemeColors[index % defaultThemeColors.length],
  160. opacity: selectedItems && selectedItems.length
  161. ? selectedItems.includes(index) ? 1 : 0.25
  162. : 1
  163. }
  164. }
  165. }
  166. }),
  167. itemStyle: {
  168. emphasis: {
  169. shadowBlur: 10,
  170. shadowOffsetX: 0,
  171. shadowColor: 'rgba(0, 0, 0, 0.5)'
  172. }
  173. },
  174. ...labelOption,
  175. roseType: roseTypeValue,
  176. radius: radiusValue
  177. }
  178. seriesArr.push(seriesObj)
  179. }
  180. const tooltip: EChartOption.Tooltip = {
  181. trigger: 'item',
  182. formatter (params: EChartOption.Tooltip.Format) {
  183. const { color, name, value, percent, dataIndex } = params
  184. const tooltipLabels = []
  185. if (color) {
  186. tooltipLabels.push(
  187. `<span class="widget-tooltip-circle" style="background: ${color}"></span>`
  188. )
  189. }
  190. tooltipLabels.push(
  191. `${name}<br/>${getFormattedValue(
  192. value as number,
  193. metrics[metrics.length > 1 ? dataIndex : 0].format
  194. )}(${percent}%)`
  195. )
  196. return tooltipLabels.join('')
  197. }
  198. }
  199. return {
  200. tooltip,
  201. legend: getLegendOption(legend, legendData),
  202. series: seriesArr
  203. }
  204. }