color3LineComponent.tsx 6.1 KB

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