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 @@ {{ $t('draw_elements') }}
+ + + + +
@@ -178,7 +199,7 @@ const { t } = useI18n(); const { fabric, canvasEditor } = useSelect(); const state = reactive({ isDrawingLineMode: false, - isArrow: false, + lineType: false, }); // let drawHandler = null; @@ -297,11 +318,11 @@ const addRect = (option) => { } canvasEditor.canvas.setActiveObject(rect); }; -const drawingLineModeSwitch = (isArrow) => { - state.isArrow = isArrow; +const drawingLineModeSwitch = (type) => { + state.lineType = type; state.isDrawingLineMode = !state.isDrawingLineMode; canvasEditor.setMode(state.isDrawingLineMode); - canvasEditor.setArrow(isArrow); + canvasEditor.setLineType(type); // this.canvasEditor.setMode(this.isDrawingLineMode); // this.canvasEditor.setArrow(isArrow);