From 95bd40da260977e48ffb13d5be56c3dd41ee21a3 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Thu, 5 Oct 2017 01:11:37 -0700 Subject: [PATCH] color picker hue inversion indicator --- .../camera_calibration/camera_calibration.tsx | 6 +- webpack/farmware/index.tsx | 4 +- .../__tests__/farmbot_picker_test.tsx | 44 ++++++++++++ .../farmware/weed_detector/farmbot_picker.tsx | 67 +++++++++++++------ .../weed_detector/image_workspace.tsx | 4 +- webpack/farmware/weed_detector/interfaces.ts | 1 + 6 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 webpack/farmware/weed_detector/__tests__/farmbot_picker_test.tsx diff --git a/webpack/farmware/camera_calibration/camera_calibration.tsx b/webpack/farmware/camera_calibration/camera_calibration.tsx index b66f6048e..c4c86fc6e 100644 --- a/webpack/farmware/camera_calibration/camera_calibration.tsx +++ b/webpack/farmware/camera_calibration/camera_calibration.tsx @@ -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 { @@ -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)} /> diff --git a/webpack/farmware/index.tsx b/webpack/farmware/index.tsx index af1466b0d..06e85db91 100644 --- a/webpack/farmware/index.tsx +++ b/webpack/farmware/index.tsx @@ -27,7 +27,7 @@ export class FarmwarePage extends React.Component { - + { S_HI={envGet("CAMERA_CALIBRATION_S_HI", this.props.env)} V_HI={envGet("CAMERA_CALIBRATION_V_HI", this.props.env)} /> - + diff --git a/webpack/farmware/weed_detector/__tests__/farmbot_picker_test.tsx b/webpack/farmware/weed_detector/__tests__/farmbot_picker_test.tsx new file mode 100644 index 000000000..2b6bc48a6 --- /dev/null +++ b/webpack/farmware/weed_detector/__tests__/farmbot_picker_test.tsx @@ -0,0 +1,44 @@ +import * as React from "react"; +import { shallow } from "enzyme"; +import { FarmbotColorPicker, getHueBoxes } from "../farmbot_picker"; +import { FarmbotPickerProps } from "../interfaces"; + +describe("", () => { + it("renders", () => { + const props: FarmbotPickerProps = { + h: [30, 90], + s: [100, 255], + v: [100, 255], + invertHue: false + }; + const wrapper = shallow(); + 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); + }); +}); diff --git a/webpack/farmware/weed_detector/farmbot_picker.tsx b/webpack/farmware/weed_detector/farmbot_picker.tsx index fc5231d1a..cf7ba70f8 100644 --- a/webpack/farmware/weed_detector/farmbot_picker.tsx +++ b/webpack/farmware/weed_detector/farmbot_picker.tsx @@ -6,13 +6,46 @@ import * as _ from "lodash"; /** Wrapper class around `react-color`'s `` and ``. * Add an extra white box feature for showing user weed detection settings. */ -export class FarmbotColorPicker extends React.Component { - 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 { constructor() { super(); this.state = {}; @@ -23,7 +56,6 @@ export class FarmbotColorPicker extends React.Component position: "relative", width: "100%", paddingBottom: "4rem", - overflow: "hidden" }; } @@ -36,16 +68,6 @@ export class FarmbotColorPicker extends React.Component }; } - 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 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 = () =>
; @@ -75,17 +97,18 @@ export class FarmbotColorPicker extends React.Component hsv: { h: H_AVG, s: 0, v: 0 }, hsl: { h: H_AVG, s: 0, l: 0 } }; - return
+ return
-
+
-
+ {getHueBoxes(this.props.h, !!this.props.invertHue) + .map((box, i) =>
)}
-
+
{ + v={[V_LO, V_HI]} + invertHue={this.props.invertHue} /> diff --git a/webpack/farmware/weed_detector/interfaces.ts b/webpack/farmware/weed_detector/interfaces.ts index d689862f6..0e244a6a7 100644 --- a/webpack/farmware/weed_detector/interfaces.ts +++ b/webpack/farmware/weed_detector/interfaces.ts @@ -26,6 +26,7 @@ export interface FarmbotPickerProps { h: [number, number]; s: [number, number]; v: [number, number]; + invertHue?: boolean; } export interface EnvSliderProps {