@plait/draw 0.29.0 → 0.30.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, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, drawLinearPath, rotate, getElementById, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, BOARD_TO_HOST, transformPoint, toPoint, isSelectionMoving, PlaitPluginElementComponent, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
2
- import { getRectangleByPoints, getFactorByPoints, getDirectionByVector, getOppositeDirection, getDirectionFactor, getPoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, Generator, normalizeShapePoints, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, acceptImageTypes, buildImage, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint, ImageGenerator } from '@plait/common';
3
- import { Alignment, buildText, AlignEditor, TextManage, DEFAULT_FONT_SIZE, getTextFromClipboard, getTextSize } from '@plait/text';
1
+ import { PlaitElement, ACTIVE_STROKE_WIDTH, 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, drawLinearPath, rotate, getElementById, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, isPolylineHitRectangle, isSelectionMoving, PlaitPluginElementComponent, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElementByPoint } from '@plait/core';
2
+ import { getRectangleByPoints, Generator, normalizeShapePoints, isDndMode, isDrawingMode, getFactorByPoints, getDirectionByVector, getOppositeDirection, getDirectionFactor, DEFAULT_ROUTE_MARGIN, reduceRouteMargin, getNextPoint, generateElbowLineRoute, getPoints, removeDuplicatePoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, acceptImageTypes, getElementOfFocusedImage, buildImage, getRectangleResizeHandleRefs, 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';
4
5
  import { pointsOnBezierCurves } from 'points-on-curve';
5
6
  import * as i0 from '@angular/core';
6
7
  import { Component, ChangeDetectionStrategy } from '@angular/core';
7
8
  import { Subject } from 'rxjs';
8
- import { isKeyHotkey } from 'is-hotkey';
9
9
  import { Node } from 'slate';
10
10
 
11
11
  var BasicShapes;
@@ -1168,192 +1168,575 @@ const getShape = (value) => {
1168
1168
  return value.shape;
1169
1169
  };
1170
1170
 
1171
- const createGeometryElement = (shape, points, text, options) => {
1172
- let textOptions = {};
1173
- let alignment = Alignment.center;
1174
- if (shape === BasicShapes.text) {
1175
- textOptions = { autoSize: true };
1176
- alignment = undefined;
1177
- }
1178
- let flowchartOptions = {};
1179
- if (getFlowchartPointers().includes(shape)) {
1180
- flowchartOptions = { fill: '#ffffff' };
1171
+ class GeometryShapeGenerator extends Generator {
1172
+ canDraw(element, data) {
1173
+ return true;
1181
1174
  }
1182
- return {
1183
- id: idCreator(),
1184
- type: 'geometry',
1185
- shape,
1186
- angle: 0,
1187
- opacity: 1,
1188
- textHeight: DefaultTextProperty.height,
1189
- text: buildText(text, alignment),
1190
- points,
1191
- ...textOptions,
1192
- ...options,
1193
- ...flowchartOptions
1194
- };
1195
- };
1196
- const getPointsByCenterPoint = (point, width, height) => {
1197
- const leftTopPoint = [point[0] - width / 2, point[1] - height / 2];
1198
- const rightBottomPoint = [point[0] + width / 2, point[1] + height / 2];
1199
- return [leftTopPoint, rightBottomPoint];
1200
- };
1201
- const getTextRectangle = (element) => {
1202
- const elementRectangle = getRectangleByPoints(element.points);
1203
- const strokeWidth = getStrokeWidthByElement(element);
1204
- const height = element.textHeight;
1205
- const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1206
- return {
1207
- height,
1208
- width: width > 0 ? width : 0,
1209
- x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
1210
- y: elementRectangle.y + (elementRectangle.height - height) / 2
1211
- };
1212
- };
1213
- const drawBoundMask = (board, element) => {
1214
- const G = createG();
1215
- const rectangle = getRectangleByPoints(element.points);
1216
- const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
1217
- const shape = getShape(element);
1218
- const maskG = drawGeometry(board, activeRectangle, shape, {
1219
- stroke: SELECTION_BORDER_COLOR,
1220
- strokeWidth: 1,
1221
- fill: SELECTION_FILL_COLOR,
1222
- fillStyle: 'solid'
1223
- });
1224
- G.appendChild(maskG);
1225
- const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
1226
- connectorPoints.forEach(point => {
1227
- const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
1228
- stroke: '#999999',
1229
- strokeWidth: 1,
1230
- fill: '#FFF',
1231
- fillStyle: 'solid'
1175
+ baseDraw(element, data) {
1176
+ const rectangle = getRectangleByPoints(element.points);
1177
+ const shape = element.shape;
1178
+ if (shape === BasicShapes.text) {
1179
+ return;
1180
+ }
1181
+ const strokeWidth = getStrokeWidthByElement(element);
1182
+ const strokeColor = getStrokeColorByElement(element);
1183
+ const fill = getFillByElement(element);
1184
+ const strokeLineDash = getLineDashByElement(element);
1185
+ return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1186
+ stroke: strokeColor,
1187
+ strokeWidth,
1188
+ fill,
1189
+ strokeLineDash
1232
1190
  });
1233
- G.appendChild(circleG);
1191
+ }
1192
+ }
1193
+
1194
+ const insertGeometry = (board, points, shape) => {
1195
+ let newElement = createGeometryElement(shape, points, '', {
1196
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1197
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1234
1198
  });
1235
- return G;
1236
- };
1237
- const drawGeometry = (board, outerRectangle, shape, options) => {
1238
- return getEngine(shape).draw(board, outerRectangle, options);
1239
- };
1240
- const getNearestPoint = (element, point, inflateDelta = 0) => {
1241
- const rectangle = getRectangleByPoints(element.points);
1242
- const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
1243
- const shape = getShape(element);
1244
- return getEngine(shape).getNearestPoint(activeRectangle, point);
1199
+ Transforms.insertNode(board, newElement, [board.children.length]);
1200
+ clearSelectedElement(board);
1201
+ addSelectedElement(board, newElement);
1245
1202
  };
1246
- const getCenterPointsOnPolygon = (points) => {
1247
- const centerPoint = [];
1248
- for (let i = 0; i < points.length; i++) {
1249
- let j = i == points.length - 1 ? 0 : i + 1;
1250
- centerPoint.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1251
- }
1252
- return centerPoint;
1203
+ const insertText = (board, points, text = '文本') => {
1204
+ let newElement = createGeometryElement(BasicShapes.text, points, text);
1205
+ Transforms.insertNode(board, newElement, [board.children.length]);
1206
+ clearSelectedElement(board);
1207
+ addSelectedElement(board, newElement);
1253
1208
  };
1254
- const getEdgeOnPolygonByPoint = (corners, point) => {
1255
- for (let index = 1; index <= corners.length; index++) {
1256
- let start = corners[index - 1];
1257
- let end = index === corners.length ? corners[0] : corners[index];
1258
- const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1259
- if (distance < 1) {
1260
- return [start, end];
1261
- }
1209
+ const resizeGeometry = (board, points, textHeight, path) => {
1210
+ const normalizePoints = normalizeShapePoints(points);
1211
+ const element = PlaitNode.get(board, path);
1212
+ const newHeight = textHeight / board.viewport.zoom;
1213
+ const newProperties = { points: normalizePoints, textHeight: newHeight };
1214
+ if (PlaitDrawElement.isText(element) && element.autoSize) {
1215
+ newProperties.autoSize = false;
1262
1216
  }
1263
- return null;
1264
- };
1265
- const getDefaultFlowchartProperty = (symbol) => {
1266
- return DefaultFlowchartPropertyMap[symbol];
1217
+ Transforms.setNode(board, newProperties, path);
1267
1218
  };
1268
1219
 
1269
- const drawLineArrow = (element, points, options) => {
1270
- const arrowG = createG();
1271
- if (PlaitLine.isSourceMark(element, LineMarkerType.none) && PlaitLine.isTargetMark(element, LineMarkerType.none)) {
1272
- return null;
1273
- }
1274
- if (!PlaitLine.isSourceMark(element, LineMarkerType.none)) {
1275
- const source = getExtendPoint(points[0], points[1], 24);
1276
- const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
1277
- sourceArrow && arrowG.appendChild(sourceArrow);
1278
- }
1279
- if (!PlaitLine.isTargetMark(element, LineMarkerType.none)) {
1280
- const source = getExtendPoint(points[points.length - 1], points[points.length - 2], 24);
1281
- const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
1282
- arrow && arrowG.appendChild(arrow);
1283
- }
1284
- return arrowG;
1285
- };
1286
- const getArrow = (element, arrowOptions, options) => {
1287
- const { marker, source, target, isSource } = arrowOptions;
1288
- let targetArrow;
1289
- switch (marker) {
1290
- case LineMarkerType.openTriangle: {
1291
- targetArrow = drawOpenTriangle(element, source, target, options);
1292
- break;
1293
- }
1294
- case LineMarkerType.solidTriangle: {
1295
- targetArrow = drawSolidTriangle(source, target, options);
1296
- break;
1297
- }
1298
- case LineMarkerType.arrow: {
1299
- targetArrow = drawArrow(element, source, target, options);
1300
- break;
1301
- }
1302
- case LineMarkerType.sharpArrow: {
1303
- targetArrow = drawSharpArrow(source, target, options);
1304
- break;
1305
- }
1306
- case LineMarkerType.oneSideUp: {
1307
- targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1308
- break;
1309
- }
1310
- case LineMarkerType.oneSideDown: {
1311
- targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1312
- break;
1220
+ const normalizePoints = (board, element, width, textHeight) => {
1221
+ let points = element.points;
1222
+ let autoSize = element.autoSize;
1223
+ const defaultSpace = ShapeDefaultSpace.rectangleAndText;
1224
+ if (autoSize) {
1225
+ const editor = PlaitGeometry.getTextEditor(element);
1226
+ if (AlignEditor.isActive(editor, Alignment.right)) {
1227
+ points = [
1228
+ [points[1][0] - (width + defaultSpace * 2), points[0][1]],
1229
+ [points[1][0], points[0][1] + textHeight]
1230
+ ];
1313
1231
  }
1314
- case LineMarkerType.hollowTriangle: {
1315
- targetArrow = drawHollowTriangleArrow(source, target, options);
1316
- break;
1232
+ else if (AlignEditor.isActive(editor, Alignment.center)) {
1233
+ const oldWidth = Math.abs(points[0][0] - points[1][0]);
1234
+ const offset = (width - oldWidth) / 2;
1235
+ points = [
1236
+ [points[0][0] - offset - defaultSpace, points[0][1]],
1237
+ [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
1238
+ ];
1317
1239
  }
1318
- case LineMarkerType.singleSlash: {
1319
- targetArrow = drawSingleSlash(source, target, isSource, options);
1320
- break;
1240
+ else {
1241
+ points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
1321
1242
  }
1322
1243
  }
1323
- return targetArrow;
1324
- };
1325
- const drawSharpArrow = (source, target, options) => {
1326
- const startPoint = target;
1327
- const { pointLeft, pointRight } = arrowPoints(source, target, 12, 20);
1328
- const g = createG();
1329
- const path = createPath();
1330
- let polylinePath = `M${pointRight[0]},${pointRight[1]}A8,8,20,0,1,${pointLeft[0]},${pointLeft[1]}L${startPoint[0]},${startPoint[1]}Z`;
1331
- path.setAttribute('d', polylinePath);
1332
- path.setAttribute('stroke', `${options?.stroke}`);
1333
- path.setAttribute('stroke-width', `${options?.strokeWidth}`);
1334
- path.setAttribute('fill', `${options?.stroke}`);
1335
- g.appendChild(path);
1336
- return g;
1244
+ return { points };
1337
1245
  };
1338
- const drawArrow = (element, source, target, options) => {
1339
- const directionFactor = getFactorByPoints(source, target);
1340
- const strokeWidth = getStrokeWidthByElement(element);
1341
- const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
1342
- const middlePoint = [endPoint[0] - 8 * directionFactor.x, endPoint[1] - 8 * directionFactor.y];
1343
- const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
1344
- const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
1345
- const path = arrowG.querySelector('path');
1346
- path.setAttribute('stroke-linejoin', 'round');
1347
- return arrowG;
1246
+ const setText = (board, element, text, width, textHeight) => {
1247
+ const newElement = {
1248
+ text,
1249
+ textHeight,
1250
+ ...normalizePoints(board, element, width, textHeight)
1251
+ };
1252
+ const path = board.children.findIndex(child => child === element);
1253
+ Transforms.setNode(board, newElement, [path]);
1348
1254
  };
1349
- const drawSolidTriangle = (source, target, options) => {
1350
- const endPoint = target;
1351
- const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
1352
- return drawLinearPath([pointLeft, endPoint, pointRight], { ...options, fill: options.stroke }, true);
1255
+ const setTextSize = (board, element, textWidth, textHeight) => {
1256
+ if (element.autoSize) {
1257
+ const newElement = {
1258
+ textHeight,
1259
+ ...normalizePoints(board, element, textWidth, textHeight)
1260
+ };
1261
+ const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
1262
+ const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
1263
+ if (!isPointsEqual || !isTextHeightEqual) {
1264
+ const path = board.children.findIndex(child => child === element);
1265
+ Transforms.setNode(board, newElement, [path]);
1266
+ }
1267
+ }
1353
1268
  };
1354
- const drawOpenTriangle = (element, source, target, options) => {
1355
- const directionFactor = getFactorByPoints(source, target);
1356
- const strokeWidth = getStrokeWidthByElement(element);
1269
+
1270
+ const insertImage = (board, imageItem, startPoint) => {
1271
+ const { width, height, url } = imageItem;
1272
+ const host = BOARD_TO_HOST.get(board);
1273
+ const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1274
+ const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1275
+ const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1276
+ const points = startPoint
1277
+ ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1278
+ : [
1279
+ [point[0] - width / 2, point[1] - height / 2],
1280
+ [point[0] + width / 2, point[1] + height / 2]
1281
+ ];
1282
+ const imageElement = {
1283
+ id: idCreator(),
1284
+ type: 'image',
1285
+ points,
1286
+ url
1287
+ };
1288
+ Transforms.insertNode(board, imageElement, [board.children.length]);
1289
+ Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
1290
+ };
1291
+
1292
+ const resizeLine = (board, options, path) => {
1293
+ Transforms.setNode(board, options, path);
1294
+ };
1295
+ const setLineTexts = (board, element, texts) => {
1296
+ const path = PlaitBoard.findPath(board, element);
1297
+ Transforms.setNode(board, { texts }, path);
1298
+ };
1299
+ const removeLineText = (board, element, index) => {
1300
+ const path = PlaitBoard.findPath(board, element);
1301
+ const texts = element.texts?.length ? [...element.texts] : [];
1302
+ const newTexts = [...texts];
1303
+ newTexts.splice(index, 1);
1304
+ Transforms.setNode(board, { texts: newTexts }, path);
1305
+ };
1306
+ const setLineMark = (board, element, handleKey, marker) => {
1307
+ const path = PlaitBoard.findPath(board, element);
1308
+ let handle = handleKey === LineHandleKey.source ? element.source : element.target;
1309
+ handle = { ...handle, marker };
1310
+ Transforms.setNode(board, { [handleKey]: handle }, path);
1311
+ };
1312
+
1313
+ const DrawTransforms = {
1314
+ setText,
1315
+ insertGeometry,
1316
+ resizeGeometry,
1317
+ insertText,
1318
+ setTextSize,
1319
+ resizeLine,
1320
+ setLineTexts,
1321
+ removeLineText,
1322
+ setLineMark,
1323
+ insertImage
1324
+ };
1325
+
1326
+ const withGeometryCreateByDrag = (board) => {
1327
+ const { pointerMove, pointerUp } = board;
1328
+ let geometryShapeG = null;
1329
+ board.pointerMove = (event) => {
1330
+ geometryShapeG?.remove();
1331
+ geometryShapeG = createG();
1332
+ const geometryGenerator = new GeometryShapeGenerator(board);
1333
+ const geometryPointers = getGeometryPointers();
1334
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1335
+ const dragMode = isGeometryPointer && isDndMode(board);
1336
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1337
+ const pointer = PlaitBoard.getPointer(board);
1338
+ if (dragMode) {
1339
+ const points = getDefaultGeometryPoints(pointer, movingPoint);
1340
+ if (pointer === BasicShapes.text) {
1341
+ const textG = getTemporaryTextG(movingPoint);
1342
+ geometryShapeG.appendChild(textG);
1343
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1344
+ }
1345
+ else {
1346
+ const temporaryElement = createGeometryElement(pointer, points, '', {
1347
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1348
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1349
+ });
1350
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1351
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1352
+ }
1353
+ }
1354
+ pointerMove(event);
1355
+ };
1356
+ board.pointerUp = (event) => {
1357
+ const pointer = PlaitBoard.getPointer(board);
1358
+ const geometryPointers = getGeometryPointers();
1359
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1360
+ const dragMode = isGeometryPointer && isDndMode(board);
1361
+ if (dragMode) {
1362
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1363
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1364
+ if (pointer === BasicShapes.text) {
1365
+ DrawTransforms.insertText(board, points);
1366
+ }
1367
+ else {
1368
+ DrawTransforms.insertGeometry(board, points, pointer);
1369
+ }
1370
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1371
+ }
1372
+ geometryShapeG?.remove();
1373
+ geometryShapeG = null;
1374
+ preventTouchMove(board, event, false);
1375
+ pointerUp(event);
1376
+ };
1377
+ return board;
1378
+ };
1379
+ const withGeometryCreateByDrawing = (board) => {
1380
+ const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1381
+ let start = null;
1382
+ let geometryShapeG = null;
1383
+ let temporaryElement = null;
1384
+ let isShift = false;
1385
+ board.keydown = (event) => {
1386
+ isShift = isKeyHotkey('shift', event);
1387
+ keydown(event);
1388
+ };
1389
+ board.keyup = (event) => {
1390
+ isShift = false;
1391
+ keyup(event);
1392
+ };
1393
+ board.pointerDown = (event) => {
1394
+ const geometryPointers = getGeometryPointers();
1395
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1396
+ if (isGeometryPointer && isDrawingMode(board)) {
1397
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1398
+ start = point;
1399
+ const pointer = PlaitBoard.getPointer(board);
1400
+ preventTouchMove(board, event, true);
1401
+ if (pointer === BasicShapes.text) {
1402
+ const points = getDefaultGeometryPoints(pointer, point);
1403
+ const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text);
1404
+ Transforms.insertNode(board, textElement, [board.children.length]);
1405
+ clearSelectedElement(board);
1406
+ addSelectedElement(board, textElement);
1407
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1408
+ start = null;
1409
+ }
1410
+ }
1411
+ pointerDown(event);
1412
+ };
1413
+ board.pointerMove = (event) => {
1414
+ geometryShapeG?.remove();
1415
+ geometryShapeG = createG();
1416
+ const geometryGenerator = new GeometryShapeGenerator(board);
1417
+ const drawMode = !!start;
1418
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1419
+ const pointer = PlaitBoard.getPointer(board);
1420
+ if (drawMode && pointer !== BasicShapes.text) {
1421
+ const points = normalizeShapePoints([start, movingPoint], isShift);
1422
+ temporaryElement = createGeometryElement(pointer, points, '', {
1423
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1424
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1425
+ });
1426
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1427
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1428
+ }
1429
+ pointerMove(event);
1430
+ };
1431
+ board.pointerUp = (event) => {
1432
+ const isDrawMode = !!start;
1433
+ if (isDrawMode) {
1434
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1435
+ const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
1436
+ if (Math.hypot(width, height) === 0) {
1437
+ const pointer = PlaitBoard.getPointer(board);
1438
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1439
+ if (pointer !== BasicShapes.text) {
1440
+ temporaryElement = createGeometryElement(pointer, points, '', {
1441
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1442
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1443
+ });
1444
+ }
1445
+ }
1446
+ }
1447
+ if (temporaryElement) {
1448
+ Transforms.insertNode(board, temporaryElement, [board.children.length]);
1449
+ clearSelectedElement(board);
1450
+ addSelectedElement(board, temporaryElement);
1451
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1452
+ }
1453
+ geometryShapeG?.remove();
1454
+ geometryShapeG = null;
1455
+ start = null;
1456
+ temporaryElement = null;
1457
+ preventTouchMove(board, event, false);
1458
+ pointerUp(event);
1459
+ };
1460
+ return board;
1461
+ };
1462
+ const getDefaultGeometryPoints = (pointer, targetPoint) => {
1463
+ const defaultProperty = getGeometryDefaultProperty(pointer);
1464
+ return getPointsByCenterPoint(targetPoint, defaultProperty.width, defaultProperty.height);
1465
+ };
1466
+ const getGeometryDefaultProperty = (pointer) => {
1467
+ const isText = pointer === BasicShapes.text;
1468
+ const isFlowChart = getFlowchartPointers().includes(pointer);
1469
+ if (isText) {
1470
+ return DefaultTextProperty;
1471
+ }
1472
+ else if (isFlowChart) {
1473
+ return getDefaultFlowchartProperty(pointer);
1474
+ }
1475
+ else {
1476
+ return DefaultBasicShapeProperty;
1477
+ }
1478
+ };
1479
+ const getTemporaryTextG = (movingPoint) => {
1480
+ const textG = createG();
1481
+ const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
1482
+ const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
1483
+ const richtext = document.createElement('div');
1484
+ richtext.textContent = DefaultTextProperty.text;
1485
+ richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
1486
+ richtext.style.cursor = 'default';
1487
+ foreignObject.appendChild(richtext);
1488
+ textG.appendChild(foreignObject);
1489
+ return textG;
1490
+ };
1491
+
1492
+ const DefaultLineStyle = {
1493
+ strokeWidth: 2,
1494
+ strokeColor: '#000'
1495
+ };
1496
+
1497
+ const createGeometryElement = (shape, points, text, options) => {
1498
+ let textOptions = {};
1499
+ let alignment = Alignment.center;
1500
+ if (shape === BasicShapes.text) {
1501
+ textOptions = { autoSize: true };
1502
+ alignment = undefined;
1503
+ }
1504
+ let flowchartOptions = {};
1505
+ if (getFlowchartPointers().includes(shape)) {
1506
+ flowchartOptions = { fill: '#ffffff' };
1507
+ }
1508
+ return {
1509
+ id: idCreator(),
1510
+ type: 'geometry',
1511
+ shape,
1512
+ angle: 0,
1513
+ opacity: 1,
1514
+ textHeight: DefaultTextProperty.height,
1515
+ text: buildText(text, alignment),
1516
+ points,
1517
+ ...textOptions,
1518
+ ...options,
1519
+ ...flowchartOptions
1520
+ };
1521
+ };
1522
+ const getPointsByCenterPoint = (point, width, height) => {
1523
+ const leftTopPoint = [point[0] - width / 2, point[1] - height / 2];
1524
+ const rightBottomPoint = [point[0] + width / 2, point[1] + height / 2];
1525
+ return [leftTopPoint, rightBottomPoint];
1526
+ };
1527
+ const getTextRectangle = (element) => {
1528
+ const elementRectangle = getRectangleByPoints(element.points);
1529
+ const strokeWidth = getStrokeWidthByElement(element);
1530
+ const height = element.textHeight;
1531
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1532
+ return {
1533
+ height,
1534
+ width: width > 0 ? width : 0,
1535
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
1536
+ y: elementRectangle.y + (elementRectangle.height - height) / 2
1537
+ };
1538
+ };
1539
+ const drawBoundMask = (board, element) => {
1540
+ const G = createG();
1541
+ const rectangle = getRectangleByPoints(element.points);
1542
+ const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
1543
+ const shape = getShape(element);
1544
+ const maskG = drawGeometry(board, activeRectangle, shape, {
1545
+ stroke: SELECTION_BORDER_COLOR,
1546
+ strokeWidth: 1,
1547
+ fill: SELECTION_FILL_COLOR,
1548
+ fillStyle: 'solid'
1549
+ });
1550
+ G.appendChild(maskG);
1551
+ const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
1552
+ connectorPoints.forEach(point => {
1553
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
1554
+ stroke: '#999999',
1555
+ strokeWidth: 1,
1556
+ fill: '#FFF',
1557
+ fillStyle: 'solid'
1558
+ });
1559
+ G.appendChild(circleG);
1560
+ });
1561
+ return G;
1562
+ };
1563
+ const drawGeometry = (board, outerRectangle, shape, options) => {
1564
+ return getEngine(shape).draw(board, outerRectangle, options);
1565
+ };
1566
+ const getNearestPoint = (element, point, inflateDelta = 0) => {
1567
+ const rectangle = getRectangleByPoints(element.points);
1568
+ const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
1569
+ const shape = getShape(element);
1570
+ return getEngine(shape).getNearestPoint(activeRectangle, point);
1571
+ };
1572
+ const getCenterPointsOnPolygon = (points) => {
1573
+ const centerPoint = [];
1574
+ for (let i = 0; i < points.length; i++) {
1575
+ let j = i == points.length - 1 ? 0 : i + 1;
1576
+ centerPoint.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1577
+ }
1578
+ return centerPoint;
1579
+ };
1580
+ const getEdgeOnPolygonByPoint = (corners, point) => {
1581
+ for (let index = 1; index <= corners.length; index++) {
1582
+ let start = corners[index - 1];
1583
+ let end = index === corners.length ? corners[0] : corners[index];
1584
+ const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1585
+ if (distance < 1) {
1586
+ return [start, end];
1587
+ }
1588
+ }
1589
+ return null;
1590
+ };
1591
+ const getDefaultFlowchartProperty = (symbol) => {
1592
+ return DefaultFlowchartPropertyMap[symbol];
1593
+ };
1594
+ const createDefaultFlowchart = (point) => {
1595
+ const decisionProperty = getDefaultFlowchartProperty(FlowchartSymbols.decision);
1596
+ const processProperty = getDefaultFlowchartProperty(FlowchartSymbols.process);
1597
+ const terminalProperty = getDefaultFlowchartProperty(FlowchartSymbols.terminal);
1598
+ const options = {
1599
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1600
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1601
+ };
1602
+ const lineOptions = {
1603
+ strokeColor: DefaultLineStyle.strokeColor,
1604
+ strokeWidth: DefaultLineStyle.strokeWidth
1605
+ };
1606
+ const startElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, point), '开始', options);
1607
+ const processPoint1 = [point[0], point[1] + terminalProperty.height / 2 + 55 + processProperty.height / 2];
1608
+ const processElement1 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint1), '过程', options);
1609
+ const decisionPoint = [processPoint1[0], processPoint1[1] + processProperty.height / 2 + 55 + decisionProperty.height / 2];
1610
+ const decisionElement = createGeometryElement(FlowchartSymbols.decision, getDefaultGeometryPoints(FlowchartSymbols.decision, decisionPoint), '过程', options);
1611
+ const processPoint2 = [decisionPoint[0] + decisionProperty.width / 2 + 75 + processProperty.width / 2, decisionPoint[1]];
1612
+ const processElement2 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint2), '过程', options);
1613
+ const endPoint = [decisionPoint[0], decisionPoint[1] + decisionProperty.height / 2 + 95 + terminalProperty.height / 2];
1614
+ const endElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, endPoint), '结束', options);
1615
+ const line1 = createLineElement(LineShape.elbow, [
1616
+ [0, 0],
1617
+ [0, 0]
1618
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: startElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: processElement1.id }, [], lineOptions);
1619
+ const line2 = createLineElement(LineShape.elbow, [
1620
+ [0, 0],
1621
+ [0, 0]
1622
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement1.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: decisionElement.id }, [], lineOptions);
1623
+ const line3 = createLineElement(LineShape.elbow, [
1624
+ [0, 0],
1625
+ [0, 0]
1626
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: endElement.id }, [
1627
+ {
1628
+ text: buildText('是'),
1629
+ position: 0.5,
1630
+ width: 14,
1631
+ height: 20
1632
+ }
1633
+ ], lineOptions);
1634
+ const line4 = createLineElement(LineShape.elbow, [
1635
+ [0, 0],
1636
+ [0, 0]
1637
+ ], { marker: LineMarkerType.none, connection: [1, 0.5], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0, 0.5], boundId: processElement2.id }, [
1638
+ {
1639
+ text: buildText('否'),
1640
+ position: 0.5,
1641
+ width: 14,
1642
+ height: 20
1643
+ }
1644
+ ], lineOptions);
1645
+ const line5 = createLineElement(LineShape.elbow, [
1646
+ [0, 0],
1647
+ [0, 0]
1648
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement2.id }, { marker: LineMarkerType.arrow, connection: [1, 0.5], boundId: endElement.id }, [], lineOptions);
1649
+ return [startElement, processElement1, decisionElement, processElement2, endElement, line1, line2, line3, line4, line5];
1650
+ };
1651
+
1652
+ const drawLineArrow = (element, points, options) => {
1653
+ const arrowG = createG();
1654
+ if (PlaitLine.isSourceMark(element, LineMarkerType.none) && PlaitLine.isTargetMark(element, LineMarkerType.none)) {
1655
+ return null;
1656
+ }
1657
+ if (!PlaitLine.isSourceMark(element, LineMarkerType.none)) {
1658
+ const source = getExtendPoint(points[0], points[1], 24);
1659
+ const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
1660
+ sourceArrow && arrowG.appendChild(sourceArrow);
1661
+ }
1662
+ if (!PlaitLine.isTargetMark(element, LineMarkerType.none)) {
1663
+ const source = getExtendPoint(points[points.length - 1], points[points.length - 2], 24);
1664
+ const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
1665
+ arrow && arrowG.appendChild(arrow);
1666
+ }
1667
+ return arrowG;
1668
+ };
1669
+ const getArrow = (element, arrowOptions, options) => {
1670
+ const { marker, source, target, isSource } = arrowOptions;
1671
+ let targetArrow;
1672
+ switch (marker) {
1673
+ case LineMarkerType.openTriangle: {
1674
+ targetArrow = drawOpenTriangle(element, source, target, options);
1675
+ break;
1676
+ }
1677
+ case LineMarkerType.solidTriangle: {
1678
+ targetArrow = drawSolidTriangle(source, target, options);
1679
+ break;
1680
+ }
1681
+ case LineMarkerType.arrow: {
1682
+ targetArrow = drawArrow(element, source, target, options);
1683
+ break;
1684
+ }
1685
+ case LineMarkerType.sharpArrow: {
1686
+ targetArrow = drawSharpArrow(source, target, options);
1687
+ break;
1688
+ }
1689
+ case LineMarkerType.oneSideUp: {
1690
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1691
+ break;
1692
+ }
1693
+ case LineMarkerType.oneSideDown: {
1694
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1695
+ break;
1696
+ }
1697
+ case LineMarkerType.hollowTriangle: {
1698
+ targetArrow = drawHollowTriangleArrow(source, target, options);
1699
+ break;
1700
+ }
1701
+ case LineMarkerType.singleSlash: {
1702
+ targetArrow = drawSingleSlash(source, target, isSource, options);
1703
+ break;
1704
+ }
1705
+ }
1706
+ return targetArrow;
1707
+ };
1708
+ const drawSharpArrow = (source, target, options) => {
1709
+ const startPoint = target;
1710
+ const { pointLeft, pointRight } = arrowPoints(source, target, 12, 20);
1711
+ const g = createG();
1712
+ const path = createPath();
1713
+ let polylinePath = `M${pointRight[0]},${pointRight[1]}A8,8,20,0,1,${pointLeft[0]},${pointLeft[1]}L${startPoint[0]},${startPoint[1]}Z`;
1714
+ path.setAttribute('d', polylinePath);
1715
+ path.setAttribute('stroke', `${options?.stroke}`);
1716
+ path.setAttribute('stroke-width', `${options?.strokeWidth}`);
1717
+ path.setAttribute('fill', `${options?.stroke}`);
1718
+ g.appendChild(path);
1719
+ return g;
1720
+ };
1721
+ const drawArrow = (element, source, target, options) => {
1722
+ const directionFactor = getFactorByPoints(source, target);
1723
+ const strokeWidth = getStrokeWidthByElement(element);
1724
+ const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
1725
+ const middlePoint = [endPoint[0] - 8 * directionFactor.x, endPoint[1] - 8 * directionFactor.y];
1726
+ const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
1727
+ const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
1728
+ const path = arrowG.querySelector('path');
1729
+ path.setAttribute('stroke-linejoin', 'round');
1730
+ return arrowG;
1731
+ };
1732
+ const drawSolidTriangle = (source, target, options) => {
1733
+ const endPoint = target;
1734
+ const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
1735
+ return drawLinearPath([pointLeft, endPoint, pointRight], { ...options, fill: options.stroke }, true);
1736
+ };
1737
+ const drawOpenTriangle = (element, source, target, options) => {
1738
+ const directionFactor = getFactorByPoints(source, target);
1739
+ const strokeWidth = getStrokeWidthByElement(element);
1357
1740
  const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
1358
1741
  const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 40);
1359
1742
  return drawLinearPath([pointLeft, endPoint, pointRight], options);
@@ -1375,13 +1758,13 @@ const drawHollowTriangleArrow = (source, target, options) => {
1375
1758
  return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
1376
1759
  };
1377
1760
 
1378
- const createLineElement = (shape, points, source, target, options) => {
1761
+ const createLineElement = (shape, points, source, target, texts, options) => {
1379
1762
  return {
1380
1763
  id: idCreator(),
1381
1764
  type: 'line',
1382
1765
  shape,
1383
1766
  source,
1384
- texts: [],
1767
+ texts: texts ? texts : [],
1385
1768
  target,
1386
1769
  opacity: 1,
1387
1770
  points,
@@ -1452,8 +1835,41 @@ const getLineHandleRefPair = (board, element) => {
1452
1835
  const getElbowPoints = (board, element) => {
1453
1836
  if (element.points.length === 2) {
1454
1837
  const handleRefPair = getLineHandleRefPair(board, element);
1455
- const offset = element.source.boundId || element.target.boundId ? 30 : 0;
1456
- let points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, offset);
1838
+ const offset = element.source.boundId || element.target.boundId ? DEFAULT_ROUTE_MARGIN : 0;
1839
+ const sourceElement = element.source.boundId && getElementById(board, element.source.boundId);
1840
+ const targetElement = element.target.boundId && getElementById(board, element.target.boundId);
1841
+ const isBound = sourceElement && targetElement;
1842
+ let points = [];
1843
+ if (isBound) {
1844
+ const targetRectangle = RectangleClient.inflate(getRectangleByPoints(targetElement.points), getStrokeWidthByElement(targetElement) * 2);
1845
+ const sourceRectangle = RectangleClient.inflate(getRectangleByPoints(sourceElement.points), getStrokeWidthByElement(sourceElement) * 2);
1846
+ const sourcePoint = handleRefPair.source.point;
1847
+ const targetPoint = handleRefPair.target.point;
1848
+ const { sourceOffset, targetOffset } = reduceRouteMargin(sourceRectangle, targetRectangle);
1849
+ const sourceOuterRectangle = RectangleClient.expand(sourceRectangle, sourceOffset[3], sourceOffset[0], sourceOffset[1], sourceOffset[2]);
1850
+ const targetOuterRectangle = RectangleClient.expand(targetRectangle, targetOffset[3], targetOffset[0], targetOffset[1], targetOffset[2]);
1851
+ const nextSourcePoint = getNextPoint(sourcePoint, sourceOuterRectangle, handleRefPair.source.direction);
1852
+ const nextTargetPoint = getNextPoint(targetPoint, targetOuterRectangle, handleRefPair.target.direction);
1853
+ const isIntersect = RectangleClient.isPointInRectangle(targetRectangle, sourcePoint) ||
1854
+ RectangleClient.isPointInRectangle(targetOuterRectangle, nextSourcePoint) ||
1855
+ RectangleClient.isPointInRectangle(sourceOuterRectangle, nextTargetPoint) ||
1856
+ RectangleClient.isPointInRectangle(sourceRectangle, targetPoint);
1857
+ if (!isIntersect) {
1858
+ points = generateElbowLineRoute({
1859
+ sourcePoint,
1860
+ nextSourcePoint,
1861
+ sourceRectangle,
1862
+ sourceOuterRectangle,
1863
+ targetPoint,
1864
+ nextTargetPoint,
1865
+ targetRectangle,
1866
+ targetOuterRectangle
1867
+ });
1868
+ }
1869
+ }
1870
+ if (!points.length) {
1871
+ points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, offset);
1872
+ }
1457
1873
  points = removeDuplicatePoints(points);
1458
1874
  return points;
1459
1875
  }
@@ -1626,17 +2042,6 @@ const getBoardLines = (board) => {
1626
2042
  recursion: (element) => PlaitDrawElement.isDrawElement(element)
1627
2043
  });
1628
2044
  };
1629
- const removeDuplicatePoints = (points) => {
1630
- const newArray = [];
1631
- points.forEach(point => {
1632
- const index = newArray.findIndex(otherPoint => {
1633
- return point[0] === otherPoint[0] && point[1] === otherPoint[1];
1634
- });
1635
- if (index === -1)
1636
- newArray.push(point);
1637
- });
1638
- return newArray;
1639
- };
1640
2045
  const getExtendPoint = (source, target, extendDistance) => {
1641
2046
  const distance = distanceBetweenPointAndPoint(...source, ...target);
1642
2047
  const sin = (target[1] - source[1]) / distance;
@@ -1702,6 +2107,55 @@ const getSelectedImageElements = (board) => {
1702
2107
  return selectedElements;
1703
2108
  };
1704
2109
 
2110
+ const isRectangleHitDrawElement = (board, element, selection) => {
2111
+ if (PlaitDrawElement.isGeometry(element)) {
2112
+ const client = getRectangleByPoints(element.points);
2113
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2114
+ if (element.textHeight > client.height) {
2115
+ const textClient = getTextRectangle(element);
2116
+ return RectangleClient.isHit(rangeRectangle, client) || RectangleClient.isHit(rangeRectangle, textClient);
2117
+ }
2118
+ return RectangleClient.isHit(rangeRectangle, client);
2119
+ }
2120
+ if (PlaitDrawElement.isImage(element)) {
2121
+ const client = getRectangleByPoints(element.points);
2122
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2123
+ return RectangleClient.isHit(rangeRectangle, client);
2124
+ }
2125
+ if (PlaitDrawElement.isLine(element)) {
2126
+ const points = getLinePoints(board, element);
2127
+ const strokeWidth = getStrokeWidthByElement(element);
2128
+ const isHitText = isHitLineText(board, element, selection.focus);
2129
+ const isHit = isHitPolyLine(points, selection.focus, strokeWidth, 3) || isHitText;
2130
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2131
+ const isContainPolyLinePoint = points.some(point => {
2132
+ return RectangleClient.isHit(rangeRectangle, RectangleClient.toRectangleClient([point, point]));
2133
+ });
2134
+ const isIntersect = Point.isEquals(selection.anchor, selection.focus) ? isHit : isPolylineHitRectangle(points, rangeRectangle);
2135
+ return isContainPolyLinePoint || isIntersect;
2136
+ }
2137
+ return null;
2138
+ };
2139
+ const isHitDrawElement = (board, element, point) => {
2140
+ if (PlaitDrawElement.isGeometry(element)) {
2141
+ const fill = getFillByElement(element);
2142
+ if (fill !== DefaultGeometryStyle.fill) {
2143
+ return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
2144
+ }
2145
+ else {
2146
+ const strokeWidth = getStrokeWidthByElement(element);
2147
+ const engine = getEngine(getShape(element));
2148
+ const corners = engine.getCornerPoints(getRectangleByPoints(element.points));
2149
+ const isHit = isHitPolyLine(corners, point, strokeWidth, 3);
2150
+ return isHit;
2151
+ }
2152
+ }
2153
+ if (PlaitDrawElement.isImage(element) || PlaitDrawElement.isLine(element)) {
2154
+ return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
2155
+ }
2156
+ return null;
2157
+ };
2158
+
1705
2159
  var LineMarkerType;
1706
2160
  (function (LineMarkerType) {
1707
2161
  LineMarkerType["arrow"] = "arrow";
@@ -1762,206 +2216,51 @@ const PlaitLine = {
1762
2216
  getPoints(board, line) {
1763
2217
  let sourcePoint = line.source.boundId
1764
2218
  ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
1765
- : line.points[0];
1766
- let targetPoint = line.target.boundId
1767
- ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
1768
- : line.points[line.points.length - 1];
1769
- const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
1770
- return [sourcePoint, ...restPoints, targetPoint];
1771
- }
1772
- };
1773
-
1774
- var StrokeStyle;
1775
- (function (StrokeStyle) {
1776
- StrokeStyle["solid"] = "solid";
1777
- StrokeStyle["dashed"] = "dashed";
1778
- })(StrokeStyle || (StrokeStyle = {}));
1779
-
1780
- const PlaitDrawElement = {
1781
- isGeometry: (value) => {
1782
- return value.type === 'geometry';
1783
- },
1784
- isLine: (value) => {
1785
- return value.type === 'line';
1786
- },
1787
- isText: (value) => {
1788
- return value.type === 'geometry' && value.shape === BasicShapes.text;
1789
- },
1790
- isImage: (value) => {
1791
- return value.type === 'image';
1792
- },
1793
- isDrawElement: (value) => {
1794
- if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
1795
- return true;
1796
- }
1797
- else {
1798
- return false;
1799
- }
1800
- },
1801
- isShape: (value) => {
1802
- return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
1803
- },
1804
- isBaseShape: (value) => {
1805
- return Object.keys(BasicShapes).includes(value.type);
1806
- },
1807
- isFlowchart: (value) => {
1808
- return Object.keys(FlowchartSymbols).includes(value.type);
1809
- }
1810
- };
1811
-
1812
- class GeometryShapeGenerator extends Generator {
1813
- canDraw(element, data) {
1814
- return true;
1815
- }
1816
- baseDraw(element, data) {
1817
- const rectangle = getRectangleByPoints(element.points);
1818
- const shape = element.shape;
1819
- if (shape === BasicShapes.text) {
1820
- return;
1821
- }
1822
- const strokeWidth = getStrokeWidthByElement(element);
1823
- const strokeColor = getStrokeColorByElement(element);
1824
- const fill = getFillByElement(element);
1825
- const strokeLineDash = getLineDashByElement(element);
1826
- return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1827
- stroke: strokeColor,
1828
- strokeWidth,
1829
- fill,
1830
- strokeLineDash
1831
- });
1832
- }
1833
- }
1834
-
1835
- const insertGeometry = (board, points, shape) => {
1836
- let newElement = createGeometryElement(shape, points, '', {
1837
- strokeColor: DefaultBasicShapeProperty.strokeColor,
1838
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
1839
- });
1840
- Transforms.insertNode(board, newElement, [board.children.length]);
1841
- clearSelectedElement(board);
1842
- addSelectedElement(board, newElement);
1843
- };
1844
- const insertText = (board, points, text = '文本') => {
1845
- let newElement = createGeometryElement(BasicShapes.text, points, text);
1846
- Transforms.insertNode(board, newElement, [board.children.length]);
1847
- clearSelectedElement(board);
1848
- addSelectedElement(board, newElement);
1849
- };
1850
- const resizeGeometry = (board, points, textHeight, path) => {
1851
- const normalizePoints = normalizeShapePoints(points);
1852
- const element = PlaitNode.get(board, path);
1853
- const newHeight = textHeight / board.viewport.zoom;
1854
- const newProperties = { points: normalizePoints, textHeight: newHeight };
1855
- if (PlaitDrawElement.isText(element) && element.autoSize) {
1856
- newProperties.autoSize = false;
1857
- }
1858
- Transforms.setNode(board, newProperties, path);
1859
- };
1860
-
1861
- const normalizePoints = (board, element, width, textHeight) => {
1862
- let points = element.points;
1863
- let autoSize = element.autoSize;
1864
- const defaultSpace = ShapeDefaultSpace.rectangleAndText;
1865
- if (autoSize) {
1866
- const editor = PlaitGeometry.getTextEditor(element);
1867
- if (AlignEditor.isActive(editor, Alignment.right)) {
1868
- points = [
1869
- [points[1][0] - (width + defaultSpace * 2), points[0][1]],
1870
- [points[1][0], points[0][1] + textHeight]
1871
- ];
1872
- }
1873
- else if (AlignEditor.isActive(editor, Alignment.center)) {
1874
- const oldWidth = Math.abs(points[0][0] - points[1][0]);
1875
- const offset = (width - oldWidth) / 2;
1876
- points = [
1877
- [points[0][0] - offset - defaultSpace, points[0][1]],
1878
- [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
1879
- ];
1880
- }
1881
- else {
1882
- points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
1883
- }
1884
- }
1885
- return { points };
1886
- };
1887
- const setText = (board, element, text, width, textHeight) => {
1888
- const newElement = {
1889
- text,
1890
- textHeight,
1891
- ...normalizePoints(board, element, width, textHeight)
1892
- };
1893
- const path = board.children.findIndex(child => child === element);
1894
- Transforms.setNode(board, newElement, [path]);
1895
- };
1896
- const setTextSize = (board, element, textWidth, textHeight) => {
1897
- if (element.autoSize) {
1898
- const newElement = {
1899
- textHeight,
1900
- ...normalizePoints(board, element, textWidth, textHeight)
1901
- };
1902
- const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
1903
- const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
1904
- if (!isPointsEqual || !isTextHeightEqual) {
1905
- const path = board.children.findIndex(child => child === element);
1906
- Transforms.setNode(board, newElement, [path]);
1907
- }
1908
- }
1909
- };
1910
-
1911
- const insertImage = (board, imageItem, startPoint) => {
1912
- const { width, height, url } = imageItem;
1913
- const host = BOARD_TO_HOST.get(board);
1914
- const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1915
- const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1916
- const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1917
- const points = startPoint
1918
- ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1919
- : [
1920
- [point[0] - width / 2, point[1] - height / 2],
1921
- [point[0] + width / 2, point[1] + height / 2]
1922
- ];
1923
- const imageElement = {
1924
- id: idCreator(),
1925
- type: 'image',
1926
- points,
1927
- url
1928
- };
1929
- Transforms.insertNode(board, imageElement, [board.children.length]);
1930
- Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
2219
+ : line.points[0];
2220
+ let targetPoint = line.target.boundId
2221
+ ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2222
+ : line.points[line.points.length - 1];
2223
+ const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2224
+ return [sourcePoint, ...restPoints, targetPoint];
2225
+ }
1931
2226
  };
1932
2227
 
1933
- const resizeLine = (board, options, path) => {
1934
- Transforms.setNode(board, options, path);
1935
- };
1936
- const setLineTexts = (board, element, texts) => {
1937
- const path = PlaitBoard.findPath(board, element);
1938
- Transforms.setNode(board, { texts }, path);
1939
- };
1940
- const removeLineText = (board, element, index) => {
1941
- const path = PlaitBoard.findPath(board, element);
1942
- const texts = element.texts?.length ? [...element.texts] : [];
1943
- const newTexts = [...texts];
1944
- newTexts.splice(index, 1);
1945
- Transforms.setNode(board, { texts: newTexts }, path);
1946
- };
1947
- const setLineMark = (board, element, handleKey, marker) => {
1948
- const path = PlaitBoard.findPath(board, element);
1949
- let handle = handleKey === LineHandleKey.source ? element.source : element.target;
1950
- handle = { ...handle, marker };
1951
- Transforms.setNode(board, { [handleKey]: handle }, path);
1952
- };
2228
+ var StrokeStyle;
2229
+ (function (StrokeStyle) {
2230
+ StrokeStyle["solid"] = "solid";
2231
+ StrokeStyle["dashed"] = "dashed";
2232
+ })(StrokeStyle || (StrokeStyle = {}));
1953
2233
 
1954
- const DrawTransforms = {
1955
- setText,
1956
- insertGeometry,
1957
- resizeGeometry,
1958
- insertText,
1959
- setTextSize,
1960
- resizeLine,
1961
- setLineTexts,
1962
- removeLineText,
1963
- setLineMark,
1964
- insertImage
2234
+ const PlaitDrawElement = {
2235
+ isGeometry: (value) => {
2236
+ return value.type === 'geometry';
2237
+ },
2238
+ isLine: (value) => {
2239
+ return value.type === 'line';
2240
+ },
2241
+ isText: (value) => {
2242
+ return value.type === 'geometry' && value.shape === BasicShapes.text;
2243
+ },
2244
+ isImage: (value) => {
2245
+ return value.type === 'image';
2246
+ },
2247
+ isDrawElement: (value) => {
2248
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
2249
+ return true;
2250
+ }
2251
+ else {
2252
+ return false;
2253
+ }
2254
+ },
2255
+ isShape: (value) => {
2256
+ return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
2257
+ },
2258
+ isBaseShape: (value) => {
2259
+ return Object.keys(BasicShapes).includes(value.type);
2260
+ },
2261
+ isFlowchart: (value) => {
2262
+ return Object.keys(FlowchartSymbols).includes(value.type);
2263
+ }
1965
2264
  };
1966
2265
 
1967
2266
  class GeometryComponent extends CommonPluginElement {
@@ -2362,172 +2661,6 @@ const withDrawHotkey = (board) => {
2362
2661
  return board;
2363
2662
  };
2364
2663
 
2365
- const withGeometryCreateByDrag = (board) => {
2366
- const { pointerMove, pointerUp } = board;
2367
- let geometryShapeG = null;
2368
- board.pointerMove = (event) => {
2369
- geometryShapeG?.remove();
2370
- geometryShapeG = createG();
2371
- const geometryGenerator = new GeometryShapeGenerator(board);
2372
- const geometryPointers = getGeometryPointers();
2373
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2374
- const dragMode = isGeometryPointer && isDndMode(board);
2375
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2376
- const pointer = PlaitBoard.getPointer(board);
2377
- if (dragMode) {
2378
- const points = getDefaultGeometryPoints(pointer, movingPoint);
2379
- if (pointer === BasicShapes.text) {
2380
- const textG = getTemporaryTextG(movingPoint);
2381
- geometryShapeG.appendChild(textG);
2382
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2383
- }
2384
- else {
2385
- const temporaryElement = createGeometryElement(pointer, points, '', {
2386
- strokeColor: DefaultBasicShapeProperty.strokeColor,
2387
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
2388
- });
2389
- geometryGenerator.draw(temporaryElement, geometryShapeG);
2390
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2391
- }
2392
- }
2393
- pointerMove(event);
2394
- };
2395
- board.pointerUp = (event) => {
2396
- const pointer = PlaitBoard.getPointer(board);
2397
- const geometryPointers = getGeometryPointers();
2398
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2399
- const dragMode = isGeometryPointer && isDndMode(board);
2400
- if (dragMode) {
2401
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2402
- const points = getDefaultGeometryPoints(pointer, targetPoint);
2403
- if (pointer === BasicShapes.text) {
2404
- DrawTransforms.insertText(board, points);
2405
- }
2406
- else {
2407
- DrawTransforms.insertGeometry(board, points, pointer);
2408
- }
2409
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2410
- }
2411
- geometryShapeG?.remove();
2412
- geometryShapeG = null;
2413
- preventTouchMove(board, event, false);
2414
- pointerUp(event);
2415
- };
2416
- return board;
2417
- };
2418
- const withGeometryCreateByDrawing = (board) => {
2419
- const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
2420
- let start = null;
2421
- let geometryShapeG = null;
2422
- let temporaryElement = null;
2423
- let isShift = false;
2424
- board.keydown = (event) => {
2425
- isShift = isKeyHotkey('shift', event);
2426
- keydown(event);
2427
- };
2428
- board.keyup = (event) => {
2429
- isShift = false;
2430
- keyup(event);
2431
- };
2432
- board.pointerDown = (event) => {
2433
- const geometryPointers = getGeometryPointers();
2434
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2435
- if (isGeometryPointer && isDrawingMode(board)) {
2436
- const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2437
- start = point;
2438
- const pointer = PlaitBoard.getPointer(board);
2439
- preventTouchMove(board, event, true);
2440
- if (pointer === BasicShapes.text) {
2441
- const points = getDefaultGeometryPoints(pointer, point);
2442
- const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text);
2443
- Transforms.insertNode(board, textElement, [board.children.length]);
2444
- clearSelectedElement(board);
2445
- addSelectedElement(board, textElement);
2446
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2447
- start = null;
2448
- }
2449
- }
2450
- pointerDown(event);
2451
- };
2452
- board.pointerMove = (event) => {
2453
- geometryShapeG?.remove();
2454
- geometryShapeG = createG();
2455
- const geometryGenerator = new GeometryShapeGenerator(board);
2456
- const drawMode = !!start;
2457
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2458
- const pointer = PlaitBoard.getPointer(board);
2459
- if (drawMode && pointer !== BasicShapes.text) {
2460
- const points = normalizeShapePoints([start, movingPoint], isShift);
2461
- temporaryElement = createGeometryElement(pointer, points, '', {
2462
- strokeColor: DefaultBasicShapeProperty.strokeColor,
2463
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
2464
- });
2465
- geometryGenerator.draw(temporaryElement, geometryShapeG);
2466
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2467
- }
2468
- pointerMove(event);
2469
- };
2470
- board.pointerUp = (event) => {
2471
- const isDrawMode = !!start;
2472
- if (isDrawMode) {
2473
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2474
- const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
2475
- if (Math.hypot(width, height) === 0) {
2476
- const pointer = PlaitBoard.getPointer(board);
2477
- const points = getDefaultGeometryPoints(pointer, targetPoint);
2478
- if (pointer !== BasicShapes.text) {
2479
- temporaryElement = createGeometryElement(pointer, points, '', {
2480
- strokeColor: DefaultBasicShapeProperty.strokeColor,
2481
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
2482
- });
2483
- }
2484
- }
2485
- }
2486
- if (temporaryElement) {
2487
- Transforms.insertNode(board, temporaryElement, [board.children.length]);
2488
- clearSelectedElement(board);
2489
- addSelectedElement(board, temporaryElement);
2490
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2491
- }
2492
- geometryShapeG?.remove();
2493
- geometryShapeG = null;
2494
- start = null;
2495
- temporaryElement = null;
2496
- preventTouchMove(board, event, false);
2497
- pointerUp(event);
2498
- };
2499
- return board;
2500
- };
2501
- const getDefaultGeometryPoints = (pointer, targetPoint) => {
2502
- const defaultProperty = getGeometryDefaultProperty(pointer);
2503
- return getPointsByCenterPoint(targetPoint, defaultProperty.width, defaultProperty.height);
2504
- };
2505
- const getGeometryDefaultProperty = (pointer) => {
2506
- const isText = pointer === BasicShapes.text;
2507
- const isFlowChart = getFlowchartPointers().includes(pointer);
2508
- if (isText) {
2509
- return DefaultTextProperty;
2510
- }
2511
- else if (isFlowChart) {
2512
- return getDefaultFlowchartProperty(pointer);
2513
- }
2514
- else {
2515
- return DefaultBasicShapeProperty;
2516
- }
2517
- };
2518
- const getTemporaryTextG = (movingPoint) => {
2519
- const textG = createG();
2520
- const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
2521
- const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
2522
- const richtext = document.createElement('div');
2523
- richtext.textContent = DefaultTextProperty.text;
2524
- richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
2525
- richtext.style.cursor = 'default';
2526
- foreignObject.appendChild(richtext);
2527
- textG.appendChild(foreignObject);
2528
- return textG;
2529
- };
2530
-
2531
2664
  const buildClipboardData = (board, elements, startPoint) => {
2532
2665
  return elements.map(element => {
2533
2666
  if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
@@ -2618,13 +2751,13 @@ const withDrawFragment = (baseBoard) => {
2618
2751
  };
2619
2752
  board.insertFragment = (data, targetPoint) => {
2620
2753
  const elements = getDataFromClipboard(data);
2754
+ const selectedElements = getSelectedElements(board);
2621
2755
  const drawElements = elements.filter(value => PlaitDrawElement.isDrawElement(value));
2622
2756
  if (elements.length > 0 && drawElements.length > 0) {
2623
2757
  insertClipboardData(board, drawElements, targetPoint);
2624
2758
  }
2625
2759
  else if (elements.length === 0) {
2626
2760
  const text = getTextFromClipboard(data);
2627
- const selectedElements = getSelectedElements(board);
2628
2761
  // (* ̄︶ ̄)
2629
2762
  const insertAsChildren = selectedElements.length === 1 && selectedElements[0].children;
2630
2763
  const insertAsFreeText = !insertAsChildren;
@@ -2636,7 +2769,8 @@ const withDrawFragment = (baseBoard) => {
2636
2769
  }
2637
2770
  if (data?.files.length) {
2638
2771
  const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
2639
- if (acceptImageArray.includes(data?.files[0].type)) {
2772
+ const canInsertionImage = !getElementOfFocusedImage(board) && !(selectedElements.length === 1 && board.isImageBindingAllowed(selectedElements[0]));
2773
+ if (acceptImageArray.includes(data?.files[0].type) && canInsertionImage) {
2640
2774
  const imageFile = data.files[0];
2641
2775
  buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
2642
2776
  DrawTransforms.insertImage(board, imageItem, targetPoint);
@@ -2653,11 +2787,6 @@ const getBoundedLineElements = (board, plaitShapes) => {
2653
2787
  return lines.filter(line => plaitShapes.find(shape => PlaitLine.isBoundElementOfSource(line, shape) || PlaitLine.isBoundElementOfTarget(line, shape)));
2654
2788
  };
2655
2789
 
2656
- const DefaultLineStyle = {
2657
- strokeWidth: 2,
2658
- strokeColor: '#000'
2659
- };
2660
-
2661
2790
  const getHitGeometryResizeHandleRef = (board, element, point) => {
2662
2791
  const rectangle = getRectangleByPoints(element.points);
2663
2792
  const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
@@ -2714,7 +2843,7 @@ const withLineCreateByDraw = (board) => {
2714
2843
  targetRef.boundId = hitElement ? hitElement.id : undefined;
2715
2844
  const lineGenerator = new LineShapeGenerator(board);
2716
2845
  const lineShape = PlaitBoard.getPointer(board);
2717
- temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
2846
+ temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, [], {
2718
2847
  strokeColor: DefaultLineStyle.strokeColor,
2719
2848
  strokeWidth: DefaultLineStyle.strokeWidth
2720
2849
  });
@@ -2953,9 +3082,9 @@ const withLineText = (board) => {
2953
3082
  const { dblclick } = board;
2954
3083
  board.dblclick = (event) => {
2955
3084
  const clickPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2956
- const hitTarget = getHitElements(board, { ranges: [{ anchor: clickPoint, focus: clickPoint }] }, (element) => {
3085
+ const hitTarget = getHitElementByPoint(board, clickPoint, (element) => {
2957
3086
  return PlaitDrawElement.isLine(element);
2958
- })[0];
3087
+ });
2959
3088
  if (hitTarget) {
2960
3089
  const points = getLinePoints(board, hitTarget);
2961
3090
  const point = getNearestPointBetweenPointAndSegments(clickPoint, points);
@@ -3064,7 +3193,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
3064
3193
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3065
3194
 
3066
3195
  const withDraw = (board) => {
3067
- const { drawElement, getRectangle, isHitSelection, isMovable, isAlign } = board;
3196
+ const { drawElement, getRectangle, isRectangleHit, isHit, isMovable, isAlign } = board;
3068
3197
  board.drawElement = (context) => {
3069
3198
  if (PlaitDrawElement.isGeometry(context.element)) {
3070
3199
  return GeometryComponent;
@@ -3090,34 +3219,19 @@ const withDraw = (board) => {
3090
3219
  }
3091
3220
  return getRectangle(element);
3092
3221
  };
3093
- board.isHitSelection = (element, range) => {
3094
- if (PlaitDrawElement.isGeometry(element)) {
3095
- const client = getRectangleByPoints(element.points);
3096
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
3097
- if (element.textHeight > client.height) {
3098
- const textClient = getTextRectangle(element);
3099
- return RectangleClient.isHit(rangeRectangle, client) || RectangleClient.isHit(rangeRectangle, textClient);
3100
- }
3101
- return RectangleClient.isHit(rangeRectangle, client);
3102
- }
3103
- if (PlaitDrawElement.isImage(element)) {
3104
- const client = getRectangleByPoints(element.points);
3105
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
3106
- return RectangleClient.isHit(rangeRectangle, client);
3222
+ board.isRectangleHit = (element, selection) => {
3223
+ const result = isRectangleHitDrawElement(board, element, selection);
3224
+ if (result !== null) {
3225
+ return result;
3107
3226
  }
3108
- if (PlaitDrawElement.isLine(element)) {
3109
- const points = getLinePoints(board, element);
3110
- const strokeWidth = getStrokeWidthByElement(element);
3111
- const isHitText = isHitLineText(board, element, range.focus);
3112
- const isHit = isHitPolyLine(points, range.focus, strokeWidth, 3) || isHitText;
3113
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
3114
- const isContainPolyLinePoint = points.some(point => {
3115
- return RectangleClient.isHit(rangeRectangle, RectangleClient.toRectangleClient([point, point]));
3116
- });
3117
- const isIntersect = range.anchor === range.focus ? isHit : isPolylineHitRectangle(points, rangeRectangle);
3118
- return isContainPolyLinePoint || isIntersect;
3227
+ return isRectangleHit(element, selection);
3228
+ };
3229
+ board.isHit = (element, point) => {
3230
+ const result = isHitDrawElement(board, element, point);
3231
+ if (result !== null) {
3232
+ return result;
3119
3233
  }
3120
- return isHitSelection(element, range);
3234
+ return isHit(element, point);
3121
3235
  };
3122
3236
  board.isMovable = (element) => {
3123
3237
  if (PlaitDrawElement.isGeometry(element)) {
@@ -3152,5 +3266,5 @@ const withDraw = (board) => {
3152
3266
  * Generated bundle index. Do not edit.
3153
3267
  */
3154
3268
 
3155
- export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getEdgeOnPolygonByPoint, getElbowPoints, getExtendPoint, getFillByElement, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLinePointers, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, isHitLineText, isHitPolyLine, removeDuplicatePoints, transformOpsToPoints, transformPointToConnection, withDraw };
3269
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, createDefaultFlowchart, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getEdgeOnPolygonByPoint, getElbowPoints, getExtendPoint, getFillByElement, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLinePointers, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, isHitDrawElement, isHitLineText, isHitPolyLine, isRectangleHitDrawElement, transformOpsToPoints, transformPointToConnection, withDraw };
3156
3270
  //# sourceMappingURL=plait-draw.mjs.map