mateuszRybczonek / vue2-interact

MIT License
30 stars 9 forks source link

how to use it on vue 3 #27

Open mmdrn opened 2 years ago

mmdrn commented 2 years ago

Hello How can i use it in vue3??

booladsudan commented 2 years ago

Hello I have the same question as I can't make it work on my current project. Please if you have time to spare, I love this work of yours but I hope this will be update for vue3.

bhomaidan1990 commented 2 years ago

I have modified the component to work with Vue 3 by changing the event bus:

App.vue

...
const emitter = mitt();
const app = createApp(App);
app.config.globalProperties.emitter = emitter;
...

VueInteractDraggable.vue

<template>
  <div
    ref="interactElement"
    :class="{ 'vue-interact-animated': interactIsAnimating }"
    :style="{
      transform: interactTransformString,
      transition: interactTransitionString,
    }"
  >
    <slot />
  </div>
</template>

<script>
import interact from "interactjs";

export default {
  name: "VueInteractDraggable",

  props: {
    interactBlockDragDown: {
      type: Boolean,
      default: false,
    },
    interactBlockDragLeft: {
      type: Boolean,
      default: false,
    },
    interactBlockDragRight: {
      type: Boolean,
      default: false,
    },
    interactBlockDragUp: {
      type: Boolean,
      default: false,
    },
    interactEventBusEvents: {
      type: Object,
      default: () => {},
    },
    interactMaxRotation: {
      type: Number,
      default: 0,
    },
    interactLockXAxis: {
      type: Boolean,
      default: false,
    },
    interactLockYAxis: {
      type: Boolean,
      default: false,
    },
    interactLockSwipeDown: {
      type: Boolean,
      default: false,
    },
    interactLockSwipeLeft: {
      type: Boolean,
      default: false,
    },
    interactLockSwipeRight: {
      type: Boolean,
      default: false,
    },
    interactLockSwipeUp: {
      type: Boolean,
      default: false,
    },
    interactOutOfSightXCoordinate: {
      type: Number,
      default: 500,
    },
    interactOutOfSightYCoordinate: {
      type: Number,
      default: 1000,
    },
    interactXThreshold: {
      type: Number,
      default: 200,
    },
    interactYThreshold: {
      type: Number,
      default: 300,
    },
  },

  data() {
    return {
      interactIsAnimating: true,
      interactDragged: null,
      interactPosition: {
        x: 0,
        y: 0,
        rotation: 0,
      },
    };
  },

  computed: {
    interactTransformString() {
      if (!this.interactIsAnimating || this.interactDragged) {
        const { x, y, rotation } = this.interactPosition;
        return `translate3D(${x}px, ${y}px, 0) rotate(${rotation}deg)`;
      }

      return null;
    },

    interactTransitionString() {
      if (this.interactIsAnimating)
        return "transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)";

      return null;
    },
  },

  watch: {
    interactEventBusEvents(val) {
      this.interactSetEventBusEvents();
    },
  },

  mounted() {
    this.interactSetEventBusEvents();

    const element = this.$refs.interactElement;

    interact(element).draggable({
      onstart: () => {
        this.interactIsAnimating = false;
      },

      onmove: (event) => {
        let x = 0;
        let y = 0;

        if (this.interactLockSwipeLeft && event.dx < 0) x = 0;
        else if (this.interactLockSwipeRight && event.dx > 0) x = 0;
        else
          x = this.interactLockXAxis
            ? 0
            : (this.interactPosition.x || 0) + event.dx;

        if (this.interactLockSwipeUp && event.dy < 0) y = 0;
        else if (this.interactLockSwipeDown && event.dy > 0) y = 0;
        else
          y = this.interactLockYAxis
            ? 0
            : (this.interactPosition.y || 0) + event.dy;

        let rotation = this.interactMaxRotation * (x / this.interactXThreshold);

        if (rotation > this.interactMaxRotation)
          rotation = this.interactMaxRotation;
        else if (rotation < -this.interactMaxRotation)
          rotation = -this.interactMaxRotation;

        this.interactSetPosition({ x, y, rotation });
      },

      onend: () => {
        const { x: cardPositionX, y: cardPositionY } = this.interactPosition;
        const { interactXThreshold, interactYThreshold } = this;
        this.interactIsAnimating = true;

        if (cardPositionX > interactXThreshold) this.interactDraggedRight();
        else if (cardPositionX < -interactXThreshold)
          this.interactDraggedLeft();
        else if (cardPositionY > interactYThreshold) this.interactDraggedDown();
        else if (cardPositionY < -interactYThreshold) this.interactDraggedUp();
        else this.interactResetCardPosition();
      },
    });
  },

  beforeUnmount() {
    interact(this.$refs.interactElement).unset();
    this.interactUnsetEventBusEvents();
  },

  methods: {
    interactDraggedDown() {
      if (this.interactBlockDragDown) {
        this.interactResetCardPosition();
        return;
      }
      this.interactUnsetElement();
      this.interactSetPosition({ y: this.interactOutOfSightYCoordinate });
      this.$emit("draggedDown");
    },

    interactDraggedLeft() {
      if (this.interactBlockDragLeft) {
        this.interactResetCardPosition();
        return;
      }
      this.interactUnsetElement();
      this.interactSetPosition({
        x: -this.interactOutOfSightXCoordinate,
        rotation: -this.interactMaxRotation,
      });
      this.$emit("draggedLeft");
    },

    interactDraggedRight() {
      if (this.interactBlockDragRight) {
        this.interactResetCardPosition();
        return;
      }
      this.interactUnsetElement();
      this.interactSetPosition({
        x: this.interactOutOfSightXCoordinate,
        rotation: this.interactMaxRotation,
      });
      this.$emit("draggedRight");
    },

    interactDraggedUp() {
      if (this.interactBlockDragUp) {
        this.interactResetCardPosition();
        return;
      }
      this.interactUnsetElement();
      this.interactSetPosition({ y: -this.interactOutOfSightYCoordinate });
      this.$emit("draggedUp");
    },

    interactSetEventBusEvents() {
      if (this.interactEventBusEvents) {
        if (this.interactEventBusEvents.draggedDown) {
          this.emitter.$on(
            this.interactEventBusEvents.draggedDown,
            this.interactDraggedDown
          );
        }

        if (this.interactEventBusEvents.draggedLeft) {
          this.emitter.$on(
            this.interactEventBusEvents.draggedLeft,
            this.interactDraggedLeft
          );
        }

        if (this.interactEventBusEvents.draggedRight) {
          this.emitter.$on(
            this.interactEventBusEvents.draggedRight,
            this.interactDraggedRight
          );
        }

        if (this.interactEventBusEvents.draggedUp) {
          this.emitter.$on(
            this.interactEventBusEvents.draggedUp,
            this.interactDraggedUp
          );
        }
      }
    },

    interactSetPosition(coordinates) {
      const { x = 0, y = 0, rotation = 0 } = coordinates;

      this.interactPosition = { x, y, rotation };
    },

    interactUnsetElement() {
      interact(this.$refs.interactElement).unset();
      this.interactDragged = true;
    },

    interactUnsetEventBusEvents() {
      if (this.interactEventBusEvents) {
        if (this.interactEventBusEvents.draggedDown) {
          this.emitter.$off(
            this.interactEventBusEvents.draggedDown,
            this.draggedDown
          );
        }

        if (this.interactEventBusEvents.draggedLeft) {
          this.emitter.$off(
            this.interactEventBusEvents.draggedLeft,
            this.draggedLeft
          );
        }

        if (this.interactEventBusEvents.draggedRight) {
          this.emitter.$off(
            this.interactEventBusEvents.draggedRight,
            this.draggedRight
          );
        }

        if (this.interactEventBusEvents.draggedUp) {
          this.emitter.$off(
            this.interactEventBusEvents.draggedUp,
            this.draggedUp
          );
        }
      }
    },

    interactResetCardPosition() {
      this.interactSetPosition({ x: 0, y: 0, rotation: 0 });
    },
  },
  emits: ['draggedUp', 'draggedDown', 'draggedLeft', 'draggedRight'],
};
</script>