@plait/draw
Version:
Implementation of the core logic of the flowchart drawing tool plugin.
1 lines • 958 kB
Source Map (JSON)
{"version":3,"file":"plait-draw.mjs","sources":["../../../packages/draw/src/interfaces/geometry.ts","../../../packages/draw/src/interfaces/swimlane.ts","../../../packages/draw/src/interfaces/table.ts","../../../packages/draw/src/constants/default.ts","../../../packages/draw/src/constants/geometry.ts","../../../packages/draw/src/constants/pointer.ts","../../../packages/draw/src/constants/image.ts","../../../packages/draw/src/constants/theme.ts","../../../packages/draw/src/constants/swimlane.ts","../../../packages/draw/src/constants/text.ts","../../../packages/draw/src/constants/line.ts","../../../packages/draw/src/generators/text.generator.ts","../../../packages/draw/src/utils/table-selected.ts","../../../packages/draw/src/utils/table.ts","../../../packages/draw/src/utils/memorize.ts","../../../packages/draw/src/utils/arrow-line/arrow-line-resize.ts","../../../packages/draw/src/utils/arrow-line/arrow-line-arrow.ts","../../../packages/draw/src/generators/arrow-line.generator.ts","../../../packages/draw/src/utils/text-size.ts","../../../packages/draw/src/utils/arrow-line/arrow-line-basic.ts","../../../packages/draw/src/utils/position/arrow-line.ts","../../../packages/draw/src/utils/multi-text-geometry.ts","../../../packages/draw/src/generators/vector-line-generator.ts","../../../packages/draw/src/utils/vector-line.ts","../../../packages/draw/src/utils/polygon.ts","../../../packages/draw/src/engines/basic-shapes/cloud.ts","../../../packages/draw/src/utils/hit.ts","../../../packages/draw/src/utils/common.ts","../../../packages/draw/src/utils/style/stroke.ts","../../../packages/draw/src/generators/geometry-shape.generator.ts","../../../packages/draw/src/utils/line.ts","../../../packages/draw/src/utils/position/line.ts","../../../packages/draw/src/generators/line-active.generator.ts","../../../packages/draw/src/generators/arrow-line-auto-complete.generator.ts","../../../packages/draw/src/generators/single-text.generator.ts","../../../packages/draw/src/generators/table.generator.ts","../../../packages/draw/src/utils/shape.ts","../../../packages/draw/src/utils/uml.ts","../../../packages/draw/src/utils/geometry.ts","../../../packages/draw/src/utils/arrow-line/elbow.ts","../../../packages/draw/src/utils/selected.ts","../../../packages/draw/src/transforms/geometry.ts","../../../packages/draw/src/transforms/geometry-text.ts","../../../packages/draw/src/transforms/image.ts","../../../packages/draw/src/transforms/arrow-line.ts","../../../packages/draw/src/utils/swimlane.ts","../../../packages/draw/src/transforms/swimlane.ts","../../../packages/draw/src/transforms/multi-text-geometry-text.ts","../../../packages/draw/src/transforms/table-text.ts","../../../packages/draw/src/transforms/table.ts","../../../packages/draw/src/transforms/vector-line.ts","../../../packages/draw/src/transforms/common.ts","../../../packages/draw/src/transforms/index.ts","../../../packages/draw/src/utils/position/geometry.ts","../../../packages/draw/src/plugins/with-draw-resize.ts","../../../packages/draw/src/utils/snap-resizing.ts","../../../packages/draw/src/utils/clipboard.ts","../../../packages/draw/src/engines/basic-shapes/comment.ts","../../../packages/draw/src/engines/basic-shapes/polygon.ts","../../../packages/draw/src/engines/basic-shapes/cross.ts","../../../packages/draw/src/engines/basic-shapes/diamond.ts","../../../packages/draw/src/engines/basic-shapes/ellipse.ts","../../../packages/draw/src/engines/basic-shapes/hexagon.ts","../../../packages/draw/src/engines/basic-shapes/left-arrow.ts","../../../packages/draw/src/engines/basic-shapes/octagon.ts","../../../packages/draw/src/engines/basic-shapes/parallelogram.ts","../../../packages/draw/src/engines/basic-shapes/pentagon.ts","../../../packages/draw/src/engines/basic-shapes/pentagon-arrow.ts","../../../packages/draw/src/engines/basic-shapes/process-arrow.ts","../../../packages/draw/src/engines/basic-shapes/right-arrow.ts","../../../packages/draw/src/engines/basic-shapes/rectangle.ts","../../../packages/draw/src/engines/basic-shapes/round-rectangle.ts","../../../packages/draw/src/engines/basic-shapes/round-comment.ts","../../../packages/draw/src/engines/basic-shapes/trapezoid.ts","../../../packages/draw/src/engines/basic-shapes/triangle.ts","../../../packages/draw/src/engines/basic-shapes/two-way-arrow.ts","../../../packages/draw/src/engines/basic-shapes/star.ts","../../../packages/draw/src/engines/flowchart/terminal.ts","../../../packages/draw/src/engines/flowchart/manual-input.ts","../../../packages/draw/src/engines/flowchart/preparation.ts","../../../packages/draw/src/engines/flowchart/manual-loop.ts","../../../packages/draw/src/engines/flowchart/merge.ts","../../../packages/draw/src/engines/flowchart/delay.ts","../../../packages/draw/src/engines/flowchart/stored-data.ts","../../../packages/draw/src/engines/flowchart/predefined-process.ts","../../../packages/draw/src/engines/flowchart/off-page.ts","../../../packages/draw/src/engines/flowchart/or.ts","../../../packages/draw/src/engines/flowchart/summing-junction.ts","../../../packages/draw/src/engines/flowchart/document.ts","../../../packages/draw/src/engines/flowchart/multi-document.ts","../../../packages/draw/src/engines/flowchart/database.ts","../../../packages/draw/src/engines/flowchart/hard-disk.ts","../../../packages/draw/src/engines/flowchart/internal-storage.ts","../../../packages/draw/src/engines/flowchart/note-curly-left.ts","../../../packages/draw/src/engines/flowchart/note-curly-right.ts","../../../packages/draw/src/engines/flowchart/note-square.ts","../../../packages/draw/src/engines/flowchart/display.ts","../../../packages/draw/src/engines/table/table.ts","../../../packages/draw/src/engines/uml/actor.ts","../../../packages/draw/src/engines/uml/container.ts","../../../packages/draw/src/engines/uml/package.ts","../../../packages/draw/src/engines/uml/combined-fragment.ts","../../../packages/draw/src/engines/uml/deletion.ts","../../../packages/draw/src/engines/uml/activity-class.ts","../../../packages/draw/src/engines/uml/note.ts","../../../packages/draw/src/engines/uml/assembly.ts","../../../packages/draw/src/engines/uml/required-interface.ts","../../../packages/draw/src/engines/uml/provided-interface.ts","../../../packages/draw/src/engines/uml/component.ts","../../../packages/draw/src/engines/uml/component-box.ts","../../../packages/draw/src/engines/uml/template.ts","../../../packages/draw/src/engines/index.ts","../../../packages/draw/src/utils/arrow-line/arrow-line-common.ts","../../../packages/draw/src/interfaces/arrow-line.ts","../../../packages/draw/src/interfaces/element.ts","../../../packages/draw/src/interfaces/vector-line.ts","../../../packages/draw/src/interfaces/index.ts","../../../packages/draw/src/geometry.component.ts","../../../packages/draw/src/arrow-line.component.ts","../../../packages/draw/src/vector-line.component.ts","../../../packages/draw/src/plugins/with-draw-hotkey.ts","../../../packages/draw/src/plugins/with-geometry-create.ts","../../../packages/draw/src/plugins/with-draw-fragment.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-create.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-resize.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-bound-reaction.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-text.ts","../../../packages/draw/src/image.component.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-auto-complete.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-auto-complete-reaction.ts","../../../packages/draw/src/plugins/arrow-line/with-arrow-line-text-move.ts","../../../packages/draw/src/plugins/with-draw-rotate.ts","../../../packages/draw/src/table.component.ts","../../../packages/draw/src/plugins/with-table-resize.ts","../../../packages/draw/src/plugins/with-table.ts","../../../packages/draw/src/plugins/with-swimlane-create.ts","../../../packages/draw/src/plugins/with-swimlane.ts","../../../packages/draw/src/plugins/with-vector-line-create.ts","../../../packages/draw/src/plugins/with-vector-line-resize.ts","../../../packages/draw/src/plugins/with-draw.ts","../../../packages/draw/src/plait-draw.ts"],"sourcesContent":["import { PlaitElement, Point } from '@plait/core';\nimport { DrawTextInfo } from '../generators/text.generator';\nimport { ParagraphElement, StrokeStyle } from '@plait/common';\n\nexport enum BasicShapes {\n rectangle = 'rectangle',\n ellipse = 'ellipse',\n diamond = 'diamond',\n roundRectangle = 'roundRectangle',\n parallelogram = 'parallelogram',\n text = 'text',\n triangle = 'triangle',\n leftArrow = 'leftArrow',\n trapezoid = 'trapezoid',\n rightArrow = 'rightArrow',\n cross = 'cross',\n star = 'star',\n pentagon = 'pentagon',\n hexagon = 'hexagon',\n octagon = 'octagon',\n pentagonArrow = 'pentagonArrow',\n processArrow = 'processArrow',\n twoWayArrow = 'twoWayArrow',\n comment = 'comment',\n roundComment = 'roundComment',\n cloud = 'cloud'\n}\n\nexport enum FlowchartSymbols {\n process = 'process',\n decision = 'decision',\n data = 'data',\n connector = 'connector',\n terminal = 'terminal',\n manualInput = 'manualInput',\n preparation = 'preparation',\n manualLoop = 'manualLoop',\n merge = 'merge',\n delay = 'delay',\n storedData = 'storedData',\n or = 'or',\n summingJunction = 'summingJunction',\n predefinedProcess = 'predefinedProcess',\n offPage = 'offPage',\n document = 'document',\n multiDocument = 'multiDocument',\n database = 'database',\n hardDisk = 'hardDisk',\n internalStorage = 'internalStorage',\n noteCurlyRight = 'noteCurlyRight',\n noteCurlyLeft = 'noteCurlyLeft',\n noteSquare = 'noteSquare',\n display = 'display'\n}\n\nexport enum UMLSymbols {\n actor = 'actor',\n useCase = 'useCase',\n container = 'container',\n note = 'note',\n simpleClass = 'simpleClass',\n activityClass = 'activityClass',\n branchMerge = 'branchMerge',\n port = 'port',\n package = 'package',\n combinedFragment = 'combinedFragment',\n class = 'class',\n interface = 'interface',\n object = 'object',\n component = 'component',\n componentBox = 'componentBox',\n template = 'template',\n activation = 'activation',\n deletion = 'deletion',\n assembly = 'assembly',\n providedInterface = 'providedInterface',\n requiredInterface = 'requiredInterface'\n}\n\nexport enum GeometryCommonTextKeys {\n name = 'name',\n content = 'content'\n}\n\nexport type GeometryShapes = BasicShapes | FlowchartSymbols | UMLSymbols;\n\nexport type SwimlaneDirection = 'horizontal' | 'vertical';\n\nexport interface PlaitBaseGeometry<T extends string = 'geometry', P extends Point[] = [Point, Point], S extends string = GeometryShapes>\n extends PlaitElement {\n type: T;\n points: P;\n shape: S;\n}\n\nexport interface PlaitCommonGeometry<T extends string = 'geometry', P extends Point[] = [Point, Point], S extends string = GeometryShapes>\n extends PlaitBaseGeometry<T, P, S> {\n // node style attributes\n fill?: string;\n strokeColor?: string;\n strokeWidth?: number;\n strokeStyle?: StrokeStyle;\n angle?: number;\n opacity?: number;\n}\n\nexport interface PlaitCustomGeometry<T extends string = string, P extends Point[] = Point[], S extends string = string>\n extends PlaitBaseGeometry<T, P, S> {}\n\nexport interface PlaitMultipleTextGeometry extends PlaitCommonGeometry {\n texts: DrawTextInfo[];\n}\n\nexport interface PlaitGeometry extends PlaitCommonGeometry {\n text?: ParagraphElement;\n}\n\nexport interface PlaitRectangle extends PlaitGeometry {\n shape: BasicShapes.rectangle;\n}\n\nexport interface PlaitEllipse extends PlaitGeometry {\n shape: BasicShapes.ellipse;\n}\n\nexport interface PlaitDiamond extends PlaitGeometry {\n shape: BasicShapes.diamond;\n}\n\nexport const PlaitGeometry = {};\n","import { PlaitBaseTable } from './table';\n\nexport enum SwimlaneSymbols {\n swimlaneVertical = 'swimlaneVertical',\n swimlaneHorizontal = 'swimlaneHorizontal'\n}\n\nexport enum SwimlaneDrawSymbols {\n swimlaneVertical = 'swimlaneVertical',\n swimlaneHorizontal = 'swimlaneHorizontal',\n swimlaneVerticalWithHeader = 'swimlaneVerticalWithHeader',\n swimlaneHorizontalWithHeader = 'swimlaneHorizontalWithHeader'\n}\n\nexport interface PlaitSwimlane extends PlaitBaseTable {\n type: 'swimlane';\n shape: SwimlaneSymbols;\n header?: boolean;\n}\n\nexport interface PlaitSwimlaneVertical extends PlaitSwimlane {\n shape: SwimlaneSymbols.swimlaneVertical;\n}\n\nexport interface PlaitSwimlaneHorizontal extends PlaitSwimlane {\n shape: SwimlaneSymbols.swimlaneHorizontal;\n}\n","import { PlaitBoard, PlaitElement, Point } from '@plait/core';\nimport { ParagraphElement } from '@plait/common';\nimport { DrawOptions } from './engine';\n\nexport enum TableSymbols {\n table = 'table'\n}\n\nexport interface PlaitTableBoard extends PlaitBoard {\n buildTable: (element: PlaitBaseTable) => PlaitBaseTable;\n}\n\nexport interface PlaitBaseTable extends PlaitElement {\n id: string;\n points: Point[];\n rows: {\n id: string;\n height?: number;\n }[];\n columns: {\n id: string;\n width?: number;\n }[];\n cells: PlaitTableCell[];\n groupId?: string;\n}\n\nexport interface PlaitTable extends PlaitBaseTable {\n type: 'table';\n}\n\nexport interface PlaitTableCell {\n id: string;\n rowId: string;\n columnId: string;\n colspan?: number;\n rowspan?: number;\n text?: PlaitTableCellParagraph;\n fill?: string;\n}\n\nexport interface PlaitTableDrawOptions extends DrawOptions {\n element: PlaitTable;\n}\n\nexport interface PlaitTableCellWithPoints extends PlaitTableCell {\n points: [Point, Point];\n}\n\nexport interface PlaitTableCellParagraph extends ParagraphElement {\n direction?: 'vertical' | 'horizontal';\n}\n\nexport const PlaitTableElement = {\n isTable: (value: any): value is PlaitTable => {\n return value.type === 'table';\n },\n isVerticalText: (value: PlaitTableCell): value is PlaitTableCell => {\n return value.text?.direction === 'vertical';\n }\n};\n","export const WithDrawPluginKey = 'plait-draw-plugin-key';\n\nexport enum DrawI18nKey {\n lineText = 'line-text',\n geometryText = 'geometry-text'\n}","import { ACTIVE_STROKE_WIDTH, DEFAULT_COLOR } from '@plait/core';\nimport { BasicShapes, FlowchartSymbols, GeometryShapes, GeometryCommonTextKeys, UMLSymbols } from '../interfaces';\nimport { Alignment, DEFAULT_FILL } from '@plait/common';\n\nexport const ShapeDefaultSpace = {\n rectangleAndText: 4\n};\n\nexport const DefaultDrawStyle = {\n strokeWidth: 2,\n defaultRadius: 4,\n strokeColor: '#000',\n fill: DEFAULT_FILL\n};\n\nexport const DefaultDrawActiveStyle = {\n strokeWidth: ACTIVE_STROKE_WIDTH,\n selectionStrokeWidth: ACTIVE_STROKE_WIDTH\n};\n\nexport const DefaultBasicShapeProperty = {\n width: 100,\n height: 100,\n strokeColor: DEFAULT_COLOR,\n strokeWidth: 2\n};\n\nexport const DefaultPentagonArrowProperty = {\n width: 120,\n height: 50\n};\n\nexport const DefaultTwoWayArrowProperty = {\n width: 138,\n height: 80\n};\n\nexport const DefaultArrowProperty = {\n width: 100,\n height: 80\n};\n\nexport const DefaultCloudProperty = {\n width: 120,\n height: 100\n};\n\nexport const DefaultTextProperty = {\n width: 36,\n height: 20,\n text: '文本'\n};\n\nexport const GeometryThreshold = {\n defaultTextMaxWidth: 34 * 14\n};\n\nexport const DefaultConnectorProperty = {\n width: 44,\n height: 44\n};\n\nexport const DefaultFlowchartProperty = {\n width: 120,\n height: 60\n};\n\nexport const DefaultDataBaseProperty = {\n width: 70,\n height: 80\n};\n\nexport const DefaultInternalStorageProperty = {\n width: 80,\n height: 80\n};\n\nexport const DefaultDecisionProperty = {\n width: 140,\n height: 70\n};\n\nexport const DefaultDataProperty = {\n width: 124,\n height: 60\n};\n\nexport const DefaultDocumentProperty = {\n width: 120,\n height: 70\n};\n\nexport const DefaultNoteProperty = {\n width: 160,\n height: 100\n};\n\nexport const DefaultMultiDocumentProperty = {\n width: 120,\n height: 80\n};\n\nexport const DefaultManualInputProperty = {\n width: 117,\n height: 59\n};\n\nexport const DefaultMergeProperty = {\n width: 47,\n height: 33\n};\n\nexport const DefaultActorProperty = {\n width: 68,\n height: 100\n};\n\nexport const DefaultContainerProperty = {\n width: 300,\n height: 240\n};\n\nexport const DefaultPackageProperty = {\n width: 210,\n height: 150,\n texts: [\n {\n id: GeometryCommonTextKeys.name,\n text: '包名',\n align: Alignment.left\n },\n {\n id: GeometryCommonTextKeys.content,\n text: '',\n align: Alignment.left\n }\n ]\n};\n\nexport const DefaultActivationProperty = {\n width: 18,\n height: 80\n};\n\nexport const DefaultObjectProperty = {\n width: 120,\n height: 60\n};\n\nexport const DefaultComponentBoxProperty = {\n width: 200,\n height: 150\n};\n\nexport const DefaultDeletionProperty = {\n width: 40,\n height: 40\n};\n\nexport const DefaultPortProperty = {\n width: 20,\n height: 20\n};\n\nexport const DefaultRequiredInterfaceProperty = {\n width: 70,\n height: 56\n};\n\nexport const DefaultAssemblyProperty = {\n width: 120,\n height: 56\n};\n\nexport const DefaultProvidedInterfaceProperty = {\n width: 70,\n height: 34\n};\n\nexport const DefaultCombinedFragmentProperty = {\n width: 400,\n height: 280,\n texts: [\n {\n id: GeometryCommonTextKeys.name,\n text: 'Opt | Alt | Loop',\n align: Alignment.left\n },\n {\n id: GeometryCommonTextKeys.content,\n text: '[Condition]',\n align: Alignment.left\n }\n ]\n};\n\nexport const DefaultClassProperty = {\n width: 230,\n height: 180,\n texts: [\n { text: 'Class', align: Alignment.center },\n {\n text: '+ attribute1:type defaultValue\\n+ attribute2:type\\n- attribute3:type',\n align: Alignment.left\n },\n {\n text: '+ operation1(params):returnType\\n- operation2(params)\\n- operation3()',\n align: Alignment.left\n }\n ]\n};\n\nexport const DefaultInterfaceProperty = {\n width: 230,\n height: 140,\n texts: [\n { text: '<<interface>>\\nInterface', align: Alignment.center },\n {\n text: '+ operation1(params):returnType\\n- operation2(params)\\n- operation3()',\n align: Alignment.left\n }\n ]\n};\n\nexport const DefaultBasicShapePropertyMap: Record<string, { width: number; height: number }> = {\n [BasicShapes.pentagonArrow]: DefaultPentagonArrowProperty,\n [BasicShapes.processArrow]: DefaultPentagonArrowProperty,\n [BasicShapes.cloud]: DefaultCloudProperty,\n [BasicShapes.twoWayArrow]: DefaultTwoWayArrowProperty,\n [BasicShapes.leftArrow]: DefaultArrowProperty,\n [BasicShapes.rightArrow]: DefaultArrowProperty\n};\n\nexport const DefaultFlowchartPropertyMap = {\n [FlowchartSymbols.connector]: DefaultConnectorProperty,\n [FlowchartSymbols.process]: DefaultFlowchartProperty,\n [FlowchartSymbols.decision]: DefaultDecisionProperty,\n [FlowchartSymbols.data]: DefaultDataProperty,\n [FlowchartSymbols.terminal]: DefaultFlowchartProperty,\n [FlowchartSymbols.manualInput]: DefaultManualInputProperty,\n [FlowchartSymbols.preparation]: DefaultFlowchartProperty,\n [FlowchartSymbols.manualLoop]: DefaultFlowchartProperty,\n [FlowchartSymbols.merge]: DefaultMergeProperty,\n [FlowchartSymbols.delay]: DefaultFlowchartProperty,\n [FlowchartSymbols.storedData]: DefaultFlowchartProperty,\n [FlowchartSymbols.or]: DefaultConnectorProperty,\n [FlowchartSymbols.summingJunction]: DefaultConnectorProperty,\n [FlowchartSymbols.predefinedProcess]: DefaultFlowchartProperty,\n [FlowchartSymbols.offPage]: DefaultFlowchartProperty,\n [FlowchartSymbols.document]: DefaultDocumentProperty,\n [FlowchartSymbols.multiDocument]: DefaultMultiDocumentProperty,\n [FlowchartSymbols.database]: DefaultDataBaseProperty,\n [FlowchartSymbols.hardDisk]: DefaultFlowchartProperty,\n [FlowchartSymbols.internalStorage]: DefaultInternalStorageProperty,\n [FlowchartSymbols.noteCurlyLeft]: DefaultNoteProperty,\n [FlowchartSymbols.noteCurlyRight]: DefaultNoteProperty,\n [FlowchartSymbols.noteSquare]: DefaultNoteProperty,\n [FlowchartSymbols.display]: DefaultFlowchartProperty\n};\n\nexport const DefaultUMLPropertyMap = {\n [UMLSymbols.actor]: DefaultActorProperty,\n [UMLSymbols.useCase]: DefaultDocumentProperty,\n [UMLSymbols.container]: DefaultContainerProperty,\n [UMLSymbols.note]: DefaultObjectProperty,\n [UMLSymbols.package]: DefaultPackageProperty,\n [UMLSymbols.combinedFragment]: DefaultCombinedFragmentProperty,\n [UMLSymbols.class]: DefaultClassProperty,\n [UMLSymbols.interface]: DefaultInterfaceProperty,\n [UMLSymbols.activation]: DefaultActivationProperty,\n [UMLSymbols.object]: DefaultObjectProperty,\n [UMLSymbols.deletion]: DefaultDeletionProperty,\n [UMLSymbols.activityClass]: DefaultObjectProperty,\n [UMLSymbols.simpleClass]: DefaultObjectProperty,\n [UMLSymbols.component]: DefaultMultiDocumentProperty,\n [UMLSymbols.template]: DefaultMultiDocumentProperty,\n [UMLSymbols.componentBox]: DefaultComponentBoxProperty,\n [UMLSymbols.port]: DefaultPortProperty,\n [UMLSymbols.branchMerge]: DefaultDeletionProperty,\n [UMLSymbols.assembly]: DefaultAssemblyProperty,\n [UMLSymbols.providedInterface]: DefaultProvidedInterfaceProperty,\n [UMLSymbols.requiredInterface]: DefaultRequiredInterfaceProperty\n};\n\nexport const MultipleTextGeometryTextKeys: { [key in GeometryShapes]?: string[] } = {\n [UMLSymbols.package]: Object.keys(GeometryCommonTextKeys),\n [UMLSymbols.combinedFragment]: Object.keys(GeometryCommonTextKeys)\n};\n\nexport const LINE_HIT_GEOMETRY_BUFFER = 4;\n\nexport const LINE_SNAPPING_BUFFER = 4;\n\nexport const LINE_SNAPPING_CONNECTOR_BUFFER = 4;\n\nexport const LINE_ALIGN_TOLERANCE = 4;\n\nexport const GEOMETRY_WITHOUT_TEXT = [\n FlowchartSymbols.or,\n FlowchartSymbols.summingJunction,\n UMLSymbols.activation,\n UMLSymbols.deletion,\n UMLSymbols.port,\n UMLSymbols.branchMerge,\n UMLSymbols.assembly,\n UMLSymbols.providedInterface,\n UMLSymbols.requiredInterface\n] as GeometryShapes[];\n\nexport const GEOMETRY_WITH_MULTIPLE_TEXT = [UMLSymbols.package, UMLSymbols.combinedFragment];\n\nexport const GEOMETRY_NOT_CLOSED = [\n FlowchartSymbols.noteCurlyLeft,\n FlowchartSymbols.noteCurlyRight,\n FlowchartSymbols.noteSquare,\n UMLSymbols.requiredInterface,\n UMLSymbols.deletion\n] as GeometryShapes[];\n","import {\n BasicShapes,\n FlowchartSymbols,\n ArrowLineShape,\n SwimlaneDrawSymbols,\n TableSymbols,\n UMLSymbols,\n VectorLinePointerType,\n SwimlaneSymbols\n} from '../interfaces';\n\nexport type DrawPointerType =\n | BasicShapes\n | ArrowLineShape\n | FlowchartSymbols\n | SwimlaneDrawSymbols\n | TableSymbols\n | UMLSymbols\n | VectorLinePointerType;\n\nexport const getGeometryPointers = () => {\n return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols), ...Object.keys(UMLSymbols)];\n};\n\nexport const getSwimlanePointers = () => {\n return Object.keys(SwimlaneDrawSymbols);\n};\n\nexport const getSwimlaneShapes = () => {\n return Object.keys(SwimlaneSymbols);\n};\n\nexport const getBasicPointers = () => {\n return Object.keys(BasicShapes);\n};\n\nexport const getFlowchartPointers = () => {\n return Object.keys(FlowchartSymbols);\n};\n\nexport const getUMLPointers = () => {\n return Object.keys(UMLSymbols);\n};\n\nexport const getArrowLinePointers = () => {\n return Object.keys(ArrowLineShape);\n};\n\nexport const getVectorLinePointers = () => {\n return Object.keys(VectorLinePointerType);\n};\n","export const DEFAULT_IMAGE_WIDTH = 1000;\n","import { DEFAULT_COLOR, ThemeColorMode } from '@plait/core';\n\nexport const DrawThemeColors = {\n [ThemeColorMode.default]: {\n strokeColor: DEFAULT_COLOR,\n fill: '#FFFFFF'\n },\n [ThemeColorMode.colorful]: {\n strokeColor: '#06ADBF',\n fill: '#CDEFF2'\n },\n [ThemeColorMode.soft]: {\n strokeColor: '#6D89C1',\n fill: '#DADFEB'\n },\n [ThemeColorMode.retro]: {\n strokeColor: '#E9C358',\n fill: '#F6EDCF'\n },\n [ThemeColorMode.dark]: {\n strokeColor: '#FFFFFF',\n fill: '#434343'\n },\n [ThemeColorMode.starry]: {\n strokeColor: '#42ABE5',\n fill: '#163F5A'\n }\n};\n","import { SwimlaneDrawSymbols } from '../interfaces/swimlane';\n\nexport const SWIMLANE_HEADER_SIZE = 42;\n\nexport const DefaultSwimlaneVerticalWithHeaderProperty = {\n width: 580,\n height: 524\n};\n\nexport const DefaultSwimlaneHorizontalWithHeaderProperty = {\n width: 524,\n height: 580\n};\n\nexport const DefaultSwimlaneVerticalProperty = {\n width: 580,\n height: 524\n};\n\nexport const DefaultSwimlaneHorizontalProperty = {\n width: 524,\n height: 580\n};\n\nexport const DefaultSwimlanePropertyMap: Record<string, { width: number; height: number }> = {\n [SwimlaneDrawSymbols.swimlaneHorizontal]: DefaultSwimlaneHorizontalProperty,\n [SwimlaneDrawSymbols.swimlaneVertical]: DefaultSwimlaneVerticalProperty,\n [SwimlaneDrawSymbols.swimlaneHorizontalWithHeader]: DefaultSwimlaneHorizontalWithHeaderProperty,\n [SwimlaneDrawSymbols.swimlaneVerticalWithHeader]: DefaultSwimlaneVerticalWithHeaderProperty\n};\n","export const MIN_TEXT_WIDTH = 5;\n","export const DefaultLineStyle = {\n strokeWidth: 2,\n strokeColor: '#000'\n};\n\nexport const LINE_TEXT_SPACE = 4;\n\nexport const LINE_AUTO_COMPLETE_DIAMETER = 6;\n\nexport const LINE_AUTO_COMPLETE_OPACITY = 1;\n\nexport const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 1;\n\nexport const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 12;\n\nexport const LINE_TEXT = '文本';\n","import {\n ParagraphElement,\n PlaitCommonElementRef,\n TextManage,\n TextManageChangeData,\n TextPlugin,\n WithTextPluginKey,\n WithTextPluginOptions\n} from '@plait/common';\nimport { PlaitBoard, PlaitElement, PlaitOptionsBoard, RectangleClient } from '@plait/core';\nimport { getEngine } from '../engines';\nimport { DrawShapes, PlaitGeometry, TextRectangleOptions } from '../interfaces';\nimport { getTextKey, getTextRectangle } from '../utils';\n\nexport interface DrawTextInfo extends TextRectangleOptions {\n text: ParagraphElement;\n}\n\nexport interface TextGeneratorOptions<T> {\n onChange: (element: T, textChangeRef: TextManageChangeData, text: DrawTextInfo) => void;\n getRenderRectangle?: (element: T, text: DrawTextInfo) => RectangleClient;\n getMaxWidth?: () => number;\n}\n\n// TODO: 是否可以完全基于位置定位 TextManager,实现 line 和 多文本 geometry 统一\n// 一个元素有多个文本时,单纯通过位置无法获取 TextManage,因此这里单独通过 Map 保存关键字 key 和 TextManage 的对应关系\n// 1. 单文本元素 key 就是元素的 id\n// 2. 表格元素 key 是单元格的 id\n// 3. 符合 isMultipleTextGeometry 的元素,key 是元素 id + text.id (通常不是 id 而是文本位置的常量)\n// 4. arrow-line 和 vector-line 文本不依赖于 text.generator,基于 text 可以直接找到 TextManage\nexport const KEY_TO_TEXT_MANAGE: WeakMap<PlaitBoard, { [key: string]: TextManage }> = new WeakMap();\n\nexport const setTextManage = (board: PlaitBoard, element: PlaitElement, text: DrawTextInfo, textManage: TextManage) => {\n const textManages = KEY_TO_TEXT_MANAGE.get(board)!;\n return KEY_TO_TEXT_MANAGE.set(board, { ...textManages, [getTextKey(element, text)]: textManage });\n};\n\nexport const getTextManage = (board: PlaitBoard, element: PlaitElement | undefined, text: Pick<DrawTextInfo, 'id'>): TextManage => {\n const textManages = KEY_TO_TEXT_MANAGE.get(board)!;\n return textManages[getTextKey(element, text)];\n};\n\nexport const deleteTextManage = (board: PlaitBoard, key: string) => {\n const textManages = KEY_TO_TEXT_MANAGE.get(board)!;\n delete textManages[key];\n KEY_TO_TEXT_MANAGE.set(board, textManages);\n};\n\nexport class TextGenerator<T extends PlaitElement = PlaitGeometry> {\n protected board: PlaitBoard;\n\n protected element: T;\n\n protected texts: DrawTextInfo[];\n\n protected options: TextGeneratorOptions<T>;\n\n public textManages!: TextManage[];\n\n get shape(): DrawShapes {\n return this.element.shape || this.element.type;\n }\n\n constructor(board: PlaitBoard, element: T, texts: DrawTextInfo[], options: TextGeneratorOptions<T>) {\n this.board = board;\n this.texts = texts;\n this.element = element;\n this.options = options;\n }\n\n initialize() {\n const textPlugins = ((this.board as PlaitOptionsBoard).getPluginOptions<WithTextPluginOptions>(WithTextPluginKey) || {})\n .textPlugins;\n this.textManages = this.texts.map(text => {\n const textManage = this.createTextManage(text, textPlugins);\n setTextManage(this.board, this.element, text, textManage);\n return textManage;\n });\n const ref = PlaitElement.getElementRef<PlaitCommonElementRef>(this.element);\n ref.initializeTextManage(this.textManages);\n }\n\n draw(elementG: SVGElement) {\n const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);\n this.texts.forEach(drawShapeText => {\n const textManage = getTextManage(this.board, this.element, drawShapeText);\n if (drawShapeText.text && textManage) {\n textManage.draw(drawShapeText.text);\n elementG.append(textManage.g);\n (this.element.angle || this.element.angle === 0) && textManage.updateAngle(centerPoint, this.element.angle);\n }\n });\n }\n\n update(element: T, previousDrawShapeTexts: DrawTextInfo[], currentDrawShapeTexts: DrawTextInfo[], elementG: SVGElement) {\n this.element = element;\n\n const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element)!);\n const textPlugins = ((this.board as PlaitOptionsBoard).getPluginOptions<WithTextPluginOptions>(WithTextPluginKey) || {})\n .textPlugins;\n const removedTexts = previousDrawShapeTexts.filter(value => {\n return !currentDrawShapeTexts.find(item => item.id === value.id);\n });\n if (removedTexts.length) {\n removedTexts.forEach(item => {\n const textManage = getTextManage(this.board, element, item);\n const index = this.textManages.findIndex(value => value === textManage);\n if (index > -1 && item.text) {\n this.textManages.splice(index, 1);\n }\n textManage?.destroy();\n deleteTextManage(this.board, item.id);\n });\n }\n currentDrawShapeTexts.forEach(drawShapeText => {\n if (drawShapeText.text) {\n let textManage = getTextManage(this.board, this.element, drawShapeText);\n if (!textManage) {\n textManage = this.createTextManage(drawShapeText, textPlugins);\n setTextManage(this.board, element, drawShapeText, textManage);\n textManage.draw(drawShapeText.text);\n elementG.append(textManage.g);\n this.textManages.push(textManage);\n } else {\n textManage.updateText(drawShapeText.text);\n textManage.updateRectangle();\n }\n (this.element.angle || this.element.angle === 0) && textManage.updateAngle(centerPoint, this.element.angle);\n }\n });\n }\n\n private createTextManage(text: DrawTextInfo, textPlugins?: TextPlugin[]) {\n const textManage = new TextManage(this.board, {\n getRectangle: () => {\n return this.getRectangle(text);\n },\n onChange: (data: TextManageChangeData) => {\n return this.options.onChange(this.element, data, text);\n },\n getMaxWidth: () => {\n return this.getMaxWidth(text);\n },\n getRenderRectangle: () => {\n return this.options.getRenderRectangle ? this.options.getRenderRectangle(this.element, text) : this.getRectangle(text);\n },\n textPlugins\n });\n return textManage;\n }\n\n getRectangle(text: DrawTextInfo) {\n const getRectangle = getEngine<T>(this.shape).getTextRectangle;\n if (getRectangle) {\n return getRectangle(this.board, this.element, text);\n }\n return getTextRectangle(this.board, this.element);\n }\n\n getMaxWidth(text: DrawTextInfo) {\n return this.options.getMaxWidth ? this.options.getMaxWidth() : this.getRectangle(text).width;\n }\n\n destroy() {\n const ref = PlaitElement.getElementRef<PlaitCommonElementRef>(this.element);\n ref.destroyTextManage();\n this.textManages = [];\n this.texts.forEach(item => {\n deleteTextManage(this.board, item.id);\n });\n }\n}\n","import { PlaitBoard, getSelectedElements, PlaitElement } from '@plait/core';\nimport { PlaitTableCell, PlaitBaseTable, PlaitTable } from '../interfaces/table';\nimport { PlaitDrawElement } from '../interfaces';\n\nexport const isSingleSelectTable = (board: PlaitBoard) => {\n const selectedElements = getSelectedElements(board);\n return selectedElements && selectedElements.length === 1 && PlaitDrawElement.isElementByTable(selectedElements[0]);\n};\n\nexport const getSelectedTableElements = (board: PlaitBoard, elements?: PlaitElement[]) => {\n const selectedElements = elements?.length ? elements : getSelectedElements(board);\n return selectedElements.filter(value => PlaitDrawElement.isElementByTable(value)) as PlaitTable[];\n};\n\nexport const SELECTED_CELLS = new WeakMap<PlaitBaseTable, PlaitTableCell[]>();\n\nexport function getSelectedCells(element: PlaitBaseTable) {\n return SELECTED_CELLS.get(element);\n}\n\nexport function setSelectedCells(element: PlaitBaseTable, cells: PlaitTableCell[]) {\n return SELECTED_CELLS.set(element, cells);\n}\n\nexport function clearSelectedCells(element: PlaitBaseTable) {\n return SELECTED_CELLS.delete(element);\n}\n","import { idCreator, PlaitBoard, Point, RectangleClient } from '@plait/core';\nimport { PlaitBaseTable, PlaitTable, PlaitTableBoard, PlaitTableCell, PlaitTableCellWithPoints } from '../interfaces/table';\nimport { getTextManage } from '../generators/text.generator';\nimport { Alignment } from '@plait/common';\nimport { TEXT_DEFAULT_HEIGHT } from '@plait/text-plugins';\nimport { getSelectedCells, getSelectedTableElements, isSingleSelectTable } from './table-selected';\nimport { BaseEditor } from 'slate';\n\nexport function getCellsWithPoints(board: PlaitBoard, element: PlaitBaseTable): PlaitTableCellWithPoints[] {\n const table = (board as PlaitTableBoard)?.buildTable(element);\n if (!table || !table.points || !table.columns || !table.rows) {\n throw new Error('can not get table cells points');\n }\n const rectangle = RectangleClient.getRectangleByPoints(table.points);\n const columnsCount = table.columns.length;\n const rowsCount = table.rows.length;\n const cellWidths = calculateCellsSize(table.columns, rectangle.width, columnsCount, true);\n const cellHeights = calculateCellsSize(table.rows, rectangle.height, rowsCount, false);\n const cells: PlaitTableCellWithPoints[] = table.cells.map(cell => {\n const rowIdx = table.rows.findIndex(row => row.id === cell.rowId);\n const columnIdx = table.columns.findIndex(column => column.id === cell.columnId);\n\n let cellTopLeftX = rectangle.x;\n for (let i = 0; i < columnIdx; i++) {\n cellTopLeftX += cellWidths[i];\n }\n\n let cellTopLeftY = rectangle.y;\n for (let i = 0; i < rowIdx; i++) {\n cellTopLeftY += cellHeights[i];\n }\n\n const cellWidth = calculateCellSize(cell, cellWidths, columnIdx, true);\n const cellBottomRightX = cellTopLeftX + cellWidth;\n\n const cellHeight = calculateCellSize(cell, cellHeights, rowIdx, false);\n const cellBottomRightY = cellTopLeftY + cellHeight;\n\n return {\n ...cell,\n points: [\n [cellTopLeftX, cellTopLeftY],\n [cellBottomRightX, cellBottomRightY]\n ]\n };\n });\n\n return cells;\n}\n\nexport function getCellWithPoints(board: PlaitBoard, table: PlaitBaseTable, cellId: string) {\n try {\n const cells = getCellsWithPoints(board as PlaitTableBoard, table);\n const cellIndex = cells && table.cells.findIndex(item => item.id === cellId);\n return cells[cellIndex];\n } catch (error) {\n throw new Error('can not get table cell points');\n }\n}\n\nfunction calculateCellsSize(items: { id: string; [key: string]: any }[], tableSize: number, count: number, isWidth: boolean) {\n const cellSizes: number[] = [];\n const sizeType = isWidth ? 'width' : 'height';\n\n // The remaining size of the table excluding cells with already set sizes.\n let totalSizeRemaining = tableSize;\n\n items.forEach((item, index) => {\n if (item[sizeType]) {\n cellSizes[index] = item[sizeType];\n totalSizeRemaining -= item[sizeType];\n }\n });\n\n // Divide the remaining size equally.\n const remainingItemCount = count - cellSizes.filter(item => !!item).length;\n const remainingCellSize = remainingItemCount > 0 ? totalSizeRemaining / remainingItemCount : 0;\n for (let i = 0; i < count; i++) {\n if (!cellSizes[i]) {\n cellSizes[i] = remainingCellSize;\n }\n }\n return cellSizes;\n}\n\nfunction calculateCellSize(cell: PlaitTableCell, sizes: number[], index: number, isWidth: boolean) {\n const span = isWidth ? cell.colspan || 1 : cell.rowspan || 1;\n let size = 0;\n for (let i = 0; i < span; i++) {\n const cellIndex = index + i;\n size += sizes[cellIndex];\n }\n return size;\n}\n\nexport function getHitCell(board: PlaitTableBoard, element: PlaitBaseTable, point: Point) {\n const table = board.buildTable(element);\n const cells = getCellsWithPoints(board, table);\n const rectangle = RectangleClient.getRectangleByPoints([point, point]);\n const cell = cells.find(item => {\n const cellRectangle = RectangleClient.getRectangleByPoints(item.points);\n return RectangleClient.isHit(rectangle, cellRectangle);\n });\n if (cell) {\n return table.cells.find(item => item.id === cell.id);\n }\n return null;\n}\n\nexport function editCell(board: PlaitBoard, cell: PlaitTableCell) {\n const textManage = getTextManageByCell(board, cell);\n textManage && textManage.edit();\n}\n\nexport function getTextManageByCell(board: PlaitBoard, cell: PlaitTableCell) {\n return getTextManage(board, undefined, cell);\n}\n\nexport const updateColumns = (table: PlaitBaseTable, columnId: string, width: number, offset: number) => {\n const columns = table.columns.map(item => (item.id === columnId ? { ...item, width } : item));\n const points = [table.points[0], [table.points[1][0] + offset, table.points[1][1]]] as Point[];\n return { columns, points };\n};\n\nexport const updateRows = (table: PlaitBaseTable, rowId: string, height: number, offset: number) => {\n const rows = table.rows.map(item => (item.id === rowId ? { ...item, height } : item));\n const points = [table.points[0], [table.points[1][0], table.points[1][1] + offset]] as Point[];\n return { rows, points };\n};\n\nexport function updateCellIdsByRowOrColumn(cells: PlaitTableCell[], oldId: string, newId: string, type: 'row' | 'column') {\n const id: 'rowId' | 'columnId' = `${type}Id`;\n cells.forEach(item => {\n if (item[id] === oldId) {\n item[id] = newId;\n }\n });\n}\n\nexport function updateRowOrColumnIds(element: PlaitTable, type: 'row' | 'column') {\n element[`${type}s`].forEach(item => {\n const newId = idCreator();\n updateCellIdsByRowOrColumn(element.cells, item.id, newId, type);\n item.id = newId;\n });\n}\n\nexport function updateCellIds(cells: PlaitTableCell[]) {\n cells.forEach(item => {\n const newId = idCreator();\n item.id = newId;\n });\n}\n\nexport function isCellIncludeText(cell: PlaitTableCell) {\n return cell.text;\n}\n\nexport function getCellsRectangle(board: PlaitTableBoard, element: PlaitTable, cells: PlaitTableCell[]) {\n const cellsWithPoints = getCellsWithPoints(board as PlaitTableBoard, element);\n const points = cells.map(cell => {\n const cellWithPoints = cellsWithPoints.find(item => item.id === cell.id);\n return cellWithPoints!.points;\n });\n return RectangleClient.getRectangleByPoints(points);\n}\n\nexport const createCell = (rowId: string, columnId: string, text: string | null = null) => {\n const cell: PlaitTableCell = {\n id: idCreator(),\n rowId,\n columnId\n };\n if (text !== null) {\n cell['text'] = {\n children: [{ text }],\n align: Alignment.center\n };\n }\n return cell;\n};\n\nexport const getSelectedTableCellsEditor = (board: PlaitBoard): BaseEditor[] | undefined => {\n if (isSingleSelectTable(board)) {\n const elements = getSelectedTableElements(board);\n const selectedCells = getSelectedCells(elements[0]);\n const selectedCellsEditor = selectedCells?.map(cell => {\n const textManage = getTextManageByCell(board, cell);\n return textManage?.editor;\n });\n if (selectedCellsEditor?.length) {\n return selectedCellsEditor as BaseEditor[];\n }\n }\n return undefined;\n};\n","import { PlaitBoard, PlaitElement } from '@plait/core';\nimport { BasicShapes, GeometryShapes, MemorizeKey, PlaitDrawElement } from '../interfaces';\nimport { getMemorizedLatest, memorizeLatest } from '@plait/common';\nimport { DrawPointerType } from '../constants';\nimport { BaseOperation, BaseSetNodeOperation, Node } from 'slate';\n\nconst SHAPE_MAX_LENGTH = 6;\nconst memorizedShape: WeakMap<PlaitBoard, GeometryShapes[]> = new WeakMap();\n\nexport const getMemorizeKey = (element: PlaitElement) => {\n let key = '';\n switch (true) {\n case PlaitDrawElement.isText(element): {\n key = MemorizeKey.text;\n break;\n }\n case PlaitDrawElement.isBasicShape(element): {\n key = MemorizeKey.basicShape;\n break;\n }\n case PlaitDrawElement.isFlowchart(element): {\n key = MemorizeKey.flowchart;\n break;\n }\n case PlaitDrawElement.isArrowLine(element): {\n key = MemorizeKey.arrowLine;\n break;\n }\n case PlaitDrawElement.isUML(element): {\n key = MemorizeKey.UML;\n }\n }\n return key;\n};\n\nexport const getLineMemorizedLatest = () => {\n const properties = getMemorizedLatest(MemorizeKey.arrowLine);\n return { ...properties };\n};\n\nexport const getMemorizedLatestByPointer = (pointer: DrawPointerType) => {\n let memorizeKey = '';\n if (PlaitDrawElement.isBasicShape({ shape: pointer })) {\n memorizeKey = pointer === BasicShapes.text ? MemorizeKey.text : MemorizeKey.basicShape;\n } else if (PlaitDrawElement.isUML({ shape: pointer })) {\n memorizeKey = MemorizeKey.UML;\n } else {\n memorizeKey = MemorizeKey.flowchart;\n }\n const properties = { ...getMemorizedLatest(memorizeKey) };\n const textProperties = { ...properties.text };\n delete properties.text;\n return { textProperties, geometryProperties: properties };\n};\n\nexport const memorizeLatestText = <T extends PlaitElement = PlaitDrawElement>(element: T, operations: BaseOperation[]) => {\n const memorizeKey = getMemorizeKey(element);\n let textMemory = getMemorizedLatest(memorizeKey)?.text || {};\n const setNodeOperation = operations.find((operation) => operation.type === 'set_node');\n if (setNodeOperation) {\n const { properties, newProperties } = setNodeOperation as BaseSetNodeOperation;\n for (const key in newProperties) {\n const value = newProperties[key as keyof Partial<Node>];\n if (value == null) {\n delete textMemory[key];\n } else {\n textMemory[key] = value;\n }\n }\n for (const key in properties) {\n if (!newProperties.hasOwnProperty(key)) {\n delete textMemory[key];\n }\n }\n memorizeLatest(memorizeKey, 'text', textMemory);\n }\n};\n\nexport const memorizeLatestShape = (board: PlaitBoard, shape: GeometryShapes) => {\n const shapes = memorizedShape.has(board) ? memorizedShape.get(board)! : [];\n const shapeIndex = shapes.indexOf(shape);\n if (shape === BasicShapes.text || shapeIndex === 0) {\n return;\n }\n if (shapeIndex !== -1) {\n shapes.splice(shapeIndex, 1);\n } else {\n if (shapes.length === SHAPE_MAX_LENGTH) {\n shapes.pop();\n }\n }\n shapes.unshift(shape);\n memorizedShape.set(board, shapes);\n};\n\nexport const getMemorizedLatestShape = (board: PlaitBoard) => {\n return memorizedShape.get(board);\n};\n","import { ElbowLineRouteOptions, ResizeState, generateElbowLineRoute, removeDuplicatePoints, simplifyOrthogonalPoints } from '@plait/common';\nimport { PlaitBoard, Point, RectangleClient, createDebugGenerator } from '@plait/core';\nimport { getElbowLineRouteOptions, getArrowLineHandleRefPair } from './arrow-line-common';\nimport { PlaitArrowLine } from '../../interfaces';\nimport { LINE_ALIGN_TOLERANCE } from '../../constants/geometry';\n\nconst debugKey = 'debug:plait:line-mirror';\nconst debugGenerator = createDebugGenerator(debugKey);\n\nexport const alignPoint = (basePoint: Point, movingPoint: Point) => {\n const newPoint: Point = [...movingPoint];\n if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {\n newPoint[0] = basePoint[0];\n }\n if (Point.isHorizontal(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {\n newPoint[1] = basePoint[1];\n }\n return newPoint;\n};\n\nexport const alignPoints = (basePoints: Point[], movingPoint: Point, targetIndex?: number) => {\n let newMovingPoint: Point = [...movingPoint];\n basePoints.forEach((basePoint, index) => {\n if (index === targetIndex) {\n return;\n }\n newMovingPoint = alignPoint(basePoint, newMovingPoint);\n });\n return newMovingPoint as Point;\n};\n\nexport function getResizedPreviousAndNextPoint(nextRenderPoints: Point[], sourcePoint: Point, targetPoint: Point, handleIndex: number) {\n const referencePoint: { previous: Point | null; next: Point | null } = {\n previous: null,\n next: null\n };\n\n const startPoint = nextRenderPoints[handleIndex];\n const endPoint = nextRenderPoints[handleIndex + 1];\n const isHorizontal = Point.isHorizontal(startPoint, endPoint);\n const isVertical = Point.isVertical(startPoint, endPoint);\n const previousPoint = nextRenderPoints[handleIndex - 1] ?? nextRenderPoints[0];\n const beforePreviousPoint = nextRenderPoints[handleIndex - 2] ?? sourcePoint;\n if (\n (isHorizontal && Point.isHorizontal(beforePreviousPoint, previousPoint)) ||\n (isVertical && Point.isVertical(beforePreviousPoint, previousPoint))\n ) {\n referencePoint.previous = previousPoint;\n }\n\n const nextPoint = nextRenderPoints[handleIndex + 2] ?? nextRenderPoints[nextRenderPoints.length - 1];\n const afterNextPoint = nextRenderPoints[handleIndex + 3] ?? targetPoint;\n if ((isHorizontal && Point.isHorizontal(nextPoint, afterNextPoint)) || (isVertical && Point.isVertical(nextPoint, afterNextPoint))) {\n referencePoint.next = nextPoint;\n }\n return referencePoint;\n}\n\nexport function alignElbowSegment(\n startKeyPoint: Point,\n endKeyPoint: Point,\n resizeState: ResizeState,\n resizedPreviousAndNextPoint: { previous: Point | null; next: Point | null }\n) {\n let newStartPoint = startKeyPoint;\n let newEndPoint = endKeyPoint;\n if (Point.isHorizontal(startKeyPoint, endKeyPoint)) {\n const offsetY = Point.getOffsetY(resizeState.startPoint, resizeState.endPoint);\n let pointY = startKeyPoint[1] + offsetY;\n if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPoint.previous[1] - pointY) < LINE_ALIGN_TOLERANCE) {\n pointY = resizedPreviousAndNextPoint.previous[1];\n } else if (resizedPreviousAndNextPoint.next && Math.abs(resizedPreviousAndNextPoint.next[1] - pointY) < LINE_ALIGN_TOLERANCE) {\n pointY = resizedPreviousAndNextPoint.next[1];\n }\n newStartPoint = [startKeyPoint[0], pointY];\n newEndPoint = [endKeyPoint[0], pointY];\n }\n if (Point.isVertical(startKeyPoint, endKeyPoint)) {\n const offsetX = Point.getOffsetX(resizeState.startPoint, resizeState.endPoint);\n let pointX = startKeyPoint[0] + offsetX;\n if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPo