color picker hue inversion indicator
This commit is contained in:
parent
c0a7d70c68
commit
95bd40da26
|
@ -9,6 +9,7 @@ import { envSave } from "../weed_detector/remote_env/actions";
|
|||
import { WDENVKey } from "../weed_detector/remote_env/interfaces";
|
||||
import { selectImage } from "../images/actions";
|
||||
import { calibrate, scanImage } from "./actions";
|
||||
import { envGet } from "../weed_detector/remote_env/selectors";
|
||||
|
||||
export class CameraCalibration extends
|
||||
React.Component<CameraCalibrationProps, CameraCalibrationState> {
|
||||
|
@ -51,7 +52,10 @@ export class CameraCalibration extends
|
|||
V_LO={this.props.V_LO}
|
||||
H_HI={this.props.H_HI}
|
||||
S_HI={this.props.S_HI}
|
||||
V_HI={this.props.V_HI} />
|
||||
V_HI={this.props.V_HI}
|
||||
invertHue={!!envGet(
|
||||
"CAMERA_CALIBRATION_invert_hue_selection",
|
||||
this.props.env)} />
|
||||
</Col>
|
||||
</Row>
|
||||
</WidgetBody>
|
||||
|
|
|
@ -27,7 +27,7 @@ export class FarmwarePage extends React.Component<FarmwareProps, {}> {
|
|||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={12} sm={5}>
|
||||
<Col xs={12} sm={6}>
|
||||
<CameraCalibration
|
||||
dispatch={this.props.dispatch}
|
||||
currentImage={this.props.currentImage}
|
||||
|
@ -43,7 +43,7 @@ export class FarmwarePage extends React.Component<FarmwareProps, {}> {
|
|||
S_HI={envGet("CAMERA_CALIBRATION_S_HI", this.props.env)}
|
||||
V_HI={envGet("CAMERA_CALIBRATION_V_HI", this.props.env)} />
|
||||
</Col>
|
||||
<Col xs={12} sm={5} smOffset={1}>
|
||||
<Col xs={12} sm={6}>
|
||||
<WeedDetector {...this.props} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import * as React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import { FarmbotColorPicker, getHueBoxes } from "../farmbot_picker";
|
||||
import { FarmbotPickerProps } from "../interfaces";
|
||||
|
||||
describe("<FarmbotColorPicker />", () => {
|
||||
it("renders", () => {
|
||||
const props: FarmbotPickerProps = {
|
||||
h: [30, 90],
|
||||
s: [100, 255],
|
||||
v: [100, 255],
|
||||
invertHue: false
|
||||
};
|
||||
const wrapper = shallow(<FarmbotColorPicker {...props} />);
|
||||
expect(wrapper.find("#farmbot-color-picker").length).toEqual(1);
|
||||
expect(wrapper.find("#hue").length).toEqual(1);
|
||||
expect(wrapper.find("#saturation").length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getHueBoxes()", () => {
|
||||
function verifyBox(
|
||||
box: React.CSSProperties,
|
||||
left: string,
|
||||
width: string,
|
||||
background: string | undefined) {
|
||||
expect(box.left).toEqual(left);
|
||||
expect(box.width).toEqual(width);
|
||||
expect(box.background).toEqual(background);
|
||||
}
|
||||
it("returns box css", () => {
|
||||
const boxes = getHueBoxes([30, 90], false);
|
||||
verifyBox(boxes[0], "0%", "17%", "rgba(0, 0, 0, 0.3)");
|
||||
verifyBox(boxes[1], "17%", "33%", undefined);
|
||||
verifyBox(boxes[2], "50%", "50%", "rgba(0, 0, 0, 0.3)");
|
||||
});
|
||||
|
||||
it("returns box css: inverted hue", () => {
|
||||
const boxes = getHueBoxes([30, 90], true);
|
||||
verifyBox(boxes[0], "0%", "17%", undefined);
|
||||
verifyBox(boxes[1], "17%", "33%", "rgba(0, 0, 0, 0.3)");
|
||||
verifyBox(boxes[2], "50%", "50%", undefined);
|
||||
});
|
||||
});
|
|
@ -6,13 +6,46 @@ import * as _ from "lodash";
|
|||
/** Wrapper class around `react-color`'s `<Saturation />` and `<Hue />`.
|
||||
* Add an extra white box feature for showing user weed detection settings.
|
||||
*/
|
||||
export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}> {
|
||||
BASE_CSS: React.CSSProperties = {
|
||||
position: "absolute",
|
||||
border: "2px solid white",
|
||||
boxShadow: "0 0 2px 2px rgba(0, 0, 0, 0.3) inset"
|
||||
};
|
||||
|
||||
const selectedCSS: React.CSSProperties = {
|
||||
position: "absolute",
|
||||
border: "2px solid white",
|
||||
boxShadow: "0 0 5px 2px rgba(0, 0, 0, 0.3)",
|
||||
zIndex: 2
|
||||
};
|
||||
|
||||
const unselectedCSS: React.CSSProperties = {
|
||||
position: "absolute",
|
||||
borderWidth: "5px 0 5px 0",
|
||||
borderColor: "#f4f4f4",
|
||||
borderStyle: "solid",
|
||||
background: "rgba(0, 0, 0, 0.3)",
|
||||
boxShadow: "0 0 15px 2px rgba(0, 0, 0, 0.3) inset"
|
||||
};
|
||||
|
||||
export function getHueBoxes(
|
||||
hue: number[], inverted: boolean): React.CSSProperties[] {
|
||||
/**
|
||||
* d0 d1 d2 d3 <- divider positions
|
||||
* .--------------------.
|
||||
* | box0 | box1 | box2 |
|
||||
* '--------------------'
|
||||
* w0 w1 w2 <- widths
|
||||
*/
|
||||
function n(h: number) { return ((h * 2) / 360) * 100; } // normalize
|
||||
const d = [0, n(Math.min(...hue)), n(Math.max(...hue)), 100];
|
||||
const boxWidths = [d[1], d[2] - d[1], d[3] - d[2]];
|
||||
const selected = [inverted, !inverted, inverted];
|
||||
return boxWidths.map(function (w, i) {
|
||||
const [top, height, left, width] =
|
||||
[0, 100, d[i], w].map(x => `${Math.round(x)}%`);
|
||||
return {
|
||||
top, height, left, width, ...(selected[i] ? selectedCSS : unselectedCSS)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {};
|
||||
|
@ -23,7 +56,6 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
|
|||
position: "relative",
|
||||
width: "100%",
|
||||
paddingBottom: "4rem",
|
||||
overflow: "hidden"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -36,16 +68,6 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
|
|||
};
|
||||
}
|
||||
|
||||
hueboxCSS = (): React.CSSProperties => {
|
||||
const l = ((this.props.h[0] * 2) / 360) * 100;
|
||||
const w = ((this.props.h[1] * 2) / 360) * 100 - l;
|
||||
const width = `${w}%`;
|
||||
const left = `${l}%`;
|
||||
const height = "100%";
|
||||
const top = 0;
|
||||
return { ...this.BASE_CSS, width, height, top, left };
|
||||
}
|
||||
|
||||
saturationboxCSS = (): React.CSSProperties => {
|
||||
const MAX = 255;
|
||||
const [s0, s1] = this.props.s;
|
||||
|
@ -58,7 +80,7 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
|
|||
|
||||
const [width, height, left, top] = [w, h, l, t].map(x => `${x}%`);
|
||||
|
||||
return { ...this.BASE_CSS, width, height, top, left };
|
||||
return { ...selectedCSS, width, height, top, left };
|
||||
}
|
||||
|
||||
customPointer = () => <div />;
|
||||
|
@ -75,17 +97,18 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
|
|||
hsv: { h: H_AVG, s: 0, v: 0 },
|
||||
hsl: { h: H_AVG, s: 0, l: 0 }
|
||||
};
|
||||
return <div>
|
||||
return <div id="farmbot-color-picker">
|
||||
<div style={{ width: "100%", paddingBottom: "5rem" }} />
|
||||
<div style={this.hueCSS()}>
|
||||
<div id="hue" style={this.hueCSS()}>
|
||||
<Hue
|
||||
{...dontTouchThis}
|
||||
pointer={this.customPointer}
|
||||
onChange={_.noop} />
|
||||
<div style={this.hueboxCSS()} />
|
||||
{getHueBoxes(this.props.h, !!this.props.invertHue)
|
||||
.map((box, i) => <div key={i} style={box} />)}
|
||||
</div>
|
||||
<div style={{ width: "100%", paddingBottom: "1rem" }} />
|
||||
<div style={this.saturationCSS()}>
|
||||
<div id="saturation" style={this.saturationCSS()}>
|
||||
<Saturation
|
||||
{...dontTouchThis}
|
||||
pointer={this.customPointer}
|
||||
|
|
|
@ -37,6 +37,7 @@ interface Props extends NumericValues {
|
|||
currentImage: TaggedImage | undefined;
|
||||
images: TaggedImage[];
|
||||
onChange(key: NumericKeyName, value: number): void;
|
||||
invertHue?: boolean;
|
||||
}
|
||||
|
||||
/** Mapping of HSV values to FBOS Env variables. */
|
||||
|
@ -104,7 +105,8 @@ export class ImageWorkspace extends React.Component<Props, {}> {
|
|||
<FarmbotColorPicker
|
||||
h={[H_LO, H_HI]}
|
||||
s={[S_LO, S_HI]}
|
||||
v={[V_LO, V_HI]} />
|
||||
v={[V_LO, V_HI]}
|
||||
invertHue={this.props.invertHue} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
|
|
|
@ -26,6 +26,7 @@ export interface FarmbotPickerProps {
|
|||
h: [number, number];
|
||||
s: [number, number];
|
||||
v: [number, number];
|
||||
invertHue?: boolean;
|
||||
}
|
||||
|
||||
export interface EnvSliderProps {
|
||||
|
|
Loading…
Reference in a new issue