Skip to content

Commit

Permalink
feat: add basic button render
Browse files Browse the repository at this point in the history
  • Loading branch information
doouding committed Dec 9, 2024
1 parent b204cec commit ca1ac30
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,7 @@ export function mindmap(
ctx.globalAlpha = origin;
}
}
});

model.extraConnectors.forEach(connector => {
const dx = connector.x - bound.x;
const dy = connector.y - bound.y;

renderConnector(connector, ctx, matrix.translate(dx, dy), renderer, rc);
model.getCollapseButton(to);
});
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { ShapeElementModel } from '@blocksuite/affine-model';
import type {
LocalShapeElementModel,
ShapeElementModel,
} from '@blocksuite/affine-model';

import type { RoughCanvas } from '../../../utils/rough/canvas.js';
import type { CanvasRenderer } from '../../canvas-renderer.js';

import { type Colors, drawGeneralShape } from './utils.js';

export function diamond(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { ShapeElementModel } from '@blocksuite/affine-model';
import type {
LocalShapeElementModel,
ShapeElementModel,
} from '@blocksuite/affine-model';

import type { RoughCanvas } from '../../../utils/rough/canvas.js';
import type { CanvasRenderer } from '../../canvas-renderer.js';

import { type Colors, drawGeneralShape } from './utils.js';

export function ellipse(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand Down
19 changes: 12 additions & 7 deletions packages/affine/block-surface/src/renderer/elements/shape/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { ShapeElementModel, ShapeType } from '@blocksuite/affine-model';
import type {
LocalShapeElementModel,
ShapeElementModel,
ShapeType,
} from '@blocksuite/affine-model';
import type { IBound } from '@blocksuite/global/utils';

import {
Expand Down Expand Up @@ -30,7 +34,7 @@ import { type Colors, horizontalOffset, verticalOffset } from './utils.js';
const shapeRenderers: Record<
ShapeType,
(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand All @@ -45,7 +49,7 @@ const shapeRenderers: Record<
};

export function shape(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand Down Expand Up @@ -76,7 +80,7 @@ export function shape(
}

function renderText(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
{ color }: Colors
) {
Expand All @@ -103,9 +107,10 @@ function renderText(
fontWeight
);
const metrics = getFontMetrics(fontFamily, fontSize, fontWeight);
const lines = deltaInsertsToChunks(
wrapTextDeltas(text, font, w - horPadding * 2)
);
const lines =
typeof text === 'string'
? [text.split('\n').map(line => ({ insert: line }))]
: deltaInsertsToChunks(wrapTextDeltas(text, font, w - horPadding * 2));
const horOffset = horizontalOffset(model.w, model.textAlign, horPadding);
const vertOffset =
verticalOffset(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { ShapeElementModel } from '@blocksuite/affine-model';
import type {
LocalShapeElementModel,
ShapeElementModel,
} from '@blocksuite/affine-model';

import type { RoughCanvas } from '../../../utils/rough/canvas.js';
import type { CanvasRenderer } from '../../canvas-renderer.js';
Expand All @@ -11,7 +14,7 @@ import { type Colors, drawGeneralShape } from './utils.js';
const K_RECT = 1 - 0.5522847498;

export function rect(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { ShapeElementModel } from '@blocksuite/affine-model';
import type {
LocalShapeElementModel,
ShapeElementModel,
} from '@blocksuite/affine-model';

import type { RoughCanvas } from '../../../utils/rough/canvas.js';
import type { CanvasRenderer } from '../../canvas-renderer.js';

import { type Colors, drawGeneralShape } from './utils.js';

export function triangle(
model: ShapeElementModel,
model: ShapeElementModel | LocalShapeElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
LocalShapeElementModel,
ShapeElementModel,
TextAlign,
TextVerticalAlign,
Expand Down Expand Up @@ -28,7 +29,7 @@ export type Colors = {

export function drawGeneralShape(
ctx: CanvasRenderingContext2D,
shapeModel: ShapeElementModel,
shapeModel: ShapeElementModel | LocalShapeElementModel,
renderer: CanvasRenderer,
filled: boolean,
fillColor: string,
Expand Down
109 changes: 92 additions & 17 deletions packages/affine/model/src/elements/mindmap/mindmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type { ConnectorStyle, MindmapStyleGetter } from './style.js';

import { LayoutType, MindmapStyle } from '../../consts/mindmap.js';
import { LocalConnectorElementModel } from '../connector/local-connector.js';
import { LocalShapeElementModel } from '../shape/shape.js';
import { mindmapStyleGetters } from './style.js';
import { findInfiniteLoop } from './utils.js';

Expand All @@ -38,6 +39,7 @@ export type NodeDetail = {
*/
index: string;
parent?: string;
collapsed?: boolean;
};

export type MindmapNode = {
Expand Down Expand Up @@ -153,9 +155,9 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement

private _tree!: MindmapRoot;

connectors = new Map<string, LocalConnectorElementModel>();
collapseButtons = new Map<string, LocalShapeElementModel>();

extraConnectors = new Map<string, LocalConnectorElementModel>();
connectors = new Map<string, LocalConnectorElementModel>();

get nodeMap() {
return this._nodeMap;
Expand Down Expand Up @@ -214,6 +216,23 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
tree.left.reverse();
}

private _isCollapseButtonOutdated(options: {
button: LocalShapeElementModel;
node: MindmapNode;
updateKey?: boolean;
}) {
const { button, node } = options;
const cacheKey = `${node.detail.collapsed ?? false}-${node.element.xywh}-${this.style}`;

if (button.cache.get('MINDMAP_COLLAPSE_BUTTON') === cacheKey) {
return false;
} else if (options.updateKey) {
button.cache.set('MINDMAP_COLLAPSE_BUTTON', cacheKey);
}

return true;
}

private _isConnectorOutdated(
options: {
connector: LocalConnectorElementModel;
Expand All @@ -226,12 +245,10 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
const { connector, from, to, layout } = options;
const cacheKey = `${from.element.xywh}-${to.element.xywh}-${layout}-${this.style}`;

// @ts-ignore
if (connector['MINDMAP_CONNECTOR'] === cacheKey) {
if (connector.cache.get('MINDMAP_CONNECTOR') === cacheKey) {
return { outdated: false, cacheKey };
} else if (updateKey) {
// @ts-ignore
connector['MINDMAP_CONNECTOR'] = cacheKey;
connector.cache.set('MINDMAP_CONNECTOR', cacheKey);
}

return { outdated: true, cacheKey };
Expand All @@ -253,17 +270,11 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
from: MindmapNode,
to: MindmapNode,
layout: LayoutType,
connectorStyle: ConnectorStyle,
extra: boolean = false
connectorStyle: ConnectorStyle
) {
const id = `#${from.id}-${to.id}`;

if (extra) {
this.extraConnectors.set(
id,
new LocalConnectorElementModel(this.surface)
);
} else if (this.connectors.has(id)) {
if (this.connectors.has(id)) {
const connector = this.connectors.get(id)!;
const { outdated } = this._isConnectorOutdated({
connector,
Expand All @@ -287,9 +298,7 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
this.connectors.set(id, connector);
}

const connector = extra
? this.extraConnectors.get(id)!
: this.connectors.get(id)!;
const connector = this.connectors.get(id)!;

connector.id = id;
connector.source = {
Expand Down Expand Up @@ -532,6 +541,72 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
return node.children;
}

getCollapseButton(node: MindmapNode) {
const id = `collapse-btn-${node.id}`;
const btnExisted = this.collapseButtons.has(id);
const collapseButton =
this.collapseButtons.get(id) || new LocalShapeElementModel(this.surface);

if (
!btnExisted ||
this._isCollapseButtonOutdated({
button: collapseButton,
node,
updateKey: true,
})
) {
const style = this.styleGetter.getNodeStyle(node, this.getPath(node));
const buttonStyle = node.detail.collapsed
? style.expandButton
: style.collapseButton;

Object.entries(buttonStyle).forEach(([key, value]) => {
if (Object.hasOwn(collapseButton, key)) {
// @ts-ignore
collapseButton[key as unknown] = value;
}
});

const nodeElementBound = node.element.elementBound;
const buttonBound = nodeElementBound.moveDelta(
6 + nodeElementBound.w,
(nodeElementBound.h - buttonStyle.height) / 2
);

buttonBound.w = buttonStyle.width;
buttonBound.h = buttonStyle.height;
collapseButton.xywh = buttonBound.serialize();
collapseButton.groupSignal.value = this.id;

Check failure on line 579 in packages/affine/model/src/elements/mindmap/mindmap.ts

View workflow job for this annotation

GitHub Actions / Build

Property 'groupSignal' does not exist on type 'LocalShapeElementModel'.
collapseButton.opacity = 0;
}

if (!btnExisted) {
this.collapseButtons.set(id, collapseButton);
this.surface.addLocalElement(collapseButton);

collapseButton.onPointerEnter = () => {
collapseButton.opacity = 1;
};
collapseButton.onPointerLeave = () => {
collapseButton.opacity = 0;
};
collapseButton.onClick = () => {
const nodeDetail = this.children.get(node.id);

if (nodeDetail) {
this.surface.doc.transact(() => {
this.children.set(node.id, {
...nodeDetail,
collapsed: nodeDetail.collapsed ? false : true,
});
});
}
};
}

return collapseButton;
}

getConnector(from: MindmapNode, to: MindmapNode) {
if (!this._nodeMap.has(from.id) || !this._nodeMap.has(to.id)) {
return null;
Expand Down
Loading

0 comments on commit ca1ac30

Please sign in to comment.