Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(edgeless): edgeless related api #5972

Merged
merged 52 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
2a94340
fix: add model renderer
doouding Jan 8, 2024
7e6a73f
fix: remove batch
doouding Jan 8, 2024
4515d16
fix: remove batch
doouding Jan 8, 2024
d221061
fix: remove batch
doouding Jan 8, 2024
6ead01f
fix: cleanup
doouding Jan 9, 2024
4e8aec6
fix: remove surface block methods
doouding Jan 10, 2024
1d4dcea
Merge branch 'master' into refactor/surface
doouding Jan 10, 2024
2d2bdbf
refactor: remove group manager
doouding Jan 10, 2024
b0e6c16
refactor: remove connector
doouding Jan 11, 2024
c22be2b
fix: build
doouding Jan 11, 2024
e2a5b7e
refactor: viewport
doouding Jan 12, 2024
bfa38d4
fix: type
doouding Jan 12, 2024
667b01f
fix: rendering
doouding Jan 15, 2024
6ba052b
fix: completely remove original element model
doouding Jan 16, 2024
0bfad29
fix: build & remove element
doouding Jan 16, 2024
2b07b1d
Merge branch 'master' into refactor/surface
doouding Jan 16, 2024
4882478
fix: build
doouding Jan 16, 2024
eaa25bc
fix: integration test
doouding Jan 17, 2024
026d7f3
fix: unit test
doouding Jan 17, 2024
caacd34
fix: remove unused slot
doouding Jan 17, 2024
9208710
fix: remove unused slot
doouding Jan 17, 2024
0b234a9
Merge branch 'master' into refactor/surface
doouding Jan 17, 2024
40e88eb
fix: build
doouding Jan 17, 2024
0ed064a
fix: circular
doouding Jan 17, 2024
512f968
fix: unit test
doouding Jan 17, 2024
6b51680
fix: connector
doouding Jan 17, 2024
f32d4d8
fix: surface service
doouding Jan 17, 2024
e0dbee2
fix: surface page service
doouding Jan 17, 2024
688d78a
fix(edgeless): error
doouding Jan 17, 2024
85bc41d
fix: over rerendering
doouding Jan 18, 2024
c22c7d1
Merge branch 'master' into refactor/surface
doouding Jan 18, 2024
ff3d2d5
fix: test
doouding Jan 18, 2024
713a314
fix: component-toolbar
doouding Jan 18, 2024
911ab14
Merge branch 'master' into refactor/surface
doouding Jan 18, 2024
8aca3c7
fix: initFieldObserver
doouding Jan 18, 2024
b3c7db5
fix: group
doouding Jan 18, 2024
91851f3
fix: derive
doouding Jan 18, 2024
1cf3f10
Merge branch 'master' into refactor/surface
doouding Jan 18, 2024
97d182f
fix: dervie
doouding Jan 18, 2024
bb2d2d3
fix: test
doouding Jan 18, 2024
bc9b315
fix: bound
doouding Jan 18, 2024
0191ab7
chore: remove unused code
doouding Jan 18, 2024
06582c8
feat: add ModelToProps utility type
doouding Jan 19, 2024
c262d95
fix: bug
doouding Jan 19, 2024
a797db9
fix: viewport
doouding Jan 19, 2024
f1bb96e
chore: remove redundant code
doouding Jan 19, 2024
0c47357
Merge branch 'master' into refactor/surface
doouding Jan 19, 2024
fe0f795
fix: build
doouding Jan 19, 2024
4f02963
Merge branch 'master' into refactor/surface
doouding Jan 19, 2024
66c3c1b
fix: build
doouding Jan 19, 2024
6f7d23e
fix: test
doouding Jan 19, 2024
3a428dd
fix: test
doouding Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ export class EmbedCardCreateModal extends WithDisposable(ShadowlessElement) {
assertExists(edgelessPageElement);

const surface = edgelessPageElement.surface;
const center = Vec.toVec(surface.viewport.center);
surface.addElement(
const center = Vec.toVec(surface.renderer.center);
edgelessPageElement.service.addBlock(
flavour as EdgelessElementType,
{
url,
Expand Down
110 changes: 16 additions & 94 deletions packages/blocks/src/_common/edgeless/mixin/edgeless-selectable.ts
Original file line number Diff line number Diff line change
@@ -1,114 +1,36 @@
import type { Constructor } from '@blocksuite/global/utils';
import type { BlockModel } from '@blocksuite/store';
import { BlockModel } from '@blocksuite/store';

import type { SurfaceBlockModel } from '../../../models.js';
import { BLOCK_BATCH } from '../../../surface-block/batch.js';
import {
Bound,
getBoundsWithRotation,
getPointsFromBoundsWithRotation,
type IEdgelessElement,
type IVec,
linePolygonIntersects,
PointLocation,
polygonGetPointTangent,
polygonNearestPoint,
rotatePoints,
type SerializedXYWH,
} from '../../../surface-block/index.js';
import { EdgelessBlockModel } from '../../../page-block/edgeless/type.js';
import { type SerializedXYWH } from '../../../surface-block/index.js';

export type EdgelessSelectableProps = {
xywh: SerializedXYWH;
index: string;
rotate?: number;
};

export function selectable<
Props extends EdgelessSelectableProps,
T extends Constructor<BlockModel<Props>> = Constructor<BlockModel<Props>>,
>(SuperClass: T) {
class DerivedSelectableInEdgelessClass
extends SuperClass
implements IEdgelessElement
{
connectable = true;
batch = BLOCK_BATCH;
override rotate = 0;
if (SuperClass === BlockModel) {
return EdgelessBlockModel as unknown as typeof EdgelessBlockModel<Props>;
} else {
let currentClass = SuperClass;

get elementBound() {
const bound = Bound.deserialize(this.xywh);
return Bound.from(
getBoundsWithRotation({ ...bound, rotate: this.rotate })
);
while (
Object.getPrototypeOf(currentClass.prototype) !== BlockModel.prototype &&
Object.getPrototypeOf(currentClass.prototype) !== null
) {
currentClass = Object.getPrototypeOf(currentClass.prototype).constructor;
}

hitTest(x: number, y: number): boolean {
const bound = Bound.deserialize(this.xywh);
return bound.isPointInBound([x, y], 0);
if (Object.getPrototypeOf(currentClass.prototype) === null) {
throw new Error('The SuperClass is not a subclass of BlockModel');
}

containedByBounds(bounds: Bound): boolean {
const bound = Bound.deserialize(this.xywh);
const points = getPointsFromBoundsWithRotation({
x: bound.x,
y: bound.y,
w: bound.w,
h: bound.h,
rotate: this.rotate,
});
return points.some(point => bounds.containsPoint(point));
}

getNearestPoint(point: IVec): IVec {
const bound = Bound.deserialize(this.xywh);
return polygonNearestPoint(
rotatePoints(bound.points, bound.center, this.rotate ?? 0),
point
);
}

intersectWithLine(start: IVec, end: IVec): PointLocation[] | null {
const bound = Bound.deserialize(this.xywh);
return linePolygonIntersects(
start,
end,
rotatePoints(bound.points, bound.center, this.rotate ?? 0)
);
}

getRelativePointLocation(relativePoint: IVec): PointLocation {
const bound = Bound.deserialize(this.xywh);
const point = bound.getRelativePoint(relativePoint);
const rotatePoint = rotatePoints(
[point],
bound.center,
this.rotate ?? 0
)[0];
const points = rotatePoints(bound.points, bound.center, this.rotate ?? 0);
const tangent = polygonGetPointTangent(points, rotatePoint);

return new PointLocation(rotatePoint, tangent);
}

boxSelect(bound: Bound): boolean {
return (
this.containedByBounds(bound) ||
bound.points.some((point, i, points) =>
this.intersectWithLine(point, points[(i + 1) % points.length])
)
);
}

get group() {
const surfaceModel = this.page.getBlockByFlavour(
'affine:surface'
) as SurfaceBlockModel[];

return surfaceModel[0]?.getGroup(this.id) ?? null;
}
Object.setPrototypeOf(currentClass.prototype, EdgelessBlockModel.prototype);
}

return DerivedSelectableInEdgelessClass as Constructor<
BlockModel<Props> & IEdgelessElement
>;
return SuperClass as unknown as typeof EdgelessBlockModel<Props>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,19 @@ export class EmbedBlockElement<
return this._isInSurface;
}

get edgeless() {
if (this._isInSurface) return null;
return this.host.querySelector('affine-edgeless-page');
}

get surface() {
if (!this.isInSurface) return null;
return this.host.querySelector('affine-surface');
}

get bound(): Bound {
return Bound.deserialize(
(this.surface?.pickById(this.model.id) ?? this.model).xywh
(this.edgeless?.service.getElementById(this.model.id) ?? this.model).xywh
);
}

Expand Down Expand Up @@ -188,7 +193,7 @@ export class EmbedBlockElement<
const width = this._width;
const height = this._height;
const bound = Bound.deserialize(
(surface.pickById(this.model.id) ?? this.model).xywh
(this.edgeless?.service.getElementById(this.model.id) ?? this.model).xywh
);
const scaleX = bound.w / width;
const scaleY = bound.h / height;
Expand Down
2 changes: 1 addition & 1 deletion packages/blocks/src/_common/embed-block-helper/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function createEmbedBlock<
xywh: '[0,0,0,0]',
rotate: 0,
...(userProps || {}),
} as EmbedProps<Props>;
} as unknown as EmbedProps<Props>;
},
metadata: {
version: schema.version,
Expand Down
13 changes: 7 additions & 6 deletions packages/blocks/src/_common/export-manager/export-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {
getPageByEditorHost,
isInsideDocEditor,
matchFlavours,
type TopLevelBlockModel,
} from '../../_common/utils/index.js';
import type { PageBlockModel } from '../../models.js';
import type { EdgelessPageBlockComponent } from '../../page-block/edgeless/edgeless-page-block.js';
import { getBlocksInFrame } from '../../page-block/edgeless/frame-manager.js';
import type { EdgelessBlockModel } from '../../page-block/edgeless/type.js';
import { xywhArrayToObject } from '../../page-block/edgeless/utils/convert.js';
import { getBackgroundGrid } from '../../page-block/edgeless/utils/query.js';
import type { IBound } from '../../surface-block/consts.js';
import type { SurfaceElement } from '../../surface-block/elements/surface-element.js';
import type { ElementModel } from '../../surface-block/element-model/index.js';
import type { Renderer } from '../../surface-block/index.js';
import { Bound } from '../../surface-block/utils/bound.js';
import { FileExporter } from './file-exporter.js';
Expand Down Expand Up @@ -186,8 +186,8 @@ export class ExportManager {
bound: IBound,
blockElementGetter: (model: BlockModel) => Element | null = () => null,
edgeless?: EdgelessPageBlockComponent,
nodes?: TopLevelBlockModel[],
surfaces?: SurfaceElement[],
nodes?: EdgelessBlockModel[],
surfaces?: ElementModel[],
edgelessBackground?: {
zoom: number;
}
Expand Down Expand Up @@ -231,7 +231,8 @@ export class ExportManager {
}

// TODO: refactor of this part
const blocks = nodes ?? edgeless?.getSortedElementsByBound(bound) ?? [];
const blocks =
nodes ?? edgeless?.service.pickElementsByBound(bound, 'blocks') ?? [];
for (const block of blocks) {
if (matchFlavours(block, ['affine:image'])) {
if (!block.sourceId) return;
Expand Down Expand Up @@ -430,7 +431,7 @@ export class ExportManager {
const bound = edgeless.getElementsBound();
assertExists(bound);
return await this.edgelessToCanvas(
edgeless.surface.viewport,
edgeless.surface.renderer,
bound,
(model: BlockModel) => blockElementGetter(model, this.editorHost.view),
edgeless
Expand Down
23 changes: 15 additions & 8 deletions packages/blocks/src/_common/mind-map/draw.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Workspace } from '@blocksuite/store';

import { getFontString } from '../../surface-block/canvas-renderer/element-renderer/text/utils.js';
import type { ShapeElementModel } from '../../surface-block/index.js';
import {
Bound,
CanvasElementType,
Expand All @@ -10,7 +12,6 @@ import {
type IShape,
normalizeShapeBound,
SHAPE_TEXT_PADDING,
type ShapeElement,
ShapeStyle,
type ShapeType,
StrokeStyle,
Expand Down Expand Up @@ -70,15 +71,18 @@ const drawAllNode = (node: TreeNode, surface: SurfaceBlockComponent) => {
};
const drawNode = (node: TreeNode): LayoutNode_ => {
const { text, children } = node;
const id = surface.addElement(CanvasElementType.SHAPE, {
const service = surface.edgeless.service;
const id = service.addElement(CanvasElementType.SHAPE, {
...DEFAULT_SHAPE_PROPS,
xywh: `[${0},${0},${0},${0}]`,
text: new Workspace.Y.Text(text),
});
shapeIds.push(id);
const ele = surface.pickById(id) as ShapeElement;
const ele = service.getElementById(id) as ShapeElementModel;
const maxWidth =
Math.max(...text.split('\n').map(line => getLineWidth(line, ele.font))) +
Math.max(
...text.split('\n').map(line => getLineWidth(line, getFontString(ele)))
) +
SHAPE_TEXT_PADDING * 2;
const bound = normalizeShapeBound(
ele,
Expand All @@ -103,15 +107,17 @@ const drawAllNode = (node: TreeNode, surface: SurfaceBlockComponent) => {
const updatePosition = (node: LayoutNode_, result: LayoutNodeResult) => {
const { id, width, height } = node;
const { x, y } = result.self;
surface.updateElement(id, {
const service = surface.edgeless.service;

service.updateElement(id, {
xywh: `[${x},${y},${width},${height}]`,
});
node.children.forEach((child, index) => {
const layoutNodeResult = result.children[index];
updatePosition(child, layoutNodeResult);
if (layoutNodeResult.connector) {
const direction = directionMap[layoutNodeResult.connector.direction];
const connectorId = surface.addElement(CanvasElementType.CONNECTOR, {
const connectorId = service.addElement(CanvasElementType.CONNECTOR, {
...DEFAULT_CONNECTOR_PROPS,
source: {
id: id,
Expand All @@ -135,9 +141,10 @@ export function drawMindMap(
) {
const { shapeIds, connectorIds } = drawAllNode(mindMap, surfaceElement);
const { edgeless } = surfaceElement;
edgeless.selectionManager.set({

edgeless.service.selection.set({
elements: [...shapeIds, ...connectorIds],
editing: false,
});
surfaceElement.group.createGroupOnSelected();
surfaceElement.edgeless.service.createGroupFromSelected();
}
16 changes: 15 additions & 1 deletion packages/blocks/src/_common/theme/theme-observer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Slot } from '@blocksuite/global/utils';

import type { CssVariablesMap } from './css-variables.js';
import { StyleVariables } from './css-variables.js';
import { isCssVariable, StyleVariables } from './css-variables.js';

export function extractCssVariables(element: Element): CssVariablesMap {
const styles = window.getComputedStyle(element);
Expand Down Expand Up @@ -48,6 +48,20 @@ export class ThemeObserver extends Slot<CssVariablesMap> {
});
}

getVariableValue(variable: string) {
if (isCssVariable(variable)) {
const value = this._cssVariables?.[variable];

if (value === undefined) {
console.error(new Error(`Cannot find css variable: ${variable}`));
} else {
return value;
}
}

return variable;
}

override dispose() {
super.dispose();
this._observer?.disconnect();
Expand Down
22 changes: 13 additions & 9 deletions packages/blocks/src/_common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import type { FrameBlockModel } from '../frame-block/index.js';
import type { ImageBlockModel } from '../image-block/index.js';
import type { BookmarkBlockModel } from '../models.js';
import type { NoteBlockModel } from '../note-block/index.js';
import {
type BrushElement,
type CanvasElement,
type ConnectorElement,
type ConnectorMode,
type GroupElement,
} from '../surface-block/elements/index.js';
import type { EdgelessElement } from '../page-block/edgeless/type.js';
import type { ConnectorMode } from '../surface-block/element-model/connector.js';
import type {
BrushElementModel,
ConnectorElementModel,
GroupElementModel,
} from '../surface-block/element-model/index.js';
import { type CanvasElement } from '../surface-block/element-model/index.js';
import type { ShapeType } from '../surface-block/index.js';
import type { NavigatorMode } from './edgeless/frame/consts.js';
import type { RefNodeSlots } from './inline/presets/nodes/reference-node/reference-node.js';
Expand Down Expand Up @@ -129,7 +130,7 @@ export type TopLevelBlockModel =
| EmbedFigmaModel
| EmbedLinkedDocModel;

export type EdgelessElement = TopLevelBlockModel | CanvasElement;
export type { EdgelessElement };

export type Alignable = EdgelessElement;

Expand All @@ -139,7 +140,10 @@ export type Erasable = EdgelessElement;

export type Connectable =
| TopLevelBlockModel
| Exclude<CanvasElement, ConnectorElement | BrushElement | GroupElement>;
| Exclude<
CanvasElement,
ConnectorElementModel | BrushElementModel | GroupElementModel
>;

export type DefaultTool = {
type: 'default';
Expand Down
4 changes: 4 additions & 0 deletions packages/blocks/src/_common/utils/iterable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ export function keys<T>(obj: T): (keyof T)[] {
return Object.keys(obj as object) as (keyof T)[];
}

export function values<T>(obj: T): T[keyof T][] {
return Object.values(obj as object);
}

type IterableType<T> = T extends Array<infer U> ? U : T;

export function last<T extends Iterable<unknown>>(
Expand Down
Loading
Loading