@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.
- package/esm2022/constants/line.mjs +1 -1
- package/esm2022/generators/line-active.generator.mjs +1 -1
- package/esm2022/plugins/with-draw-fragment.mjs +5 -4
- package/esm2022/plugins/with-draw.mjs +15 -31
- package/esm2022/plugins/with-geometry-create.mjs +2 -2
- package/esm2022/plugins/with-line-create.mjs +2 -2
- package/esm2022/plugins/with-line-text.mjs +4 -4
- package/esm2022/utils/geometry.mjs +64 -3
- package/esm2022/utils/hit.mjs +58 -0
- package/esm2022/utils/index.mjs +2 -1
- package/esm2022/utils/line.mjs +39 -17
- package/fesm2022/plait-draw.mjs +705 -591
- package/fesm2022/plait-draw.mjs.map +1 -1
- package/package.json +1 -1
- package/plugins/with-geometry-create.d.ts +2 -1
- package/utils/geometry.d.ts +1 -0
- package/utils/hit.d.ts +3 -0
- package/utils/index.d.ts +1 -0
- package/utils/line.d.ts +2 -3
package/fesm2022/plait-draw.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { PlaitElement, ACTIVE_STROKE_WIDTH, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle,
|
|
2
|
-
import { getRectangleByPoints, getFactorByPoints, getDirectionByVector, getOppositeDirection, getDirectionFactor, getPoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90,
|
|
3
|
-
import { Alignment,
|
|
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
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
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
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
shape
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
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
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
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
|
-
|
|
1264
|
-
};
|
|
1265
|
-
const getDefaultFlowchartProperty = (symbol) => {
|
|
1266
|
-
return DefaultFlowchartPropertyMap[symbol];
|
|
1217
|
+
Transforms.setNode(board, newProperties, path);
|
|
1267
1218
|
};
|
|
1268
1219
|
|
|
1269
|
-
const
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
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
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
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
|
-
|
|
1319
|
-
|
|
1320
|
-
break;
|
|
1240
|
+
else {
|
|
1241
|
+
points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
|
|
1321
1242
|
}
|
|
1322
1243
|
}
|
|
1323
|
-
return
|
|
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
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
const
|
|
1345
|
-
|
|
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
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
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
|
-
|
|
1355
|
-
|
|
1356
|
-
const
|
|
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 ?
|
|
1456
|
-
|
|
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
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
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
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
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
|
-
|
|
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 =
|
|
3085
|
+
const hitTarget = getHitElementByPoint(board, clickPoint, (element) => {
|
|
2957
3086
|
return PlaitDrawElement.isLine(element);
|
|
2958
|
-
})
|
|
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,
|
|
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.
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
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
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
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
|
|
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,
|
|
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
|