Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions .changeset/forty-dogs-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@plait/draw': patch
---

adjust table resize
9 changes: 7 additions & 2 deletions packages/draw/src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ export const PlaitDrawElement = {
}
},
isShapeElement: (value: any): value is PlaitShapeElement => {
return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isTable(value) || PlaitDrawElement.isSwimlane(value);
return (
PlaitDrawElement.isImage(value) ||
PlaitDrawElement.isGeometry(value) ||
PlaitDrawElement.isTable(value) ||
PlaitDrawElement.isSwimlane(value)
);
},
isBasicShape: (value: any) => {
return Object.keys(BasicShapes).includes(value.shape);
Expand Down Expand Up @@ -77,5 +82,5 @@ export const PlaitDrawElement = {
},
isElementByTable: (value: any): value is PlaitBaseTable => {
return PlaitDrawElement.isTable(value) || PlaitDrawElement.isSwimlane(value) || PlaitDrawElement.isGeometryByTable(value);
},
}
};
232 changes: 156 additions & 76 deletions packages/draw/src/plugins/with-table-resize.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getHitElementByPoint, PlaitBoard, Point, RectangleClient, Transforms, isSelectedElement } from '@plait/core';
import { PlaitBaseTable, PlaitTableBoard, PlaitTableCellWithPoints } from '../interfaces/table';
import { PlaitBaseTable, PlaitTableBoard, PlaitTableCell, PlaitTableCellWithPoints } from '../interfaces/table';
import {
getIndexByResizeHandle,
isCornerHandle,
Expand All @@ -22,7 +22,7 @@ interface TableResizeOptions extends ResizeOptions {
cell: PlaitTableCellWithPoints;
}

const MIN_CELL_SIZE = 20;
const MIN_CELL_SIZE = 32;

export function withTableResize(board: PlaitTableBoard) {
let snapG: SVGGElement | null;
Expand All @@ -35,26 +35,10 @@ export function withTableResize(board: PlaitTableBoard) {
hitTest: (point: Point) => {
const hitElement = getHitElementByPoint(board, point);
if (hitElement && PlaitDrawElement.isElementByTable(hitElement)) {
let rectangle = board.getRectangle(hitElement) as RectangleClient;
let handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, hitElement.angle);
if (handleRef) {
const selectElement = isSelectedElement(board, hitElement);
if (
(selectElement && isSingleSelectElementByTable(board)) ||
(!selectElement && !isCornerHandle(board, handleRef.handle))
) {
return {
element: hitElement,
handle: handleRef.handle,
cursorClass: handleRef.cursorClass,
rectangle
};
}
}
const cells = getCellsWithPoints(board, hitElement);
for (let i = 0; i < cells.length; i++) {
rectangle = RectangleClient.getRectangleByPoints(cells[i].points);
handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);
const rectangle = RectangleClient.getRectangleByPoints(cells[i].points);
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);
if (handleRef && !isCornerHandle(board, handleRef.handle)) {
return {
element: hitElement,
Expand All @@ -67,12 +51,29 @@ export function withTableResize(board: PlaitTableBoard) {
};
}
}
const rectangle = board.getRectangle(hitElement) as RectangleClient;
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, hitElement.angle);
if (handleRef) {
const selectElement = isSelectedElement(board, hitElement);
if (
(selectElement && isSingleSelectElementByTable(board)) ||
(!selectElement && !isCornerHandle(board, handleRef.handle))
Comment thread
pubuzhixing8 marked this conversation as resolved.
Outdated
) {
return {
element: hitElement,
handle: handleRef.handle,
cursorClass: handleRef.cursorClass,
rectangle
};
}
}
}
return null;
},
onResize: (resizeRef: ResizeRef<PlaitBaseTable, ResizeHandle, TableResizeOptions>, resizeState: ResizeState) => {
snapG?.remove();
const path = PlaitBoard.findPath(board, resizeRef.element);

if (resizeRef.options?.cell && resizeRef.rectangle) {
const handleIndex = getIndexByResizeHandle(resizeRef.handle);
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, handleIndex, resizeRef.rectangle!);
Expand All @@ -82,67 +83,83 @@ export function withTableResize(board: PlaitTableBoard) {
const targetPoints = originPoints.map(p => {
return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
}) as [Point, Point];
const offsetX = targetPoints[1][0] - originPoints[1][0];
const offsetY = targetPoints[1][1] - originPoints[1][1];
const width = targetPoints[1][0] - targetPoints[0][0];
const height = targetPoints[1][1] - targetPoints[0][1];
if (offsetX !== 0 && width >= MIN_CELL_SIZE) {
const { columns, points } = updateColumns(resizeRef.element, resizeRef.options?.cell.columnId, width, offsetX);
Transforms.setNode(board, { columns, points }, path);
} else if (offsetY !== 0 && height >= MIN_CELL_SIZE) {
const { rows, points } = updateRows(resizeRef.element, resizeRef.options?.cell.rowId, height, offsetY);
Transforms.setNode(board, { rows, points }, path);
}
} else {
const isFromCorner = isCornerHandle(board, resizeRef.handle);
const isAspectRatio = resizeState.isShift;
const handleIndex = getIndexByResizeHandle(resizeRef.handle);
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, handleIndex, resizeRef.rectangle!);
const resizeSnapRefOptions = getSnapResizingRefOptions(
board,
resizeRef,
resizeState,
{
originPoint,
handlePoint
},
isAspectRatio,
isFromCorner
);
const resizeSnapRef = getSnapResizingRef(board, [resizeRef.element], resizeSnapRefOptions);
snapG = resizeSnapRef.snapG;
PlaitBoard.getElementActiveHost(board).append(snapG);
const points = resizeSnapRef.activePoints as [Point, Point];
const originPoints = resizeRef.element.points;

const originRect = RectangleClient.getRectangleByPoints(originPoints);
const targetRect = RectangleClient.getRectangleByPoints(points);
const targetRect = RectangleClient.getRectangleByPoints(targetPoints);
const offsetWidth = targetRect.width - originRect.width;
const offsetHeight = targetRect.height - originRect.height;
let columns = [...resizeRef.element.columns];
let rows = [...resizeRef.element.rows];
if (offsetWidth !== 0) {
columns = columns.map(item => {
if (item.width) {
return {
...item,
width: item.width + offsetWidth * (item.width / originRect.width)
};
}
return item;
});
const direction = getResizeCellDirection(handleIndex);
if (offsetWidth !== 0 && direction) {
const columnIndex = getResizeColumnOrRowIndex(resizeRef.element, resizeRef.options?.cell, direction, false);
let width = targetPoints[1][0] - targetPoints[0][0];
if (resizeRef.options?.cell.colspan && resizeRef.options?.cell.colspan !== 1) {
const columnWidth = getResizeColumnOrRowSize(board, resizeRef.element, columnIndex, false);
width = columnWidth + offsetWidth;
}
if (width >= MIN_CELL_SIZE) {
const { columns, points } = updateColumns(
resizeRef.element,
resizeRef.element.columns[columnIndex].id,
width,
offsetWidth,
direction
);
Transforms.setNode(board, { columns, points }, path);
}
}
if (offsetHeight !== 0) {
rows = rows.map(item => {
if (item.height) {
return {
...item,
height: item.height + offsetHeight * (item.height / originRect.height)
};
}
return item;
});
if (offsetHeight !== 0 && direction) {
const rowIndex = getResizeColumnOrRowIndex(resizeRef.element, resizeRef.options?.cell, direction, true);
let height = targetPoints[1][1] - targetPoints[0][1];
if (resizeRef.options?.cell.rowspan && resizeRef.options?.cell.rowspan !== 1) {
const rowHeight = getResizeColumnOrRowSize(board, resizeRef.element, rowIndex, true);
height = rowHeight + offsetHeight;
}
if (height >= MIN_CELL_SIZE) {
const { rows, points } = updateRows(
resizeRef.element,
resizeRef.element.rows[rowIndex].id,
height,
offsetHeight,
direction
);
Transforms.setNode(board, { rows, points }, path);
}
}
} else {
const isFromCorner = isCornerHandle(board, resizeRef.handle);
if (isFromCorner) {
const handleIndex = getIndexByResizeHandle(resizeRef.handle);
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, handleIndex, resizeRef.rectangle!);
const resizeSnapRefOptions = getSnapResizingRefOptions(
board,
resizeRef,
resizeState,
{
originPoint,
handlePoint
},
true,
true
);
const resizeSnapRef = getSnapResizingRef(board, [resizeRef.element], resizeSnapRefOptions);
snapG = resizeSnapRef.snapG;
PlaitBoard.getElementActiveHost(board).append(snapG);
const points = resizeSnapRef.activePoints as [Point, Point];
const originPoints = resizeRef.element.points;
const originRect = RectangleClient.getRectangleByPoints(originPoints);
const targetRect = RectangleClient.getRectangleByPoints(points);
const offsetWidth = targetRect.width - originRect.width;
const offsetHeight = targetRect.height - originRect.height;
let columns = [...resizeRef.element.columns];
let rows = [...resizeRef.element.rows];
if (offsetWidth !== 0) {
columns = calculateRowsOrColumns(columns, offsetWidth, originRect.width, false);
}
if (offsetHeight !== 0) {
rows = calculateRowsOrColumns(rows, offsetHeight, originRect.height, true);
}
Transforms.setNode(board, { points: normalizeShapePoints(points), rows, columns }, path);
}
Transforms.setNode(board, { points: normalizeShapePoints(points), columns, rows }, path);
}
},
afterResize: (resizeRef: ResizeRef<PlaitBaseTable, ResizeHandle, TableResizeOptions>) => {
Expand All @@ -155,3 +172,66 @@ export function withTableResize(board: PlaitTableBoard) {

return board;
}

function calculateRowsOrColumns(
data: { id: string; width?: number; height?: number }[],
offset: number,
originSize: number,
isRow: boolean
) {
const dimension = isRow ? 'height' : 'width';
return data.map(item => {
if (item[dimension]) {
const value = item[dimension]! + offset * (item[dimension]! / originSize);
return {
...item,
[dimension]: value
};
}
return item;
});
}

function getResizeCellDirection(handleIndex: number) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start 和 end 概念的抽取需要讨论下

if ([Number(ResizeHandle.s), Number(ResizeHandle.e)].includes(handleIndex)) {
return 'end';
}
if ([Number(ResizeHandle.n), Number(ResizeHandle.w)].includes(handleIndex)) {
return 'start';
}
return undefined;
}

