Skip to content

Commit 9f10e1c

Browse files
authored
fix(Layer): fix Layer lifecycle (#112)
feat(Graph): Add method to get elements in viewport
1 parent 44198dd commit 9f10e1c

File tree

8 files changed

+102
-114
lines changed

8 files changed

+102
-114
lines changed

src/components/canvas/groups/BlockGroups.ts

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,23 @@ export class BlockGroups<P extends BlockGroupsProps = BlockGroupsProps> extends
4848
return groupingFn(blocks);
4949
});
5050

51-
constructor(props: BlockGroupsProps & { updateBlocksOnDrag?: boolean }) {
52-
super(props);
53-
this.unsubscribe.push(
54-
computed(() => {
51+
protected afterInit(): void {
52+
this.onSignal(
53+
computed<TGroup[]>(() => {
5554
const groupedBlocks = this.$groupsBlocksMap.value;
5655
return Object.entries(groupedBlocks).map(([key, blocks]) =>
5756
mapToGroups(key, { blocks, rect: getUsableRectByBlockIds(blocks) })
5857
);
59-
}).subscribe((groups: TGroup[]) => {
58+
}),
59+
(groups: TGroup[]) => {
6060
this.setGroups(groups);
61-
})
61+
}
6262
);
63+
super.afterInit();
6364
}
6465
};
6566
}
6667

67-
private unsubscribe: (() => void)[] = [];
68-
6968
protected $groupsBlocksMap = new Signal<Record<string, BlockState[]>>({});
7069

7170
protected $groupsSource = this.props.graph.rootStore.groupsList.$groups;
@@ -76,6 +75,7 @@ export class BlockGroups<P extends BlockGroupsProps = BlockGroupsProps> extends
7675
zIndex: 1,
7776
classNames: ["no-user-select"],
7877
transformByCameraPosition: true,
78+
...props.canvas,
7979
},
8080
...props,
8181
});
@@ -92,16 +92,15 @@ export class BlockGroups<P extends BlockGroupsProps = BlockGroupsProps> extends
9292
graph: this.props.graph,
9393
ownerDocument: this.props.root!,
9494
});
95+
}
9596

96-
this.unsubscribe.push(
97-
this.$groupsSource.subscribe((groups) => {
98-
this.shouldUpdateChildren = true;
99-
this.shouldRenderChildren = true;
100-
this.setState({ groups });
101-
})
102-
);
103-
104-
this.performRender = this.performRender.bind(this);
97+
protected afterInit(): void {
98+
this.onSignal(this.$groupsSource, (groups) => {
99+
this.shouldUpdateChildren = true;
100+
this.shouldRenderChildren = true;
101+
this.setState({ groups });
102+
});
103+
super.afterInit();
105104
}
106105

107106
public getParent(): CoreComponent | undefined {
@@ -136,11 +135,6 @@ export class BlockGroups<P extends BlockGroupsProps = BlockGroupsProps> extends
136135
super.unmountLayer();
137136
}
138137

139-
protected unmount(): void {
140-
this.unsubscribe.forEach((unsubscribe) => unsubscribe());
141-
super.unmount();
142-
}
143-
144138
protected getGroupComponent(group: GroupState) {
145139
return group.$state.value.component || this.props.groupComponent || Group;
146140
}
@@ -157,8 +151,4 @@ export class BlockGroups<P extends BlockGroupsProps = BlockGroupsProps> extends
157151
);
158152
});
159153
}
160-
161-
public render() {
162-
this.resetTransform();
163-
}
164154
}

src/components/canvas/layers/belowLayer/BelowLayer.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,22 @@ export class BelowLayer extends Layer<TBelowLayerProps, TBelowLayerContext> {
2626
zIndex: 1,
2727
classNames: ["no-pointer-events"],
2828
transformByCameraPosition: true,
29+
...props.canvas,
2930
},
3031
...props,
3132
});
33+
this.background = this.props.graph.rootStore.settings.$background.value || (Background as typeof Component);
34+
}
3235

36+
protected afterInit(): void {
3337
this.onSignal(this.props.graph.rootStore.settings.$background, () => {
3438
this.background = this.props.graph.rootStore.settings.$background.value || (Background as typeof Component);
3539
this.shouldUpdateChildren = true;
3640
this.performRender();
3741
});
38-
}
39-
40-
protected afterInit(): void {
41-
this.onGraphEvent("camera-change", this.performRender);
4242
super.afterInit();
4343
}
4444

45-
public render() {
46-
this.resetTransform();
47-
}
48-
4945
public updateChildren(): ComponentDescriptor<CoreComponentProps, CoreComponentContext>[] {
5046
return [this.background.create({})];
5147
}

