Files
AFFiNE-Mirror/blocksuite/affine/gfx/group/src/renderer/utils.ts
T
L-Sun 680f3b3006 feat(editor): impl shape text with dom renderer (#13471)
#### PR Dependency Tree


* **PR #13464**
  * **PR #13465**
    * **PR #13471** 👈
      * **PR #13472**
        * **PR #13473**

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

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

* **New Features**
* DOM rendering added for groups, mind maps and connectors so group
titles/outlines and mindmap connectors are visible on canvas.
* Shapes now support right-to-left text with proper vertical alignment.
* **Improvements**
  * Connector labels scale with viewport zoom for crisper display.
* Group-related selections (including nested groups) now update visuals
consistently.
* **Performance**
* Reduced DOM churn and fewer redraws during rendering and selection
changes.
* **Refactor**
* Renderer import/export surfaces consolidated with no user-facing
behavior changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-14 04:29:13 +00:00

78 lines
1.9 KiB
TypeScript

import {
getFontString,
getLineHeight,
getLineWidth,
truncateTextByWidth,
} from '@blocksuite/affine-gfx-text';
import type { GroupElementModel } from '@blocksuite/affine-model';
import { FontWeight } from '@blocksuite/affine-model';
import { Bound } from '@blocksuite/global/gfx';
import {
GROUP_TITLE_FONT,
GROUP_TITLE_FONT_SIZE,
GROUP_TITLE_OFFSET,
GROUP_TITLE_PADDING,
} from './consts';
export function titleRenderParams(group: GroupElementModel, zoom: number) {
let text = group.title.toString().trim();
const font = getGroupTitleFont(zoom);
const lineWidth = getLineWidth(text, font);
const lineHeight = getLineHeight(
GROUP_TITLE_FONT,
GROUP_TITLE_FONT_SIZE / zoom,
'normal'
);
const bound = group.elementBound;
const padding = [
GROUP_TITLE_PADDING[0] / zoom,
GROUP_TITLE_PADDING[1] / zoom,
];
const offset = GROUP_TITLE_OFFSET / zoom;
let titleWidth = lineWidth + padding[0] * 2;
const titleHeight = lineHeight + padding[1] * 2;
if (titleWidth > bound.w) {
text = truncateTextByWidth(text, font, bound.w - 10);
text = text.slice(0, text.length - 1) + '..';
titleWidth = bound.w;
}
return {
font,
bound,
text,
titleWidth,
titleHeight,
offset,
lineHeight,
padding,
titleBound: new Bound(
bound.x,
bound.y - titleHeight - offset,
titleWidth,
titleHeight
),
};
}
export function titleBound(group: GroupElementModel, zoom: number) {
const { titleWidth, titleHeight, bound } = titleRenderParams(group, zoom);
return new Bound(bound.x, bound.y - titleHeight, titleWidth, titleHeight);
}
function getGroupTitleFont(zoom: number) {
const fontSize = GROUP_TITLE_FONT_SIZE / zoom;
const font = getFontString({
fontSize,
fontFamily: GROUP_TITLE_FONT,
fontWeight: FontWeight.Regular,
fontStyle: 'normal',
});
return font;
}