function getResizeColumnOrRowIndex(element: PlaitBaseTable, resizeCell: PlaitTableCell, direction: 'start' | 'end', isRow: boolean) {
const data = isRow ? element.rows : element.columns;
const id = isRow ? resizeCell.rowId : resizeCell.columnId;
const span = isRow ? resizeCell.rowspan : resizeCell.colspan;
let index = data.findIndex(item => item.id === id);
if (direction === 'end' && span && span !== 1) {
index += span - 1;
}
return index;
}

function getResizeColumnOrRowSize(board: PlaitBoard, element: PlaitBaseTable, index: number, isRow: boolean) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCurrentRowHeightOrColumnWidth vs getMinColumnWidthOrRowHeight

const size = isRow ? element.rows[index]['height'] : element.columns[index]['width'];
if (size) {
return size;
}
const id = isRow ? element.rows[index].id : element.columns[index].id;
const dimension = isRow ? 'height' : 'width';
const cellsWithPoints = getCellsWithPoints(board, element);
const minDimension = cellsWithPoints.reduce((acc, item) => {
const itemId = isRow ? item.rowId : item.columnId;
if (itemId === id) {
const rectangle = RectangleClient.getRectangleByPoints(item.points);
const itemSize = rectangle[dimension];
if (!acc || itemSize < acc) {
acc = itemSize;
}
}
return acc;
}, 0);

