123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- import * as React from "react";
- import { Color3, Color4 } from "babylonjs/Maths/math.color";
- import { ColorComponentEntry } from './colorComponentEntry';
- import { HexColor } from './hexColor';
- require("./colorPicker.scss");
- /**
- * Interface used to specify creation options for color picker
- */
- export interface IColorPickerProps {
- color: Color3 | Color4,
- debugMode?: boolean,
- onColorChanged?: (color: Color3 | Color4) => void
- }
- /**
- * Interface used to specify creation options for color picker
- */
- export interface IColorPickerState {
- color: Color3;
- alpha: number;
- }
- /**
- * Class used to create a color picker
- */
- export class ColorPicker extends React.Component<IColorPickerProps, IColorPickerState> {
- private _saturationRef: React.RefObject<HTMLDivElement>;
- private _hueRef: React.RefObject<HTMLDivElement>;
- private _isSaturationPointerDown: boolean;
- private _isHuePointerDown: boolean;
- constructor(props: IColorPickerProps) {
- super(props);
- if (this.props.color instanceof Color4) {
- this.state = {color: new Color3(this.props.color.r, this.props.color.g, this.props.color.b), alpha: this.props.color.a};
- } else {
- this.state = {color : this.props.color.clone(), alpha: 1};
- }
- this._saturationRef = React.createRef();
- this._hueRef = React.createRef();
- }
- onSaturationPointerDown(evt: React.PointerEvent<HTMLDivElement>) {
- this._evaluateSaturation(evt);
- this._isSaturationPointerDown = true;
- evt.currentTarget.setPointerCapture(evt.pointerId);
- }
- onSaturationPointerUp(evt: React.PointerEvent<HTMLDivElement>) {
- this._isSaturationPointerDown = false;
- evt.currentTarget.releasePointerCapture(evt.pointerId);
- }
- onSaturationPointerMove(evt: React.PointerEvent<HTMLDivElement>) {
- if (!this._isSaturationPointerDown) {
- return;
- }
- this._evaluateSaturation(evt);
- }
- onHuePointerDown(evt: React.PointerEvent<HTMLDivElement>) {
- this._evaluateHue(evt);
- this._isHuePointerDown = true;
- evt.currentTarget.setPointerCapture(evt.pointerId);
- }
-
- onHuePointerUp(evt: React.PointerEvent<HTMLDivElement>) {
- this._isHuePointerDown = false;
- evt.currentTarget.releasePointerCapture(evt.pointerId);
- }
- onHuePointerMove(evt: React.PointerEvent<HTMLDivElement>) {
- if (!this._isHuePointerDown) {
- return;
- }
- this._evaluateHue(evt);
- }
- private _evaluateSaturation(evt: React.PointerEvent<HTMLDivElement>) {
- let left = evt.nativeEvent.offsetX;
- let top = evt.nativeEvent.offsetY;
-
- const saturation = Math.min(1, Math.max(0.0001, left / this._saturationRef.current!.clientWidth));
- const value = Math.min(1, Math.max(0.0001, 1 - (top / this._saturationRef.current!.clientHeight)));
- if (this.props.debugMode) {
- console.log("Saturation: " + saturation);
- console.log("Value: " + value);
- }
- let hsv = this.state.color.toHSV();
- Color3.HSVtoRGBToRef(hsv.r, saturation, value, this.state.color);
- this.setState({color: this.state.color});
- }
- private _evaluateHue(evt: React.PointerEvent<HTMLDivElement>) {
- let left = evt.nativeEvent.offsetX;
-
- const hue = 360 * Math.min(0.9999, Math.max(0.0001, left / this._hueRef.current!.clientWidth));
- if (this.props.debugMode) {
- console.log("Hue: " + hue);
- }
- let hsv = this.state.color.toHSV();
- Color3.HSVtoRGBToRef(hue, Math.max(hsv.g, 0.0001), Math.max(hsv.b, 0.0001), this.state.color);
- this.setState({color: this.state.color});
- }
- componentDidUpdate() {
- this.raiseOnColorChanged();
- }
- raiseOnColorChanged() {
- if (!this.props.onColorChanged) {
- return;
- }
- if (this.props.color instanceof Color4) {
- let newColor4 = Color4.FromColor3(this.state.color, this.state.alpha);
- this.props.onColorChanged(newColor4);
- return;
- }
- this.props.onColorChanged(this.state.color.clone());
- }
- public render() {
- let colorHex = this.state.color.toHexString();
- let hsv = this.state.color.toHSV();
- let colorRef = new Color3();
- Color3.HSVtoRGBToRef(hsv.r, 1, 1, colorRef)
- let colorHexRef = colorRef.toHexString();
- let hasAlpha = this.props.color instanceof Color4;
- return (
- <div className="color-picker-container">
- <div className="color-picker-saturation"
- onPointerMove={e => this.onSaturationPointerMove(e)}
- onPointerDown={e => this.onSaturationPointerDown(e)}
- onPointerUp={e => this.onSaturationPointerUp(e)}
- ref={this._saturationRef}
- style={{
- background: colorHexRef
- }}>
- <div className="color-picker-saturation-white">
- </div>
- <div className="color-picker-saturation-black">
- </div>
- <div className="color-picker-saturation-cursor" style={{
- top: `${ -(hsv.b * 100) + 100 }%`,
- left: `${ hsv.g * 100 }%`,
- }}>
- </div>
- </div>
- <div className="color-picker-hue">
- <div className="color-picker-hue-color" style={{
- background: colorHex
- }}>
- </div>
- <div className="color-picker-hue-slider"
- ref={this._hueRef}
- onPointerMove={e => this.onHuePointerMove(e)}
- onPointerDown={e => this.onHuePointerDown(e)}
- onPointerUp={e => this.onHuePointerUp(e)}
- >
- <div className="color-picker-hue-cursor" style={{
- left: `${ (hsv.r / 360.0) * 100 }%`,
- border: `1px solid ` + colorHexRef
- }}>
- </div>
- </div>
- </div>
- <div className="color-picker-rgb">
- <div className="red">
- <ColorComponentEntry label="R" min={0} max={255} value={Math.round(this.state.color.r * 255)} onChange={value => {
- this.state.color.r = value / 255.0;
- this.forceUpdate();
- }}/>
- </div>
- <div className="green">
- <ColorComponentEntry label="G" min={0} max={255} value={Math.round(this.state.color.g * 255)} onChange={value => {
- this.state.color.g = value / 255.0;
- this.forceUpdate();
- }}/>
- </div>
- <div className="blue">
- <ColorComponentEntry label="B" min={0} max={255} value={Math.round(this.state.color.b * 255)} onChange={value => {
- this.state.color.b = value / 255.0;
- this.forceUpdate();
- }}/>
- </div>
- <div className={"alpha" + (hasAlpha ? "" : " grayed")}>
- <ColorComponentEntry label="A" min={0} max={255} value={Math.round(this.state.alpha * 255)} onChange={value => {
- this.setState({alpha: value / 255.0});
- this.forceUpdate();
- }}/>
- </div>
- </div>
- <div className="color-picker-hex">
- <div className="color-picker-hex-label">
- Hex
- </div>
- <div className="color-picker-hex-value">
- <HexColor expectedLength={6} value={colorHex} onChange={value => {
- this.setState({color: Color3.FromHexString(value)});
- }}/>
- </div>
- </div>
- </div>
- );
- }
- }
|