Skip to content

Commit

Permalink
feat(draw): add database,hardDisk and internalStorage shape for flowc…
Browse files Browse the repository at this point in the history
…hart #WIK-15269 (#850)
  • Loading branch information
MissLixf authored Apr 28, 2024
1 parent e0ba1c1 commit fd05792
Show file tree
Hide file tree
Showing 8 changed files with 409 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-bobcats-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@plait/draw': minor
---

add database,hardDisk and internalStorage shape for flowchart
13 changes: 13 additions & 0 deletions packages/draw/src/constants/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ export const DefaultFlowchartProperty = {
height: 60
};

export const DefaultDataBaseProperty = {
width: 70,
height: 80
};

export const DefaultInternalStorageProperty = {
width: 80,
height: 80
};

export const DefaultDecisionProperty = {
width: 140,
height: 70
Expand Down Expand Up @@ -104,6 +114,9 @@ export const DefaultFlowchartPropertyMap = {
[FlowchartSymbols.offPage]: DefaultFlowchartProperty,
[FlowchartSymbols.document]: DefaultDocumentProperty,
[FlowchartSymbols.multiDocument]: DefaultMultiDocumentProperty,
[FlowchartSymbols.database]: DefaultDataBaseProperty,
[FlowchartSymbols.hardDisk]: DefaultFlowchartProperty,
[FlowchartSymbols.internalStorage]: DefaultInternalStorageProperty,
[FlowchartSymbols.noteCurlyLeft]: DefaultNoteProperty,
[FlowchartSymbols.noteCurlyRight]: DefaultNoteProperty,
[FlowchartSymbols.noteSquare]: DefaultNoteProperty
Expand Down
120 changes: 120 additions & 0 deletions packages/draw/src/engines/flowchart/database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {
PlaitBoard,
Point,
PointOfRectangle,
RectangleClient,
Vector,
getEllipseTangentSlope,
getNearestPointBetweenPointAndEllipse,
getNearestPointBetweenPointAndSegments,
getVectorFromPointAndSlope,
isPointInEllipse,
setStrokeLinecap
} from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { ShapeDefaultSpace } from '../../constants';
import { getStrokeWidthByElement } from '../../utils/style/stroke';
import { Options } from 'roughjs/bin/core';
import { RectangleEngine } from '../basic-shapes/rectangle';

export const DatabaseEngine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
const rs = PlaitBoard.getRoughSVG(board);
const shape = rs.path(
`M${rectangle.x} ${rectangle.y + rectangle.height * 0.15}
A${rectangle.width / 2} ${rectangle.height * 0.15}, 0, 0, 0,${rectangle.x + rectangle.width} ${rectangle.y +
rectangle.height * 0.15}
A${rectangle.width / 2} ${rectangle.height * 0.15}, 0, 0, 0,${rectangle.x} ${rectangle.y + rectangle.height * 0.15}
V${rectangle.y + rectangle.height - rectangle.height * 0.15}
A${rectangle.width / 2} ${rectangle.height * 0.15}, 0, 0, 0, ${rectangle.x + rectangle.width} ${rectangle.y +
rectangle.height -
rectangle.height * 0.15}
V${rectangle.y + rectangle.height * 0.15}`,
{ ...options, fillStyle: 'solid' }
);
setStrokeLinecap(shape, 'round');
return shape;
},
isInsidePoint(rectangle: RectangleClient, point: Point) {
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
const isInRectangle = RectangleClient.isHit(
{
...rectangle,
y: rectangle.y + rectangle.height * 0.15,
height: rectangle.height - rectangle.height * 0.3
},
rangeRectangle
);

const isInTopEllipse = isPointInEllipse(
point,
[rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * 0.15],
rectangle.width / 2,
rectangle.height * 0.15
);

const isInBottomEllipse = isPointInEllipse(
point,
[rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height - rectangle.height * 0.15],
rectangle.width / 2,
rectangle.height * 0.15
);
return isInRectangle || isInTopEllipse || isInBottomEllipse;
},
getCornerPoints(rectangle: RectangleClient) {
return RectangleClient.getCornerPoints(rectangle);
},

getNearestPoint(rectangle: RectangleClient, point: Point) {
const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
if (nearestPoint[1] < rectangle.y + rectangle.height * 0.15) {
const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * 0.15] as Point;
const nearestPoint = getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height * 0.15);
if (nearestPoint[1] > centerPoint[1]) {
nearestPoint[1] = centerPoint[1] * 2 - nearestPoint[1];
}
return nearestPoint;
}
if (nearestPoint[1] > rectangle.y + rectangle.height - rectangle.height * 0.15) {
const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height - rectangle.height * 0.15] as Point;
const nearestPoint = getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height * 0.15);
if (nearestPoint[1] < centerPoint[1]) {
nearestPoint[1] = centerPoint[0] * 2 - nearestPoint[1];
}
return nearestPoint;
}
return nearestPoint;
},

