mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 形状编辑支持多个控制点(#228)
This commit is contained in:
parent
dad2295f04
commit
f2b25336f4
@ -6,8 +6,8 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="基于 Vue3.x + TypeScript 的在线演示文稿(幻灯片)应用,还原了大部分 Office PowerPoint 常用功能,实现在线PPT的编辑、演示。支持导出PPT文件。" />
|
||||
<meta name="keywords" content="ppt,powerpoint,office powerpoint,在线ppt,幻灯片,演示文稿,ppt在线制作,Vue3,TypeScript" />
|
||||
<meta name="description" content="PPTist:基于 Vue3.x + TypeScript 的在线演示文稿(幻灯片)应用,还原了大部分 Office PowerPoint 常用功能,实现在线PPT的编辑、演示。支持导出PPT文件。" />
|
||||
<meta name="keywords" content="pptist,ppt,powerpoint,office powerpoint,在线ppt,幻灯片,演示文稿,ppt在线制作,Vue3,TypeScript" />
|
||||
<title>PPTist - 在线演示文稿</title>
|
||||
|
||||
<style>
|
||||
|
1203
package-lock.json
generated
1203
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@
|
||||
"number-precision": "^1.6.0",
|
||||
"pinia": "^2.1.7",
|
||||
"pptxgenjs": "^3.12.0",
|
||||
"pptxtojson": "^0.1.4",
|
||||
"pptxtojson": "^0.1.7",
|
||||
"prosemirror-commands": "^1.5.2",
|
||||
"prosemirror-dropcursor": "^1.8.1",
|
||||
"prosemirror-gapcursor": "^1.3.2",
|
||||
@ -44,7 +44,7 @@
|
||||
"svg-pathdata": "^6.0.3",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"vue": "^3.3.11",
|
||||
"vue": "^3.4.33",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -67,7 +67,7 @@
|
||||
"npm-run-all2": "^6.1.1",
|
||||
"sass": "^1.69.6",
|
||||
"typescript": "~5.3.0",
|
||||
"vite": "^5.0.10",
|
||||
"vue-tsc": "^1.8.25"
|
||||
"vite": "^5.3.4",
|
||||
"vue-tsc": "^2.0.26"
|
||||
}
|
||||
}
|
||||
|
@ -19,206 +19,226 @@ interface ShapeListItem {
|
||||
children: ShapePoolItem[]
|
||||
}
|
||||
|
||||
export const SHAPE_PATH_FORMULAS = {
|
||||
export interface ShapePathFormula {
|
||||
editable?: boolean
|
||||
defaultValue?: number[]
|
||||
range?: [number, number][]
|
||||
relative?: string[]
|
||||
getBaseSize?: ((width: number, height: number) => number)[]
|
||||
formula: (width: number, height: number, values?: number[]) => string
|
||||
}
|
||||
|
||||
export const SHAPE_PATH_FORMULAS: {
|
||||
[key: string]: ShapePathFormula
|
||||
} = {
|
||||
[ShapePathFormulasKeys.ROUND_RECT]: {
|
||||
editable: true,
|
||||
defaultValue: 0.125,
|
||||
range: [0, 0.5],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.125],
|
||||
range: [[0, 0.5]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M ${radius} 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height - radius} Q ${width} ${height} ${width - radius} ${height} L ${radius} ${height} Q 0 ${height} 0 ${height - radius} L 0 ${radius} Q 0 0 ${radius} 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_DIAGONAL]: {
|
||||
editable: true,
|
||||
defaultValue: 0.2,
|
||||
range: [0, 0.9],
|
||||
relative: 'right',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.2],
|
||||
range: [[0, 0.9]],
|
||||
relative: ['right'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M 0 ${height - radius} L 0 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} L ${radius} ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_SINGLE]: {
|
||||
editable: true,
|
||||
defaultValue: 0.2,
|
||||
range: [0, 0.9],
|
||||
relative: 'right',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.2],
|
||||
range: [[0, 0.9]],
|
||||
relative: ['right'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M 0 ${height} L 0 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_SAMESIDE]: {
|
||||
editable: true,
|
||||
defaultValue: 0.2,
|
||||
range: [0, 0.5],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.2],
|
||||
range: [[0, 0.5]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M 0 ${radius} L ${radius} 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} L 0 ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_DIAGONAL]: {
|
||||
editable: true,
|
||||
defaultValue: 0.125,
|
||||
range: [0, 1],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.125],
|
||||
range: [[0, 1]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M ${radius} 0 L ${width} 0 L ${width} ${height - radius} Q ${width} ${height} ${width - radius} ${height} L 0 ${height} L 0 ${radius} Q 0 0 ${radius} 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_SINGLE]: {
|
||||
editable: true,
|
||||
defaultValue: 0.125,
|
||||
range: [0, 1],
|
||||
relative: 'right',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.125],
|
||||
range: [[0, 1]],
|
||||
relative: ['right'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M 0 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height} L 0 ${height} L 0 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_SAMESIDE]: {
|
||||
editable: true,
|
||||
defaultValue: 0.125,
|
||||
range: [0, 0.5],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.125],
|
||||
range: [[0, 0.5]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M 0 ${radius} Q 0 0 ${radius} 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height} L 0 ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_ROUND_RECT]: {
|
||||
editable: true,
|
||||
defaultValue: 0.125,
|
||||
range: [0, 0.5],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const radius = Math.min(width, height) * value
|
||||
defaultValue: [0.125],
|
||||
range: [[0, 0.5]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const radius = Math.min(width, height) * values![0]
|
||||
return `M ${radius} 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} L 0 ${height} L 0 ${radius} Q 0 0 ${radius} 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.MESSAGE]: {
|
||||
formula: (width: number, height: number) => {
|
||||
editable: true,
|
||||
range: [[0, 0.8], [0.1, 0.3]],
|
||||
defaultValue: [0.3, 0.2],
|
||||
relative: ['left_bottom', 'bottom'],
|
||||
getBaseSize: [
|
||||
width => width,
|
||||
(width, height) => height,
|
||||
],
|
||||
formula: (width, height, values) => {
|
||||
const point = width * values![0]
|
||||
const arrowWidth = width * 0.2
|
||||
const arrowheight = height * 0.2
|
||||
return `M 0 0 L ${width} 0 L ${width} ${height - arrowheight} L ${width / 2} ${height - arrowheight} L ${width / 2 - arrowWidth} ${height} L ${width / 2 - arrowWidth} ${height - arrowheight} L 0 ${height - arrowheight} Z`
|
||||
const arrowheight = height * values![1]
|
||||
return `M 0 0 L ${width} 0 L ${width} ${height - arrowheight} L ${point + arrowWidth} ${height - arrowheight} L ${point} ${height} L ${point} ${height - arrowheight} L 0 ${height - arrowheight} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_MESSAGE]: {
|
||||
formula: (width: number, height: number) => {
|
||||
formula: (width, height) => {
|
||||
const radius = Math.min(width, height) * 0.125
|
||||
const arrowWidth = width * 0.2
|
||||
const arrowheight = height * 0.2
|
||||
const arrowWidth = Math.min(width, height) * 0.2
|
||||
const arrowheight = Math.min(width, height) * 0.2
|
||||
return `M 0 ${radius} Q 0 0 ${radius} 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height - radius - arrowheight} Q ${width} ${height - arrowheight} ${width - radius} ${height - arrowheight} L ${width / 2} ${height - arrowheight} L ${width / 2 - arrowWidth} ${height} L ${width / 2 - arrowWidth} ${height - arrowheight} L ${radius} ${height - arrowheight} Q 0 ${height - arrowheight} 0 ${height - radius - arrowheight} L 0 ${radius} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.L]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0.1, 0.9],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const lineWidth = Math.min(width, height) * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0.1, 0.9]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const lineWidth = Math.min(width, height) * values![0]
|
||||
return `M 0 0 L 0 ${height} L ${width} ${height} L ${width} ${height - lineWidth} L ${lineWidth} ${height - lineWidth} L ${lineWidth} 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.RING_RECT]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0.1, 0.45],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const lineWidth = Math.min(width, height) * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0.1, 0.45]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const lineWidth = Math.min(width, height) * values![0]
|
||||
return `M 0 0 ${width} 0 ${width} ${height} L 0 ${height} L 0 0 Z M ${lineWidth} ${lineWidth} L ${lineWidth} ${height - lineWidth} L ${width - lineWidth} ${height - lineWidth} L ${width - lineWidth} ${lineWidth} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.PLUS]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0.1, 0.9],
|
||||
relative: 'center',
|
||||
getBaseSize: (width: number, height: number) => Math.min(width, height),
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const lineWidth = Math.min(width, height) * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0.1, 0.9]],
|
||||
relative: ['center'],
|
||||
getBaseSize: [(width, height) => Math.min(width, height)],
|
||||
formula: (width, height, values) => {
|
||||
const lineWidth = Math.min(width, height) * values![0]
|
||||
return `M ${width / 2 - lineWidth / 2} 0 L ${width / 2 - lineWidth / 2} ${height / 2 - lineWidth / 2} L 0 ${height / 2 - lineWidth / 2} L 0 ${height / 2 + lineWidth / 2} L ${width / 2 - lineWidth / 2} ${height / 2 + lineWidth / 2} L ${width / 2 - lineWidth / 2} ${height} L ${width / 2 + lineWidth / 2} ${height} L ${width / 2 + lineWidth / 2} ${height / 2 + lineWidth / 2} L ${width} ${height / 2 + lineWidth / 2} L ${width} ${height / 2 - lineWidth / 2} L ${width / 2 + lineWidth / 2} ${height / 2 - lineWidth / 2} L ${width / 2 + lineWidth / 2} 0 Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.TRIANGLE]: {
|
||||
editable: true,
|
||||
defaultValue: 0.5,
|
||||
range: [0, 1],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number) => width,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const vertex = width * value
|
||||
defaultValue: [0.5],
|
||||
range: [[0, 1]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [width => width],
|
||||
formula: (width, height, values) => {
|
||||
const vertex = width * values![0]
|
||||
return `M ${vertex} 0 L 0 ${height} L ${width} ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.PARALLELOGRAM_LEFT]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0, 0.9],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number) => width,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const point = width * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0, 0.9]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [width => width],
|
||||
formula: (width, height, values) => {
|
||||
const point = width * values![0]
|
||||
return `M ${point} 0 L ${width} 0 L ${width - point} ${height} L 0 ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.PARALLELOGRAM_RIGHT]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0, 0.9],
|
||||
relative: 'right',
|
||||
getBaseSize: (width: number) => width,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const point = width * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0, 0.9]],
|
||||
relative: ['right'],
|
||||
getBaseSize: [width => width],
|
||||
formula: (width, height, values) => {
|
||||
const point = width * values![0]
|
||||
return `M 0 0 L ${width - point} 0 L ${width} ${height} L ${point} ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.TRAPEZOID]: {
|
||||
editable: true,
|
||||
defaultValue: 0.25,
|
||||
range: [0, 0.5],
|
||||
relative: 'left',
|
||||
getBaseSize: (width: number) => width,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const point = width * value
|
||||
defaultValue: [0.25],
|
||||
range: [[0, 0.5]],
|
||||
relative: ['left'],
|
||||
getBaseSize: [width => width],
|
||||
formula: (width, height, values) => {
|
||||
const point = width * values![0]
|
||||
return `M ${point} 0 L ${width - point} 0 L ${width} ${height} L 0 ${height} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.BULLET]: {
|
||||
editable: true,
|
||||
defaultValue: 0.2,
|
||||
range: [0, 1],
|
||||
relative: 'top',
|
||||
getBaseSize: (width: number, height: number) => height,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const point = height * value
|
||||
defaultValue: [0.2],
|
||||
range: [[0, 1]],
|
||||
relative: ['top'],
|
||||
getBaseSize: [(width, height) => height],
|
||||
formula: (width, height, values) => {
|
||||
const point = height * values![0]
|
||||
return `M ${width / 2} 0 L 0 ${point} L 0 ${height} L ${width} ${height} L ${width} ${point} Z`
|
||||
}
|
||||
},
|
||||
[ShapePathFormulasKeys.INDICATOR]: {
|
||||
editable: true,
|
||||
defaultValue: 0.2,
|
||||
range: [0, 0.9],
|
||||
relative: 'right',
|
||||
getBaseSize: (width: number) => width,
|
||||
formula: (width: number, height: number, value: number) => {
|
||||
const point = width * value
|
||||
defaultValue: [0.2],
|
||||
range: [[0, 0.9]],
|
||||
relative: ['right'],
|
||||
getBaseSize: [width => width],
|
||||
formula: (width, height, values) => {
|
||||
const point = width * values![0]
|
||||
return `M ${width} ${height / 2} L ${width - point} 0 L 0 0 L ${point} ${height / 2} L 0 ${height} L ${width - point} ${height} Z`
|
||||
}
|
||||
},
|
||||
|
@ -235,9 +235,9 @@ export default () => {
|
||||
newElement.viewBox = [width, height]
|
||||
|
||||
const pathFormula = SHAPE_PATH_FORMULAS[data.pathFormula]
|
||||
if ('editable' in pathFormula) {
|
||||
newElement.path = pathFormula.formula(width, height, pathFormula.defaultValue)
|
||||
newElement.keypoint = pathFormula.defaultValue
|
||||
if ('editable' in pathFormula && pathFormula.editable) {
|
||||
newElement.path = pathFormula.formula(width, height, pathFormula.defaultValue!)
|
||||
newElement.keypoints = pathFormula.defaultValue
|
||||
}
|
||||
else newElement.path = pathFormula.formula(width, height)
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ export interface ShapeText {
|
||||
* 一般情况下,形状的大小变化时仅由宽高基于 viewBox 的缩放比例来调整形状,而 viewBox 本身和 path 不会变化,
|
||||
* 但也有一些形状希望能更精确的控制一些关键点的位置,此时就需要提供路径计算公式,通过在缩放时更新 viewBox 并重新计算 path 来重新绘制形状
|
||||
*
|
||||
* keypoint?: 关键点位置百分比
|
||||
* keypoints?: 关键点位置百分比
|
||||
*/
|
||||
export interface PPTShapeElement extends PPTBaseElement {
|
||||
type: 'shape'
|
||||
@ -336,7 +336,7 @@ export interface PPTShapeElement extends PPTBaseElement {
|
||||
special?: boolean
|
||||
text?: ShapeText
|
||||
pathFormula?: ShapePathFormulasKeys
|
||||
keypoint?: number
|
||||
keypoints?: number[]
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,9 +24,10 @@
|
||||
/>
|
||||
<div
|
||||
class="operate-keypoint-handler"
|
||||
v-if="elementInfo.keypoint !== undefined"
|
||||
:style="keypointStyle"
|
||||
@mousedown.stop="$event => moveShapeKeypoint($event, elementInfo)"
|
||||
v-for="(keypoint, index) in keypoints"
|
||||
:key="index"
|
||||
:style="keypoint.styles"
|
||||
@mousedown.stop="$event => moveShapeKeypoint($event, elementInfo, index)"
|
||||
></div>
|
||||
</template>
|
||||
</div>
|
||||
@ -39,7 +40,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, type CSSProperties } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import type { PPTShapeElement } from '@/types/slides'
|
||||
@ -56,7 +57,7 @@ const props = defineProps<{
|
||||
handlerVisible: boolean
|
||||
rotateElement: (e: MouseEvent, element: PPTShapeElement) => void
|
||||
scaleElement: (e: MouseEvent, element: PPTShapeElement, command: OperateResizeHandlers) => void
|
||||
moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement) => void
|
||||
moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement, index: number) => void
|
||||
}>()
|
||||
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
@ -65,19 +66,31 @@ const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
|
||||
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
|
||||
const { resizeHandlers, borderLines } = useCommonOperate(scaleWidth, scaleHeight)
|
||||
|
||||
const keypointStyle = computed(() => {
|
||||
if (!props.elementInfo.pathFormula || props.elementInfo.keypoint === undefined) return {}
|
||||
|
||||
const keypoints = computed(() => {
|
||||
if (!props.elementInfo.pathFormula || props.elementInfo.keypoints === undefined) return []
|
||||
const pathFormula = SHAPE_PATH_FORMULAS[props.elementInfo.pathFormula]
|
||||
if ('editable' in pathFormula) {
|
||||
const keypointPos = pathFormula.getBaseSize(props.elementInfo.width, props.elementInfo.height) * props.elementInfo.keypoint
|
||||
if (pathFormula.relative === 'left') return { left: keypointPos * canvasScale.value + 'px' }
|
||||
if (pathFormula.relative === 'right') return { left: (props.elementInfo.width - keypointPos) * canvasScale.value + 'px' }
|
||||
if (pathFormula.relative === 'center') return { left: (props.elementInfo.width - keypointPos) / 2 * canvasScale.value + 'px' }
|
||||
if (pathFormula.relative === 'top') return { top: keypointPos * canvasScale.value + 'px' }
|
||||
if (pathFormula.relative === 'bottom') return { top: (props.elementInfo.height - keypointPos) * canvasScale.value + 'px' }
|
||||
}
|
||||
return {}
|
||||
|
||||
return props.elementInfo.keypoints.map((keypoint, index) => {
|
||||
const getBaseSize = pathFormula.getBaseSize![index]
|
||||
const relative = pathFormula.relative![index]
|
||||
const keypointPos = getBaseSize(props.elementInfo.width, props.elementInfo.height) * keypoint
|
||||
|
||||
let styles: CSSProperties = {}
|
||||
if (relative === 'left') styles = { left: keypointPos * canvasScale.value + 'px' }
|
||||
else if (relative === 'right') styles = { left: (props.elementInfo.width - keypointPos) * canvasScale.value + 'px' }
|
||||
else if (relative === 'center') styles = { left: (props.elementInfo.width - keypointPos) / 2 * canvasScale.value + 'px' }
|
||||
else if (relative === 'top') styles = { top: keypointPos * canvasScale.value + 'px' }
|
||||
else if (relative === 'bottom') styles = { top: (props.elementInfo.height - keypointPos) * canvasScale.value + 'px' }
|
||||
else if (relative === 'left_bottom') styles = { left: keypointPos * canvasScale.value + 'px', top: props.elementInfo.height * canvasScale.value + 'px' }
|
||||
else if (relative === 'right_bottom') styles = { left: (props.elementInfo.width - keypointPos) * canvasScale.value + 'px', top: props.elementInfo.height * canvasScale.value + 'px' }
|
||||
else if (relative === 'top_right') styles = { left: props.elementInfo.width * canvasScale.value + 'px', top: keypointPos * canvasScale.value + 'px' }
|
||||
else if (relative === 'bottom_right') styles = { left: props.elementInfo.width * canvasScale.value + 'px', top: (props.elementInfo.height - keypointPos) * canvasScale.value + 'px' }
|
||||
|
||||
return {
|
||||
keypoint,
|
||||
styles,
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -69,7 +69,7 @@ const props = defineProps<{
|
||||
rotateElement: (e: MouseEvent, element: Exclude<PPTElement, PPTChartElement | PPTLineElement | PPTVideoElement | PPTAudioElement>) => void
|
||||
scaleElement: (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: OperateResizeHandlers) => void
|
||||
dragLineElement: (e: MouseEvent, element: PPTLineElement, command: OperateLineHandlers) => void
|
||||
moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement) => void
|
||||
moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement, index: number) => void
|
||||
openLinkDialog: () => void
|
||||
}>()
|
||||
|
||||
|
@ -20,7 +20,7 @@ export default (
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const moveShapeKeypoint = (e: MouseEvent | TouchEvent, element: PPTShapeElement) => {
|
||||
const moveShapeKeypoint = (e: MouseEvent | TouchEvent, element: PPTShapeElement, index = 0) => {
|
||||
const isTouchEvent = !(e instanceof MouseEvent)
|
||||
if (isTouchEvent && (!e.changedTouches || !e.changedTouches[0])) return
|
||||
|
||||
@ -29,13 +29,19 @@ export default (
|
||||
const startPageX = isTouchEvent ? e.changedTouches[0].pageX : e.pageX
|
||||
const startPageY = isTouchEvent ? e.changedTouches[0].pageY : e.pageY
|
||||
|
||||
const originKeypoints = element.keypoints!
|
||||
|
||||
const pathFormula = SHAPE_PATH_FORMULAS[element.pathFormula!]
|
||||
let shapePathData: ShapePathData | null = null
|
||||
if ('editable' in pathFormula) {
|
||||
const baseSize = pathFormula.getBaseSize(element.width, element.height)
|
||||
const originPos = baseSize * element.keypoint!
|
||||
const [min, max] = pathFormula.range
|
||||
const relative = pathFormula.relative
|
||||
if ('editable' in pathFormula && pathFormula.editable) {
|
||||
const getBaseSize = pathFormula.getBaseSize![index]
|
||||
const range = pathFormula.range![index]
|
||||
const relative = pathFormula.relative![index]
|
||||
const keypoint = originKeypoints[index]
|
||||
|
||||
const baseSize = getBaseSize(element.width, element.height)
|
||||
const originPos = baseSize * keypoint
|
||||
const [min, max] = range
|
||||
|
||||
shapePathData = { baseSize, originPos, min, max, relative }
|
||||
}
|
||||
@ -55,19 +61,30 @@ export default (
|
||||
|
||||
let keypoint = 0
|
||||
|
||||
if (relative === 'left') keypoint = (originPos + moveX) / baseSize
|
||||
if (relative === 'right') keypoint = (originPos - moveX) / baseSize
|
||||
if (relative === 'center') keypoint = (originPos - moveX * 2) / baseSize
|
||||
if (relative === 'top') keypoint = (originPos + moveY) / baseSize
|
||||
if (relative === 'bottom') keypoint = (originPos - moveY) / baseSize
|
||||
else if (relative === 'left') keypoint = (originPos + moveX) / baseSize
|
||||
else if (relative === 'right') keypoint = (originPos - moveX) / baseSize
|
||||
else if (relative === 'top') keypoint = (originPos + moveY) / baseSize
|
||||
else if (relative === 'bottom') keypoint = (originPos - moveY) / baseSize
|
||||
else if (relative === 'left_bottom') keypoint = (originPos + moveX) / baseSize
|
||||
else if (relative === 'right_bottom') keypoint = (originPos - moveX) / baseSize
|
||||
else if (relative === 'top_right') keypoint = (originPos + moveY) / baseSize
|
||||
else if (relative === 'bottom_right') keypoint = (originPos - moveY) / baseSize
|
||||
|
||||
if (keypoint < min) keypoint = min
|
||||
if (keypoint > max) keypoint = max
|
||||
|
||||
let keypoints: number[] = []
|
||||
if (Array.isArray(originKeypoints)) {
|
||||
keypoints = [...originKeypoints]
|
||||
keypoints[index] = keypoint
|
||||
}
|
||||
else keypoints = [keypoint]
|
||||
|
||||
return {
|
||||
...el,
|
||||
keypoint,
|
||||
path: pathFormula.formula(shapeElement.width, shapeElement.height, keypoint),
|
||||
keypoints,
|
||||
path: pathFormula.formula(shapeElement.width, shapeElement.height, keypoints),
|
||||
}
|
||||
}
|
||||
return el
|
||||
|
@ -405,7 +405,7 @@ export default (
|
||||
const pathFormula = SHAPE_PATH_FORMULAS[el.pathFormula]
|
||||
|
||||
let path = ''
|
||||
if ('editable' in pathFormula) path = pathFormula.formula(width, height, el.keypoint!)
|
||||
if ('editable' in pathFormula) path = pathFormula.formula(width, height, el.keypoints!)
|
||||
else path = pathFormula.formula(width, height)
|
||||
|
||||
return {
|
||||
|
@ -224,13 +224,13 @@ const changeShape = (shape: ShapePoolItem) => {
|
||||
const pathFormula = SHAPE_PATH_FORMULAS[shape.pathFormula]
|
||||
if ('editable' in pathFormula) {
|
||||
props.path = pathFormula.formula(width, height, pathFormula.defaultValue)
|
||||
props.keypoint = pathFormula.defaultValue
|
||||
props.keypoints = pathFormula.defaultValue
|
||||
}
|
||||
else props.path = pathFormula.formula(width, height)
|
||||
}
|
||||
else {
|
||||
props.pathFormula = undefined
|
||||
props.keypoint = undefined
|
||||
props.keypoints = undefined
|
||||
}
|
||||
updateElement(props)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user