<div class="tileContainer">
</div>
body{background-color:#1A1919;text-align:center;}
.tileContainer{
border:10px solid black;
display:inline-block;
position:relative;
width:1024px;
height:768px;
overflow:hidden;
box-sizing:border-box;
}
.tile{
position:relative;
vertical-align:top;
display:inline-block;
border-right:1px solid rgba(0, 0, 0, 0.5);
border-bottom:1px solid rgba(0, 0, 0, 0.5);
box-sizing:border-box;
}
.tile:after{
content:"";
background-color:#cc1c32;
width:6px;
height:6px;
position:absolute;
top:100%;
right:0px;
transform:translate(50%, -50%);
z-index:2;
line-height:1;
}
/*-- no grid --*/
.noGrid .tile{
border-right:0px solid rgba(0, 0, 0, 0.5);
border-bottom:0px solid rgba(0, 0, 0, 0.5);
}
.noGrid .tile:after{
content:none;
}
// options
var options = {
imgSrc : "https://unsplash.it/g/1024/768?image=887",
containerName : "tileContainer",
grid : false,
tileWidth : 80,
tileHeight : 80,
mouseTrail:true
}
// ----------------------------------------------------------
var tileWidth, tileHeight, numTiles, tileHolder, tileContainer;
var directionX, directionY;
var imgOriginalWidth, imgOriginalHeight;
var imgCoverWidth, imgCoverHeight;
var imageLoaded = false;
numTiles=0;
tileWidth = options.tileWidth;
tileHeight = options.tileHeight;
tileContainer = document.getElementsByClassName(options.containerName)[0];
function init(){
if(options.grid == false)tileContainer.className += " noGrid";
//preload image and get original image size, then create tiles
var image = new Image();
image.src = options.imgSrc;
image.onload = function(e){
imageLoaded = true;
imgOriginalWidth = e.currentTarget.width;
imgOriginalHeight = e.currentTarget.height;
createTileHolder();
checkTileNumber();
positionImage();
addListeners();
};
}
function resizeHandler()
{
if(imageLoaded == false)return;
//not working yet
checkTileNumber();
positionImage();
}
function createTileHolder(){
tileHolder = document.createElement('div');
tileHolder.className = "tileHolder";
tileHolder.style.position = "absolute";
tileHolder.style.top = "50%";
tileHolder.style.left = "50%";
tileHolder.style.transform = "translate(-50%, -50%)";
tileContainer.appendChild(tileHolder);
}
function checkTileNumber()
{
tileHolder.style.width = Math.ceil(tileContainer.offsetWidth / tileWidth) * tileWidth + "px";
tileHolder.style.height = Math.ceil(tileContainer.offsetHeight / tileHeight) * tileHeight + "px";
var tilesFitInWindow = Math.ceil(tileContainer.offsetWidth / tileWidth) * Math.ceil(tileContainer.offsetHeight / tileHeight);
if(numTiles < tilesFitInWindow){
for (var i=0, l=tilesFitInWindow-numTiles; i < l; i++){
addTiles();
}
}else if(numTiles > tilesFitInWindow){
for (var i=0, l=numTiles-tilesFitInWindow; i < l; i++){
removeTiles();
}
}
}
function addTiles()
{
var tile = document.createElement('div');
tile.className = "tile";
//maintain aspect ratio
imgCoverWidth = tileContainer.offsetWidth;
imgCoverHeight = tileContainer.offsetHeight;
if(imgOriginalWidth > imgOriginalHeight){
imgCoverHeight = imgOriginalHeight / imgOriginalWidth * imgCoverWidth;
}else{
imgCoverWidth = imgOriginalWidth / imgOriginalHeight * imgCoverHeight;
}
tile.style.background = 'url("'+options.imgSrc+'") no-repeat';
tile.style.backgroundSize = imgCoverWidth + "px " + imgCoverHeight + "px";
tile.style.width = tileWidth + "px";
tile.style.height = tileHeight + "px";
document.querySelectorAll(".tileHolder")[0].appendChild(tile);
tile.addEventListener("mouseover", moveImage);
numTiles++;
}
function removeTiles()
{
var tileToRemove = document.querySelectorAll(".tile")[0];
tileToRemove.removeEventListener("mouseover", moveImage);
TweenMax.killTweensOf(tileToRemove);
tileToRemove.parentNode.removeChild(tileToRemove);
numTiles--;
}
function addListeners(){
if(options.mouseTrail){
document.addEventListener('mousemove', function (event) {
directionX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
directionY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
});
}
}
function positionImage(){
for(var t=0, l=numTiles; t < l; t++)
{
var nowTile = document.querySelectorAll(".tile")[t];
var left = (-nowTile.offsetLeft - (tileHolder.offsetLeft - (tileHolder.offsetWidth/2)));
var top = (-nowTile.offsetTop - (tileHolder.offsetTop - (tileHolder.offsetHeight/2)));
nowTile.style.backgroundPosition = left + "px " + top + "px";
}
}
function resetImage(nowTile){
var left = (-nowTile.offsetLeft - (tileHolder.offsetLeft - (tileHolder.offsetWidth/2)));
var top = (-nowTile.offsetTop - (tileHolder.offsetTop - (tileHolder.offsetHeight/2)));
TweenMax.to(nowTile, 1, {backgroundPosition:left + "px " + top + "px", ease:Power1.easeInOut});
}
function moveImage(e){
var nowTile = e.currentTarget
var minWidth = -tileContainer.offsetWidth+nowTile.offsetWidth;
var minHeight = -tileContainer.offsetHeight+nowTile.offsetHeight;
var nowLeftPos = (-nowTile.offsetLeft - (tileHolder.offsetLeft - (tileHolder.offsetWidth/2)));
var nowTopPos = (-nowTile.offsetTop - (tileHolder.offsetTop - (tileHolder.offsetHeight/2)))
var offset = 60;
var left = nowLeftPos;
var top = nowTopPos;
if(options.mouseTrail){
//direction-aware movement
if(directionX > 0){
left = nowLeftPos + offset;
}else if(directionX < 0){
left = nowLeftPos - offset;
}
if(directionY > 0){
top = nowTopPos + offset;
}else if(directionY < 0){
top = nowTopPos - offset;
}
}else{
//random movement
left = getRandomInt(nowLeftPos - offset , nowLeftPos + offset);
top = getRandomInt(nowTopPos - offset, nowTopPos + offset);
}
// bounds
if(left < minWidth)left=minWidth;
if(left > 0)left=0;
if(top < minHeight)top=minHeight;
if(top > 0)top=0;
//tween
TweenMax.to(nowTile, 1.5, {backgroundPosition:left + "px " + top + "px", ease:Power1.easeOut, onComplete:resetImage, onCompleteParams:[nowTile]});
}
///////////////////////////////////////////////////////////////////
init();
// handle event
//window.addEventListener("optimizedResize", resizeHandler);
////////////////////////UTILS//////////////////////////////////////
//////////////////////////////////////////////////////////////////
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
(function() {
var throttle = function(type, name, obj) {
obj = obj || window;
var running = false;
var func = function() {
if (running) { return; }
running = true;
requestAnimationFrame(function() {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
};
/* init - you can init any event */
throttle("resize", "optimizedResize");
})();
This Pen doesn't use any external CSS resources.