Skip to content

Commit

Permalink
feat(draw): GeometryComponent support multi text #WIK-15441 (#870)
Browse files Browse the repository at this point in the history
  • Loading branch information
MissLixf authored May 14, 2024
1 parent ea97097 commit 866ca87
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .changeset/six-mirrors-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@plait/draw': minor
---

GeometryComponent support multi text
39 changes: 39 additions & 0 deletions packages/draw/src/generators/single-text.generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { PlaitBoard, PlaitElement } from '@plait/core';
import { ParagraphElement } from '@plait/text';
import { PlaitCommonGeometry, PlaitGeometry } from '../interfaces';
import { ViewContainerRef } from '@angular/core';
import { PlaitDrawShapeText, TextGenerator, TextGeneratorOptions } from './text.generator';
import { isMultipleTextGeometry } from '../utils';

export class SingleTextGenerator<T extends PlaitElement = PlaitGeometry> extends TextGenerator<T> {
get textManage() {
return this.textManages[0];
}

constructor(board: PlaitBoard, element: T, text: ParagraphElement, viewContainerRef: ViewContainerRef, options: TextGeneratorOptions) {
super(board, element, [{ key: element.shape, text: text, textHeight: element.textHeight }], viewContainerRef, options);
}

update(
element: T,
previousDrawShapeTexts: PlaitDrawShapeText[],
currentDrawShapeTexts: PlaitDrawShapeText[],
elementG: SVGElement
): void;
update(element: T, previousText: ParagraphElement, currentText: ParagraphElement, elementG: SVGElement): void;
update(
element: T,
previousText: ParagraphElement | PlaitDrawShapeText[],
currentText: ParagraphElement | PlaitDrawShapeText[],
elementG: SVGElement
) {
if (!isMultipleTextGeometry((element as unknown) as PlaitCommonGeometry)) {
super.update(
element,
[{ text: previousText as ParagraphElement, key: element.shape, textHeight: element.textHeight }],
[{ text: currentText as ParagraphElement, key: element.shape, textHeight: element.textHeight }],
elementG
);
}
}
}
4 changes: 2 additions & 2 deletions packages/draw/src/generators/text.generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class TextGenerator<T extends PlaitElement = PlaitGeometry> {
if (drawShapeText.text) {
textManage.draw(drawShapeText.text);
elementG.append(textManage.g);
this.element.angle ?? textManage.updateAngle(centerPoint, this.element.angle);
this.element.angle && textManage.updateAngle(centerPoint, this.element.angle);
}
});
}
Expand All @@ -74,7 +74,7 @@ export class TextGenerator<T extends PlaitElement = PlaitGeometry> {
if (drawShapeText.text) {
textManage.updateText(drawShapeText.text);
textManage.updateRectangle();
this.element.angle ?? textManage.updateAngle(centerPoint, this.element.angle);
this.element.angle && textManage.updateAngle(centerPoint, this.element.angle);
}
});
}
Expand Down
140 changes: 73 additions & 67 deletions packages/draw/src/geometry.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,44 @@ import {
OnContextChanged,
isSelectionMoving,
getSelectedElements,
PlaitOptionsBoard,
ACTIVE_STROKE_WIDTH,
RectangleClient
} from '@plait/core';
import { Subject } from 'rxjs';
import { PlaitGeometry } from './interfaces/geometry';
import { PlaitCommonGeometry, PlaitGeometry, PlaitMultipleTextGeometry } from './interfaces/geometry';
import { GeometryShapeGenerator } from './generators/geometry-shape.generator';
import { TextManage, TextManageRef } from '@plait/text';
import { TextManageRef } from '@plait/text';
import { DrawTransforms } from './transforms';
import { ActiveGenerator, WithTextPluginKey, WithTextOptions, CommonPluginElement, canResize } from '@plait/common';
import { GeometryThreshold } from './constants/geometry';
import { PlaitText } from './interfaces';
import { getEngine } from './engines';
import { ActiveGenerator, CommonPluginElement, canResize } from '@plait/common';
import { LineAutoCompleteGenerator } from './generators/line-auto-complete.generator';
import { memorizeLatestText } from './utils';
import { getTextRectangle } from './utils/common';
import { isMultipleTextGeometry, memorizeLatestText } from './utils';
import { TextGenerator } from './generators/text.generator';
import { SingleTextGenerator } from './generators/single-text.generator';

