2013-04-18 3 views
6

Я создаю сайт для фотографии, и я хочу создать приятный «черепичный» интерфейс, который будет выглядеть так же, как интерфейс в новой версии 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> 
+0

может выглядеть там несколько профилирующих уроков: http://discover-devtools.codeschool.com/ дополнительно Google IO 2012 было несколько сессий по оптимизации производительности – bushed

ответ

7

Если бы я был вами, я бы использовал Isotope для основной компоновки и добавил слайд показывает и щелкает события вдоль его стороны. Вы можете вставить любой контент, который вам нравится.jQuery Isotope.

Updated Working Model

Full page result

JS

$(function() { 

    var $container = $('#container'); 

    $container.imagesLoaded(function() { 
     $container.isotope({ 
      itemSelector: '.photo' 
     }); 
    }); 
}); 


var $container = $('#container'); 
// initialize Isotope 
$container.isotope({ 
    // options... 
    resizable: false, // disable normal resizing 
    // set columnWidth to a percentage of container width 
    masonry: { 
     columnWidth: $container.width()/5 
    } 
}); 

// update columnWidth on window resize 
$(window).smartresize(function() { 
    $container.isotope({ 
     // update columnWidth to a percentage of container width 
     masonry: { 
      columnWidth: $container.width()/5 
     } 
    }); 
}); 

//click function 

    $(function() { 
     $('.photo').click(function() { 
      $(this).toggleClass('red'); 
     }); 
    }); 

//hover function 

    $(function() { 
     $('#photo1').hover(function() { 
      $('#info1').fadeToggle(); 
     }); 
    }); 

Доказательство анимации внутри и концепт изотопом

Примечание Эта анимация общая клудж плавника e настроить перед использованием.

function animatie() { 
    var d = 0; 
    for (var i = 0; i < 3; ++i) { 
     var b = "#info" + i; 
     $(b).css('background', 'silver'); 
     $(b).hide().delay(d).slideDown(1000).delay(3000).slideUp(1000); 
     d += 5000; 
    } 
} 
animatie(); 
window.setInterval(animatie, 15000); 

$(function() { 
    for (var i = 0; i < 3; ++i) { 
     var z = '.box' + i; 
     var divHeight = $(z).height(); 
     $(z).css('max-height', divHeight + 'px'); 
     $(z).css('max-height', divHeight + 'px'); 
     $(z).css('overflow', 'hidden'); 
    } 
}); 
$(window).resize(function() { 
    for (var i = 0; i < 3; ++i) { 
     var z = '.box' + i; 
     var divHeight = $(z).height(); 
     $(z).css('max-height', divHeight + 'px'); 
     $(z).css('overflow', 'hidden'); 
    } 
}); 

Это очень классный плагин для компоновки, сортировки и фильтрации. Это даст вам плитки и анимации в качестве основных функций.

Fluid Isotope

Images Loaded Plugin

Infinite Scroll

Добавлена ​​анимация внутри изотопом, Check Out обновленные jsFiddles выше

+0

благодарю вас для этого предложения это выглядит хорошо, но я все еще ищу решение, которое я мог бы реализовать самостоятельно, без накладных расходов, которые имеет эта большая библиотека. Мне также нужна анимация плитки - плитка имеет две стороны, вторая всегда отображается после таймаута, слайды с одной из сторон плитки. –

+0

Плагин также, похоже, имеет немного проблем с изменением размера и не ведет себя хорошо на мобильных устройствах. По этим причинам меня больше интересует способ улучшить мой текущий код или перестроить его, чтобы нужные функции были там. –

+0

@MZetko Можете ли вы включить связанные CSS и изображения, а также собрать [jsFiddle] (http://jsfiddle.net/) того, что у вас есть до сих пор – apaul

1

@MZetko Я понимаю и уважаю ваше желание реализовать его на ON ,

@ apaul34208 указал в правильном направлении, когда предложил Isotope. Это термин, используемый для такого вида сетки макета. Вам не нужно использовать jQuery, но было бы полезно посмотреть, как он делает то, что он делает, чтобы сделать это ... :)

Я в настоящее время реализую сайт Wordpress с шаблоном Studiofolio и хотя я думаю, что было бы очень интересно сделать это сам, я рад, что потратил эти деньги на это. Теперь я могу закончить настройку и перейти к следующему проекту. Ура!

+0

Я только что заметил, что вы хотели бы иметь анимацию плит и заботиться о хорошей поддержке мобильных устройств. Этот шаблон WP хорош для обоих, поэтому взгляните на демо, чтобы посмотреть, как это делается. –

+0

Мне очень нравятся оба предложения, но меня все больше интересует решение, в котором я мог бы полностью контролировать ... Это не проект, который я делаю для кого-то, но что-то, что я хочу сделать правильно, а также я возможно, может. –

1

1) Загрузка изображений

Вы должны скрыть изображения по умолчанию. Вы можете сделать это, установив свои размеры на 1px
(используя display:none может вызвать проблемы с загрузкой). В конце вашего CSS:

div.tile img { width:1px; height:1px } 

Это будет перезаписана вашей плитки определенных стилей на основе одного элемента после того, как ваши расчеты сделаны.

Чтобы иметь опыт работы в то время как они загружаются, вы должны использовать фоновый цвет, кроме белого :-)
(например, смотреть на вашем div.wide-tile правила). В конце вашего CSS:

.col .tile { background-color: #2440b2; } 

Это будет иметь большую специфичность, чем ваш белый фон, так что будет перекрывать их.

Чтобы избежать мерцания, я бы спрятал все плитки до тех пор, пока их начальное положение не узнает (я не изменял ваши js).

[working demo](убедитесь, что использовать пустой кэш)

2) Reisizing с анимацией

В принципе, вы должны отказаться от использования поплавков для этой работы и использовать абсолютно позиционированные элементы (плавающие объекты не могут быть анимированы).

После этого вы можете просто использовать переходы CSS на плитки (top, left), поэтому, когда вы пересчитываете свои позиции внутри обработчика изменения размера, они будут перемещаться на свои новые позиции с приятной анимацией.

-webkit-transition: left .5s, top .5s; 
-moz-transition: left .5s, top .5s; 
transition: left .5s, top .5s; 

[working demo]

Смежные вопросы