I'm interested in how I can make a grid with an undetermined amount of columns and rows that I can put inside another div and have it not spill into others objects or mess with the parent size.
I want it to be square and I'm using Tailwind CSS but I can adapt to SCSS or vanilla CSS. Also I want it to be touchable/moveable with a mouse on desktop and touch capable devices.
How would I go about accomplishing this?
CodePudding user response:
Assuming I've understood your question correctly, here is one way you could do it. I haven't tested it with a touch device but it shouldn't be hard to modify it to also respond to touch events.
const items = [
['a0', 'a1', 'a2'],
['b0', 'b1', 'b2'],
['c0', 'c1', 'c2']
];
let html = '';
for (let rowItems of items) {
html = '<div >';
for (let item of rowItems) {
html = '<div >';
html = item;
html = '</div>';
}
html = '</div>';
}
const viewElem = document.querySelector('#view');
const outputElem = document.querySelector('#output');
outputElem.innerHTML = html;
let mouseStartPos = null;
let startOffset = null;
outputElem.addEventListener('mousedown', e => {
outputElem.classList.remove('animate');
mouseStartPos = {
x: e.clientX,
y: e.clientY
};
startOffset = {
x: outputElem.offsetLeft - viewElem.offsetLeft,
y: outputElem.offsetTop - viewElem.offsetTop
};
});
window.addEventListener('mouseup', e => {
mouseStartPos = null;
startOffset = null;
outputElem.classList.add('animate');
const xGridOffset = -1 * Math.max(0, Math.min(Math.round((outputElem.offsetLeft - viewElem.offsetLeft) / -100), items.length - 1));
const yGridOffset = -1 * Math.max(0, Math.min(Math.round((outputElem.offsetTop - viewElem.offsetTop) / -100), items[0].length - 1));
outputElem.style.left = `${xGridOffset * 100}px`;
outputElem.style.top = `${yGridOffset * 100}px`;
});
window.addEventListener('mousemove', e => {
if (mouseStartPos) {
const xOffset = mouseStartPos.x - e.clientX;
const yOffset = mouseStartPos.y - e.clientY;
outputElem.style.left = `${-1 * xOffset startOffset.x}px`;
outputElem.style.top = `${-1 * yOffset startOffset.y}px`;
}
});
#view {
width: 100px;
height: 100px;
overflow: hidden;
border: 2px solid blue;
}
#output {
position: relative;
}
.row {
display: flex;
}
.item {
display: flex;
min-width: 100px;
width: 100px;
height: 100px;
box-sizing: border-box;
justify-content: center;
align-items: center;
border: 1px solid red;
}
#output.animate {
transition: left 1s ease 0s, top 1s ease 0s;
}
Drag it!<br/>
<br/>
<div id="view">
<div id="output"></div>
</div>