| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- <template>
- <div
- class="base-element-shape"
- :style="{
- top: elementInfo.top + 'px',
- left: elementInfo.left + 'px',
- width: elementInfo.width + 'px',
- height: elementInfo.height + 'px',
- }"
- >
- <div
- class="rotate-wrapper"
- :style="{ transform: `rotate(${elementInfo.rotate}deg)` }"
- >
- <div
- class="element-content"
- :style="{
- opacity: elementInfo.opacity,
- filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
- transform: flipStyle,
- color: text.defaultColor,
- fontFamily: text.defaultFontName,
- }"
- >
- <svg
- overflow="visible"
- :width="elementInfo.width"
- :height="elementInfo.height"
- >
- <defs>
- <PatternDefs
- v-if="elementInfo.pattern"
- :id="`base-pattern-${elementInfo.id}`"
- :src="elementInfo.pattern"
- />
- <GradientDefs
- v-else-if="elementInfo.gradient"
- :id="`base-gradient-${elementInfo.id}`"
- :type="elementInfo.gradient.type"
- :colors="elementInfo.gradient.colors"
- :rotate="elementInfo.gradient.rotate"
- />
- </defs>
- <g
- :transform="`scale(${elementInfo.width / elementInfo.viewBox[0]}, ${elementInfo.height / elementInfo.viewBox[1]}) translate(0,0) matrix(1,0,0,1,0,0)`"
- >
- <path
- vector-effect="non-scaling-stroke"
- stroke-linecap="butt"
- stroke-miterlimit="8"
- :d="elementInfo.path"
- :fill="fill"
- :stroke="outlineColor"
- :stroke-width="outlineWidth"
- :stroke-dasharray="strokeDashArray"
- ></path>
- </g>
- </svg>
- <div class="shape-text" :style="text.style" :class="[text.align, { 'editable': editable || text.content }]">
- <div class="ProseMirror-static" v-html="text.content"></div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { computed } from 'vue'
- import { storeToRefs } from 'pinia'
- import type { PPTShapeElement, ShapeText } from '@/types/slides'
- import { useSlidesStore } from '@/store'
- import useElementOutline from '@/views/components/element/hooks/useElementOutline'
- import useElementShadow from '@/views/components/element/hooks/useElementShadow'
- import useElementFlip from '@/views/components/element/hooks/useElementFlip'
- import useElementFill from '@/views/components/element/hooks/useElementFill'
- import GradientDefs from './GradientDefs.vue'
- import PatternDefs from './PatternDefs.vue'
- const props = defineProps<{
- elementInfo: PPTShapeElement
- }>()
- const { theme } = storeToRefs(useSlidesStore())
- const element = computed(() => props.elementInfo)
- const { fill } = useElementFill(element, 'base')
- const outline = computed(() => props.elementInfo.outline)
- const { outlineWidth, outlineColor, strokeDashArray } = useElementOutline(outline)
- const shadow = computed(() => props.elementInfo.shadow)
- const { shadowStyle } = useElementShadow(shadow)
- const flipH = computed(() => props.elementInfo.flipH)
- const flipV = computed(() => props.elementInfo.flipV)
- const { flipStyle } = useElementFlip(flipH, flipV)
- const text = computed<ShapeText>(() => {
- const defaultText: ShapeText = {
- content: '',
- align: 'middle',
- defaultFontName: theme.value.fontName,
- defaultColor: theme.value.fontColor,
- }
- if (!props.elementInfo.text) return defaultText
- return props.elementInfo.text
- })
- </script>
- <style lang="scss" scoped>
- .base-element-shape {
- position: absolute;
- }
- .rotate-wrapper {
- width: 100%;
- height: 100%;
- }
- .element-content {
- width: 100%;
- height: 100%;
- position: relative;
- line-height: 1.5;
- svg {
- transform-origin: 0 0;
- overflow: visible;
- display: block;
- }
- }
- .shape-text {
- width:100%;
- height:100%;
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: column;
- padding: 5px;
- word-break: break-word;
- pointer-events: none;
- white-space: break-spaces;
- &.editable {
- pointer-events: all;
- }
- &.top {
- justify-content: flex-start;
- }
- &.middle {
- justify-content: center;
- left: 50%;
- top: 50%;
- -webkit-transform: translate(-50%,-50%);
- transform: translate(-50%,-50%);
- }
- &.bottom {
- justify-content: flex-end;
- }
- }
- </style>
|