Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit dc32eff

Browse files
committed
Started transitioning to the new tree.
1 parent fb99443 commit dc32eff

34 files changed

+1757
-283
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
"@fortawesome/react-fontawesome": "^0.1.9",
99
"@reduxjs/toolkit": "^1.3.6",
1010
"bootstrap": "^4.4.1",
11+
"css-box-model": "^1.2.1",
1112
"immer": "^6.0.5",
1213
"konva": "^6.0.0",
1314
"react": "^16.13.1",
15+
"react-beautiful-dnd-next": "^11.0.5",
1416
"react-bootstrap": "^1.0.1",
1517
"react-dom": "^16.13.1",
1618
"react-konva": "^16.13.0-2",

src/App.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
flex-direction: row;
1717
}
1818

19-
.App-canvas {
19+
.App-canvas,
20+
.App-tree {
2021
display: flex;
2122
flex-direction: column;
2223
}
24+
25+
.App-tree {
26+
overflow: auto;
27+
}

src/App.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function App() {
3131
const [state, dispatch] = useAppReducer();
3232

3333
useKey('Delete', () => {
34-
if (typeof state.selectedId !== "number") {
34+
if (state.selectedId === null) {
3535
return;
3636
}
3737

@@ -94,7 +94,10 @@ function App() {
9494
pageImage={pageImage}
9595
/>
9696
</Col>
97-
<Col xl={2}>
97+
<Col
98+
xl={2}
99+
className="App-tree"
100+
>
98101
<PageTreeView />
99102
</Col>
100103
</Row>

src/components/PageCanvas/Block.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import React from 'react';
22
import { Group, Rect, Transformer } from 'react-konva';
33
import Konva from 'konva';
44

5-
import { PageTreeItem, Position } from '../../types';
6-
import { TreeMap } from "../../reducer/types";
5+
import { DocumentTreeItem, ElementType, ItemId, Position } from '../../types';
6+
import { TreeItems } from "../../reducer/types";
77
import { calculateDragBounds } from "./utils";
88
import { clamp } from "../../utils";
99
import { IRect } from "konva/types/types";
@@ -13,7 +13,7 @@ interface Box extends IRect {
1313
}
1414

1515
export interface ChangeCallbackParams extends Position {
16-
nodeId: number;
16+
nodeId: ItemId;
1717
width?: number;
1818
height?: number;
1919
}
@@ -23,14 +23,14 @@ export interface BlockProps {
2323
opacity?: number;
2424
draggable?: boolean;
2525
onChange?: (args: ChangeCallbackParams) => void;
26-
item: PageTreeItem;
26+
item: DocumentTreeItem;
2727
isSelected?: boolean;
2828
isHovered?: boolean;
29-
onSelected?: (itemId: number) => void;
29+
onSelected?: (itemId: ItemId) => void;
3030
children?: React.ReactNode
3131
pageWidth: number;
3232
pageHeight: number;
33-
treeMap: TreeMap;
33+
treeItems: TreeItems;
3434
}
3535

3636
const MINIMUM_NODE_WIDTH = 5;
@@ -60,13 +60,13 @@ export function Block(props: BlockProps): React.ReactElement | null {
6060
}, [props]);
6161

6262
const dragBoundFunc = React.useCallback<(pos: Position) => Position>((pos) => {
63-
const bounds = calculateDragBounds(groupRef.current, props.item, props.treeMap, props.pageWidth, props.pageHeight);
63+
const bounds = calculateDragBounds(groupRef.current, props.item, props.treeItems, props.pageWidth, props.pageHeight);
6464

6565
return {
6666
x: clamp(pos.x, bounds.left, bounds.right),
6767
y: clamp(pos.y, bounds.top, bounds.bottom),
6868
};
69-
}, [props.item, props.pageHeight, props.pageWidth, props.treeMap]);
69+
}, [props.item, props.pageHeight, props.pageWidth, props.treeItems]);
7070

7171
const handleDragEnd = React.useCallback<(evt: Konva.KonvaEventObject<DragEvent>) => void>((evt) => {
7272
evt.cancelBubble = true;
@@ -115,13 +115,15 @@ export function Block(props: BlockProps): React.ReactElement | null {
115115
}
116116

117117
const scale = groupRef.current.getAbsoluteScale();
118+
119+
const parent: DocumentTreeItem | null = props.item.parentId ? props.treeItems[props.item.parentId] : null;
118120

119-
const bbox = props.item.parentId ? props.treeMap[props.item.parentId].value.bbox : {
121+
const bbox = (!parent || parent.type === ElementType.Page) ? {
120122
x0: 0,
121123
y0: 0,
122124
x1: props.pageWidth,
123125
y1: props.pageHeight,
124-
};
126+
} : parent.data.bbox;
125127

126128
const scaledBbox = {
127129
left: bbox.x0 * scale.x,
@@ -144,7 +146,11 @@ export function Block(props: BlockProps): React.ReactElement | null {
144146
}
145147

146148
return newBox;
147-
}, [props.item.parentId, props.pageHeight, props.pageWidth, props.treeMap]);
149+
}, [props.item.parentId, props.pageHeight, props.pageWidth, props.treeItems]);
150+
151+
if (props.item.type === ElementType.Page) {
152+
throw new Error('Block component cannot handle Page element type.');
153+
}
148154

149155
return (
150156
<Group
@@ -164,8 +170,8 @@ export function Block(props: BlockProps): React.ReactElement | null {
164170
strokeScaleEnabled={false}
165171
strokeEnabled={props.isHovered}
166172
opacity={props.opacity}
167-
width={props.item.value.bbox.x1 - props.item.value.bbox.x0}
168-
height={props.item.value.bbox.y1 - props.item.value.bbox.y0}
173+
width={props.item.data.bbox.x1 - props.item.data.bbox.x0}
174+
height={props.item.data.bbox.y1 - props.item.data.bbox.y0}
169175
onTransformEnd={handleTransformEnd}
170176
/>
171177
{props.isSelected && (

src/components/PageCanvas/PageGraphics.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
import { Image, Layer, Stage } from "react-konva";
2-
import { BlockTreeItem, PageImage } from "../../types";
2+
import { BlockTreeItem, ItemId, PageImage } from "../../types";
33
import { Block, ChangeCallbackParams } from "./Block";
44
import React from "react";
55
import { useAppReducer } from "../../reducerContext";
66
import { createUpdateTreeNodeRect } from "../../reducer/actions";
7+
import { getNodeOrThrow } from "../../reducer";
78

89
export interface Props {
910
width: number;
1011
height: number;
1112
scale: number;
12-
onSelect: (id: number) => void;
13+
onSelect: (id: ItemId) => void;
1314
onDeselect: () => void;
14-
hoveredId?: number | null;
15-
selectedId?: number | null;
15+
hoveredId?: ItemId | null;
16+
selectedId?: ItemId | null;
1617
pageImage?: PageImage;
1718
}
1819

1920
export default function PageGraphics({ width, height, onSelect, scale, onDeselect, hoveredId, pageImage, selectedId }: Props) {
2021
const [state, dispatch] = useAppReducer();
2122

22-
const treeMap = state.treeMap;
23+
const treeItems = state.treeItems;
2324

2425
function handleChange(args: ChangeCallbackParams) {
2526
dispatch(createUpdateTreeNodeRect(args));
2627
}
2728

28-
if (!pageImage) {
29+
if (!pageImage || state.treeRootId === null) {
2930
return null;
3031
}
3132

@@ -48,8 +49,9 @@ export default function PageGraphics({ width, height, onSelect, scale, onDeselec
4849
</Layer>
4950
<Layer>
5051
{
51-
state.tree
52-
.map(item => treeMap[item] as BlockTreeItem)
52+
state.treeItems[state.treeRootId]
53+
.children
54+
.map(item => getNodeOrThrow(state.treeItems, item) as BlockTreeItem)
5355
.map((block: BlockTreeItem) =>
5456
(
5557
<Block
@@ -62,16 +64,12 @@ export default function PageGraphics({ width, height, onSelect, scale, onDeselec
6264
isSelected={selectedId === block.id}
6365
isHovered={hoveredId === block.id}
6466
draggable
65-
treeMap={treeMap}
67+
treeItems={treeItems}
6668
{...pageProps}
6769
>
6870
{
6971
block.children?.map((paraId) => {
70-
const para = treeMap[paraId];
71-
72-
if (!para) {
73-
return null;
74-
}
72+
const para = getNodeOrThrow(treeItems, paraId);
7573

7674
return (
7775
<Block
@@ -84,16 +82,12 @@ export default function PageGraphics({ width, height, onSelect, scale, onDeselec
8482
isSelected={selectedId === para.id}
8583
isHovered={hoveredId === para.id}
8684
draggable
87-
treeMap={treeMap}
85+
treeItems={treeItems}
8886
{...pageProps}
8987
>
9088
{
91-
para.children?.map((lineId: number) => {
92-
const line = treeMap[lineId];
93-
94-
if (!line) {
95-
return null;
96-
}
89+
para.children?.map((lineId: ItemId) => {
90+
const line = getNodeOrThrow(treeItems, lineId);
9791

9892
return (
9993
<Block
@@ -106,7 +100,7 @@ export default function PageGraphics({ width, height, onSelect, scale, onDeselec
106100
isSelected={selectedId === line.id}
107101
isHovered={hoveredId === line.id}
108102
draggable
109-
treeMap={treeMap}
103+
treeItems={treeItems}
110104
{...pageProps}
111105
/>
112106
);

src/components/PageCanvas/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { useMeasure, useTitle } from "react-use";
33
import { Button, Spinner } from 'react-bootstrap';
44

5-
import { PageImage, RecognizeUpdate } from '../../types';
5+
import { ItemId, PageImage, RecognizeUpdate } from '../../types';
66
import { createInit, createChangeSelected } from '../../reducer/actions';
77
import PageGraphics from "./PageGraphics";
88
import { recognize } from "../../ocr";
@@ -45,7 +45,7 @@ export default function PageCanvas(props: Props) {
4545

4646
React.useLayoutEffect(setFitScale, [setFitScale]);
4747

48-
function handleSelected(itemId: number | null) {
48+
function handleSelected(itemId: ItemId | null) {
4949
dispatch(createChangeSelected(itemId));
5050
}
5151

src/components/PageCanvas/utils.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Konva from "konva";
2-
import { BaseTreeItem, ElementType, PageTreeItem, Position } from "../../types";
3-
import { TreeMap } from "../../reducer/types";
2+
import { BaseTreeItem, DocumentTreeItem, ElementType, Position } from "../../types";
3+
import { TreeItems } from "../../reducer/types";
44
import { Bbox } from "tesseract.js";
55

66
type BoundsTuple = [number, number, number, number];
@@ -26,10 +26,10 @@ const bboxToBoundsTuple = (bbox: Bbox): BoundsTuple => ([
2626
bbox.y1,
2727
]);
2828

29-
const getParent = (treeMap: TreeMap, item: PageTreeItem): BaseTreeItem<ElementType, any> | null => typeof item.parentId === 'number' ? treeMap[item.parentId] : null;
29+
const getParent = (treeItems: TreeItems, item: DocumentTreeItem): BaseTreeItem<ElementType, any> | null => item.parentId !== null ? treeItems[item.parentId] : null;
3030

31-
export function calculateDragBounds(node: Konva.Node | null, item: PageTreeItem, treeMap: TreeMap, pageWidth: number, pageHeight: number) {
32-
if (!node) {
31+
export function calculateDragBounds(node: Konva.Node | null, item: DocumentTreeItem, treeItems: TreeItems, pageWidth: number, pageHeight: number) {
32+
if (!node || item.type === ElementType.Page) {
3333
return INFINITE_BOUNDS;
3434
}
3535

@@ -41,8 +41,8 @@ export function calculateDragBounds(node: Konva.Node | null, item: PageTreeItem,
4141

4242
const scale = node.getAbsoluteScale();
4343

44-
const nodeWidth = item.value.bbox.x1 - item.value.bbox.x0;
45-
const nodeHeight = item.value.bbox.y1 - item.value.bbox.y0;
44+
const nodeWidth = item.data.bbox.x1 - item.data.bbox.x0;
45+
const nodeHeight = item.data.bbox.y1 - item.data.bbox.y0;
4646

4747
const stageOffset: Position = {
4848
x: stage.x() / scale.x,
@@ -51,9 +51,9 @@ export function calculateDragBounds(node: Konva.Node | null, item: PageTreeItem,
5151

5252
const pageBounds: BoundsTuple = [0, 0, pageWidth, pageHeight];
5353

54-
const parent = getParent(treeMap, item);
54+
const parent = getParent(treeItems, item);
5555

56-
const parentBounds: BoundsTuple = parent ? bboxToBoundsTuple(parent.value.bbox) : pageBounds;
56+
const parentBounds: BoundsTuple = parent ? bboxToBoundsTuple(parent.data.bbox) : pageBounds;
5757

5858
const offsetParentBounds = offsetBounds(parentBounds, stageOffset);
5959

src/components/PageTreeView/index.css

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.Tree {
2+
height: 100%;
3+
flex: 1 1;
4+
flex-basis: 0;
5+
overflow: auto;
6+
}
7+
8+
%rowItem {
9+
display: inline-block;
10+
vertical-align: middle;
11+
}
12+
13+
.Tree-rowContents {
14+
@extend %rowItem;
15+
position: relative;
16+
height: 100%;
17+
flex: 1 0 auto;
18+
display: flex;
19+
align-items: center;
20+
font-size: 0.8rem;
21+
}
22+
23+
.Tree-rowLabel {
24+
@extend %rowItem;
25+
flex: 0 1 auto;
26+
}
27+
28+
.Tree-collapseButton,
29+
.Tree-expandButton {
30+
appearance: none;
31+
border: none;
32+
background: transparent;
33+
padding: 0;
34+
z-index: 2;
35+
position: absolute;
36+
top: 50%;
37+
width: 24px;
38+
height: 24px;
39+
transform: translate3d(-100%, -50%, 0);
40+
cursor: pointer;
41+
42+
&::after {
43+
content: "";
44+
position: absolute;
45+
transform-origin: 5px 4px;
46+
transform: translate3d(-50%, -20%, 0);
47+
border: solid transparent 7px;
48+
border-left-width: 5px;
49+
border-right-width: 5px;
50+
border-top-color: gray;
51+
}
52+
53+
&:hover::after {
54+
border-top-color: black;
55+
}
56+
57+
&:focus {
58+
outline: none;
59+
60+
&::after {
61+
filter: drop-shadow(0 0 1px #83bef9) drop-shadow(0 0 1px #83bef9) drop-shadow(0 0 1px #83bef9);
62+
}
63+
}
64+
}
65+
66+
.Tree-expandButton::after {
67+
transform: translate3d(-50%, -20%, 0) rotateZ(-90deg);
68+
}

0 commit comments

Comments
 (0)