index.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <template>
  2. <div class="editable-element-shape"
  3. :class="{ 'lock': elementInfo.lock }"
  4. :style="{
  5. top: elementInfo.top + 'px',
  6. left: elementInfo.left + 'px',
  7. }"
  8. @mousedown="$event => handleSelectElement($event)"
  9. >
  10. <div
  11. class="element-content"
  12. v-contextmenu="contextmenus"
  13. :style="{ filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '' }"
  14. >
  15. <SvgWrapper
  16. overflow="visible"
  17. :width="svgWidth"
  18. :height="svgHeight"
  19. >
  20. <defs>
  21. <LinePointMarker
  22. v-if="elementInfo.points[0]"
  23. :id="elementInfo.id"
  24. position="start"
  25. :type="elementInfo.points[0]"
  26. :color="elementInfo.color"
  27. :baseSize="elementInfo.width"
  28. />
  29. <LinePointMarker
  30. v-if="elementInfo.points[1]"
  31. :id="elementInfo.id"
  32. position="end"
  33. :type="elementInfo.points[1]"
  34. :color="elementInfo.color"
  35. :baseSize="elementInfo.width"
  36. />
  37. </defs>
  38. <path
  39. :d="path"
  40. :stroke="elementInfo.color"
  41. :stroke-width="elementInfo.width"
  42. :stroke-dasharray="lineDashArray"
  43. fill="none"
  44. stroke-linecap
  45. stroke-linejoin
  46. stroke-miterlimit
  47. :marker-start="elementInfo.points[0] ? `url(#${elementInfo.id}-${elementInfo.points[0]}-start)` : ''"
  48. :marker-end="elementInfo.points[1] ? `url(#${elementInfo.id}-${elementInfo.points[1]}-end)` : ''"
  49. ></path>
  50. </SvgWrapper>
  51. </div>
  52. </div>
  53. </template>
  54. <script lang="ts">
  55. import { computed, defineComponent, PropType } from 'vue'
  56. import { PPTLineElement } from '@/types/slides'
  57. import { ContextmenuItem } from '@/components/Contextmenu/types'
  58. import useElementShadow from '@/views/components/element/hooks/useElementShadow'
  59. import LinePointMarker from './LinePointMarker.vue'
  60. import SvgWrapper from '@/components/SvgWrapper.vue'
  61. export default defineComponent({
  62. name: 'editable-element-shape',
  63. components: {
  64. LinePointMarker,
  65. SvgWrapper,
  66. },
  67. props: {
  68. elementInfo: {
  69. type: Object as PropType<PPTLineElement>,
  70. required: true,
  71. },
  72. selectElement: {
  73. type: Function as PropType<(e: MouseEvent, element: PPTLineElement, canMove?: boolean) => void>,
  74. required: true,
  75. },
  76. contextmenus: {
  77. type: Function as PropType<() => ContextmenuItem[]>,
  78. },
  79. },
  80. setup(props) {
  81. const handleSelectElement = (e: MouseEvent) => {
  82. if(props.elementInfo.lock) return
  83. e.stopPropagation()
  84. props.selectElement(e, props.elementInfo)
  85. }
  86. const shadow = computed(() => props.elementInfo.shadow)
  87. const { shadowStyle } = useElementShadow(shadow)
  88. const svgWidth = computed(() => {
  89. const width = Math.abs(props.elementInfo.start[0] - props.elementInfo.end[0])
  90. return width < 24 ? 24 : width
  91. })
  92. const svgHeight = computed(() => {
  93. const height = Math.abs(props.elementInfo.start[1] - props.elementInfo.end[1])
  94. return height < 24 ? 24 : height
  95. })
  96. const lineDashArray = computed(() => props.elementInfo.style === 'dashed' ? '10, 5' : '0, 0')
  97. const path = computed(() => {
  98. const start = props.elementInfo.start.join(',')
  99. const end = props.elementInfo.end.join(',')
  100. return `M${start} L${end}`
  101. })
  102. return {
  103. handleSelectElement,
  104. shadowStyle,
  105. svgWidth,
  106. svgHeight,
  107. lineDashArray,
  108. path,
  109. }
  110. },
  111. })
  112. </script>
  113. <style lang="scss" scoped>
  114. .editable-element-shape {
  115. position: absolute;
  116. cursor: move;
  117. &.lock .element-content {
  118. cursor: default;
  119. }
  120. }
  121. .element-content {
  122. width: 100%;
  123. height: 100%;
  124. position: relative;
  125. svg {
  126. transform-origin: 0 0;
  127. overflow: visible;
  128. }
  129. }
  130. </style>