getConnectorPoints(rectangle: RectangleClient) {
return RectangleClient.getEdgeCenterPoints(rectangle);
},

getTangentVectorByConnectionPoint(rectangle: RectangleClient, pointOfRectangle: PointOfRectangle) {
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
let centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height - rectangle.height * 0.15];
let a = rectangle.width / 2;
let b = rectangle.height * 0.15;
const isInTopEllipse = connectionPoint[1] < rectangle.y + rectangle.height * 0.15 && connectionPoint[0] > rectangle.x;
if (isInTopEllipse) {
centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * 0.15];
}
const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
const slope = getEllipseTangentSlope(point[0], point[1], a, b) as any;
const vector = getVectorFromPointAndSlope(point[0], point[1], slope);
return vector;
},

getTextRectangle: (element: PlaitGeometry) => {
const elementRectangle = RectangleClient.getRectangleByPoints(element.points!);
const strokeWidth = getStrokeWidthByElement(element);
const height = element.textHeight;
const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
return {
height,
width: width > 0 ? width : 0,
x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
y: elementRectangle.y + elementRectangle.height * 0.3 + (elementRectangle.height - elementRectangle.height * 0.45 - height) / 2
};
}
};
120 changes: 120 additions & 0 deletions packages/draw/src/engines/flowchart/hard-disk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {
PlaitBoard,
Point,
PointOfRectangle,
RectangleClient,
getEllipseTangentSlope,
getNearestPointBetweenPointAndEllipse,
getNearestPointBetweenPointAndSegments,
getVectorFromPointAndSlope,
isPointInEllipse,
setStrokeLinecap
} from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { ShapeDefaultSpace } from '../../constants';
import { getStrokeWidthByElement } from '../../utils/style/stroke';
import { Options } from 'roughjs/bin/core';
import { RectangleEngine } from '../basic-shapes/rectangle';

