From 60622b4811088f61269e0ad4f337ded4cfeacf62 Mon Sep 17 00:00:00 2001 From: pipipi-pikachu Date: Sat, 27 Feb 2021 16:27:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E3=80=81=E6=8A=98=E7=BA=BF=E7=BA=BF=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/lines.ts | 24 +++- src/hooks/useCreateElement.ts | 10 +- src/types/edit.ts | 5 +- src/types/slides.ts | 2 + .../Canvas/Operate/LineElementOperate.vue | 15 ++- .../Editor/Canvas/hooks/useDragLineElement.ts | 32 ++++- src/views/Editor/CanvasTool/LinePool.vue | 109 ++++++++++-------- .../element/LineElement/BaseLineElement.vue | 8 ++ .../components/element/LineElement/index.vue | 8 ++ 9 files changed, 153 insertions(+), 60 deletions(-) diff --git a/src/configs/lines.ts b/src/configs/lines.ts index fb6eff0e..425bdce9 100644 --- a/src/configs/lines.ts +++ b/src/configs/lines.ts @@ -2,12 +2,26 @@ export interface LinePoolItem { path: string; style: string; points: [string, string]; + isBroken?: boolean; + isCurve?: boolean; } export const LINE_LIST = [ - { path: 'M0,0 L20,20', style: 'solid', points: ['', ''] }, - { path: 'M0,0 L20,20', style: 'dashed', points: ['', ''] }, - { path: 'M0,0 L20,20', style: 'solid', points: ['', 'arrow'] }, - { path: 'M0,0 L20,20', style: 'dashed', points: ['', 'arrow'] }, - { path: 'M0,0 L20,20', style: 'solid', points: ['', 'dot'] }, + { + type: '直线', + children: [ + { path: 'M 0 0 L 20 20', style: 'solid', points: ['', ''] }, + { path: 'M 0 0 L 20 20', style: 'dashed', points: ['', ''] }, + { path: 'M 0 0 L 20 20', style: 'solid', points: ['', 'arrow'] }, + { path: 'M 0 0 L 20 20', style: 'dashed', points: ['', 'arrow'] }, + { path: 'M 0 0 L 20 20', style: 'solid', points: ['', 'dot'] }, + ], + }, + { + type: '折线、曲线', + 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 }, + ], + }, ] \ No newline at end of file diff --git a/src/hooks/useCreateElement.ts b/src/hooks/useCreateElement.ts index 428abd8a..6973e496 100644 --- a/src/hooks/useCreateElement.ts +++ b/src/hooks/useCreateElement.ts @@ -3,7 +3,7 @@ import { MutationTypes, useStore } from '@/store' import { createRandomCode } from '@/utils/common' import { getImageSize } from '@/utils/image' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' -import { ChartType, PPTElement, TableCell } from '@/types/slides' +import { PPTLineElement, ChartType, PPTElement, TableCell } from '@/types/slides' import { ShapePoolItem } from '@/configs/shapes' import { LinePoolItem } from '@/configs/lines' import useHistorySnapshot from '@/hooks/useHistorySnapshot' @@ -177,7 +177,8 @@ export default () => { */ const createLineElement = (position: LineElementPosition, data: LinePoolItem) => { const { left, top, start, end } = position - createElement({ + + const newElement: PPTLineElement = { type: 'line', id: createRandomCode(), left, @@ -188,7 +189,10 @@ export default () => { color: themeColor.value, style: data.style, width: 2, - }) + } + 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] + createElement(newElement) } return { diff --git a/src/types/edit.ts b/src/types/edit.ts index c9e1eecb..b2b3338f 100644 --- a/src/types/edit.ts +++ b/src/types/edit.ts @@ -44,11 +44,12 @@ export const enum OperateResizeHandlers { RIGHT_BOTTOM = 'right-bottom', } -export type OperateLineHandler = 'start' | 'end' +export type OperateLineHandler = 'start' | 'end' | 'mid' export const enum OperateLineHandlers { START = 'start', - END = 'end,' + END = 'end', + MID = 'mid', } export interface AlignmentLineAxis { diff --git a/src/types/slides.ts b/src/types/slides.ts index 09a300e7..aff28a99 100644 --- a/src/types/slides.ts +++ b/src/types/slides.ts @@ -117,6 +117,8 @@ export interface PPTLineElement { color: string; points: [string, string]; shadow?: PPTElementShadow; + broken?: [number, number]; + curve?: [number, number]; } export type ChartType = 'bar' | 'line' | 'pie' diff --git a/src/views/Editor/Canvas/Operate/LineElementOperate.vue b/src/views/Editor/Canvas/Operate/LineElementOperate.vue index ab8cfe7a..c45bd1ed 100644 --- a/src/views/Editor/Canvas/Operate/LineElementOperate.vue +++ b/src/views/Editor/Canvas/Operate/LineElementOperate.vue @@ -51,7 +51,7 @@ export default defineComponent({ const canvasScale = computed(() => store.state.canvasScale) const resizeHandlers = computed(() => { - return [ + const handlers = [ { handler: OperateLineHandlers.START, style: { @@ -67,6 +67,19 @@ export default defineComponent({ } }, ] + + if (props.elementInfo.curve || props.elementInfo.broken) { + const midHandler = (props.elementInfo.curve || props.elementInfo.broken) as [number, number] + + handlers.push({ + handler: OperateLineHandlers.MID, + style: { + left: midHandler[0] * canvasScale.value + 'px', + top: midHandler[1] * canvasScale.value + 'px', + } + }) + } + return handlers }) return { diff --git a/src/views/Editor/Canvas/hooks/useDragLineElement.ts b/src/views/Editor/Canvas/hooks/useDragLineElement.ts index 0e029fc7..372c347f 100644 --- a/src/views/Editor/Canvas/hooks/useDragLineElement.ts +++ b/src/views/Editor/Canvas/hooks/useDragLineElement.ts @@ -78,6 +78,10 @@ export default (elementList: Ref) => { let endX = element.left + element.end[0] let endY = element.top + element.end[1] + const mid = element.broken || element.curve || [0, 0] + let midX = element.left + mid[0] + let midY = element.top + mid[1] + // 拖拽起点或终点的位置 // 水平和垂直方向上有吸附 if (command === OperateLineHandlers.START) { @@ -96,7 +100,7 @@ export default (elementList: Ref) => { } } } - else { + else if (command === OperateLineHandlers.END) { endX = endX + moveX endY = endY + moveY @@ -112,6 +116,19 @@ export default (elementList: Ref) => { } } } + else { + midX = midX + moveX + midY = midY + moveY + + if (Math.abs(midX - startX) < sorptionRange) midX = startX + if (Math.abs(midY - startY) < sorptionRange) midY = startY + if (Math.abs(midX - endX) < sorptionRange) midX = endX + if (Math.abs(midY - endY) < sorptionRange) midY = endY + if (Math.abs(midX - (startX + endX) / 2) < sorptionRange && Math.abs(midY - (startY + endY) / 2) < sorptionRange) { + midX = (startX + endX) / 2 + midY = (startY + endY) / 2 + } + } // 计算更新起点和终点基于自身元素位置的坐标 const minX = Math.min(startX, endX) @@ -132,13 +149,22 @@ export default (elementList: Ref) => { elementList.value = elementList.value.map(el => { if (el.id === element.id) { - return { - ...el, + const newEl: PPTLineElement = { + ...(el as PPTLineElement), left: minX, top: minY, start: start, end: end, } + if (command !== OperateLineHandlers.MID) { + 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] + } + else { + if (element.broken) newEl.broken = [midX - minX, midY - minY] + if (element.curve) newEl.curve = [midX - minX, midY - minY] + } + return newEl } return el }) diff --git a/src/views/Editor/CanvasTool/LinePool.vue b/src/views/Editor/CanvasTool/LinePool.vue index 7607015a..eeb2a7fb 100644 --- a/src/views/Editor/CanvasTool/LinePool.vue +++ b/src/views/Editor/CanvasTool/LinePool.vue @@ -1,46 +1,51 @@