index.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <template>
  2. <v-rect
  3. :config="{
  4. width: size?.width,
  5. height: height,
  6. fill: background ? background : '#000',
  7. opacity: opacity,
  8. ...bgConfig,
  9. }"
  10. />
  11. <component
  12. :is="itemsRenderer"
  13. :items="items"
  14. :top="top"
  15. :activeNdx="active ? items.indexOf(active) : -1"
  16. :ref="(r: any) => itemShapes = r ? r.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. opacity: number;
  55. top: number;
  56. active?: TLItem;
  57. }>();
  58. const emit = defineEmits<{
  59. (e: "update:active", data: TLItem | undefined): void;
  60. (e: "update", data: { ndx: number; time: number }): void;
  61. (e: "add", data: any): void;
  62. (e: "del", ndx: number): void;
  63. }>();
  64. const invMat = useViewerInvertTransform();
  65. const bgConfig = computed(() => {
  66. return new Transform()
  67. .multiply(invMat.value.copy())
  68. .translate(0, props.top)
  69. .decompose();
  70. });
  71. const itemShapes = ref<DC<EntityShape>[]>([]);
  72. const { drag } = useDrag(itemShapes);
  73. let total = { x: 0, y: 0 };
  74. watch(drag, (drag) => {
  75. if (!drag) {
  76. total = { x: 0, y: 0 };
  77. return;
  78. }
  79. const cur = props.items[drag.ndx];
  80. if (
  81. checkTLItem(
  82. props.items,
  83. { ...cur, time: cur.time + (total.x + drag.x) / misPixel },
  84. drag.ndx
  85. )
  86. ) {
  87. const curX = cur.time * misPixel + total.x + drag.x;
  88. emit("update", { ndx: drag.ndx, time: curX / misPixel });
  89. total = { x: 0, y: 0 };
  90. } else {
  91. total.x += drag.x;
  92. total.y += drag.y;
  93. }
  94. });
  95. watchEffect((onCleanup) => {
  96. for (let i = 0; i < itemShapes.value.length; i++) {
  97. const $shape = itemShapes.value[i]?.getNode();
  98. if (!$shape) continue;
  99. $shape.on("click.uactive", () => {
  100. emit("update:active", props.active === props.items[i] ? undefined : props.items[i]);
  101. });
  102. onCleanup(() => $shape.off("click.uactive"));
  103. }
  104. });
  105. const copyHandler = (ndx: number) => {
  106. const newFrame = {
  107. ...props.items[ndx],
  108. time: getAddTLItemTime(props.items, ndx, props.items[ndx].duration),
  109. };
  110. emit("add", newFrame);
  111. };
  112. const delHandler = (ndx: number) => {
  113. emit("del", ndx);
  114. };
  115. </script>