Плавная прокрутка плитки изображения на большой сетке?
Длительный слушатель, первый раз вызывающий абонент.
Хорошо, я приношу свои извинения за длину этого сообщения, но я хочу быть предельно ясным в том, что я пытаюсь сделать, и о том, что я пытался, надеюсь, руководствовать ваши ответы.
Цель:
Я пытаюсь создать сетку из плиток (изображений) 100 х 100, и я буду отображать только часть сетки за раз, потому что изображения 240 х 120. Нажимая кнопки (обратите внимание: нет необходимости в прокрутке мыши, масштабировании и т.д..), пользователь будет перемещаться по горизонтали и по вертикали.
В качестве аналогии возьмите шашку, которая настроена для игры, и вы смотрите на нее. Было бы довольно просто отобразить, требуя всего лишь нескольких базовых изображений и помещая их в сетку. Теперь подумайте, что вы только хотели показать нижнюю 1/3 платы. Затем, когда пользователь нажимает на них, они перемещают свой вид на середину, а другой щелчок берет их на верхнюю 1/3 панели. Это простой пример того, что я пытаюсь выполнить, за исключением гораздо большей сетки с меньшим представлением/перемещением.
Что я пробовал:
- Сначала я написал код в PHP, чтобы нарисовать полную сетку 100x100, и все выглядело великолепно.
- Затем я изменил код, чтобы на самом деле писать файлы для каждого квадрата, сохраняя их как X-Y.png
- Я втянулся в мир инструментов карты и инструментов типа масштабирования.
- У меня был некоторый частичный успех при написании собственного решения.
Инструменты карты/Масштабирование сбоя:
После получения полной карты и фрагментов я попытался выяснить, как черт прокручивать часть этого окна. Лампочка погасла: "как насчет того, как карты Google делают что-то!" Это, когда начались неприятности, и я засасывал кроличью нору, изучая все эти картографические инструменты, которые действительно меня не достали, потому что просто они кажутся только для отображения географических карт.
Однако, в какой-то момент я получил Zoomify, и я подумал, что это действительно вариант. Первая проблема заключалась в том, что я не мог заставить ее забрать свои собственные плитки без одного снимка полного изображения, поэтому я попробовал каждую программу захвата экрана под солнцем, чтобы попытаться получить полный снимок моего браузера с полной сеткой, чтобы позволить zoomize сделать их. Скажем так, это не сработало, но я попытался уменьшить размер. Это сработало, но потеряло много качества, и я понял, что zoomize даже не выполняет действительно то, что мне нужно, потому что 1. свиток не так гладен; и 2. эти изображения в конечном итоге содержат некоторые ссылки, связанные с их координатами X-Y, что означает, что мне нужно контролировать, сколько прокручивается каждый раз, когда будут нажаты стрелки вверх, вниз, влево, вправо.
Моя неудачная попытка сделать это не сама.
Хорошо, тогда я вернулся к основам, и я выбросил сетку в DIV с переполнением: скрытый в CSS. Отлично, теперь у меня было окно. Я не хотел загружать все эти изображения одновременно, поэтому я рисовал только часть сетки в абсолютно позиционированных DIV с уникальным идентификатором (например, Tile_1_1). Все это выглядело отлично, но теперь мне нужно было убедиться, что вы прокручиваете сетку при нажатии на кнопки со стрелками, поэтому я бросил ее на функцию javascript для этого. У меня был javascript, который вычисляет новый X и новый Y и заменяет источник изображения всех фрагментов, так как все они названы после их координат X/Y в сетке. Фактически, это полностью сработало, и теперь карта прокручивается. Проблема в том, что это немного изменчиво, чтобы просто изменить источники изображения. Нет иллюзий, что мы перемещаемся по этой сетке так же сильно, как только контент мгновенно меняется. И ЭТО мои друзья - это то, где мне нужна наша помощь.
Где я ошибся? Был ли я на правильном пути с этой последней попыткой? Должен ли я полностью переосмыслить это или есть какое-то простое исправление для перемещения плиток немного элегантнее, чем замена источника?
Пожалуйста, имейте в виду, что я неплохо справился с php, css и т.д., но я никогда не вкладывал много времени в javascript, поэтому вам может понадобиться немного больше объяснить в этой области.
P.S. это была самая близкая вещь, которую я мог найти на этих досках, но на самом деле она не получила четкого ответа: Прокрутка/предварительная загрузка плитки (стиль Google Maps) слоев HTML с помощью Ajax
Обновление: используемое решение
Мне понравились и ответы Cobby, и псевдопоты. Решение Pseudosavant было действительно правильным моим союзником, позволяя CSS выполнять большую часть тяжелой работы, однако я пошел с решением Cobby. Я думал, что это даст мне немного больше контроля, и потому, что я на самом деле использую бриллиантовую сетку, я мог бы обернуть вокруг себя голову (не говоря, что другой тоже не обязательно будет работать).
Вот что я сделал. Я знаю, что код немного груб и нуждается в некоторой очистке, но, возможно, он может помочь кому-то.
Сначала мне нужно было найти связь между моей осью 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 вокруг этого с переполнением: спрячьте и дайте ему идентификатор (мой - #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;
}
}
то просто используйте echo $newTiles для использования script.
Удалить похоже, просто выставляя в 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>";
}
Надеюсь, это поможет кому-то. Спасибо всем за идеи и поддержку!
Ответы
Ответ 1
Я думаю, вам нужно вернуться к подходу всей сетки, вложенной в DIV с помощью overflow:hidden
, но использовать JavaScript, чтобы определить, какие изображения должны быть видимыми, и загружать только эти изображения по мере необходимости, а затем загружать в дополнительные соответствующие изображения, когда пользователь прокручивает эту область.
Прокрутка, конечно, должна просто манипулировать свойствами CSS left
и top
для вашей сетки, чтобы переместить ее в содержащем overflow: hidden
DIV. В вашем случае было бы проще всего просто изменить свойства CSS позиционирования с шагом вашего размера плитки (так что у вас никогда не будет показов фрагментов).
С точки зрения программирования это немного больно, но похоже, что у вас уже есть метод для расчета того, какие из них должны/должны отображаться?
С помощью этого метода он будет иметь первоначальный сбой при загрузке изображений в первый раз, но последующее перемещение сетки не придется перезагружать одни и те же изображения. После того, как вы это сделаете, вы можете использовать jQuery или аналогично анимации свойств left
и top
, чтобы обеспечить плавный эффект прокрутки.
Затем, если вы хотите, вы можете использовать это дальше и разрешить частичную прокрутку фрагментов и прокрутку по клику и перетаскиванию, такую как Google Maps. Кроме того, если вы хотите работать с производительностью, я рекомендую настроить сервер nginx, который прослушивает несколько поддоменов вашего сайта, чтобы воспроизводить изображения с фрагментами.
РЕДАКТИРОВАТЬ: Я рекомендую анимировать scrollLeft
и scrollTop
в контейнере div
(который имеет overflow: hidden
), даст гораздо лучшую производительность/плавную прокрутку.
Существует чистая программа под названием TileMill, в то время как OP не использует ее, она может быть применима для других людей.
Ответ 2
Вот решение, которое я использовал раньше.
- Плитки должны быть
<div>
, которые должны быть inline-block
с <img>
внутри него. Управляйте шириной и высотой заголовка с помощью <div>
. * Важно, чтобы между элементами <div>
не было белого пространства, иначе плитки не будут закрыты рядом друг с другом.
- Плитки должны быть в
#container
<div>
, который имеет line-height
0. Контейнер должен быть установлен в несколько кратных размерах плитки, так как плитки автоматически завернут линию. Таким образом, 20 плиток могут быть 4x5 или 5x4 в зависимости от размера контейнера.
-
#container
должен находиться в другом <div>
с overflow: hidden
, который я вызываю в окне просмотра. Вы можете прокручивать #viewport
с помощью jQuery и .scrollLeft
.scrollTop
.
Вот пример jsfiddle: http://jsfiddle.net/pseudosavant/b4hSV/
Ответ 3
Вы можете дать ровную анимацию, если ваша анимация основана на времени, а не на позиции/фрейме. Я бы начал с рассмотрения requestAnimationFrame
(или правильных полиномиальных по времени для него) и разработал вычисления анимации/позиционирования, исходя из. Вопрос:
заданное время t
, что должны делать прокрутки x
и y
смещения моей карты?
Затем подумайте о том, чтобы использовать иллюзию наличия видового экрана в массивном наборе плиток, вместо того, чтобы на самом деле иметь массивный набор плиток, который использует overflow: hidden
для просмотра маленького окна просмотра. Вы не хотите исчерпывать DOM со слишком большим количеством фрагментов.
Предположим, что ваш viewport позволяет просматривать 4 x 4 плитки, которые составляют максимум 5 x 5 фрагментов с учетом частично отображаемых фрагментов, когда смещение плитки не привязывается к вашему окну просмотра (что будет в большинстве случаев времени). 5 x 5 плиток будут все, что вам когда-либо понадобится, независимо от того, сколько плиток на вашей карте действительно есть. Здесь эскиз:
http://jsfiddle.net/6uRHD/
Задача:
- Рассчитать ускорение/скорость/позицию на основе действий пользователя (прокрутка, подталкивание с демпфированием), а затем вычислить положение в момент времени t анимации.
- Рассчитайте, какие плитки попадают в набор 5 x 5, основанный на позиции, а также вычисляют смещение видового экрана для этих фрагментов.