index.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. const {
  2. formatMagnitudeNumber,
  3. formatScaledValue,
  4. getOption,
  5. normalizeIndex,
  6. parsePositiveNumber,
  7. selectBestUnit
  8. } = require('../calculator-helpers.js')
  9. const TWO_PI = 2 * Math.PI
  10. const MODE_OPTIONS = [
  11. { key: 'capacitive', label: '容抗' },
  12. { key: 'inductive', label: '感抗' }
  13. ]
  14. const REACTANCE_UNIT_OPTIONS = [
  15. { label: 'mΩ', factor: 1e-3 },
  16. { label: 'Ω', factor: 1 },
  17. { label: 'kΩ', factor: 1e3 },
  18. { label: 'MΩ', factor: 1e6 },
  19. { label: 'GΩ', factor: 1e9 }
  20. ]
  21. const ADMITTANCE_UNIT_OPTIONS = [
  22. { label: 'pS', factor: 1e-12 },
  23. { label: 'nS', factor: 1e-9 },
  24. { label: 'μS', factor: 1e-6 },
  25. { label: 'mS', factor: 1e-3 },
  26. { label: 'S', factor: 1 },
  27. { label: 'kS', factor: 1e3 },
  28. { label: 'MS', factor: 1e6 }
  29. ]
  30. const CAPACITANCE_UNIT_OPTIONS = [
  31. { label: 'pF', factor: 1e-12 },
  32. { label: 'nF', factor: 1e-9 },
  33. { label: 'μF', factor: 1e-6 },
  34. { label: 'mF', factor: 1e-3 },
  35. { label: 'F', factor: 1 }
  36. ]
  37. const INDUCTANCE_UNIT_OPTIONS = [
  38. { label: 'pH', factor: 1e-12 },
  39. { label: 'nH', factor: 1e-9 },
  40. { label: 'μH', factor: 1e-6 },
  41. { label: 'mH', factor: 1e-3 },
  42. { label: 'H', factor: 1 },
  43. { label: 'kH', factor: 1e3 }
  44. ]
  45. const FREQUENCY_UNIT_OPTIONS = [
  46. { label: 'Hz', factor: 1 },
  47. { label: 'kHz', factor: 1e3 },
  48. { label: 'MHz', factor: 1e6 },
  49. { label: 'GHz', factor: 1e9 },
  50. { label: 'THz', factor: 1e12 }
  51. ]
  52. function getReactiveUnitOptions(modeKey) {
  53. return modeKey === 'inductive' ? INDUCTANCE_UNIT_OPTIONS : CAPACITANCE_UNIT_OPTIONS
  54. }
  55. function formatUnitValue(baseValue, options, fallbackIndex = 0) {
  56. if (!Number.isFinite(baseValue)) return '--'
  57. const selected = selectBestUnit(options, baseValue, fallbackIndex)
  58. return formatScaledValue(baseValue, selected.unit, {
  59. fallbackText: '',
  60. includeUnit: true
  61. })
  62. }
  63. function createEmptyResultRows(modeKey) {
  64. const isInductive = modeKey === 'inductive'
  65. return [
  66. {
  67. label: isInductive ? '感抗 XL' : '容抗 XC',
  68. meta: isInductive ? 'XL = 2πfL' : 'XC = 1 / (2πfC)',
  69. value: '--'
  70. },
  71. {
  72. label: isInductive ? '感抗导纳 YL' : '容抗导纳 YC',
  73. meta: 'Y = 1 / X',
  74. value: '--'
  75. }
  76. ]
  77. }
  78. function calculateResultRows(modeKey, frequency, reactive) {
  79. const rows = createEmptyResultRows(modeKey)
  80. if (!Number.isFinite(frequency) || !Number.isFinite(reactive)) return rows
  81. const reactance = modeKey === 'inductive'
  82. ? TWO_PI * frequency * reactive
  83. : 1 / (TWO_PI * frequency * reactive)
  84. const admittance = 1 / reactance
  85. return [
  86. {
  87. ...rows[0],
  88. value: formatUnitValue(reactance, REACTANCE_UNIT_OPTIONS, 1)
  89. },
  90. {
  91. ...rows[1],
  92. value: formatUnitValue(admittance, ADMITTANCE_UNIT_OPTIONS, 4)
  93. }
  94. ]
  95. }
  96. function buildState(source = {}) {
  97. const modeIndex = normalizeIndex(source.reactanceModeIndex, MODE_OPTIONS, 0)
  98. const mode = getOption(MODE_OPTIONS, modeIndex)
  99. const reactiveUnitOptions = getReactiveUnitOptions(mode.key)
  100. const capacitanceUnitIndex = normalizeIndex(source.reactanceCapacitanceUnitIndex, CAPACITANCE_UNIT_OPTIONS, 1)
  101. const frequencyUnitIndex = normalizeIndex(source.reactanceFrequencyUnitIndex, FREQUENCY_UNIT_OPTIONS, 0)
  102. const inductanceUnitIndex = normalizeIndex(source.reactanceInductanceUnitIndex, INDUCTANCE_UNIT_OPTIONS, 3)
  103. const reactiveUnitIndex = mode.key === 'inductive' ? inductanceUnitIndex : capacitanceUnitIndex
  104. const frequencyUnit = getOption(FREQUENCY_UNIT_OPTIONS, frequencyUnitIndex)
  105. const reactiveUnit = getOption(reactiveUnitOptions, reactiveUnitIndex)
  106. const frequencyText = String(source.reactanceFrequencyValue || '')
  107. const reactiveText = String(source.reactanceReactiveValue || '')
  108. const frequencyNumber = parsePositiveNumber(frequencyText)
  109. const reactiveNumber = parsePositiveNumber(reactiveText)
  110. const invalidInput = [frequencyNumber, reactiveNumber].some((value) => Number.isNaN(value))
  111. const values = {
  112. frequency: Number.isFinite(frequencyNumber) ? frequencyNumber * frequencyUnit.factor : null,
  113. reactive: Number.isFinite(reactiveNumber) ? reactiveNumber * reactiveUnit.factor : null
  114. }
  115. let frequencyDisplayUnit = frequencyUnit
  116. let frequencyDisplayUnitIndex = frequencyUnitIndex
  117. let reactiveDisplayUnit = reactiveUnit
  118. let reactiveDisplayUnitIndex = reactiveUnitIndex
  119. let frequencyDisplayValue = Number.isFinite(frequencyNumber)
  120. ? formatMagnitudeNumber(frequencyNumber, { fallbackText: '' })
  121. : frequencyText
  122. let reactiveDisplayValue = Number.isFinite(reactiveNumber)
  123. ? formatMagnitudeNumber(reactiveNumber, { fallbackText: '' })
  124. : reactiveText
  125. const resultRows = invalidInput
  126. ? createEmptyResultRows(mode.key)
  127. : calculateResultRows(mode.key, values.frequency, values.reactive)
  128. return {
  129. reactanceCapacitanceUnitIndex: mode.key === 'capacitive' ? reactiveDisplayUnitIndex : capacitanceUnitIndex,
  130. reactanceErrorText: invalidInput ? '输入值需大于 0' : '',
  131. reactanceFrequencyDisplayValue: frequencyDisplayValue,
  132. reactanceFrequencyUnitIndex: frequencyDisplayUnitIndex,
  133. reactanceFrequencyUnitOptions: FREQUENCY_UNIT_OPTIONS,
  134. reactanceFrequencyUnitText: frequencyDisplayUnit.label,
  135. reactanceFrequencyValue: frequencyText,
  136. reactanceInductanceUnitIndex: mode.key === 'inductive' ? reactiveDisplayUnitIndex : inductanceUnitIndex,
  137. reactanceModeIndex: modeIndex,
  138. reactanceModeKey: mode.key,
  139. reactanceModeOptions: MODE_OPTIONS,
  140. reactanceModeText: mode.label,
  141. reactanceReactiveDisplayValue: reactiveDisplayValue,
  142. reactanceReactiveName: mode.key === 'inductive' ? '电感' : '电容',
  143. reactanceReactiveSymbol: mode.key === 'inductive' ? 'L' : 'C',
  144. reactanceReactiveUnitIndex: reactiveDisplayUnitIndex,
  145. reactanceReactiveUnitOptions: reactiveUnitOptions,
  146. reactanceReactiveUnitText: reactiveDisplayUnit.label,
  147. reactanceReactiveValue: reactiveText,
  148. reactanceResultRows: resultRows
  149. }
  150. }
  151. function createInitialState() {
  152. return buildState({
  153. reactanceCapacitanceUnitIndex: 1,
  154. reactanceFrequencyUnitIndex: 0,
  155. reactanceInductanceUnitIndex: 3,
  156. reactanceModeIndex: 0,
  157. reactanceReactiveValue: ''
  158. })
  159. }
  160. function updateState(state, changedData = {}) {
  161. return buildState({
  162. ...state,
  163. ...changedData
  164. })
  165. }
  166. function clearInputs(state = {}) {
  167. return updateState(state, {
  168. reactanceFrequencyValue: '',
  169. reactanceReactiveValue: ''
  170. })
  171. }
  172. function normalizeValue(state, fieldKey, fieldValue) {
  173. const source = buildState(state)
  174. const config = {
  175. frequency: {
  176. options: FREQUENCY_UNIT_OPTIONS,
  177. unitIndex: source.reactanceFrequencyUnitIndex,
  178. unitIndexKey: 'reactanceFrequencyUnitIndex',
  179. valueKey: 'reactanceFrequencyValue'
  180. },
  181. reactive: {
  182. options: source.reactanceReactiveUnitOptions,
  183. unitIndex: source.reactanceReactiveUnitIndex,
  184. unitIndexKey: source.reactanceModeKey === 'inductive'
  185. ? 'reactanceInductanceUnitIndex'
  186. : 'reactanceCapacitanceUnitIndex',
  187. valueKey: 'reactanceReactiveValue'
  188. }
  189. }[fieldKey]
  190. if (!config) return source
  191. const text = fieldValue === undefined ? source[config.valueKey] : fieldValue
  192. const numberValue = parsePositiveNumber(text)
  193. if (!Number.isFinite(numberValue)) {
  194. return updateState(source, {
  195. [config.valueKey]: text
  196. })
  197. }
  198. const currentUnit = getOption(config.options, config.unitIndex)
  199. const baseValue = numberValue * currentUnit.factor
  200. const selected = selectBestUnit(config.options, baseValue, config.unitIndex)
  201. return updateState(source, {
  202. [config.unitIndexKey]: selected.index,
  203. [config.valueKey]: formatScaledValue(baseValue, selected.unit, { fallbackText: '' })
  204. })
  205. }
  206. module.exports = {
  207. ADMITTANCE_UNIT_OPTIONS,
  208. CAPACITANCE_UNIT_OPTIONS,
  209. FREQUENCY_UNIT_OPTIONS,
  210. INDUCTANCE_UNIT_OPTIONS,
  211. MODE_OPTIONS,
  212. REACTANCE_UNIT_OPTIONS,
  213. clearInputs,
  214. createInitialState,
  215. normalizeValue,
  216. updateState
  217. }