export const HardDiskEngine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
const rs = PlaitBoard.getRoughSVG(board);
const shape = rs.path(
`M${rectangle.x + rectangle.width - rectangle.width * 0.15} ${rectangle.y}
A${rectangle.width * 0.15} ${rectangle.height / 2}, 0, 0, 0,${rectangle.x +
rectangle.width -
rectangle.width * 0.15} ${rectangle.y + rectangle.height}
A${rectangle.width * 0.15} ${rectangle.height / 2}, 0, 0, 0,${rectangle.x + rectangle.width - rectangle.width * 0.15} ${
rectangle.y
}
H${rectangle.x + rectangle.width * 0.15}
A${rectangle.width * 0.15} ${rectangle.height / 2}, 0, 0, 0, ${rectangle.x + rectangle.width * 0.15} ${rectangle.y +
rectangle.height}
H${rectangle.x + rectangle.width - rectangle.width * 0.15}`,
{ ...options, fillStyle: 'solid' }
);
setStrokeLinecap(shape, 'round');
return shape;
},
isInsidePoint(rectangle: RectangleClient, point: Point) {
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
const isInRectangle = RectangleClient.isHit(
{
...rectangle,
x: rectangle.x + rectangle.width * 0.15,
width: rectangle.width - rectangle.width * 0.3
},
rangeRectangle
);

const isInLeftEllipse = isPointInEllipse(
point,
[rectangle.x + rectangle.width * 0.15, rectangle.y + rectangle.height / 2],
rectangle.width * 0.15,
rectangle.height / 2
);

const isInRightEllipse = isPointInEllipse(
point,
[rectangle.x + rectangle.width - rectangle.width * 0.15, rectangle.y + rectangle.height / 2],
rectangle.width * 0.15,
rectangle.height / 2
);
return isInRectangle || isInLeftEllipse || isInRightEllipse;
},
getCornerPoints(rectangle: RectangleClient) {
return RectangleClient.getCornerPoints(rectangle);
},
getNearestPoint(rectangle: RectangleClient, point: Point) {
const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
if (nearestPoint[0] < rectangle.x + rectangle.width * 0.15) {
const centerPoint = [rectangle.x + rectangle.width * 0.15, rectangle.y + rectangle.height / 2] as Point;
const nearestPoint = getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width * 0.15, rectangle.height / 2);
if (nearestPoint[0] > centerPoint[0]) {
nearestPoint[0] = centerPoint[0] * 2 - nearestPoint[0];
}
return nearestPoint;
}
if (nearestPoint[0] > rectangle.x + rectangle.width - rectangle.width * 0.15) {
const centerPoint = [rectangle.x + rectangle.width - rectangle.width * 0.15, rectangle.y + rectangle.height / 2] as Point;
const nearestPoint = getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width * 0.15, rectangle.height / 2);
if (nearestPoint[0] < centerPoint[0]) {
nearestPoint[0] = centerPoint[0] * 2 - nearestPoint[0];
}
return nearestPoint;
}
return nearestPoint;
},
getConnectorPoints(rectangle: RectangleClient) {
return RectangleClient.getEdgeCenterPoints(rectangle);
},

getTangentVectorByConnectionPoint(rectangle: RectangleClient, pointOfRectangle: PointOfRectangle) {
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
let centerPoint = [rectangle.x + rectangle.width * 0.15, rectangle.y + rectangle.height / 2];
let a = rectangle.width * 0.15;
let b = rectangle.height / 2;
const isInRightEllipse =
connectionPoint[0] > rectangle.x + rectangle.width - rectangle.width * 0.15 && connectionPoint[1] > rectangle.y;
if (isInRightEllipse) {
centerPoint = [rectangle.x + rectangle.width - rectangle.width * 0.15, rectangle.y + rectangle.height / 2];
}
const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
const slope = getEllipseTangentSlope(point[0], point[1], a, b) as any;
const vector = getVectorFromPointAndSlope(point[0], point[1], slope);
return vector;
},

getTextRectangle: (element: PlaitGeometry) => {
const elementRectangle = RectangleClient.getRectangleByPoints(element.points!);
const strokeWidth = getStrokeWidthByElement(element);
const height = element.textHeight;
const width = elementRectangle.width - elementRectangle.width * 0.45 - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
return {
height,
width: width > 0 ? width : 0,
x: elementRectangle.x + elementRectangle.width * 0.15 + ShapeDefaultSpace.rectangleAndText + strokeWidth,
y: elementRectangle.y + (elementRectangle.height - height) / 2
};
}
};
59 changes: 59 additions & 0 deletions packages/draw/src/engines/flowchart/internal-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
PlaitBoard,
Point,
PointOfRectangle,
RectangleClient,
getNearestPointBetweenPointAndSegments,
setStrokeLinecap
} from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { ShapeDefaultSpace } from '../../constants';
import { getStrokeWidthByElement } from '../../utils/style/stroke';
import { Options } from 'roughjs/bin/core';
import { RectangleEngine } from '../basic-shapes/rectangle';
import { getPolygonEdgeByConnectionPoint } from '../../utils/polygon';

