TotpLooper.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <script setup>
  2. const props = defineProps({
  3. step_count: {
  4. type: Number,
  5. default: 10
  6. },
  7. period : Number,
  8. generated_at: Number,
  9. autostart: {
  10. type: Boolean,
  11. default: true
  12. },
  13. })
  14. const generatedAt = ref(null)
  15. const remainingTimeout = ref(null)
  16. const initialStepToNextStepTimeout = ref(null)
  17. const stepToStepInterval = ref(null)
  18. const stepIndex = ref(null)
  19. // |<----period p----->|
  20. // | | |
  21. // |------- ··· ------------|--------|----------|---------->
  22. // | | | |
  23. // unix T0 Tp.start Tgen_at Tp.end
  24. // | | |
  25. // elapsedTimeInCurrentPeriod--|<------>| |
  26. // (in ms) | | |
  27. // ● ● ● ● ●|● ◌ ◌ ◌ ◌ |
  28. // | | || |
  29. // | | |<-------->|--remainingTimeBeforeEndOfPeriod (for remainingTimeout)
  30. // durationBetweenTwoSteps-->|-|< ||
  31. // (for stepToStepInterval) | | >||<---durationFromInitialToNextStep (for initialStepToNextStepTimeout)
  32. // |
  33. // |
  34. // stepIndex
  35. const elapsedTimeInCurrentPeriod = computed(() => {
  36. return generatedAt.value % props.period
  37. })
  38. const remainingTimeBeforeEndOfPeriod = computed(() => {
  39. return props.period - elapsedTimeInCurrentPeriod.value
  40. })
  41. const durationBetweenTwoSteps = computed(() => {
  42. return props.period / props.step_count
  43. })
  44. const initialStepIndex = computed(() => {
  45. let relativePosition = (elapsedTimeInCurrentPeriod.value * props.step_count) / props.period
  46. return (Math.floor(relativePosition) + 0)
  47. })
  48. const emit = defineEmits(['loop-started', 'loop-ended', 'stepped-up'])
  49. /**
  50. * Starts looping
  51. */
  52. const startLoop = (generated_at = null) => {
  53. clearLooper()
  54. generatedAt.value = generated_at != null ? generated_at : props.generated_at
  55. emit('loop-started', initialStepIndex.value)
  56. stepIndex.value = initialStepIndex.value
  57. // Main timeout that runs until the end of the period
  58. remainingTimeout.value = setTimeout(function() {
  59. clearLooper()
  60. emit('loop-ended')
  61. }, remainingTimeBeforeEndOfPeriod.value * 1000);
  62. // During the remainingTimeout countdown we emit an event every durationBetweenTwoSteps seconds,
  63. // except for the first next dot
  64. let durationFromInitialToNextStep = (Math.ceil(elapsedTimeInCurrentPeriod.value / durationBetweenTwoSteps.value) * durationBetweenTwoSteps.value) - elapsedTimeInCurrentPeriod.value
  65. initialStepToNextStepTimeout.value = setTimeout(function() {
  66. if( durationFromInitialToNextStep > 0 ) {
  67. stepIndex.value += 1
  68. emit('stepped-up', stepIndex.value)
  69. }
  70. stepToStepInterval.value = setInterval(function() {
  71. stepIndex.value += 1
  72. emit('stepped-up', stepIndex.value)
  73. }, durationBetweenTwoSteps.value * 1000)
  74. }, durationFromInitialToNextStep * 1000)
  75. }
  76. /**
  77. * Resets all timers and internal vars
  78. */
  79. const clearLooper = () => {
  80. clearTimeout(remainingTimeout.value)
  81. clearTimeout(initialStepToNextStepTimeout.value)
  82. clearInterval(stepToStepInterval.value)
  83. stepIndex.value = generatedAt.value = null
  84. }
  85. onMounted(() => {
  86. if (props.autostart == true) {
  87. startLoop()
  88. }
  89. })
  90. onUnmounted(() => {
  91. clearLooper()
  92. })
  93. defineExpose({
  94. startLoop,
  95. clearLooper,
  96. props
  97. })
  98. </script>
  99. <template>
  100. <div>
  101. </div>
  102. </template>