2019-08-13 15:36:46 -04:00
|
|
|
import { Icon, SelectTree } from '@ohif/ui';
|
2019-05-30 00:46:45 -04:00
|
|
|
import React, { Component } from 'react';
|
2019-12-09 14:47:23 -03:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import cloneDeep from 'lodash.clonedeep';
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-05-30 00:46:45 -04:00
|
|
|
import LabellingTransition from './LabellingTransition.js';
|
|
|
|
|
import OHIFLabellingData from './OHIFLabellingData.js';
|
2019-12-10 17:41:43 -03:00
|
|
|
import EditDescriptionDialog from './../EditDescriptionDialog/EditDescriptionDialog.js';
|
|
|
|
|
import './LabellingFlow.css';
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-10 17:29:40 -03:00
|
|
|
class LabellingFlow extends Component {
|
2019-05-02 17:12:06 -04:00
|
|
|
constructor(props) {
|
2019-05-30 00:46:45 -04:00
|
|
|
super(props);
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-10 17:41:43 -03:00
|
|
|
const newMeasurementData = cloneDeep(props.measurementData);
|
|
|
|
|
this.treatMeasurementData(newMeasurementData);
|
|
|
|
|
|
|
|
|
|
let newEditLocation = props.editLocation;
|
|
|
|
|
if (!props.editDescription && !props.editLocation) {
|
|
|
|
|
newEditLocation = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-02 17:12:06 -04:00
|
|
|
this.state = {
|
2019-12-10 17:41:43 -03:00
|
|
|
measurementData: newMeasurementData,
|
2019-05-02 17:12:06 -04:00
|
|
|
skipAddLabelButton: props.skipAddLabelButton,
|
|
|
|
|
editDescription: props.editDescription,
|
2019-12-10 17:41:43 -03:00
|
|
|
editLocation: newEditLocation,
|
2019-05-02 17:12:06 -04:00
|
|
|
confirmationState: false,
|
|
|
|
|
displayComponent: true,
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-05-30 00:46:45 -04:00
|
|
|
this.descriptionInput = React.createRef();
|
|
|
|
|
this.initialItems = OHIFLabellingData;
|
|
|
|
|
this.currentItems = cloneDeep(this.initialItems);
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidUpdate = () => {
|
2019-08-06 10:24:40 -03:00
|
|
|
if (this.state.editDescription) {
|
|
|
|
|
this.descriptionInput.current.focus();
|
|
|
|
|
}
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-10 17:41:43 -03:00
|
|
|
treatMeasurementData = measurementData => {
|
|
|
|
|
const { editDescription, editLocation } = this.props;
|
|
|
|
|
|
|
|
|
|
if (editDescription) {
|
|
|
|
|
measurementData.description = undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (editLocation) {
|
|
|
|
|
measurementData.location = undefined;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
descriptionDialogUpdate = description => {
|
|
|
|
|
this.props.updateLabelling({ description });
|
|
|
|
|
this.props.labellingDoneCallback();
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-02 17:12:06 -04:00
|
|
|
render() {
|
2019-12-10 17:41:43 -03:00
|
|
|
if (this.props.editDescriptionOnDialog) {
|
|
|
|
|
return (
|
|
|
|
|
<EditDescriptionDialog
|
|
|
|
|
onCancel={this.props.labellingDoneCallback}
|
|
|
|
|
onUpdate={this.descriptionDialogUpdate}
|
|
|
|
|
measurementData={this.state.measurementData}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-02 17:12:06 -04:00
|
|
|
return (
|
|
|
|
|
<LabellingTransition
|
|
|
|
|
displayComponent={this.state.displayComponent}
|
|
|
|
|
onTransitionExit={this.props.labellingDoneCallback}
|
|
|
|
|
>
|
2019-08-06 10:24:40 -03:00
|
|
|
<>
|
|
|
|
|
<div
|
2019-12-10 17:29:40 -03:00
|
|
|
className={`labellingComponent ${this.state.editDescription &&
|
|
|
|
|
'editDescription'}`}
|
2019-08-06 10:24:40 -03:00
|
|
|
onMouseLeave={this.fadeOutAndLeave}
|
|
|
|
|
onMouseEnter={this.clearFadeOutTimer}
|
|
|
|
|
>
|
|
|
|
|
{this.labellingStateFragment()}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
2019-05-02 17:12:06 -04:00
|
|
|
</LabellingTransition>
|
2019-05-30 00:46:45 -04:00
|
|
|
);
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
labellingStateFragment = () => {
|
2019-12-10 17:29:40 -03:00
|
|
|
const { skipAddLabelButton, editLocation, measurementData } = this.state;
|
|
|
|
|
const { description, locationLabel, location } = measurementData;
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
if (!skipAddLabelButton) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="addLabelButton"
|
|
|
|
|
onClick={this.showLabelling}
|
|
|
|
|
>
|
2019-12-10 17:29:40 -03:00
|
|
|
{location ? 'Edit' : 'Add'} Label
|
2019-05-02 17:12:06 -04:00
|
|
|
</button>
|
|
|
|
|
</>
|
2019-05-30 00:46:45 -04:00
|
|
|
);
|
2019-05-02 17:12:06 -04:00
|
|
|
} else {
|
|
|
|
|
if (editLocation) {
|
|
|
|
|
return (
|
|
|
|
|
<SelectTree
|
|
|
|
|
items={this.currentItems}
|
|
|
|
|
columns={1}
|
2019-12-09 14:47:23 -03:00
|
|
|
onSelected={this.selectTreeSelectCallback}
|
2019-05-02 17:12:06 -04:00
|
|
|
selectTreeFirstTitle="Assign Label"
|
|
|
|
|
/>
|
2019-05-30 00:46:45 -04:00
|
|
|
);
|
2019-05-02 17:12:06 -04:00
|
|
|
} else {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div
|
|
|
|
|
className="checkIconWrapper"
|
|
|
|
|
onClick={this.fadeOutAndLeaveFast}
|
|
|
|
|
>
|
2019-05-30 12:08:46 -04:00
|
|
|
<Icon name="check" className="checkIcon" />
|
2019-05-02 17:12:06 -04:00
|
|
|
</div>
|
|
|
|
|
<div className="locationDescriptionWrapper">
|
|
|
|
|
<div className="location">{locationLabel}</div>
|
|
|
|
|
<div className="description">
|
|
|
|
|
<input
|
|
|
|
|
id="descriptionInput"
|
|
|
|
|
ref={this.descriptionInput}
|
|
|
|
|
defaultValue={description || ''}
|
|
|
|
|
autoComplete="off"
|
2019-11-04 00:53:24 -03:00
|
|
|
onKeyPress={this.handleKeyPress}
|
2019-05-02 17:12:06 -04:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="commonButtons">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="commonButton left"
|
|
|
|
|
onClick={this.relabel}
|
|
|
|
|
>
|
|
|
|
|
Relabel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="commonButton right"
|
|
|
|
|
onClick={this.setDescriptionUpdateMode}
|
|
|
|
|
>
|
|
|
|
|
{description ? 'Edit ' : 'Add '}
|
|
|
|
|
Description
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="editDescriptionButtons">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="commonButton left"
|
|
|
|
|
onClick={this.descriptionCancel}
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="commonButton right"
|
|
|
|
|
onClick={this.descriptionSave}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
2019-05-30 00:46:45 -04:00
|
|
|
);
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-09 14:47:23 -03:00
|
|
|
relabel = event => this.setState({ editLocation: true });
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
setDescriptionUpdateMode = () => {
|
2019-05-30 00:46:45 -04:00
|
|
|
this.descriptionInput.current.focus();
|
2019-12-09 14:47:23 -03:00
|
|
|
this.setState({ editDescription: true });
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
descriptionCancel = () => {
|
2019-05-30 00:46:45 -04:00
|
|
|
const { description = '' } = cloneDeep(this.state);
|
|
|
|
|
this.descriptionInput.current.value = description;
|
2019-12-09 14:47:23 -03:00
|
|
|
this.setState({ editDescription: false });
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-11-04 00:53:24 -03:00
|
|
|
handleKeyPress = e => {
|
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
|
this.descriptionSave();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-02 17:12:06 -04:00
|
|
|
descriptionSave = () => {
|
2019-05-30 00:46:45 -04:00
|
|
|
const description = this.descriptionInput.current.value;
|
|
|
|
|
this.props.updateLabelling({ description });
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
|
description,
|
|
|
|
|
editDescription: false,
|
2019-05-30 00:46:45 -04:00
|
|
|
});
|
|
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-09 14:47:23 -03:00
|
|
|
selectTreeSelectCallback = (event, itemSelected) => {
|
2019-05-30 00:46:45 -04:00
|
|
|
const location = itemSelected.value;
|
2019-12-10 17:29:40 -03:00
|
|
|
const locationLabel = itemSelected.label;
|
2019-05-30 00:46:45 -04:00
|
|
|
this.props.updateLabelling({ location });
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
|
editLocation: false,
|
|
|
|
|
confirmationState: true,
|
2019-12-10 17:29:40 -03:00
|
|
|
measurementData: {
|
|
|
|
|
...this.state.measurementData,
|
|
|
|
|
location,
|
|
|
|
|
locationLabel,
|
|
|
|
|
},
|
2019-05-30 00:46:45 -04:00
|
|
|
});
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
if (this.isTouchScreen) {
|
2019-12-10 17:29:40 -03:00
|
|
|
this.setTimeout = setTimeout(
|
|
|
|
|
() => this.setState({ displayComponent: false }),
|
|
|
|
|
2000
|
|
|
|
|
);
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
showLabelling = () => {
|
|
|
|
|
this.setState({
|
|
|
|
|
skipAddLabelButton: true,
|
|
|
|
|
editLocation: false,
|
2019-05-30 00:46:45 -04:00
|
|
|
});
|
|
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
fadeOutAndLeave = () => {
|
|
|
|
|
// Wait for 1 sec to dismiss the labelling component
|
2019-12-09 14:47:23 -03:00
|
|
|
this.fadeOutTimer = setTimeout(
|
|
|
|
|
() => this.setState({ displayComponent: false }),
|
|
|
|
|
1000
|
|
|
|
|
);
|
2019-05-30 00:46:45 -04:00
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
|
2019-12-09 14:47:23 -03:00
|
|
|
fadeOutAndLeaveFast = () => this.setState({ displayComponent: false });
|
2019-05-02 17:12:06 -04:00
|
|
|
|
|
|
|
|
clearFadeOutTimer = () => {
|
|
|
|
|
if (!this.fadeOutTimer) {
|
2019-05-30 00:46:45 -04:00
|
|
|
return;
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
|
2019-05-30 00:46:45 -04:00
|
|
|
clearTimeout(this.fadeOutTimer);
|
|
|
|
|
};
|
2019-05-02 17:12:06 -04:00
|
|
|
}
|
2019-12-10 17:29:40 -03:00
|
|
|
|
|
|
|
|
LabellingFlow.propTypes = {
|
|
|
|
|
measurementData: PropTypes.object.isRequired,
|
|
|
|
|
labellingDoneCallback: PropTypes.func.isRequired,
|
|
|
|
|
updateLabelling: PropTypes.func.isRequired,
|
|
|
|
|
initialTopDistance: PropTypes.number,
|
|
|
|
|
skipAddLabelButton: PropTypes.bool,
|
|
|
|
|
editLocation: PropTypes.bool,
|
|
|
|
|
editDescription: PropTypes.bool,
|
|
|
|
|
editDescriptionOnDialog: PropTypes.bool,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LabellingFlow.defaultProps = {
|
|
|
|
|
skipAddLabelButton: false,
|
|
|
|
|
editLocation: false,
|
|
|
|
|
editDescription: false,
|
|
|
|
|
editDescriptionOnDialog: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default LabellingFlow;
|