@plait/draw 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
- import { PlaitElement, ACTIVE_STROKE_WIDTH, ThemeColorMode, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, BOARD_TO_HOST, transformPoint, toPoint, idCreator, createG, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, depthFirstRecursion, getIsRecursionFunc, getElementById, Direction, catmullRomFitting, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, isPolylineHitRectangle, isSelectionMoving, RgbaToHEX, PlaitPluginElementComponent, setClipboardData, getDataFromClipboard, getHitElementByPoint, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
2
- import { getRectangleByPoints, Generator, getMemorizedLatest, memorizeLatest, PropertyTransforms, normalizeShapePoints, isDndMode, isDrawingMode, RESIZE_HANDLE_DIAMETER, getExtendPoint, getFactorByPoints, getRectangleResizeHandleRefs, getDirectionByVector, getOppositeDirection, getDirectionFactor, DEFAULT_ROUTE_MARGIN, reduceRouteMargin, getNextPoint, generateElbowLineRoute, getPoints, removeDuplicatePoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, TRANSPARENT, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, isVirtualKey, isDelete, isSpaceHotkey, acceptImageTypes, getElementOfFocusedImage, buildImage, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint, ImageGenerator } from '@plait/common';
3
- import { AlignEditor, Alignment, DEFAULT_FONT_SIZE, buildText, TextManage, getTextFromClipboard, getTextSize } from '@plait/text';
4
- import { isKeyHotkey } from 'is-hotkey';
1
+ import { PlaitElement, ACTIVE_STROKE_WIDTH, ThemeColorMode, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, depthFirstRecursion, getIsRecursionFunc, getElementById, Direction, catmullRomFitting, distanceBetweenPointAndSegments, createMask, createRect, findElements, Point, getSelectedElements, isPolylineHitRectangle, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, BOARD_TO_HOST, transformPoint, toPoint, isSelectionMoving, RgbaToHEX, PlaitPluginElementComponent, preventTouchMove, BoardTransforms, PlaitPointerType, setClipboardData, getDataFromClipboard, getHitElementByPoint, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
2
+ import { getRectangleByPoints, RESIZE_HANDLE_DIAMETER, getExtendPoint, getFactorByPoints, Generator, getRectangleResizeHandleRefs, getMemorizedLatest, memorizeLatest, getDirectionByVector, getOppositeDirection, getDirectionFactor, DEFAULT_ROUTE_MARGIN, reduceRouteMargin, getNextPoint, generateElbowLineRoute, getPoints, removeDuplicatePoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, TRANSPARENT, normalizeShapePoints, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, acceptImageTypes, getElementOfFocusedImage, buildImage, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint, ImageGenerator } from '@plait/common';
3
+ import { Alignment, buildText, DEFAULT_FONT_SIZE, getTextSize, AlignEditor, TextManage, getTextFromClipboard } from '@plait/text';
5
4
  import { pointsOnBezierCurves } from 'points-on-curve';
6
5
  import * as i0 from '@angular/core';
7
- import { Component, ChangeDetectionStrategy } from '@angular/core';
6
+ import { Component, ChangeDetectionStrategy, NgZone } from '@angular/core';
8
7
  import { Subject } from 'rxjs';
8
+ import { isKeyHotkey } from 'is-hotkey';
9
9
  import { Node } from 'slate';
10
10
 
11
11
  var BasicShapes;
@@ -1200,597 +1200,181 @@ const getShape = (value) => {
1200
1200
  return value.shape;
1201
1201
  };
1202
1202
 
1203
- class GeometryShapeGenerator extends Generator {
1204
- canDraw(element, data) {
1205
- return true;
1206
- }
1207
- draw(element, data) {
1208
- const rectangle = getRectangleByPoints(element.points);
1209
- const shape = element.shape;
1210
- if (shape === BasicShapes.text) {
1211
- return;
1212
- }
1213
- const strokeWidth = getStrokeWidthByElement(element);
1214
- const strokeColor = getStrokeColorByElement(this.board, element);
1215
- const fill = getFillByElement(this.board, element);
1216
- const strokeLineDash = getLineDashByElement(element);
1217
- return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1218
- stroke: strokeColor,
1219
- strokeWidth,
1220
- fill,
1221
- strokeLineDash
1222
- });
1223
- }
1224
- }
1203
+ const DefaultLineStyle = {
1204
+ strokeWidth: 2,
1205
+ strokeColor: '#000'
1206
+ };
1207
+ const LINE_TEXT_SPACE = 4;
1208
+ const LINE_AUTO_COMPLETE_DIAMETER = 6;
1209
+ const LINE_AUTO_COMPLETE_OPACITY = 0.6;
1210
+ const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
1211
+ const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
1225
1212
 
