Плавная прокрутка изображений на большой сетке? - PullRequest
16 голосов
/ 31 января 2012

Долгое время слушатель, впервые звонящий сюда.

Хорошо, я прошу прощения за длину этого поста, но я хочу быть очень ясным о том, что я пытаюсь сделать и что я пытался направлять ваши ответы.

Цель: Я пытаюсь создать сетку из плиток (изображений) 100 x 100, и я буду отображать только часть сетки за раз, потому что изображения имеют размер 240 x 120. При нажатии кнопок (примечание: нет необходимости прокрутки, масштабирования и т. Д.). .), пользователь будет прокручивать по горизонтали и вертикали.

В качестве аналогии, возьмите шашечную доску, на которой настроено играть, и вы смотрите на нее сверху вниз. Это было бы довольно просто отобразить, потребовав всего несколько базовых изображений и поместив их в сетку. Теперь учтите, что вы хотели показать только 1/3 нижней части доски. Затем, когда пользователь щелкает вверх, он перемещает свое представление в середину, и другой щелчок переносит его на верхнюю треть доски. Это простой пример того, что я пытаюсь выполнить, за исключением гораздо большей сетки с меньшим обзором / перемещением.

Что я пробовал:

  1. Сначала я написал код на PHP, чтобы нарисовать полную сетку 100x100, и все выглядело отлично
  2. Затем я изменил код, чтобы фактически записывать файлы для каждого квадрата, сохраняя их как X-Y.png
  3. Я попал в мир картографических инструментов и инструментов для увеличения типов
  4. У меня был некоторый частичный успех при написании собственного решения

Инструменты карты / Ошибка увеличения:

После получения полной карты и тайлов я попытался выяснить, как, черт возьми, прокручивать только часть этого окна. Лампочка погасла: «Как насчет того, как Google Maps делает вещи!» Именно тогда начались неприятности, и я немного засосал кроличью нору, исследуя все эти инструменты карт, которые действительно никуда меня не привели, потому что, по-видимому, они сделаны исключительно для отображения географических карт.

Однако в тот или иной момент меня привели к Zoomify, и я подумал, что это действительно может быть вариантом. Первая проблема заключалась в том, что я не мог заставить себя брать свои плитки без единого снимка полного изображения, поэтому я попробовал каждую программу захвата экрана под солнцем, чтобы получить полный снимок моего браузера с полной сеткой, чтобы увеличить сделать их. Скажем так, это не сработало, но я попытался с уменьшенным размером. Это работало, но потеряло много качества, и я понял, что zoomify даже не выполняет то, что мне нужно, потому что: 1. прокрутка не такая плавная; и 2. эти изображения в конечном итоге будут содержать некоторые ссылки, связанные с их координатами X-Y, что означает, что мне нужно контролировать, сколько прокручивается при каждом нажатии стрелок вверх, вниз, влево, вправо.

Моя не столь неудачная попытка сделать это самостоятельно

Хорошо, тогда я вернулся к основам и бросил сетку в DIV с переполнением: скрыто в CSS. Отлично, теперь у меня есть окно. Я не хотел загружать все эти изображения одновременно, поэтому я нарисовал только часть сетки в абсолютно позиционированных DIV с уникальными идентификаторами (например, Tile_1_1). Все это выглядело великолепно, но теперь мне нужно было создать впечатление, что вы прокручиваете сетку, нажимая кнопки со стрелками, поэтому я выбрал ее для функции javascript. Я заставил javascript вычислить новый X и новый Y и поменять местами источник Image всех плиток, так как все они названы в честь своих координат X / Y на сетке. На самом деле, это полностью сработало, и теперь карта прокручивается. Проблема в том, что немного поменять источник изображения. Нет иллюзий, что мы перемещаемся по этой сетке настолько, насколько быстро меняется контент. И это мои друзья, где я нуждаюсь в нашей помощи.

Где я ошибся? Я был на правильном пути с этой последней попыткой? Нужно ли полностью переосмыслить это или есть какое-то простое исправление для перемещения плиток немного более элегантно, чем замена источника?

Пожалуйста, имейте в виду, что я неплохо справился с php, css и т. Д., Но я никогда не тратил много времени на javascript, поэтому вам, возможно, потребуется немного больше объяснить в этой области.

PS Это была самая близкая вещь, которую я мог найти на этих досках, но так и не получил однозначного ответа: Прокрутка / предварительная загрузка листов (стиль Google Maps) слоев HTML с Ajax

Обновление: используемое решение

Мне понравились ответы как Кобби, так и псевдосаванта.Решение Псевдосаванта было действительно правильным моим союзником, позволив CSS выполнить большую часть тяжелой работы, однако я согласился с решением Кобби.Я думал, что это даст мне немного больше контроля, и, поскольку я на самом деле использую алмазную сетку, я мог бы лучше обернуть ее вокруг (не говоря уже о том, что другой не обязательно будет работать).

