area.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. /*
  21. * Area chart options generator
  22. */
  23. export default function (dataSource, flatInfo, chartParams) {
  24. const hasGroups = flatInfo.groups
  25. const {
  26. xAxis,
  27. metrics,
  28. groups,
  29. xAxisInterval,
  30. xAxisRotate,
  31. dataZoomThreshold,
  32. smooth,
  33. step,
  34. stack,
  35. symbol,
  36. hasLegend,
  37. legendSelected,
  38. legendPosition,
  39. toolbox,
  40. splitLineX,
  41. splitLineY,
  42. splitLineStyle,
  43. splitLineWidth,
  44. top,
  45. bottom,
  46. left,
  47. right,
  48. suffixYAxis
  49. } = chartParams
  50. let grouped
  51. let metricOptions
  52. let xAxisOptions
  53. let smoothOption
  54. let stepOption
  55. let stackOption
  56. let symbolOption
  57. let legendOptions
  58. let toolboxOptions
  59. let gridOptions
  60. let dataZoomOptions
  61. let suffixYAxisOptions
  62. suffixYAxisOptions = suffixYAxis && suffixYAxis.length ? {axisLabel: {
  63. formatter: `{value} ${suffixYAxis}`
  64. }} : null
  65. // symbol
  66. symbolOption = symbol && symbol.length
  67. ? { symbol: 'emptyCircle' }
  68. : { symbol: 'none' }
  69. // smooth
  70. smoothOption = smooth && smooth.length ? { smooth: true } : null
  71. // step
  72. stepOption = step && step.length ? { step: true } : null
  73. // stack
  74. stackOption = stack && stack.length ? { stack: 'stack' } : null
  75. // 数据分组
  76. let xAxisDistincted = []
  77. if (hasGroups && groups && groups.length) {
  78. xAxisDistincted = getGroupedXaxis(dataSource, xAxis)
  79. grouped = makeGrouped(dataSource, [].concat(groups).filter((i) => !!i), xAxis, metrics, xAxisDistincted)
  80. }
  81. // series 数据项; series = metrics * groups
  82. const metricArr = []
  83. if (metrics) {
  84. metrics.forEach((m) => {
  85. if (hasGroups && groups && groups.length) {
  86. Object
  87. .keys(grouped)
  88. .forEach((k) => {
  89. const serieObj = {
  90. name: `${k} ${m}`,
  91. type: 'line',
  92. areaStyle: {normal: {}},
  93. sampling: 'average',
  94. data: grouped[k].map((g) => g[m]),
  95. ...symbolOption,
  96. ...smoothOption,
  97. ...stepOption,
  98. ...stackOption
  99. }
  100. metricArr.push(serieObj)
  101. })
  102. } else {
  103. const serieObj = {
  104. name: m,
  105. type: 'line',
  106. areaStyle: {normal: {}},
  107. sampling: 'average',
  108. symbol: symbolOption,
  109. data: dataSource.map((d) => d[m]),
  110. ...symbolOption,
  111. ...smoothOption,
  112. ...stepOption
  113. }
  114. metricArr.push(serieObj)
  115. }
  116. })
  117. metricOptions = {
  118. series: metricArr
  119. }
  120. }
  121. // x轴数据
  122. xAxisOptions = xAxis && {
  123. xAxis: {
  124. data: hasGroups && groups && groups.length
  125. ? xAxisDistincted
  126. : dataSource.map((d) => d[xAxis]),
  127. axisLabel: {
  128. interval: xAxisInterval,
  129. rotate: xAxisRotate
  130. },
  131. splitLine: {
  132. show: splitLineX && splitLineX.length,
  133. lineStyle: {
  134. width: splitLineWidth,
  135. type: splitLineStyle
  136. }
  137. }
  138. }
  139. }
  140. // legend
  141. let adjustedBottom = 0
  142. let adjustedRight = 0
  143. if (hasLegend && hasLegend.length) {
  144. let orient
  145. let positions
  146. switch (legendPosition) {
  147. case 'right':
  148. orient = { orient: 'vertical' }
  149. positions = { right: 8, top: 40, bottom: 16 }
  150. adjustedRight = 108
  151. break
  152. case 'bottom':
  153. orient = { orient: 'horizontal' }
  154. positions = { bottom: 16, left: 8, right: 8 }
  155. adjustedBottom = 72
  156. break
  157. default:
  158. orient = { orient: 'horizontal' }
  159. positions = { top: 3, left: 8, right: 120 }
  160. break
  161. }
  162. const selected = legendSelected === 'unselectAll'
  163. ? {
  164. selected: metricArr.reduce((obj, m) => ({...obj, [m.name]: false }), {})
  165. } : null
  166. legendOptions = {
  167. legend: {
  168. data: metricArr.map((m) => m.name),
  169. type: 'scroll',
  170. ...orient,
  171. ...positions,
  172. ...selected
  173. }
  174. }
  175. }
  176. // toolbox
  177. toolboxOptions = toolbox && toolbox.length
  178. ? {
  179. toolbox: {
  180. feature: {
  181. dataZoom: {
  182. yAxisIndex: 'none'
  183. },
  184. restore: {},
  185. saveAsImage: {
  186. pixelRatio: 2
  187. }
  188. },
  189. right: 8
  190. }
  191. } : null
  192. // grid
  193. gridOptions = {
  194. grid: {
  195. top,
  196. left,
  197. right: Math.max(right, adjustedRight),
  198. bottom: Math.max(bottom, adjustedBottom)
  199. }
  200. }
  201. dataZoomOptions = dataZoomThreshold > 0 && dataZoomThreshold < dataSource.length && {
  202. dataZoom: [{
  203. type: 'inside',
  204. start: Math.round((1 - dataZoomThreshold / dataSource.length) * 100),
  205. end: 100
  206. }, {
  207. start: Math.round((1 - dataZoomThreshold / dataSource.length) * 100),
  208. end: 100,
  209. handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
  210. handleSize: '80%',
  211. handleStyle: {
  212. color: '#fff',
  213. shadowBlur: 3,
  214. shadowColor: 'rgba(0, 0, 0, 0.6)',
  215. shadowOffsetX: 2,
  216. shadowOffsetY: 2
  217. }
  218. }]
  219. }
  220. return {
  221. yAxis: {
  222. type: 'value',
  223. splitLine: {
  224. show: splitLineY && splitLineY.length,
  225. lineStyle: {
  226. width: splitLineWidth,
  227. type: splitLineStyle
  228. }
  229. },
  230. ...suffixYAxisOptions
  231. },
  232. tooltip: {
  233. trigger: 'axis'
  234. },
  235. ...metricOptions,
  236. ...xAxisOptions,
  237. ...legendOptions,
  238. ...toolboxOptions,
  239. ...gridOptions,
  240. ...dataZoomOptions
  241. }
  242. }
  243. export function makeGrouped (dataSource, groupColumns, xAxis, metrics, xAxisDistincted) {
  244. const grouped = {}
  245. if (xAxis && metrics) {
  246. dataSource.forEach((ds) => {
  247. const accColumn = groupColumns
  248. .reduce((arr, col) => arr.concat(ds[col]), [])
  249. .join(' ')
  250. if (!grouped[accColumn]) {
  251. grouped[accColumn] = {}
  252. }
  253. grouped[accColumn][ds[xAxis]] = ds
  254. })
  255. Object.keys(grouped).map((accColumn) => {
  256. const currentGroupValues = grouped[accColumn]
  257. grouped[accColumn] = xAxisDistincted.map((xd) => {
  258. if (currentGroupValues[xd]) {
  259. return currentGroupValues[xd]
  260. } else {
  261. return metrics.reduce((obj, m) => ({ ...obj, [m]: 0 }), {})
  262. }
  263. })
  264. })
  265. }
  266. return grouped
  267. }
  268. export function getGroupedXaxis (dataSource, xAxis) {
  269. return xAxis
  270. ? Object.keys(dataSource.reduce((distinct, ds) => {
  271. if (!distinct[ds[xAxis]]) {
  272. distinct[ds[xAxis]] = true
  273. }
  274. return distinct
  275. }, {}))
  276. : []
  277. }