1226
- const SHAPE_MAX_LENGTH = 6;
1227
- const memorizedShape = new WeakMap();
1228
- const getMemorizeKey = (element) => {
1229
- let key = '';
1230
- switch (true) {
1231
- case PlaitDrawElement.isText(element): {
1232
- key = MemorizeKey.text;
1233
- break;
1234
- }
1235
- case PlaitDrawElement.isBasicShape(element): {
1236
- key = MemorizeKey.basicShape;
1237
- break;
1238
- }
1239
- case PlaitDrawElement.isFlowchart(element): {
1240
- key = MemorizeKey.flowchart;
1241
- break;
1242
- }
1243
- case PlaitDrawElement.isLine(element): {
1244
- key = MemorizeKey.line;
1245
- break;
1246
- }
1213
+ const createGeometryElement = (shape, points, text, options = {}, textProperties = {}) => {
1214
+ let textOptions = {};
1215
+ let alignment = Alignment.center;
1216
+ let textHeight = DefaultTextProperty.height;
1217
+ if (shape === BasicShapes.text) {
1218
+ textOptions = { autoSize: true };
1219
+ alignment = undefined;
1247
1220
  }
1248
- return key;
1221
+ textProperties = { ...textProperties };
1222
+ textProperties?.align && (alignment = textProperties?.align);
1223
+ textProperties?.textHeight && (textHeight = textProperties?.textHeight);
1224
+ delete textProperties?.align;
1225
+ delete textProperties?.textHeight;
1226
+ return {
1227
+ id: idCreator(),
1228
+ type: 'geometry',
1229
+ shape,
1230
+ angle: 0,
1231
+ opacity: 1,
1232
+ textHeight,
1233
+ text: buildText(text, alignment, textProperties),
1234
+ points,
1235
+ ...textOptions,
1236
+ ...options
1237
+ };
1249
1238
  };
1250
- const getLineMemorizedLatest = () => {
1251
- const properties = getMemorizedLatest(MemorizeKey.line);
1252
- delete properties?.text;
1253
- return properties || {};
1239
+ const getPointsByCenterPoint = (point, width, height) => {
1240
+ const leftTopPoint = [point[0] - width / 2, point[1] - height / 2];
1241
+ const rightBottomPoint = [point[0] + width / 2, point[1] + height / 2];
1242
+ return [leftTopPoint, rightBottomPoint];
1254
1243
  };
1255
- const getMemorizedLatestByPointer = (pointer) => {
1256
- let memorizeKey = '';
1257
- if (PlaitDrawElement.isBasicShape({ shape: pointer })) {
1258
- memorizeKey = pointer === BasicShapes.text ? MemorizeKey.text : MemorizeKey.basicShape;
1259
- }
1260
- else {
1261
- memorizeKey = MemorizeKey.flowchart;
1262
- }
1263
- const properties = { ...getMemorizedLatest(memorizeKey) } || {};
1264
- const textProperties = properties.text || {};
1265
- delete properties.text;
1266
- return { textProperties, geometryProperties: properties };
1244
+ const getTextRectangle = (element) => {
1245
+ const elementRectangle = getRectangleByPoints(element.points);
1246
+ const strokeWidth = getStrokeWidthByElement(element);
1247
+ const height = element.textHeight;
1248
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1249
+ return {
1250
+ height,
1251
+ width: width > 0 ? width : 0,
1252
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
1253
+ y: elementRectangle.y + (elementRectangle.height - height) / 2
1254
+ };
1267
1255
  };
1268
- const memorizeLatestText = (element, operations) => {
1269
- const memorizeKey = getMemorizeKey(element);
1270
- let textMemory = getMemorizedLatest(memorizeKey)?.text || {};
1271
- const setNodeOperation = operations.find(operation => operation.type === 'set_node');
1272
- if (setNodeOperation) {
1273
- const newProperties = setNodeOperation.newProperties;
1274
- textMemory = { ...textMemory, ...newProperties };
1275
- memorizeLatest(memorizeKey, 'text', textMemory);
1276
- }
1256
+ const drawBoundMask = (board, element) => {
1257
+ const G = createG();
1258
+ const rectangle = getRectangleByPoints(element.points);
1259
+ const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
1260
+ const shape = getShape(element);
1261
+ const maskG = drawGeometry(board, activeRectangle, shape, {
1262
+ stroke: SELECTION_BORDER_COLOR,
1263
+ strokeWidth: 1,
1264
+ fill: SELECTION_FILL_COLOR,
1265
+ fillStyle: 'solid'
1266
+ });
1267
+ G.appendChild(maskG);
1268
+ const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
1269
+ connectorPoints.forEach(point => {
1270
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
1271
+ stroke: '#999999',
1272
+ strokeWidth: 1,
1273
+ fill: '#FFF',
1274
+ fillStyle: 'solid'
1275
+ });
1276
+ G.appendChild(circleG);
1277
+ });
1278
+ return G;
1277
1279
  };
1278
- const memorizeLatestShape = (board, shape) => {
1279
- const shapes = memorizedShape.has(board) ? memorizedShape.get(board) : [];
1280
- const shapeIndex = shapes.indexOf(shape);
1281
- if (shape === BasicShapes.text || shapeIndex === 0) {
1282
- return;
1283
- }
1284
- if (shapeIndex !== -1) {
1285
- shapes.splice(shapeIndex, 1);
1280
+ const drawGeometry = (board, outerRectangle, shape, options) => {
1281
+ return getEngine(shape).draw(board, outerRectangle, options);
1282
+ };
1283
+ const getNearestPoint = (element, point, inflateDelta = 0) => {
1284
+ const rectangle = getRectangleByPoints(element.points);
1285
+ const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
1286
+ const shape = getShape(element);
1287
+ return getEngine(shape).getNearestPoint(activeRectangle, point);
1288
+ };
1289
+ const getCenterPointsOnPolygon = (points) => {
1290
+ const centerPoint = [];
1291
+ for (let i = 0; i < points.length; i++) {
1292
+ let j = i == points.length - 1 ? 0 : i + 1;
1293
+ centerPoint.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1286
1294
  }
1287
- else {
1288
- if (shapes.length === SHAPE_MAX_LENGTH) {
1289
- shapes.pop();
1295
+ return centerPoint;
1296
+ };
1297
+ const getEdgeOnPolygonByPoint = (corners, point) => {
1298
+ for (let index = 1; index <= corners.length; index++) {
1299
+ let start = corners[index - 1];
1300
+ let end = index === corners.length ? corners[0] : corners[index];
1301
+ const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1302
+ if (distance < 1) {
1303
+ return [start, end];
1290
1304
  }
1291
1305
  }
1292
- shapes.unshift(shape);
1293
- memorizedShape.set(board, shapes);
1294
- };
1295
- const getMemorizedLatestShape = (board) => {
1296
- return memorizedShape.get(board);
1297
- };
1298
-
1299
- const setStrokeColor = (board, strokeColor) => {
1300
- PropertyTransforms.setProperty(board, { strokeColor }, { getMemorizeKey });
1306
+ return null;
1301
1307
  };
1302
- const setStrokeWidth = (board, strokeWidth) => {
1303
- PropertyTransforms.setProperty(board, { strokeWidth }, { getMemorizeKey });
1308
+ const getDefaultFlowchartProperty = (symbol) => {
1309
+ return DefaultFlowchartPropertyMap[symbol];
1304
1310
  };
1305
- const setFillColor = (board, fill) => {
1306
- PropertyTransforms.setProperty(board, { fill }, { getMemorizeKey });
1311
+ const createDefaultFlowchart = (point) => {
1312
+ const decisionProperty = getDefaultFlowchartProperty(FlowchartSymbols.decision);
1313
+ const processProperty = getDefaultFlowchartProperty(FlowchartSymbols.process);
1314
+ const terminalProperty = getDefaultFlowchartProperty(FlowchartSymbols.terminal);
1315
+ const options = {
1316
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1317
+ };
1318
+ const lineOptions = {
1319
+ strokeWidth: DefaultLineStyle.strokeWidth
1320
+ };
1321
+ const startElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, point), '开始', options);
1322
+ const processPoint1 = [point[0], point[1] + terminalProperty.height / 2 + 55 + processProperty.height / 2];
1323
+ const processElement1 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint1), '过程', options);
1324
+ const decisionPoint = [processPoint1[0], processPoint1[1] + processProperty.height / 2 + 55 + decisionProperty.height / 2];
1325
+ const decisionElement = createGeometryElement(FlowchartSymbols.decision, getDefaultGeometryPoints(FlowchartSymbols.decision, decisionPoint), '过程', options);
1326
+ const processPoint2 = [decisionPoint[0] + decisionProperty.width / 2 + 75 + processProperty.width / 2, decisionPoint[1]];
1327
+ const processElement2 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint2), '过程', options);
1328
+ const endPoint = [decisionPoint[0], decisionPoint[1] + decisionProperty.height / 2 + 95 + terminalProperty.height / 2];
1329
+ const endElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, endPoint), '结束', options);
1330
+ const line1 = createLineElement(LineShape.elbow, [
1331
+ [0, 0],
1332
+ [0, 0]
1333
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: startElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: processElement1.id }, [], lineOptions);
1334
+ const line2 = createLineElement(LineShape.elbow, [
1335
+ [0, 0],
1336
+ [0, 0]
1337
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement1.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: decisionElement.id }, [], lineOptions);
1338
+ const line3 = createLineElement(LineShape.elbow, [
1339
+ [0, 0],
1340
+ [0, 0]
1341
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: endElement.id }, [
1342
+ {
1343
+ text: buildText('是'),
1344
+ position: 0.5,
1345
+ width: 14,
1346
+ height: 20
1347
+ }
1348
+ ], lineOptions);
1349
+ const line4 = createLineElement(LineShape.elbow, [
1350
+ [0, 0],
1351
+ [0, 0]
1352
+ ], { marker: LineMarkerType.none, connection: [1, 0.5], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0, 0.5], boundId: processElement2.id }, [
1353
+ {
1354
+ text: buildText('否'),
1355
+ position: 0.5,
1356
+ width: 14,
1357
+ height: 20
1358
+ }
1359
+ ], lineOptions);
1360
+ const line5 = createLineElement(LineShape.elbow, [
1361
+ [0, 0],
1362
+ [0, 0]
1363
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement2.id }, { marker: LineMarkerType.arrow, connection: [1, 0.5], boundId: endElement.id }, [], lineOptions);
1364
+ return [startElement, processElement1, decisionElement, processElement2, endElement, line1, line2, line3, line4, line5];
1307
1365
  };