@Component({
selector: 'plait-draw-geometry',
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true
})
export class GeometryComponent extends CommonPluginElement<PlaitGeometry, PlaitBoard>
implements OnInit, OnDestroy, OnContextChanged<PlaitGeometry, PlaitBoard> {
export class GeometryComponent extends CommonPluginElement<PlaitCommonGeometry, PlaitBoard>
implements OnInit, OnDestroy, OnContextChanged<PlaitCommonGeometry, PlaitBoard> {
destroy$ = new Subject<void>();

activeGenerator!: ActiveGenerator<PlaitGeometry>;
activeGenerator!: ActiveGenerator<PlaitCommonGeometry>;

lineAutoCompleteGenerator!: LineAutoCompleteGenerator;

shapeGenerator!: GeometryShapeGenerator;

get textManage() {
return this.getTextManages()[0];
}
textGenerator!: TextGenerator<PlaitMultipleTextGeometry> | SingleTextGenerator;

constructor() {
super();
}

initializeGenerator() {
this.activeGenerator = new ActiveGenerator<PlaitGeometry>(this.board, {
this.activeGenerator = new ActiveGenerator<PlaitCommonGeometry>(this.board, {
getStrokeWidth: () => {
const selectedElements = getSelectedElements(this.board);
if (selectedElements.length === 1 && !isSelectionMoving(this.board)) {
Expand All @@ -64,7 +59,7 @@ export class GeometryComponent extends CommonPluginElement<PlaitGeometry, PlaitB
return 0.5;
}
},
getRectangle: (element: PlaitGeometry) => {
getRectangle: (element: PlaitCommonGeometry) => {
return RectangleClient.getRectangleByPoints(element.points);
},
hasResizeHandle: () => {
Expand All @@ -81,85 +76,95 @@ export class GeometryComponent extends CommonPluginElement<PlaitGeometry, PlaitB
ngOnInit(): void {
super.ngOnInit();
this.initializeGenerator();
this.shapeGenerator.processDrawing(this.element, this.getElementG());
this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
this.shapeGenerator.processDrawing(this.element as PlaitGeometry, this.getElementG());
this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
selected: this.selected
});
this.lineAutoCompleteGenerator.processDrawing(this.element as PlaitGeometry, PlaitBoard.getElementActiveHost(this.board), {
selected: this.selected
});
this.drawText();
this.textGenerator.draw(this.getElementG());
}

onContextChanged(
value: PlaitPluginElementContext<PlaitGeometry, PlaitBoard>,
previous: PlaitPluginElementContext<PlaitGeometry, PlaitBoard>
value: PlaitPluginElementContext<PlaitCommonGeometry, PlaitBoard>,
previous: PlaitPluginElementContext<PlaitCommonGeometry, PlaitBoard>
) {
this.initializeWeakMap();
const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
if (value.element !== previous.element || isChangeTheme) {
this.shapeGenerator.processDrawing(this.element, this.getElementG());
this.shapeGenerator.processDrawing(this.element as PlaitGeometry, this.getElementG());
this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
this.lineAutoCompleteGenerator.processDrawing(this.element as PlaitGeometry, PlaitBoard.getElementActiveHost(this.board), {
selected: this.selected
});
this.updateText();
this.updateText(previous.element, value.element);
} else {
const hasSameSelected = value.selected === previous.selected;
const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
if (!hasSameSelected || !hasSameHandleState) {
this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
this.lineAutoCompleteGenerator.processDrawing(this.element as PlaitGeometry, PlaitBoard.getElementActiveHost(this.board), {
selected: this.selected
});
}
}
}

drawText() {
this.textManage.draw(this.element.text);
this.getElementG().append(this.textManage.g);
const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);
this.textManage.updateAngle(centerPoint, this.element.angle);
}

updateText() {
this.textManage.updateText(this.element.text);
this.textManage.updateRectangle();
const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);
this.textManage.updateAngle(centerPoint, this.element.angle);
updateText(previousElement: PlaitCommonGeometry, currentElement: PlaitCommonGeometry) {
if (isMultipleTextGeometry(this.element)) {
(this.textGenerator as TextGenerator<PlaitMultipleTextGeometry>).update(
this.element,
previousElement.texts,
currentElement.texts,
this.getElementG()
);
} else {
(this.textGenerator as SingleTextGenerator).update(
this.element as PlaitGeometry,
previousElement.text,
currentElement.text,
this.getElementG()
);
}
}

initializeTextManage() {
const plugins = ((this.board as PlaitOptionsBoard).getPluginOptions<WithTextOptions>(WithTextPluginKey) || {}).textPlugins;
const onTextValueChangeHandle = (textManageRef: TextManageRef) => {
const height = textManageRef.height / this.board.viewport.zoom;
const width = textManageRef.width / this.board.viewport.zoom;
if (textManageRef.newValue) {
DrawTransforms.setText(this.board, this.element as PlaitGeometry, textManageRef.newValue, width, height);
} else {
DrawTransforms.setTextSize(this.board, this.element as PlaitGeometry, width, height);
}
textManageRef.operations && memorizeLatestText(this.element, textManageRef.operations);
};

const manage = new TextManage(this.board, this.viewContainerRef, {
getRectangle: () => {
const getRectangle = getEngine(this.element.shape).getTextRectangle;
if (getRectangle) {
return getRectangle(this.element);
if (isMultipleTextGeometry(this.element)) {
this.textGenerator = new TextGenerator<PlaitMultipleTextGeometry>(
this.board,
this.element as PlaitMultipleTextGeometry,
this.element.texts!,
this.viewContainerRef,
{
onValueChangeHandle: onTextValueChangeHandle
}
return getTextRectangle(this.element);
},
onValueChangeHandle: (textManageRef: TextManageRef) => {
const height = textManageRef.height / this.board.viewport.zoom;
const width = textManageRef.width / this.board.viewport.zoom;
if (textManageRef.newValue) {
DrawTransforms.setText(this.board, this.element, textManageRef.newValue, width, height);
} else {
DrawTransforms.setTextSize(this.board, this.element, width, height);
}
textManageRef.operations && memorizeLatestText(this.element, textManageRef.operations);
},
getMaxWidth: () => {
let width = getTextRectangle(this.element).width;
const getRectangle = getEngine(this.element.shape).getTextRectangle;
if (getRectangle) {
width = getRectangle(this.element).width;
);
} else {
this.textGenerator = new SingleTextGenerator(
this.board,
this.element as PlaitGeometry,
this.element.text,
this.viewContainerRef,
{
onValueChangeHandle: onTextValueChangeHandle
}
return (this.element as PlaitText)?.autoSize ? GeometryThreshold.defaultTextMaxWidth : width;
},
textPlugins: plugins
});
this.initializeTextManages([manage]);
);
}

this.textGenerator.initialize();
this.initializeTextManages(this.textGenerator.textManages);
}

ngOnDestroy(): void {
Expand All @@ -168,6 +173,7 @@ export class GeometryComponent extends CommonPluginElement<PlaitGeometry, PlaitB
this.destroy$.complete();
this.activeGenerator.destroy();
this.lineAutoCompleteGenerator.destroy();
this.textGenerator.destroy();
this.destroyTextManages();
}
}
15 changes: 11 additions & 4 deletions packages/draw/src/interfaces/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PlaitElement, Point } from '@plait/core';
import { ParagraphElement } from '@plait/text';
import { StrokeStyle } from './element';
import { PlaitTable } from './table';
import { PlaitDrawShapeText } from '../generators/text.generator';

export enum BasicShapes {
rectangle = 'rectangle',
Expand Down Expand Up @@ -65,14 +66,11 @@ export enum SwimlaneSymbols {

export type GeometryShapes = BasicShapes | FlowchartSymbols | SwimlaneSymbols;

export interface PlaitGeometry extends PlaitElement {
export interface PlaitCommonGeometry extends PlaitElement {
points: [Point, Point];
type: 'geometry';
shape: GeometryShapes;

text: ParagraphElement;
textHeight: number;

// node style attributes
fill?: string;
strokeColor?: string;
Expand All @@ -83,6 +81,15 @@ export interface PlaitGeometry extends PlaitElement {
opacity: number;
}

export interface PlaitMultipleTextGeometry extends PlaitCommonGeometry {
texts?: PlaitDrawShapeText[];
}

export interface PlaitGeometry extends PlaitCommonGeometry {
text: ParagraphElement;
textHeight: number;
}

export interface PlaitRectangle extends PlaitGeometry {
shape: BasicShapes.rectangle;
}
Expand Down
6 changes: 5 additions & 1 deletion packages/draw/src/utils/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
getSelectedElements,
idCreator
} from '@plait/core';
import { GeometryShapes, BasicShapes, PlaitGeometry, FlowchartSymbols } from '../interfaces/geometry';
import { GeometryShapes, BasicShapes, PlaitGeometry, FlowchartSymbols, PlaitMultipleTextGeometry } from '../interfaces/geometry';
import { Alignment, CustomText, DEFAULT_FONT_SIZE, buildText, getTextSize } from '@plait/text';
import { Element } from 'slate';
import {
Expand Down Expand Up @@ -376,3 +376,7 @@ export const rerenderGeometryActive = (board: PlaitBoard, element: PlaitGeometry
const selected = getSelectedElements(board).includes(element);
activeGenerator.processDrawing(element, PlaitBoard.getElementActiveHost(board), { selected });
};

export const isMultipleTextGeometry = (geometry: PlaitGeometry | PlaitMultipleTextGeometry): geometry is PlaitMultipleTextGeometry => {
return !!geometry.texts;
};

0 comments on commit 866ca87

Please sign in to comment.