renderer.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <template>
  2. <div
  3. class="draw-layout"
  4. id="draw-renderer"
  5. ref="layout"
  6. :style="{ cursor: cursorStyle }"
  7. >
  8. <template v-if="layout">
  9. <v-stage ref="stage" :config="size">
  10. <v-layer :config="viewerConfig" id="formal">
  11. <v-rect :config="config" ref="shape" />
  12. <slot />
  13. </v-layer>
  14. </v-stage>
  15. </template>
  16. </div>
  17. </template>
  18. <script lang="ts" setup>
  19. import { computed, getCurrentInstance, onUnmounted, ref, watch, watchEffect } from "vue";
  20. import {
  21. mergeFuns,
  22. rendererMap,
  23. useCursor,
  24. useGlobalResize,
  25. useGlobalVar,
  26. useStage,
  27. useViewer,
  28. useViewerInvertTransform,
  29. useViewerInvertTransformConfig,
  30. useViewerTransform,
  31. useViewerTransformConfig,
  32. } from "./hook";
  33. import { install } from "./install-lib";
  34. import { Pos } from "./dec";
  35. const props = defineProps<{ scale: { value: number; center: Pos } }>();
  36. const emit = defineEmits<{ (e: "update:scaleValue", v: number): void }>();
  37. const instance = getCurrentInstance();
  38. install(instance!.appContext.app);
  39. rendererMap.set(instance, { unmounteds: [] });
  40. onUnmounted(() => {
  41. mergeFuns(rendererMap.get(instance)!.unmounteds)();
  42. });
  43. const stage = useStage();
  44. const { size } = useGlobalResize();
  45. const layout = ref();
  46. const viewerConfig = useViewerTransformConfig();
  47. const cursor = useCursor();
  48. const cursorStyle = computed(() => {
  49. if (cursor.value.includes(".")) {
  50. return `url(${cursor.value}), auto`;
  51. } else {
  52. return cursor.value;
  53. }
  54. });
  55. const viewer = useViewer();
  56. watch(
  57. () => props.scale,
  58. (scale) => {
  59. if (size.value) {
  60. viewer.viewer.scalePixel(scale.center, {
  61. x: scale.value / viewerConfig.value.scaleX,
  62. y: 1,
  63. });
  64. }
  65. },
  66. { deep: true }
  67. );
  68. watchEffect(
  69. () => {
  70. if (Math.abs(props.scale.value - viewerConfig.value.scaleX) > 0.001) {
  71. emit("update:scaleValue", viewerConfig.value.scaleX);
  72. }
  73. },
  74. { flush: "post" }
  75. );
  76. const invConfig = useViewerInvertTransformConfig();
  77. const viewMat = useViewerTransform();
  78. const viewInvertMat = useViewerInvertTransform();
  79. const config = computed(
  80. () =>
  81. size.value && {
  82. ...invConfig.value,
  83. ...size.value,
  84. }
  85. );
  86. const { updateSize } = useGlobalResize();
  87. const { misPixel } = useGlobalVar();
  88. defineExpose({
  89. updateSize,
  90. getTimeScreen(time: number) {
  91. return viewMat.value.point({ x: time * misPixel, y: 0 }).x;
  92. },
  93. });
  94. </script>
  95. <style scoped lang="scss">
  96. .draw-layout {
  97. width: 100%;
  98. height: 100%;
  99. overflow: hidden;
  100. position: relative;
  101. display: flex;
  102. align-items: center;
  103. justify-content: center;
  104. .draw-content {
  105. position: relative;
  106. width: 100%;
  107. height: 100%;
  108. }
  109. }
  110. .mount-mask {
  111. position: absolute;
  112. inset: 0;
  113. overflow: hidden;
  114. pointer-events: none;
  115. z-index: 999;
  116. }
  117. </style>