2017-06-19 22 views
2

我正在构建一个网格UI,用户应该能够点击单元格来缩放它们。如何缩放多个div并留在容器内?

所需的行为:

  • 细胞应向外扩展的容器和被裁切*。
  • 单元格可以重叠其他单元格(缩放时)。
  • (只有一个单元需要一次缩放,这不是我们主要关心的问题)。

*左:恶意行为(细胞O的部分数据丢失)。 右:期望的行为 enter image description here

我的方法:

很显然,我可以transform: scale() translate()在同一时间,以达到期望的结果。 您可以使用单元格NtranslateY(22px))查看此内容。

问题:

这种方法不能很好地扩展到9个细胞(更不用说90,这是我的实际使用情况)。

容器必须overflow: hidden。滚动等不是一种选择。

我的问题(S):

这感觉就像在解决一些必须有人已经解决了已经编程一个相当粗糙的尝试。

有没有更好的方法来构建这样的用户界面?(我打开插件或其他方法)。

如果不是,在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>

+0

感谢的@Akshay,它的工作原理。不幸的是,它禁用第二次点击(完全恢复“缩放”)。 –

回答

0

我设置了一个函数,用于评估单元格是否在网格的边界(任何边界)附近。如果是这种情况,在单元格上注入一个样式,设置一个变换样式属性,使其在缩放时沿边框的相反方向移动。

这是一个快速和肮脏的方法,显然有改进的余地。

$(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>

+1

谢谢@vals!使用'.clientWidth' /'.clientHeight'和'.offset ...'属性是个好主意。问题是单元格“C”。如果它位于中间,它将用'+ ='bottom'even转换。 –

+0

现在工作正常。我使用offsetTop来获取相对于网格的顶部坐标,并且这需要网格被定位。添加位置:相对于它解决了问题 – vals

+0

我能够将您的方法适用于我的用例(小增加),再次感谢@vals。 –

1

我创建为一个概念证明类似的东西。我认为这可能有助于您指出正确的方向。看看这里的演示:https://codepen.io/RTakes/pen/aWejOy

这就是我在处理缩放时如何处理居中。它会根据当前位置计算要动画的位置。

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 
    } 
} 
+1

感谢@RickTakes!模态对话框的问题在于它们不断地中断用户交互......必须有更直观的方式。 –