BodyCell.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 React from 'react'
  21. import OperatorTypes from 'utils/operatorTypes'
  22. import { ITableColumnConfig, ITableConditionStyle, DefaultTableCellStyle } from 'containers/Widget/components/Config/Table'
  23. import { IFieldFormatConfig, getFormattedValue } from 'containers/Widget/components/Config/Format'
  24. import { TableConditionStyleTypes } from 'containers/Widget/components/Config/Table/Column'
  25. import { textAlignAdapter } from '../util'
  26. interface IBodyCellProps {
  27. format: IFieldFormatConfig
  28. config: ITableColumnConfig
  29. cellVal: string | number
  30. cellValRange: [number, number]
  31. children: Array<string | number | boolean>
  32. }
  33. function BodyCell (props: IBodyCellProps) {
  34. const { format, config, cellVal, cellValRange, ...rest } = props
  35. const cellCssStyle = getBodyCellStyle(config, cellVal, cellValRange)
  36. if (format) {
  37. const formattedVal = getFormattedValue(cellVal, format)
  38. return (
  39. <td style={cellCssStyle} {...rest}>{formattedVal}</td>
  40. )
  41. }
  42. return (
  43. <td style={cellCssStyle} {...rest} />
  44. )
  45. }
  46. export default BodyCell
  47. function getBodyCellStyle (columnConfig: ITableColumnConfig, cellVal: string | number, cellValRange: [number, number]) {
  48. const basicStyle = getBasicStyledCell(columnConfig)
  49. const conditionStyle = getMergedConditionStyledCell(basicStyle, cellVal, columnConfig, cellValRange)
  50. const cellStyle = { ...basicStyle, ...conditionStyle }
  51. return cellStyle
  52. }
  53. function getBasicStyledCell (columnConfig: ITableColumnConfig) {
  54. const style = columnConfig ? columnConfig.style : DefaultTableCellStyle
  55. const { fontSize, fontFamily, fontWeight, fontColor, fontStyle, backgroundColor, justifyContent } = style
  56. const cssStyle: React.CSSProperties = {
  57. fontSize: `${fontSize}px`,
  58. fontFamily,
  59. fontWeight: fontWeight as React.CSSProperties['fontWeight'],
  60. color: fontColor,
  61. fontStyle,
  62. backgroundColor,
  63. textAlign: textAlignAdapter(justifyContent)
  64. }
  65. return cssStyle
  66. }
  67. function hasMatchedTheCondition (
  68. cellVal: string | number,
  69. operatorType: OperatorTypes,
  70. conditionValues: Array<string | number>
  71. ) {
  72. let matchTheCondition = false
  73. switch (operatorType) {
  74. case OperatorTypes.Between:
  75. const [minVal, maxVal] = conditionValues
  76. matchTheCondition = (cellVal >= minVal && cellVal <= maxVal)
  77. break
  78. case OperatorTypes.Contain:
  79. matchTheCondition = cellVal.toString().indexOf(conditionValues[0].toString()) >= 0
  80. break
  81. case OperatorTypes.Equal:
  82. matchTheCondition = (cellVal === conditionValues[0])
  83. break
  84. case OperatorTypes.GreaterThan:
  85. matchTheCondition = (cellVal > conditionValues[0])
  86. break
  87. case OperatorTypes.GreaterThanOrEqual:
  88. matchTheCondition = (cellVal >= conditionValues[0])
  89. break
  90. case OperatorTypes.In:
  91. matchTheCondition = conditionValues.findIndex((cVal) => cVal === cellVal) >= 0
  92. break
  93. case OperatorTypes.LessThan:
  94. matchTheCondition = (cellVal < conditionValues[0])
  95. break
  96. case OperatorTypes.LessThanOrEqual:
  97. matchTheCondition = (cellVal <= conditionValues[0])
  98. break
  99. case OperatorTypes.NotEqual:
  100. matchTheCondition = (cellVal !== conditionValues[0])
  101. break
  102. }
  103. return matchTheCondition
  104. }
  105. function getBackgroundConditionCellStyle (
  106. conditionStyle: ITableConditionStyle
  107. ): React.CSSProperties {
  108. const { colors } = conditionStyle
  109. const { fore, background } = colors
  110. const cssStyle: React.CSSProperties = {
  111. color: fore,
  112. backgroundColor: background
  113. }
  114. return cssStyle
  115. }
  116. function getTextConditionCellStyle (
  117. conditionStyle: ITableConditionStyle
  118. ): React.CSSProperties {
  119. const { colors } = conditionStyle
  120. const { fore } = colors
  121. const cssStyle: React.CSSProperties = {
  122. color: fore
  123. }
  124. return cssStyle
  125. }
  126. function getNumericBarConditionCellStyle (
  127. basicStyle: React.CSSProperties,
  128. conditionStyle: ITableConditionStyle,
  129. cellVal: number,
  130. maxCellVal: number,
  131. minCellVal: number
  132. ): React.CSSProperties {
  133. const { zeroPosition, colors } = conditionStyle
  134. const { fore, positive, negative } = colors
  135. const valRange = (Math.max(maxCellVal, 0) - Math.min(0, minCellVal))
  136. let cellBarPercentage: number = void 0
  137. if (cellVal < minCellVal) {
  138. cellBarPercentage = 0
  139. } else if (cellVal > maxCellVal) {
  140. cellBarPercentage = 100
  141. }
  142. let barZeroPosition: number
  143. switch (zeroPosition) {
  144. case 'center':
  145. if (cellBarPercentage === void 0) {
  146. cellBarPercentage = Math.abs(cellVal) / Math.max(Math.abs(minCellVal), Math.abs(maxCellVal)) * 50
  147. }
  148. barZeroPosition = 50
  149. break
  150. case 'auto':
  151. if (cellBarPercentage === void 0) {
  152. cellBarPercentage = (Math.abs(cellVal) / valRange) * 100
  153. }
  154. barZeroPosition = Math.abs(Math.min(0, minCellVal)) / (Math.abs(minCellVal) + Math.abs(maxCellVal)) * 100
  155. break
  156. }
  157. const backgroundColor = basicStyle.backgroundColor || 'transparent'
  158. const divisions = [`${backgroundColor} 0%`]
  159. if (cellVal < 0) {
  160. divisions.push(`${backgroundColor} ${barZeroPosition - cellBarPercentage}%`)
  161. divisions.push(`${negative} ${barZeroPosition - cellBarPercentage}%`)
  162. divisions.push(`${negative} ${barZeroPosition}%`)
  163. divisions.push(`${backgroundColor} ${barZeroPosition}%`)
  164. } else {
  165. divisions.push(`${backgroundColor} ${barZeroPosition}%`)
  166. divisions.push(`${positive} ${barZeroPosition}%`)
  167. divisions.push(`${positive} ${barZeroPosition + cellBarPercentage}%`)
  168. divisions.push(`${backgroundColor} ${barZeroPosition + cellBarPercentage}%`)
  169. }
  170. divisions.push(`${backgroundColor} 100%`)
  171. const cssStyle: React.CSSProperties = {
  172. color: fore,
  173. background: `linear-gradient(90deg, ${divisions.join(',')})`
  174. }
  175. return cssStyle
  176. }
  177. function getConditionStyledCell (
  178. basicStyle: React.CSSProperties,
  179. cellVal: string | number,
  180. conditionStyle: ITableConditionStyle,
  181. cellValRange?: [number, number]
  182. ) {
  183. const { operatorType, conditionValues, type } = conditionStyle
  184. const matchTheCondition = hasMatchedTheCondition(cellVal, operatorType, conditionValues)
  185. if (!matchTheCondition) { return null }
  186. let cssStyle: React.CSSProperties
  187. switch (type) {
  188. case TableConditionStyleTypes.BackgroundColor:
  189. cssStyle = getBackgroundConditionCellStyle(conditionStyle)
  190. break
  191. case TableConditionStyleTypes.TextColor:
  192. cssStyle = getTextConditionCellStyle(conditionStyle)
  193. break
  194. case TableConditionStyleTypes.NumericBar:
  195. const [minCellVal, maxCellVal] = cellValRange
  196. cssStyle = getNumericBarConditionCellStyle(basicStyle, conditionStyle, +cellVal, maxCellVal, minCellVal)
  197. break
  198. case TableConditionStyleTypes.Custom:
  199. // @TODO
  200. break
  201. }
  202. return cssStyle
  203. }
  204. function getMergedConditionStyledCell (
  205. basicStyle: React.CSSProperties,
  206. cellVal: string | number,
  207. columnConfig: ITableColumnConfig,
  208. cellValRange?: [number, number]
  209. ): React.CSSProperties {
  210. if (!columnConfig) { return null }
  211. const { styleType, conditionStyles } = columnConfig
  212. let conditionCellStyle: React.CSSProperties
  213. if (conditionStyles.length > 0) {
  214. conditionCellStyle = conditionStyles.reduce((acc, c) => ({
  215. ...acc,
  216. ...getConditionStyledCell(basicStyle, cellVal, c, cellValRange)
  217. }), {})
  218. }
  219. return conditionCellStyle
  220. }