jvs-ppt-ui 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -2
- package/dist/lib/jvs-ppt-ui.es.js +22404 -21454
- package/dist/lib/jvs-ppt-ui.umd.js +102 -101
- package/dist/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/App.vue +53 -53
- package/src/components/AIPptDialog.vue +2 -0
- package/src/components/CanvasArea.vue +164 -72
- package/src/components/Header.vue +374 -144
- package/src/components/PptEditor.vue +33 -15
- package/src/components/PresentationMode.vue +24 -4
- package/src/components/SidebarRight.vue +8 -1
- package/src/components/SvgChart.vue +5 -2
- package/src/components/TemplateGallery.vue +1321 -866
- package/src/components/Toolbar.vue +244 -22
- package/src/components/canvas/CanvasTransformHandles.vue +5 -1
- package/src/components/canvas/elements/CanvasShapeElement.vue +98 -19
- package/src/components/canvas/elements/CanvasTextElement.vue +39 -9
- package/src/components/canvas/textSelectionOverlay.ts +305 -0
- package/src/composables/canvas/useCanvasAlignment.ts +286 -238
- package/src/composables/canvas/useCanvasContextMenu.ts +53 -22
- package/src/composables/canvas/useCanvasFormatting.ts +35 -12
- package/src/composables/canvas/useCanvasTable.ts +52 -24
- package/src/composables/canvas/useCanvasText.ts +12 -0
- package/src/composables/canvas/useCanvasTransform.ts +15 -2
- package/src/composables/sidebar/useSidebarElementTransform.ts +5 -5
- package/src/composables/sidebar/useSidebarShapeFormat.ts +2 -2
- package/src/composables/useSlides.ts +495 -132
- package/src/style.css +88 -0
- package/src/types/index.ts +8 -0
- package/src/utils/line.ts +274 -312
- package/src/utils/pptxShapes.ts +1 -1
- package/src/utils/pptxShapesLazy.ts +39 -0
- package/src/utils/svgPathParser.ts +12 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, computed, nextTick, type Ref } from 'vue'
|
|
2
|
-
import {
|
|
2
|
+
import { shapeFormulas } from '../../utils/pptxShapesLazy'
|
|
3
3
|
|
|
4
4
|
export interface FormattingOptions {
|
|
5
5
|
activeSlide: Ref<any>
|
|
@@ -45,6 +45,29 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
45
45
|
|
|
46
46
|
const quickRecentColors = ref<string[]>([])
|
|
47
47
|
|
|
48
|
+
// 组合内子元素感知:按选中 id 递归解析(含嵌套组),不能只查顶层 elements,
|
|
49
|
+
// 否则选中组合内子元素时字号/颜色/填充/边框等设置全部静默失效
|
|
50
|
+
function findElementNested(id: string | null | undefined, elements: any[] = activeSlide.value?.elements || []): any {
|
|
51
|
+
if (!id) return null
|
|
52
|
+
for (const el of elements) {
|
|
53
|
+
if (el.id === id) return el
|
|
54
|
+
if (Array.isArray(el.elements) && el.elements.length) {
|
|
55
|
+
const found = findElementNested(id, el.elements)
|
|
56
|
+
if (found) return found
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveSelectedElements(typeFilter?: string): any[] {
|
|
63
|
+
const out: any[] = []
|
|
64
|
+
for (const id of selectedElementIds.value || []) {
|
|
65
|
+
const el = findElementNested(id)
|
|
66
|
+
if (el && (!typeFilter || el.type === typeFilter)) out.push(el)
|
|
67
|
+
}
|
|
68
|
+
return out
|
|
69
|
+
}
|
|
70
|
+
|
|
48
71
|
function rgbToHex(rgbStr: string | undefined): string {
|
|
49
72
|
if (!rgbStr || rgbStr === 'transparent') return 'transparent'
|
|
50
73
|
if (rgbStr.startsWith('#')) return rgbStr
|
|
@@ -147,7 +170,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
147
170
|
const quickBorderStyle = computed({
|
|
148
171
|
get() {
|
|
149
172
|
if (!selectedElementId.value || !activeSlide.value) return 'solid'
|
|
150
|
-
const el =
|
|
173
|
+
const el = findElementNested(selectedElementId.value)
|
|
151
174
|
if (!el) return 'solid'
|
|
152
175
|
if (el.type === 'line') {
|
|
153
176
|
return el.lineStyle || 'solid'
|
|
@@ -156,7 +179,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
156
179
|
},
|
|
157
180
|
set(val) {
|
|
158
181
|
if (selectedElementIds.value.length === 0 || !activeSlide.value) return
|
|
159
|
-
const els =
|
|
182
|
+
const els = resolveSelectedElements()
|
|
160
183
|
if (els.length === 0) return
|
|
161
184
|
els.forEach((el: any) => {
|
|
162
185
|
if (el.type === 'line') {
|
|
@@ -171,7 +194,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
171
194
|
|
|
172
195
|
const quickBorderWidth = computed({
|
|
173
196
|
get() {
|
|
174
|
-
const el = (selectedElement && selectedElement.value) || (
|
|
197
|
+
const el = (selectedElement && selectedElement.value) || findElementNested(selectedElementId.value)
|
|
175
198
|
if (!el) return 1
|
|
176
199
|
if (el.type === 'line') {
|
|
177
200
|
return el.style?.strokeWidth !== undefined ? el.style.strokeWidth : 1
|
|
@@ -181,7 +204,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
181
204
|
},
|
|
182
205
|
set(val) {
|
|
183
206
|
if (selectedElementIds.value.length === 0 || !activeSlide.value) return
|
|
184
|
-
const els =
|
|
207
|
+
const els = resolveSelectedElements()
|
|
185
208
|
if (els.length === 0) return
|
|
186
209
|
els.forEach((el: any) => {
|
|
187
210
|
let num = val
|
|
@@ -324,7 +347,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
324
347
|
|
|
325
348
|
function selectQuickTextColor(color: string, type: 'color' | 'background') {
|
|
326
349
|
if (selectedElementIds.value.length === 0 || !activeSlide.value) return
|
|
327
|
-
const els =
|
|
350
|
+
const els = resolveSelectedElements()
|
|
328
351
|
if (els.length === 0) return
|
|
329
352
|
|
|
330
353
|
// 0. Synchronize DOM contents to reactive state first for non-table elements
|
|
@@ -581,7 +604,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
581
604
|
|
|
582
605
|
function selectQuickFillColor(color: string) {
|
|
583
606
|
if (selectedElementIds.value.length === 0 || !activeSlide.value) return
|
|
584
|
-
const els =
|
|
607
|
+
const els = resolveSelectedElements()
|
|
585
608
|
if (els.length === 0) return
|
|
586
609
|
|
|
587
610
|
let hasAppliedToCells = false
|
|
@@ -649,7 +672,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
649
672
|
|
|
650
673
|
function changeQuickBorderColor(color: string) {
|
|
651
674
|
if (selectedElementIds.value.length === 0 || !activeSlide.value) return
|
|
652
|
-
const els =
|
|
675
|
+
const els = resolveSelectedElements()
|
|
653
676
|
if (els.length === 0) return
|
|
654
677
|
|
|
655
678
|
els.forEach((el: any) => {
|
|
@@ -697,7 +720,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
697
720
|
if (!el) return
|
|
698
721
|
const isEllipse = shape.title === '椭圆' || shape.pathFormula === 'ellipse' || shape.pptxShapeType === 'ellipse'
|
|
699
722
|
if (selectedElementIds.value.length > 1 && activeSlide.value) {
|
|
700
|
-
const els =
|
|
723
|
+
const els = resolveSelectedElements('shape')
|
|
701
724
|
els.forEach((item: any) => {
|
|
702
725
|
item.content = shape.path
|
|
703
726
|
item.viewBox = shape.viewBox
|
|
@@ -712,7 +735,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
712
735
|
|
|
713
736
|
if (shape.pathFormula) {
|
|
714
737
|
item.pathFormula = shape.pathFormula
|
|
715
|
-
const formulaObj =
|
|
738
|
+
const formulaObj = shapeFormulas()[shape.pathFormula]
|
|
716
739
|
if (formulaObj) {
|
|
717
740
|
if (shape.keypoints) {
|
|
718
741
|
item.keypoints = [...shape.keypoints]
|
|
@@ -745,7 +768,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
745
768
|
|
|
746
769
|
if (shape.pathFormula) {
|
|
747
770
|
el.pathFormula = shape.pathFormula
|
|
748
|
-
const formulaObj =
|
|
771
|
+
const formulaObj = shapeFormulas()[shape.pathFormula]
|
|
749
772
|
if (formulaObj) {
|
|
750
773
|
if (shape.keypoints) {
|
|
751
774
|
el.keypoints = [...shape.keypoints]
|
|
@@ -786,7 +809,7 @@ export function useCanvasFormatting(options: FormattingOptions) {
|
|
|
786
809
|
}
|
|
787
810
|
|
|
788
811
|
if (selectedElementIds.value.length > 1 && activeSlide.value) {
|
|
789
|
-
const els =
|
|
812
|
+
const els = resolveSelectedElements('line')
|
|
790
813
|
els.forEach(updateItem)
|
|
791
814
|
} else {
|
|
792
815
|
updateItem(el)
|
|
@@ -24,6 +24,27 @@ interface TableMeasure {
|
|
|
24
24
|
rowDots: number[]
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// 剥离表格编辑态的运行时属性(contenteditable/selected-cell/选区边框/索引),
|
|
28
|
+
// 存入 el.content 前必须清理,否则编辑态样式会被烙进内容(退出编辑后蓝边框残留)
|
|
29
|
+
export function cleanTableDOMForSaving(tableEl: HTMLTableElement) {
|
|
30
|
+
tableEl.querySelectorAll('td').forEach(td => {
|
|
31
|
+
td.removeAttribute('contenteditable')
|
|
32
|
+
td.classList.remove('selected-cell')
|
|
33
|
+
td.classList.remove('focused-cell')
|
|
34
|
+
td.removeAttribute('data-row')
|
|
35
|
+
td.removeAttribute('data-col')
|
|
36
|
+
td.removeAttribute('data-sel-top')
|
|
37
|
+
td.removeAttribute('data-sel-bottom')
|
|
38
|
+
td.removeAttribute('data-sel-left')
|
|
39
|
+
td.removeAttribute('data-sel-right')
|
|
40
|
+
td.style.boxShadow = ''
|
|
41
|
+
if (td.style.cursor === 'default') {
|
|
42
|
+
td.style.removeProperty('cursor')
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
tableEl.style.removeProperty('cursor')
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
export function useCanvasTable(options: TableOptions) {
|
|
28
49
|
const {
|
|
29
50
|
activeSlide,
|
|
@@ -97,6 +118,15 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
97
118
|
targetEl.content = html
|
|
98
119
|
bumpTableMeasure()
|
|
99
120
|
addHistorySnapshot()
|
|
121
|
+
// CanvasTextElement 的 syncContentToDom 在焦点位于单元格内时不再回写 DOM(保光标),
|
|
122
|
+
// 结构/样式操作随后的恢复代码(重设 contenteditable、重新绑定、重新聚焦)依赖新
|
|
123
|
+
// DOM,这里在 nextTick 强制同步一次;焦点不在表格内时组件 watch 已写过,此处幂等
|
|
124
|
+
nextTick(() => {
|
|
125
|
+
const container = document.getElementById(`editable-${targetEl.id}`)
|
|
126
|
+
if (container && container.innerHTML !== html) {
|
|
127
|
+
container.innerHTML = html
|
|
128
|
+
}
|
|
129
|
+
})
|
|
100
130
|
}
|
|
101
131
|
|
|
102
132
|
function getTableMeasure(el: any): TableMeasure | null {
|
|
@@ -359,6 +389,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
359
389
|
|
|
360
390
|
tableEl.querySelectorAll('td').forEach(td => {
|
|
361
391
|
td.style.boxShadow = ''
|
|
392
|
+
td.classList.remove('focused-cell')
|
|
362
393
|
td.removeAttribute('data-sel-top')
|
|
363
394
|
td.removeAttribute('data-sel-bottom')
|
|
364
395
|
td.removeAttribute('data-sel-left')
|
|
@@ -393,31 +424,16 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
393
424
|
if (isRight) shadows.push('inset -1.5px 0 0 0 #2563eb')
|
|
394
425
|
|
|
395
426
|
if (selectedTds.length === 1 && activeEl === td) {
|
|
427
|
+
// 焦点(光标)落在唯一选中格上:既不要描边也不要 selected-cell 蒙层,
|
|
428
|
+
// 否则出现"光标在单元格里还显示选中效果";focused-cell 类供 CSS 压掉蒙层
|
|
396
429
|
td.style.boxShadow = 'none'
|
|
430
|
+
td.classList.add('focused-cell')
|
|
397
431
|
} else {
|
|
398
432
|
td.style.boxShadow = shadows.length > 0 ? shadows.join(', ') : 'none'
|
|
399
433
|
}
|
|
400
434
|
})
|
|
401
435
|
}
|
|
402
436
|
|
|
403
|
-
function cleanTableDOMForSaving(tableEl: HTMLTableElement) {
|
|
404
|
-
tableEl.querySelectorAll('td').forEach(td => {
|
|
405
|
-
td.removeAttribute('contenteditable')
|
|
406
|
-
td.classList.remove('selected-cell')
|
|
407
|
-
td.removeAttribute('data-row')
|
|
408
|
-
td.removeAttribute('data-col')
|
|
409
|
-
td.removeAttribute('data-sel-top')
|
|
410
|
-
td.removeAttribute('data-sel-bottom')
|
|
411
|
-
td.removeAttribute('data-sel-left')
|
|
412
|
-
td.removeAttribute('data-sel-right')
|
|
413
|
-
td.style.boxShadow = ''
|
|
414
|
-
if (td.style.cursor === 'default') {
|
|
415
|
-
td.style.removeProperty('cursor')
|
|
416
|
-
}
|
|
417
|
-
})
|
|
418
|
-
tableEl.style.removeProperty('cursor')
|
|
419
|
-
}
|
|
420
|
-
|
|
421
437
|
function doSelectColumn(tableEl: HTMLTableElement, el: any, colIdx: number) {
|
|
422
438
|
tableEl.querySelectorAll('td').forEach(td => td.setAttribute('contenteditable', 'true'))
|
|
423
439
|
bindTableSelectionEvents(el)
|
|
@@ -836,8 +852,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
836
852
|
const freshTd = freshTable.querySelector(`td[data-row="${newSelectR}"][data-col="${newSelectC}"]`) as HTMLTableCellElement
|
|
837
853
|
if (freshTd) {
|
|
838
854
|
freshTd.classList.add('selected-cell')
|
|
839
|
-
|
|
855
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
856
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
840
857
|
freshTd.focus()
|
|
858
|
+
updateSelectionBorders(freshTable)
|
|
841
859
|
}
|
|
842
860
|
}
|
|
843
861
|
}
|
|
@@ -962,8 +980,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
962
980
|
const freshTd = freshTable.querySelector(`td[data-row="${newSelectR}"][data-col="${newSelectC}"]`) as HTMLTableCellElement
|
|
963
981
|
if (freshTd) {
|
|
964
982
|
freshTd.classList.add('selected-cell')
|
|
965
|
-
|
|
983
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
984
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
966
985
|
freshTd.focus()
|
|
986
|
+
updateSelectionBorders(freshTable)
|
|
967
987
|
}
|
|
968
988
|
}
|
|
969
989
|
}
|
|
@@ -1024,8 +1044,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1024
1044
|
const freshTd = freshTable.querySelector(`td[data-row="${newSelectR}"][data-col="${newSelectC}"]`) as HTMLTableCellElement
|
|
1025
1045
|
if (freshTd) {
|
|
1026
1046
|
freshTd.classList.add('selected-cell')
|
|
1027
|
-
|
|
1047
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
1048
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
1028
1049
|
freshTd.focus()
|
|
1050
|
+
updateSelectionBorders(freshTable)
|
|
1029
1051
|
}
|
|
1030
1052
|
}
|
|
1031
1053
|
}
|
|
@@ -1092,8 +1114,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1092
1114
|
const freshTd = freshTable.querySelector(`td[data-row="${newSelectR}"][data-col="${newSelectC}"]`) as HTMLTableCellElement
|
|
1093
1115
|
if (freshTd) {
|
|
1094
1116
|
freshTd.classList.add('selected-cell')
|
|
1095
|
-
|
|
1117
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
1118
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
1096
1119
|
freshTd.focus()
|
|
1120
|
+
updateSelectionBorders(freshTable)
|
|
1097
1121
|
}
|
|
1098
1122
|
}
|
|
1099
1123
|
}
|
|
@@ -1158,8 +1182,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1158
1182
|
const freshTd = freshTable.querySelector(`td[data-row="${bounds.minRow}"][data-col="${bounds.minCol}"]`) as HTMLTableCellElement
|
|
1159
1183
|
if (freshTd) {
|
|
1160
1184
|
freshTd.classList.add('selected-cell')
|
|
1161
|
-
|
|
1185
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
1186
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
1162
1187
|
freshTd.focus()
|
|
1188
|
+
updateSelectionBorders(freshTable)
|
|
1163
1189
|
}
|
|
1164
1190
|
}
|
|
1165
1191
|
}
|
|
@@ -1260,8 +1286,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1260
1286
|
const freshTd = freshTable.querySelector(`td[data-row="${rStart}"][data-col="${cStart}"]`) as HTMLTableCellElement
|
|
1261
1287
|
if (freshTd) {
|
|
1262
1288
|
freshTd.classList.add('selected-cell')
|
|
1263
|
-
|
|
1289
|
+
// 先 focus 再算边框:focus() 同步设置 activeElement,这样 updateSelectionBorders
|
|
1290
|
+
// 里"唯一选中格=焦点格"的抑制分支才生效,结构操作后不会边描边边留蒙层
|
|
1264
1291
|
freshTd.focus()
|
|
1292
|
+
updateSelectionBorders(freshTable)
|
|
1265
1293
|
}
|
|
1266
1294
|
}
|
|
1267
1295
|
}
|
|
@@ -2,6 +2,7 @@ import { ref, nextTick, type Ref } from 'vue'
|
|
|
2
2
|
import { normalizeHtmlFontFamily } from '../useSlides'
|
|
3
3
|
import { getDefaultPlaceholderContent, isSvgPathString } from '../../utils/canvas/elementStyles'
|
|
4
4
|
import { isEllipseShape } from '../../utils/line'
|
|
5
|
+
import { cleanTableDOMForSaving } from './useCanvasTable'
|
|
5
6
|
|
|
6
7
|
export interface TextOptions {
|
|
7
8
|
activeSlide: Ref<any>
|
|
@@ -514,6 +515,17 @@ export function useCanvasText(options: TextOptions) {
|
|
|
514
515
|
htmlVal = htmlVal.replace(/style="\s*;\s*"/gi, '')
|
|
515
516
|
htmlVal = htmlVal.replace(/style="\s*"/gi, '')
|
|
516
517
|
}
|
|
518
|
+
// 表格:活 DOM 带编辑态运行时属性(contenteditable/selected-cell/选区边框),
|
|
519
|
+
// 存档前克隆清理,避免烙进 content(退出编辑后蓝边框残留)
|
|
520
|
+
if (htmlVal.includes('<table')) {
|
|
521
|
+
const div = document.createElement('div')
|
|
522
|
+
div.innerHTML = htmlVal
|
|
523
|
+
const tableEl = div.querySelector('table')
|
|
524
|
+
if (tableEl) {
|
|
525
|
+
cleanTableDOMForSaving(tableEl)
|
|
526
|
+
htmlVal = div.innerHTML
|
|
527
|
+
}
|
|
528
|
+
}
|
|
517
529
|
el.content = htmlVal
|
|
518
530
|
|
|
519
531
|
if (el.content && el.content.includes('<table')) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ref, nextTick, type Ref } from 'vue'
|
|
2
|
-
import {
|
|
2
|
+
import { shapeFormulas } from '../../utils/pptxShapesLazy'
|
|
3
|
+
import { syncSlideConnections } from '../../utils/line'
|
|
3
4
|
|
|
4
5
|
export interface ResizeState {
|
|
5
6
|
el: any
|
|
@@ -412,6 +413,9 @@ export function useCanvasTransform(options: CanvasTransformOptions) {
|
|
|
412
413
|
}
|
|
413
414
|
}
|
|
414
415
|
}
|
|
416
|
+
if (activeSlide.value && activeSlide.value.elements) {
|
|
417
|
+
syncSlideConnections(activeSlide.value, logicalWidth.value, logicalHeight.value, selectedElementIds.value)
|
|
418
|
+
}
|
|
415
419
|
}
|
|
416
420
|
|
|
417
421
|
function stopResize() {
|
|
@@ -539,6 +543,9 @@ export function useCanvasTransform(options: CanvasTransformOptions) {
|
|
|
539
543
|
newAngle = (newAngle % 360 + 360) % 360
|
|
540
544
|
state.el.style.rotate = Math.round(newAngle)
|
|
541
545
|
}
|
|
546
|
+
if (activeSlide.value && activeSlide.value.elements) {
|
|
547
|
+
syncSlideConnections(activeSlide.value, logicalWidth.value, logicalHeight.value, selectedElementIds.value)
|
|
548
|
+
}
|
|
542
549
|
}
|
|
543
550
|
|
|
544
551
|
function stopRotate() {
|
|
@@ -598,7 +605,7 @@ export function useCanvasTransform(options: CanvasTransformOptions) {
|
|
|
598
605
|
if (!isDraggingKeypoint || !currentElement.value) return
|
|
599
606
|
|
|
600
607
|
const curEl = currentElement.value
|
|
601
|
-
const formulaObj =
|
|
608
|
+
const formulaObj = shapeFormulas()[curEl.pathFormula as string]
|
|
602
609
|
if (!formulaObj) return
|
|
603
610
|
|
|
604
611
|
const dx = e.clientX - dragKeypointStartX
|
|
@@ -1031,6 +1038,9 @@ export function useCanvasTransform(options: CanvasTransformOptions) {
|
|
|
1031
1038
|
parentGroup.elements[idx] = { ...curEl, path: newPath, content: newPath }
|
|
1032
1039
|
}
|
|
1033
1040
|
}
|
|
1041
|
+
if (activeSlide.value && activeSlide.value.elements) {
|
|
1042
|
+
syncSlideConnections(activeSlide.value, logicalWidth.value, logicalHeight.value, selectedElementIds.value)
|
|
1043
|
+
}
|
|
1034
1044
|
}
|
|
1035
1045
|
|
|
1036
1046
|
function stopDragKeypoint() {
|
|
@@ -1249,6 +1259,9 @@ export function useCanvasTransform(options: CanvasTransformOptions) {
|
|
|
1249
1259
|
currentElement.value = null
|
|
1250
1260
|
window.removeEventListener('mousemove', handleDragLinePoint)
|
|
1251
1261
|
window.removeEventListener('mouseup', stopDragLinePoint)
|
|
1262
|
+
if (activeSlide.value && activeSlide.value.elements) {
|
|
1263
|
+
syncSlideConnections(activeSlide.value, logicalWidth.value, logicalHeight.value, selectedElementIds.value)
|
|
1264
|
+
}
|
|
1252
1265
|
pauseHistory.value = false
|
|
1253
1266
|
addHistorySnapshot()
|
|
1254
1267
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computed, type Ref, type ComputedRef } from 'vue'
|
|
2
|
-
import {
|
|
2
|
+
import { shapeFormulas } from '../../utils/pptxShapesLazy'
|
|
3
3
|
import { useSlides } from '../useSlides'
|
|
4
4
|
|
|
5
5
|
export function useSidebarElementTransform(
|
|
@@ -277,7 +277,7 @@ export function useSidebarElementTransform(
|
|
|
277
277
|
if (typeof el.height === 'number') el.height = newH
|
|
278
278
|
}
|
|
279
279
|
if (el.type === 'shape' && el.pathFormula) {
|
|
280
|
-
const formulaObj =
|
|
280
|
+
const formulaObj = shapeFormulas()[el.pathFormula]
|
|
281
281
|
if (formulaObj) {
|
|
282
282
|
const logicalW = parseFloat(el.style.width) || val
|
|
283
283
|
const logicalH = parseFloat(el.style.height) || 120
|
|
@@ -333,7 +333,7 @@ export function useSidebarElementTransform(
|
|
|
333
333
|
})
|
|
334
334
|
}
|
|
335
335
|
if (selectedElement.value.type === 'shape' && selectedElement.value.pathFormula) {
|
|
336
|
-
const formulaObj =
|
|
336
|
+
const formulaObj = shapeFormulas()[selectedElement.value.pathFormula]
|
|
337
337
|
if (formulaObj) {
|
|
338
338
|
const logicalW = parseFloat(selectedElement.value.style.width) || val
|
|
339
339
|
const logicalH = parseFloat(selectedElement.value.style.height) || 120
|
|
@@ -408,7 +408,7 @@ export function useSidebarElementTransform(
|
|
|
408
408
|
if (typeof el.width === 'number') el.width = newW
|
|
409
409
|
}
|
|
410
410
|
if (el.type === 'shape' && el.pathFormula) {
|
|
411
|
-
const formulaObj =
|
|
411
|
+
const formulaObj = shapeFormulas()[el.pathFormula]
|
|
412
412
|
if (formulaObj) {
|
|
413
413
|
const logicalW = parseFloat(el.style.width) || 120
|
|
414
414
|
const logicalH = parseFloat(el.style.height) || val
|
|
@@ -464,7 +464,7 @@ export function useSidebarElementTransform(
|
|
|
464
464
|
})
|
|
465
465
|
}
|
|
466
466
|
if (selectedElement.value.type === 'shape' && selectedElement.value.pathFormula) {
|
|
467
|
-
const formulaObj =
|
|
467
|
+
const formulaObj = shapeFormulas()[selectedElement.value.pathFormula]
|
|
468
468
|
if (formulaObj) {
|
|
469
469
|
const logicalW = parseFloat(selectedElement.value.style.width) || 120
|
|
470
470
|
const logicalH = parseFloat(selectedElement.value.style.height) || val
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, computed, watch, nextTick, type Ref, type ComputedRef } from 'vue'
|
|
2
|
-
import {
|
|
2
|
+
import { shapeFormulas } from '../../utils/pptxShapesLazy'
|
|
3
3
|
import {
|
|
4
4
|
isImagePlaceholder,
|
|
5
5
|
normalizeGradientConfig,
|
|
@@ -1253,7 +1253,7 @@ export function useSidebarShapeFormat(
|
|
|
1253
1253
|
|
|
1254
1254
|
if (shape.pathFormula) {
|
|
1255
1255
|
item.pathFormula = shape.pathFormula
|
|
1256
|
-
const formulaObj =
|
|
1256
|
+
const formulaObj = shapeFormulas()[shape.pathFormula]
|
|
1257
1257
|
if (formulaObj) {
|
|
1258
1258
|
if (shape.keypoints) {
|
|
1259
1259
|
item.keypoints = [...shape.keypoints]
|