1308
- const setStrokeStyle = (board, strokeStyle) => {
1309
- PropertyTransforms.setProperty(board, { strokeStyle }, { getMemorizeKey });
1366
+ const getAutoCompletePoints = (element) => {
1367
+ const AutoCompleteMargin = (12 + RESIZE_HANDLE_DIAMETER / 2) * 2;
1368
+ let rectangle = getRectangleByPoints(element.points);
1369
+ rectangle = RectangleClient.inflate(rectangle, AutoCompleteMargin);
1370
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1310
1371
  };
1311
-
1312
- const insertGeometry = (board, points, shape) => {
1313
- let newElement = createGeometryElement(shape, points, '', {
1314
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
1315
- });
1316
- Transforms.insertNode(board, newElement, [board.children.length]);
1317
- clearSelectedElement(board);
1318
- addSelectedElement(board, newElement);
1319
- };
1320
- const insertText = (board, points, text = '文本') => {
1321
- let newElement = createGeometryElement(BasicShapes.text, points, text);
1322
- Transforms.insertNode(board, newElement, [board.children.length]);
1323
- clearSelectedElement(board);
1324
- addSelectedElement(board, newElement);
1325
- };
1326
- const resizeGeometry = (board, points, textHeight, path) => {
1327
- const normalizePoints = normalizeShapePoints(points);
1328
- const element = PlaitNode.get(board, path);
1329
- const newHeight = textHeight / board.viewport.zoom;
1330
- const newProperties = { points: normalizePoints, textHeight: newHeight };
1331
- if (PlaitDrawElement.isText(element) && element.autoSize) {
1332
- newProperties.autoSize = false;
1333
- }
1334
- Transforms.setNode(board, newProperties, path);
1335
- };
1336
- const transformShape = (board, element, shape) => {
1337
- const path = PlaitBoard.findPath(board, element);
1338
- Transforms.setNode(board, { shape }, path);
1339
- };
1340
-
1341
- const normalizePoints = (board, element, width, textHeight) => {
1342
- let points = element.points;
1343
- let autoSize = element.autoSize;
1344
- const defaultSpace = ShapeDefaultSpace.rectangleAndText;
1345
- if (autoSize) {
1346
- const editor = PlaitGeometry.getTextEditor(element);
1347
- if (AlignEditor.isActive(editor, Alignment.right)) {
1348
- points = [
1349
- [points[1][0] - (width + defaultSpace * 2), points[0][1]],
1350
- [points[1][0], points[0][1] + textHeight]
1351
- ];
1352
- }
1353
- else if (AlignEditor.isActive(editor, Alignment.center)) {
1354
- const oldWidth = Math.abs(points[0][0] - points[1][0]);
1355
- const offset = (width - oldWidth) / 2;
1356
- points = [
1357
- [points[0][0] - offset - defaultSpace, points[0][1]],
1358
- [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
1359
- ];
1360
- }
1361
- else {
1362
- points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
1363
- }
1364
- }
1365
- return { points };
1366
- };
1367
- const setText = (board, element, text, width, textHeight) => {
1368
- const newElement = {
1369
- text,
1370
- textHeight,
1371
- ...normalizePoints(board, element, width, textHeight)
1372
- };
1373
- const path = board.children.findIndex(child => child === element);
1374
- Transforms.setNode(board, newElement, [path]);
1375
- };
1376
- const setTextSize = (board, element, textWidth, textHeight) => {
1377
- if (element.autoSize) {
1378
- const newElement = {
1379
- textHeight,
1380
- ...normalizePoints(board, element, textWidth, textHeight)
1381
- };
1382
- const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
1383
- const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
1384
- if (!isPointsEqual || !isTextHeightEqual) {
1385
- const path = board.children.findIndex(child => child === element);
1386
- Transforms.setNode(board, newElement, [path]);
1387
- }
1388
- }
1389
- };
1390
-
1391
- const insertImage = (board, imageItem, startPoint) => {
1392
- const { width, height, url } = imageItem;
1393
- const host = BOARD_TO_HOST.get(board);
1394
- const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1395
- const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1396
- const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1397
- const points = startPoint
1398
- ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1399
- : [
1400
- [point[0] - width / 2, point[1] - height / 2],
1401
- [point[0] + width / 2, point[1] + height / 2]
1402
- ];
1403
- const imageElement = {
1404
- id: idCreator(),
1405
- type: 'image',
1406
- points,
1407
- url
1408
- };
1409
- Transforms.insertNode(board, imageElement, [board.children.length]);
1410
- Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
1411
- };
1412
-
1413
- const resizeLine = (board, options, path) => {
1414
- Transforms.setNode(board, options, path);
1415
- };
1416
- const setLineTexts = (board, element, texts) => {
1417
- const path = PlaitBoard.findPath(board, element);
1418
- Transforms.setNode(board, { texts }, path);
1419
- };
1420
- const removeLineText = (board, element, index) => {
1421
- const path = PlaitBoard.findPath(board, element);
1422
- const texts = element.texts?.length ? [...element.texts] : [];
1423
- const newTexts = [...texts];
1424
- newTexts.splice(index, 1);
1425
- Transforms.setNode(board, { texts: newTexts }, path);
1426
- };
1427
- const setLineMark = (board, element, handleKey, marker) => {
1428
- const path = PlaitBoard.findPath(board, element);
1429
- let handle = handleKey === LineHandleKey.source ? element.source : element.target;
1430
- handle = { ...handle, marker };
1431
- memorizeLatest(MemorizeKey.line, handleKey, marker);
1432
- Transforms.setNode(board, { [handleKey]: handle }, path);
1433
- };
1434
-
1435
- const DrawTransforms = {
1436
- setText,
1437
- insertGeometry,
1438
- resizeGeometry,
1439
- insertText,
1440
- setTextSize,
1441
- resizeLine,
1442
- setLineTexts,
1443
- removeLineText,
1444
- setLineMark,
1445
- insertImage,
1446
- transformShape,
1447
- setStrokeColor,
1448
- setStrokeWidth,
1449
- setFillColor,
1450
- setStrokeStyle
1451
- };
1452
-
1453
- const withGeometryCreateByDrag = (board) => {
1454
- const { pointerMove, pointerUp } = board;
1455
- let geometryShapeG = null;
1456
- board.pointerMove = (event) => {
1457
- geometryShapeG?.remove();
1458
- geometryShapeG = createG();
1459
- const geometryGenerator = new GeometryShapeGenerator(board);
1460
- const geometryPointers = getGeometryPointers();
1461
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1462
- const dragMode = isGeometryPointer && isDndMode(board);
1463
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1464
- const pointer = PlaitBoard.getPointer(board);
1465
- if (dragMode) {
1466
- const points = getDefaultGeometryPoints(pointer, movingPoint);
1467
- if (pointer === BasicShapes.text) {
1468
- const textG = getTemporaryTextG(movingPoint);
1469
- geometryShapeG.appendChild(textG);
1470
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1471
- }
1472
- else {
1473
- const temporaryElement = createGeometryElement(pointer, points, '', {
1474
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
1475
- });
1476
- geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
1477
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1478
- }
1479
- }
1480
- pointerMove(event);
1481
- };
1482
- board.pointerUp = (event) => {
1483
- const pointer = PlaitBoard.getPointer(board);
1484
- const geometryPointers = getGeometryPointers();
1485
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1486
- const dragMode = isGeometryPointer && isDndMode(board);
1487
- if (dragMode) {
1488
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1489
- const points = getDefaultGeometryPoints(pointer, targetPoint);
1490
- if (pointer === BasicShapes.text) {
1491
- DrawTransforms.insertText(board, points);
1492
- }
1493
- else {
1494
- DrawTransforms.insertGeometry(board, points, pointer);
1495
- }
1496
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1497
- }
1498
- geometryShapeG?.remove();
1499
- geometryShapeG = null;
1500
- preventTouchMove(board, event, false);
1501
- pointerUp(event);
1502
- };
1503
- return board;
1504
- };
1505
- const withGeometryCreateByDrawing = (board) => {
1506
- const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1507
- let start = null;
1508
- let geometryShapeG = null;
1509
- let temporaryElement = null;
1510
- let isShift = false;
1511
- board.keydown = (event) => {
1512
- isShift = isKeyHotkey('shift', event);
1513
- keydown(event);
1514
- };
1515
- board.keyup = (event) => {
1516
- isShift = false;
1517
- keyup(event);
1518
- };
1519
- board.pointerDown = (event) => {
1520
- const geometryPointers = getGeometryPointers();
1521
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1522
- if (!PlaitBoard.isReadonly(board) && isGeometryPointer && isDrawingMode(board)) {
1523
- const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1524
- start = point;
1525
- const pointer = PlaitBoard.getPointer(board);
1526
- preventTouchMove(board, event, true);
1527
- if (pointer === BasicShapes.text) {
1528
- const memorizedLatest = getMemorizedLatestByPointer(pointer);
1529
- const points = getDefaultGeometryPoints(pointer, point);
1530
- const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text, memorizedLatest.geometryProperties, memorizedLatest.textProperties);
1531
- Transforms.insertNode(board, textElement, [board.children.length]);
1532
- clearSelectedElement(board);
1533
- addSelectedElement(board, textElement);
1534
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1535
- start = null;
1536
- }
1537
- }
1538
- pointerDown(event);
1539
- };
1540
- board.pointerMove = (event) => {
1541
- geometryShapeG?.remove();
1542
- geometryShapeG = createG();
1543
- const geometryGenerator = new GeometryShapeGenerator(board);
1544
- const drawMode = !!start;
1545
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1546
- const pointer = PlaitBoard.getPointer(board);
1547
- if (drawMode && pointer !== BasicShapes.text) {
1548
- const points = normalizeShapePoints([start, movingPoint], isShift);
1549
- const memorizedLatest = getMemorizedLatestByPointer(pointer);
1550
- temporaryElement = createGeometryElement(pointer, points, '', {
1551
- strokeWidth: DefaultBasicShapeProperty.strokeWidth,
1552
- ...memorizedLatest.geometryProperties
1553
- }, memorizedLatest.textProperties);
1554
- geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
1555
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1556
- }
1557
- pointerMove(event);
1558
- };
1559
- board.pointerUp = (event) => {
1560
- const isDrawMode = !!start;
1561
- if (isDrawMode) {
1562
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1563
- const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
1564
- if (Math.hypot(width, height) === 0) {
1565
- const pointer = PlaitBoard.getPointer(board);
1566
- const points = getDefaultGeometryPoints(pointer, targetPoint);
1567
- if (pointer !== BasicShapes.text) {
1568
- const memorizedLatest = getMemorizedLatestByPointer(pointer);
1569
- temporaryElement = createGeometryElement(pointer, points, '', {
1570
- strokeWidth: DefaultBasicShapeProperty.strokeWidth,
1571
- ...memorizedLatest.geometryProperties
1572
- }, memorizedLatest.textProperties);
1573
- }
1574
- }
1575
- }
1576
- if (temporaryElement) {
1577
- memorizeLatestShape(board, temporaryElement.shape);
1578
- Transforms.insertNode(board, temporaryElement, [board.children.length]);
1579
- clearSelectedElement(board);
1580
- addSelectedElement(board, temporaryElement);
1581
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1582
- }
1583
- geometryShapeG?.remove();
1584
- geometryShapeG = null;
1585
- start = null;
1586
- temporaryElement = null;
1587
- preventTouchMove(board, event, false);
1588
- pointerUp(event);
1589
- };
1590
- return board;
1591
- };
1592
- const getDefaultGeometryPoints = (pointer, targetPoint) => {
1593
- const defaultProperty = getGeometryDefaultProperty(pointer);
1594
- return getPointsByCenterPoint(targetPoint, defaultProperty.width, defaultProperty.height);
1595
- };
1596
- const getGeometryDefaultProperty = (pointer) => {
1597
- const isText = pointer === BasicShapes.text;
1598
- const isFlowChart = getFlowchartPointers().includes(pointer);
1599
- if (isText) {
1600
- return DefaultTextProperty;
1601
- }
1602
- else if (isFlowChart) {
1603
- return getDefaultFlowchartProperty(pointer);
1604
- }
1605
- else {
1606
- return DefaultBasicShapeProperty;
1607
- }
1608
- };
1609
- const getTemporaryTextG = (movingPoint) => {
1610
- const textG = createG();
1611
- const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
1612
- const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
1613
- const richtext = document.createElement('div');
1614
- richtext.textContent = DefaultTextProperty.text;
1615
- richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
1616
- richtext.style.cursor = 'default';
1617
- foreignObject.appendChild(richtext);
1618
- textG.appendChild(foreignObject);
1619
- return textG;
1620
- };
1621
-
1622
- const DefaultLineStyle = {
1623
- strokeWidth: 2,
1624
- strokeColor: '#000'
1625
- };
1626
- const LINE_TEXT_SPACE = 4;
1627
- const LINE_AUTO_COMPLETE_DIAMETER = 6;
1628
- const LINE_AUTO_COMPLETE_OPACITY = 0.6;
1629
- const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
1630
- const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
1631
-
1632
- const createGeometryElement = (shape, points, text, options = {}, textProperties = {}) => {
1633
- let textOptions = {};
1634
- let alignment = Alignment.center;
1635
- if (shape === BasicShapes.text) {
1636
- textOptions = { autoSize: true };
1637
- alignment = undefined;
1638
- }
1639
- textProperties = { ...textProperties };
1640
- textProperties?.align && (alignment = textProperties?.align);
1641
- delete textProperties?.align;
1642
- return {
1643
- id: idCreator(),
1644
- type: 'geometry',
1645
- shape,
1646
- angle: 0,
1647
- opacity: 1,
1648
- textHeight: DefaultTextProperty.height,
1649
- text: buildText(text, alignment, textProperties),
1650
- points,
1651
- ...textOptions,
1652
- ...options
1653
- };
1654
- };
1655
- const getPointsByCenterPoint = (point, width, height) => {
1656
- const leftTopPoint = [point[0] - width / 2, point[1] - height / 2];
1657
- const rightBottomPoint = [point[0] + width / 2, point[1] + height / 2];
1658
- return [leftTopPoint, rightBottomPoint];
1659
- };
1660
- const getTextRectangle = (element) => {
1661
- const elementRectangle = getRectangleByPoints(element.points);
1662
- const strokeWidth = getStrokeWidthByElement(element);
1663
- const height = element.textHeight;
1664
- const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1665
- return {
1666
- height,
1667
- width: width > 0 ? width : 0,
1668
- x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
1669
- y: elementRectangle.y + (elementRectangle.height - height) / 2
1670
- };
1671
- };
1672
- const drawBoundMask = (board, element) => {
1673
- const G = createG();
1674
- const rectangle = getRectangleByPoints(element.points);
1675
- const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
1676
- const shape = getShape(element);
1677
- const maskG = drawGeometry(board, activeRectangle, shape, {
1678
- stroke: SELECTION_BORDER_COLOR,
1679
- strokeWidth: 1,
1680
- fill: SELECTION_FILL_COLOR,
1681
- fillStyle: 'solid'
1682
- });
1683
- G.appendChild(maskG);
1684
- const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
1685
- connectorPoints.forEach(point => {
1686
- const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
1687
- stroke: '#999999',
1688
- strokeWidth: 1,
1689
- fill: '#FFF',
1690
- fillStyle: 'solid'
1691
- });
1692
- G.appendChild(circleG);
1693
- });
1694
- return G;
1695
- };
1696
- const drawGeometry = (board, outerRectangle, shape, options) => {
1697
- return getEngine(shape).draw(board, outerRectangle, options);
1698
- };
1699
- const getNearestPoint = (element, point, inflateDelta = 0) => {
1700
- const rectangle = getRectangleByPoints(element.points);
1701
- const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
1702
- const shape = getShape(element);
1703
- return getEngine(shape).getNearestPoint(activeRectangle, point);
1704
- };
1705
- const getCenterPointsOnPolygon = (points) => {
1706
- const centerPoint = [];
1707
- for (let i = 0; i < points.length; i++) {
1708
- let j = i == points.length - 1 ? 0 : i + 1;
1709
- centerPoint.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1710
- }
1711
- return centerPoint;
1712
- };
1713
- const getEdgeOnPolygonByPoint = (corners, point) => {
1714
- for (let index = 1; index <= corners.length; index++) {
1715
- let start = corners[index - 1];
1716
- let end = index === corners.length ? corners[0] : corners[index];
1717
- const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1718
- if (distance < 1) {
1719
- return [start, end];
1720
- }
1721
- }
1722
- return null;
1723
- };
1724
- const getDefaultFlowchartProperty = (symbol) => {
1725
- return DefaultFlowchartPropertyMap[symbol];
1726
- };
1727
- const createDefaultFlowchart = (point) => {
1728
- const decisionProperty = getDefaultFlowchartProperty(FlowchartSymbols.decision);
1729
- const processProperty = getDefaultFlowchartProperty(FlowchartSymbols.process);
1730
- const terminalProperty = getDefaultFlowchartProperty(FlowchartSymbols.terminal);
1731
- const options = {
1732
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
1733
- };
1734
- const lineOptions = {
1735
- strokeWidth: DefaultLineStyle.strokeWidth
1736
- };
1737
- const startElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, point), '开始', options);
1738
- const processPoint1 = [point[0], point[1] + terminalProperty.height / 2 + 55 + processProperty.height / 2];
1739
- const processElement1 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint1), '过程', options);
1740
- const decisionPoint = [processPoint1[0], processPoint1[1] + processProperty.height / 2 + 55 + decisionProperty.height / 2];
1741
- const decisionElement = createGeometryElement(FlowchartSymbols.decision, getDefaultGeometryPoints(FlowchartSymbols.decision, decisionPoint), '过程', options);
1742
- const processPoint2 = [decisionPoint[0] + decisionProperty.width / 2 + 75 + processProperty.width / 2, decisionPoint[1]];
1743
- const processElement2 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint2), '过程', options);
1744
- const endPoint = [decisionPoint[0], decisionPoint[1] + decisionProperty.height / 2 + 95 + terminalProperty.height / 2];
1745
- const endElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, endPoint), '结束', options);
1746
- const line1 = createLineElement(LineShape.elbow, [
1747
- [0, 0],
1748
- [0, 0]
1749
- ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: startElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: processElement1.id }, [], lineOptions);
1750
- const line2 = createLineElement(LineShape.elbow, [
1751
- [0, 0],
1752
- [0, 0]
1753
- ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement1.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: decisionElement.id }, [], lineOptions);
1754
- const line3 = createLineElement(LineShape.elbow, [
1755
- [0, 0],
1756
- [0, 0]
1757
- ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: endElement.id }, [
1758
- {
1759
- text: buildText('是'),
1760
- position: 0.5,
1761
- width: 14,
1762
- height: 20
1763
- }
1764
- ], lineOptions);
1765
- const line4 = createLineElement(LineShape.elbow, [
1766
- [0, 0],
1767
- [0, 0]
1768
- ], { marker: LineMarkerType.none, connection: [1, 0.5], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0, 0.5], boundId: processElement2.id }, [
1769
- {
1770
- text: buildText('否'),
1771
- position: 0.5,
1772
- width: 14,
1773
- height: 20
1774
- }
1775
- ], lineOptions);
1776
- const line5 = createLineElement(LineShape.elbow, [
1777
- [0, 0],
1778
- [0, 0]
1779
- ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement2.id }, { marker: LineMarkerType.arrow, connection: [1, 0.5], boundId: endElement.id }, [], lineOptions);
1780
- return [startElement, processElement1, decisionElement, processElement2, endElement, line1, line2, line3, line4, line5];
1781
- };
1782
- const getAutoCompletePoints = (element) => {
1783
- const AutoCompleteMargin = (12 + RESIZE_HANDLE_DIAMETER / 2) * 2;
1784
- let rectangle = getRectangleByPoints(element.points);
1785
- rectangle = RectangleClient.inflate(rectangle, AutoCompleteMargin);
1786
- return RectangleClient.getEdgeCenterPoints(rectangle);
1787
- };
1788
- const getHitIndexOfAutoCompletePoint = (movingPoint, points) => {
1789
- return points.findIndex(point => {
1790
- const movingRectangle = RectangleClient.toRectangleClient([movingPoint]);
1791
- let rectangle = RectangleClient.toRectangleClient([point]);
1792
- rectangle = RectangleClient.inflate(rectangle, RESIZE_HANDLE_DIAMETER);
1793
- return RectangleClient.isHit(movingRectangle, rectangle);
1372
+ const getHitIndexOfAutoCompletePoint = (movingPoint, points) => {
1373
+ return points.findIndex(point => {
1374
+ const movingRectangle = RectangleClient.toRectangleClient([movingPoint]);
1375
+ let rectangle = RectangleClient.toRectangleClient([point]);
1376
+ rectangle = RectangleClient.inflate(rectangle, RESIZE_HANDLE_DIAMETER);
1377
+ return RectangleClient.isHit(movingRectangle, rectangle);
1794
1378
  });
1795
1379
  };
1796
1380
  const getDrawDefaultStrokeColor = (theme) => {
@@ -1799,6 +1383,32 @@ const getDrawDefaultStrokeColor = (theme) => {
1799
1383
  const getFlowchartDefaultFill = (theme) => {
1800
1384
  return DrawThemeColors[theme].fill;
1801
1385
  };
1386
+ const getDefaultTextShapeProperty = (board, fontSize) => {
1387
+ fontSize = fontSize ? Number(fontSize) : DEFAULT_FONT_SIZE;
1388
+ const textSize = getTextSize(board, '文本', 10, { fontSize });
1389
+ return {
1390
+ width: textSize.width + ShapeDefaultSpace.rectangleAndText * 2,
1391
+ height: textSize.height,
1392
+ text: '文本'
1393
+ };
1394
+ };
1395
+ const getDefaultGeometryPoints = (pointer, centerPoint) => {
1396
+ const defaultProperty = getDefaultGeometryProperty(pointer);
1397
+ return getPointsByCenterPoint(centerPoint, defaultProperty.width, defaultProperty.height);
1398
+ };
1399
+ const getDefaultGeometryProperty = (pointer) => {
1400
+ const isFlowChart = getFlowchartPointers().includes(pointer);
1401
+ if (isFlowChart) {
1402
+ return getDefaultFlowchartProperty(pointer);
1403
+ }
1404
+ else {
1405
+ return DefaultBasicShapeProperty;
1406
+ }
1407
+ };
1408
+ const getDefaultTextPoints = (board, centerPoint, fontSize) => {
1409
+ const property = getDefaultTextShapeProperty(board, fontSize);
1410
+ return getPointsByCenterPoint(centerPoint, property.width, property.height);
1411
+ };
1802
1412
 
1803
1413
  const ARROW_LENGTH = 20;
1804
1414
  const drawLineArrow = (element, points, options) => {
@@ -1954,6 +1564,79 @@ const getHitOutlineGeometry = (board, point, offset = 0) => {
1954
1564
  return geometry;
1955
1565
  };
1956
1566
 
1567
+ const SHAPE_MAX_LENGTH = 6;
1568
+ const memorizedShape = new WeakMap();
1569
+ const getMemorizeKey = (element) => {
1570
+ let key = '';
1571
+ switch (true) {
1572
+ case PlaitDrawElement.isText(element): {
1573
+ key = MemorizeKey.text;
1574
+ break;
1575
+ }
1576
+ case PlaitDrawElement.isBasicShape(element): {
1577
+ key = MemorizeKey.basicShape;
1578
+ break;
1579
+ }
1580
+ case PlaitDrawElement.isFlowchart(element): {
1581
+ key = MemorizeKey.flowchart;
1582
+ break;
1583
+ }
1584
+ case PlaitDrawElement.isLine(element): {
1585
+ key = MemorizeKey.line;
1586
+ break;
1587
+ }
1588
+ }
1589
+ return key;
1590
+ };
1591
+ const getLineMemorizedLatest = () => {
1592
+ const properties = getMemorizedLatest(MemorizeKey.line);
1593
+ delete properties?.text;
1594
+ return { ...properties } || {};
1595
+ };
1596
+ const getMemorizedLatestByPointer = (pointer) => {
1597
+ let memorizeKey = '';
1598
+ if (PlaitDrawElement.isBasicShape({ shape: pointer })) {
1599
+ memorizeKey = pointer === BasicShapes.text ? MemorizeKey.text : MemorizeKey.basicShape;
1600
+ }
1601
+ else {
1602
+ memorizeKey = MemorizeKey.flowchart;
1603
+ }
1604
+ const properties = { ...getMemorizedLatest(memorizeKey) } || {};
1605
+ const textProperties = { ...properties.text } || {};
1606
+ delete properties.text;
1607
+ return { textProperties, geometryProperties: properties };
1608
+ };
1609
+ const memorizeLatestText = (element, operations) => {
1610
+ const memorizeKey = getMemorizeKey(element);
1611
+ let textMemory = getMemorizedLatest(memorizeKey)?.text || {};
1612
+ const setNodeOperation = operations.find(operation => operation.type === 'set_node');
1613
+ if (setNodeOperation) {
1614
+ const newProperties = setNodeOperation.newProperties;
1615
+ textMemory = { ...textMemory, ...newProperties };
1616
+ memorizeLatest(memorizeKey, 'text', textMemory);
1617
+ }
1618
+ };
1619
+ const memorizeLatestShape = (board, shape) => {
1620
+ const shapes = memorizedShape.has(board) ? memorizedShape.get(board) : [];
1621
+ const shapeIndex = shapes.indexOf(shape);
1622
+ if (shape === BasicShapes.text || shapeIndex === 0) {
1623
+ return;
1624
+ }
1625
+ if (shapeIndex !== -1) {
1626
+ shapes.splice(shapeIndex, 1);
1627
+ }
1628
+ else {
1629
+ if (shapes.length === SHAPE_MAX_LENGTH) {
1630
+ shapes.pop();
1631
+ }
1632
+ }
1633
+ shapes.unshift(shape);
1634
+ memorizedShape.set(board, shapes);
1635
+ };
1636
+ const getMemorizedLatestShape = (board) => {
1637
+ return memorizedShape.get(board);
1638
+ };
1639
+
1957
1640
  const createLineElement = (shape, points, source, target, texts, options) => {
1958
1641
  return {
1959
1642
  id: idCreator(),
@@ -2436,74 +2119,234 @@ const PlaitLine = {
2436
2119
  else {
2437
2120
  return line.target.marker === markType;
2438
2121
  }
2439
- },
2440
- isSourceMark(line, markType) {
2441
- return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.source);
2442
- },
2443
- isTargetMark(line, markType) {
2444
- return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
2445
- },
2446
- isBoundElementOfSource(line, element) {
2447
- return line.source.boundId === element.id;
2448
- },
2449
- isBoundElementOfTarget(line, element) {
2450
- return line.target.boundId === element.id;
2451
- },
2452
- getPoints(board, line) {
2453
- let sourcePoint = line.source.boundId
2454
- ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
2455
- : line.points[0];
2456
- let targetPoint = line.target.boundId
2457
- ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2458
- : line.points[line.points.length - 1];
2459
- const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2460
- return [sourcePoint, ...restPoints, targetPoint];
2122
+ },
2123
+ isSourceMark(line, markType) {
2124
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.source);
2125
+ },
2126
+ isTargetMark(line, markType) {
2127
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
2128
+ },
2129
+ isBoundElementOfSource(line, element) {
2130
+ return line.source.boundId === element.id;
2131
+ },
2132
+ isBoundElementOfTarget(line, element) {
2133
+ return line.target.boundId === element.id;
2134
+ },
2135
+ getPoints(board, line) {
2136
+ let sourcePoint = line.source.boundId
2137
+ ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
2138
+ : line.points[0];
2139
+ let targetPoint = line.target.boundId
2140
+ ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2141
+ : line.points[line.points.length - 1];
2142
+ const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2143
+ return [sourcePoint, ...restPoints, targetPoint];
2144
+ }
2145
+ };
2146
+
2147
+ var StrokeStyle;
2148
+ (function (StrokeStyle) {
2149
+ StrokeStyle["solid"] = "solid";
2150
+ StrokeStyle["dashed"] = "dashed";
2151
+ })(StrokeStyle || (StrokeStyle = {}));
2152
+ var MemorizeKey;
2153
+ (function (MemorizeKey) {
2154
+ MemorizeKey["basicShape"] = "basicShape";
2155
+ MemorizeKey["flowchart"] = "flowchart";
2156
+ MemorizeKey["text"] = "text";
2157
+ MemorizeKey["line"] = "line";
2158
+ })(MemorizeKey || (MemorizeKey = {}));
2159
+
2160
+ const PlaitDrawElement = {
2161
+ isGeometry: (value) => {
2162
+ return value.type === 'geometry';
2163
+ },
2164
+ isLine: (value) => {
2165
+ return value.type === 'line';
2166
+ },
2167
+ isText: (value) => {
2168
+ return value.type === 'geometry' && value.shape === BasicShapes.text;
2169
+ },
2170
+ isImage: (value) => {
2171
+ return value.type === 'image';
2172
+ },
2173
+ isDrawElement: (value) => {
2174
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
2175
+ return true;
2176
+ }
2177
+ else {
2178
+ return false;
2179
+ }
2180
+ },
2181
+ isShape: (value) => {
2182
+ return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
2183
+ },
2184
+ isBasicShape: (value) => {
2185
+ return Object.keys(BasicShapes).includes(value.shape);
2186
+ },
2187
+ isFlowchart: (value) => {
2188
+ return Object.keys(FlowchartSymbols).includes(value.shape);
2189
+ }
2190
+ };
2191
+
2192
+ class GeometryShapeGenerator extends Generator {
2193
+ canDraw(element, data) {
2194
+ return true;
2195
+ }
2196
+ draw(element, data) {
2197
+ const rectangle = getRectangleByPoints(element.points);
2198
+ const shape = element.shape;
2199
+ if (shape === BasicShapes.text) {
2200
+ return;
2201
+ }
2202
+ const strokeWidth = getStrokeWidthByElement(element);
2203
+ const strokeColor = getStrokeColorByElement(this.board, element);
2204
+ const fill = getFillByElement(this.board, element);
2205
+ const strokeLineDash = getLineDashByElement(element);
2206
+ return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
2207
+ stroke: strokeColor,
2208
+ strokeWidth,
2209
+ fill,
2210
+ strokeLineDash
2211
+ });
2212
+ }
2213
+ }
2214
+
2215
+ const insertGeometry = (board, points, shape) => {
2216
+ let newElement = createGeometryElement(shape, points, '', {
2217
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
2218
+ });
2219
+ Transforms.insertNode(board, newElement, [board.children.length]);
2220
+ clearSelectedElement(board);
2221
+ addSelectedElement(board, newElement);
2222
+ };
2223
+ const insertText = (board, points, text = '文本') => {
2224
+ let newElement = createGeometryElement(BasicShapes.text, points, text);
2225
+ Transforms.insertNode(board, newElement, [board.children.length]);
2226
+ clearSelectedElement(board);
2227
+ addSelectedElement(board, newElement);
2228
+ };
2229
+ const resizeGeometry = (board, points, textHeight, path) => {
2230
+ const normalizePoints = normalizeShapePoints(points);
2231
+ const element = PlaitNode.get(board, path);
2232
+ const newHeight = textHeight / board.viewport.zoom;
2233
+ const newProperties = { points: normalizePoints, textHeight: newHeight };
2234
+ if (PlaitDrawElement.isText(element) && element.autoSize) {
2235
+ newProperties.autoSize = false;
2236
+ }
2237
+ Transforms.setNode(board, newProperties, path);
2238
+ };
2239
+ const transformShape = (board, element, shape) => {
2240
+ const path = PlaitBoard.findPath(board, element);
2241
+ Transforms.setNode(board, { shape }, path);
2242
+ };
2243
+
2244
+ const normalizePoints = (board, element, width, textHeight) => {
2245
+ let points = element.points;
2246
+ let autoSize = element.autoSize;
2247
+ const defaultSpace = ShapeDefaultSpace.rectangleAndText;
2248
+ if (autoSize) {
2249
+ const editor = PlaitGeometry.getTextEditor(element);
2250
+ if (AlignEditor.isActive(editor, Alignment.right)) {
2251
+ points = [
2252
+ [points[1][0] - (width + defaultSpace * 2), points[0][1]],
2253
+ [points[1][0], points[0][1] + textHeight]
2254
+ ];
2255
+ }
2256
+ else if (AlignEditor.isActive(editor, Alignment.center)) {
2257
+ const oldWidth = Math.abs(points[0][0] - points[1][0]);
2258
+ const offset = (width - oldWidth) / 2;
2259
+ points = [
2260
+ [points[0][0] - offset - defaultSpace, points[0][1]],
2261
+ [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
2262
+ ];
2263
+ }
2264
+ else {
2265
+ points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
2266
+ }
2267
+ }
2268
+ return { points };
2269
+ };
2270
+ const setText = (board, element, text, width, textHeight) => {
2271
+ const newElement = {
2272
+ text,
2273
+ textHeight,
2274
+ ...normalizePoints(board, element, width, textHeight)
2275
+ };
2276
+ const path = board.children.findIndex(child => child === element);
2277
+ Transforms.setNode(board, newElement, [path]);
2278
+ };
2279
+ const setTextSize = (board, element, textWidth, textHeight) => {
2280
+ if (element.autoSize) {
2281
+ const newElement = {
2282
+ textHeight,
2283
+ ...normalizePoints(board, element, textWidth, textHeight)
2284
+ };
2285
+ const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
2286
+ const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
2287
+ if (!isPointsEqual || !isTextHeightEqual) {
2288
+ const path = board.children.findIndex(child => child === element);
2289
+ Transforms.setNode(board, newElement, [path]);
2290
+ }
2461
2291
  }
2462
2292
  };
2463
2293
 
2464
- var StrokeStyle;
2465
- (function (StrokeStyle) {
2466
- StrokeStyle["solid"] = "solid";
2467
- StrokeStyle["dashed"] = "dashed";
2468
- })(StrokeStyle || (StrokeStyle = {}));
2469
- var MemorizeKey;
2470
- (function (MemorizeKey) {
2471
- MemorizeKey["basicShape"] = "basicShape";
2472
- MemorizeKey["flowchart"] = "flowchart";
2473
- MemorizeKey["text"] = "text";
2474
- MemorizeKey["line"] = "line";
2475
- })(MemorizeKey || (MemorizeKey = {}));
2294
+ const insertImage = (board, imageItem, startPoint) => {
2295
+ const { width, height, url } = imageItem;
2296
+ const host = BOARD_TO_HOST.get(board);
2297
+ const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
2298
+ const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
2299
+ const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
2300
+ const points = startPoint
2301
+ ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
2302
+ : [
2303
+ [point[0] - width / 2, point[1] - height / 2],
2304
+ [point[0] + width / 2, point[1] + height / 2]
2305
+ ];
2306
+ const imageElement = {
2307
+ id: idCreator(),
2308
+ type: 'image',
2309
+ points,
2310
+ url
2311
+ };
2312
+ Transforms.insertNode(board, imageElement, [board.children.length]);
2313
+ Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
2314
+ };
2476
2315
 
2477
- const PlaitDrawElement = {
2478
- isGeometry: (value) => {
2479
- return value.type === 'geometry';
2480
- },
2481
- isLine: (value) => {
2482
- return value.type === 'line';
2483
- },
2484
- isText: (value) => {
2485
- return value.type === 'geometry' && value.shape === BasicShapes.text;
2486
- },
2487
- isImage: (value) => {
2488
- return value.type === 'image';
2489
- },
2490
- isDrawElement: (value) => {
2491
- if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
2492
- return true;
2493
- }
2494
- else {
2495
- return false;
2496
- }
2497
- },
2498
- isShape: (value) => {
2499
- return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
2500
- },
2501
- isBasicShape: (value) => {
2502
- return Object.keys(BasicShapes).includes(value.shape);
2503
- },
2504
- isFlowchart: (value) => {
2505
- return Object.keys(FlowchartSymbols).includes(value.shape);
2506
- }
2316
+ const resizeLine = (board, options, path) => {
2317
+ Transforms.setNode(board, options, path);
2318
+ };
2319
+ const setLineTexts = (board, element, texts) => {
2320
+ const path = PlaitBoard.findPath(board, element);
2321
+ Transforms.setNode(board, { texts }, path);
2322
+ };
2323
+ const removeLineText = (board, element, index) => {
2324
+ const path = PlaitBoard.findPath(board, element);
2325
+ const texts = element.texts?.length ? [...element.texts] : [];
2326
+ const newTexts = [...texts];
2327
+ newTexts.splice(index, 1);
2328
+ Transforms.setNode(board, { texts: newTexts }, path);
2329
+ };
2330
+ const setLineMark = (board, element, handleKey, marker) => {
2331
+ const path = PlaitBoard.findPath(board, element);
2332
+ let handle = handleKey === LineHandleKey.source ? element.source : element.target;
2333
+ handle = { ...handle, marker };
2334
+ memorizeLatest(MemorizeKey.line, handleKey, marker);
2335
+ Transforms.setNode(board, { [handleKey]: handle }, path);
2336
+ };
2337
+
2338
+ const DrawTransforms = {
2339
+ setText,
2340
+ insertGeometry,
2341
+ resizeGeometry,
2342
+ insertText,
2343
+ setTextSize,
2344
+ resizeLine,
2345
+ setLineTexts,
2346
+ removeLineText,
2347
+ setLineMark,
2348
+ insertImage,
2349
+ transformShape
2507
2350
  };
2508
2351
 
2509
2352
  class LineAutoCompleteGenerator extends Generator {
@@ -2636,7 +2479,7 @@ class GeometryComponent extends CommonPluginElement {
2636
2479
  this.textManage.updateRectangle();
2637
2480
  }
2638
2481
  initializeTextManage() {
2639
- const plugins = this.board.getPluginOptions(WithTextPluginKey).textPlugins;
2482
+ const plugins = (this.board.getPluginOptions(WithTextPluginKey) || {}).textPlugins;
2640
2483
  const manage = new TextManage(this.board, this.viewContainerRef, {
2641
2484
  getRectangle: () => {
2642
2485
  const getRectangle = getEngine(this.element.shape).getTextRectangle;
@@ -2674,7 +2517,7 @@ class GeometryComponent extends CommonPluginElement {
2674
2517
  this.destroy$.next();
2675
2518
  this.destroy$.complete();
2676
2519
  this.activeGenerator.destroy();
2677
- this.lineAutoCompleteGenerator;
2520
+ this.lineAutoCompleteGenerator.destroy();
2678
2521
  }
2679
2522
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2680
2523
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: GeometryComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -2949,6 +2792,173 @@ const withDrawHotkey = (board) => {
2949
2792
  return board;
2950
2793
  };
2951
2794
 
2795
+ const withGeometryCreateByDrag = (board) => {
2796
+ const { pointerMove, pointerUp } = board;
2797
+ let geometryShapeG = null;
2798
+ let temporaryElement = null;
2799
+ let fakeCreateTextRef = null;
2800
+ board.pointerMove = (event) => {
2801
+ geometryShapeG?.remove();
2802
+ geometryShapeG = createG();
2803
+ const geometryGenerator = new GeometryShapeGenerator(board);
2804
+ const geometryPointers = getGeometryPointers();
2805
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2806
+ const dragMode = isGeometryPointer && isDndMode(board);
2807
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2808
+ const pointer = PlaitBoard.getPointer(board);
2809
+ if (dragMode) {
2810
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
2811
+ if (pointer === BasicShapes.text) {
2812
+ const property = getDefaultTextShapeProperty(board, memorizedLatest.textProperties['font-size']);
2813
+ const points = getPointsByCenterPoint(movingPoint, property.width, property.height);
2814
+ temporaryElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text, memorizedLatest.geometryProperties, { ...memorizedLatest.textProperties, textHeight: property.height });
2815
+ if (!fakeCreateTextRef) {
2816
+ const textManage = new TextManage(board, PlaitBoard.getComponent(board).viewContainerRef, {
2817
+ getRectangle: () => {
2818
+ return getTextRectangle(temporaryElement);
2819
+ }
2820
+ });
2821
+ PlaitBoard.getComponent(board)
2822
+ .viewContainerRef.injector.get(NgZone)
2823
+ .run(() => {
2824
+ textManage.draw(temporaryElement.text);
2825
+ });
2826
+ fakeCreateTextRef = {
2827
+ g: createG(),
2828
+ textManage
2829
+ };
2830
+ PlaitBoard.getHost(board).append(fakeCreateTextRef.g);
2831
+ fakeCreateTextRef.g.append(textManage.g);
2832
+ }
2833
+ else {
2834
+ fakeCreateTextRef.textManage.updateRectangle();
2835
+ fakeCreateTextRef.g.append(fakeCreateTextRef.textManage.g);
2836
+ }
2837
+ }
2838
+ else {
2839
+ const points = getDefaultGeometryPoints(pointer, movingPoint);
2840
+ const textHeight = getDefaultTextShapeProperty(board, memorizedLatest.textProperties['font-size']).height;
2841
+ temporaryElement = createGeometryElement(pointer, points, '', {
2842
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth,
2843
+ ...memorizedLatest.geometryProperties
2844
+ }, { ...memorizedLatest.textProperties, textHeight });
2845
+ geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
2846
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2847
+ }
2848
+ }
2849
+ pointerMove(event);
2850
+ };
2851
+ board.pointerUp = (event) => {
2852
+ const geometryPointers = getGeometryPointers();
2853
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2854
+ const dragMode = isGeometryPointer && isDndMode(board);
2855
+ if (dragMode && temporaryElement) {
2856
+ insertElement(board, temporaryElement);
2857
+ fakeCreateTextRef?.textManage.destroy();
2858
+ fakeCreateTextRef?.g.remove();
2859
+ fakeCreateTextRef = null;
2860
+ }
2861
+ geometryShapeG?.remove();
2862
+ geometryShapeG = null;
2863
+ preventTouchMove(board, event, false);
2864
+ pointerUp(event);
2865
+ };
2866
+ return board;
2867
+ };
2868
+ const withGeometryCreateByDrawing = (board) => {
2869
+ const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
2870
+ let start = null;
2871
+ let geometryShapeG = null;
2872
+ let temporaryElement = null;
2873
+ let isShift = false;
2874
+ board.keydown = (event) => {
2875
+ isShift = isKeyHotkey('shift', event);
2876
+ keydown(event);
2877
+ };
2878
+ board.keyup = (event) => {
2879
+ isShift = false;
2880
+ keyup(event);
2881
+ };
2882
+ board.pointerDown = (event) => {
2883
+ const geometryPointers = getGeometryPointers();
2884
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2885
+ if (!PlaitBoard.isReadonly(board) && isGeometryPointer && isDrawingMode(board)) {
2886
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2887
+ start = point;
2888
+ const pointer = PlaitBoard.getPointer(board);
2889
+ preventTouchMove(board, event, true);
2890
+ if (pointer === BasicShapes.text) {
2891
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
2892
+ const property = getDefaultTextShapeProperty(board, memorizedLatest.textProperties['font-size']);
2893
+ const points = getPointsByCenterPoint(point, property.width, property.height);
2894
+ const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text, memorizedLatest.geometryProperties, { ...memorizedLatest.textProperties, textHeight: property.height });
2895
+ Transforms.insertNode(board, textElement, [board.children.length]);
2896
+ clearSelectedElement(board);
2897
+ addSelectedElement(board, textElement);
2898
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2899
+ start = null;
2900
+ }
2901
+ }
2902
+ pointerDown(event);
2903
+ };
2904
+ board.pointerMove = (event) => {
2905
+ geometryShapeG?.remove();
2906
+ geometryShapeG = createG();
2907
+ const geometryGenerator = new GeometryShapeGenerator(board);
2908
+ const drawMode = !!start;
2909
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2910
+ const pointer = PlaitBoard.getPointer(board);
2911
+ if (drawMode && pointer !== BasicShapes.text) {
2912
+ const points = normalizeShapePoints([start, movingPoint], isShift);
2913
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
2914
+ const textHeight = getDefaultTextShapeProperty(board, memorizedLatest.textProperties['font-size']).height;
2915
+ temporaryElement = createGeometryElement(pointer, points, '', {
2916
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth,
2917
+ ...memorizedLatest.geometryProperties
2918
+ }, { ...memorizedLatest.textProperties, textHeight });
2919
+ geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
2920
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2921
+ }
2922
+ pointerMove(event);
2923
+ };
2924
+ board.pointerUp = (event) => {
2925
+ const isDrawMode = !!start;
2926
+ if (isDrawMode) {
2927
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2928
+ const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
2929
+ if (Math.hypot(width, height) === 0) {
2930
+ const pointer = PlaitBoard.getPointer(board);
2931
+ if (pointer !== BasicShapes.text) {
2932
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
2933
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
2934
+ const textHeight = getDefaultTextShapeProperty(board, memorizedLatest.textProperties['font-size']).height;
2935
+ temporaryElement = createGeometryElement(pointer, points, '', {
2936
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth,
2937
+ ...memorizedLatest.geometryProperties
2938
+ }, { ...memorizedLatest.textProperties, textHeight });
2939
+ }
2940
+ }
2941
+ }
2942
+ if (temporaryElement) {
2943
+ insertElement(board, temporaryElement);
2944
+ }
2945
+ geometryShapeG?.remove();
2946
+ geometryShapeG = null;
2947
+ start = null;
2948
+ temporaryElement = null;
2949
+ preventTouchMove(board, event, false);
2950
+ pointerUp(event);
2951
+ };
2952
+ return board;
2953
+ };
2954
+ const insertElement = (board, element) => {
2955
+ memorizeLatestShape(board, element.shape);
2956
+ Transforms.insertNode(board, element, [board.children.length]);
2957
+ clearSelectedElement(board);
2958
+ addSelectedElement(board, element);
2959
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2960
+ };
2961
+
2952
2962
  const buildClipboardData = (board, elements, startPoint) => {
2953
2963
  return elements.map(element => {
2954
2964
  if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
@@ -3455,22 +3465,32 @@ class ImageComponent extends CommonPluginElement {
3455
3465
  };
3456
3466
  }
3457
3467
  });
3468
+ this.lineAutoCompleteGenerator = new LineAutoCompleteGenerator(this.board);
3458
3469
  }
3459
3470
  ngOnInit() {
3460
3471
  super.ngOnInit();
3461
3472
  this.initializeGenerator();
3462
3473
  this.imageGenerator.processDrawing(this.element, this.g, this.viewContainerRef);
3474
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3475
+ selected: this.selected
3476
+ });
3463
3477
  }
3464
3478
  onContextChanged(value, previous) {
3465
3479
  if (value.element !== previous.element) {
3466
3480
  this.imageGenerator.updateImage(this.g, previous.element, value.element);
3467
3481
  this.imageGenerator.componentRef.instance.isFocus = this.selected;
3482
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3483
+ selected: this.selected
3484
+ });
3468
3485
  }
3469
3486
  else {
3470
3487
  const hasSameSelected = value.selected === previous.selected;
3471
3488
  const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
3472
3489
  if (!hasSameSelected || !hasSameHandleState) {
3473
3490
  this.imageGenerator.componentRef.instance.isFocus = this.selected;
3491
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3492
+ selected: this.selected
3493
+ });
3474
3494
  }
3475
3495
  }
