Files
ohif-viewer/platform/viewer/src/components/Labelling/LabellingFlow.js
T

264 lines
6.9 KiB
JavaScript
Raw Normal View History

2019-08-13 15:36:46 -04:00
import { Icon, SelectTree } from '@ohif/ui';
import React, { useState, useEffect, useRef } from 'react';
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
const LabellingFlow = ({
measurementData,
editLocation,
editDescription,
skipAddLabelButton,
updateLabelling,
labellingDoneCallback,
editDescriptionOnDialog,
}) => {
const [fadeOutTimer, setFadeOutTimer] = useState();
const [showComponent, setShowComponent] = useState(true);
const descriptionInput = useRef();
const [state, setState] = useState({
measurementData,
editLocation,
editDescription,
skipAddLabelButton,
});
const initialItems = OHIFLabellingData;
const currentItems = cloneDeep(initialItems);
useEffect(() => {
const treatMeasurementData = measurementData => {
if (editDescription) {
measurementData.description = undefined;
}
if (editLocation) {
measurementData.location = undefined;
}
};
2019-05-02 17:12:06 -04:00
const newMeasurementData = cloneDeep(measurementData);
treatMeasurementData(newMeasurementData);
2019-12-10 17:41:43 -03:00
setState(state => ({
...state,
2019-12-10 18:18:37 -03:00
editLocation: !editDescription && !editLocation,
measurementData: newMeasurementData,
}));
}, [editDescription, editLocation, measurementData]);
2019-05-02 17:12:06 -04:00
useEffect(() => {
if (descriptionInput.current) {
descriptionInput.current.focus();
}
}, [state]);
const relabel = event =>
setState(state => ({ ...state, editLocation: true }));
const setDescriptionUpdateMode = () => {
descriptionInput.current.focus();
setState(state => ({ ...state, editDescription: true }));
2019-05-30 00:46:45 -04:00
};
2019-05-02 17:12:06 -04:00
const descriptionCancel = () => {
const { description = '' } = cloneDeep(state);
descriptionInput.current.value = description;
setState(state => ({ ...state, editDescription: false }));
};
2019-12-10 17:41:43 -03:00
2019-12-10 18:18:37 -03:00
const handleKeyPress = event => {
if (event.key === 'Enter') {
descriptionSave();
2019-12-10 17:41:43 -03:00
}
};
2019-12-10 17:41:43 -03:00
const descriptionSave = () => {
const description = descriptionInput.current.value;
updateLabelling({ description });
setState(state => ({
...state,
description,
editDescription: false,
}));
};
const selectTreeSelectCallback = (event, itemSelected) => {
const location = itemSelected.value;
const locationLabel = itemSelected.label;
updateLabelling({ location });
setState(state => ({
...state,
editLocation: false,
measurementData: {
...state.measurementData,
location,
locationLabel,
},
}));
2019-12-10 17:41:43 -03:00
};
const showLabelling = () => {
setState(state => ({
...state,
skipAddLabelButton: true,
editLocation: false,
}));
2019-12-10 17:41:43 -03:00
};
/*
* Waits for 1 sec to dismiss the labelling component.
*
*/
2019-12-10 18:18:37 -03:00
const fadeOutAndLeave = () =>
setFadeOutTimer(setTimeout(fadeOutAndLeaveFast, 1000));
const fadeOutAndLeaveFast = () => setShowComponent(false);
const clearFadeOutTimer = () => {
2019-12-10 18:18:37 -03:00
if (fadeOutTimer) {
clearTimeout(fadeOutTimer);
setFadeOutTimer(null);
2019-12-10 17:41:43 -03:00
}
};
const descriptionDialogUpdate = description => {
updateLabelling({ description });
labellingDoneCallback();
};
2019-05-02 17:12:06 -04:00
const labellingStateFragment = () => {
const { skipAddLabelButton, editLocation, measurementData } = state;
const { description, locationLabel, location } = measurementData;
2019-05-02 17:12:06 -04:00
if (!skipAddLabelButton) {
return (
2019-12-10 18:18:37 -03:00
<button
type="button"
className="addLabelButton"
onClick={showLabelling}
>
{location ? 'Edit' : 'Add'} Label
</button>
2019-05-30 00:46:45 -04:00
);
2019-05-02 17:12:06 -04:00
} else {
if (editLocation) {
return (
<SelectTree
items={currentItems}
2019-05-02 17:12:06 -04:00
columns={1}
onSelected={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={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={descriptionInput}
2019-05-02 17:12:06 -04:00
defaultValue={description || ''}
autoComplete="off"
onKeyPress={handleKeyPress}
2019-05-02 17:12:06 -04:00
/>
</div>
</div>
<div className="commonButtons">
<button
type="button"
className="commonButton left"
onClick={relabel}
2019-05-02 17:12:06 -04:00
>
Relabel
</button>
<button
type="button"
className="commonButton right"
onClick={setDescriptionUpdateMode}
2019-05-02 17:12:06 -04:00
>
{description ? 'Edit ' : 'Add '}
Description
</button>
</div>
<div className="editDescriptionButtons">
<button
type="button"
className="commonButton left"
onClick={descriptionCancel}
2019-05-02 17:12:06 -04:00
>
Cancel
</button>
<button
type="button"
className="commonButton right"
onClick={descriptionSave}
2019-05-02 17:12:06 -04:00
>
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
if (editDescriptionOnDialog) {
return (
<EditDescriptionDialog
onCancel={labellingDoneCallback}
onUpdate={descriptionDialogUpdate}
measurementData={state.measurementData}
/>
);
}
2019-05-02 17:12:06 -04:00
return (
<LabellingTransition
displayComponent={showComponent}
onTransitionExit={labellingDoneCallback}
>
<>
<div
className={`labellingComponent ${state.editDescription &&
'editDescription'}`}
onMouseLeave={fadeOutAndLeave}
onMouseEnter={clearFadeOutTimer}
>
{labellingStateFragment()}
</div>
</>
</LabellingTransition>
);
};
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;