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

feat(draw): support text edit in cell #872

Merged
merged 5 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .changeset/great-suns-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@plait/draw': patch
---

support text edit in cell

add KEY_TO_TEXT_MANAGE Map
4 changes: 2 additions & 2 deletions packages/draw/src/generators/single-text.generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export class SingleTextGenerator<T extends PlaitElement = PlaitGeometry> extends
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 }],
[{ text: previousText as ParagraphElement, key: element.id, textHeight: element.textHeight }],
[{ text: currentText as ParagraphElement, key: element.id, textHeight: element.textHeight }],
elementG
);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/draw/src/generators/table.generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Generator } from '@plait/common';
import { RectangleClient } from '@plait/core';
import { PlaitTable } from '../interfaces/table';
import { getEngine } from '../engines';
import { getDrawDefaultStrokeColor } from '../utils';

export interface TableData {}

Expand All @@ -17,8 +18,8 @@ export class TableGenerator extends Generator<PlaitTable, TableData> {
this.board,
rectangle,
{
strokeWidth: 1,
stroke: '#333'
strokeWidth: 2,
stroke: getDrawDefaultStrokeColor(this.board.theme.themeColorMode),
},
{
element: element
Expand Down
33 changes: 26 additions & 7 deletions packages/draw/src/generators/text.generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ export interface TextGeneratorOptions {
onValueChangeHandle: (textChangeRef: TextManageRef, text: PlaitDrawShapeText) => void;
}

export const KEY_TO_TEXT_MANAGE: Map<string, TextManage> = new Map();

export const setTextManage = (key: string, textManage: TextManage) => {
return KEY_TO_TEXT_MANAGE.set(key, textManage);
};

export const getTextManage = (key: string) => {
return KEY_TO_TEXT_MANAGE.get(key);
};

export const deleteTextManage = (key: string) => {
return KEY_TO_TEXT_MANAGE.delete(key);
};

export class TextGenerator<T extends PlaitElement = PlaitGeometry> {
protected board: PlaitBoard;

Expand Down Expand Up @@ -50,15 +64,18 @@ export class TextGenerator<T extends PlaitElement = PlaitGeometry> {
initialize() {
const textPlugins = ((this.board as PlaitOptionsBoard).getPluginOptions<WithTextOptions>(WithTextPluginKey) || {}).textPlugins;
this.textManages = this.texts.map(text => {
return this.createTextManage(text, textPlugins);
const textManage = this.createTextManage(text, textPlugins);
setTextManage(text.key, textManage);
return textManage;
});
ELEMENT_TO_TEXT_MANAGES.set(this.element, this.textManages);
}

draw(elementG: SVGElement) {
const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);
this.texts.forEach((drawShapeText, index) => {
const textManage = this.textManages[index];
if (drawShapeText.text) {
this.texts.forEach(drawShapeText => {
const textManage = getTextManage(drawShapeText.key);
if (drawShapeText.text && textManage) {
textManage.draw(drawShapeText.text);
elementG.append(textManage.g);
this.element.angle && textManage.updateAngle(centerPoint, this.element.angle);
Expand All @@ -68,10 +85,11 @@ export class TextGenerator<T extends PlaitElement = PlaitGeometry> {

update(element: T, previousDrawShapeTexts: PlaitDrawShapeText[], currentDrawShapeTexts: PlaitDrawShapeText[], elementG: SVGElement) {
this.element = element;
ELEMENT_TO_TEXT_MANAGES.set(this.element, this.textManages);
const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);
currentDrawShapeTexts.forEach((drawShapeText, index) => {
const textManage = this.textManages[index];
if (drawShapeText.text) {
currentDrawShapeTexts.forEach(drawShapeText => {
const textManage = getTextManage(drawShapeText.key);
if (drawShapeText.text && textManage) {
textManage.updateText(drawShapeText.text);
textManage.updateRectangle();
this.element.angle && textManage.updateAngle(centerPoint, this.element.angle);
Expand Down Expand Up @@ -117,5 +135,6 @@ export class TextGenerator<T extends PlaitElement = PlaitGeometry> {
});
this.textManages = [];
ELEMENT_TO_TEXT_MANAGES.delete(this.element);
KEY_TO_TEXT_MANAGE.clear();
}
}
4 changes: 0 additions & 4 deletions packages/draw/src/geometry.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ export class GeometryComponent extends CommonPluginElement<PlaitCommonGeometry,
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 as PlaitGeometry, this.getElementG());
Expand Down Expand Up @@ -162,9 +161,7 @@ export class GeometryComponent extends CommonPluginElement<PlaitCommonGeometry,
}
);
}

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

ngOnDestroy(): void {
Expand All @@ -174,6 +171,5 @@ export class GeometryComponent extends CommonPluginElement<PlaitCommonGeometry,
this.activeGenerator.destroy();
this.lineAutoCompleteGenerator.destroy();
this.textGenerator.destroy();
this.destroyTextManages();
}
}
24 changes: 22 additions & 2 deletions packages/draw/src/plugins/with-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import {
RectangleClient,
Selection,
isPolylineHitRectangle,
getSelectedElements
getSelectedElements,
toViewBoxPoint,
toHostPoint,
getHitElementByPoint
} from '@plait/core';
import { editCell, getHitCell } from '../utils/table';

export const withTable = (board: PlaitBoard) => {
const { drawElement, getRectangle, isRectangleHit, isHit, isMovable, getDeletedFragment } = board;
const { drawElement, getRectangle, isRectangleHit, isHit, isMovable, getDeletedFragment, dblClick } = board;
board.drawElement = (context: PlaitPluginElementContext) => {
if (PlaitTableElement.isTable(context.element)) {
return TableComponent;
Expand Down Expand Up @@ -58,5 +62,21 @@ export const withTable = (board: PlaitBoard) => {
}
return isRectangleHit(element, selection);
};

board.dblClick = (event: MouseEvent) => {
event.preventDefault();
if (!PlaitBoard.isReadonly(board)) {
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
const hitElement = getHitElementByPoint(board, point);
if (hitElement && PlaitTableElement.isTable(hitElement)) {
const hitCell = getHitCell(hitElement, point);
if (hitCell && hitCell.text && hitCell.textHeight) {
editCell(hitCell);
}
}
}
dblClick(event);
};

return board;
};
28 changes: 19 additions & 9 deletions packages/draw/src/table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { PlaitTable, PlaitTableCell } from './interfaces/table';
import { PlaitDrawShapeText, TextGenerator } from './generators/text.generator';
import { TableGenerator } from './generators/table.generator';
import { TextManageRef } from '@plait/text';
import { DrawTransforms } from './transforms';
import { getCellsWithPoints } from './utils/table';
import { memorizeLatestText } from './utils';

@Component({
selector: 'plait-draw-table',
Expand Down Expand Up @@ -63,23 +66,30 @@ export class TableComponent extends CommonPluginElement<PlaitTable, PlaitBoard>
initializeTextManage() {
const texts = this.getDrawShapeTexts(this.element.cells);
this.textGenerator = new TextGenerator(this.board, this.element, texts, this.viewContainerRef, {
onValueChangeHandle: (textChangeRef: TextManageRef, text: PlaitDrawShapeText) => {}
onValueChangeHandle: (textManageRef: TextManageRef, text: PlaitDrawShapeText) => {
const cells = getCellsWithPoints(this.element);
const height = textManageRef.height / this.board.viewport.zoom;
const width = textManageRef.width / this.board.viewport.zoom;
if (textManageRef.newValue) {
DrawTransforms.setTableText(
this.board,
this.element,
cells.find(item => item.id === text.key)!,
textManageRef.newValue,
width,
height
);
}
textManageRef.operations && memorizeLatestText(this.element, textManageRef.operations);
}
});
this.textGenerator.initialize();
this.initializeTextManages(this.textGenerator.textManages);
}

updateText(previousTable: PlaitTable, currentTable: PlaitTable) {
const previousTexts = this.getDrawShapeTexts(previousTable.cells);
const currentTexts = this.getDrawShapeTexts(currentTable.cells);
this.textGenerator.update(this.element, previousTexts, currentTexts, this.getElementG());
}

onContextChanged(
value: PlaitPluginElementContext<PlaitTable, PlaitBoard>,
previous: PlaitPluginElementContext<PlaitTable, PlaitBoard>
) {
this.initializeWeakMap();
if (value.element !== previous.element) {
this.tableGenerator.processDrawing(this.element, this.getElementG());
this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
Expand Down
4 changes: 3 additions & 1 deletion packages/draw/src/transforms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { insertText, insertGeometry, resizeGeometry, switchGeometryShape, insert
import { setText, setTextSize } from './geometry-text';
import { insertImage } from './image';
import { connectLineToGeometry, removeLineText, resizeLine, setLineMark, setLineShape, setLineTexts } from './line';
import { setTableText } from './table-text';

export const DrawTransforms = {
setText,
Expand All @@ -17,5 +18,6 @@ export const DrawTransforms = {
insertImage,
switchGeometryShape,
connectLineToGeometry,
insertGeometryByVector
insertGeometryByVector,
setTableText
};
45 changes: 45 additions & 0 deletions packages/draw/src/transforms/table-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { PlaitBoard, RectangleClient, Transforms } from '@plait/core';
import { ShapeDefaultSpace } from '../constants';
import { Element } from 'slate';
import { PlaitTable, PlaitTableCellParagraph, PlaitTableCellWithPoints } from '../interfaces/table';

export const setTableText = (
board: PlaitBoard,
table: PlaitTable,
cell: PlaitTableCellWithPoints,
text: Element,
textWidth: number,
textHeight: number
) => {
const cellIndex = table.cells.findIndex(item => item.id === cell.id);
let rows = [...table.rows];
let cells = [...table.cells];
let points = [...table.points];
const { height: cellHeight } = RectangleClient.getRectangleByPoints(cell.points);
if (cell.text!.writingMode === 'vertical-lr') {
// 文字高度发生改变,修改该列的宽度
// update table width
} else {
const rowIdx = table.rows.findIndex(row => row.id === cell.rowId);
const tableRow = table.rows[rowIdx];
const compareHeight = tableRow.height ?? Math.max(cellHeight, cell.textHeight || 0);
if (textHeight > compareHeight) {
const defaultSpace = ShapeDefaultSpace.rectangleAndText;
const newRowHeight = textHeight + defaultSpace * 2;
rows[rowIdx] = {
...tableRow,
height: newRowHeight
};
// update table height
const offset = newRowHeight - compareHeight;
points = [points[0], [points[1][0], points[1][1] + offset]];
}
}
cells[cellIndex] = {
...cell,
textHeight: textHeight,
text: text as PlaitTableCellParagraph
};
const path = board.children.findIndex(child => child === table);
Transforms.setNode(board, { rows, cells, points }, [path]);
};
25 changes: 24 additions & 1 deletion packages/draw/src/utils/table.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RectangleClient } from '@plait/core';
import { Point, RectangleClient } from '@plait/core';
import { PlaitTable, PlaitTableCell, PlaitTableCellWithPoints } from '../interfaces/table';
import { getTextManage } from '../generators/text.generator';

export function getCellsWithPoints(table: PlaitTable): PlaitTableCellWithPoints[] {
const rectangle = RectangleClient.getRectangleByPoints(table.points);
Expand Down Expand Up @@ -74,3 +75,25 @@ function calculateCellSize(cell: PlaitTableCell, sizes: number[], index: number,
}
return size;
}

export function getHitCell(table: PlaitTable, point: Point) {
const cells = getCellsWithPoints(table);
const rectangle = RectangleClient.getRectangleByPoints([point, point]);
const cell = cells.find(item => {
const cellRectangle = RectangleClient.getRectangleByPoints(item.points);
return RectangleClient.isHit(rectangle, cellRectangle);
});
if (cell) {
return table.cells.find(item => item.id === cell.id);
}
return null;
}

export function editCell(cell: PlaitTableCell) {
const textManage = getTextManageByCell(cell);
textManage && textManage.edit();
}

export function getTextManageByCell(cell: PlaitTableCell) {
return getTextManage(cell.id);
}
Loading
Loading