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

Add toggle color layer visibility button #3943

Merged
merged 12 commits into from
Mar 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md).
- Segmentation ID mappings can now be used in volume and hybrid tracings. [#3949](https://github.com/scalableminds/webknossos/pull/3949)
- A maximize-button was added to the viewports in the annotation view. Maximization can also be toggled with the `.` shortcut. [#3876](https://github.com/scalableminds/webknossos/pull/3876)
- [webknossos-connect](https://github.com/scalableminds/webknossos-connect) now starts with webKnossos on local and development instances by default. [#3913](https://github.com/scalableminds/webknossos/pull/3913)
- Added a button for each color layer to enable/disable the layer. [#3943](https://github.com/scalableminds/webknossos/pull/3943)
- Paginated routes now send a `X-Total-Count` HTTP header which shows how many entries were found in total. [#3899](https://github.com/scalableminds/webknossos/pull/3899)

### Changed
Expand Down
2 changes: 2 additions & 0 deletions docs/tracing_ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ For multi-layer datasets, each layer can be adjusted separately.
#### Colors
- `Brightness`: Increase / Decrease the brightness of the data layer.
- `Contrast`: Increase / Decrease the contrast of the data layer.
- `Opacity`: Increase / Decrease the opacity of the data layer.
- `Color`: Every data layer can be colored to make them easily identifiable. By default, all layers have a white overlay, showing the true, raw black & white data.
- `Visibility`: Use the eye icon on the right side of the name of the data layer to enable/disable this layer.

#### Segmentation
- `Segmentation Opacity`: Increases / Decreases the opacity of the segmentation layer. A low value will make the segmentation almost transparent letting you see the underlying data layers more clearly. A high value will make the segmentation opaque which is useful for adjusting and reviewing the exact fit of the segmentation layer. Only possible if your dataset has a segmentation layer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class DatasetImportView extends React.PureComponent<Props, State> {
brightness: 0,
contrast: 1,
color: [255, 255, 255],
isDisabled: false,
};
const datasetDefaultConfiguration = (await getDatasetDefaultConfiguration(
this.props.datasetId,
Expand Down
9 changes: 6 additions & 3 deletions frontend/javascripts/libs/datasource.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@
"properties": {
"name": { "type": "string" },
"category": { "enum": ["color", "segmentation"] },
"elementClass": { "enum": ["uint8", "uint16", "uint24", "uint32", "uint64", "float,", "double", "int8", "int16", "int32", "int64"] }
"elementClass": {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

my ide beautifies code again 🤔
As this is accepted by prettier I suggest to keep it this way.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, in the long run, this can be quite cumbersome. This is especially prone to merge conflicts. Can you please disable any IDE auto-formatting which differs from prettiers behavior?

"enum": ["uint8", "uint16", "uint24", "uint32", "uint64", "float,", "double", "int8", "int16", "int32", "int64"]
}
},
"required": ["name", "category", "elementClass"]
},
Expand Down Expand Up @@ -128,9 +130,10 @@
"properties": {
"brightness": { "type": "number" },
"contrast": { "type": "number" },
"color": { "$ref": "#/definitions/types::Vector3" }
"color": { "$ref": "#/definitions/types::Vector3" },
"isDisabled": { "type": "boolean" }
},
"required": ["brightness", "contrast", "color"]
"required": ["brightness", "contrast", "color", "isDisabled"]
}
}
}
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/libs/datasource.types.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,6 @@ export type LayerUserConfiguration = {
brightness: number,
contrast: number,
color: Vector3,
isDisabled: boolean,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ class PlaneMaterialFactory {
updateUniformsForLayer(settings: DatasetLayerConfiguration, name: string): void {
this.uniforms[`${name}_brightness`].value = settings.brightness / 255;
this.uniforms[`${name}_contrast`].value = settings.contrast;
this.uniforms[`${name}_alpha`].value = settings.alpha / 100;
this.uniforms[`${name}_alpha`].value = settings.isDisabled ? 0 : settings.alpha / 100;

if (settings.color != null) {
const color = this.convertColor(settings.color);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ function SettingsReducer(state: OxalisState, action: Action): OxalisState {
contrast: 1,
color: [255, 255, 255],
alpha: 100,
isDisabled: false,
},
initialLayerSettings[layer.name],
);
Expand All @@ -122,7 +123,7 @@ function SettingsReducer(state: OxalisState, action: Action): OxalisState {
};
}
case "SET_VIEW_MODE": {
const allowedModes = state.tracing.restrictions.allowedModes;
const { allowedModes } = state.tracing.restrictions;
if (allowedModes.includes(action.viewMode)) {
return updateTemporaryConfig(state, { viewMode: action.viewMode });
} else {
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export type DatasetLayerConfiguration = {|
+brightness: number,
+contrast: number,
+alpha: number,
+isDisabled: boolean,
|};

export type LoadingStrategy = "BEST_QUALITY_FIRST" | "PROGRESSIVE_QUALITY";
Expand Down
50 changes: 42 additions & 8 deletions frontend/javascripts/oxalis/view/settings/dataset_settings_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @flow
*/

import { Col, Collapse, Divider, Icon, Row, Select, Tag, Tooltip } from "antd";
import { Col, Collapse, Divider, Icon, Row, Select, Switch, Tag, Tooltip } from "antd";
import type { Dispatch } from "redux";
import { connect } from "react-redux";
import * as React from "react";
Expand Down Expand Up @@ -39,8 +39,8 @@ import constants, {
} from "oxalis/constants";
import messages, { settings } from "messages";

const Panel = Collapse.Panel;
const Option = Select.Option;
const { Panel } = Collapse;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

also done by my ide

const { Option } = Select;

type DatasetSettingsProps = {|
datasetConfiguration: DatasetConfiguration,
Expand All @@ -65,20 +65,35 @@ class DatasetSettings extends React.PureComponent<DatasetSettingsProps> {
isLastLayer: boolean,
) => {
const isRGB = isRgb(this.props.dataset, layerName);
const { brightness, contrast, alpha, color } = layer;
const { brightness, contrast, alpha, color, isDisabled } = layer;
return (
<div key={layerName}>
<Row>
<Col span={24}>
{/* TODO Maybe use the new antd icons instead of the switch when upgrading antd. */}
<Tooltip title={isDisabled ? "Enable" : "Disable"} placement="top">
{/* This div is necessary for the tooltip to be displayed */}
<div style={{ display: "inline-block", marginRight: 8 }}>
<Switch
size="small"
onChange={val => this.props.onChangeLayer(layerName, "isDisabled", !val)}
checked={!isDisabled}
/>
</div>
</Tooltip>
<span style={{ fontWeight: 700 }}>{layerName}</span>
<Tag style={{ cursor: "default", marginLeft: 8 }} color={isRGB && "#1890ff"}>
{isRGB ? "24-bit" : "8-bit"} Layer
</Tag>
<Tooltip title="If you are having trouble finding your data, webKnossos can try to find a position which contains data.">
<Icon
type="scan"
onClick={() => this.handleFindData(layerName)}
style={{ float: "right", marginTop: 4, cursor: "pointer" }}
onClick={!isDisabled ? () => this.handleFindData(layerName) : () => {}}
style={{
float: "right",
marginTop: 4,
cursor: !isDisabled ? "pointer" : "not-allowed",
}}
/>
</Tooltip>
</Col>
Expand All @@ -90,6 +105,7 @@ class DatasetSettings extends React.PureComponent<DatasetSettingsProps> {
step={5}
value={brightness}
onChange={_.partial(this.props.onChangeLayer, layerName, "brightness")}
disabled={isDisabled}
/>
<NumberSliderSetting
label="Contrast"
Expand All @@ -98,19 +114,22 @@ class DatasetSettings extends React.PureComponent<DatasetSettingsProps> {
step={0.1}
value={contrast}
onChange={_.partial(this.props.onChangeLayer, layerName, "contrast")}
disabled={isDisabled}
/>
<NumberSliderSetting
label="Opacity"
min={0}
max={100}
value={alpha}
onChange={_.partial(this.props.onChangeLayer, layerName, "alpha")}
disabled={isDisabled}
/>
<ColorSetting
label="Color"
value={Utils.rgbToHex(color)}
onChange={_.partial(this.props.onChangeLayer, layerName, "color")}
className="ant-btn"
disabled={isDisabled}
/>
{!isLastLayer && <Divider />}
</div>
Expand Down Expand Up @@ -176,16 +195,31 @@ class DatasetSettings extends React.PureComponent<DatasetSettingsProps> {
);
}

renderPanelHeader = (hasInvisibleLayers: boolean) =>
hasInvisibleLayers ? (
<span>
Color Layers
<Tooltip title="Not all layers are currently visible.">
<Icon type="exclamation-circle-o" style={{ marginLeft: 16, color: "coral" }} />
</Tooltip>
</span>
) : (
"Color Layers"
);

render() {
const { layers } = this.props.datasetConfiguration;
const colorSettings = Object.entries(layers).map((entry, index) =>
// $FlowFixMe Object.entries returns mixed for Flow
this.getColorSettings(entry, index, index === _.size(layers) - 1),
);

const hasInvisibleLayers =
Object.keys(layers).find(
layerName => layers[layerName].isDisabled || layers[layerName].alpha === 0,
) != null;
return (
<Collapse bordered={false} defaultActiveKey={["1", "2", "3", "4"]}>
<Panel header="Color Layers" key="1">
<Panel header={this.renderPanelHeader(hasInvisibleLayers)} key="1">
{colorSettings}
</Panel>
{this.props.hasSegmentation ? this.getSegmentationPanel() : null}
Expand Down
34 changes: 28 additions & 6 deletions frontend/javascripts/oxalis/view/settings/setting_input_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ type NumberSliderSettingProps = {
max: number,
min: number,
step: number,
disabled: boolean,
};

export class NumberSliderSetting extends React.PureComponent<NumberSliderSettingProps> {
static defaultProps = {
min: 1,
step: 1,
disabled: false,
};

_onChange = (_value: number) => {
Expand All @@ -27,15 +29,22 @@ export class NumberSliderSetting extends React.PureComponent<NumberSliderSetting
};

render() {
const { value, label, max, min, step, onChange } = this.props;
const { value, label, max, min, step, onChange, disabled } = this.props;

return (
<Row type="flex" align="middle">
<Col span={9}>
<label className="setting-label">{label}</label>
</Col>
<Col span={8}>
<Slider min={min} max={max} onChange={onChange} value={value} step={step} />
<Slider
min={min}
max={max}
onChange={onChange}
value={value}
step={step}
disabled={disabled}
/>
</Col>
<Col span={5}>
<InputNumber
Expand All @@ -45,6 +54,7 @@ export class NumberSliderSetting extends React.PureComponent<NumberSliderSetting
value={value}
onChange={this._onChange}
size="small"
disabled={disabled}
/>
</Col>
</Row>
Expand Down Expand Up @@ -337,24 +347,30 @@ type ColorSettingPropTypes = {
value: string,
label: string,
onChange: (value: Vector3) => void,
disabled: boolean,
};

export class ColorSetting extends React.PureComponent<ColorSettingPropTypes> {
static defaultProps = {
disabled: false,
};

onColorChange = (evt: SyntheticInputEvent<>) => {
this.props.onChange(Utils.hexToRgb(evt.target.value));
};

render() {
const { label, value, disabled } = this.props;
return (
<Row className="margin-bottom" align="top">
<Col span={9}>
<label className="setting-label">{this.props.label}</label>
<label className="setting-label">{label}</label>
</Col>
<Col span={15}>
<div
id="color-picker-wrapper"
style={{
backgroundColor: this.props.value,
backgroundColor: value,
display: "block",
width: 16,
height: 16,
Expand All @@ -364,9 +380,15 @@ export class ColorSetting extends React.PureComponent<ColorSettingPropTypes> {
>
<input
type="color"
style={{ opacity: 0, display: "block", border: "none", cursor: "pointer" }}
style={{
opacity: 0,
display: "block",
border: "none",
cursor: disabled ? "not-allowed" : "pointer",
}}
onChange={this.onColorChange}
value={this.props.value}
value={value}
disabled={disabled}
/>
</div>
</Col>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ const datasetConfigOverrides: { [key: string]: DatasetConfiguration } = {
ROI2017_wkw_fallback: {
fourBit: false,
interpolation: true,
layers: { color: { color: [255, 255, 255], contrast: 1, brightness: 0, alpha: 100 } },
layers: {
color: { color: [255, 255, 255], contrast: 1, brightness: 0, alpha: 100, isDisabled: true },
},
quality: 0,
segmentationOpacity: 0,
highlightHoveredCellId: true,
Expand Down