jvs-ppt-ui 0.0.14 → 0.0.16
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/dist/lib/check_imgs.html +18 -0
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.css +187 -27
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.js +1 -1
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.json +345 -65
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.ttf +0 -0
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.woff +0 -0
- package/dist/lib/jvs-ppt-ui/iconfont/iconfont.woff2 +0 -0
- package/dist/lib/jvs-ppt-ui/img/al.png +0 -0
- package/dist/lib/jvs-ppt-ui/img/d.png +0 -0
- package/dist/lib/jvs-ppt-ui/img/dl.png +0 -0
- package/dist/lib/jvs-ppt-ui/img/l.png +0 -0
- package/dist/lib/jvs-ppt-ui.es.js +44973 -43349
- package/dist/lib/jvs-ppt-ui.umd.js +102 -102
- package/dist/lib/style.css +1 -1
- package/package.json +1 -1
- package/scripts/check-icons.mjs +22 -0
- package/scripts/patch-anim-icons.mjs +45 -0
- package/src/assets/iconfont/iconfont.css +187 -27
- package/src/assets/iconfont/iconfont.js +1 -1
- package/src/assets/iconfont/iconfont.json +345 -65
- package/src/assets/iconfont/iconfont.ttf +0 -0
- package/src/assets/iconfont/iconfont.woff +0 -0
- package/src/assets/iconfont/iconfont.woff2 +0 -0
- package/src/components/CanvasArea.vue +218 -193
- package/src/components/ChartTypeSelector.vue +509 -148
- package/src/components/Header.vue +327 -44
- package/src/components/PresentationGroupChild.vue +44 -13
- package/src/components/PresentationMode.vue +84 -33
- package/src/components/QuickBorderPopover.vue +51 -11
- package/src/components/QuickColorPopover.vue +65 -21
- package/src/components/SidebarLeft.vue +286 -107
- package/src/components/SidebarRight.vue +45 -38
- package/src/components/TemplateGallery.vue +1110 -1237
- package/src/components/ToastNotification.vue +2 -2
- package/src/components/Toolbar.vue +825 -733
- package/src/components/canvas/CanvasQuickToolbar.vue +17 -30
- package/src/components/canvas/elements/CanvasGroupElement.vue +6 -0
- package/src/components/canvas/elements/CanvasShapeElement.vue +198 -38
- package/src/components/canvas/elements/CanvasTextElement.vue +4 -3
- package/src/components/sidebar/common/SidebarAlignGroup.vue +104 -50
- package/src/components/sidebar/common/SidebarBorderAccordion.vue +375 -148
- package/src/components/sidebar/common/SidebarPositionGroup.vue +358 -149
- package/src/components/sidebar/common/SidebarReflectionAccordion.vue +429 -203
- package/src/components/sidebar/common/SidebarShadowAccordion.vue +844 -416
- package/src/components/sidebar/panels/GradientEditor.vue +671 -316
- package/src/components/sidebar/panels/LayoutThumbSvg.vue +33 -16
- package/src/components/sidebar/panels/SidebarAnimationPanel.vue +701 -138
- package/src/components/sidebar/panels/SidebarChartFormatPanel.vue +3 -3
- package/src/components/sidebar/panels/SidebarDesignPanel.vue +1754 -416
- package/src/components/sidebar/panels/SidebarMediaFormatPanel.vue +12 -0
- package/src/components/sidebar/panels/SidebarShapeFormatPanel.vue +813 -174
- package/src/components/sidebar/panels/SidebarTableFormatPanel.vue +2 -2
- package/src/components/sidebar/panels/SidebarTextFormatPanel.vue +1938 -1427
- package/src/components/sidebar/panels/SidebarTransitionPanel.vue +791 -210
- package/src/composables/canvas/useCanvasShortcuts.ts +20 -6
- package/src/composables/canvas/useCanvasText.ts +1 -1
- package/src/composables/canvas/useCanvasTransform.ts +44 -0
- package/src/composables/presetThemes.ts +43 -44
- package/src/composables/sidebar/useSidebarAnimation.ts +101 -25
- package/src/composables/sidebar/useSidebarDesign.ts +30 -11
- package/src/composables/sidebar/useSidebarElementTransform.ts +10 -1
- package/src/composables/sidebar/useSidebarImage.ts +10 -2
- package/src/composables/sidebar/useSidebarShapeFormat.ts +562 -107
- package/src/composables/useSlides.ts +331 -153
- package/src/main.ts +2 -0
- package/src/style.css +926 -359
- package/src/utils/canvas/elementStyles.ts +42 -1
|
@@ -468,7 +468,7 @@ function handleFpClick(el: any) {
|
|
|
468
468
|
|
|
469
469
|
<!-- Shape Selector (Only for shapes, single selection) -->
|
|
470
470
|
<template v-if="!((selectedElementIds || []).length > 1) && selectedElement.type === 'shape' && !isImagePlaceholderHelper(selectedElement)">
|
|
471
|
-
<el-popover v-model:visible="quickShapePopoverVisible" placement="bottom" :width="380" trigger="click"
|
|
471
|
+
<el-popover v-model:visible="quickShapePopoverVisible" placement="bottom" :offset="4" :width="380" trigger="click"
|
|
472
472
|
popper-class="shape-popover-popper" :show-arrow="false">
|
|
473
473
|
<template #reference>
|
|
474
474
|
<button class="quick-toolbar-btn shape-dropdown-btn" title="更换形状"
|
|
@@ -539,7 +539,7 @@ function handleFpClick(el: any) {
|
|
|
539
539
|
|
|
540
540
|
<!-- Line Selector (Only for lines) -->
|
|
541
541
|
<template v-if="selectedElement.type === 'line'">
|
|
542
|
-
<el-popover v-model:visible="quickLineTypePopoverVisible" placement="bottom" :width="240" trigger="click"
|
|
542
|
+
<el-popover v-model:visible="quickLineTypePopoverVisible" placement="bottom" :offset="4" :width="240" trigger="click"
|
|
543
543
|
popper-class="line-dropdown-popper" :show-arrow="false">
|
|
544
544
|
<template #reference>
|
|
545
545
|
<button class="quick-toolbar-btn shape-dropdown-btn" title="更换线条"
|
|
@@ -606,44 +606,31 @@ function handleFpClick(el: any) {
|
|
|
606
606
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'solid' }"
|
|
607
607
|
@click="emit('changeLineType', selectedElement, 'solid'); quickLineTypePopoverVisible = false"
|
|
608
608
|
title="实线">
|
|
609
|
-
<
|
|
610
|
-
<line x1="8" y1="32" x2="32" y2="8" />
|
|
611
|
-
</svg>
|
|
609
|
+
<img src="/jvs-ppt-ui/img/l.png" class="line-img" alt="实线" />
|
|
612
610
|
</div>
|
|
613
611
|
<div class="line-grid-item"
|
|
614
612
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'dashed' }"
|
|
615
613
|
@click="emit('changeLineType', selectedElement, 'dashed'); quickLineTypePopoverVisible = false"
|
|
616
614
|
title="虚线">
|
|
617
|
-
<
|
|
618
|
-
<line x1="8" y1="32" x2="32" y2="8" />
|
|
619
|
-
</svg>
|
|
615
|
+
<img src="/jvs-ppt-ui/img/d.png" class="line-img" alt="虚线" />
|
|
620
616
|
</div>
|
|
621
617
|
<div class="line-grid-item"
|
|
622
618
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'arrow' }"
|
|
623
619
|
@click="emit('changeLineType', selectedElement, 'arrow'); quickLineTypePopoverVisible = false"
|
|
624
620
|
title="单向箭头线">
|
|
625
|
-
<
|
|
626
|
-
<line x1="8" y1="32" x2="30" y2="10" />
|
|
627
|
-
<polygon points="30,10 22,12 28,18" fill="currentColor" class="line-polygon-head" />
|
|
628
|
-
</svg>
|
|
621
|
+
<img src="/jvs-ppt-ui/img/al.png" class="line-img" alt="实线单向箭头" />
|
|
629
622
|
</div>
|
|
630
623
|
<div class="line-grid-item"
|
|
631
624
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'dashed-arrow' }"
|
|
632
625
|
@click="emit('changeLineType', selectedElement, 'dashed-arrow'); quickLineTypePopoverVisible = false"
|
|
633
626
|
title="虚线单向箭头线">
|
|
634
|
-
<
|
|
635
|
-
<line x1="8" y1="32" x2="30" y2="10" class="line-thumb-svg dashed" />
|
|
636
|
-
<polygon points="30,10 22,12 28,18" fill="currentColor" class="line-polygon-head" />
|
|
637
|
-
</svg>
|
|
627
|
+
<img src="/jvs-ppt-ui/img/dl.png" class="line-img" alt="虚线单向箭头" />
|
|
638
628
|
</div>
|
|
639
629
|
<div class="line-grid-item"
|
|
640
630
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'dot' }"
|
|
641
631
|
@click="emit('changeLineType', selectedElement, 'dot'); quickLineTypePopoverVisible = false"
|
|
642
|
-
title="
|
|
643
|
-
<
|
|
644
|
-
<line x1="8" y1="32" x2="28" y2="12" />
|
|
645
|
-
<circle cx="30" cy="10" r="3.2" fill="currentColor" class="line-polygon-head" />
|
|
646
|
-
</svg>
|
|
632
|
+
title="直线">
|
|
633
|
+
<img src="/jvs-ppt-ui/img/l.png" class="line-img" alt="直线" />
|
|
647
634
|
</div>
|
|
648
635
|
</div>
|
|
649
636
|
|
|
@@ -653,7 +640,7 @@ function handleFpClick(el: any) {
|
|
|
653
640
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'elbow' }"
|
|
654
641
|
@click="emit('changeLineType', selectedElement, 'elbow'); quickLineTypePopoverVisible = false"
|
|
655
642
|
title="直角折线连接线">
|
|
656
|
-
<svg viewBox="0 0 40 40" width="
|
|
643
|
+
<svg viewBox="0 0 40 40" width="16" height="16" class="line-thumb-svg fill-none">
|
|
657
644
|
<path d="M10 10 v20 h20" />
|
|
658
645
|
<polygon points="30,30 24,27 24,33" fill="currentColor" class="line-polygon-head" />
|
|
659
646
|
</svg>
|
|
@@ -662,7 +649,7 @@ function handleFpClick(el: any) {
|
|
|
662
649
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'double-elbow' }"
|
|
663
650
|
@click="emit('changeLineType', selectedElement, 'double-elbow'); quickLineTypePopoverVisible = false"
|
|
664
651
|
title="双折折线连接线">
|
|
665
|
-
<svg viewBox="0 0 40 40" width="
|
|
652
|
+
<svg viewBox="0 0 40 40" width="16" height="16" class="line-thumb-svg fill-none">
|
|
666
653
|
<path d="M10 10 h10 v20 h10" />
|
|
667
654
|
<polygon points="30,30 24,27 24,33" fill="currentColor" class="line-polygon-head" />
|
|
668
655
|
</svg>
|
|
@@ -671,7 +658,7 @@ function handleFpClick(el: any) {
|
|
|
671
658
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'curve' }"
|
|
672
659
|
@click="emit('changeLineType', selectedElement, 'curve'); quickLineTypePopoverVisible = false"
|
|
673
660
|
title="圆弧曲线连接线">
|
|
674
|
-
<svg viewBox="0 0 40 40" width="
|
|
661
|
+
<svg viewBox="0 0 40 40" width="16" height="16" class="line-thumb-svg fill-none">
|
|
675
662
|
<path d="M10 10 Q30 10 30 30" />
|
|
676
663
|
<polygon points="30,30 27,24 33,24" fill="currentColor" class="line-polygon-head" />
|
|
677
664
|
</svg>
|
|
@@ -680,7 +667,7 @@ function handleFpClick(el: any) {
|
|
|
680
667
|
:class="{ active: getSelectedLineTypeHelper(selectedElement) === 'wavy' }"
|
|
681
668
|
@click="emit('changeLineType', selectedElement, 'wavy'); quickLineTypePopoverVisible = false"
|
|
682
669
|
title="波浪曲线连接线">
|
|
683
|
-
<svg viewBox="0 0 40 40" width="
|
|
670
|
+
<svg viewBox="0 0 40 40" width="16" height="16" class="line-thumb-svg fill-none">
|
|
684
671
|
<path d="M10 10 C20 10 20 30 30 30" />
|
|
685
672
|
<polygon points="30,30 24,27 24,33" fill="currentColor" class="line-polygon-head" />
|
|
686
673
|
</svg>
|
|
@@ -754,7 +741,7 @@ function handleFpClick(el: any) {
|
|
|
754
741
|
<!-- Multiple Elements Alignment & Grouping (When multiple elements are selected) -->
|
|
755
742
|
<template v-if="(selectedElementIds || []).length > 1">
|
|
756
743
|
<!-- Alignment Popover -->
|
|
757
|
-
<el-popover v-model:visible="quickMultiAlignPopoverVisible" placement="top" :width="168" trigger="click"
|
|
744
|
+
<el-popover v-model:visible="quickMultiAlignPopoverVisible" placement="top" :offset="4" :width="168" trigger="click"
|
|
758
745
|
popper-class="quick-multi-align-popover" :show-arrow="false">
|
|
759
746
|
<template #reference>
|
|
760
747
|
<button class="quick-toolbar-btn" :class="{ 'panel-active': quickMultiAlignPopoverVisible }" title="对齐排版">
|
|
@@ -887,7 +874,7 @@ function handleFpClick(el: any) {
|
|
|
887
874
|
</el-select>
|
|
888
875
|
|
|
889
876
|
<!-- Text Align / Font Style Popover -->
|
|
890
|
-
<el-popover v-model:visible="quickAlignPopoverVisible" placement="bottom" :width="260" trigger="click"
|
|
877
|
+
<el-popover v-model:visible="quickAlignPopoverVisible" placement="bottom" :offset="4" :width="260" trigger="click"
|
|
891
878
|
popper-class="quick-align-popover" :show-arrow="false">
|
|
892
879
|
<template #reference>
|
|
893
880
|
<button class="quick-toolbar-btn" title="对齐与样式"
|
|
@@ -1021,7 +1008,7 @@ function handleFpClick(el: any) {
|
|
|
1021
1008
|
</el-popover>
|
|
1022
1009
|
|
|
1023
1010
|
<!-- Unordered List Quick Button & Popover -->
|
|
1024
|
-
<el-popover v-model:visible="isQuickUlVisible" placement="bottom" :width="250" trigger="click"
|
|
1011
|
+
<el-popover v-model:visible="isQuickUlVisible" placement="bottom" :offset="4" :width="250" trigger="click"
|
|
1025
1012
|
popper-class="list-popover-panel" :show-arrow="false">
|
|
1026
1013
|
<template #reference>
|
|
1027
1014
|
<button class="quick-toolbar-btn"
|
|
@@ -1086,7 +1073,7 @@ function handleFpClick(el: any) {
|
|
|
1086
1073
|
</el-popover>
|
|
1087
1074
|
|
|
1088
1075
|
<!-- Ordered List Quick Button & Popover -->
|
|
1089
|
-
<el-popover v-model:visible="isQuickOlVisible" placement="bottom" :width="250" trigger="click"
|
|
1076
|
+
<el-popover v-model:visible="isQuickOlVisible" placement="bottom" :offset="4" :width="250" trigger="click"
|
|
1090
1077
|
popper-class="list-popover-panel" :show-arrow="false">
|
|
1091
1078
|
<template #reference>
|
|
1092
1079
|
<button class="quick-toolbar-btn"
|
|
@@ -1167,7 +1154,7 @@ function handleFpClick(el: any) {
|
|
|
1167
1154
|
</button>
|
|
1168
1155
|
|
|
1169
1156
|
<!-- Z-Index Layer Control -->
|
|
1170
|
-
<el-popover v-model:visible="quickZIndexPopoverVisible" placement="top" :width="140" trigger="click"
|
|
1157
|
+
<el-popover v-model:visible="quickZIndexPopoverVisible" placement="top" :offset="4" :width="140" trigger="click"
|
|
1171
1158
|
popper-class="quick-z-index-popover" :show-arrow="false">
|
|
1172
1159
|
<template #reference>
|
|
1173
1160
|
<button class="quick-toolbar-btn" :class="{ 'panel-active': quickZIndexPopoverVisible }" title="层级">
|
|
@@ -63,6 +63,8 @@ const emit = defineEmits<{
|
|
|
63
63
|
(e: 'textBlur', ev: FocusEvent, child: any): void
|
|
64
64
|
(e: 'textInput', ev: Event, child: any): void
|
|
65
65
|
(e: 'textKeyDown', ev: KeyboardEvent, child: any): void
|
|
66
|
+
(e: 'textMouseMove', ev: MouseEvent, child: any): void
|
|
67
|
+
(e: 'textMouseLeave', ev: MouseEvent, child: any): void
|
|
66
68
|
(e: 'startEditing', id: string, ev?: MouseEvent): void
|
|
67
69
|
(e: 'formulaDblClick', child: any): void
|
|
68
70
|
(e: 'tableDblClick', ev: MouseEvent, child: any): void
|
|
@@ -118,6 +120,8 @@ function sortGroupElements(elements: any[]) {
|
|
|
118
120
|
@focusout="emit('textBlur', $event, child)"
|
|
119
121
|
@input="emit('textInput', $event, child)"
|
|
120
122
|
@keydown="emit('textKeyDown', $event, child)"
|
|
123
|
+
@mousemove="emit('textMouseMove', $event, child)"
|
|
124
|
+
@mouseleave="emit('textMouseLeave', $event, child)"
|
|
121
125
|
@dblclick="emit('startEditing', child.id)"
|
|
122
126
|
@formula-dbl-click="emit('formulaDblClick', child)"
|
|
123
127
|
@table-dbl-click="emit('tableDblClick', $event, child)"
|
|
@@ -193,6 +197,8 @@ function sortGroupElements(elements: any[]) {
|
|
|
193
197
|
@text-blur="(ev, c) => emit('textBlur', ev, c)"
|
|
194
198
|
@text-input="(ev, c) => emit('textInput', ev, c)"
|
|
195
199
|
@text-key-down="(ev, c) => emit('textKeyDown', ev, c)"
|
|
200
|
+
@text-mouse-move="(ev, c) => emit('textMouseMove', ev, c)"
|
|
201
|
+
@text-mouse-leave="(ev, c) => emit('textMouseLeave', ev, c)"
|
|
196
202
|
@start-editing="(id, ev) => emit('startEditing', id, ev)"
|
|
197
203
|
/>
|
|
198
204
|
</template>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { computed, ref, watch, onBeforeUnmount, nextTick } from 'vue'
|
|
3
3
|
import {
|
|
4
4
|
getElementPattern,
|
|
5
|
+
isElementPatternTile,
|
|
6
|
+
getElementPatternTileSize,
|
|
5
7
|
getElementGradientConfig,
|
|
6
8
|
getElementGradientCss,
|
|
7
9
|
getSvgGradientCoords,
|
|
@@ -24,7 +26,8 @@ import { createTextSelectionOverlay, type TextSelectionOverlayHandle } from '../
|
|
|
24
26
|
|
|
25
27
|
const { shapeFormatPainter, isReadonly } = useSlides()
|
|
26
28
|
const isTextPaintActive = computed(() => !!(shapeFormatPainter.value && shapeFormatPainter.value.mode === 'text-range'))
|
|
27
|
-
const
|
|
29
|
+
const svgIdKey = computed(() => props.isReflection ? `${props.element.id}-refl` : `${props.element.id}`)
|
|
30
|
+
const isTextSelectable = computed(() => !props.isReflection && ((props.isEditingText && props.selectedElementId === props.element.id) || isTextPaintActive.value))
|
|
28
31
|
|
|
29
32
|
function getEffectiveBorderWidth(el: any): number {
|
|
30
33
|
if (props.isImagePlaceholder && props.isImagePlaceholder(el) && el.style?.enableBorder !== true) return 0
|
|
@@ -35,6 +38,23 @@ function getEffectiveBorderWidth(el: any): number {
|
|
|
35
38
|
return 0
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
function getShapePatternTransform(el: any, isTriangle = false): string | undefined {
|
|
42
|
+
if (!el || !isElementPatternTile(el)) return undefined
|
|
43
|
+
const { width, height } = getElementWidthHeight(el)
|
|
44
|
+
if (isTriangle) {
|
|
45
|
+
const sx = width > 0 ? 100 / width : 1
|
|
46
|
+
const sy = height > 0 ? 100 / height : 1
|
|
47
|
+
return `scale(${sx}, ${sy})`
|
|
48
|
+
}
|
|
49
|
+
const vbW = el.viewBox ? el.viewBox[0] : (width || 200)
|
|
50
|
+
const vbH = el.viewBox ? el.viewBox[1] : (height || 200)
|
|
51
|
+
const hasBorder = hasElementBorder(el)
|
|
52
|
+
const bw = hasBorder ? getEffectiveBorderWidth(el) : 0
|
|
53
|
+
const effW = bw > 0 ? Math.max(1, width - bw) : Math.max(1, width)
|
|
54
|
+
const effH = bw > 0 ? Math.max(1, height - bw) : Math.max(1, height)
|
|
55
|
+
return `scale(${vbW / effW}, ${vbH / effH})`
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
function getShapeSvgTransform(el: any): string | undefined {
|
|
39
59
|
if (!el) return undefined
|
|
40
60
|
const { width, height } = getElementWidthHeight(el)
|
|
@@ -65,7 +85,7 @@ function getShapeSvgTransform(el: any): string | undefined {
|
|
|
65
85
|
function getEffectiveBorderColor(el: any, fallback = '#10b981'): string {
|
|
66
86
|
if (props.isImagePlaceholder && props.isImagePlaceholder(el) && el.style?.enableBorder !== true) return 'transparent'
|
|
67
87
|
if (el.style?.enableBorder === false) return 'transparent'
|
|
68
|
-
if (hasElementBorderGradient(el)) return `url(#shape-border-gradient-${
|
|
88
|
+
if (hasElementBorderGradient(el)) return `url(#shape-border-gradient-${svgIdKey.value})`
|
|
69
89
|
return el.style?.borderColor || getElementBorderColor(el) || fallback
|
|
70
90
|
}
|
|
71
91
|
|
|
@@ -75,6 +95,75 @@ function isOpenLineShape(el: any): boolean {
|
|
|
75
95
|
return shapType === 'arc' || shapType === 'straightConnector1' || shapType === 'line' || (typeof el.width === 'number' && el.width <= 0) || (typeof el.height === 'number' && el.height <= 0)
|
|
76
96
|
}
|
|
77
97
|
|
|
98
|
+
function getShapeVb(el: any): { w: number; h: number } {
|
|
99
|
+
if (!el) return { w: 200, h: 200 }
|
|
100
|
+
const { width, height } = getElementWidthHeight(el)
|
|
101
|
+
const w = el.viewBox ? el.viewBox[0] : (width || 200)
|
|
102
|
+
const h = el.viewBox ? el.viewBox[1] : (height || 200)
|
|
103
|
+
return { w, h }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isRectShape(el: any): boolean {
|
|
107
|
+
if (!el) return false
|
|
108
|
+
if (el.shapType === 'rect' || el.shapType === 'roundRect') return true
|
|
109
|
+
if (el.content === 'rect') return true
|
|
110
|
+
if (el.pathFormula === 'roundRect') return true
|
|
111
|
+
if (el.title === '矩形' || el.title === '圆角矩形') return true
|
|
112
|
+
const raw = (el.path || el.content || '').trim().replace(/\s+/g, '').toUpperCase()
|
|
113
|
+
if (raw === 'M00L2000L200200L0200Z' || raw === 'M00H200V200H0Z') return true
|
|
114
|
+
if (raw.startsWith('M500L1500Q200020050L200150Q200200150200')) return true
|
|
115
|
+
if (/^M00L([0-9.]+)0L\1([0-9.]+)L0\2Z$/i.test(raw)) return true
|
|
116
|
+
if (/^M00H([0-9.]+)V([0-9.]+)H0Z$/i.test(raw)) return true
|
|
117
|
+
if ((el.style?.borderRadius && parseFloat(String(el.style.borderRadius)) > 0) || (el.radius && parseFloat(String(el.radius)) > 0)) {
|
|
118
|
+
if (raw.includes('L2000L200200L0200') || (raw.startsWith('M00L') && raw.endsWith('Z'))) return true
|
|
119
|
+
}
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function getRectRadiusInVb(el: any): { rx: number; ry: number } {
|
|
124
|
+
if (!el) return { rx: 0, ry: 0 }
|
|
125
|
+
const { width, height } = getElementWidthHeight(el)
|
|
126
|
+
let r = 0
|
|
127
|
+
const isRoundRect = el.pathFormula === 'roundRect' || el.shapType === 'roundRect' || el.title === '圆角矩形'
|
|
128
|
+
const rVal = el.style?.borderRadius !== undefined && el.style?.borderRadius !== null && el.style?.borderRadius !== ''
|
|
129
|
+
? el.style.borderRadius
|
|
130
|
+
: el.radius
|
|
131
|
+
|
|
132
|
+
if (isRoundRect && Array.isArray(el.keypoints) && el.keypoints[0] !== undefined && el.keypoints[0] !== null) {
|
|
133
|
+
const kp = Number(el.keypoints[0])
|
|
134
|
+
if (!isNaN(kp)) {
|
|
135
|
+
r = Math.min(width, height) * Math.max(0, Math.min(0.5, kp))
|
|
136
|
+
}
|
|
137
|
+
} else if (isRoundRect && el.keypoints && typeof el.keypoints === 'object' && !Array.isArray(el.keypoints) && (el.keypoints as any).adj !== undefined) {
|
|
138
|
+
const adj = Number((el.keypoints as any).adj)
|
|
139
|
+
if (!isNaN(adj)) {
|
|
140
|
+
r = Math.min(width, height) * Math.max(0, Math.min(0.5, adj * 0.5))
|
|
141
|
+
}
|
|
142
|
+
} else if (rVal !== undefined && rVal !== null && rVal !== '') {
|
|
143
|
+
const parsed = parseFloat(String(rVal))
|
|
144
|
+
if (!isNaN(parsed)) r = parsed
|
|
145
|
+
} else if (isRoundRect) {
|
|
146
|
+
r = Math.min(width, height) * 0.125
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (r <= 0) return { rx: 0, ry: 0 }
|
|
150
|
+
|
|
151
|
+
const { w: vbW, h: vbH } = getShapeVb(el)
|
|
152
|
+
|
|
153
|
+
const maxR = Math.min(width, height) / 2
|
|
154
|
+
const clampedR = Math.min(r, maxR)
|
|
155
|
+
|
|
156
|
+
const hasBorder = hasElementBorder(el)
|
|
157
|
+
const bw = hasBorder ? getEffectiveBorderWidth(el) : 0
|
|
158
|
+
const effW = bw > 0 ? Math.max(1, width - bw) : width
|
|
159
|
+
const effH = bw > 0 ? Math.max(1, height - bw) : height
|
|
160
|
+
|
|
161
|
+
const rx = (clampedR * vbW) / effW
|
|
162
|
+
const ry = (clampedR * vbH) / effH
|
|
163
|
+
|
|
164
|
+
return { rx, ry }
|
|
165
|
+
}
|
|
166
|
+
|
|
78
167
|
const props = defineProps<{
|
|
79
168
|
element: any
|
|
80
169
|
activeSlide?: any
|
|
@@ -87,6 +176,7 @@ const props = defineProps<{
|
|
|
87
176
|
getElementTextShadow?: (el: any) => string
|
|
88
177
|
getReflectionLeadingCompensation?: (el: any) => number
|
|
89
178
|
isImagePlaceholder?: (el: any) => boolean
|
|
179
|
+
isReflection?: boolean
|
|
90
180
|
// 直接父盒子(组合)的像素尺寸,用于把 % 样式的宽高解析成 px。
|
|
91
181
|
// 由 CanvasGroupElement 传入;顶层元素不传,走 px 样式分支。
|
|
92
182
|
parentWidthPx?: number
|
|
@@ -239,15 +329,29 @@ function getRawText(el: any): string {
|
|
|
239
329
|
return val
|
|
240
330
|
}
|
|
241
331
|
|
|
332
|
+
function getImagePlaceholderFill(el: any): string {
|
|
333
|
+
const fill = getElementFill(el)
|
|
334
|
+
if (!fill || fill === '#f1f5f9' || fill === '#f8fafc') {
|
|
335
|
+
return '#d9dde3'
|
|
336
|
+
}
|
|
337
|
+
return fill
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function getImagePlaceholderRadius(el: any): string {
|
|
341
|
+
const raw = el.style?.borderRadius !== undefined
|
|
342
|
+
? (typeof el.style.borderRadius === 'number' ? `${el.style.borderRadius}px` : el.style.borderRadius)
|
|
343
|
+
: (el.radius ? `${el.radius}px` : '0px')
|
|
344
|
+
if (!raw || raw === '0px' || raw === '4px') {
|
|
345
|
+
return '12px'
|
|
346
|
+
}
|
|
347
|
+
return raw
|
|
348
|
+
}
|
|
349
|
+
|
|
242
350
|
function formatShapeHtml(el: any): string {
|
|
243
|
-
let raw = getRawText(el)
|
|
244
351
|
if (props.isImagePlaceholder && props.isImagePlaceholder(el)) {
|
|
245
|
-
|
|
246
|
-
if (!stripped) {
|
|
247
|
-
const prompt = el.placeholder?.prompt || el.name || '图片占位符'
|
|
248
|
-
raw = `<div>${prompt}</div>`
|
|
249
|
-
}
|
|
352
|
+
return ''
|
|
250
353
|
}
|
|
354
|
+
const raw = getRawText(el)
|
|
251
355
|
const norm = props.normalizeHtmlFontFamily ? props.normalizeHtmlFontFamily(raw) : raw
|
|
252
356
|
if (el.style?.textBackground && el.style.textBackground !== 'transparent') {
|
|
253
357
|
if (!norm.includes('background-color')) {
|
|
@@ -272,9 +376,9 @@ function formatShapeHtml(el: any): string {
|
|
|
272
376
|
height: '100%',
|
|
273
377
|
backgroundColor: getElementPattern(element) ? 'transparent' : ((getElementGradientCss(element) || (getElementFill(element) !== undefined && getElementFill(element) !== 'none')) ? (getElementGradientCss(element) ? 'transparent' : getElementFill(element)) : (getElementFill(element) === 'none' ? 'transparent' : '#3b82f6')),
|
|
274
378
|
backgroundImage: getElementPattern(element) ? `url('${getElementPattern(element)}')` : (getElementGradientCss(element) || 'none'),
|
|
275
|
-
backgroundSize: getElementPattern(element) ? 'cover' : undefined,
|
|
276
|
-
backgroundPosition: getElementPattern(element) ? 'center center' : undefined,
|
|
277
|
-
backgroundRepeat: getElementPattern(element) ? 'no-repeat' : undefined,
|
|
379
|
+
backgroundSize: getElementPattern(element) ? (isElementPatternTile(element) ? `${getElementPatternTileSize(element).w}px ${getElementPatternTileSize(element).h}px` : 'cover') : undefined,
|
|
380
|
+
backgroundPosition: getElementPattern(element) ? (isElementPatternTile(element) ? '0 0' : 'center center') : undefined,
|
|
381
|
+
backgroundRepeat: getElementPattern(element) ? (isElementPatternTile(element) ? 'repeat' : 'no-repeat') : undefined,
|
|
278
382
|
borderRadius: '50%',
|
|
279
383
|
borderWidth: (isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true)
|
|
280
384
|
? '0px'
|
|
@@ -302,7 +406,7 @@ function formatShapeHtml(el: any): string {
|
|
|
302
406
|
<defs v-if="getElementBorderGradientConfig(element)">
|
|
303
407
|
<radialGradient
|
|
304
408
|
v-if="getElementBorderGradientConfig(element)!.path && getElementBorderGradientConfig(element)!.path !== 'line'"
|
|
305
|
-
:id="`shape-border-gradient-${
|
|
409
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
306
410
|
:cx="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
307
411
|
:cy="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
308
412
|
:r="getElementBorderGradientConfig(element)!.path === 'rect' ? '60%' : (getElementBorderGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -319,7 +423,7 @@ function formatShapeHtml(el: any): string {
|
|
|
319
423
|
</radialGradient>
|
|
320
424
|
<linearGradient
|
|
321
425
|
v-else
|
|
322
|
-
:id="`shape-border-gradient-${
|
|
426
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
323
427
|
:x1="getSvgGradientCoords(getElementBorderGradientConfig(element)).x1"
|
|
324
428
|
:y1="getSvgGradientCoords(getElementBorderGradientConfig(element)).y1"
|
|
325
429
|
:x2="getSvgGradientCoords(getElementBorderGradientConfig(element)).x2"
|
|
@@ -357,13 +461,26 @@ function formatShapeHtml(el: any): string {
|
|
|
357
461
|
:style="{ filter: (element.shadow && element.shadow.type === 'inner') ? `url(#shape-inner-shadow-${element.id})` : '' }"
|
|
358
462
|
>
|
|
359
463
|
<defs>
|
|
360
|
-
<pattern
|
|
361
|
-
|
|
464
|
+
<pattern
|
|
465
|
+
v-if="getElementPattern(element)"
|
|
466
|
+
:id="`shape-pattern-${svgIdKey}`"
|
|
467
|
+
:width="isElementPatternTile(element) ? getElementPatternTileSize(element).w : '100%'"
|
|
468
|
+
:height="isElementPatternTile(element) ? getElementPatternTileSize(element).h : '100%'"
|
|
469
|
+
:patternUnits="isElementPatternTile(element) ? 'userSpaceOnUse' : 'objectBoundingBox'"
|
|
470
|
+
:patternContentUnits="isElementPatternTile(element) ? 'userSpaceOnUse' : 'objectBoundingBox'"
|
|
471
|
+
:patternTransform="getShapePatternTransform(element, true)"
|
|
472
|
+
>
|
|
473
|
+
<image
|
|
474
|
+
:href="getElementPattern(element)"
|
|
475
|
+
:width="isElementPatternTile(element) ? getElementPatternTileSize(element).w : 1"
|
|
476
|
+
:height="isElementPatternTile(element) ? getElementPatternTileSize(element).h : 1"
|
|
477
|
+
preserveAspectRatio="none"
|
|
478
|
+
/>
|
|
362
479
|
</pattern>
|
|
363
480
|
<template v-if="getElementGradientConfig(element)">
|
|
364
481
|
<radialGradient
|
|
365
482
|
v-if="getElementGradientConfig(element)!.path && getElementGradientConfig(element)!.path !== 'line'"
|
|
366
|
-
:id="`shape-gradient-${
|
|
483
|
+
:id="`shape-gradient-${svgIdKey}`"
|
|
367
484
|
:cx="`${getElementGradientConfig(element)!.center ? Math.round(getElementGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
368
485
|
:cy="`${getElementGradientConfig(element)!.center ? Math.round(getElementGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
369
486
|
:r="getElementGradientConfig(element)!.path === 'rect' ? '60%' : (getElementGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -380,7 +497,7 @@ function formatShapeHtml(el: any): string {
|
|
|
380
497
|
</radialGradient>
|
|
381
498
|
<linearGradient
|
|
382
499
|
v-else
|
|
383
|
-
:id="`shape-gradient-${
|
|
500
|
+
:id="`shape-gradient-${svgIdKey}`"
|
|
384
501
|
:x1="getSvgGradientCoords(element).x1"
|
|
385
502
|
:y1="getSvgGradientCoords(element).y1"
|
|
386
503
|
:x2="getSvgGradientCoords(element).x2"
|
|
@@ -398,7 +515,7 @@ function formatShapeHtml(el: any): string {
|
|
|
398
515
|
<template v-if="getElementBorderGradientConfig(element)">
|
|
399
516
|
<radialGradient
|
|
400
517
|
v-if="getElementBorderGradientConfig(element)!.path && getElementBorderGradientConfig(element)!.path !== 'line'"
|
|
401
|
-
:id="`shape-border-gradient-${
|
|
518
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
402
519
|
:cx="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
403
520
|
:cy="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
404
521
|
:r="getElementBorderGradientConfig(element)!.path === 'rect' ? '60%' : (getElementBorderGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -415,7 +532,7 @@ function formatShapeHtml(el: any): string {
|
|
|
415
532
|
</radialGradient>
|
|
416
533
|
<linearGradient
|
|
417
534
|
v-else
|
|
418
|
-
:id="`shape-border-gradient-${
|
|
535
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
419
536
|
:x1="getSvgGradientCoords(getElementBorderGradientConfig(element)).x1"
|
|
420
537
|
:y1="getSvgGradientCoords(getElementBorderGradientConfig(element)).y1"
|
|
421
538
|
:x2="getSvgGradientCoords(getElementBorderGradientConfig(element)).x2"
|
|
@@ -433,7 +550,7 @@ function formatShapeHtml(el: any): string {
|
|
|
433
550
|
</defs>
|
|
434
551
|
<polygon
|
|
435
552
|
points="50,0 0,100 100,100"
|
|
436
|
-
:fill="hasElementFill(element) ? (getElementPattern(element) ? `url(#shape-pattern-${
|
|
553
|
+
:fill="hasElementFill(element) ? (getElementPattern(element) ? `url(#shape-pattern-${svgIdKey})` : (getElementGradientConfig(element) ? `url(#shape-gradient-${svgIdKey})` : (element.style?.fill !== undefined ? element.style.fill : '#f59e0b'))) : 'none'"
|
|
437
554
|
:stroke="getEffectiveBorderColor(element, '#d97706')"
|
|
438
555
|
:stroke-width="getEffectiveBorderWidth(element)"
|
|
439
556
|
:stroke-dasharray="element.style?.borderStyle === 'dashed' ? '5 5' : ''"
|
|
@@ -452,13 +569,26 @@ function formatShapeHtml(el: any): string {
|
|
|
452
569
|
:style="{ filter: (element.shadow && element.shadow.type === 'inner') ? `url(#shape-inner-shadow-${element.id})` : '' }"
|
|
453
570
|
>
|
|
454
571
|
<defs>
|
|
455
|
-
<pattern
|
|
456
|
-
|
|
572
|
+
<pattern
|
|
573
|
+
v-if="getElementPattern(element)"
|
|
574
|
+
:id="`shape-pattern-${svgIdKey}`"
|
|
575
|
+
:width="isElementPatternTile(element) ? getElementPatternTileSize(element).w : '100%'"
|
|
576
|
+
:height="isElementPatternTile(element) ? getElementPatternTileSize(element).h : '100%'"
|
|
577
|
+
:patternUnits="isElementPatternTile(element) ? 'userSpaceOnUse' : 'objectBoundingBox'"
|
|
578
|
+
:patternContentUnits="isElementPatternTile(element) ? 'userSpaceOnUse' : 'objectBoundingBox'"
|
|
579
|
+
:patternTransform="getShapePatternTransform(element, false)"
|
|
580
|
+
>
|
|
581
|
+
<image
|
|
582
|
+
:href="getElementPattern(element)"
|
|
583
|
+
:width="isElementPatternTile(element) ? getElementPatternTileSize(element).w : 1"
|
|
584
|
+
:height="isElementPatternTile(element) ? getElementPatternTileSize(element).h : 1"
|
|
585
|
+
preserveAspectRatio="none"
|
|
586
|
+
/>
|
|
457
587
|
</pattern>
|
|
458
588
|
<template v-if="getElementGradientConfig(element)">
|
|
459
589
|
<radialGradient
|
|
460
590
|
v-if="getElementGradientConfig(element)!.path && getElementGradientConfig(element)!.path !== 'line'"
|
|
461
|
-
:id="`shape-gradient-${
|
|
591
|
+
:id="`shape-gradient-${svgIdKey}`"
|
|
462
592
|
:cx="`${getElementGradientConfig(element)!.center ? Math.round(getElementGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
463
593
|
:cy="`${getElementGradientConfig(element)!.center ? Math.round(getElementGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
464
594
|
:r="getElementGradientConfig(element)!.path === 'rect' ? '60%' : (getElementGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -475,7 +605,7 @@ function formatShapeHtml(el: any): string {
|
|
|
475
605
|
</radialGradient>
|
|
476
606
|
<linearGradient
|
|
477
607
|
v-else
|
|
478
|
-
:id="`shape-gradient-${
|
|
608
|
+
:id="`shape-gradient-${svgIdKey}`"
|
|
479
609
|
:x1="getSvgGradientCoords(element).x1"
|
|
480
610
|
:y1="getSvgGradientCoords(element).y1"
|
|
481
611
|
:x2="getSvgGradientCoords(element).x2"
|
|
@@ -493,7 +623,7 @@ function formatShapeHtml(el: any): string {
|
|
|
493
623
|
<template v-if="getElementBorderGradientConfig(element)">
|
|
494
624
|
<radialGradient
|
|
495
625
|
v-if="getElementBorderGradientConfig(element)!.path && getElementBorderGradientConfig(element)!.path !== 'line'"
|
|
496
|
-
:id="`shape-border-gradient-${
|
|
626
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
497
627
|
:cx="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
498
628
|
:cy="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
499
629
|
:r="getElementBorderGradientConfig(element)!.path === 'rect' ? '60%' : (getElementBorderGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -510,7 +640,7 @@ function formatShapeHtml(el: any): string {
|
|
|
510
640
|
</radialGradient>
|
|
511
641
|
<linearGradient
|
|
512
642
|
v-else
|
|
513
|
-
:id="`shape-border-gradient-${
|
|
643
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
514
644
|
:x1="getSvgGradientCoords(getElementBorderGradientConfig(element)).x1"
|
|
515
645
|
:y1="getSvgGradientCoords(getElementBorderGradientConfig(element)).y1"
|
|
516
646
|
:x2="getSvgGradientCoords(getElementBorderGradientConfig(element)).x2"
|
|
@@ -529,10 +659,26 @@ function formatShapeHtml(el: any): string {
|
|
|
529
659
|
<g
|
|
530
660
|
:transform="getShapeSvgTransform(element)"
|
|
531
661
|
>
|
|
662
|
+
<rect
|
|
663
|
+
v-if="isRectShape(element)"
|
|
664
|
+
x="0"
|
|
665
|
+
y="0"
|
|
666
|
+
:width="getShapeVb(element).w"
|
|
667
|
+
:height="getShapeVb(element).h"
|
|
668
|
+
:rx="getRectRadiusInVb(element).rx"
|
|
669
|
+
:ry="getRectRadiusInVb(element).ry"
|
|
670
|
+
vector-effect="non-scaling-stroke"
|
|
671
|
+
:fill="hasElementFill(element) ? (getElementPattern(element) ? `url(#shape-pattern-${svgIdKey})` : (getElementGradientConfig(element) ? `url(#shape-gradient-${svgIdKey})` : (getElementFill(element) !== undefined ? getElementFill(element) : '#3b82f6'))) : 'none'"
|
|
672
|
+
:stroke="(isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true) ? 'none' : (element.style?.enableBorder === false ? 'none' : getEffectiveBorderColor(element, 'none'))"
|
|
673
|
+
:stroke-width="(isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true) ? 0 : (element.style?.enableBorder === false ? 0 : getElementBorderWidth(element))"
|
|
674
|
+
:stroke-linecap="element.style?.strokeLinecap || element.borderLineCap || element.lineCap || (element.shapType === 'arc' ? 'round' : (isOpenLineShape(element) ? 'butt' : undefined))"
|
|
675
|
+
:stroke-dasharray="element.style?.borderStyle === 'dashed' || element.borderType === 'dashed' ? '5 5' : ''"
|
|
676
|
+
/>
|
|
532
677
|
<path
|
|
678
|
+
v-else
|
|
533
679
|
vector-effect="non-scaling-stroke"
|
|
534
680
|
:d="element.path || element.content"
|
|
535
|
-
:fill="hasElementFill(element) ? (getElementPattern(element) ? `url(#shape-pattern-${
|
|
681
|
+
:fill="hasElementFill(element) ? (getElementPattern(element) ? `url(#shape-pattern-${svgIdKey})` : (getElementGradientConfig(element) ? `url(#shape-gradient-${svgIdKey})` : (getElementFill(element) !== undefined ? getElementFill(element) : '#3b82f6'))) : 'none'"
|
|
536
682
|
:stroke="(isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true) ? 'none' : (element.style?.enableBorder === false ? 'none' : getEffectiveBorderColor(element, 'none'))"
|
|
537
683
|
:stroke-width="(isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true) ? 0 : (element.style?.enableBorder === false ? 0 : getElementBorderWidth(element))"
|
|
538
684
|
:stroke-linecap="element.style?.strokeLinecap || element.borderLineCap || element.lineCap || (element.shapType === 'arc' ? 'round' : (isOpenLineShape(element) ? 'butt' : undefined))"
|
|
@@ -558,12 +704,12 @@ function formatShapeHtml(el: any): string {
|
|
|
558
704
|
:style="{
|
|
559
705
|
width: '100%',
|
|
560
706
|
height: '100%',
|
|
561
|
-
backgroundColor: getElementPattern(element) ? 'transparent' : ((getElementGradientCss(element) || (getElementFill(element) !== undefined && getElementFill(element) !== 'none')) ? (getElementGradientCss(element) ? 'transparent' : getElementFill(element)) : (getElementFill(element) === 'none' ? 'transparent' : '#10b981')),
|
|
707
|
+
backgroundColor: getElementPattern(element) ? 'transparent' : ((isImagePlaceholder && isImagePlaceholder(element) && !getElementGradientCss(element)) ? getImagePlaceholderFill(element) : ((getElementGradientCss(element) || (getElementFill(element) !== undefined && getElementFill(element) !== 'none')) ? (getElementGradientCss(element) ? 'transparent' : getElementFill(element)) : (getElementFill(element) === 'none' ? 'transparent' : '#10b981'))),
|
|
562
708
|
backgroundImage: getElementPattern(element) ? `url('${getElementPattern(element)}')` : (getElementGradientCss(element) || 'none'),
|
|
563
|
-
backgroundSize: getElementPattern(element) ? 'cover' : undefined,
|
|
564
|
-
backgroundPosition: getElementPattern(element) ? 'center center' : undefined,
|
|
565
|
-
backgroundRepeat: getElementPattern(element) ? 'no-repeat' : undefined,
|
|
566
|
-
borderRadius: element.style?.borderRadius !== undefined ? element.style.borderRadius : '0px',
|
|
709
|
+
backgroundSize: getElementPattern(element) ? (isElementPatternTile(element) ? `${getElementPatternTileSize(element).w}px ${getElementPatternTileSize(element).h}px` : 'cover') : undefined,
|
|
710
|
+
backgroundPosition: getElementPattern(element) ? (isElementPatternTile(element) ? '0 0' : 'center center') : undefined,
|
|
711
|
+
backgroundRepeat: getElementPattern(element) ? (isElementPatternTile(element) ? 'repeat' : 'no-repeat') : undefined,
|
|
712
|
+
borderRadius: (isImagePlaceholder && isImagePlaceholder(element)) ? getImagePlaceholderRadius(element) : (element.style?.borderRadius !== undefined ? (typeof element.style.borderRadius === 'number' ? `${element.style.borderRadius}px` : element.style.borderRadius) : (element.radius ? `${element.radius}px` : '0px')),
|
|
567
713
|
borderWidth: (isImagePlaceholder && isImagePlaceholder(element) && element.style?.enableBorder !== true)
|
|
568
714
|
? '0px'
|
|
569
715
|
: (element.style?.enableBorder === false ? '0px' : `${getElementBorderWidth(element)}px`),
|
|
@@ -588,7 +734,7 @@ function formatShapeHtml(el: any): string {
|
|
|
588
734
|
<defs v-if="getElementBorderGradientConfig(element)">
|
|
589
735
|
<radialGradient
|
|
590
736
|
v-if="getElementBorderGradientConfig(element)!.path && getElementBorderGradientConfig(element)!.path !== 'line'"
|
|
591
|
-
:id="`shape-border-gradient-${
|
|
737
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
592
738
|
:cx="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.x * 100) : 50}%`"
|
|
593
739
|
:cy="`${getElementBorderGradientConfig(element)!.center ? Math.round(getElementBorderGradientConfig(element)!.center!.y * 100) : 50}%`"
|
|
594
740
|
:r="getElementBorderGradientConfig(element)!.path === 'rect' ? '60%' : (getElementBorderGradientConfig(element)!.path === 'path' ? '70%' : '50%')"
|
|
@@ -605,7 +751,7 @@ function formatShapeHtml(el: any): string {
|
|
|
605
751
|
</radialGradient>
|
|
606
752
|
<linearGradient
|
|
607
753
|
v-else
|
|
608
|
-
:id="`shape-border-gradient-${
|
|
754
|
+
:id="`shape-border-gradient-${svgIdKey}`"
|
|
609
755
|
:x1="getSvgGradientCoords(getElementBorderGradientConfig(element)).x1"
|
|
610
756
|
:y1="getSvgGradientCoords(getElementBorderGradientConfig(element)).y1"
|
|
611
757
|
:x2="getSvgGradientCoords(getElementBorderGradientConfig(element)).x2"
|
|
@@ -625,8 +771,8 @@ function formatShapeHtml(el: any): string {
|
|
|
625
771
|
y="0"
|
|
626
772
|
width="100%"
|
|
627
773
|
height="100%"
|
|
628
|
-
:rx="parseFloat(element.style?.borderRadius) || 0"
|
|
629
|
-
:ry="parseFloat(element.style?.borderRadius) || 0"
|
|
774
|
+
:rx="parseFloat(element.style?.borderRadius) || parseFloat(element.radius) || 0"
|
|
775
|
+
:ry="parseFloat(element.style?.borderRadius) || parseFloat(element.radius) || 0"
|
|
630
776
|
fill="none"
|
|
631
777
|
:stroke="getEffectiveBorderColor(element, '#10b981')"
|
|
632
778
|
:stroke-width="getEffectiveBorderWidth(element)"
|
|
@@ -636,8 +782,22 @@ function formatShapeHtml(el: any): string {
|
|
|
636
782
|
</svg>
|
|
637
783
|
</div>
|
|
638
784
|
|
|
785
|
+
<!-- Image Placeholder Centered Icon Overlay -->
|
|
786
|
+
<div
|
|
787
|
+
v-if="isImagePlaceholder && isImagePlaceholder(element)"
|
|
788
|
+
class="image-placeholder-icon-overlay"
|
|
789
|
+
style="position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none;"
|
|
790
|
+
>
|
|
791
|
+
<svg width="56" height="56" viewBox="0 0 24 24" fill="none" style="max-width: 45%; max-height: 45%;">
|
|
792
|
+
<rect x="3" y="3" width="18" height="18" rx="2" stroke="#475569" stroke-width="2" />
|
|
793
|
+
<circle cx="8.5" cy="8.5" r="1.5" fill="#475569" />
|
|
794
|
+
<path d="M21 15l-5-5L5 21" stroke="#475569" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
|
795
|
+
</svg>
|
|
796
|
+
</div>
|
|
797
|
+
|
|
639
798
|
<!-- Embedded Shape Text Overlay -->
|
|
640
799
|
<div
|
|
800
|
+
v-else
|
|
641
801
|
class="shape-text-overlay-wrapper"
|
|
642
802
|
style="position: absolute; display: flex; flex-direction: column; box-sizing: border-box; pointer-events: none;"
|
|
643
803
|
:style="{
|
|
@@ -656,7 +816,7 @@ function formatShapeHtml(el: any): string {
|
|
|
656
816
|
}">
|
|
657
817
|
<div
|
|
658
818
|
ref="shapeEditableRef"
|
|
659
|
-
:id="`editable-${element.id}`"
|
|
819
|
+
:id="isReflection ? undefined : `editable-${element.id}`"
|
|
660
820
|
:contenteditable="isTextSelectable ? 'true' : 'false'"
|
|
661
821
|
@mousedown="isTextSelectable ? $event.stopPropagation() : null"
|
|
662
822
|
@click="isTextSelectable ? $event.stopPropagation() : null"
|
|
@@ -681,7 +841,7 @@ function formatShapeHtml(el: any): string {
|
|
|
681
841
|
boxSizing: 'content-box',
|
|
682
842
|
overflow: 'wrap',
|
|
683
843
|
wordBreak: 'break-word',
|
|
684
|
-
pointerEvents: isTextSelectable ? 'auto' : (getRawText(element).trim() ? 'auto' : 'none'),
|
|
844
|
+
pointerEvents: isReflection ? 'none' : (isTextSelectable ? 'auto' : (getRawText(element).trim() ? 'auto' : 'none')),
|
|
685
845
|
cursor: isTextSelectable ? 'text' : undefined,
|
|
686
846
|
userSelect: isTextSelectable ? 'text' : 'none',
|
|
687
847
|
color: element.style?.textColor || element.style?.color || element.textColor || ((isImagePlaceholder && isImagePlaceholder(element)) ? '#6366f1' : (element.style?.fill === '#ffffff' || element.style?.fill === '#FFFFFF' ? '#475569' : (themeRecipe?.shape?.textColor || '#ffffff'))),
|