Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > Задачка на рисование мозаики из фото


Автор: KonstRuctor 26.4.2013, 16:58
Привет всем!
Есть задачка на выходные smile сам решить не могу
ДАНО:
количество фотографий n = 5;
ширина контейнера div = 520px;
ПЕРЕМЕННЫЕ:
фотографии лежат в папочке, при этом фотографии могут быть любых разумных размеров.
как портретные, так и ландшафтные, 800*600, 500*800 и так далее. 
ЗАДАЧА:
красиво вписать n фотографий по ширине div, чтобы они занимали всю ширину дива.
РАЗМЕТКА:
Код

<div class="photo_list">
    <img src="1.jpg">
    <img src="2.jpg">
    <img src="3.jpg">
    <img src="4.jpg">
    <img src="5.jpg">
</div>

Что я умею сейчас. С помощью гугла нашел и сам подправил такой скрипт:
Код

$("document").ready(function(){

    $('.photo_list img').each(
        function(){
            var $this=$(this);
            var h=$this.height();
            var w=$this.width();
            var nh=75;   //высота до которой нужно масштабировать ---- вот это значение должно плавать!
            var nw=500;  //ну и ширина
            var k1=nh/nw;
            var k2=h/w;

            if (k1>k2)
            {
                h=h*(nw/w);
                w=nw;
            } else {
                w=w*(nh/h);
                h=nh;
            }
            $this.width(w);
            $this.height(h);
            if (h<nh) //Если картинка была слишком широкой, то при пропорциональном сжатии теряем в высоте, знач нужно выровнять по высоте
            {
                $this.css('margin-top',(nh-h)/2);
            }
        }
    );
});

Этот скрипт работает, но прижимает фото к левому краю, а я хочу заполнить див, то есть иметь плавающую высоту.
Во вложении жипег того, что хочется получить – это я просто сверстал руками, а хочется чтобы это делал робот smile
Есть идеи? Спасибо!

Автор: sQu1rr 27.4.2013, 14:18
Код

<!DOCTYPE html> <!-- мы же html5 используем да? -->
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script> <!-- на ваш вкус -->
<script type="text/javascript" src="https://raw.github.com/desandro/imagesloaded/master/jquery.imagesloaded.min.js"></script> <!-- IE не проглотит, лучше из локального места -->
<style>
    <!-- нужно же показать, где границы дива -->
    .photo_list {
        border: 2px solid blue;
        width: 520px;
        overflow: hidden;
    }
</style>
<script>
(function(){
    var imgList; // div.photo_list
    
    function resizeImages() {
        var height = 0, width = 0, SPACING = 6; // SPACING - расстояние между картинками в пикселях
        /*
            Пусть у нас есть прямоугольник с измерениями width,height.
            Ставим в него картинки одну за другой, пропорционально растягивая их до одной высоты (наибольшей)
            Обрабатываем картинку за картинкой
                пусть w,h - измерения текущего изображения
                если высота (h) больше общей высоты (height), сохраняем новое значение,
                    увеличиваем общую длину (width) во столько же раз, на сколько h больше height и
                    прибавляем w
                если высота (h) меньше общей высоты (heigth), увеличиваем w во столько же раз, на сколько h
                    меньше height и прибавляем к width
        */
        this.each(function(){
            var h = $(this).height(),
                w = $(this).width(),
                k = height ? (height / h) : 1;
            height = Math.max(h, height);
            width = (height > h) ? (w * k + width) : (w + width / k);
        });
        // расчитываем коэфициент разницы между width и нужной нам длиной (с учетом отступов)
        var k = width / (imgList.width() - (this.size()-1) * SPACING);
        height /= k; // нам важна только высота
        // применяем новые размеры к каждому изображению, примерно по той же схеме
        this.each(function(){
            var h = $(this).height(),
                w = $(this).width(),
                ik = height / h;
            $(this).height(height);
            $(this).width((h >= height) ? (w * ik) : (w / ik));
        });
        // любому непоследнему изображению добавляем отступы с правой стороны
        this.not(':last').css('margin-right', SPACING + 'px');
        // устанавливаем высотку контейнеру
        imgList.height(height);
    }

    $('document').ready(function(){
        imgList = $('.photo_list'); // div.photo_list
        imgList.find('img').imagesLoaded(resizeImages); // крупим callback на полную загрузку изображений
    });
})();
</script>
</head>
<body>
<!-- изображения должны идти пез пробелов и разрывов строк, а то браузер поставит пробелы между картинками -->
<div class="photo_list">
    <img src="1.jpg"/><img src="2.jpg"/><img src="3.jpg"/><img src="4.jpg"/><img src="5.jpg"/>
</div>
</body>
</html>

Как-то так... не забывайте, что document.read выполнится раньше загрузки изображений (если они не в кэше), а значит их высота и длина не будут известны на время выполнения функции. (https://github.com/desandro/imagesloaded)

Сам скрипт кстати не намного больше чем ваш, кол-во строк даже одинаково smile
Код

(function(){
    var imgList;
    function resizeImages() {
        var height = 0, width = 0, SPACING = 6;
        this.each(function(){
            var h = $(this).height(),
                w = $(this).width(),
                k = height ? (height / h) : 1;
            height = Math.max(h, height);
            width = (height > h) ? (w * k + width) : (w + width / k);
        });
        var k = width / (imgList.width() - (this.size()-1) * SPACING);
        height /= k;
        this.each(function(){
            var h = $(this).height(),
                w = $(this).width(),
                ik = height / h;
            $(this).height(height);
            $(this).width((h >= height) ? (w * ik) : (w / ik));
        });
        this.not(':last').css('margin-right', SPACING + 'px');
        imgList.height(height);
    }
    
    $('document').ready(function(){
        imgList = $('.photo_list');
        imgList.find('img').imagesLoaded(resizeImages);
    });
})();

Автор: KonstRuctor 29.4.2013, 12:58
Спасибо! Второй день разбираю скрипт.
По уму, конечно, надо html отдавать с уже готовыми картинками, которые сделаны в размер.

Столкнулся с такой штукой: иногда последнее фото перескакивает на следующую строку,
видимо, из-за неверного округления дробных значений ширины / высоты...
См. прикрепленный файл.
Может быть, округлять все значения в меньшую сторону и выравнивать всю группу влево...
Все равно идеальную точность растяжки по ширине не будет видно... Или будет?

Автор: sQu1rr 29.4.2013, 19:56
не будет, и это еще и от бразуера зависит. поставьте в тех местах моего кода, где деление, умножение, Math.floor() и все будет так как вы хотите

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)