src/components/canvas/layers/connectionLayer/ConnectionLayer.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export class ConnectionLayer extends Layer<
132132
canvas: {
133133
zIndex: 4,
134134
classNames: ["no-pointer-events"],
135+
...props.canvas,
135136
},
136137
...props,
137138
});
@@ -148,9 +149,6 @@ export class ConnectionLayer extends Layer<
148149

149150
this.enabled = Boolean(this.props.graph.rootStore.settings.getConfigFlag("canCreateNewConnections"));
150151

151-
this.eventAborter = new AbortController();
152-
this.performRender = this.performRender.bind(this);
153-
154152
this.onSignal(this.props.graph.rootStore.settings.$settings, (value) => {
155153
this.enabled = Boolean(value.canCreateNewConnections);
156154
});
@@ -163,7 +161,6 @@ export class ConnectionLayer extends Layer<
163161
*/
164162
protected afterInit(): void {
165163
// Register event listeners with the graphOn wrapper method for automatic cleanup when unmounted
166-
this.onGraphEvent("camera-change", this.performRender);
167164
this.onGraphEvent("mousedown", this.handleMouseDown, {
168165
capture: true,
169166
});

src/components/canvas/layers/newBlockLayer/NewBlockLayer.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class NewBlockLayer extends Layer<
6666
canvas: {
6767
zIndex: 4,
6868
classNames: ["no-pointer-events"],
69+
...props.canvas,
6970
},
7071
...props,
7172
});
@@ -79,9 +80,6 @@ export class NewBlockLayer extends Layer<
7980
colors: this.props.graph.graphColors,
8081
graph: this.props.graph,
8182
});
82-
83-
this.eventAborter = new AbortController();
84-
this.performRender = this.performRender.bind(this);
8583
}
8684

8785
/**
@@ -90,14 +88,11 @@ export class NewBlockLayer extends Layer<
9088
* after the layer is unmounted and reattached.
9189
*/
9290
protected afterInit(): void {
91+
super.afterInit();
9392
// Register event listeners with the graphOn wrapper method for automatic cleanup when unmounted
94-
this.onGraphEvent("camera-change", this.performRender);
9593
this.onGraphEvent("mousedown", this.handleMouseDown, {
9694
capture: true,
9795
});
98-
99-
// Call parent afterInit to ensure proper initialization
100-
super.afterInit();
10196
}
10297

