You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .cursor/rules/layer-rules.mdc
+27-10Lines changed: 27 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,22 @@ Layers are fundamental to the Canvas rendering pipeline in @gravity-ui/graph. Th
10
10
11
11
## Key Layer Concepts
12
12
- **Purpose:** Each layer is responsible for a specific aspect of the graph, which can include **rendering visual elements** (e.g., `BackgroundLayer`, `ConnectionLayer`) or **managing behavior and logic** (e.g., handling specific user interactions, managing non-visual state). A layer might not have a direct visual representation but still participate in the graph's lifecycle and logic.
- **`LayerProps` Interface:** Defines configuration for a layer. Key properties include:
15
+
- `canvas`: Configuration for the HTML5 Canvas element (optional).
16
+
- `zIndex`: Stacking order.
17
+
- `classNames`: CSS classes.
18
+
- `respectPixelRatio`: (boolean, default: true) Whether the canvas should account for device pixel ratio for sharper rendering.
19
+
- `transformByCameraPosition`: (boolean, default: false) Whether the canvas transform should automatically follow the camera's position and scale.
20
+
- `html`: Configuration for the HTML overlay element (optional).
21
+
- `zIndex`: Stacking order.
22
+
- `classNames`: CSS classes.
23
+
- `transformByCameraPosition`: (boolean, default: false) Whether the HTML element's transform should automatically follow the camera's position and scale via CSS `matrix()`.
24
+
- `camera`: The `ICamera` instance.
25
+
- `graph`: The main `Graph` instance.
26
+
- `root`: The root HTML element where the layer will be attached.
27
+
- **`LayerContext` Interface:** Provides context information accessible within the layer (via `this.context`). Includes:
- **Location:** Core layer logic and specific layer implementations are found in `src/components/canvas/layers/` and potentially base classes/services like `src/services/Layer.ts`.
14
30
- **Rendering Order/Priority:** Layers are rendered/processed in a specific sequence determined by the main graph component. The order is crucial for visual correctness and logical flow (e.g., connections below blocks, interaction handlers processed before rendering). Typical order might be: Background -> Connections -> Blocks -> Groups -> Behavior/Interaction Layers -> Highlight Layers.
15
31
- **Performance:** Layers optimize rendering and processing by:
@@ -25,7 +41,7 @@ Layers are fundamental to the Canvas rendering pipeline in @gravity-ui/graph. Th
25
41
- The base `Layer` class has the following generic signature: `Layer<Props extends LayerProps, Context extends LayerContext, State extends TComponentState>`.
26
42
- `LayerProps`, `LayerContext`, and `TComponentState` are defined in `src/services/Layer.ts` and `src/lib/Component.ts` respectively.
27
43
- When defining your custom layer, specify your custom Props, Context (if needed, extending `LayerContext`), and State (if needed, extending `TComponentState`) in this order: `class MyLayer extends Layer<TMyLayerProps, TMyLayerContext, TMyLayerState> {...}`.
28
-
- Your custom `TMyLayerProps` interface **must extend the base `LayerProps`**. This is because the base constructor requires properties like `graph` and `camera`.
44
+
- Your custom `TMyLayerProps` interface **must extend the base `LayerProps`**. This is because the base constructor requires properties like `graph` and `camera`. Make sure to define custom props alongside the base ones.
29
45
30
46
- **Constructor and Props:**
31
47
- The constructor of your custom layer will typically receive the *full* `LayerProps` (or your extended `TMyLayerProps`).
@@ -53,18 +69,19 @@ Layers are fundamental to the Canvas rendering pipeline in @gravity-ui/graph. Th
53
69
- **Modifying Existing Layers:**
54
70
- When changing how elements are rendered or behaviors are managed, modify the relevant methods (e.g., `render`, event handlers) of the corresponding layer.
55
71
- Ensure efficiency; avoid unnecessary computations or drawing invisible elements.
56
-
- **Handling Device Pixel Ratio (DPR):** For crisp rendering on HiDPI displays, ensure the layer respects DPR.
57
-
- **Recommended:** Set `respectPixelRatio: true` in the `canvas` options when initializing the layer via `super({ canvas: { respectPixelRatio: true }, ... })`. The base `Layer` class will then attempt to handle canvas sizing automatically.
58
-
- **Manual (if needed):** If automatic handling isn't sufficient or more control is required:
59
-
1. Get the DPR from context: `const dpr = this.context.constants.system.PIXEL_RATIO;`
60
-
2. In your layer's `render` method, reset the transform: `ctx.setTransform(1, 0, 0, 1, 0, 0);`
61
-
3. Clear the correct area: `ctx.clearRect(0, 0, viewWidth * dpr, viewHeight * dpr);` (where `viewWidth`/`viewHeight` are CSS dimensions from camera state).
62
-
4. Scale the context *before* drawing: `ctx.scale(dpr, dpr);`
72
+
- **Handling Device Pixel Ratio (DPR) and Transforms:** For crisp rendering and correct positioning, especially when using Canvas:
73
+
- **`respectPixelRatio`:** Set this to `true` (default) in `LayerProps.canvas` to enable automatic DPR handling by the base `Layer` class. The canvas dimensions will be scaled, and transforms applied correctly.
74
+
- **`transformByCameraPosition`:** Set this to `true` in `LayerProps.canvas` or `LayerProps.html` if the layer's content should move/scale with the camera automatically.
75
+
- **Manual Transforms:**
76
+
- Use `this.resetTransform()` at the beginning of your `render` method. This clears the canvas and applies the base camera transform (if `transformByCameraPosition` is true for canvas) respecting the DPR.
77
+
- Use `this.applyTransform(x, y, scale, respectPixelRatio)` to apply additional transformations relative to the camera or world space, ensuring DPR is accounted for.
78
+
- Use `this.getDRP()` to get the calculated Device Pixel Ratio (respecting `respectPixelRatio` flag).
79
+
- **Coordinate Systems:** Remember that `this.context.ctx` transformations managed by `resetTransform` and `applyTransform` handle the conversion from world space to the scaled canvas coordinate space. Draw using world coordinates.
63
80
- **Layer Lifecycle & Context:**
64
81
- Use `afterInit` for setup that requires the canvas and context to be ready.
65
82
- Inside `afterInit`, reliably get the canvas using `this.getCanvas()`.
66
-
- Initialize or update the layer's full context using `this.setContext({ canvas, ctx: canvas.getContext('2d'), camera: ..., constants: ..., colors: ..., graph: ..., ...this.context });`. This ensures the context object (`this.context`) is correctly typed and populated for your layer.
67
-
- Attach event listeners (e.g., `mousemove`, `mouseleave`) to the graph's root element (`this.props.graph.layers?.$root`) within `afterInit`.
83
+
- Initialize or update the layer's full context using `this.setContext({ ...this.context, /* your additions */ });`. The base `Layer` already initializes `graph`, `camera`, `colors`, `constants`, `layer`. If you create a canvas/HTML element, you need to add `graphCanvas`/`html` and `ctx` to the context after creation (e.g., in `afterInit`).
84
+
- Attach event listeners (e.g., `mousemove`, `mouseleave`) to the graph's root element (`this.props.graph.getGraphHTML()`) or specific layer elements (`this.getCanvas()`, `this.getHTML()`) within `afterInit`.
68
85
- Always clean up listeners and subscriptions in the `unmount` method.
69
86
- **Camera Interaction & Coordinates:**
70
87
- Subscribe to graph's `'camera-change'` event (`this.props.graph.on(...)`) to get updates. The event detail (`event.detail`) provides the `TCameraState` (containing `width`, `height`, `scale`, `x`, `y`).
Copy file name to clipboardExpand all lines: .cursor/rules/project-rules.mdc
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -62,6 +62,7 @@ Rendering system:
62
62
- Full graph is rendered on Canvas for performance
63
63
- When zooming in, HTML/React mode is automatically enabled for interactive elements
64
64
- Uses a smart system that tracks visible blocks and renders only them in React
65
+
- Rendering is organized into Layers (`src/services/Layer.ts`) which control drawing order and can optimize rendering based on camera position and device pixel ratio (`respectPixelRatio`, `transformByCameraPosition` properties in `LayerProps`).
Each layer can have its own canvas and/or HTML elements for rendering and interaction:
73
+
Custom layers should extend the base `Layer` class (`src/services/Layer.ts`). This class provides the core functionality for managing Canvas and HTML elements within the graph's rendering pipeline.
- When `true`, the canvas dimensions are automatically scaled by the device pixel ratio (`window.devicePixelRatio`).
183
+
- The `resetTransform()` and `applyTransform()` methods automatically account for this scaling, so you can draw using world coordinates without manual DPR calculation.
184
+
- Set to `false` only if you need explicit manual control over pixel scaling.
-**For Canvas:** When `true`, the `resetTransform()` method automatically applies the current camera translation (`x`, `y`) and `scale` to the canvas context (`ctx`). This means your subsequent drawing operations in the `render` method should use world coordinates.
188
+
-**For HTML:** When `true`, the HTML element gets the `layer-with-camera` class, and its CSS `transform: matrix(...)` is automatically updated on camera changes to match the camera's position and scale.
189
+
190
+
-**`resetTransform()`**:
191
+
- Call this at the beginning of your canvas `render` method.
192
+
- It resets the canvas context's transform to the identity matrix.
193
+
- It clears the entire canvas (`clearRect`).
194
+
- If `transformByCameraPosition` is `true` for the canvas, it applies the current camera transform (`scale`, `x`, `y`), automatically accounting for DPR if `respectPixelRatio` is `true`.
195
+
196
+
-**`applyTransform(x, y, scale, respectPixelRatioOverride)`**:
197
+
- Applies an *additional* transformation to the canvas context, relative to the current transform (which includes the camera transform if set by `resetTransform`).
198
+
- Useful for drawing elements at specific world positions/scales relative to the base camera view.
199
+
- It automatically accounts for DPR based on the layer's `respectPixelRatio` setting unless overridden by the optional fourth argument.
200
+
201
+
-**`getDRP()`**:
202
+
- Returns the device pixel ratio value that the layer is currently using (respecting the `respectPixelRatio` flag).
203
+
- Use this only if you need the DPR value for complex manual calculations, usually unnecessary when using `resetTransform` and `applyTransform`.
204
+
205
+
**In summary:** For most canvas layers, set `respectPixelRatio: true` and `transformByCameraPosition: true`, call `resetTransform()` at the start of `render`, and draw using world coordinates. Use `applyTransform` for specific relative positioning if needed.
206
+
126
207
### Built-in CSS Classes
127
208
128
209
The library provides several built-in CSS classes that can be used with layers:
0 commit comments