Reputation: 105
I'm building a grid UI, where users should be able to click on cells to scale them.
Desired Behavior:
*Left: Unwanted behavior (parts of cell O
are gone).
Right: Desired behavior
My Approach:
Obviously, I can transform: scale() translate()
at the same time, to reach the desired result.
You can see this with cell N
(translateY(22px)
).
Problems:
This approach doesn't scale well to 9 cells (let alone 90, which is my actual use case).
The container must be overflow: hidden
. Scrolling etc. are not an option.
My Question(s):
This feels like a pretty crude attempt at solving something that someone must have solved already programmatically.
Is there a better way to build such a UI? (I'm open to plugins or other approaches).
If not, what's a good way to script this in jQuery?
$(function() {
$(".cell").click(function() {
$(this).toggleClass("zoom-in");
});
});
.grid {
width: 300px;
height: 300px;
background: gray;
overflow: hidden;
}
.cell {
background: tomato;
width: 30%;
height: 30%;
margin: 5px;
float: left;
text-align: center;
z-index: 999;
transition: all 0.2s ease-in-out;
}
.zoom-in {
transform: scale(2);
transition: all 0.2s ease-in-out;
}
#nord {
background-color: white;
}
#nord.zoom-in {
transform: scale(2) translateY(22px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div> Click white and red cells to scale. Click again to revert.</div>
<div class="grid">
<div class="cell">NW</div>
<div id="nord" class="cell">N</div>
<div class="cell">NO</div>
<div class="cell">W</div>
<div class="cell">C</div>
<div class="cell">O</div>
<div class="cell">SW</div>
<div class="cell">S</div>
<div class="cell">SO</div>
</div>
Upvotes: 2
Views: 487
Reputation: 64164
I have set up a function that evaluates if the cell is near the border (any border) of the grid. If this is the case, injects a style on the cell setting a transform style property that will make it move in the opposite direction of the border when zoomed.
This is a quick and dirty approach, obviously there is room for improvement.
$(function() {
$(".cell").click(function() {
$(this).toggleClass("zoom-in");
});
});
document.addEventListener('DOMContentLoaded', setEvent, false);
function setEvent () {
var elements = document.getElementsByClassName('cell');
var grid = elements[0].parentElement;
var gridWidth = grid.clientWidth;
var gridHeight = grid.clientHeight;
var maxGrid = {
right: gridWidth,
bottom: gridHeight
}
for (var n = 0; n < elements.length; n++) {
evaluate (elements[n], maxGrid);
}
}
function evaluate (element, maxGrid) {
var transOrigin = "";
var left = element.offsetLeft;
if (left < element.clientWidth) {
transOrigin += 'left ';
}
if (left + element.clientWidth > maxGrid.right - element.clientWidth) {
transOrigin += 'right ';
}
var top = element.offsetTop;
if (top < element.clientHeight) {
transOrigin += 'top';
}
if (top + element.clientHeight > maxGrid.bottom - element.clientHeight) {
transOrigin += 'bottom';
}
element.style.transformOrigin = transOrigin;
}
.grid {
width: 300px;
height: 300px;
background: gray;
overflow: hidden;
position: relative; /* important to have this */
}
.cell {
background: tomato;
width: 30%;
height: 30%;
margin: 5px;
float: left;
text-align: center;
z-index: 999;
transition: all 0.2s ease-in-out;
}
.zoom-in {
transform: scale(2);
transition: all 0.2s ease-in-out;
}
#nord {
background-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div> Click white and red cells to scale. Click again to revert.</div>
<div class="grid">
<div class="cell">NW</div>
<div id="nord" class="cell">N</div>
<div class="cell">NO</div>
<div class="cell">W</div>
<div class="cell">C</div>
<div class="cell">O</div>
<div class="cell">SW</div>
<div class="cell">S</div>
<div class="cell">SO</div>
</div>
Upvotes: 0
Reputation: 1197
I created something similar as a proof of concept. I think it may help point you in the right direction. Check out the demo here: https://codepen.io/RTakes/pen/aWejOy
This is how I handled centering when also scaling. It calculates the position to animate to, from it's current position.
function computeCenterPosition(element, sizeFactor = 0) {
const screenCenter = {
x: window.innerWidth / 2,
y: window.innerHeight / 2
};
const elCenter = {
x: (element.offsetWidth / 2) + element.offsetLeft,
y: (element.offsetHeight / 2) + element.offsetTop
};
return {
x: (elCenter.x - screenCenter.x) * -1,
y: (elCenter.y - screenCenter.y) * -1
}
}
Upvotes: 1