bottom.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <template>
  2. <ui-editor-toolbar toolbar class="animation-toolbar">
  3. <div class="top-bar">
  4. <div class="play-bar">
  5. <ui-icon type="close" ctrl @click="play = !play" />
  6. </div>
  7. <div class="scale-bar">
  8. <ui-icon type="close" class="icon" ctrl />
  9. <Slider
  10. class="slider"
  11. v-model:value="scale"
  12. :min="0.5"
  13. :max="8"
  14. :step="0.01"
  15. :tooltipOpen="false"
  16. />
  17. <ui-icon type="close" class="icon" ctrl />
  18. </div>
  19. </div>
  20. <div class="oper-bar" :class="{ disabled: play }">
  21. <Renderer v-model:scale="scale">
  22. <TimeLine
  23. v-for="prop in tlProps"
  24. :items="am[prop.attr]"
  25. :height="prop.height"
  26. :top="prop.top"
  27. :itemsRenderer="prop.component"
  28. @update="({ ndx, time }) => (am[prop.attr][ndx].time = time)"
  29. @add="
  30. (item) => {
  31. am[prop.attr].push(item);
  32. $emit('update:active', { key: prop.attr, ndx: am[prop.attr].length - 1 });
  33. }
  34. "
  35. @del="(ndx) => am[prop.attr].splice(ndx, 1)"
  36. :active="prop.attr === active?.key ? am[prop.attr][active.ndx] : undefined"
  37. @update:active="(active: any) => $emit('update:active', active && { key: prop.attr, ndx: am[prop.attr].indexOf(active) })"
  38. />
  39. <Time @update-current-time="(time) => $emit('update:currentTime', time)">
  40. <TimeCurrent
  41. :currentTime="currentTime"
  42. @update:current-time="(time) => $emit('update:currentTime', time)"
  43. :follow="play"
  44. />
  45. </Time>
  46. </Renderer>
  47. </div>
  48. </ui-editor-toolbar>
  49. </template>
  50. <script lang="ts" setup>
  51. import { Slider } from "ant-design-vue";
  52. import { ref, watch } from "vue";
  53. import { AnimationModel } from "@/store/animation";
  54. import Renderer from "@/components/drawing/renderer.vue";
  55. import Time from "@/components/drawing-time/time.vue";
  56. import TimeCurrent from "@/components/drawing-time/current.vue";
  57. import TimeLine from "@/components/drawing-time-line/index.vue";
  58. import TimeLineFrame from "@/components/drawing-time-line/frame.vue";
  59. import TimeLineAction from "@/components/drawing-time-line/action.vue";
  60. import { Active } from "./type";
  61. const props = defineProps<{ am: AnimationModel; active?: Active; currentTime: number }>();
  62. const emit = defineEmits<{
  63. (e: "update:active", data: Active | undefined): void;
  64. (e: "update:currentTime", v: number): void;
  65. }>();
  66. const scale = ref(1);
  67. const tlProps = [
  68. { attr: "frames", component: TimeLineFrame, height: 30, top: 24 },
  69. { attr: "actions", component: TimeLineAction, height: 30, top: 65 },
  70. { attr: "subtitles", component: TimeLineAction, height: 30, top: 105 },
  71. { attr: "paths", component: TimeLineAction, height: 30, top: 140 },
  72. ] as const;
  73. const play = ref(false);
  74. watch(play, (_a, _b, onCleanup) => {
  75. let isDes = false;
  76. let prevNow = Date.now();
  77. const animation = () => {
  78. if (play.value && !isDes) {
  79. const curNow = Date.now();
  80. emit("update:currentTime", props.currentTime + (curNow - prevNow) * 0.001);
  81. prevNow = curNow;
  82. requestAnimationFrame(animation);
  83. }
  84. };
  85. animation();
  86. onCleanup(() => (isDes = true));
  87. });
  88. </script>
  89. <style scoped lang="scss">
  90. .top-bar {
  91. display: flex;
  92. height: 40px;
  93. align-items: center;
  94. border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  95. .play-bar {
  96. flex: 1;
  97. display: flex;
  98. justify-content: center;
  99. }
  100. .scale-bar {
  101. width: 180px;
  102. flex: 0 0 auto;
  103. display: flex;
  104. align-items: center;
  105. padding: 0 20px;
  106. position: relative;
  107. &::before {
  108. content: "";
  109. position: absolute;
  110. left: 0;
  111. width: 1px;
  112. height: 16px;
  113. background: rgba(255, 255, 255, 0.16);
  114. }
  115. .slider {
  116. flex: 1;
  117. }
  118. .icon {
  119. margin: 0 5px;
  120. }
  121. }
  122. }
  123. .oper-bar {
  124. height: calc(100% - 40px);
  125. }
  126. </style>