'Automatically scroll to a grid cell under cursor during zoom in/out
I have a grid of cells which can be zoom in/out via mouse wheel by changing cells size. It works ok, except it doesn't "follow" grid position on the screen when zooming in/out.
Here is an example snippet, if you position cursor on cell 13 and start zoom w/mouse wheel, the cell moves away from the cursor.
let cols = 5,
rows = 5,
zoom = 12,
zoomMin = 1,
zoomMax = 25,
mouseDown,
clientX,
clientY;
for(let i = 0, cell = document.createElement("div"); i < cols*rows; i++)
{
cell.textContent = i + 1;
table.appendChild(cell);
cell = cell.cloneNode(false);
}
document.body.style.setProperty("--cols", cols);
document.body.style.setProperty("--rows", rows);
setZoom(zoom);
table.addEventListener("wheel", e =>
{
e.preventDefault();
e.stopPropagation();
zoom = Math.min(zoomMax, Math.max(zoomMin, zoom + (e.deltaY < 0 ? 1 : -1)));
setZoom(zoom);
}, {passive:false});
table.addEventListener("mousedown", e =>
{
e.preventDefault();
table.classList.add("drag");
mouseDown = e;
({clientX, clientY} = e);
window.addEventListener("mouseup", onMouseUp);
window.addEventListener("mousemove", onMouseMove);
});
function onMouseMove (e)
{
if (e.clientX == clientX && e.clientY == clientY)
return;
table.scrollBy(clientX - e.clientX, clientY - e.clientY);
({clientX, clientY} = e);
}
function onMouseUp(e)
{
table.classList.remove("drag");
window.removeEventListener("mouseup", onMouseUp);
window.removeEventListener("mousemove", onMouseMove);
}
function setZoom(z)
{
document.body.style.setProperty("--zoom", ((z/10*z/10) + 1) +"em");
}
#table
{
display: inline-grid;
grid-template-columns: repeat(var(--cols), 1fr);
text-align: center;
max-width: calc(2em * var(--cols) + 0.4em);
max-height: calc(2em * var(--rows) + 0.4em);
overflow: auto;
padding: 1px 0 0 1px;
cursor: grab;
}
#table.drag
{
cursor: grabbing;
}
#table > div
{
border: 1px solid black;
margin-left: -1px;
margin-top: -1px;
width: var(--zoom);
height: var(--zoom);
line-height: var(--zoom);
padding: 0.5em;
}
<div id="table"></div>
My current thought of steps needed to follow cell under cursor during zoom:
- get cell under cursor
- get rectangle of the cell
- get position of the cell relative to top-left corner of the table
- get position of the cursor relative to top-left corner of the cell (in percent)
- get position of the cursor relative to top-left corner of the table (in percent)
- change zoom
- get new position of the cell relative to top-left corner of the table
- get new position of the cursor relative to top-left corner of the table
- based on percent from step 5, get new cursor position relative to top-left corner of the table
- based on percent from step 4, get new top-left corner of the cell relative to the cursor
- calculate needed scroll position of the cell based on step 3
- scroll table to result of step 11
This is quite complicated, and I hope there is a better/simpler formula for this.
Any tips are appreciated
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
