I am creating a website for photography, and I want to create a nice "tiled" interface that will look like the interface in the new version of MSN Money Now (note - the new version of the website can only be viewed on Windows 8) - http://t.money .msn.com / now / . I tried to implement this in Javascript.
Here is an example of a page with pre-populated data: http://photoachiever.azurewebsites.net/en
I created Tile groups - each 2 units high, 2 units wide, which can contain either one large square tile, two wide tiles, or four small square tiles. Now, since I want the site to be responsive, I wanted to calculate the optimal block size on the fly in Javascript so that 100% of the space is always filled, and for wider screens, for example, more columns are visible, etc. It works the same on the MSN Money website, but there are two important differences:
1) When my images are uploaded for the first time, I just see them in their highest result right up to the moment when all images are uploaded and JS is executed. On the MSN Money network, only the green area is displayed, and the images appear later, they are already significantly changed. 2) When I resize the window, it is far from fluidity and very noticeable are the cullations and, mainly, the resizing of the image. However, in MSN Money, resizing is very smooth, and even the images seem to just resize without glitches. In addition, they managed to change the font size.
Could you explain to me how the MSN Money website achieved these results? I saw several similare questions here on Stack Overflow, but they never required the equal width and height of the individual fragments that I really needed for my design.
Bonus question: Could you add some explanations on how to achieve a responsive animated div overflow? An example found at http://www.brainyquote.com/ - when you resize a window, it converts all quotes in an animated way.
Edit: I am tying my current code that is far from correct (the preformation is very low and the images appear too large and their size drops after they are downloaded).
The first part of the code (attaches all events to fragments and adds animation when clicked):
function attachTileEvents() { if ($(".tile-flow").size() >= 1) { $(window).resize(function () { delay(function () { resizeTiles(); }, 100); }); $(document).on("click", ".tile-flow .load-next-page", manualLoadContentDetection); $(window).on("scroll", scrollLoadContentDetection); $(document).on("touchend", scrollLoadContentDetection); } resizeTiles(); $(".tile .contents").each(function () { var tile = $(this).parent()[0] var mouse = { x: 0, y: 0, down: false }; var maxRotation = 16; var minScale = 0.95; var setRotation = function (scaled) { //Rotations as percentages var width = tile.offsetWidth; var height = tile.offsetHeight; var diag = Math.sqrt((width / 2) * (width / 2) + (height / 2) * (height / 2)); var dist = Math.sqrt((mouse.x - (width / 2)) * (mouse.x - (width / 2)) + (mouse.y - (height / 2)) * (mouse.y - (height / 2))); var fract = 1.0; if (dist > 0) { fract = dist / diag; } var yRotation = (mouse.x - (width / 2)) / (width / 2); var xRotation = (mouse.y - (height / 2)) / (height / 2); if (scaled) { tile.style.webkitTransform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)" + " scale(" + (minScale + fract * (1 - minScale)) + ")"; tile.style.mozTransform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)" + " scale(" + (minScale + fract * (1 - minScale)) + ")"; tile.style.transform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)" + " scale(" + (minScale + fract * (1 - minScale)) + ")"; } else { tile.style.webkitTransform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)"; tile.style.mozTransform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)"; tile.style.transform = "rotateX(" + -xRotation * maxRotation + "deg)" + " rotateY(" + yRotation * maxRotation + "deg)"; } } var MouseDown = function (e) { mouse.x = e.offsetX; mouse.y = e.offsetY; mouse.down = true; setRotation(true); } var MouseUp = function (e) { if (mouse.down) { mouse.down = false; tile.style.webkitTransform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; tile.style.mozTransform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; tile.style.transform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; } } var MouseOut = function (e) { mouse.down = false; tile.style.webkitTransform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; tile.style.mozTransform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; tile.style.transform = "rotateX(0deg)" + " rotateY(0deg) scale(1.0)"; } var MouseMove = function (e) { mouse.x = e.offsetX; mouse.y = e.offsetY; if (mouse.down == true) { setRotation(false); } } $(tile).on("mousemove", MouseMove); $(tile).on("mousedown", MouseDown); $(tile).on("mouseup", MouseUp); $(tile).on("mouseout", MouseOut); });}
And the main part is resizing:
var TileSizes = { wideWidth: 0, singleWidth: 0, margin: 0 }; function resizeTiles() { var rowColumnNumber = 2; var width = $(window).width(); if (width >= 2500) { rowColumnNumber = 7; } else if (width >= 2000) { rowColumnNumber = 6; } else if (width >= 1600) { rowColumnNumber = 5; } else if (width >= 1280) { rowColumnNumber = 4; } else if (width >= 768) { rowColumnNumber = 3; } else if (width >= 480) { rowColumnNumber = 2; } else { rowColumnNumber = 1; } var totalWidth = $(".tile-flow").width() - 17; //compensate for the scrollbar //calculate the margin size : 5% of the flow width var margin = Math.round(totalWidth * 0.05 / rowColumnNumber); var wideSize = Math.floor((totalWidth - margin * (rowColumnNumber - 1)) / rowColumnNumber); var halfSize = Math.floor((wideSize - margin) / 2); var quaterSize = Math.floor(halfSize * 2.5 / 3); var heightSize = Math.floor(halfSize * 2 / 2.0); var doubleHeightSize = heightSize * 2 + margin; var detailsSize = quaterSize * 2 + margin; TileSizes.wideWidth = doubleHeightSize; TileSizes.singleWidth = heightSize; TileSizes.margin = margin; $(".big-square-tile").width(doubleHeightSize); $(".big-square-tile").height(doubleHeightSize); $(".wide-tile").width(doubleHeightSize); $(".small-tile").width(halfSize); $(".tile-flow .col .small-tile:even").css("margin-right", margin); $(".small-tile").height(heightSize); $(".wide-tile").height(heightSize); $(".col").width(doubleHeightSize); $(".col").css("margin-right", margin); $(".col:nth-child(" + rowColumnNumber + "n)").css("margin-right", 0); //all tiles get bottom margin var how = 0; $(".wide-tile .contents footer").each(function () { if ((how % 4 == 0) || (how % 4 == 1)) { $(this).width(TileSizes.singleWidth - 20); } else { $(this).height(75); } if (how % 4 == 0) { $(this).css("left", TileSizes.wideWidth); } else if (how % 4 == 1) { $(this).css("left", -TileSizes.singleWidth); } else if (how % 4 == 2) { $(this).css("top", TileSizes.singleWidth); } else { $(this).css("top", -95); } how = how + 1; }); $(".big-square-tile .contents footer").each(function () { $(this).height(75); if (how % 2 == 0) { $(this).css("top", TileSizes.wideWidth); } else { $(this).css("top", -95); } how = how + 1; }); $(".small-tile .contents footer").each(function () { $(this).width(TileSizes.singleWidth - 20); $(this).height(TileSizes.singleWidth - 20); if (how % 4 == 0) { $(this).css("left", TileSizes.singleWidth); } else if (how % 4 == 1) { $(this).css("left", -TileSizes.singleWidth); } else if (how % 4 == 2) { $(this).css("top", TileSizes.singleWidth); } else { $(this).css("top", -TileSizes.singleWidth); } how = how + 1; }); $(".tile").css("margin-bottom", margin); //resize images var imageList = Array(); $(".big-square-tile img").each(function () { imageList.push($(this)); var img = new Image(); img.onload = function () { var originalHeight = this.height; var originalWidth = this.width; var index = parseInt(this.id.replace("RESIZINGBIG", "")); if (originalHeight > originalWidth) { imageList[index].css("height", "auto"); imageList[index].css("width", "100%"); } else { imageList[index].css("height", "100%"); imageList[index].css("width", "auto"); } } img.id = "RESIZINGBIG" + (imageList.length - 1); img.src = $(this).attr('src'); }); $(".small-tile img").each(function () { imageList.push($(this)); var img = new Image(); img.onload = function () { var originalHeight = this.height; var originalWidth = this.width; var index = parseInt(this.id.replace("RESIZINGSMALL", "")); if (originalHeight > originalWidth) { imageList[index].css("height", "auto"); imageList[index].css("width", "100%"); } else { imageList[index].css("height", "100%"); imageList[index].css("width", "auto"); } } img.id = "RESIZINGSMALL" + (imageList.length - 1); img.src = $(this).attr('src'); }); $(".wide-tile img").each(function () { $(this).css("height", "auto"); $(this).css("width", "100%"); });}
And here is an example of what the HTML looks like:
<div class="tile-flow"> <div class="tile-row"> <div class="col"> <div class="tile big-square-tile"> <div class="contents"> <img src="~/Images/Test/5.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> </div> <div class="col"> <div class="tile small-tile"> <div class="contents"> <img src="~/Images/Test/2.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> <div class="tile small-tile"> <div class="contents"> <img src="~/Images/Test/3.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> <div class="tile wide-tile"> <div class="contents"> <img src="~/Images/Test/4.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> </div> <div class="col"> <div class="tile big-square-tile"> <div class="contents"> <img src="~/Images/Test/6.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> </div> <div class="col"> <div class="tile wide-tile"> <div class="contents"> <img src="~/Images/Test/1.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> <div class="tile wide-tile"> <div class="contents"> <img src="~/Images/Test/7.jpg" /> <footer> <h1>Test</h1> <span class="author">by Test</span> </footer> </div> </div> </div> </div> </div>