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

Merge branch 'multiple-items-y' into 'main'

Overlapping items in a column

See merge request !11
parents c41c8ebc 9374568a
No related branches found
No related tags found
1 merge request!11Overlapping items in a column
Pipeline #142026 passed
......@@ -15,6 +15,7 @@ module.exports = {
"/examples/Disabled.md",
"/examples/DisabledItems.md",
"/examples/Responsive.md",
"/examples/MultipleItemsY.md",
],
},
],
......
# Example 9: Multiple Items per field
Grid with multiple items per slot (overlaps only in y direction possible,
width of every item has to be `1`). The items are placed in the grid automatically.
To allow this behaviour, the grid component has to receive the prop `multiple-items-y` with the value `true`.
<ClientOnly>
<script setup>
import Example9MultipleItemsY from "../../example/src/Example9MultipleItemsY.vue";
</script>
<Example9MultipleItemsY />
</ClientOnly>
......@@ -244,3 +244,17 @@ Examples for such a mechanism can be found in Examples 4 and 5.
:::
To handle movements from one grid to another, the attributes `gridId` and `originGridId` of the event will help.
## Overlapping grid items
If two items overlap, the one which is defined later in the array will be on top of the other one.
They cannot be dragged.
If you want to have overlapping items which can be dragged, there exists the `multipleItemsY` prop.
If this is set to `true`, items can be dragged on top of each other. The items will be stacked horizontally.
This is useful for e.g. a calendar-like frontend.
::: danger
If `multipleItemsY` is set to `true`, the `w` property of all items has to be set to `1`.
Otherwise, this will lead to unexpected behaviour.
:::
......@@ -7,6 +7,7 @@ import Example5Colors from "./Example5Colors.vue";
import Example6Disabled from "./Example6Disabled.vue";
import Example7DisabledItems from "./Example7DisabledItems.vue";
import Example8Responsive from "./Example8Responsive.vue";
import Example9MultipleItemsY from "./Example9MultipleItemsY.vue";
</script>
<template>
......@@ -88,6 +89,13 @@ import Example8Responsive from "./Example8Responsive.vue";
<h2>Example 8:</h2>
<p>The grid is responsive. Try resizing it below:</p>
<example8-responsive></example8-responsive>
<h2>Example 9:</h2>
<p>
Grid with multiple items per slot (overlaps only in y direction possible,
width of every item has to be <kbd>1</kbd>)
</p>
<example9-multiple-items-y />
</div>
</template>
......
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "Example9MultipleItemsY",
data() {
return {
items: [
{ x: 1, y: 4, w: 1, h: 1, key: "item 1" },
{ x: 1, y: 1, w: 1, h: 1, key: "item 2" },
{ x: 1, y: 2, w: 1, h: 2, key: "item 3" },
{ x: 1, y: 3, w: 1, h: 1, key: "item 4" },
{ x: 1, y: 4, w: 1, h: 2, key: "item 5" },
{ x: 1, y: 2, w: 1, h: 3, key: "item 6" },
{ x: 2, y: 2, w: 1, h: 3, key: "item 7" },
{ x: 2, y: 1, w: 1, h: 3, key: "item 8" },
{ x: 2, y: 4, w: 1, h: 2, key: "item 9" },
{ x: 2, y: 7, w: 1, h: 3, key: "item 10" },
{ x: 2, y: 3, w: 1, h: 1, key: "item 11" },
],
};
},
});
</script>
<template>
<div class="parent">
<drag-grid
v-model="items"
:cols="2"
:rows="8"
class="grid"
multiple-items-y
>
<template #item="{ key }">
<div class="item">
{{ key }}
</div>
</template>
</drag-grid>
</div>
</template>
<style scoped>
.parent {
min-height: 600px;
}
.grid {
border: #97fa56 2px solid;
width: clamp(20vw, 500px, 80vw);
aspect-ratio: 1;
}
.item {
background: #325442;
color: #97fa56;
border: #97fa56 2px dotted;
width: 100%;
height: 100%;
}
</style>
......@@ -79,6 +79,16 @@ export default {
required: true,
},
disabled: Boolean,
numSiblings: {
type: Number,
required: false,
default: 1,
},
siblingIndex: {
type: Number,
required: false,
default: 0,
},
},
computed: {
isInGrid() {
......@@ -102,6 +112,12 @@ export default {
cursor() {
return this.disabled ? "auto" : "grab";
},
width() {
return 100 / this.numSiblings + "%";
},
left() {
return (100 / this.numSiblings) * this.siblingIndex + "%";
},
dataTransferString() {
return JSON.stringify(this.dataTransfer);
},
......@@ -128,5 +144,8 @@ export default {
calc(1px * v-bind(offsetY))
);
z-index: v-bind(zIndex);
width: v-bind(width);
left: v-bind(left);
position: relative;
}
</style>
......@@ -22,13 +22,15 @@
</div>
<DragContainer
v-for="item in value"
v-for="item in items"
:key="item.key"
:drag-i-d="item.key"
:x="getInt('x', item)"
:y="getInt('y', item)"
:w="getInt('w', item)"
:h="getInt('h', item)"
:num-siblings="item.numSiblings"
:sibling-index="item.siblingIndex"
:data="getObject('data', item)"
:context="context"
:grid-id="gridId"
......@@ -127,6 +129,11 @@ export default {
required: false,
default: false,
},
multipleItemsY: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
positionAllowed(x, y, key) {
......@@ -142,17 +149,19 @@ export default {
return false;
}
for (let item of this.value) {
if (key === item.key) continue;
if (
x >= this.getInt("x", item) &&
x < this.getInt("x", item) + this.getInt("w", item)
) {
if (!this.multipleItemsY) {
for (let item of this.value) {
if (key === item.key) continue;
if (
y >= this.getInt("y", item) &&
y < this.getInt("y", item) + this.getInt("h", item)
x >= this.getInt("x", item) &&
x < this.getInt("x", item) + this.getInt("w", item)
) {
return false;
if (
y >= this.getInt("y", item) &&
y < this.getInt("y", item) + this.getInt("h", item)
) {
return false;
}
}
}
}
......@@ -299,6 +308,52 @@ export default {
context: this.context,
};
},
items() {
if (!this.multipleItemsY) return this.value;
if (this.value.some((item) => item.w > 1)) {
console.warn(
"You are using multipleItemsY but some items have a width greater than 1.",
"This is not supported and will lead to unexpected behaviour."
);
}
// calculate numSiblings for each field
// First dimension: the columns
let xSiblings = [];
this.value.forEach((item) => {
for (let i = 0; i < item.h; i++) {
if (!xSiblings[item.x]) xSiblings[item.x] = [];
if (xSiblings[item.x][item.y + i] === undefined) {
xSiblings[item.x][item.y + i] = 0;
}
xSiblings[item.x][item.y + i]++;
}
});
let xSiblingsCopy = structuredClone(xSiblings);
return this.value.map((item) => {
let numSiblings = xSiblings[item.x]
.filter((i, index) => {
return index >= item.y && index < item.y + item.h;
})
.reduce((a, b) => Math.max(a, b), 0);
for (let i = item.y; i < item.h + item.y; i++) {
xSiblingsCopy[item.x][i]--;
}
let offset = xSiblingsCopy[item.x]
.filter((i, index) => {
return index >= item.y && index < item.y + item.h;
})
.reduce((a, b) => Math.max(a, b), 0);
return {
...item,
numSiblings: numSiblings,
siblingIndex: offset,
};
});
},
},
};
</script>
......
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