index.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <template>
  2. <v-rect
  3. :config="{
  4. width: size?.width,
  5. height: height,
  6. fill: background ? background : '#000',
  7. opacity: background ? 1 : 0,
  8. ...bgConfig,
  9. }"
  10. />
  11. <component
  12. :is="itemsRenderer"
  13. :items="items"
  14. :top="top"
  15. :activeNdx="active ? items.indexOf(active) : -1"
  16. :ref="({ shapes }: any) => itemShapes = shapes"
  17. />
  18. <template v-for="(itemShape, i) in itemShapes">
  19. <Operate
  20. v-if="itemShape"
  21. :target="itemShape"
  22. :menus="[
  23. {
  24. label: '复制',
  25. handler: () => copyHandler(i),
  26. },
  27. {
  28. label: '删除',
  29. handler: () => delHandler(i),
  30. },
  31. ]"
  32. />
  33. </template>
  34. </template>
  35. <script lang="ts" setup>
  36. import { computed, ref, watch, watchEffect } from "vue";
  37. import {
  38. useDrag,
  39. useGlobalResize,
  40. useGlobalVar,
  41. useViewerInvertTransform,
  42. } from "../drawing/hook";
  43. import { Transform } from "konva/lib/Util";
  44. import { DC, EntityShape } from "../drawing/dec";
  45. import Operate from "../drawing/operate.vue";
  46. import { checkTLItem, getAddTLItemTime, TLItem } from "./check";
  47. const { misPixel } = useGlobalVar();
  48. const { size } = useGlobalResize();
  49. const props = defineProps<{
  50. items: TLItem[];
  51. itemsRenderer: any;
  52. background?: string;
  53. height: number;
  54. top: number;
  55. active?: TLItem;
  56. }>();
  57. const emit = defineEmits<{
  58. (e: "update:active", data: TLItem | undefined): void;
  59. (e: "update", data: { ndx: number; time: number }): void;
  60. (e: "add", data: any): void;
  61. (e: "del", ndx: number): void;
  62. }>();
  63. const invMat = useViewerInvertTransform();
  64. const bgConfig = computed(() => {
  65. return new Transform()
  66. .multiply(invMat.value.copy())
  67. .translate(0, props.top)
  68. .decompose();
  69. });
  70. const itemShapes = ref<DC<EntityShape>[]>([]);
  71. const { drag } = useDrag(itemShapes);
  72. let total = { x: 0, y: 0 };
  73. watch(drag, (drag) => {
  74. if (!drag) {
  75. total = { x: 0, y: 0 };
  76. return;
  77. }
  78. const cur = props.items[drag.ndx];
  79. if (
  80. checkTLItem(
  81. props.items,
  82. { ...cur, time: cur.time + (total.x + drag.x) / misPixel },
  83. drag.ndx
  84. )
  85. ) {
  86. const curX = cur.time * misPixel + total.x + drag.x;
  87. emit("update", { ndx: drag.ndx, time: curX / misPixel });
  88. total = { x: 0, y: 0 };
  89. } else {
  90. total.x += drag.x;
  91. total.y += drag.y;
  92. }
  93. });
  94. watchEffect((onCleanup) => {
  95. for (let i = 0; i < itemShapes.value.length; i++) {
  96. const $shape = itemShapes.value[i]?.getNode();
  97. if (!$shape) continue;
  98. $shape.on("click.uactive", () => {
  99. emit("update:active", props.active === props.items[i] ? undefined : props.items[i]);
  100. });
  101. onCleanup(() => $shape.off("click.uactive"));
  102. }
  103. });
  104. const copyHandler = (ndx: number) => {
  105. const newFrame = {
  106. ...props.items[ndx],
  107. time: getAddTLItemTime(props.items, ndx, props.items[ndx].duration),
  108. };
  109. emit("add", newFrame);
  110. };
  111. const delHandler = (ndx: number) => {
  112. emit("del", ndx);
  113. };
  114. </script>