Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Помогите реализовать "ленивую" загрузку большой карты (https://javascript.ru/forum/misc/76047-pomogite-realizovat-lenivuyu-zagruzku-bolshojj-karty.html)

imhateb 28.11.2018 23:38

Помогите реализовать "ленивую" загрузку большой карты
 
Здравствуйте.

Задался я целью создать карту из игры. Написал скрипт для автокликера и он наделал мне за ночь 30к скриншотов.

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

В итоге я плюнул на идею с прогами для панорам и написал скрипт, который добавляет изображения на страницу с нужным мне смещением. Вот он:
var coordX = 0,
	coordY = 30300,
	image = '0000';

for(var i = 0; i < 30400; i++){					
	image = parseInt(image.replace(/\D+/g,"")); // переводим строку в число, чтобы отобросить лишние нули
	image = image.toString();					// переводим число в строку, чтобы посчитать количество оставшихся символов.
	var len = image.length;		                // считаем количество символов

	if (len == 1) {image = '000'+image;}
	if (len == 2) {image = '00'+image;}
	if (len == 3) {image = '0'+image;}

	if (i % 301 == 0){
		coordX = 0+600*(i/301);
		coordY = 30300-300*(i/301);
	}

	$('body').append('<img src="screens/Image_'+image+'.jpg" style="left: '+coordX+'px; top: '+coordY+'px;">');
	coordX = coordX+200;
	coordY = coordY+100;

	image = parseInt(image.replace(/\D+/g,"")); // переводим строку в число, чтобы можно было прибавить единицу
	image = image+1;                            // +1
	image = image.toString();					// переводим число в строку, чтобы подготовить к следующему циклу

}


Для перемещения по карте методом перетаскивания я использовал плагин dragscroll.js.

И всё прекрасно, за исключением того, что карта реально огромная. Вес всех файлов составляет чуть более 2Gb. И соответственно загружается это дело достаточно долго.

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

Вот эта карта - http://lss.format23.ru

P.S. И ещё момент. Возможно я использовал не самый оптимальный код для вставки такого большого количества элементов на страницу. Что-то я слышал про предварительное создание элементов перед вставкой в DOM. Но что-то до полного понимания этого механизма я пока не дошёл. Вероятно вы сможете предложить более удачный вариант для этой задачи.

j0hnik 28.11.2018 23:43

самый простой способ ленивой загрузки
<img data-src="какоетоизображение.jpg">
получить координаты видимой области или чуть с запасом и заменить data-src на src
<img src="какоетоизображение.jpg">
при появлении атрибута загрузка автоматически произойдет.

сетка в соседней теме полагаю для карты

imhateb 28.11.2018 23:53

Цитата:

Сообщение от j0hnik (Сообщение 499483)
самый простой способ ленивой загрузки
<img data-src="какоетоизображение.jpg">
получить координаты видимой области или чуть с запасом и заменить data-src на src
<img src="какоетоизображение.jpg">
при появлении атрибута загрузка автоматически произойдет.

сетка в соседней теме полагаю для карты

Угу. Для неё ))) Хотелось бы сделать, чтобы при наведении на клетку показывались её координаты. И ещё чтобы можно было переходить к нужным координатам. Для этого таблицу и мучаю.

По поводу смены атрибутов понятно вроде. Но как мне получить список файлов, которые сейчас должны быть показаны? Они ж получается не по порядку идут. Мы видим сразу несколько рядов.

Карта строится от правого угла вниз. Следующий ряд идёт выше опять спрва налево вниз. и т.д. Т.е. правый угол это у нас картинка 0000, затем 0001 .... самая нижняя 0301. Затем идёт следующий ряд. Т.е. над первой картинкой что справа, идёт картинка 0302, ещё выше 0603 и т.д.

рони 29.11.2018 00:15

imhateb,
http://webmap-blog.ru/yandex-maps/ra...i-yandeks-kart

imhateb 29.11.2018 00:33

Предложенный Вами вариант просто чудесен. Но у меня нет одного целого изображения. И вариантов создать его из 30401 фрагментов я не нашёл. Все программы для склеивания изображений не помогли. Поэтому я и написал скрипт для вставки этих изображений в страницу.

MallSerg 29.11.2018 16:32

google Ну а по хорошему нужно взять библиотеку для карт и сделать тайлы из скриншотов для 3- 5 маштабов отображения карты. ( т.е. придется склеивать соседние скриншоты для того что бы масштабировать и вырезать из них нужный квадрат для тайла и так для всех размеров).

imhateb 29.11.2018 19:07

Приветствую.

В общем, вчера ночью я всё таки победил (как мне кажется) эту "ленивую загрузку". Результат тут - http://lss.format23.ru/

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

