Home > Software engineering >  How to create a scrollable/touchable grid in CSS and JS?
How to create a scrollable/touchable grid in CSS and JS?

Time:06-25

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>

  • Related