Здесьэто то, что я сделалЯ знаю, что код немного груб и нуждается в некоторой очистке, но, возможно, он может кому-то помочь.

Сначала мне нужно было найти связь между моей осью X и Y, поэтому я нарисовал небольшую диаграмму.

enter image description here

Я быстро заметил, что больше X означало запуск ромба и дальше влево, и выше, чтобы получить правильные координаты в центре вида (определяемый пользователем начало), а затем сместить на Yкоординаты, чтобы снять некоторые отрицательные налево и понизить начальную точку.

Затем PHP для рисования сетки выглядит примерно так ($ xcoord и $ ycoord происходят из формы):

//draw the grid
//Offset leftStart and topStart by Xcoord
$leftStart = 360 - ($xcoord * 120);
$topStart = 360 - ($xcoord * 60);

//Offset leftStart and topStart by Ycoord
$leftStart += ($ycoord * 120);
$topStart -= ($ycoord * 60);

for($y = 1; $y <= 99; $y++) { //y min to y max
    $left = $leftStart;
    $top = $topStart;
    for($x = 1; $x <= 99; $x++) { //x min to x max
       //I only want to draw part of the square
       if(($x < ($xcoord + 6)  && $x > ($xcoord - 6)) && ($y < ($ycoord + 6)  && $y > ($ycoord - 6))) {
          //Put out the image - this is how i needed mine formated
          echo "\t<div class=\"move\" id=\"T" . $x . "_" . $y . "\" style='position:absolute; left:" . $left . "px; top:" . $top . "px;'>\n";
          echo "\t\t<img src=\"./<path to your image>" . $x . "-" . $y . ".gif\">\n";
          echo "\t</div>\n";
       }
       $left = $left + 120;
       $top = $top + 60;
    }
$leftStart = $leftStart - 120;
$topStart = $topStart + 60;
}

Создайте DIV с переполнением: hidden и присвойте ему идентификатор (мой - #tileView).Хорошо, теперь у вас внутри алмаза нарисована сетка, и теперь нам нужно начать ее перемещать!

Вот так выглядит мой jquery.Извините, если это нужно улучшить, я только что изучил Jquery и Ajax вчера.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("#top").click(function(){
        var y = document.getElementById('ycoord').value;
        var x = document.getElementById('xcoord').value;
        $(".move").animate({"left": "-=120px", "top": "+=60px"}, 500);
        changeImg(x, y, 'up');
        $("#ycoord").val(parseInt( y ) - 1);
    });     
    $("#bottom").click(function(){
        var y = document.getElementById('ycoord').value;
        var x = document.getElementById('xcoord').value;
        $(".move").animate({"left": "+=120px", "top": "-=60px"}, 500);
        changeImg(x, y, 'down');
        $("#ycoord").val(parseInt( y ) + 1);
    });     
    $("#left").click(function(){
        var y = document.getElementById('ycoord').value;
        var x = document.getElementById('xcoord').value;
        $(".move").animate({"left": "+=120px", "top": "+=60px"}, 500);
        changeImg(x, y, 'left');
        $("#xcoord").val(parseInt( x ) - 1);
    });
     $("#right").click(function(){
        var y = document.getElementById('ycoord').value;
        var x = document.getElementById('xcoord').value;
        $(".move").animate({"left": "-=120px", "top": "-=60px"}, 500);
        changeImg(x, y, 'right');
        $("#xcoord").val(parseInt( x ) + 1);
    });

function changeImg(x, y, move){
    $.ajax({
        type: "POST",
        url: "addImage.php",
        data: 'x=' + x + '&y=' + y + '&move=' + move,  
        cache: false,
        success: function(html){
            $(html).appendTo($("#tileView"));
        }
    });
    $.ajax({
        type: "POST",
        url: "removeImage.php",
        data: 'x=' + x + '&y=' + y + '&move=' + move,  
        cache: false,
        success: function(xml){             
            $("removeTile",xml).each(function(id) {    
            removeTile = $("removeTile",xml).get(id);
            removeID = $("tileID",removeTile).text();
            $("#" + removeID).remove();
        });
        }
    });
}
});
</script>

Ajax вызывает addImage.php, чтобы добавить новую строку в нужное место, и deleteImage.php, чтобы удалить строку, которая сейчас выходит изпросмотр (без удаления этих строк я обнаружил, что все началось довольно медленно).

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

