Skip to content

Commit 116dba1

Browse files
extend region classlist prop to array object
1 parent 8781aa4 commit 116dba1

File tree

11 files changed

+136
-53
lines changed

11 files changed

+136
-53
lines changed

src/Annotator/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export type AnnotatorProps = {
2020
taskDescription?: string;
2121
allowedArea?: { x: number; y: number; w: number; h: number };
2222
regionTagList?: Array<string>;
23-
regionClsList?: Array<string>;
23+
regionClsList?: Array<string | { id: string; label: string }>;
2424
imageTagList?: Array<string>;
2525
imageClsList?: Array<string>;
2626
enabledTools?: Array<string>;

src/Annotator/reducers/general-reducer.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ export default <T extends ImmutableObject<MainLayoutState>>(
3535

3636
if (action.type === "ON_CLS_ADDED" && !!action.cls) {
3737
const oldRegionClsList = state.regionClsList;
38+
const isStringRegionClsList = oldRegionClsList?.every(
39+
(cls) => typeof cls === "string"
40+
);
41+
if (!isStringRegionClsList) return state;
3842
return {
3943
...state,
40-
regionClsList: oldRegionClsList?.concat(action.cls),
44+
regionClsList: ((oldRegionClsList || []) as string[]).concat(action.cls),
4145
};
4246
}
4347

@@ -148,7 +152,11 @@ export default <T extends ImmutableObject<MainLayoutState>>(
148152
if (oldRegion?.cls !== action.region.cls) {
149153
state = saveToHistory(state, "Change Region Classification") as T;
150154
const clsIndex = action.region.cls
151-
? state.regionClsList?.indexOf(action.region.cls)
155+
? state.regionClsList?.findIndex((cls) =>
156+
typeof cls === "string"
157+
? cls === action.region.cls
158+
: cls.id === action.region.cls
159+
)
152160
: undefined;
153161
if (clsIndex !== undefined && clsIndex !== -1) {
154162
state = Immutable(state).setIn(
@@ -631,10 +639,13 @@ export default <T extends ImmutableObject<MainLayoutState>>(
631639
let newRegion;
632640
let defaultRegionCls = state.selectedCls,
633641
defaultRegionColor = "#ff0000";
634-
635642
const clsIndex =
636643
defaultRegionCls && state.regionClsList
637-
? state.regionClsList.indexOf(defaultRegionCls)
644+
? state.regionClsList.findIndex((cls) =>
645+
typeof cls === "string"
646+
? cls === defaultRegionCls
647+
: cls.id === defaultRegionCls
648+
)
638649
: -1;
639650
if (clsIndex !== -1) {
640651
defaultRegionColor = colors[clsIndex % colors.length];
@@ -745,7 +756,6 @@ export default <T extends ImmutableObject<MainLayoutState>>(
745756
return state;
746757
}
747758
state = saveToHistory(state, "Create Keypoints") as T;
748-
console.log(state.keypointDefinitions);
749759
const [[keypointsDefinitionId, { landmarks }]] = Object.entries(
750760
state.keypointDefinitions
751761
);

src/ClassSelectionMenu/index.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ const Number = styled("div")(() => ({
5252
color: muiColors.grey[700],
5353
}));
5454

55+
const getRegionValue = (item: string | { id: string; label: string }) => {
56+
return typeof item === "string" ? item : item.id;
57+
};
58+
5559
interface ClassSelectionMenuProps {
5660
selectedCls?: string;
57-
regionClsList: string[];
58-
onSelectCls: (label?: string) => void;
61+
regionClsList: (string | { id: string; label: string })[];
62+
onSelectCls: (value: string) => void;
5963
}
6064

6165
export const ClassSelectionMenu = ({
@@ -64,9 +68,15 @@ export const ClassSelectionMenu = ({
6468
onSelectCls,
6569
}: ClassSelectionMenuProps) => {
6670
useEffect(() => {
67-
const keyMapping: Record<string, (label?: string) => void> = {};
71+
const keyMapping: Record<
72+
string,
73+
(item?: string | { id: string; label: string }) => void
74+
> = {};
6875
for (let i = 0; i < 9 && i < regionClsList.length; i++) {
69-
keyMapping[i + 1] = () => onSelectCls(regionClsList[i]);
76+
keyMapping[i + 1] = () => {
77+
const item = regionClsList[i];
78+
onSelectCls(getRegionValue(item));
79+
};
7080
}
7181
const onKeyDown = (e: KeyboardEvent) => {
7282
if (keyMapping[e.key]) {
@@ -86,19 +96,29 @@ export const ClassSelectionMenu = ({
8696
icon={<BallotIcon style={{ color: muiColors.grey[700] }} />}
8797
expandedByDefault
8898
>
89-
{regionClsList.map((label, index) => (
99+
{regionClsList.map((item, index) => (
90100
<LabelContainer
91-
className={classnames({ selected: label === selectedCls })}
92-
onClick={() => onSelectCls(label)}
101+
className={classnames({
102+
selected: getRegionValue(item) === selectedCls,
103+
})}
104+
onClick={() => onSelectCls(getRegionValue(item))}
93105
>
94106
<Circle
95107
style={{ backgroundColor: colors[index % colors.length] }}
96108
/>
97-
<Label className={classnames({ selected: label === selectedCls })}>
98-
{capitalize(label)}
109+
<Label
110+
className={classnames({
111+
selected: getRegionValue(item) === selectedCls,
112+
})}
113+
>
114+
{capitalize(typeof item === "string" ? item : item.label)}
99115
</Label>
100116
<DashSep />
101-
<Number className={classnames({ selected: label === selectedCls })}>
117+
<Number
118+
className={classnames({
119+
selected: getRegionValue(item) === selectedCls,
120+
})}
121+
>
102122
{index < 9 ? `Key [${index + 1}]` : ""}
103123
</Number>
104124
</LabelContainer>

src/DemoSite/Editor.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ export const examples: Record<string, () => Omit<AnnotatorProps, "onExit">> = {
4545
taskDescription:
4646
"Annotate each image according to this _markdown_ specification.",
4747
regionTagList: ["has-bun"],
48-
regionClsList: ["hotdog", "not-hotdog"],
48+
regionClsList: [
49+
{ id: "1", label: "hotdog" },
50+
{ id: "2", label: "not-hotdog" },
51+
],
4952
enabledTools: [
5053
"select",
5154
"create-point",

src/ImageCanvas/index.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type Props = {
6262
showHighlightBox?: boolean;
6363
showPointDistances?: boolean;
6464
pointDistancePrecision?: number;
65-
regionClsList?: Array<string>;
65+
regionClsList?: Array<string> | Array<{ id: string; label: string }>;
6666
regionTagList?: Array<string>;
6767
allowedArea?: { x: number; y: number; w: number; h: number };
6868
RegionEditLabel?: ComponentType<any> | FunctionComponent<any> | null;
@@ -72,10 +72,10 @@ type Props = {
7272
autoSegmentationOptions?: AutosegOptions;
7373
modifyingAllowedArea?: boolean;
7474
allowComments?: boolean;
75-
onChangeRegion: (region: Region) => any;
76-
onBeginRegionEdit: (region: Region) => any;
77-
onCloseRegionEdit: (region: Region) => any;
78-
onDeleteRegion: (region: Region) => any;
75+
onChangeRegion: (region: Region) => void;
76+
onBeginRegionEdit: (region: Region) => void;
77+
onCloseRegionEdit: (region: Region) => void;
78+
onDeleteRegion: (region: Region) => void;
7979
onBeginBoxTransform: (region: Box, point: [number, number]) => void;
8080
onBeginMovePolygonPoint: (region: Polygon, index: number) => void;
8181
onBeginMoveKeypoint: (region: Keypoints, keypointId: string) => void;
@@ -481,7 +481,9 @@ export const ImageCanvas = ({
481481
hide={!showMask}
482482
autoSegmentationOptions={autoSegmentationOptions}
483483
imagePosition={imagePosition}
484-
regionClsList={regionClsList}
484+
regionClsList={regionClsList?.map((c) =>
485+
typeof c === "string" ? c : c.id
486+
)}
485487
imageSrc={imageSrc}
486488
regions={regions}
487489
/>

src/MainLayout/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ export const MainLayout = ({
339339
/>
340340
),
341341
<RegionSelector
342+
regionClsList={state.regionClsList}
342343
regions={activeImage ? activeImage.regions : []}
343344
onSelectRegion={action("SELECT_REGION", "region")}
344345
onDeleteRegion={action("DELETE_REGION", "region")}

src/MainLayout/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export type MainLayoutStateBase = {
101101
mode: Mode;
102102
taskDescription: string;
103103
allowedArea?: { x: number; y: number; w: number; h: number };
104-
regionClsList?: Array<string>;
104+
regionClsList?: Array<string> | Array<{ id: string; label: string }>;
105105
regionTagList?: Array<string>;
106106
imageClsList?: Array<string>;
107107
imageTagList?: Array<string>;

src/RegionLabel/index.tsx

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const useStyles = makeStyles(styles);
2323
type Props = {
2424
region: Region;
2525
editing?: boolean;
26-
allowedClasses?: Array<string>;
26+
allowedClasses?: Array<string> | Array<{ id: string; label: string }>;
2727
allowedTags?: Array<string>;
2828
cls?: string;
2929
tags?: Array<string>;
@@ -57,6 +57,21 @@ export const RegionLabel = ({
5757
if (commentInput) return commentInput.focus();
5858
};
5959

60+
const isCreatableAllowedClasses = typeof allowedClasses?.[0] === "string";
61+
const selectedRegionClass =
62+
allowedClasses?.find((c) => typeof c === "object" && c.id === region.cls) ||
63+
region.cls;
64+
const selectedLabel =
65+
selectedRegionClass && typeof selectedRegionClass === "object"
66+
? selectedRegionClass.label
67+
: region.cls;
68+
const selectedValue =
69+
selectedRegionClass && typeof selectedRegionClass === "object"
70+
? { label: selectedRegionClass.label, value: selectedRegionClass.id }
71+
: region.cls
72+
? { label: region.cls, value: region.cls }
73+
: null;
74+
6075
return (
6176
<ThemeProvider theme={theme}>
6277
<Paper
@@ -73,7 +88,7 @@ export const RegionLabel = ({
7388
className="circle"
7489
style={{ backgroundColor: region.color }}
7590
/>
76-
{region.cls}
91+
{selectedLabel}
7792
</div>
7893
)}
7994
{region.tags && (
@@ -116,36 +131,59 @@ export const RegionLabel = ({
116131
</div>
117132
{(allowedClasses || []).length > 0 && (
118133
<div style={{ marginTop: 6 }}>
119-
<CreatableSelect
120-
placeholder="Classification"
121-
onChange={(o, actionMeta) => {
122-
if (!o) return;
123-
if (
124-
actionMeta.action == "create-option" &&
125-
onRegionClassAdded
126-
) {
127-
onRegionClassAdded(o.value);
128-
}
129-
// TODO: check if this is correct after update source
130-
onChange({
131-
...region,
132-
cls: o.value,
133-
});
134-
}}
135-
value={
136-
region.cls ? { label: region.cls, value: region.cls } : null
137-
}
138-
options={asMutable(
139-
allowedClasses?.map((c) => ({ value: c, label: c }))
140-
)}
141-
/>
134+
{isCreatableAllowedClasses ? (
135+
<CreatableSelect
136+
placeholder="Classification"
137+
onChange={(o, actionMeta) => {
138+
if (!o) return;
139+
if (
140+
actionMeta.action == "create-option" &&
141+
onRegionClassAdded
142+
) {
143+
onRegionClassAdded(o.value);
144+
}
145+
onChange({
146+
...region,
147+
cls: o.value,
148+
});
149+
}}
150+
value={selectedValue}
151+
options={asMutable(
152+
allowedClasses?.map((c) => {
153+
if (typeof c === "string") {
154+
return { value: c, label: c };
155+
}
156+
return { value: c.id, label: c.label };
157+
})
158+
)}
159+
/>
160+
) : (
161+
<Select
162+
placeholder="Classification"
163+
onChange={(o) => {
164+
if (!o) return;
165+
onChange({
166+
...region,
167+
cls: o.value,
168+
});
169+
}}
170+
value={selectedValue}
171+
options={asMutable(
172+
allowedClasses?.map((c) => {
173+
if (typeof c === "string") {
174+
return { value: c, label: c };
175+
}
176+
return { value: c.id, label: c.label };
177+
})
178+
)}
179+
/>
180+
)}
142181
</div>
143182
)}
144183
{(allowedTags || []).length > 0 && (
145184
<div style={{ marginTop: 4 }}>
146185
<Select
147186
onChange={(newTags) =>
148-
// TODO: check if this is correct after update source
149187
onChange({
150188
...region,
151189
tags: newTags.map((t) => t.value),

src/RegionSelectorSidebarBox/index.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ const MemoRowHeader = memo(RowHeader);
115115

116116
interface RowProps {
117117
region: Region;
118+
regionClsList?: Array<{ id: string; label: string }> | string[];
118119
highlighted?: boolean;
119120
onSelectRegion: (r: Region) => void;
120121
onDeleteRegion: (r: Region) => void;
@@ -129,6 +130,7 @@ interface RowProps {
129130

130131
const Row = ({
131132
region: r,
133+
regionClsList,
132134
highlighted,
133135
onSelectRegion,
134136
onDeleteRegion,
@@ -137,13 +139,18 @@ const Row = ({
137139
cls,
138140
index,
139141
}: RowProps) => {
142+
const selectedCls = regionClsList?.find(
143+
(c) => typeof c === "object" && c.id === cls
144+
);
145+
const clsLabel =
146+
selectedCls && typeof selectedCls === "object" ? selectedCls.label : cls;
140147
return (
141148
<RowLayout
142149
header={false}
143150
highlighted={highlighted || false}
144151
onClick={() => onSelectRegion(r)}
145152
order={`#${index + 1}`}
146-
classification={<Chip text={cls || ""} color={color || "#ddd"} />}
153+
classification={<Chip text={clsLabel || ""} color={color || "#ddd"} />}
147154
area=""
148155
trash={<TrashIcon onClick={() => onDeleteRegion(r)} className="icon2" />}
149156
lock={
@@ -192,13 +199,15 @@ const emptyArr: Region[] = [];
192199

193200
interface RegionSelectorSidebarBoxProps {
194201
regions?: Region[];
202+
regionClsList?: Array<{ id: string; label: string }> | string[];
195203
onDeleteRegion: (r: Region) => void;
196204
onChangeRegion: (r: Region) => void;
197205
onSelectRegion: (r: Region) => void;
198206
}
199207

200208
export const RegionSelectorSidebarBox = ({
201209
regions = emptyArr,
210+
regionClsList,
202211
onDeleteRegion,
203212
onChangeRegion,
204213
onSelectRegion,
@@ -219,6 +228,7 @@ export const RegionSelectorSidebarBox = ({
219228
key={r.id}
220229
rId={r.id}
221230
{...r}
231+
regionClsList={regionClsList}
222232
region={r}
223233
index={i}
224234
onSelectRegion={onSelectRegion}

src/RegionTags/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type RegionTagsProps = {
2323
regions: Region[];
2424
projectRegionBox: ProjectBoxFn;
2525
mouseEvents: MouseEvents;
26-
regionClsList?: string[];
26+
regionClsList?: Array<string> | Array<{ id: string; label: string }>;
2727
regionTagList?: string[];
2828
onBeginRegionEdit: (r: Region) => void;
2929
onChangeRegion: (r: Region) => void;

0 commit comments

Comments
 (0)