color3LineComponent.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "../propertyChangedEvent";
  4. import { NumericInputComponent } from "./numericInputComponent";
  5. import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
  6. import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
  7. import { Color3 } from 'babylonjs/Maths/math.color';
  8. import { ColorPickerLineComponent } from './colorPickerComponent';
  9. const copyIcon: string = require("./copy.svg");
  10. export interface IColor3LineComponentProps {
  11. label: string;
  12. target: any;
  13. propertyName: string;
  14. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  15. isLinear?: boolean;
  16. }
  17. export class Color3LineComponent extends React.Component<IColor3LineComponentProps, { isExpanded: boolean, color: Color3 }> {
  18. private _localChange = false;
  19. constructor(props: IColor3LineComponentProps) {
  20. super(props);
  21. this.state = { isExpanded: false, color: this.props.target[this.props.propertyName].clone() };
  22. if (props.isLinear) {
  23. this.state.color.toGammaSpaceToRef(this.state.color);
  24. }
  25. props.target._isLinearColor = props.isLinear; // so that replayRecorder can append toLinearSpace() as appropriate
  26. }
  27. shouldComponentUpdate(nextProps: IColor3LineComponentProps, nextState: { color: Color3 }) {
  28. const currentState = this.props.isLinear ? nextProps.target[nextProps.propertyName].toGammaSpace() : nextProps.target[nextProps.propertyName];
  29. if (!currentState.equals(nextState.color) || this._localChange) {
  30. nextState.color = currentState.clone();
  31. this._localChange = false;
  32. return true;
  33. }
  34. return false;
  35. }
  36. setPropertyValue(newColor: Color3) {
  37. this.props.target[this.props.propertyName] = newColor;
  38. if (this.props.isLinear) {
  39. this.props.target[this.props.propertyName] = newColor.toLinearSpace();
  40. }
  41. }
  42. onChange(newValue: string) {
  43. this._localChange = true;
  44. const newColor = Color3.FromHexString(newValue);
  45. if (this.props.onPropertyChangedObservable) {
  46. this.props.onPropertyChangedObservable.notifyObservers({
  47. object: this.props.target,
  48. property: this.props.propertyName,
  49. value: newColor,
  50. initialValue: this.state.color,
  51. });
  52. }
  53. this.setPropertyValue(newColor);
  54. this.setState({ color: newColor });
  55. }
  56. switchExpandState() {
  57. this._localChange = true;
  58. this.setState({ isExpanded: !this.state.isExpanded });
  59. }
  60. raiseOnPropertyChanged(previousValue: Color3) {
  61. if (!this.props.onPropertyChangedObservable) {
  62. return;
  63. }
  64. this.props.onPropertyChangedObservable.notifyObservers({
  65. object: this.props.target,
  66. property: this.props.propertyName,
  67. value: this.state.color,
  68. initialValue: previousValue,
  69. });
  70. }
  71. updateStateR(value: number) {
  72. this._localChange = true;
  73. const store = this.state.color.clone();
  74. this.state.color.r = value;
  75. this.setPropertyValue(this.state.color);
  76. this.setState({ color: this.state.color });
  77. this.raiseOnPropertyChanged(store);
  78. }
  79. updateStateG(value: number) {
  80. this._localChange = true;
  81. const store = this.state.color.clone();
  82. this.state.color.g = value;
  83. this.setPropertyValue(this.state.color);
  84. this.setState({ color: this.state.color });
  85. this.raiseOnPropertyChanged(store);
  86. }
  87. updateStateB(value: number) {
  88. this._localChange = true;
  89. const store = this.state.color.clone();
  90. this.state.color.b = value;
  91. this.setPropertyValue(this.state.color);
  92. this.setState({ color: this.state.color });
  93. this.raiseOnPropertyChanged(store);
  94. }
  95. copyToClipboard() {
  96. var element = document.createElement('div');
  97. element.textContent = this.state.color.toHexString();
  98. document.body.appendChild(element);
  99. if (window.getSelection) {
  100. var range = document.createRange();
  101. range.selectNode(element);
  102. window.getSelection()!.removeAllRanges();
  103. window.getSelection()!.addRange(range);
  104. }
  105. document.execCommand('copy');
  106. element.remove();
  107. }
  108. render() {
  109. const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />;
  110. return (
  111. <div className="color3Line">
  112. <div className="firstLine" title={this.props.label}>
  113. <div className="label">
  114. {this.props.label}
  115. </div>
  116. <div className="color3">
  117. <ColorPickerLineComponent value={this.state.color} onColorChanged={color => {
  118. this.onChange(color);
  119. }} />
  120. </div>
  121. <div className="copy hoverIcon" onClick={() => this.copyToClipboard()} title="Copy to clipboard">
  122. <img src={copyIcon} alt=""/>
  123. </div>
  124. <div className="expand hoverIcon" onClick={() => this.switchExpandState()} title="Expand">
  125. {chevron}
  126. </div>
  127. </div>
  128. {
  129. this.state.isExpanded &&
  130. <div className="secondLine">
  131. <NumericInputComponent label="r" value={this.state.color.r} onChange={(value) => this.updateStateR(value)} />
  132. <NumericInputComponent label="g" value={this.state.color.g} onChange={(value) => this.updateStateG(value)} />
  133. <NumericInputComponent label="b" value={this.state.color.b} onChange={(value) => this.updateStateB(value)} />
  134. </div>
  135. }
  136. </div>
  137. );
  138. }
  139. }