Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use color picker library to fix problems with Firefox #6488

Merged
merged 9 commits into from
Sep 22, 2022
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Fixed a crash which could happen when using the "Automatically clip histogram" feature in certain scenarios. [#6433](https://github.com/scalableminds/webknossos/pull/6433)
- Fixed loading agglomeate skeletons for agglomerate ids larger than 2^31. [#6472](https://github.com/scalableminds/webknossos/pull/6472)
- Fixed bug which could lead to conflict-warnings even though there weren't any. [#6477](https://github.com/scalableminds/webknossos/pull/6477)
- Fixed that one could not change the color of a segment or tree in Firefox. [#6488](https://github.com/scalableminds/webknossos/pull/6488)

### Removed

Expand Down
81 changes: 81 additions & 0 deletions frontend/javascripts/components/color_picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useState } from "react";
import { Popover } from "antd";
import * as Utils from "libs/utils";
import { HexColorInput, HexColorPicker } from "react-colorful";
import useThrottledCallback from "beautiful-react-hooks/useThrottledCallback";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool library 🤩

import type { Vector3 } from "oxalis/constants";

export const ThrottledColorPicker = ({
color,
onChange,
}: {
color: string;
onChange: (color: string) => void;
}) => {
const [value, localSetValue] = useState(color);
const throttledSetValue = useThrottledCallback(onChange, [onChange], 20);
const setValue = (newValue: string) => {
localSetValue(newValue);
throttledSetValue(newValue);
};
return (
<>
<HexColorPicker color={value} onChange={setValue} />
<HexColorInput
color={color}
onChange={setValue}
style={{
background: "var(--ant-component-background)",
textAlign: "center",
width: "100%",
marginTop: "12px",
color: "var(--ant-text)",
borderRadius: "4px",
border: "1px solid var(--ant-border-base)",
}}
/>
</>
);
};

export function ChangeColorMenuItemContent({
title,
isDisabled,
onSetColor,
rgb,
hidePickerIcon,
}: {
title: string;
isDisabled: boolean;
onSetColor: (rgb: Vector3) => void;
rgb: Vector3;
hidePickerIcon?: boolean;
}) {
const color = Utils.rgbToHex(Utils.map3((value) => value * 255, rgb));
const onChangeColor = (colorStr: string) => {
if (isDisabled) {
return;
}
const colorRgb = Utils.hexToRgb(colorStr);
const newColor = Utils.map3((component) => component / 255, colorRgb);
onSetColor(newColor);
};
const content = isDisabled ? null : (
<ThrottledColorPicker color={color} onChange={onChangeColor} />
);
return (
<Popover content={content} trigger="click" overlayStyle={{ zIndex: 10000 }}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆 that's capturing how I felt while adding that really well

<div style={{ position: "relative", display: "inline-block", width: "100%" }}>
{hidePickerIcon ? null : (
<i
className="fas fa-eye-dropper fa-sm"
style={{
cursor: "pointer",
}}
/>
)}{" "}
{title}
</div>
</Popover>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { getSegmentColorAsHSL } from "oxalis/model/accessors/volumetracing_acces
import Toast from "libs/toast";
import { hslaToCSS } from "oxalis/shaders/utils.glsl";
import { V4 } from "libs/mjs";
import { ChangeColorMenuItemContent } from "components/color_picker";

function ColoredDotIconForSegment({ segmentColorHSLA }: { segmentColorHSLA: Vector4 }) {
const hslaCss = hslaToCSS(segmentColorHSLA);
Expand Down Expand Up @@ -380,37 +381,24 @@ function _SegmentListItem({
* to change the color of B to see the effect for A.
*/}
<Menu.Item key="changeSegmentColor" disabled={isEditingDisabled || segment.id !== mappedId}>
<div style={{ position: "relative", display: "inline-block", width: "100%" }}>
Change Segment Color
<input
type="color"
value={Utils.rgbToHex(Utils.take3(segmentColorRGBA))}
disabled={isEditingDisabled}
style={{
position: "absolute",
left: 0,
top: 0,
width: "100%",
opacity: 0,
cursor: isEditingDisabled ? "unset" : "pointer",
}}
onChange={(event) => {
if (isEditingDisabled || visibleSegmentationLayer == null) {
return;
}

let color = Utils.hexToRgb(event.target.value);
color = Utils.map3((component) => component / 255, color);
updateSegment(
segment.id,
{
color: [color[0], color[1], color[2]],
},
visibleSegmentationLayer.name,
);
}}
/>
</div>
<ChangeColorMenuItemContent
isDisabled={isEditingDisabled}
title="Change Segment Color"
onSetColor={(color) => {
if (visibleSegmentationLayer == null) {
return;
}
updateSegment(
segment.id,
{
color,
},
visibleSegmentationLayer.name,
);
}}
rgb={Utils.take3(segmentColorRGBA)}
hidePickerIcon
/>
</Menu.Item>

<Menu.Item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Checkbox, Dropdown, Menu, Modal, notification } from "antd";
import { DeleteOutlined, PlusOutlined, ShrinkOutlined } from "@ant-design/icons";
import { connect } from "react-redux";
import { batchActions } from "redux-batched-actions";
import * as React from "react";
import React from "react";
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'reac... Remove this comment to see the full error message
import { SortableTreeWithoutDndContext as SortableTree } from "react-sortable-tree";
import _ from "lodash";
import type { Dispatch } from "redux";
import type { Action } from "oxalis/model/actions/actions";
import type { Vector3 } from "oxalis/constants";
import * as Utils from "libs/utils";

import type { TreeNode } from "oxalis/view/right-border-tabs/tree_hierarchy_view_helpers";
import {
MISSING_GROUP_ID,
Expand Down Expand Up @@ -43,6 +43,7 @@ import {
import messages from "messages";
import { formatNumberToLength, formatLengthAsVx } from "libs/format_utils";
import api from "oxalis/api/internal_api";
import { ChangeColorMenuItemContent } from "components/color_picker";
const CHECKBOX_STYLE = {};
const CHECKBOX_PLACEHOLDER_STYLE = {
width: 16,
Expand Down Expand Up @@ -452,36 +453,14 @@ class TreeHierarchyView extends React.PureComponent<Props, State> {
const createMenu = () => (
<Menu>
<Menu.Item key="changeTreeColor" disabled={isEditingDisabled}>
<div style={{ position: "relative", display: "inline-block", width: "100%" }}>
<i
className="fas fa-eye-dropper fa-sm"
style={{
cursor: "pointer",
}}
/>{" "}
Change Tree Color
<input
type="color"
value={Utils.rgbToHex(Utils.map3((value) => value * 255, tree.color))}
disabled={isEditingDisabled}
style={{
position: "absolute",
left: 0,
top: 0,
width: "100%",
opacity: 0,
cursor: isEditingDisabled ? "unset" : "pointer",
}}
onChange={(event) => {
if (isEditingDisabled) {
return;
}
let color = Utils.hexToRgb(event.target.value);
color = Utils.map3((component) => component / 255, color);
this.props.onSetTreeColor(tree.treeId, color);
}}
/>
</div>
<ChangeColorMenuItemContent
title="Change Tree Color"
isDisabled={isEditingDisabled}
onSetColor={(color) => {
this.props.onSetTreeColor(tree.treeId, color);
}}
rgb={tree.color}
/>
</Menu.Item>
<Menu.Item
key="shuffleTreeColor"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
"antd": "^4.20.6",
"backbone-events-standalone": "^0.2.7",
"base64-js": "^1.2.1",
"beautiful-react-hooks": "^0.30.5",
"beautiful-react-hooks": "^3.11.1",
"chalk": "^5.0.1",
"classnames": "^2.2.5",
"color-hash": "^2.0.1",
Expand Down Expand Up @@ -200,6 +200,7 @@
"process": "^0.11.10",
"protobufjs": "^6.8.6",
"react": "^16.12.0",
"react-colorful": "^5.6.1",
"react-ansi": "^3.0.2",
"react-debounce-render": "^8.0.1",
"react-dnd": "^11.1.3",
Expand Down
15 changes: 10 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3538,10 +3538,10 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"

beautiful-react-hooks@^0.30.5:
version "0.30.6"
resolved "https://registry.yarnpkg.com/beautiful-react-hooks/-/beautiful-react-hooks-0.30.6.tgz#05b059d5b05ee4252cb97c42ad9231d9ea7733bc"
integrity sha512-Da1tFxYHPLl0gyBGgdNG2d4fb3iIz3XKttObvoYwZgxiLyc81DYGfwMt6yW+7xuafKRN8PyX8NUmq1ucl0zKOg==
beautiful-react-hooks@^3.11.1:
version "3.11.1"
resolved "https://registry.yarnpkg.com/beautiful-react-hooks/-/beautiful-react-hooks-3.11.1.tgz#2bcbf726a77993b3f454ff48867a4cced3d213fd"
integrity sha512-uXeli3YYvo15+5xFvRm/rpBtVQ1SrelVTDKPZAlBWhaY8FXQegjKpWC1TjUL5noBMtWjDtx/rPaoCNlRtqJO0g==
dependencies:
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
Expand Down Expand Up @@ -9087,7 +9087,7 @@ lodash.curry@^4.1.1:
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==

lodash.escape@^4.0.1:
version "4.0.1"
Expand Down Expand Up @@ -11977,6 +11977,11 @@ react-base16-styling@^0.9.1:
csstype "^3.0.10"
lodash.curry "^4.1.1"

react-colorful@^5.6.1:
version "5.6.1"
resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b"
integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==

react-debounce-render@^8.0.1:
version "8.0.2"
resolved "https://registry.yarnpkg.com/react-debounce-render/-/react-debounce-render-8.0.2.tgz#ce37864e9bd8d086dbd3e3e784d3270bac2cf2d3"
Expand Down