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 create swimlane #WIK-15543 #889

Merged
merged 3 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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/smart-kiwis-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@plait/draw': minor
---

support create default swimlane
17 changes: 16 additions & 1 deletion packages/draw/src/constants/geometry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ACTIVE_STROKE_WIDTH } from '@plait/core';
import { Alignment } from '@plait/text';
import { BasicShapes, FlowchartSymbols, GeometryShapes, MultipleTextGeometryCommonTextKeys, UMLSymbols } from '../interfaces';
import { BasicShapes, FlowchartSymbols, GeometryShapes, MultipleTextGeometryCommonTextKeys, SwimlaneSymbols, UMLSymbols } from '../interfaces';

export const ShapeDefaultSpace = {
rectangleAndText: 4
Expand Down Expand Up @@ -154,6 +154,16 @@ export const DefaultCombinedFragmentProperty = {
]
};

export const DefaultSwimlaneVerticalProperty = {
width: 450,
height: 500
};

export const DefaultSwimlaneHorizontalProperty = {
width: 500,
height: 450
};

export const DefaultBasicShapePropertyMap: Record<string, { width: number; height: number }> = {
[BasicShapes.pentagonArrow]: DefaultPentagonArrowProperty,
[BasicShapes.processArrow]: DefaultPentagonArrowProperty,
Expand Down Expand Up @@ -203,6 +213,11 @@ export const MultipleTextGeometryTextKeys: { [key in GeometryShapes]?: string[]
[UMLSymbols.combinedFragment]: Object.keys(MultipleTextGeometryCommonTextKeys)
};

export const DefaultSwimlanePropertyMap: Record<string, { width: number; height: number }> = {
[SwimlaneSymbols.swimlaneHorizontal]: DefaultSwimlaneHorizontalProperty,
[SwimlaneSymbols.swimlaneVertical]: DefaultSwimlaneVerticalProperty,
};

export const LINE_HIT_GEOMETRY_BUFFER = 10;

export const LINE_SNAPPING_BUFFER = 6;
Expand Down
4 changes: 4 additions & 0 deletions packages/draw/src/constants/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export const getGeometryPointers = () => {
return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols), ...Object.keys(UMLSymbols)];
};

export const getSwimlanePointers = () => {
return Object.keys(SwimlaneSymbols);
};

export const getBasicPointers = () => {
return Object.keys(BasicShapes);
};
Expand Down
29 changes: 13 additions & 16 deletions packages/draw/src/plugins/with-draw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { getLinePoints, getLineTextRectangle } from '../utils/line/line-basic';
import { withDrawRotate } from './with-draw-rotate';
import { withTable } from './with-table';
import { withSwimlane } from './with-swimlane';
import { withTableResize } from './with-table-resize';

