Skip to content

Instantly share code, notes, and snippets.

@tobyshooters
Created March 25, 2022 14:59
Show Gist options
  • Save tobyshooters/7e05535115ec6ac0eb7eb1defd1119de to your computer and use it in GitHub Desktop.
Save tobyshooters/7e05535115ec6ac0eb7eb1defd1119de to your computer and use it in GitHub Desktop.
infinite.html
<style>
body {
background: conic-gradient(from 90deg at 1px 1px, #fdf6e3 90deg, #eee8d5 0deg);
background-position: 0px 0px;
background-size: 40px 40px;
overflow: hidden;
}
.elem {
position: absolute;
display: flex;
background-color: #fdf6e3;
}
#add {
position: absolute;
bottom: 20;
right: 20;
}
#explainer {
position: absolute;
width: 400px;
top: 50;
left: 50;
}
</style>
<button id="add"/>Add square</button>
<span id="explainer">
You can make an infinite canvas in vanilla Javascript by sticking everything
into an absolute positioned div, and then writing some mouse and wheel
handlers. Drag me! Pan! Don't forget to inspect the code!
</span>
<script>
window.onload = () => {
const elems = {};
const makeDraggable = (id, content) => {
let div = document.createElement("div");
div.classList.toggle("elem");
div.appendChild(content);
div.style.top = content.style.top;
div.style.left = content.style.left;
// Store element's state in a global object;
elems[id] = { node: div };
const mousemove = (e) => {
const dx = e.clientX - elems[id]._x;
const dy = e.clientY - elems[id]._y;
div.style.top = `${div.offsetTop + dy}px`;
div.style.left = `${div.offsetLeft + dx}px`;
elems[id]._x = e.clientX;
elems[id]._y = e.clientY;
}
const mouseup = () => {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
}
div.addEventListener('mousedown', (e) => {
e.preventDefault();
elems[id]._x = e.clientX;
elems[id]._y = e.clientY;
document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
});
return div;
}
document.body.addEventListener("wheel", (e) => {
// Move all the elements
Object.values(elems).forEach(elem => {
const child = elem.node;
child.style.top = `${child.offsetTop + e.deltaY}px`;
child.style.left = `${child.offsetLeft + e.deltaX}px`;
})
// Move background
const data = (document.body.style.backgroundPosition || "0px 0px").split(" ");
const currX = parseInt(data[0].slice(0, -2));
const currY = parseInt(data[1].slice(0, -2));
document.body.style.backgroundPosition = `${currX + e.deltaX}px ${currY + e.deltaY}px`;
})
const getRandomSquare = () => {
const square = document.createElement("div");
square.style.backgroundColor = ["green", "silver", "salmon"][Math.floor(3 * Math.random())];
square.style.width = "100px";
square.style.height = "100px";
square.style.top = (document.body.scrollHeight - 100) * Math.random();
square.style.left = (document.body.scrollWidth - 100) * Math.random();
return square;
}
// Add squares to background with button
document.getElementById("add").onclick = () => {
const id = Object.keys(elems).length;
const square = getRandomSquare();
const draggableSquare = makeDraggable(id, square);
document.body.appendChild(draggableSquare);
}
const explainer = document.getElementById("explainer");
const draggableExplainer = makeDraggable(0, explainer);
document.body.appendChild(draggableExplainer);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment