index.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <template>
  2. <div ref="previewRootRef" class="mt-preview-root">
  3. <el-scrollbar
  4. ref="elScrollbarRef"
  5. class="w-1/1 h-1/1"
  6. max-height="100%"
  7. @scroll="onScroll">
  8. <div
  9. class="canvasStage">
  10. <div
  11. ref="canvasAreaRef"
  12. :class="`canvasArea ${mtPreviewProps.canDrag ? 'cursor-grab' : ''} `"
  13. @mousedown="onMouseDown"
  14. @wheel="onMouseWheel">
  15. <render-core
  16. v-model:done-json="done_json"
  17. :canvas-cfg="canvas_cfg"
  18. :grid-cfg="grid_cfg"
  19. :show-ghost-dom="false"
  20. :canvas-dom="canvasAreaRef"
  21. :global-lock="false"
  22. :preivew-mode="true"
  23. :show-popover="mtPreviewProps.showPopover" />
  24. </div>
  25. </div>
  26. <drag-canvas
  27. ref="dragCanvasRef"
  28. :scale-ratio="canvas_cfg.scale"
  29. @drag-canvas-mouse-down="dragCanvasMouseDown"
  30. @drag-canvas-mouse-move="dragCanvasMouseMove"
  31. @drag-canvas-mouse-up="dragCanvasMouseUp" />
  32. </el-scrollbar>
  33. </div>
  34. </template>
  35. <script setup lang="ts">
  36. import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
  37. import RenderCore from '@/components/mt-edit/components/render-core/index.vue'
  38. import type { IExportJson } from '../mt-edit/components/types'
  39. import { useExportJsonToDoneJson } from '../mt-edit/composables'
  40. import type { IDoneJson } from '../mt-edit/store/types'
  41. import { getItemAttr, previewCompareVal, setItemAttr } from '../mt-edit/utils'
  42. import { ElScrollbar, ElMessage, ElMessageBox } from 'element-plus'
  43. import DragCanvas from '@/components/mt-edit/components/drag-canvas/index.vue'
  44. type MtPreviewProps = {
  45. exportJson?: IExportJson
  46. canZoom?: boolean
  47. canDrag?: boolean
  48. showPopover?: boolean
  49. fitScreen?: boolean
  50. }
  51. const mtPreviewProps = withDefaults(defineProps<MtPreviewProps>(), {
  52. canDrag: true,
  53. canZoom: true,
  54. showPopover: false,
  55. fitScreen: true
  56. })
  57. const emits = defineEmits(['onEventCallBack'])
  58. const previewRootRef = ref<HTMLElement>()
  59. const canvasAreaRef = ref()
  60. const canvas_cfg = ref({
  61. width: 1920,
  62. height: 1080,
  63. scale: 1,
  64. color: '',
  65. img: '',
  66. guide: true,
  67. adsorp: true,
  68. adsorp_diff: 3,
  69. transform_origin: {
  70. x: 0,
  71. y: 0
  72. },
  73. drag_offset: {
  74. x: 0,
  75. y: 0
  76. }
  77. })
  78. const grid_cfg = ref({
  79. enabled: true,
  80. align: true,
  81. size: 10
  82. })
  83. const done_json = ref<IDoneJson[]>([])
  84. const elScrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
  85. const dragCanvasRef = ref<InstanceType<typeof DragCanvas>>()
  86. let resizeObserver: ResizeObserver | undefined
  87. const canvas_stage_width = computed(() => canvas_cfg.value.width * canvas_cfg.value.scale)
  88. const canvas_stage_height = computed(() => canvas_cfg.value.height * canvas_cfg.value.scale)
  89. const scroll_info = reactive({
  90. begin_left: 0,
  91. begin_top: 0,
  92. left: 0,
  93. top: 0
  94. })
  95. const onScroll = ({ scrollLeft, scrollTop }: { scrollLeft: number; scrollTop: number }) => {
  96. scroll_info.left = scrollLeft
  97. scroll_info.top = scrollTop
  98. }
  99. const onMouseDown = (e: MouseEvent) => {
  100. if (mtPreviewProps.canDrag) {
  101. dragCanvasRef.value?.onMouseDown(e)
  102. }
  103. }
  104. const dragCanvasMouseDown = () => {
  105. scroll_info.begin_left = scroll_info.left
  106. scroll_info.begin_top = scroll_info.top
  107. }
  108. const dragCanvasMouseMove = (move_x: number, move_y: number) => {
  109. let new_left = scroll_info.begin_left - move_x
  110. let new_top = scroll_info.begin_top - move_y
  111. elScrollbarRef.value?.setScrollLeft(new_left)
  112. elScrollbarRef.value?.setScrollTop(new_top)
  113. }
  114. /**
  115. * 画布拖动结束事件
  116. */
  117. const dragCanvasMouseUp = () => {}
  118. const fitCanvasToScreen = () => {
  119. if (!mtPreviewProps.fitScreen) {
  120. return
  121. }
  122. const root = previewRootRef.value
  123. if (!root?.clientWidth || !root?.clientHeight || !canvas_cfg.value.width || !canvas_cfg.value.height) {
  124. return
  125. }
  126. const scale = Math.min(
  127. root.clientWidth / canvas_cfg.value.width,
  128. root.clientHeight / canvas_cfg.value.height
  129. )
  130. canvas_cfg.value.scale = Number(Math.max(scale, 0.01).toFixed(4))
  131. }
  132. const fitCanvasToScreenAfterRender = async () => {
  133. await nextTick()
  134. fitCanvasToScreen()
  135. }
  136. const setItemAttrByID = (id: string, key: string, val: any) => {
  137. return setItemAttr(id, key, val, done_json.value)
  138. }
  139. const setItemAttrs = (info: { id: string; key: string; val: any }[]) => {
  140. info.forEach((f) => {
  141. setItemAttr(f.id, f.key, f.val, done_json.value)
  142. })
  143. }
  144. const getItemAttrByID = (id: string, key: string, val: any) => {
  145. return getItemAttr(id, key, done_json.value)
  146. }
  147. const onMouseWheel = (e: any) => {
  148. if (e.ctrlKey && mtPreviewProps.canZoom) {
  149. e.preventDefault()
  150. e.stopPropagation()
  151. if (e.deltaY > 0) {
  152. canvas_cfg.value.scale = (canvas_cfg.value.scale * 10 - 1) / 10
  153. } else if (e.deltaY < 0) {
  154. canvas_cfg.value.scale = (canvas_cfg.value.scale * 10 + 1) / 10
  155. }
  156. }
  157. }
  158. const setItemAttrByIDAsync = (id: string, key: string, val: any) => {
  159. // 通过改变属性的事件去设置值时 需要转换成宏任务 不然多个事件判断会有问题
  160. setTimeout(() => {
  161. setItemAttrByID(id, key, val)
  162. }, 0)
  163. }
  164. ;(window as any).$mtElMessage = ElMessage
  165. ;(window as any).$mtElMessageBox = ElMessageBox
  166. ;(window as any).$setItemAttrByID = (id: string, key: string, val: any) =>
  167. setItemAttrByIDAsync(id, key, val)
  168. ;(window as any).$getItemAttrByID = getItemAttrByID
  169. ;(window as any).$previewCompareVal = previewCompareVal
  170. ;(window as any).$mtEventCallBack = (type: string, item_id: string, ...args: any[]) =>
  171. emits('onEventCallBack', type, item_id, ...args)
  172. onMounted(() => {
  173. if (mtPreviewProps.exportJson) {
  174. const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(
  175. mtPreviewProps.exportJson
  176. )
  177. canvas_cfg.value = canvasCfg
  178. grid_cfg.value = gridCfg
  179. done_json.value = importDoneJson
  180. fitCanvasToScreenAfterRender()
  181. }
  182. if (previewRootRef.value) {
  183. resizeObserver = new ResizeObserver(() => {
  184. fitCanvasToScreen()
  185. })
  186. resizeObserver.observe(previewRootRef.value)
  187. }
  188. })
  189. onBeforeUnmount(() => {
  190. resizeObserver?.disconnect()
  191. })
  192. const setImportJson = (exportJson: IExportJson) => {
  193. const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(exportJson)
  194. canvas_cfg.value = canvasCfg
  195. grid_cfg.value = gridCfg
  196. done_json.value = importDoneJson
  197. fitCanvasToScreenAfterRender()
  198. return true
  199. }
  200. defineExpose({
  201. setItemAttrByID,
  202. setImportJson,
  203. setItemAttrs
  204. })
  205. </script>
  206. <style scoped>
  207. .mt-preview-root {
  208. width: 100%;
  209. height: 100%;
  210. overflow: hidden;
  211. background-color: v-bind('canvas_cfg.color || "#fff"');
  212. }
  213. .mt-preview-root :deep(.el-scrollbar__view) {
  214. display: flex;
  215. min-width: 100%;
  216. min-height: 100%;
  217. align-items: center;
  218. justify-content: center;
  219. }
  220. .canvasStage {
  221. position: relative;
  222. width: v-bind('canvas_stage_width + "px"');
  223. height: v-bind('canvas_stage_height + "px"');
  224. flex: 0 0 auto;
  225. }
  226. .canvasArea {
  227. position: absolute;
  228. top: 0;
  229. left: 0;
  230. width: v-bind('canvas_cfg.width + "px"');
  231. height: v-bind('canvas_cfg.height + "px"');
  232. background-color: v-bind('canvas_cfg.color');
  233. background-image: v-bind('"url("+canvas_cfg.img+")"');
  234. transform: v-bind('`scale(${canvas_cfg.scale})`');
  235. transform-origin: left top;
  236. }
  237. </style>