Я создаю сайт для фотографии, и я хочу создать приятный «черепичный» интерфейс, который будет выглядеть так же, как интерфейс в новой версии MSN Money Now (примечание - новая версия веб-сайта можно просматривать только на ПК с Windows 8) - http://t.money.msn.com/now/. Я попытался реализовать это в Javascript.Внедрение интерфейса JS для плитки
Вот пример страницы с укажи данными: http://photoachiever.azurewebsites.net/en
Я создал плитки группы - каждые 2 единицы в высоту, 2 единицы в ширину, которые могут содержать либо одну большую квадратную плитку, две широкие плитки или четыре маленьких квадратных плиток. Теперь, поскольку я хочу, чтобы сайт был отзывчивым, я хотел рассчитать на ходу в Javascript оптимальный размер блока, чтобы всегда заполнялось 100% пространства, а для более широких экранов, например, видно больше столбцов и т. Д. Он работает так же на веб-сайте MSN Money, но есть два важных отличия:
1) Когда мои изображения загружаются в первый раз, я просто вижу их в их самом высоком результате вплоть до момента, когда загружаются все изображения, и Выполняется JS. В сети MSN Money отображается только зеленая область, и изображения появляются позже, они уже значительно изменены. 2) Когда я изменяю размер окна, это далеко не текучая ситуация, и каюфлизации и, главным образом, изменение размера изображения очень заметны. Однако в MSN Money изменение размера очень плавное, и даже изображения, похоже, просто изменяются без сбоев. Кроме того, им удалось изменить размер шрифтов.
Не могли бы вы объяснить мне, как сайт MSN Money достиг этих результатов? Я видел несколько вопросов similare здесь, в Stack Overflow, но они никогда не требовали равной ширины и высоты отдельных плит, которые мне действительно нужны для моего дизайна.
Бонус вопрос: Не могли бы вы добавить некоторые объяснения, как достичь отзывчивого анимированного переполнения div? Пример, найденный на http://www.brainyquote.com/ - при изменении размера окна он пересчитывает все кавычки анимированным образом.
Редактировать: Я прилагаю свой текущий код, который далек от правильного (предварительная обработка очень низкая, а изображения появляются слишком большими, и их размер падает после их загрузки).
Первая часть кода (присоединяет все события плитки и добавляет анимацию на клик):
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);
});}
И главная часть - изменение размеров:
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%");
});}
А вот образец как выглядит код HTML:
<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>
может выглядеть там несколько профилирующих уроков: http://discover-devtools.codeschool.com/ дополнительно Google IO 2012 было несколько сессий по оптимизации производительности – bushed