color picker hue inversion indicator

This commit is contained in:
gabrielburnworth 2017-10-05 01:11:37 -07:00
parent c0a7d70c68
commit 95bd40da26
6 changed files with 100 additions and 26 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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);
});
});

View file

@ -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}

View file

@ -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>

View file

@ -26,6 +26,7 @@ export interface FarmbotPickerProps {
h: [number, number];
s: [number, number];
v: [number, number];
invertHue?: boolean;
}
export interface EnvSliderProps {