if($_REQUEST["move"] == "up") {
    $xmin = $x - 5;
    $xmax = $x + 5;
    $y = $y - 6;

    $left = 360;
    $top = -360;

    for($i = $xmin; $i <= $xmax; $i++) {
        $id = "T" . $i . "_" . $y;
        $newTiles .= "<div class='move' style='position:absolute; left:" . $left . "px; top:" . $top . "px;' id='$id'><img src='./Map/TileGroup1/1-$i-$y.gif'></div>\n";
        $left += 120;
        $top += 60;
    }
}

, а затем просто вывести $ newTiles для использования в вашем скрипте.

Удалитьаналогично, просто помещая в XML идентификаторы DIV для удаления, потому что я не мог заставить каждый () работать иначе.

if($_REQUEST["move"] == "up") {
    $xmin = $x - 5;
    $xmax = $x + 5;
    $y = $y + 5;

    echo "<?xml version=\"1.0\"?>\n";  
    echo "<response>\n";  
    for($i = $xmin; $i <= $xmax; $i++) {
        echo "\t<removeTile>\n";
        echo "\t\t<tileID>T" . $i . "_" . $y . "</tileID>\n";
        echo "\t</removeTile>\n";
    }
    echo "</response>"; 
}

Надеюсь, это кому-то поможет.Спасибо всем за идеи и поддержку!

Ответы [ 3 ]

2 голосов
/ 31 января 2012

Вот решение, которое я использовал ранее.

  1. Плитка должна быть <div>, которая установлена ​​на inline-block с <img> внутри. Управляйте шириной и высотой заголовка с помощью <div>. * Важно, чтобы между элементами <div> не было пробелов, иначе плитки не будут приставлены друг к другу.
  2. Плитка должна быть в #container <div>, которая имеет line-height 0. Контейнер должен быть установлен на несколько кратных размеров плитки, так как плитки будут автоматически переноситься по линиям. Таким образом, 20 плиток могут быть 4х5 или 5х4 в зависимости от размера контейнера.
  3. #container должен быть в другом <div> с overflow: hidden, который я называю окном просмотра. Вы можете прокрутить #viewport с помощью jQuery и .scrollLeft .scrollTop.

Вот пример jsfiddle: http://jsfiddle.net/pseudosavant/b4hSV/

1 голос
/ 31 января 2012

Вы можете обеспечить плавную анимацию, только если ваша анимация основана на времени, а не на позиции / количестве кадров. Я бы начал с рассмотрения requestAnimationFrame (или правильных временных заливок для него) и разработал ваши расчеты анимации / позиционирования на основе времени. Вопрос будет:

данное время t какими должны быть смещения прокрутки x и y моей карты?

Тогда подумайте об использовании иллюзии о наличии области просмотра в массивном наборе плиток, а не о наличии массивного набора плиток, который использует overflow: hidden для просмотра маленького окна просмотра. Вы не хотите истощать DOM слишком большим количеством плиток.

Допустим, ваш видовой экран позволяет просматривать плитки размером 4 x 4, что составляет максимум 5 x 5 плиток с учетом частично отображаемых плиток, когда смещение плитки не привязано к вашей области просмотра (что будет иметь место в большинстве случаев). времени). 5 x 5 плиток - это все, что вам когда-либо понадобится, независимо от того, сколько плиток на вашей карте. Вот эскиз:

http://jsfiddle.net/6uRHD/

Задача будет:

  1. Рассчитать ускорение / скорость / положение на основе действий пользователя (прокрутка, смещение с демпфированием), а затем вычислить положение в момент времени t вашей анимации.
  2. Вычислить, какие плитки попадают в набор плиток 5 x 5, основываясь на положении, а также рассчитать смещение области просмотра для этих плиток.
1 голос
/ 31 января 2012

Я думаю, что вам нужно вернуться к подходу всей сетки, вложенной в DIV с overflow:hidden, но использовать JavaScript, чтобы выяснить, какие изображения должны быть видимыми, и загружать только эти изображения по мере необходимости, а затем загрузить дополнительные соответствующие изображения, когда пользователь прокручивает эту область.

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

С точки зрения программирования это немного болезненно, но похоже, что у вас уже есть метод для расчета, какие из них должны отображаться / должны отображаться?

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

Затем, если хотите, вы можете продолжить это и разрешить частичную прокрутку плиток и прокрутку, щелкнув и перетащившуюся, как Google Maps. Также, если вы хотите поработать над производительностью, я бы порекомендовал настроить сервер nginx, который прослушивает несколько поддоменов вашего сайта, чтобы обслуживать мозаичные изображения.

РЕДАКТИРОВАТЬ: Я рекомендую анимировать scrollLeft и scrollTop на контейнере div (который имеет overflow: hidden) вместо этого, даст гораздо лучшую производительность / более плавную прокрутку.


Существует изящная программа под названием TileMill , хотя ОП не использует ее, она может быть применима для других людей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...