10398
protected handleMouseDown = (nativeEvent: GraphMouseEvent) => {
@@ -181,14 +176,15 @@ export class NewBlockLayer extends Layer<
181176
this.initialPoint = this.context.graph.getPointInCameraSpace(event);
182177

183178
this.context.graph.executеDefaultEventAction("block-add-start-from-shadow", { blocks }, () => {
179+
const scale = this.context.camera.getCameraScale();
184180
const xy = getXY(this.context.graphCanvas, event);
185181
const mouseX = xy[0];
186182
const mouseY = xy[1];
187183

188184
// Calculate the screen position of the clicked block
189185
const cameraRect = this.context.camera.getCameraRect();
190-
const clickedBlockX = block.connectedState.x * this.context.camera.getCameraScale() + cameraRect.x;
191-
const clickedBlockY = block.connectedState.y * this.context.camera.getCameraScale() + cameraRect.y;
186+
const clickedBlockX = block.connectedState.x * scale + cameraRect.x;
187+
const clickedBlockY = block.connectedState.y * scale + cameraRect.y;
192188

193189
// Calculate the click position relative to the block's top-left corner
194190
const clickOffsetX = mouseX - clickedBlockX;
@@ -197,12 +193,12 @@ export class NewBlockLayer extends Layer<
197193
// Create ghost blocks for each block being duplicated
198194
this.blockStates = this.copyBlocks.map((blockState) => {
199195
// Calculate screen position for each block
200-
const blockScreenX = blockState.x * this.context.camera.getCameraScale() + cameraRect.x;
201-
const blockScreenY = blockState.y * this.context.camera.getCameraScale() + cameraRect.y;
196+
const blockScreenX = blockState.x * scale + cameraRect.x;
197+
const blockScreenY = blockState.y * scale + cameraRect.y;
202198

203199
// Use block's own width and height values
204-
const blockWidth = blockState.width * this.context.camera.getCameraScale();
205-
const blockHeight = blockState.height * this.context.camera.getCameraScale();
200+
const blockWidth = blockState.width * scale;
201+
const blockHeight = blockState.height * scale;
206202

207203
return {
208204
width: blockWidth,

src/components/canvas/layers/selectionLayer/SelectionLayer.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export class SelectionLayer extends Layer<
3131
canvas: {
3232
zIndex: 4,
3333
classNames: ["no-pointer-events"],
34+
...props.canvas,
3435
},
3536
...props,
3637
});
@@ -39,8 +40,6 @@ export class SelectionLayer extends Layer<
3940
canvas: this.getCanvas(),
4041
ctx: this.getCanvas().getContext("2d"),
4142
});
42-
43-
this.performRender = this.performRender.bind(this);
4443
}
4544

4645
/**
@@ -50,7 +49,6 @@ export class SelectionLayer extends Layer<
5049
*/
5150
protected afterInit(): void {
5251
// Set up event handlers here instead of in constructor
53-
this.onGraphEvent("camera-change", this.performRender);
5452
this.onGraphEvent("mousedown", this.handleMouseDown, {
5553
capture: true,
5654
});

src/graph.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,23 @@ export class Graph {
177177
return this.getElementsOverPoint(point, filter)?.[0] as InstanceType<T> | undefined;
178178
}
179179

180+
public getViewportRect(): TRect {
181+
const CAMERA_VIEWPORT_TRESHOLD = this.graphConstants.system.CAMERA_VIEWPORT_TRESHOLD;
182+
const cameraSize = this.cameraService.getCameraState();
183+
184+
const x = -cameraSize.relativeX - cameraSize.relativeWidth * CAMERA_VIEWPORT_TRESHOLD;
185+
const y = -cameraSize.relativeY - cameraSize.relativeHeight * CAMERA_VIEWPORT_TRESHOLD;
186+
const width = -cameraSize.relativeX + cameraSize.relativeWidth * (1 + CAMERA_VIEWPORT_TRESHOLD) - x;
187+
const height = -cameraSize.relativeY + cameraSize.relativeHeight * (1 + CAMERA_VIEWPORT_TRESHOLD) - y;
188+
189+
return { x, y, width, height };
190+
}
191+
192+
public getElementsInViewport<T extends Constructor<GraphComponent>>(filter?: T[]): InstanceType<T>[] {
193+
const viewportRect = this.getViewportRect();
194+
return this.getElementsOverRect(viewportRect, filter);
195+
}
196+
180197
public getElementsOverRect<T extends Constructor<GraphComponent>>(rect: TRect, filter?: T[]): InstanceType<T>[] {
181198
const items = this.hitTest.testBox({
182199
minX: rect.x,

src/react-components/BlocksList.tsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,8 @@ export const BlocksList = memo(function BlocksList({ renderBlock, graphObject }:
4949
setBlockStates([]);
5050
return;
5151
}
52-
const CAMERA_VIEWPORT_TRESHOLD = graphObject.graphConstants.system.CAMERA_VIEWPORT_TRESHOLD;
53-
const cameraSize = graphObject.cameraService.getCameraState();
54-
55-
const x = -cameraSize.relativeX - cameraSize.relativeWidth * CAMERA_VIEWPORT_TRESHOLD;
56-
const y = -cameraSize.relativeY - cameraSize.relativeHeight * CAMERA_VIEWPORT_TRESHOLD;
57-
const width = -cameraSize.relativeX + cameraSize.relativeWidth * (1 + CAMERA_VIEWPORT_TRESHOLD) - x;
58-
const height = -cameraSize.relativeY + cameraSize.relativeHeight * (1 + CAMERA_VIEWPORT_TRESHOLD) - y;
59-
60-
const statesInRect = graphObject
61-
.getElementsOverRect(
62-
{
63-
x,
64-
y,
65-
width,
66-
height,
67-
},
68-
[CanvasBlock]
69-
)
70-
.map((component: CanvasBlock) => component.connectedState);
52+
const statesInRect = graphObject.getElementsInViewport([CanvasBlock]).map((component) => component.connectedState);
53+
7154
setBlockStates((blocks) => {
7255
if (
7356
!isEqual(
@@ -110,14 +93,20 @@ export const BlocksList = memo(function BlocksList({ renderBlock, graphObject }:
11093

11194
useEffect(() => {
11295
return () => {
113-
// throttleUpdate.cancel();
11496
scheduleListUpdate.cancel();
11597
};
11698
}, []);
11799

118100
// init list
119101
useEffect(() => {
120-
graphObject.hitTest.waitUsableRectUpdate(updateBlockList);
102+
graphObject.hitTest.waitUsableRectUpdate(() => {
103+
if (graphObject.cameraService.getCameraBlockScaleLevel() !== ECameraScaleLevel.Detailed) {
104+
setRenderAllowed(false);
105+
return;
106+
}
107+
setRenderAllowed(true);
108+
scheduleListUpdate.flush();
109+
});
121110
return graphObject.hitTest.onUsableRectUpdate(updateBlockList);
122111
}, [graphObject.hitTest, isRenderAllowed, graphState]);
123112

0 commit comments

Comments
 (0)