From add448bd5a741ac6138435a0bbabe3db22f5fd0f Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Mon, 20 Feb 2023 14:27:14 +0100 Subject: [PATCH] Include vue interactjs to support touch drag and drop --- package.json | 3 ++- src/DragContainer.vue | 55 ++++++++++++++++++++++++++++--------------- src/DragGrid.vue | 35 ++++++++++++++++++--------- src/index.js | 4 ++++ 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index c0ad805..2df9369 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "vuepress": "^1.9.8" }, "dependencies": { - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "vue-interactjs": "^0.1.10" } } diff --git a/src/DragContainer.vue b/src/DragContainer.vue index df4a865..6c2b644 100644 --- a/src/DragContainer.vue +++ b/src/DragContainer.vue @@ -1,13 +1,15 @@ <template> - <div + <interact @dragstart="handleDragStart" + @dragmove="handleDragMove" :draggable="!isDisabled" id="wrapper" ref="wrapper" @dragend="handleDragEnd" + :data-transfer="dataTransferString" > <slot></slot> - </div> + </interact> </template> <script> @@ -16,26 +18,27 @@ export default { methods: { handleDragStart(event) { if (this.isDisabled) return; - this.$refs.wrapper.style.cursor = "grabbing"; let rect = event.target.getBoundingClientRect(); - event.dataTransfer.setData( - "vueDrag/gridItem", - JSON.stringify({ - key: this.dragID, - x: this.x, - y: this.y, - w: this.w, - h: this.h, - data: this.data, - context: this.context, - originGridId: this.gridId, - mouseX: event.clientX - rect.x - rect.width / (2 * this.w), // relative to center of the top left square - mouseY: event.clientY - rect.y - rect.height / (2 * this.h), - }) - ); + this.dataTransfer = { + key: this.dragID, + x: this.x, + y: this.y, + w: this.w, + h: this.h, + data: this.data, + context: this.context, + originGridId: this.gridId, + mouseX: event.clientX - rect.x - rect.width / (2 * this.w), // relative to center of the top left square + mouseY: event.clientY - rect.y - rect.height / (2 * this.h), + }; }, handleDragEnd() { - this.$refs.wrapper.style.cursor = "grab"; + this.offsetX = 0; + this.offsetY = 0; + }, + handleDragMove(event) { + this.offsetX += event.dx; + this.offsetY += event.dy; }, }, props: { @@ -96,6 +99,16 @@ export default { cursor() { return this.disabled ? "auto" : "grab"; }, + dataTransferString() { + return JSON.stringify(this.dataTransfer); + }, + }, + data() { + return { + dataTransfer: {}, + offsetX: 0, + offsetY: 0, + }; }, }; </script> @@ -106,5 +119,9 @@ export default { grid-row: v-bind(getY) / span v-bind(h); display: v-bind(getDisplay); cursor: v-bind(cursor); + transform: translate( + calc(1px * v-bind(offsetX)), + calc(1px * v-bind(offsetY)) + ); } </style> diff --git a/src/DragGrid.vue b/src/DragGrid.vue index 78a6cb7..2b926ef 100644 --- a/src/DragGrid.vue +++ b/src/DragGrid.vue @@ -1,6 +1,7 @@ <template> - <div - @dragover.prevent="disabled ? undefined : handleDragOver($event)" + <interact + droppable + @dropmove="disabled ? undefined : handleDragOver($event)" @drop.prevent="disabled ? undefined : handleDrop($event)" @dragleave="$refs.highlightContainer.style.display = 'none'" class="grid" @@ -47,7 +48,7 @@ </GridItem> </template> <slot></slot> - </div> + </interact> </template> <script> @@ -143,12 +144,12 @@ export default { return true; }, handleDragOver(event) { - let data = event.dataTransfer.getData("vueDrag/gridItem"); + let data = event.relatedTarget.dataset.transfer; if (!data) return; let element = JSON.parse(data); let coords = this.getCoords( - event.clientX - element.mouseX, - event.clientY - element.mouseY + event.dragEvent.client.x - element.mouseX, + event.dragEvent.client.y - element.mouseY ); if (element.context !== this.context || this.noHighlight) { @@ -179,7 +180,7 @@ export default { }, handleDrop(event) { this.$refs.highlightContainer.style.display = "none"; - let data = event.dataTransfer.getData("vueDrag/gridItem"); + let data = event.relatedTarget.dataset.transfer; if (!data) return; let element = JSON.parse(data); @@ -190,8 +191,8 @@ export default { } let coords = this.getCoords( - event.clientX - element.mouseX, - event.clientY - element.mouseY + event.dragEvent.client.x - element.mouseX, + event.dragEvent.client.y - element.mouseY ); let newPositionValid = true; @@ -221,6 +222,8 @@ export default { elementCopy.context = undefined; elementCopy.originGridId = undefined; + elementCopy.mouseX = undefined; + elementCopy.mouseY = undefined; valueCopy.push(elementCopy); this.$emit("input", valueCopy); @@ -239,11 +242,20 @@ export default { this.$emit("itemChanged", element); }, + clamp: (min, num, max) => Math.min(Math.max(num, min), max), getCoords(x, y) { let rect = this.$el.getBoundingClientRect(); return { - x: Math.ceil((x - rect.x) / (rect.width / this.cols)), - y: Math.ceil((y - rect.y) / (rect.height / this.rows)), + x: this.clamp( + 1, + Math.ceil((x - rect.x) / (rect.width / this.cols)), + this.cols + ), + y: this.clamp( + 1, + Math.ceil((y - rect.y) / (rect.height / this.rows)), + this.rows + ), }; }, getInt(property, item) { @@ -301,5 +313,6 @@ export default { min-width: 100px; min-height: 100px; gap: 1em; + touch-action: none; } </style> diff --git a/src/index.js b/src/index.js index 7d9aa6e..e29a2d8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,8 @@ import components from "./components"; +import Vue from "vue"; +import VueInteractJs from "vue-interactjs"; + +Vue.use(VueInteractJs); const plugin = { install(Vue) { -- GitLab