return minDimension;
}
20 changes: 16 additions & 4 deletions packages/draw/src/utils/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,27 @@ export function getTextManageByCell(cell: PlaitTableCell) {
return getTextManage(cell.id);
}

export const updateColumns = (table: PlaitBaseTable, columnId: string, width: number, offset: number) => {
export const updateColumns = (
table: PlaitBaseTable,
columnId: string,
width: number,
offset: number,
direction: 'start' | 'end' = 'end'
) => {
const columns = table.columns.map(item => (item.id === columnId ? { ...item, width } : item));
const points = [table.points[0], [table.points[1][0] + offset, table.points[1][1]]] as Point[];
let points = [table.points[0], [table.points[1][0] + offset, table.points[1][1]]] as Point[];
if (direction === 'start') {
points = [[table.points[0][0] - offset, table.points[0][1]], table.points[1]] as Point[];
}
return { columns, points };
};

export const updateRows = (table: PlaitBaseTable, rowId: string, height: number, offset: number) => {
export const updateRows = (table: PlaitBaseTable, rowId: string, height: number, offset: number, direction: 'start' | 'end' = 'end') => {
const rows = table.rows.map(item => (item.id === rowId ? { ...item, height } : item));
const points = [table.points[0], [table.points[1][0], table.points[1][1] + offset]] as Point[];
let points = [table.points[0], [table.points[1][0], table.points[1][1] + offset]] as Point[];
if (direction === 'start') {
points = [[table.points[0][0], table.points[0][1] - offset], table.points[1]] as Point[];
}
return { rows, points };
};

Expand Down