fix(editor): non-canvas block size/position in embed-edgeless-doc at non-1 zoom (#14074)

### Problem
●Similar to
[PR#14015](https://github.com/toeverything/AFFiNE/pull/14015), the
container's own scaling factor (`viewScale`) was not taken into account.
This time the issue affects **non-canvas blocks** (e.g. `edgeless-note`,
`edgeless-image`, and any component extending `GfxBlockComponent`).
●The follwing image and video show the case when zoom is 0.5.

<img width="822" height="414" alt="图片"
src="https://github.com/user-attachments/assets/cee1cb88-2764-443c-aa7a-0443308b0e29"
/>


https://github.com/user-attachments/assets/3c744579-16c4-4f10-b421-e0606da1269f

### Solution
●Incorporated `viewScale` into the CSS `translate` calculation for all
`GfxBlockComponent` instances.

### Additional Improvement
●Minor refactor: the class returned by `toGfxBlockComponent()` now
reuses the original `getCSSTransform()` implementation from
`GfxBlockComponent.prototype` via `.call(this)`, eliminating duplicated
code.

### After
●The refined is as follows.


https://github.com/user-attachments/assets/24de0429-63a3-45a7-9b31-d91a4279e233


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Improved viewport scaling so visual transforms (translation and zoom)
correctly account for view scale, yielding more consistent rendering
during zoom and pan.
* Centralized transform calculation to a shared implementation, reducing
duplication and ensuring uniform behavior across views.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com>
This commit is contained in:
congzhou09
2026-03-04 19:38:09 +08:00
committed by GitHub
parent 11bc333714
commit e31cca3354

View File

@@ -107,15 +107,15 @@ export abstract class GfxBlockComponent<
getCSSTransform() { getCSSTransform() {
const viewport = this.gfx.viewport; const viewport = this.gfx.viewport;
const { translateX, translateY, zoom } = viewport; const { translateX, translateY, zoom, viewScale } = viewport;
const bound = Bound.deserialize(this.model.xywh); const bound = Bound.deserialize(this.model.xywh);
const scaledX = bound.x * zoom; const scaledX = (bound.x * zoom) / viewScale;
const scaledY = bound.y * zoom; const scaledY = (bound.y * zoom) / viewScale;
const deltaX = scaledX - bound.x; const deltaX = scaledX - bound.x;
const deltaY = scaledY - bound.y; const deltaY = scaledY - bound.y;
return `translate(${translateX + deltaX}px, ${translateY + deltaY}px) scale(${zoom})`; return `translate(${translateX / viewScale + deltaX}px, ${translateY / viewScale + deltaY}px) scale(${zoom / viewScale})`;
} }
getRenderingRect() { getRenderingRect() {
@@ -219,18 +219,8 @@ export function toGfxBlockComponent<
handleGfxConnection(this); handleGfxConnection(this);
} }
// eslint-disable-next-line sonarjs/no-identical-functions
getCSSTransform() { getCSSTransform() {
const viewport = this.gfx.viewport; return GfxBlockComponent.prototype.getCSSTransform.call(this);
const { translateX, translateY, zoom } = viewport;
const bound = Bound.deserialize(this.model.xywh);
const scaledX = bound.x * zoom;
const scaledY = bound.y * zoom;
const deltaX = scaledX - bound.x;
const deltaY = scaledY - bound.y;
return `translate(${translateX + deltaX}px, ${translateY + deltaY}px) scale(${zoom})`;
} }
// eslint-disable-next-line sonarjs/no-identical-functions // eslint-disable-next-line sonarjs/no-identical-functions