index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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="100vh"
  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 rootRect = previewRootRef.value?.getBoundingClientRect()
  123. if (!rootRect?.width || !rootRect?.height || !canvas_cfg.value.width || !canvas_cfg.value.height) {
  124. return
  125. }
  126. const scale = Math.min(rootRect.width / canvas_cfg.value.width, rootRect.height / canvas_cfg.value.height)
  127. canvas_cfg.value.scale = Number(Math.max(scale, 0.01).toFixed(4))
  128. }
  129. const fitCanvasToScreenAfterRender = async () => {
  130. await nextTick()
  131. fitCanvasToScreen()
  132. }
  133. const setItemAttrByID = (id: string, key: string, val: any) => {
  134. return setItemAttr(id, key, val, done_json.value)
  135. }
  136. const setItemAttrs = (info: { id: string; key: string; val: any }[]) => {
  137. info.forEach((f) => {
  138. setItemAttr(f.id, f.key, f.val, done_json.value)
  139. })
  140. }
  141. const getItemAttrByID = (id: string, key: string, val: any) => {
  142. return getItemAttr(id, key, done_json.value)
  143. }
  144. const onMouseWheel = (e: any) => {
  145. if (e.ctrlKey && mtPreviewProps.canZoom) {
  146. e.preventDefault()
  147. e.stopPropagation()
  148. if (e.deltaY > 0) {
  149. canvas_cfg.value.scale = (canvas_cfg.value.scale * 10 - 1) / 10
  150. } else if (e.deltaY < 0) {
  151. canvas_cfg.value.scale = (canvas_cfg.value.scale * 10 + 1) / 10
  152. }
  153. }
  154. }
  155. const setItemAttrByIDAsync = (id: string, key: string, val: any) => {
  156. // 通过改变属性的事件去设置值时 需要转换成宏任务 不然多个事件判断会有问题
  157. setTimeout(() => {
  158. setItemAttrByID(id, key, val)
  159. }, 0)
  160. }
  161. ;(window as any).$mtElMessage = ElMessage
  162. ;(window as any).$mtElMessageBox = ElMessageBox
  163. ;(window as any).$setItemAttrByID = (id: string, key: string, val: any) =>
  164. setItemAttrByIDAsync(id, key, val)
  165. ;(window as any).$getItemAttrByID = getItemAttrByID
  166. ;(window as any).$previewCompareVal = previewCompareVal
  167. ;(window as any).$mtEventCallBack = (type: string, item_id: string, ...args: any[]) =>
  168. emits('onEventCallBack', type, item_id, ...args)
  169. onMounted(() => {
  170. if (mtPreviewProps.exportJson) {
  171. const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(
  172. mtPreviewProps.exportJson
  173. )
  174. canvas_cfg.value = canvasCfg
  175. grid_cfg.value = gridCfg
  176. done_json.value = importDoneJson
  177. fitCanvasToScreenAfterRender()
  178. }
  179. if (previewRootRef.value) {
  180. resizeObserver = new ResizeObserver(() => {
  181. fitCanvasToScreen()
  182. })
  183. resizeObserver.observe(previewRootRef.value)
  184. }
  185. })
  186. onBeforeUnmount(() => {
  187. resizeObserver?.disconnect()
  188. })
  189. const setImportJson = (exportJson: IExportJson) => {
  190. const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(exportJson)
  191. canvas_cfg.value = canvasCfg
  192. grid_cfg.value = gridCfg
  193. done_json.value = importDoneJson
  194. fitCanvasToScreenAfterRender()
  195. return true
  196. }
  197. defineExpose({
  198. setItemAttrByID,
  199. setImportJson,
  200. setItemAttrs
  201. })
  202. </script>
  203. <style scoped>
  204. .mt-preview-root {
  205. width: 100vw;
  206. height: 100vh;
  207. overflow: hidden;
  208. background-color: v-bind('canvas_cfg.color || "#fff"');
  209. }
  210. .mt-preview-root :deep(.el-scrollbar__view) {
  211. min-width: 100%;
  212. min-height: 100vh;
  213. display: flex;
  214. align-items: center;
  215. justify-content: center;
  216. }
  217. .canvasStage {
  218. position: relative;
  219. width: v-bind('canvas_stage_width + "px"');
  220. height: v-bind('canvas_stage_height + "px"');
  221. flex: 0 0 auto;
  222. }
  223. .canvasArea {
  224. position: absolute;
  225. left: 0;
  226. top: 0;
  227. width: v-bind('canvas_cfg.width + "px"');
  228. height: v-bind('canvas_cfg.height + "px"');
  229. background-color: v-bind('canvas_cfg.color');
  230. background-image: v-bind('"url("+canvas_cfg.img+")"');
  231. transform: v-bind('`scale(${canvas_cfg.scale})`');
  232. transform-origin: left top;
  233. }
  234. </style>