mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 线条元素新增三次曲线类型
This commit is contained in:
parent
63a9fc2d6e
commit
20b0ff9d7b
@ -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 },
|
||||
],
|
||||
},
|
||||
]
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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<PPTBaseElement, 'height' | 'rotate'> {
|
||||
type: 'line';
|
||||
@ -328,6 +330,7 @@ export interface PPTLineElement extends Omit<PPTBaseElement, 'height' | 'rotate'
|
||||
shadow?: PPTElementShadow;
|
||||
broken?: [number, number];
|
||||
curve?: [number, number];
|
||||
cubic?: [[number, number], [number, number]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,9 +197,15 @@ export const getLineElementPath = (element: PPTLineElement) => {
|
||||
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}`
|
||||
}
|
@ -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
|
||||
})
|
||||
|
||||
|
@ -83,6 +83,12 @@ export default (elementList: Ref<PPTElement[]>) => {
|
||||
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<PPTElement[]>) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (command === OperateLineHandlers.C) {
|
||||
midX = midX + moveX
|
||||
midY = midY + moveY
|
||||
|
||||
@ -130,6 +136,24 @@ export default (elementList: Ref<PPTElement[]>) => {
|
||||
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<PPTElement[]>) => {
|
||||
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
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="line-pool">
|
||||
<div class="category" v-for="item in lineList" :key="item.type">
|
||||
<div class="category" v-for="(item, i) in lineList" :key="item.type">
|
||||
<div class="category-name">{{item.type}}</div>
|
||||
<div class="line-list">
|
||||
<div class="line-item" v-for="(line, index) in item.children" :key="index">
|
||||
<div class="line-item" v-for="(line, j) in item.children" :key="j">
|
||||
<div class="line-content" @click="selectLine(line)">
|
||||
<svg
|
||||
overflow="visible"
|
||||
@ -14,7 +14,7 @@
|
||||
<LinePointMarker
|
||||
class="line-marker"
|
||||
v-if="line.points[0]"
|
||||
:id="`preset-line-${index}`"
|
||||
:id="`preset-line-${i}-${j}`"
|
||||
position="start"
|
||||
:type="line.points[0]"
|
||||
color="currentColor"
|
||||
@ -23,7 +23,7 @@
|
||||
<LinePointMarker
|
||||
class="line-marker"
|
||||
v-if="line.points[1]"
|
||||
:id="`preset-line-${index}`"
|
||||
:id="`preset-line-${i}-${j}`"
|
||||
position="end"
|
||||
:type="line.points[1]"
|
||||
color="currentColor"
|
||||
@ -37,8 +37,8 @@
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
:stroke-dasharray="line.style === 'solid' ? '0, 0' : '4, 1'"
|
||||
:marker-start="line.points[0] ? `url(#${`preset-line-${index}`}-${line.points[0]}-start)` : ''"
|
||||
:marker-end="line.points[1] ? `url(#${`preset-line-${index}`}-${line.points[1]}-end)` : ''"
|
||||
:marker-start="line.points[0] ? `url(#${`preset-line-${i}-${j}`}-${line.points[0]}-start)` : ''"
|
||||
:marker-end="line.points[1] ? `url(#${`preset-line-${i}-${j}`}-${line.points[1]}-end)` : ''"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user