Вот код:
$(document).ready(function() {

	// код добавления изображений
	var coordX = 0,             // устанавливаем позицию для первого скрина (отступ слева)
		coordY = 30300,         // отступ сверху
		image = '0000',         // имя первого изображения		
		gamecorX = 0,           // переменные для добавления к изображениям игровых координат (в атрибут title)
		gamecorY = 1212,  		
		map = $('<div/>');      // создаём div для добавления в него всех элементов

		map.addClass('map');    // добавляем ему класс, чтобы он не был безымянным


	// запускаем цикл для перебора всех изображений
	for(var i = 0; i < 30400; i++){					
		// так как имена файлов у нас в формате Image_0000 придётся заморочиться с ними
		image = parseInt(image.replace(/\D+/g,"")); // переводим строку в число, чтобы отбросить лишние нули
		image = image.toString();					// переводим число в строку, чтобы посчитать количество оставшихся символов.
		var len = image.length;		                // считаем количество символов

		if (len == 1) {image = '000'+image;}
		if (len == 2) {image = '00'+image;}
		if (len == 3) {image = '0'+image;}

		// реализуем переход на следующий ряд (в одном ряду должно быть 301 изображение)
		if (i % 301 == 0){
			coordX = 0+600*(i/301);
			coordY = 30300-300*(i/301);	
			gamecorY = gamecorY-12;	
			gamecorX = 0;
		}

		// добавляем изображение в div.map 
		map.append('<img data-src="screens/Image_'+image+'.jpg" style="left: '+coordX+'px; top: '+coordY+'px;" alt="Please wait. I\'m will load soon. ;)" title="'+gamecorX+' : '+gamecorY+'">');
		coordX = coordX+200;    // задаём смещение по оси Х
		coordY = coordY+100;    // по оси Y
		gamecorX = gamecorX+4;  // изменяем игровые координаты для title			

		// снова заморачиваемся с именем файла
		image = parseInt(image.replace(/\D+/g,"")); // переводим строку в число, чтобы можно было прибавить единицу
		image = image+1;                            // +1
		image = image.toString();					// переводим число в строку, чтобы подготовить к следующему циклу
	}

	$('body').append(map); // добавляем наш блок с картинками в body
});


// определяем область видимости
$(document).scroll(function() {
	function inWindow(s){
		var scrollTop = $(window).scrollTop();
		var scrollLeft = $(window).scrollLeft();
		var windowHeight = $(window).height();
		var windowWidth = $(window).width();
		var currentEls = $(s);
		var result = [];

		currentEls.each(function(){			
			var el = $(this);
			var offset = el.offset();				
			if (scrollTop-1000 <= offset.top && (el.height() + offset.top) < (scrollTop + windowHeight+1000) && scrollLeft-1000 <= offset.left && (el.width() + offset.left) < (scrollLeft + windowWidth+1000)) result.push(this);
		});
		return $(result);
	}		
	var boxesInWindow = inWindow("img"); 

	// меняем атрибут data-src у всех видимых изображений
	var imgEl = boxesInWindow;
	for (var i=0; i<imgEl.length; i++) {
		if(imgEl[i].getAttribute('data-src')) {
		   imgEl[i].setAttribute('src',imgEl[i].getAttribute('data-src'));
		   imgEl[i].removeAttribute('data-src');
		}
	}
});


Если его можно как-то оптимизировать, чтобы он работал быстрее, было бы просто здорово.

А ещё я подумал, что наверное имело бы смысл менять атрибут "src=" на "data-src=" у всех элементов которые сейчас не видны, чтобы не хранить в памяти все загруженные картинки. Но я боюсь, что вычисления всех "невидимых" объектов будут занимать ещё больше времени чем расчёты видимых, что будет ещё сильнее тормозить страницу. Хотя скорее всего можно дописать эту штуку к уже существующему скрипту, но я пока не понял как. И вообще я не очень уверен в результате этих действий. Т.е. будет ли легче браузеру, если выгружать из памяти уже загруженные, но не видимые сейчас картинки?

В общем, я буду признателен любым советам по оптимизации. И было бы круто с примерами )) Потому что тут я уже выше своей головы прыгнул )))


P.S. И ещё момент. После добавления этого скрипта "ленивой загрузки" страница перестала открываться на мобильных устройствах. Раньше можно было дождаться загрузки и вполне себе просматривать карту. А сейчас она почему-то совсем не отображается. Я думаю, проблема где-то в этом скрипте для определения области видимости. Но не уверен.

imhateb 30.11.2018 02:01

Цитата:

Сообщение от MallSerg (Сообщение 499537)
google Ну а по хорошему нужно взять библиотеку для карт и сделать тайлы из скриншотов для 3- 5 маштабов отображения карты. ( т.е. придется склеивать соседние скриншоты для того что бы масштабировать и вырезать из них нужный квадрат для тайла и так для всех размеров).

Спасибо за совет. Но для всех этих API web-карт требуется одно большое изображение. А его у меня просто нет. И как его сделать я не смог найти. У меня есть только 30400 скриншотов сделанных внахлёст с заданным смещением. Поэтому я и пошёл собирать их на чём умею. Собрал вот на JS.


Часовой пояс GMT +3, время: 16:36.