Thresholds.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import React, { PureComponent } from 'react';
  2. import tinycolor from 'tinycolor2';
  3. import { ColorPicker } from 'app/core/components/colorpicker/ColorPicker';
  4. import { OptionModuleProps } from './module';
  5. import { BasicGaugeColor, Threshold } from 'app/types';
  6. interface State {
  7. thresholds: Threshold[];
  8. baseColor: string;
  9. }
  10. export default class Thresholds extends PureComponent<OptionModuleProps, State> {
  11. constructor(props) {
  12. super(props);
  13. this.state = {
  14. thresholds: props.options.thresholds,
  15. baseColor: props.options.baseColor,
  16. };
  17. }
  18. onAddThreshold = index => {
  19. const { maxValue, minValue } = this.props.options;
  20. const { thresholds } = this.state;
  21. const newThresholds = thresholds.map(threshold => {
  22. if (threshold.index >= index) {
  23. threshold = { ...threshold, index: threshold.index + 1 };
  24. }
  25. return threshold;
  26. });
  27. // Setting value to a value between the previous thresholds
  28. let value;
  29. if (index === 0 && thresholds.length === 0) {
  30. value = maxValue - (maxValue - minValue) / 2;
  31. } else if (index === 0 && thresholds.length > 0) {
  32. value = newThresholds[index + 1].value - (newThresholds[index + 1].value - minValue) / 2;
  33. } else if (index > newThresholds[newThresholds.length - 1].index) {
  34. value = maxValue - (maxValue - newThresholds[index - 1].value) / 2;
  35. }
  36. // Set a color that lies between the previous thresholds
  37. let color;
  38. if (index === 0 && thresholds.length === 0) {
  39. color = tinycolor.mix(BasicGaugeColor.Green, BasicGaugeColor.Red, 50).toRgbString();
  40. } else {
  41. color = tinycolor.mix(thresholds[index - 1].color, BasicGaugeColor.Red, 50).toRgbString();
  42. }
  43. this.setState(
  44. {
  45. thresholds: this.sortThresholds([...newThresholds, { index: index, value: value, color: color }]),
  46. },
  47. () => this.updateGauge()
  48. );
  49. };
  50. onRemoveThreshold = threshold => {
  51. this.setState(
  52. prevState => ({
  53. thresholds: prevState.thresholds.filter(t => t !== threshold),
  54. }),
  55. () => this.updateGauge()
  56. );
  57. };
  58. onChangeThresholdValue = (event, threshold) => {
  59. const { thresholds } = this.state;
  60. const newThresholds = thresholds.map(t => {
  61. if (t === threshold) {
  62. t = { ...t, value: event.target.value };
  63. }
  64. return t;
  65. });
  66. this.setState({
  67. thresholds: newThresholds,
  68. });
  69. };
  70. onChangeThresholdColor = (threshold, color) => {
  71. const { thresholds } = this.state;
  72. const newThresholds = thresholds.map(t => {
  73. if (t === threshold) {
  74. t = { ...t, color: color };
  75. }
  76. return t;
  77. });
  78. this.setState(
  79. {
  80. thresholds: newThresholds,
  81. },
  82. () => this.updateGauge()
  83. );
  84. };
  85. onChangeBaseColor = color => this.props.onChange({ ...this.props.options, baseColor: color });
  86. onBlur = () => {
  87. this.setState(prevState => ({
  88. thresholds: this.sortThresholds(prevState.thresholds),
  89. }));
  90. this.updateGauge();
  91. };
  92. updateGauge = () => {
  93. this.props.onChange({ ...this.props.options, thresholds: this.state.thresholds });
  94. };
  95. sortThresholds = thresholds => {
  96. return thresholds.sort((t1, t2) => {
  97. return t2.value - t1.value;
  98. });
  99. };
  100. renderThresholds() {
  101. const { thresholds } = this.state;
  102. return thresholds.map((threshold, index) => {
  103. return (
  104. <div className="threshold-row" key={`${threshold.index}-${index}`}>
  105. <div className="threshold-row-inner">
  106. <div className="threshold-row-color">
  107. {threshold.color && (
  108. <div className="threshold-row-color-inner">
  109. <ColorPicker
  110. color={threshold.color}
  111. onChange={color => this.onChangeThresholdColor(threshold, color)}
  112. />
  113. </div>
  114. )}
  115. </div>
  116. <input
  117. className="threshold-row-input"
  118. type="text"
  119. onChange={event => this.onChangeThresholdValue(event, threshold)}
  120. value={threshold.value}
  121. onBlur={this.onBlur}
  122. />
  123. <div onClick={() => this.onRemoveThreshold(threshold)} className="threshold-row-remove">
  124. <i className="fa fa-times" />
  125. </div>
  126. </div>
  127. </div>
  128. );
  129. });
  130. }
  131. renderIndicator() {
  132. const { thresholds } = this.state;
  133. return thresholds.map((t, i) => {
  134. return (
  135. <div key={`${t.value}-${i}`} className="indicator-section">
  136. <div
  137. onClick={() => this.onAddThreshold(t.index + 1)}
  138. style={{
  139. height: '50%',
  140. backgroundColor: t.color,
  141. }}
  142. />
  143. <div
  144. onClick={() => this.onAddThreshold(t.index)}
  145. style={{
  146. height: '50%',
  147. backgroundColor: t.color,
  148. }}
  149. />
  150. </div>
  151. );
  152. });
  153. }
  154. renderBaseIndicator() {
  155. return (
  156. <div className="indicator-section" style={{ height: '100%' }}>
  157. <div
  158. onClick={() => this.onAddThreshold(0)}
  159. style={{ height: '100%', backgroundColor: this.props.options.baseColor }}
  160. />
  161. </div>
  162. );
  163. }
  164. renderBase() {
  165. const { baseColor } = this.props.options;
  166. return (
  167. <div className="threshold-row threshold-row-base">
  168. <div className="threshold-row-inner threshold-row-inner--base">
  169. <div className="threshold-row-color">
  170. <div className="threshold-row-color-inner">
  171. <ColorPicker color={baseColor} onChange={color => this.onChangeBaseColor(color)} />
  172. </div>
  173. </div>
  174. <div className="threshold-row-label">Base</div>
  175. </div>
  176. </div>
  177. );
  178. }
  179. render() {
  180. return (
  181. <div className="section gf-form-group">
  182. <h5 className="section-heading">Thresholds</h5>
  183. <div className="thresholds">
  184. <div className="color-indicators">
  185. {this.renderIndicator()}
  186. {this.renderBaseIndicator()}
  187. </div>
  188. <div className="threshold-rows">
  189. {this.renderThresholds()}
  190. {this.renderBase()}
  191. </div>
  192. </div>
  193. </div>
  194. );
  195. }
  196. }