export const InternalStorageEngine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
const rs = PlaitBoard.getRoughSVG(board);
const shape = rs.path(
`M${rectangle.x} ${rectangle.y} h${rectangle.width} v${rectangle.height} h${-rectangle.width} v${-rectangle.height}
M${rectangle.x} ${rectangle.y + rectangle.height / 10} h${rectangle.width}
M${rectangle.x + rectangle.width / 10} ${rectangle.y} v${rectangle.height}
`,
{ ...options, fillStyle: 'solid' }
);
setStrokeLinecap(shape, 'round');
return shape;
},
isInsidePoint(rectangle: RectangleClient, point: Point) {
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
return RectangleClient.isHit(rectangle, rangeRectangle);
},
getCornerPoints(rectangle: RectangleClient) {
return RectangleClient.getCornerPoints(rectangle);
},
getNearestPoint(rectangle: RectangleClient, point: Point) {
return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
},
getEdgeByConnectionPoint(rectangle: RectangleClient, pointOfRectangle: PointOfRectangle): [Point, Point] | null {
const corners = RectangleEngine.getCornerPoints(rectangle);
const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
return getPolygonEdgeByConnectionPoint(corners, point);
},
getConnectorPoints(rectangle: RectangleClient) {
return RectangleClient.getEdgeCenterPoints(rectangle);
},
getTextRectangle: (element: PlaitGeometry) => {
const elementRectangle = RectangleClient.getRectangleByPoints(element.points!);
const strokeWidth = getStrokeWidthByElement(element);
const height = element.textHeight;
const width = elementRectangle.width - elementRectangle.width * 0.1 - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
return {
height,
width: width > 0 ? width : 0,
x: elementRectangle.x + elementRectangle.width * 0.1 + ShapeDefaultSpace.rectangleAndText + strokeWidth,
y: elementRectangle.y + elementRectangle.height * 0.1 + (elementRectangle.height - elementRectangle.height * 0.1 - height) / 2
};
}
};
6 changes: 6 additions & 0 deletions packages/draw/src/engines/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import { OrEngine } from './flowchart/or';
import { SummingJunctionEngine } from './flowchart/summing-junction';
import { DocumentEngine } from './flowchart/document';
import { MultiDocumentEngine } from './flowchart/multi-document';
import { DatabaseEngine } from './flowchart/database';
import { HardDiskEngine } from './flowchart/hard-disk';
import { InternalStorageEngine } from './flowchart/internal-storage';
import { NoteCurlyLeftEngine } from './flowchart/note-curly-left';
import { NoteCurlyRightEngine } from './flowchart/note-curly-right';
import { NoteSquareEngine } from './flowchart/note-square';
Expand Down Expand Up @@ -63,6 +66,9 @@ export const ShapeEngineMap: Record<GeometryShapes, ShapeEngine> = {
[FlowchartSymbols.connector]: EllipseEngine,
[FlowchartSymbols.data]: ParallelogramEngine,
[FlowchartSymbols.terminal]: TerminalEngine,
[FlowchartSymbols.database]: DatabaseEngine,
[FlowchartSymbols.hardDisk]: HardDiskEngine,
[FlowchartSymbols.internalStorage]: InternalStorageEngine,
[FlowchartSymbols.manualInput]: ManualInputEngine,
[FlowchartSymbols.preparation]: PreparationEngine,
[FlowchartSymbols.manualLoop]: ManualLoopEngine,
Expand Down
3 changes: 3 additions & 0 deletions packages/draw/src/interfaces/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export enum FlowchartSymbols {
offPage = 'offPage',
document = 'document',
multiDocument = 'multiDocument',
database = 'database',
hardDisk = 'hardDisk',
internalStorage = 'internalStorage',
noteCurlyRight = 'noteCurlyRight',
noteCurlyLeft = 'noteCurlyLeft',
noteSquare = 'noteSquare'
Expand Down
Loading

0 comments on commit fd05792

Please sign in to comment.