ThresholdsEditor.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import React, { PureComponent } from 'react';
  2. // import tinycolor, { ColorInput } from 'tinycolor2';
  3. import { Threshold, BasicGaugeColor } from '../../types';
  4. import { ColorPicker } from '../ColorPicker/ColorPicker';
  5. import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup';
  6. import { colors } from '../../utils';
  7. export interface Props {
  8. thresholds: Threshold[];
  9. onChange: (thresholds: Threshold[]) => void;
  10. }
  11. interface State {
  12. thresholds: Threshold[];
  13. baseColor: string;
  14. }
  15. export class ThresholdsEditor extends PureComponent<Props, State> {
  16. constructor(props: Props) {
  17. super(props);
  18. const thresholds: Threshold[] =
  19. props.thresholds.length > 0 ? props.thresholds : [{ index: 0, value: -Infinity, color: '#299c46' }];
  20. this.state = { thresholds, baseColor: BasicGaugeColor.Green };
  21. }
  22. onAddThreshold = (index: number) => {
  23. const { thresholds } = this.state;
  24. const maxValue = 100;
  25. const minValue = 0;
  26. if (index === 0) {
  27. return;
  28. }
  29. const newThresholds = thresholds.map(threshold => {
  30. if (threshold.index >= index) {
  31. const index = threshold.index + 1;
  32. threshold = { ...threshold, index, color: colors[index] };
  33. }
  34. return threshold;
  35. });
  36. // Setting value to a value between the previous thresholds
  37. const beforeThreshold = newThresholds.filter(threshold => threshold.index === index - 1)[0];
  38. const afterThreshold = newThresholds.filter(threshold => threshold.index === index + 1)[0];
  39. const beforeThresholdValue = beforeThreshold !== undefined ? Math.max(beforeThreshold.value, minValue) : minValue;
  40. const afterThresholdValue = afterThreshold !== undefined ? Math.min(afterThreshold.value, maxValue) : maxValue;
  41. const value = afterThresholdValue - (afterThresholdValue - beforeThresholdValue) / 2;
  42. // Set a color
  43. const color = colors[index];
  44. this.setState(
  45. {
  46. thresholds: this.sortThresholds([
  47. ...newThresholds,
  48. {
  49. index,
  50. value: value as number,
  51. color,
  52. },
  53. ]),
  54. },
  55. () => this.updateGauge()
  56. );
  57. };
  58. onRemoveThreshold = (threshold: Threshold) => {
  59. this.setState(
  60. prevState => ({ thresholds: prevState.thresholds.filter(t => t !== threshold) }),
  61. () => this.updateGauge()
  62. );
  63. };
  64. onChangeThresholdValue = (event: any, threshold: Threshold) => {
  65. const { thresholds } = this.state;
  66. const newThresholds = thresholds.map(t => {
  67. if (t === threshold) {
  68. t = { ...t, value: event.target.value };
  69. }
  70. return t;
  71. });
  72. this.setState({ thresholds: newThresholds });
  73. };
  74. onChangeThresholdColor = (threshold: Threshold, color: string) => {
  75. const { thresholds } = this.state;
  76. const newThresholds = thresholds.map(t => {
  77. if (t === threshold) {
  78. t = { ...t, color: color };
  79. }
  80. return t;
  81. });
  82. this.setState(
  83. {
  84. thresholds: newThresholds,
  85. },
  86. () => this.updateGauge()
  87. );
  88. };
  89. onChangeBaseColor = (color: string) => this.props.onChange(this.state.thresholds);
  90. onBlur = () => {
  91. this.setState(prevState => ({ thresholds: this.sortThresholds(prevState.thresholds) }));
  92. this.updateGauge();
  93. };
  94. updateGauge = () => {
  95. this.props.onChange(this.state.thresholds);
  96. };
  97. sortThresholds = (thresholds: Threshold[]) => {
  98. return thresholds.sort((t1, t2) => {
  99. return t2.value - t1.value;
  100. });
  101. };
  102. renderInput = (threshold: Threshold) => {
  103. const value = threshold.index === 0 ? 'Base' : threshold.value;
  104. return (
  105. <div className="thresholds-row-input-inner">
  106. <div className="thresholds-row-input-inner-arrow" />
  107. <input
  108. className="thresholds-row-input-inner-value"
  109. type="text"
  110. onChange={event => this.onChangeThresholdValue(event, threshold)}
  111. value={value}
  112. onBlur={this.onBlur}
  113. readOnly={threshold.index === 0}
  114. />
  115. <div className="thresholds-row-input-inner-color">
  116. {threshold.color && (
  117. <div className="thresholds-row-input-inner-color-colorpicker">
  118. <ColorPicker color={threshold.color} onChange={color => this.onChangeThresholdColor(threshold, color)} />
  119. </div>
  120. )}
  121. </div>
  122. {threshold.index > 0 && (
  123. <div className="thresholds-row-input-inner-remove" onClick={() => this.onRemoveThreshold(threshold)}>
  124. <i className="fa fa-times" />
  125. </div>
  126. )}
  127. </div>
  128. );
  129. };
  130. render() {
  131. const { thresholds } = this.state;
  132. return (
  133. <PanelOptionsGroup title="Thresholds">
  134. <div className="thresholds">
  135. {thresholds.map((threshold, index) => {
  136. return (
  137. <div className="thresholds-row" key={`${threshold.index}-${index}`}>
  138. <div className="thresholds-row-add-button" onClick={() => this.onAddThreshold(threshold.index + 1)}>
  139. <i className="fa fa-plus" />
  140. </div>
  141. <div className="thresholds-row-color-indicator" style={{ backgroundColor: threshold.color }} />
  142. <div className="thresholds-row-input">{this.renderInput(threshold)}</div>
  143. </div>
  144. );
  145. })}
  146. </div>
  147. </PanelOptionsGroup>
  148. );
  149. }
  150. }