export const withDraw = (board: PlaitBoard) => {
const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;
Expand Down Expand Up @@ -128,21 +127,19 @@ export const withDraw = (board: PlaitBoard) => {
};

return withSwimlane(
withTableResize(
withTable(
withDrawResize(
withLineAutoCompleteReaction(
withLineBoundReaction(
withLineResize(
withLineTextMove(
withLineText(
withGeometryResize(
withDrawRotate(
withLineCreateByDraw(
withLineAutoComplete(
withGeometryCreateByDrag(
withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))
)
withTable(
withDrawResize(
withLineAutoCompleteReaction(
withLineBoundReaction(
withLineResize(
withLineTextMove(
withLineText(
withGeometryResize(
withDrawRotate(
withLineCreateByDraw(
withLineAutoComplete(
withGeometryCreateByDrag(
withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))
)
)
)
Expand Down
166 changes: 166 additions & 0 deletions packages/draw/src/plugins/with-swimlane-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { PlaitBoard, Point, RectangleClient, createG, preventTouchMove, toHostPoint, toViewBoxPoint } from '@plait/core';
import { PlaitSwimlane, SwimlaneSymbols } from '../interfaces';
import { insertElement } from '../utils';
import { getSwimlanePointers } from '../constants';
import {
normalizeShapePoints,
isDndMode,
isDrawingMode,
getDirectionFactorByDirectionComponent,
getUnitVectorByPointAndPoint
} from '@plait/common';
import { TextManage } from '@plait/text';
import { isKeyHotkey } from 'is-hotkey';
import { getSnapResizingRef } from '../utils/snap-resizing';
import { TableGenerator } from '../generators/table.generator';
import { createDefaultSwimlane, getDefaultSWimlanePoints } from '../utils/swimlane';

export interface FakeCreateTextRef {
g: SVGGElement;
textManage: TextManage;
}

const isSwimlaneDndMode = (board: PlaitBoard) => {
const swimlanePointers = getSwimlanePointers();
const isSwimlanePointer = PlaitBoard.isInPointer(board, swimlanePointers);
const dndMode = isSwimlanePointer && isDndMode(board);
return dndMode;
};

const isSwimlaneDrawingMode = (board: PlaitBoard) => {
const swimlanePointers = getSwimlanePointers();
const isSwimlanePointer = PlaitBoard.isInPointer(board, swimlanePointers);
const drawingMode = isSwimlanePointer && isDrawingMode(board);
return drawingMode;
};

export const withSwimlaneCreateByDrag = (board: PlaitBoard) => {
const { pointerMove, globalPointerUp, pointerUp } = board;

let swimlaneG: SVGGElement | null = null;

let temporaryElement: PlaitSwimlane | null = null;

board.pointerMove = (event: PointerEvent) => {
swimlaneG?.remove();
swimlaneG = createG();

const tableGenerator = new TableGenerator(board);
const dragMode = isSwimlaneDndMode(board);
const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
const pointer = PlaitBoard.getPointer(board) as SwimlaneSymbols;

if (dragMode) {
const points = getDefaultSWimlanePoints(pointer, movingPoint);
temporaryElement = createDefaultSwimlane(pointer, points);
tableGenerator.processDrawing(temporaryElement, swimlaneG);
PlaitBoard.getElementActiveHost(board).append(swimlaneG);
}

pointerMove(event);
};

board.pointerUp = (event: PointerEvent) => {
if (isSwimlaneDndMode(board) && temporaryElement) {
return;
}
pointerUp(event);
};

board.globalPointerUp = (event: PointerEvent) => {
if (isSwimlaneDndMode(board) && temporaryElement) {
insertElement(board, temporaryElement);
}
temporaryElement = null;
swimlaneG?.remove();
swimlaneG = null;
preventTouchMove(board, event, false);
globalPointerUp(event);
};

return board;
};

export const withSwimlaneCreateByDrawing = (board: PlaitBoard) => {
const { pointerDown, pointerMove, pointerUp, keyDown, keyUp } = board;
let start: Point | null = null;

let swimlaneG: SVGGElement | null = null;

let temporaryElement: PlaitSwimlane | null = null;

let isShift = false;

let snapG: SVGGElement | null;

board.keyDown = (event: KeyboardEvent) => {
isShift = isKeyHotkey('shift', event);
keyDown(event);
};

board.keyUp = (event: KeyboardEvent) => {
isShift = false;
keyUp(event);
};

board.pointerDown = (event: PointerEvent) => {
if (!PlaitBoard.isReadonly(board) && isSwimlaneDrawingMode(board)) {
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
start = point;
}
pointerDown(event);
};

board.pointerMove = (event: PointerEvent) => {
swimlaneG?.remove();
swimlaneG = createG();
const tableGenerator = new TableGenerator(board);
const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
const pointer = PlaitBoard.getPointer(board) as SwimlaneSymbols;
snapG?.remove();
if (start && isSwimlaneDrawingMode(board)) {
let points: [Point, Point] = normalizeShapePoints([start, movingPoint], isShift);
const activeRectangle = RectangleClient.getRectangleByPoints(points);
const [x, y] = getUnitVectorByPointAndPoint(start, movingPoint);
const resizeSnapRef = getSnapResizingRef(board, [], {
resizePoints: points,
activeRectangle,
directionFactors: [getDirectionFactorByDirectionComponent(x), getDirectionFactorByDirectionComponent(y)],
isAspectRatio: isShift,
isFromCorner: true,
isCreate: true
});
snapG = resizeSnapRef.snapG;
PlaitBoard.getElementActiveHost(board).append(snapG);
points = normalizeShapePoints(resizeSnapRef.activePoints as [Point, Point], isShift);
temporaryElement = createDefaultSwimlane(pointer, points);
tableGenerator.processDrawing(temporaryElement, swimlaneG);
PlaitBoard.getElementActiveHost(board).append(swimlaneG);
}
pointerMove(event);
};

board.pointerUp = (event: PointerEvent) => {
if (isSwimlaneDrawingMode(board) && start) {
const targetPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
const { width, height } = RectangleClient.getRectangleByPoints([start!, targetPoint]);
if (Math.hypot(width, height) < 8) {
const pointer = PlaitBoard.getPointer(board) as SwimlaneSymbols;
const points = getDefaultSWimlanePoints(pointer, targetPoint);
temporaryElement = createDefaultSwimlane(pointer, points);
}
if (temporaryElement) {
insertElement(board, temporaryElement);
}
snapG?.remove();
swimlaneG?.remove();
swimlaneG = null;
start = null;
temporaryElement = null;
preventTouchMove(board, event, false);
return;
}
pointerUp(event);
};
return board;
};
3 changes: 2 additions & 1 deletion packages/draw/src/plugins/with-swimlane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { buildSwimlaneTable } from '../utils/swimlane';
import { PlaitTableBoard } from './with-table';
import { PlaitTable } from '../interfaces/table';
import { TableComponent } from '../table.component';
import { withSwimlaneCreateByDrag, withSwimlaneCreateByDrawing } from './with-swimlane-create';

export const withSwimlane = (board: PlaitTableBoard) => {
const { drawElement, buildTable } = board;
Expand All @@ -22,5 +23,5 @@ export const withSwimlane = (board: PlaitTableBoard) => {
return buildTable(element);
};

return board;
return withSwimlaneCreateByDrawing(withSwimlaneCreateByDrag(board));
};
3 changes: 2 additions & 1 deletion packages/draw/src/plugins/with-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { editCell, getHitCell } from '../utils/table';
import { getElementsText } from '@plait/common';
import { getSelectedTableElements } from '../utils';
import { buildTableClipboardData, insertClipboardTableData } from '../utils/clipboard';
import { withTableResize } from './with-table-resize';

export interface PlaitTableBoard extends PlaitBoard {
buildTable: (element: PlaitTable) => PlaitTable;
Expand Down Expand Up @@ -145,5 +146,5 @@ export const withTable = (board: PlaitBoard) => {
insertFragment(clipboardData, targetPoint, operationType);
};

return tableBoard;
return withTableResize(tableBoard);
};
15 changes: 13 additions & 2 deletions packages/draw/src/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { PlaitElement, RectangleClient } from '@plait/core';
import { addSelectedElement, BoardTransforms, clearSelectedElement, PlaitBoard, PlaitElement, PlaitPointerType, RectangleClient, Transforms } from '@plait/core';
import { DefaultDrawStyle, ShapeDefaultSpace } from '../constants';
import { PlaitDrawElement, PlaitGeometry } from '../interfaces';
import { PlaitCommonGeometry, PlaitDrawElement, PlaitGeometry } from '../interfaces';
import { PlaitTable } from '../interfaces/table';
import { memorizeLatestShape } from './memorize';

export const getTextRectangle = <T extends PlaitElement = PlaitGeometry>(element: T) => {
const elementRectangle = RectangleClient.getRectangleByPoints(element.points!);
Expand All @@ -22,3 +24,12 @@ export const getStrokeWidthByElement = (element: PlaitElement) => {
const strokeWidth = element.strokeWidth || DefaultDrawStyle.strokeWidth;
return strokeWidth;
};


export const insertElement = (board: PlaitBoard, element: PlaitCommonGeometry | PlaitTable) => {
memorizeLatestShape(board, element.shape);
Transforms.insertNode(board, element, [board.children.length]);
clearSelectedElement(board);
addSelectedElement(board, element);
BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
};
8 changes: 0 additions & 8 deletions packages/draw/src/utils/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,14 +333,6 @@ export const getDefaultTextPoints = (board: PlaitBoard, centerPoint: Point, font
return RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(centerPoint, property.width, property.height));
};

export const insertElement = (board: PlaitBoard, element: PlaitCommonGeometry) => {
memorizeLatestShape(board, element.shape);
Transforms.insertNode(board, element, [board.children.length]);
clearSelectedElement(board);
addSelectedElement(board, element);
BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
};

export const createTextElement = (
board: PlaitBoard,
points: [Point, Point],
Expand Down
Loading
Loading