diff --git a/src/configs/lines.ts b/src/configs/lines.ts index 0237dfe0..962b76ae 100644 --- a/src/configs/lines.ts +++ b/src/configs/lines.ts @@ -7,6 +7,7 @@ export interface LinePoolItem { points: [LinePoint, LinePoint]; isBroken?: boolean; isCurve?: boolean; + isCubic?: boolean; } interface PresetLine { @@ -30,6 +31,7 @@ export const LINE_LIST: PresetLine[] = [ children: [ { path: 'M 0 0 L 0 20 L 20 20', style: 'solid', points: ['', 'arrow'], isBroken: true }, { path: 'M 0 0 Q 0 20 20 20', style: 'solid', points: ['', 'arrow'], isCurve: true }, + { path: 'M 0 0 C 20 0 0 20 20 20', style: 'solid', points: ['', 'arrow'], isCubic: true }, ], }, ] \ No newline at end of file diff --git a/src/hooks/useCreateElement.ts b/src/hooks/useCreateElement.ts index 959709fb..1088eaaf 100644 --- a/src/hooks/useCreateElement.ts +++ b/src/hooks/useCreateElement.ts @@ -220,6 +220,7 @@ export default () => { } if (data.isBroken) newElement.broken = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2] if (data.isCurve) newElement.curve = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2] + if (data.isCubic) newElement.cubic = [[(start[0] + end[0]) / 2, (start[1] + end[1]) / 2], [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2]] createElement(newElement) } diff --git a/src/types/edit.ts b/src/types/edit.ts index b2b3338f..9dc6b48e 100644 --- a/src/types/edit.ts +++ b/src/types/edit.ts @@ -44,12 +44,14 @@ export const enum OperateResizeHandlers { RIGHT_BOTTOM = 'right-bottom', } -export type OperateLineHandler = 'start' | 'end' | 'mid' +export type OperateLineHandler = 'start' | 'end' | 'ctrl' | 'ctrl1' | 'ctrl2' export const enum OperateLineHandlers { START = 'start', END = 'end', - MID = 'mid', + C = 'ctrl', + C1 = 'ctrl1', + C2 = 'ctrl2', } export interface AlignmentLineAxis { diff --git a/src/types/slides.ts b/src/types/slides.ts index 9ea5fe45..776d066d 100644 --- a/src/types/slides.ts +++ b/src/types/slides.ts @@ -314,9 +314,11 @@ export type LinePoint = '' | 'arrow' | 'dot' * * shadow?: 阴影 * - * broken?: 折线中点位置([x, y]) + * broken?: 折线控制点位置([x, y]) * - * curve?: 曲线中点位置([x, y]) + * curve?: 二次曲线控制点位置([x, y]) + * + * curve?: 三次曲线控制点位置([[x1, y1], [x2, y2]]) */ export interface PPTLineElement extends Omit { type: 'line'; @@ -328,6 +330,7 @@ export interface PPTLineElement extends Omit { const mid = element.broken.join(',') return `M${start} L${mid} L${end}` } - if (element.curve) { + else if (element.curve) { const mid = element.curve.join(',') return `M${start} Q${mid} ${end}` } + else if (element.cubic) { + const [c1, c2] = element.cubic + const p1 = c1.join(',') + const p2 = c2.join(',') + return `M${start} C${p1} ${p2} ${end}` + } return `M${start} L${end}` } \ No newline at end of file diff --git a/src/views/Editor/Canvas/Operate/LineElementOperate.vue b/src/views/Editor/Canvas/Operate/LineElementOperate.vue index 8e39faa8..ccdd3647 100644 --- a/src/views/Editor/Canvas/Operate/LineElementOperate.vue +++ b/src/views/Editor/Canvas/Operate/LineElementOperate.vue @@ -63,16 +63,34 @@ export default defineComponent({ ] if (props.elementInfo.curve || props.elementInfo.broken) { - const midHandler = (props.elementInfo.curve || props.elementInfo.broken) as [number, number] + const ctrlHandler = (props.elementInfo.curve || props.elementInfo.broken) as [number, number] handlers.push({ - handler: OperateLineHandlers.MID, + handler: OperateLineHandlers.C, style: { - left: midHandler[0] * canvasScale.value + 'px', - top: midHandler[1] * canvasScale.value + 'px', + left: ctrlHandler[0] * canvasScale.value + 'px', + top: ctrlHandler[1] * canvasScale.value + 'px', } }) } + else if (props.elementInfo.cubic) { + const [ctrlHandler1, ctrlHandler2] = props.elementInfo.cubic + handlers.push({ + handler: OperateLineHandlers.C1, + style: { + left: ctrlHandler1[0] * canvasScale.value + 'px', + top: ctrlHandler1[1] * canvasScale.value + 'px', + } + }) + handlers.push({ + handler: OperateLineHandlers.C2, + style: { + left: ctrlHandler2[0] * canvasScale.value + 'px', + top: ctrlHandler2[1] * canvasScale.value + 'px', + } + }) + } + return handlers }) diff --git a/src/views/Editor/Canvas/hooks/useDragLineElement.ts b/src/views/Editor/Canvas/hooks/useDragLineElement.ts index 73218e1e..52b268c3 100644 --- a/src/views/Editor/Canvas/hooks/useDragLineElement.ts +++ b/src/views/Editor/Canvas/hooks/useDragLineElement.ts @@ -83,6 +83,12 @@ export default (elementList: Ref) => { let midX = element.left + mid[0] let midY = element.top + mid[1] + const [c1, c2] = element.cubic || [[0, 0], [0, 0]] + let c1X = element.left + c1[0] + let c1Y = element.top + c1[1] + let c2X = element.left + c2[0] + let c2Y = element.top + c2[1] + // 拖拽起点或终点的位置 // 水平和垂直方向上有吸附 if (command === OperateLineHandlers.START) { @@ -117,7 +123,7 @@ export default (elementList: Ref) => { } } } - else { + else if (command === OperateLineHandlers.C) { midX = midX + moveX midY = midY + moveY @@ -130,6 +136,24 @@ export default (elementList: Ref) => { midY = (startY + endY) / 2 } } + else if (command === OperateLineHandlers.C1) { + c1X = c1X + moveX + c1Y = c1Y + moveY + + if (Math.abs(c1X - startX) < sorptionRange) c1X = startX + if (Math.abs(c1Y - startY) < sorptionRange) c1Y = startY + if (Math.abs(c1X - endX) < sorptionRange) c1X = endX + if (Math.abs(c1Y - endY) < sorptionRange) c1Y = endY + } + else if (command === OperateLineHandlers.C2) { + c2X = c2X + moveX + c2Y = c2Y + moveY + + if (Math.abs(c2X - startX) < sorptionRange) c2X = startX + if (Math.abs(c2Y - startY) < sorptionRange) c2Y = startY + if (Math.abs(c2X - endX) < sorptionRange) c2X = endX + if (Math.abs(c2Y - endY) < sorptionRange) c2Y = endY + } // 计算更新起点和终点基于自身元素位置的坐标 const minX = Math.min(startX, endX) @@ -157,14 +181,18 @@ export default (elementList: Ref) => { start: start, end: end, } - if (command !== OperateLineHandlers.MID) { + if (command === OperateLineHandlers.START || command === OperateLineHandlers.END) { if (element.broken) newEl.broken = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2] if (element.curve) newEl.curve = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2] + if (element.cubic) newEl.cubic = [[(start[0] + end[0]) / 2, (start[1] + end[1]) / 2], [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2]] } - else { + else if (command === OperateLineHandlers.C) { if (element.broken) newEl.broken = [midX - minX, midY - minY] if (element.curve) newEl.curve = [midX - minX, midY - minY] } + else { + if (element.cubic) newEl.cubic = [[c1X - minX, c1Y - minY], [c2X - minX, c2Y - minY]] + } return newEl } return el diff --git a/src/views/Editor/CanvasTool/LinePool.vue b/src/views/Editor/CanvasTool/LinePool.vue index 72875b51..fc5eb2f5 100644 --- a/src/views/Editor/CanvasTool/LinePool.vue +++ b/src/views/Editor/CanvasTool/LinePool.vue @@ -1,9 +1,9 @@