Skip to content
Snippets Groups Projects
Commit 6eccaaed authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch '8-overview-over-dragged-elements' into 'main'

Resolve "Overview over dragged elements"

Closes #8

See merge request !15
parents 5f3332e1 4e02e3e2
No related branches found
No related tags found
1 merge request!15Resolve "Overview over dragged elements"
Pipeline #152897 passed
# Vue Draggable Grid
A library for Vue2 which allows drag&drop functionality in a grid context.
## Installation
```bash
npm install vue-draggable-grid
```
## Usage
Include the library in your project:
```javascript
import draggableGrid from "vue-draggable-grid";
Vue.use(draggableGrid);
// Now create your app as usual
```
An example usage could look like this:
```vue
<template>
<drag-grid v-model="items" :cols="4" :rows="4">
<template #item="item">
{{ item.data.text }}
</template>
</drag-grid>
</template>
<script>
export default {
name: "YourComponent",
data() {
return {
items: [
{
x: 1,
y: 3,
w: 2,
h: 2,
key: "item1",
data: { text: "Hello world 1" },
},
{
x: 2,
y: 2,
w: 2,
h: 1,
key: "item2",
data: { text: "Hello world 2" },
},
{
x: 3,
y: 1,
w: 1,
h: 1,
key: "item3",
data: { text: "Hello world 3" },
},
],
};
},
};
</script>
```
For more examples visit the [examples folder](./example), or read the [documentation](./docs).
Repository: [https://edugit.org/AlekSIS/libs/vue-draggable-grid/](https://edugit.org/AlekSIS/libs/vue-draggable-grid/)
Built by [Julian Leucker](https://edugit.org/ZugBahnHof).
......@@ -16,6 +16,7 @@ module.exports = {
"/examples/DisabledItems.md",
"/examples/Responsive.md",
"/examples/MultipleItemsY.md",
"/examples/Animals.md",
],
},
],
......
# Example 10: Animals
This example shows, how one can find out, if the user is dragging an item,
which item is being dragged and which grid is being dragged over. This is
an example for the proper `isDraggedOver` and the
`containerDragStart` and `containerDragEnd` events.
<ClientOnly>
<script setup>
import ExampleAOverlay from "../../example/src/ExampleAOverlay.vue";
</script>
<ExampleAOverlay />
</ClientOnly>
......@@ -8,6 +8,7 @@ import Example6Disabled from "./Example6Disabled.vue";
import Example7DisabledItems from "./Example7DisabledItems.vue";
import Example8Responsive from "./Example8Responsive.vue";
import Example9MultipleItemsY from "./Example9MultipleItemsY.vue";
import ExampleAOverlay from "./ExampleAOverlay.vue";
</script>
<template>
......@@ -96,6 +97,15 @@ import Example9MultipleItemsY from "./Example9MultipleItemsY.vue";
width of every item has to be <kbd>1</kbd>)
</p>
<example9-multiple-items-y />
<h2>Example 10:</h2>
<p>
This example shows, how one can find out, if the user is dragging an item,
which item is being dragged and which grid is being dragged over. This is
an example for the proper <kbd>isDraggedOver</kbd> and the
<kbd>containerDragStart</kbd> and <kbd>containerDragEnd</kbd> events.
</p>
<example-a-overlay />
</div>
</template>
......
<script>
import DragGrid from "../../src/DragGrid.vue";
function initialState() {
return {
items: [
{
key: "key1",
x: 1,
y: 5,
w: 1,
h: 1,
data: { name: "Cat", grid: false },
},
{
key: "key2",
x: 4,
y: 3,
w: 1,
h: 1,
data: { name: "Penguin", grid: false },
},
{
key: "key3",
x: 2,
y: 3,
w: 1,
h: 1,
data: { name: "Dog", grid: false },
},
{
key: "key4",
x: 5,
y: 4,
w: 1,
h: 1,
data: { name: "Chinchilla", grid: false },
},
{
key: "key5",
x: 5,
y: 1,
w: 1,
h: 1,
data: { name: "Iguana", grid: false },
},
{
key: "key6",
x: 3,
y: 4,
w: 1,
h: 1,
data: { name: "Axolotl", grid: true },
disabled: true,
},
],
overlays: [
{ key: "overlay1", x: 2, y: 2, animal: "Dog" },
{ key: "overlay2", x: 3, y: 5, animal: "Iguana" },
{ key: "overlay3", x: 4, y: 2, animal: "Chinchilla" },
{ key: "overlay4", x: 2, y: 4, animal: "Penguin" },
{ key: "overlay5", x: 4, y: 4, animal: "Cat" },
],
dragged: {
key1: false,
key2: false,
key3: false,
key4: false,
key5: false,
key6: false,
},
showOverlayOnlyOnDragover: false,
showAllHighlights: false,
};
}
export default {
name: "ExampleAOverlay",
components: {
DragGrid,
},
data() {
return initialState();
},
methods: {
handleItemChanged(element, gridId) {
if (gridId === "second-grid" && element.originGridId === "second-grid") {
// Disable movement inside the second grid
return;
}
let overlay = this.overlays.find((o) => o.animal === element.data.name);
this.items.map((item) => {
if (item.key === element.key) {
item.data.grid = gridId === "ov-grid";
item.x = element.x;
item.y = element.y;
item.disabled =
overlay && overlay.x === element.x && overlay.y === element.y;
}
return item;
});
if (overlay && overlay.x === element.x && overlay.y === element.y) {
this.overlays = this.overlays.filter((o) => o.key !== overlay.key);
}
},
reset() {
Object.assign(this.$data, initialState());
},
handleContainerDrag(element, type) {
this.dragged[element.key] = type === "start";
},
},
computed: {
gridOneItems() {
return this.items.filter((item) => item.data.grid);
},
gridTwoItems() {
return this.items
.filter((item) => !item.data.grid)
.map((item) => ({
...item,
x: () => 0,
y: () => 0,
disabled: false,
}));
},
computedOverlays() {
if (this.showAllHighlights) {
return Object.values(this.dragged).some((obj) => !!obj)
? this.overlays
: [];
}
return this.overlays.filter(
(o) =>
this.dragged[
((a) => (a ? a.key : a))(
// Get the key of the dragged item or null
this.items.find((item) => item.data.name === o.animal),
)
],
);
},
},
};
</script>
<template>
<div>
<drag-grid
:value="gridOneItems"
:cols="5"
:rows="5"
id="ov-grid"
context="animals"
grid-id="ov-grid"
@itemChanged="handleItemChanged($event, 'ov-grid')"
@containerDragStart="handleContainerDrag($event, 'start')"
@containerDragEnd="handleContainerDrag($event, 'end')"
>
<template #item="{ rawItem }">
<div
:class="{
container: true,
disabled: rawItem.disabled,
dragged: dragged[rawItem.key],
}"
>
<span>{{ rawItem.data.name }}</span>
</div>
</template>
<template #default="{ isDraggedOver }">
<div
class="container goal"
v-for="goal in computedOverlays"
v-show="isDraggedOver || !showOverlayOnlyOnDragover"
:key="goal.key"
:style="{
gridColumn: goal.x + ' / span 1',
gridRow: goal.y + ' / span 1',
}"
>
{{ goal.animal }} here!
</div>
</template>
</drag-grid>
<drag-grid
:value="gridTwoItems"
:cols="1"
:rows="5"
id="second-grid"
context="animals"
grid-id="second-grid"
no-highlight
@itemChanged="handleItemChanged($event, 'second-grid')"
@containerDragStart="handleContainerDrag($event, 'start')"
@containerDragEnd="handleContainerDrag($event, 'end')"
>
<template #item="{ rawItem }">
<div
:class="{
container: true,
disabled: rawItem.disabled,
dragged: dragged[rawItem.key],
}"
>
<span>{{ rawItem.data.name }}</span>
</div>
</template>
</drag-grid>
<span>
<button @click="reset">Reset</button><br />
<button @click="showOverlayOnlyOnDragover = !showOverlayOnlyOnDragover">
Show overlay
{{ showOverlayOnlyOnDragover ? "always" : "only on dragover" }}</button
><br />
<button @click="showAllHighlights = !showAllHighlights">
{{
showAllHighlights
? "Only show overlay for dragged item"
: "Show overlay for all items"
}}
</button>
</span>
</div>
</template>
<style scoped>
#ov-grid,
#second-grid {
max-width: 600px;
border-radius: 1em;
border: 0.2em solid #e0e0e0;
box-shadow: 0.2em 0.2em 0 0.1em #bdc3c7;
padding: 0.3em 0.4em 0.4em 0.3em;
}
#second-grid {
width: fit-content;
height: 100%;
}
div {
display: flex;
flex-direction: row;
gap: 1em;
align-items: stretch;
}
.container {
background: #3498db;
color: #ecf0f1;
width: 100%;
height: 100%;
user-select: none;
text-align: center;
border-radius: 0.6em;
box-shadow: #2980b9 0.1em 0.1em 0 0.1em;
min-height: 3rem;
display: flex;
justify-content: center;
align-items: center;
}
.container.disabled {
background: #bdc3c7;
box-shadow: #95a5a6 0.1em 0.1em 0 0.1em;
}
.container.goal {
background: #2ecc71;
box-shadow: #27ae60 0.1em 0.1em 0 0.1em;
animation: breathe 2s infinite;
}
@keyframes breathe {
0% {
background: #2ecc71;
box-shadow: #27ae60 0.1em 0.1em 0 0.1em;
}
50% {
background: #a3d9a5;
box-shadow: #2ecc71 0.1em 0.1em 0 0.1em;
}
100% {
background: #2ecc71;
box-shadow: #27ae60 0.1em 0.1em 0 0.1em;
}
}
.container.dragged {
animation: glare 2s infinite;
color: #222;
background: #f1c40f;
box-shadow: #f39c12 0.1em 0.1em 0 0.1em;
}
@keyframes glare {
0% {
background: #f1c40f;
box-shadow: #f39c12 0.1em 0.1em 0 0.1em;
}
50% {
background: #f7dd73;
box-shadow: #f1c40f 0.1em 0.1em 0 0.1em;
}
100% {
background: #f1c40f;
box-shadow: #f39c12 0.1em 0.1em 0 0.1em;
}
}
button {
margin-top: 1em;
padding: 0.5em 1em;
border-radius: 0.5em;
border: 0.2em solid #e0e0e0;
background: #ecf0f1;
color: #3498db;
font-weight: bold;
cursor: pointer;
}
</style>
{
"name": "vue-draggable-grid",
"version": "0.2.0",
"version": "0.4.0",
"scripts": {
"build": "vite build",
"example:build": "vite build example",
......
......@@ -15,6 +15,7 @@
<script>
export default {
name: "DragContainer",
emits: ["dragstart", "dragmove", "dragend"],
methods: {
handleDragStart(event) {
if (this.isDisabled) return;
......@@ -33,15 +34,18 @@ export default {
};
// Now the element is on top of everything else inside the grid (not on top of other grids though)
this.zIndex = 999999;
this.$emit("dragstart", this.dataTransfer);
},
handleDragEnd() {
this.offsetX = 0;
this.offsetY = 0;
this.zIndex = "auto";
this.$emit("dragend", this.dataTransfer);
},
handleDragMove(event) {
this.offsetX += event.dx;
this.offsetY += event.dy;
this.$emit("dragmove", this.dataTransfer);
},
},
props: {
......
......@@ -35,6 +35,8 @@
:context="context"
:grid-id="gridId"
:disabled="disabled || loading || item.disabled"
@dragstart="emitContainerDragStart"
@dragend="emitContainerDragEnd"
>
<slot v-bind="transformItem(item)" :raw-item="item" name="item">
<dl>
......@@ -59,7 +61,7 @@
<slot name="disabledField" :is-dragged-over="isDraggedOver"></slot>
</GridItem>
</template>
<slot></slot>
<slot :is-dragged-over="isDraggedOver"></slot>
</template>
</interact>
</template>
......@@ -75,7 +77,7 @@ export default {
GridItem,
DragContainer,
},
emits: ["input", "itemChanged"],
emits: ["input", "itemChanged", "containerDragStart", "containerDragEnd"],
data() {
return {
isDraggedOver: false,
......@@ -312,6 +314,12 @@ export default {
newItem.data = this.getObject("data", item);
return newItem;
},
emitContainerDragStart(dataTransfer) {
this.$emit("containerDragStart", dataTransfer);
},
emitContainerDragEnd(dataTransfer) {
this.$emit("containerDragEnd", dataTransfer);
},
},
computed: {
gridData() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment