util.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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 { ITableCellStyle, ITableColumnConfig, DefaultTableCellStyle } from 'containers/Widget/components/Config/Table'
  21. import { getTextWidth } from 'utils/util'
  22. import { IFieldFormatConfig, getFormattedValue } from 'containers/Widget/components/Config/Format'
  23. import { IWidgetDimension } from '../../Widget'
  24. export function traverseConfig<T> (config: T[], childrenName: keyof T, callback: (currentConfig: T, idx: number, siblings: T[]) => any) {
  25. if (!Array.isArray(config)) { return }
  26. config.forEach((cfg, idx) => {
  27. if (Array.isArray(cfg[childrenName])) {
  28. const children = cfg[childrenName as string] as T[]
  29. if (children.length > 0) {
  30. traverseConfig(children, childrenName, callback)
  31. }
  32. }
  33. callback(cfg, idx, config)
  34. })
  35. }
  36. export function findChildConfig<T> (
  37. config: T[],
  38. keyName: keyof T,
  39. childrenName: keyof T,
  40. keyValue: valueof<T>,
  41. callback: (config: T) => any
  42. ) {
  43. if (!Array.isArray(config)) { return false }
  44. const hasFound = config.some((cfg) => {
  45. if (cfg[keyName] === keyValue) {
  46. callback(cfg)
  47. return true
  48. }
  49. const children = cfg[childrenName]
  50. if (Array.isArray(children) && children.length > 0) {
  51. return findChildConfig(children, keyName, childrenName, keyValue, callback)
  52. }
  53. return false
  54. })
  55. return hasFound
  56. }
  57. export function textAlignAdapter (justifyContent: ITableCellStyle['justifyContent']) {
  58. switch (justifyContent) {
  59. case 'flex-start': return 'left'
  60. case 'center': return 'center'
  61. case 'flex-end': return 'right'
  62. default: return 'inherit'
  63. }
  64. }
  65. export function getCellSpanMap(
  66. data: any[],
  67. dimensions: IWidgetDimension[]
  68. ): { [columnName: string]: number[] } {
  69. const map = {}
  70. const columnsSpanEndIndexRecorder = {}
  71. dimensions.forEach(({ name }) => {
  72. map[name] = []
  73. columnsSpanEndIndexRecorder[name] = -1
  74. })
  75. data.forEach((record, index) => {
  76. const prevRecord = data[index - 1]
  77. dimensions.forEach(({ name }, dIndex) => {
  78. const prevColumnName = dimensions[dIndex - 1]?.name
  79. if (
  80. columnsSpanEndIndexRecorder[name] !== index - 1 &&
  81. prevRecord &&
  82. prevRecord[name] === record[name]
  83. ) {
  84. map[name][index] = 0
  85. return
  86. }
  87. if (columnsSpanEndIndexRecorder[prevColumnName] === index) {
  88. map[name][index] = 1
  89. columnsSpanEndIndexRecorder[name] = index
  90. return
  91. }
  92. let span = 1
  93. while (true) {
  94. const nextRecord = data[index + span]
  95. const currentDataIndex = index + span - 1
  96. if (
  97. nextRecord &&
  98. nextRecord[name] === record[name] &&
  99. !(
  100. prevColumnName &&
  101. currentDataIndex >= columnsSpanEndIndexRecorder[prevColumnName]
  102. )
  103. ) {
  104. span += 1
  105. } else {
  106. map[name][index] = span
  107. columnsSpanEndIndexRecorder[name] = currentDataIndex
  108. break
  109. }
  110. }
  111. })
  112. })
  113. return map
  114. }
  115. export function computeCellWidth (style: ITableCellStyle, cellValue: string | number) {
  116. const { fontWeight, fontSize, fontFamily } = style || DefaultTableCellStyle
  117. const cellWidth = !cellValue ? 0 : getTextWidth(cellValue.toString(), fontWeight, `${fontSize}px`, fontFamily)
  118. return cellWidth + 16 + 2
  119. }
  120. export function getDataColumnWidth (expression: string, columnConfig: ITableColumnConfig, format: IFieldFormatConfig, data: any[]) {
  121. if (!data.length) { return 0 }
  122. const style = columnConfig && columnConfig.style
  123. let values = data.map((record) => record[expression])
  124. values = values.filter((value, idx) => values.indexOf(value) === idx)
  125. const maxCellWidth = values.reduce((w, value) => {
  126. const formattedValue = getFormattedValue(value, format)
  127. const cellWidth = computeCellWidth(style, formattedValue)
  128. return Math.max(w, cellWidth)
  129. }, 0)
  130. return maxCellWidth
  131. }
  132. export function getTableCellValueRange (data: any[], propName: string, columnConfig?: ITableColumnConfig): [number, number] {
  133. if (data.length <= 0) { return [0, 0] }
  134. let minVal = Infinity
  135. let maxVal = -Infinity
  136. if (columnConfig) {
  137. const { conditionStyles } = columnConfig
  138. conditionStyles.forEach((style) => {
  139. if (!style.bar) { return }
  140. const { mode, min, max } = style.bar
  141. if (mode === 'auto') { return }
  142. if (typeof min === 'number') { minVal = min }
  143. if (typeof max === 'number') { maxVal = max }
  144. })
  145. } else {
  146. return [0, 0]
  147. }
  148. const validMinVal = minVal !== Infinity
  149. const validMaxVal = maxVal !== -Infinity
  150. if (validMinVal && validMaxVal) {
  151. return [minVal, maxVal]
  152. }
  153. data.forEach((item) => {
  154. const cellVal = item[propName]
  155. if (typeof cellVal !== 'number' && (typeof cellVal !== 'string' || isNaN(+cellVal))) { return }
  156. const cellNumVal = +cellVal
  157. if (!validMinVal && cellNumVal < minVal) { minVal = cellNumVal }
  158. if (!validMaxVal && cellNumVal > maxVal) { maxVal = cellNumVal }
  159. })
  160. return [minVal, maxVal]
  161. }