3476
3496
  }
@@ -3479,6 +3499,7 @@ class ImageComponent extends CommonPluginElement {
3479
3499
  this.destroy$.next();
3480
3500
  this.destroy$.complete();
3481
3501
  this.imageGenerator.destroy();
3502
+ this.lineAutoCompleteGenerator.destroy();
3482
3503
  }
3483
3504
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3484
3505
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ImageComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -3500,12 +3521,13 @@ const withLineAutoCompleteReaction = (board) => {
3500
3521
  reactionG?.remove();
3501
3522
  PlaitBoard.getBoardContainer(board).classList.remove(CursorClass.crosshair);
3502
3523
  const selectedElements = getSelectedDrawElements(board);
3524
+ const targetElement = selectedElements.length === 1 && selectedElements[0];
3503
3525
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3504
- if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && selectedElements.length === 1 && PlaitDrawElement.isGeometry(selectedElements[0])) {
3505
- const points = getAutoCompletePoints(selectedElements[0]);
3526
+ if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
3527
+ const points = getAutoCompletePoints(targetElement);
3506
3528
  const hitIndex = getHitIndexOfAutoCompletePoint(movingPoint, points);
3507
3529
  const hitPoint = points[hitIndex];
3508
- const component = PlaitElement.getComponent(selectedElements[0]);
3530
+ const component = PlaitElement.getComponent(targetElement);
3509
3531
  component.lineAutoCompleteGenerator.recoverAutoCompleteG();
3510
3532
  if (hitPoint) {
3511
3533
  component.lineAutoCompleteGenerator.removeAutoCompleteG(hitIndex);
@@ -3532,15 +3554,16 @@ const withLineAutoComplete = (board) => {
3532
3554
  let temporaryElement;
3533
3555
  board.pointerDown = (event) => {
3534
3556
  const selectedElements = getSelectedDrawElements(board);
3557
+ const targetElement = selectedElements.length === 1 && selectedElements[0];
3535
3558
  const clickPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3536
- if (!PlaitBoard.isReadonly(board) && selectedElements.length === 1 && PlaitDrawElement.isGeometry(selectedElements[0])) {
3537
- const points = getAutoCompletePoints(selectedElements[0]);
3559
+ if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
3560
+ const points = getAutoCompletePoints(targetElement);
3538
3561
  const index = getHitIndexOfAutoCompletePoint(clickPoint, points);
3539
3562
  const hitPoint = points[index];
3540
3563
  if (hitPoint) {
3541
3564
  temporaryDisableSelection(board);
3542
3565
  startPoint = clickPoint;
3543
- sourceElement = selectedElements[0];
3566
+ sourceElement = targetElement;
3544
3567
  BoardTransforms.updatePointerType(board, LineShape.elbow);
3545
3568
  }
3546
3569
  }
@@ -3656,5 +3679,5 @@ const withDraw = (board) => {
3656
3679
  * Generated bundle index. Do not edit.
3657
3680
  */
3658
3681
 
3659
- export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, REACTION_MARGIN, ShapeDefaultSpace, StrokeStyle, alignPoints, createDefaultFlowchart, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getAutoCompletePoints, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDrawDefaultStrokeColor, getEdgeOnPolygonByPoint, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, handleLineCreating, isHitDrawElement, isHitLineText, isHitPolyLine, isRectangleHitDrawElement, isTextExceedingBounds, memorizeLatestShape, memorizeLatestText, transformOpsToPoints, transformPointToConnection, withDraw };
3682
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, REACTION_MARGIN, ShapeDefaultSpace, StrokeStyle, alignPoints, createDefaultFlowchart, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getAutoCompletePoints, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDefaultTextShapeProperty, getDrawDefaultStrokeColor, getEdgeOnPolygonByPoint, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, handleLineCreating, isHitDrawElement, isHitLineText, isHitPolyLine, isRectangleHitDrawElement, isTextExceedingBounds, memorizeLatestShape, memorizeLatestText, transformOpsToPoints, transformPointToConnection, withDraw };
3660
3683
  //# sourceMappingURL=plait-draw.mjs.map