UNPKG

lost-sia

Version:

Single Image Annotation Tool

239 lines (202 loc) 4.92 kB
import React, { useState, useEffect, useRef } from "react"; import { Dropdown, Ref, Popup, Header } from "semantic-ui-react"; const LabelInput = ({ defaultLabel, disabled, focusOnRender, initLabelIds, multilabels, possibleLabelsProp, relatedId, renderPopup, visible, open, onClose, onLabelConfirmed, onLabelUpdate, }) => { const [label, setLabel] = useState([]); const [possibleLabels, setPossibleLabels] = useState([]); const [performInit, setPerformInit] = useState(true); const [confirmLabel, setConfirmLabel] = useState(0); const inputRef = useRef(null); useEffect(() => { updatePossibleLabels(); }, []); useEffect(() => { if (initLabelIds) { setPerformInit(true); } }, [initLabelIds]); useEffect(() => { if (visible) { if (focusOnRender) { if (inputRef.current) { inputRef.current.click(); } } } if (confirmLabel !== 0) { annoLabelUpdate(label); closeLabelInput(); } if (initLabelIds) { if (performInit) { setPerformInit(false); if (initLabelIds.length > 0) { setLabel(initLabelIds); } else { setLabel([]); } } } }, [ visible, focusOnRender, label, confirmLabel, possibleLabelsProp, initLabelIds, relatedId, ]); const onKeyDown = (e) => { e.stopPropagation(); performKeyAction(e.key); }; const onChange = (e, item) => { let lbl; if (multilabels) { lbl = item.value !== -1 ? item.value : []; } else { lbl = item.value !== -1 ? [item.value] : []; } setLabel(lbl); annoLabelUpdate(lbl); }; const onItemClick = (e, item) => { incrementConfirmLabel(); }; const updatePossibleLabels = () => { let _possibleLabels = []; let _defaultLabel; if (defaultLabel) { if (Number.isInteger(defaultLabel)) { _defaultLabel = undefined; } else { _defaultLabel = defaultLabel; } } else { _defaultLabel = "no label"; } if (possibleLabelsProp.length > 0) { _possibleLabels = possibleLabelsProp.map((e) => { return { key: e.id, value: e.id, text: e.label, content: ( <div onClick={(event) => onItemClick(event, e.id)}>{e.label}</div> ), }; }); } if (_defaultLabel) { _possibleLabels.unshift({ key: -1, value: -1, text: _defaultLabel, content: ( <div onClick={(event) => onItemClick(event, -1)}>{_defaultLabel}</div> ), }); } setPossibleLabels(_possibleLabels); }; const performKeyAction = (key) => { switch (key) { case "Enter": if (!multilabels) { if (visible) incrementConfirmLabel(); } break; case "Escape": closeLabelInput(); break; default: break; } }; const annoLabelUpdate = (label) => { // console.log("LabelInput -> annoLabelUpdate ", label); if (onLabelUpdate) { onLabelUpdate(label.filter((val) => val !== -1)); } }; const incrementConfirmLabel = () => { setConfirmLabel(confirmLabel + 1); }; const closeLabelInput = () => { // console.log("LabelInput -> closeLabelInput"); if (onLabelConfirmed) onLabelConfirmed(label.filter((val) => val !== -1)); if (onClose) onClose(); }; const renderLabelInput = () => { let lbl; if (multilabels) lbl = label; else { lbl = label.length > 0 ? label[0] : -1; } return ( <Ref innerRef={inputRef}> <Dropdown multiple={multilabels} search selection closeOnChange icon="search" options={possibleLabels} placeholder="Enter label" tabIndex={0} onKeyDown={(e) => onKeyDown(e)} value={lbl} onChange={(e, item) => onChange(e, item)} style={{ opacity: 0.8 }} disabled={disabled} open={open} /> </Ref> ); }; const renderLabelInfo = () => { if (!label) return null; let lbl = undefined; if (label.length > 0) { lbl = possibleLabels.find((e) => label[label.length - 1] === e.id); } if (!lbl) return "No label"; return ( <div> <Header>{lbl.label}</Header> <div dangerouslySetInnerHTML={{ __html: lbl.description }} /> </div> ); }; const renderPopupContent = () => { return <div>{renderLabelInfo()}</div>; }; if (!visible) return null; if (renderPopup) { return ( <Popup trigger={renderLabelInput()} content={renderPopupContent()} open position="right center" style={{ opacity: 0.9 }} /> ); } else { return renderLabelInput(); } }; export default LabelInput;