From bc2cc826b49ed415bd2fe28d15155726cbcf7dbd Mon Sep 17 00:00:00 2001
From: wuchenguang1998 <63847336+wuchenguang1998@users.noreply.github.com>
Date: Sat, 11 May 2024 17:55:24 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=BB=86=E5=B0=BE?=
=?UTF-8?q?=E7=AE=AD=E5=A4=B4=E7=BB=98=E5=88=B6=E5=85=83=E7=B4=A0(thinTail?=
=?UTF-8?q?Arrow)=20(#382)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: 新增细尾箭头绘制元素(thinTailArrow)
* fix: 细尾箭头样式调整
---
packages/core/objects/ThinTailArrow.js | 57 ++++++++++++++++++++++++++
packages/core/plugin/DrawLinePlugin.ts | 43 ++++++++++++++-----
src/components/attribute.vue | 1 +
src/components/tools.vue | 37 +++++++++++++----
4 files changed, 120 insertions(+), 18 deletions(-)
create mode 100644 packages/core/objects/ThinTailArrow.js
diff --git a/packages/core/objects/ThinTailArrow.js b/packages/core/objects/ThinTailArrow.js
new file mode 100644
index 00000000..fb41da17
--- /dev/null
+++ b/packages/core/objects/ThinTailArrow.js
@@ -0,0 +1,57 @@
+/*
+ * @Author: wuchenguang1998
+ * @Date: 2024-05-10 10:46:10
+ * @LastEditors: wuchenguang1998
+ * @LastEditTime: 2024-05-10 22:08:51
+ * @Description: 细尾箭头,支持控制条拖拽不变形
+ */
+import { fabric } from 'fabric';
+
+fabric.ThinTailArrow = fabric.util.createClass(fabric.Line, {
+ type: 'thinTailArrow',
+ superType: 'drawing',
+ initialize(points, options) {
+ if (!points) {
+ const { x1, x2, y1, y2 } = options;
+ points = [x1, y1, x2, y2];
+ }
+ options = options || {};
+ this.callSuper('initialize', points, options);
+ },
+ _render(ctx) {
+ ctx.save();
+ // 乘或除对应的scaleX(Y),抵消元素放缩造成的影响,使箭头不会变形
+ ctx.scale(1 / this.scaleX, 1 / this.scaleY);
+ const xDiff = (this.x2 - this.x1) * this.scaleX;
+ const yDiff = (this.y2 - this.y1) * this.scaleY;
+ ctx.translate(-xDiff / 2, -yDiff / 2);
+ // 箭头方位角
+ const angle = Math.atan2(yDiff, xDiff);
+ ctx.rotate(angle);
+ // 箭头总长(最小长度是20)
+ let length = Math.hypot(xDiff, yDiff);
+ length = length < 20 ? 20 : length;
+ // 绘制箭头
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(length - 18, -5);
+ ctx.lineTo(length - 20, -12);
+ ctx.lineTo(length, 0);
+ ctx.lineTo(length - 20, 12);
+ ctx.lineTo(length - 18, 5);
+ ctx.lineTo(0, 0);
+ ctx.lineWidth = this.strokeWidth;
+ ctx.strokeStyle = this.stroke;
+ ctx.fillStyle = this.fill;
+ ctx.stroke();
+ ctx.fill();
+ ctx.restore();
+ },
+});
+
+fabric.ThinTailArrow.fromObject = (options, callback) => {
+ const { x1, x2, y1, y2 } = options;
+ return callback(new fabric.ThinTailArrow([x1, y1, x2, y2], options));
+};
+
+export default fabric.ThinTailArrow;
diff --git a/packages/core/plugin/DrawLinePlugin.ts b/packages/core/plugin/DrawLinePlugin.ts
index 9a41ea1c..ba65c0c5 100644
--- a/packages/core/plugin/DrawLinePlugin.ts
+++ b/packages/core/plugin/DrawLinePlugin.ts
@@ -9,6 +9,7 @@
import { v4 as uuid } from 'uuid';
import { fabric } from 'fabric';
import Arrow from '../objects/Arrow';
+import ThinTailArrow from '../objects/ThinTailArrow';
import Editor from '../Editor';
type IEditor = Editor;
@@ -16,9 +17,9 @@ class DrawLinePlugin {
public canvas: fabric.Canvas;
public editor: IEditor;
static pluginName = 'DrawLinePlugin';
- static apis = ['setArrow', 'setMode'];
+ static apis = ['setLineType', 'setMode'];
isDrawingLineMode: boolean;
- isArrow: boolean;
+ lineType: string;
lineToDraw: any;
pointer: any;
pointerPoints: any;
@@ -29,7 +30,7 @@ class DrawLinePlugin {
this.isDrawingLine = false;
this.isDrawingLineMode = false;
- this.isArrow = false;
+ this.lineType = '';
this.lineToDraw = null;
this.pointer = null;
this.pointerPoints = null;
@@ -49,13 +50,34 @@ class DrawLinePlugin {
this.isDrawingLine = true;
this.pointer = canvas.getPointer(o.e);
this.pointerPoints = [this.pointer.x, this.pointer.y, this.pointer.x, this.pointer.y];
-
- const NodeHandler = this.isArrow ? Arrow : fabric.Line;
- this.lineToDraw = new NodeHandler(this.pointerPoints, {
+ let NodeHandler;
+ let opts: any = {
strokeWidth: 2,
stroke: '#000000',
id: uuid(),
- });
+ };
+ switch (this.lineType) {
+ case 'line':
+ NodeHandler = fabric.Line;
+ break;
+ case 'arrow':
+ NodeHandler = Arrow;
+ break;
+ case 'thinTailArrow':
+ NodeHandler = ThinTailArrow;
+ opts = {
+ strokeWidth: 2,
+ stroke: '#ff0000',
+ fill: '#ff0000',
+ id: uuid(),
+ };
+ break;
+ default:
+ break;
+ }
+ if (!NodeHandler) throw new Error('Draw failed: invalid lineType.');
+
+ this.lineToDraw = new NodeHandler(this.pointerPoints, opts);
this.lineToDraw.selectable = false;
this.lineToDraw.evented = false;
@@ -64,7 +86,8 @@ class DrawLinePlugin {
});
canvas.on('mouse:move', (o) => {
- if (!this.isDrawingLine) return;
+ if (!this.isDrawingLine || !['line', 'arrow', 'thinTailArrow'].includes(this.lineType))
+ return;
canvas.discardActiveObject();
const activeObject = canvas.getActiveObject();
if (activeObject) return;
@@ -105,8 +128,8 @@ class DrawLinePlugin {
});
}
- setArrow(params: any) {
- this.isArrow = params;
+ setLineType(params: any) {
+ this.lineType = params;
}
setMode(params: any) {
diff --git a/src/components/attribute.vue b/src/components/attribute.vue
index f0c7fee2..76666de2 100644
--- a/src/components/attribute.vue
+++ b/src/components/attribute.vue
@@ -320,6 +320,7 @@ const baseType = [
'group',
'line',
'arrow',
+ 'thinTailArrow',
];
// 文字元素
const textType = ['i-text', 'textbox', 'text'];
diff --git a/src/components/tools.vue b/src/components/tools.vue
index 8ba87ed5..112008da 100644
--- a/src/components/tools.vue
+++ b/src/components/tools.vue
@@ -109,8 +109,8 @@